refactor: refactoring of the project structure

This commit is contained in:
utox39
2025-03-20 16:45:29 +01:00
parent 6a8f82dd41
commit 43d0752991
11 changed files with 813 additions and 799 deletions

121
src/linux/hardware.zig Normal file
View File

@@ -0,0 +1,121 @@
const std = @import("std");
const c_unistd = @cImport(@cInclude("unistd.h"));
pub const CpuInfo = struct {
cpu_name: []u8,
cpu_cores: i32,
cpu_max_freq: f32,
};
pub const RamInfo = struct {
ram_size: f64,
ram_usage: f64,
ram_usage_percentage: u8,
};
pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
const cpu_cores = c_unistd.sysconf(c_unistd._SC_NPROCESSORS_ONLN);
// Reads /proc/cpuinfo
const cpuinfo_path = "/proc/cpuinfo";
var file = try std.fs.cwd().openFile(cpuinfo_path, .{});
defer file.close();
const cpuinfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(cpuinfo_data);
// Parsing /proc/cpuinfo
var model_name: ?[]const u8 = null;
var lines = std.mem.split(u8, cpuinfo_data, "\n");
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t");
if (std.mem.startsWith(u8, trimmed, "model name") and model_name == null) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
model_name = std.mem.trim(u8, value, " ");
break;
}
}
}
// Reads /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
const cpuinfo_max_freq_path = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
var file2 = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{});
defer file2.close();
const cpuinfo_max_freq_data = try file2.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(cpuinfo_max_freq_data);
// Parsing /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
const trimmed = std.mem.trim(u8, cpuinfo_max_freq_data, " \n\r");
const cpu_max_freq_khz: f32 = try std.fmt.parseFloat(f32, trimmed);
const cpu_max_freq: f32 = cpu_max_freq_khz / 1_000_000;
return CpuInfo{
.cpu_name = try allocator.dupe(u8, model_name orelse "Unknown"),
.cpu_cores = @as(i32, @intCast(cpu_cores)),
.cpu_max_freq = cpu_max_freq,
};
}
pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
// Reads /proc/meminfo
const meminfo_path = "/proc/meminfo";
const file = try std.fs.cwd().openFile(meminfo_path, .{});
defer file.close();
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(meminfo_data);
// Parsing /proc/meminfo
var total_mem: f64 = 0.0;
var free_mem: f64 = 0.0; // remove?
var available_mem: f64 = 0.0;
var total_mem_str: ?[]const u8 = null;
var free_mem_str: ?[]const u8 = null;
var available_mem_str: ?[]const u8 = null;
var lines = std.mem.split(u8, meminfo_data, "\n");
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t");
if (std.mem.startsWith(u8, trimmed, "MemTotal")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
total_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
total_mem = try std.fmt.parseFloat(f64, total_mem_str.?);
}
} else if (std.mem.startsWith(u8, trimmed, "MemFree")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
free_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
free_mem = try std.fmt.parseFloat(f64, free_mem_str.?);
}
} else if (std.mem.startsWith(u8, trimmed, "MemAvailable")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
available_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
available_mem = try std.fmt.parseFloat(f64, available_mem_str.?);
}
}
if ((total_mem_str != null) and (free_mem_str != null) and (available_mem_str != null)) {
break;
}
}
var used_mem = total_mem - available_mem;
// Converts KB in GB
total_mem /= (1024 * 1024);
used_mem /= (1024 * 1024);
const ram_usage_percentage: u8 = @as(u8, @intFromFloat((used_mem * 100) / total_mem));
return RamInfo{
.ram_size = total_mem,
.ram_usage = used_mem,
.ram_usage_percentage = ram_usage_percentage,
};
}

View File

@@ -1,283 +1,4 @@
const std = @import("std");
const c_sysinfo = @cImport(@cInclude("sys/sysinfo.h"));
const c_unistd = @cImport(@cInclude("unistd.h"));
const c_utsname = @cImport(@cInclude("sys/utsname.h"));
const c_ifaddrs = @cImport(@cInclude("ifaddrs.h"));
const c_inet = @cImport(@cInclude("arpa/inet.h"));
const c_net_if = @cImport(@cInclude("net/if.h"));
const c_netinet_in = @cImport(@cInclude("netinet/in.h"));
const c_socket = @cImport(@cInclude("sys/socket.h"));
/// Structure representing system uptime in days, hours, and minutes.
pub const SystemUptime = struct {
days: i8,
hours: i8,
minutes: i8,
};
pub const CpuInfo = struct {
cpu_name: []u8,
cpu_cores: i32,
cpu_max_freq: f32,
};
pub const RamInfo = struct {
ram_size: f64,
ram_usage: f64,
ram_usage_percentage: u8,
};
pub const KernelInfo = struct {
kernel_name: []u8,
kernel_release: []u8,
};
pub const NetInfo = struct {
interface_name: []u8,
ipv4_addr: []u8,
};
pub fn getUsername(allocator: std.mem.Allocator) ![]u8 {
const username = try std.process.getEnvVarOwned(allocator, "USER");
return username;
}
pub fn getHostname(allocator: std.mem.Allocator) ![]u8 {
var buf: [std.posix.HOST_NAME_MAX]u8 = undefined;
const hostnameEnv = try std.posix.gethostname(&buf);
const hostname = try allocator.dupe(u8, hostnameEnv);
return hostname;
}
/// Returns the system uptime.
///
/// Uses `sysinfo` to fetch the system uptime and calculates the elapsed time.
pub fn getSystemUptime() !SystemUptime {
const seconds_per_day: f64 = 86400.0;
const hours_per_day: f64 = 24.0;
const seconds_per_hour: f64 = 3600.0;
const seconds_per_minute: f64 = 60.0;
var info: c_sysinfo.struct_sysinfo = undefined;
if (c_sysinfo.sysinfo(&info) != 0) {
return error.SysinfoFailed;
}
const uptime_seconds: f64 = @as(f64, @floatFromInt(info.uptime));
var remainig_seconds: f64 = uptime_seconds;
const days: f64 = @floor(remainig_seconds / seconds_per_day);
remainig_seconds = (remainig_seconds / seconds_per_day) - days;
const hours = @floor(remainig_seconds * hours_per_day);
remainig_seconds = (remainig_seconds * hours_per_day) - hours;
const minutes = @floor((remainig_seconds * seconds_per_hour) / seconds_per_minute);
return SystemUptime{
.days = @as(i8, @intFromFloat(days)),
.hours = @as(i8, @intFromFloat(hours)),
.minutes = @as(i8, @intFromFloat(minutes)),
};
}
pub fn getShell(allocator: std.mem.Allocator) ![]u8 {
const shell = try std.process.getEnvVarOwned(allocator, "SHELL");
var child = std.process.Child.init(&[_][]const u8{ shell, "--version" }, allocator);
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
try child.spawn();
const output = try child.stdout.?.reader().readAllAlloc(allocator, 1024 * 1024);
_ = try child.wait();
return output;
}
pub fn getCpuInfo(allocator: std.mem.Allocator) !CpuInfo {
const cpu_cores = c_unistd.sysconf(c_unistd._SC_NPROCESSORS_ONLN);
// Reads /proc/cpuinfo
const cpuinfo_path = "/proc/cpuinfo";
var file = try std.fs.cwd().openFile(cpuinfo_path, .{});
defer file.close();
const cpuinfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(cpuinfo_data);
// Parsing /proc/cpuinfo
var model_name: ?[]const u8 = null;
var lines = std.mem.split(u8, cpuinfo_data, "\n");
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t");
if (std.mem.startsWith(u8, trimmed, "model name") and model_name == null) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
model_name = std.mem.trim(u8, value, " ");
break;
}
}
}
// Reads /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
const cpuinfo_max_freq_path = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
var file2 = try std.fs.cwd().openFile(cpuinfo_max_freq_path, .{});
defer file2.close();
const cpuinfo_max_freq_data = try file2.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(cpuinfo_max_freq_data);
// Parsing /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
const trimmed = std.mem.trim(u8, cpuinfo_max_freq_data, " \n\r");
const cpu_max_freq_khz: f32 = try std.fmt.parseFloat(f32, trimmed);
const cpu_max_freq: f32 = cpu_max_freq_khz / 1_000_000;
return CpuInfo{
.cpu_name = try allocator.dupe(u8, model_name orelse "Unknown"),
.cpu_cores = @as(i32, @intCast(cpu_cores)),
.cpu_max_freq = cpu_max_freq,
};
}
pub fn getRamInfo(allocator: std.mem.Allocator) !RamInfo {
// Reads /proc/meminfo
const meminfo_path = "/proc/meminfo";
const file = try std.fs.cwd().openFile(meminfo_path, .{});
defer file.close();
const meminfo_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(meminfo_data);
// Parsing /proc/meminfo
var total_mem: f64 = 0.0;
var free_mem: f64 = 0.0; // remove?
var available_mem: f64 = 0.0;
var total_mem_str: ?[]const u8 = null;
var free_mem_str: ?[]const u8 = null;
var available_mem_str: ?[]const u8 = null;
var lines = std.mem.split(u8, meminfo_data, "\n");
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t");
if (std.mem.startsWith(u8, trimmed, "MemTotal")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
total_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
total_mem = try std.fmt.parseFloat(f64, total_mem_str.?);
}
} else if (std.mem.startsWith(u8, trimmed, "MemFree")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
free_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
free_mem = try std.fmt.parseFloat(f64, free_mem_str.?);
}
} else if (std.mem.startsWith(u8, trimmed, "MemAvailable")) {
var parts = std.mem.split(u8, trimmed, ":");
_ = parts.next(); // discards the key
if (parts.next()) |value| {
available_mem_str = std.mem.trim(u8, value[0..(value.len - 3)], " ");
available_mem = try std.fmt.parseFloat(f64, available_mem_str.?);
}
}
if ((total_mem_str != null) and (free_mem_str != null) and (available_mem_str != null)) {
break;
}
}
var used_mem = total_mem - available_mem;
// Converts KB in GB
total_mem /= (1024 * 1024);
used_mem /= (1024 * 1024);
const ram_usage_percentage: u8 = @as(u8, @intFromFloat((used_mem * 100) / total_mem));
return RamInfo{
.ram_size = total_mem,
.ram_usage = used_mem,
.ram_usage_percentage = ram_usage_percentage,
};
}
pub fn getKernelInfo(allocator: std.mem.Allocator) !KernelInfo {
var uts: c_utsname.struct_utsname = undefined;
if (c_utsname.uname(&uts) != 0) {
return error.UnameFailed;
}
return KernelInfo{
.kernel_name = try allocator.dupe(u8, &uts.sysname),
.kernel_release = try allocator.dupe(u8, &uts.release),
};
}
pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
const os_release_path = "/etc/os-release";
const file = try std.fs.cwd().openFile(os_release_path, .{});
defer file.close();
const os_release_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(os_release_data);
var pretty_name: ?[]const u8 = null;
var lines = std.mem.split(u8, os_release_data, "\n");
while (lines.next()) |line| {
if (std.mem.startsWith(u8, line, "PRETTY_NAME")) {
var parts = std.mem.split(u8, line, "=");
_ = parts.next(); // discard the key
if (parts.next()) |value| {
pretty_name = std.mem.trim(u8, value, "\"");
break;
}
}
}
return try allocator.dupe(u8, pretty_name orelse "Unknown");
}
pub fn getTerminalName(allocator: std.mem.Allocator) ![]u8 {
const term_progrm = try std.process.getEnvVarOwned(allocator, "TERM_PROGRAM");
return term_progrm;
}
pub fn getNetInfo(allocator: std.mem.Allocator) !std.ArrayList(NetInfo) {
var net_info_list = std.ArrayList(NetInfo).init(allocator);
var ifap: ?*c_ifaddrs.ifaddrs = null;
if (c_ifaddrs.getifaddrs(&ifap) != 0) {
return error.GetifaddrsFailed;
}
defer c_ifaddrs.freeifaddrs(ifap);
var cur: ?*c_ifaddrs.ifaddrs = ifap;
while (cur) |ifa| : (cur = ifa.ifa_next) {
if (ifa.ifa_addr) |addr| {
// Skips the loopback
if ((ifa.ifa_flags & c_net_if.IFF_LOOPBACK) != 0) continue;
const sockaddr_ptr = @as(*const c_socket.sockaddr, @ptrCast(@alignCast(addr)));
if (sockaddr_ptr.sa_family != c_inet.AF_INET) continue;
var addr_in = @as(*const c_netinet_in.sockaddr_in, @ptrCast(@alignCast(sockaddr_ptr)));
var ip_buf: [c_inet.INET_ADDRSTRLEN]u8 = undefined;
const ip_str = c_inet.inet_ntop(c_inet.AF_INET, &addr_in.sin_addr, &ip_buf, c_inet.INET_ADDRSTRLEN);
if (ip_str) |ip| {
try net_info_list.append(NetInfo{
.interface_name = try allocator.dupe(u8, std.mem.span(ifa.ifa_name)),
.ipv4_addr = try allocator.dupe(u8, std.mem.span(ip)),
});
}
}
}
return net_info_list;
}
pub const hardware = @import("./hardware.zig");
pub const network = @import("./network.zig");
pub const system = @import("./system.zig");
pub const user = @import("./user.zig");

45
src/linux/network.zig Normal file
View File

@@ -0,0 +1,45 @@
const std = @import("std");
const c_ifaddrs = @cImport(@cInclude("ifaddrs.h"));
const c_inet = @cImport(@cInclude("arpa/inet.h"));
const c_net_if = @cImport(@cInclude("net/if.h"));
const c_netinet_in = @cImport(@cInclude("netinet/in.h"));
const c_socket = @cImport(@cInclude("sys/socket.h"));
pub const NetInfo = struct {
interface_name: []u8,
ipv4_addr: []u8,
};
pub fn getNetInfo(allocator: std.mem.Allocator) !std.ArrayList(NetInfo) {
var net_info_list = std.ArrayList(NetInfo).init(allocator);
var ifap: ?*c_ifaddrs.ifaddrs = null;
if (c_ifaddrs.getifaddrs(&ifap) != 0) {
return error.GetifaddrsFailed;
}
defer c_ifaddrs.freeifaddrs(ifap);
var cur: ?*c_ifaddrs.ifaddrs = ifap;
while (cur) |ifa| : (cur = ifa.ifa_next) {
if (ifa.ifa_addr) |addr| {
// Skips the loopback
if ((ifa.ifa_flags & c_net_if.IFF_LOOPBACK) != 0) continue;
const sockaddr_ptr = @as(*const c_socket.sockaddr, @ptrCast(@alignCast(addr)));
if (sockaddr_ptr.sa_family != c_inet.AF_INET) continue;
var addr_in = @as(*const c_netinet_in.sockaddr_in, @ptrCast(@alignCast(sockaddr_ptr)));
var ip_buf: [c_inet.INET_ADDRSTRLEN]u8 = undefined;
const ip_str = c_inet.inet_ntop(c_inet.AF_INET, &addr_in.sin_addr, &ip_buf, c_inet.INET_ADDRSTRLEN);
if (ip_str) |ip| {
try net_info_list.append(NetInfo{
.interface_name = try allocator.dupe(u8, std.mem.span(ifa.ifa_name)),
.ipv4_addr = try allocator.dupe(u8, std.mem.span(ip)),
});
}
}
}
return net_info_list;
}

92
src/linux/system.zig Normal file
View File

@@ -0,0 +1,92 @@
const std = @import("std");
const c_sysinfo = @cImport(@cInclude("sys/sysinfo.h"));
const c_utsname = @cImport(@cInclude("sys/utsname.h"));
/// Structure representing system uptime in days, hours, and minutes.
pub const SystemUptime = struct {
days: i8,
hours: i8,
minutes: i8,
};
pub const KernelInfo = struct {
kernel_name: []u8,
kernel_release: []u8,
};
pub fn getHostname(allocator: std.mem.Allocator) ![]u8 {
var buf: [std.posix.HOST_NAME_MAX]u8 = undefined;
const hostnameEnv = try std.posix.gethostname(&buf);
const hostname = try allocator.dupe(u8, hostnameEnv);
return hostname;
}
/// Returns the system uptime.
///
/// Uses `sysinfo` to fetch the system uptime and calculates the elapsed time.
pub fn getSystemUptime() !SystemUptime {
const seconds_per_day: f64 = 86400.0;
const hours_per_day: f64 = 24.0;
const seconds_per_hour: f64 = 3600.0;
const seconds_per_minute: f64 = 60.0;
var info: c_sysinfo.struct_sysinfo = undefined;
if (c_sysinfo.sysinfo(&info) != 0) {
return error.SysinfoFailed;
}
const uptime_seconds: f64 = @as(f64, @floatFromInt(info.uptime));
var remainig_seconds: f64 = uptime_seconds;
const days: f64 = @floor(remainig_seconds / seconds_per_day);
remainig_seconds = (remainig_seconds / seconds_per_day) - days;
const hours = @floor(remainig_seconds * hours_per_day);
remainig_seconds = (remainig_seconds * hours_per_day) - hours;
const minutes = @floor((remainig_seconds * seconds_per_hour) / seconds_per_minute);
return SystemUptime{
.days = @as(i8, @intFromFloat(days)),
.hours = @as(i8, @intFromFloat(hours)),
.minutes = @as(i8, @intFromFloat(minutes)),
};
}
pub fn getKernelInfo(allocator: std.mem.Allocator) !KernelInfo {
var uts: c_utsname.struct_utsname = undefined;
if (c_utsname.uname(&uts) != 0) {
return error.UnameFailed;
}
return KernelInfo{
.kernel_name = try allocator.dupe(u8, &uts.sysname),
.kernel_release = try allocator.dupe(u8, &uts.release),
};
}
pub fn getOsInfo(allocator: std.mem.Allocator) ![]u8 {
const os_release_path = "/etc/os-release";
const file = try std.fs.cwd().openFile(os_release_path, .{});
defer file.close();
const os_release_data = try file.readToEndAlloc(allocator, std.math.maxInt(usize));
defer allocator.free(os_release_data);
var pretty_name: ?[]const u8 = null;
var lines = std.mem.split(u8, os_release_data, "\n");
while (lines.next()) |line| {
if (std.mem.startsWith(u8, line, "PRETTY_NAME")) {
var parts = std.mem.split(u8, line, "=");
_ = parts.next(); // discard the key
if (parts.next()) |value| {
pretty_name = std.mem.trim(u8, value, "\"");
break;
}
}
}
return try allocator.dupe(u8, pretty_name orelse "Unknown");
}

28
src/linux/user.zig Normal file
View File

@@ -0,0 +1,28 @@
const std = @import("std");
pub fn getUsername(allocator: std.mem.Allocator) ![]u8 {
const username = try std.process.getEnvVarOwned(allocator, "USER");
return username;
}
pub fn getShell(allocator: std.mem.Allocator) ![]u8 {
const shell = try std.process.getEnvVarOwned(allocator, "SHELL");
var child = std.process.Child.init(&[_][]const u8{ shell, "--version" }, allocator);
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
try child.spawn();
const output = try child.stdout.?.reader().readAllAlloc(allocator, 1024 * 1024);
_ = try child.wait();
return output;
}
pub fn getTerminalName(allocator: std.mem.Allocator) ![]u8 {
const term_progrm = try std.process.getEnvVarOwned(allocator, "TERM_PROGRAM");
return term_progrm;
}