From db35dceeba55e52385fc6da100ccb9ada3fd225f Mon Sep 17 00:00:00 2001 From: iinsertNameHere Date: Fri, 19 Jul 2024 09:48:16 +0200 Subject: [PATCH] Added caching with periodic refresh --- src/catnap.nim | 5 +- src/catnaplib/global/definitions.nim | 9 +- src/catnaplib/platform/caching.nim | 54 ++++++++++++ src/catnaplib/platform/probe.nim | 119 +++++++++++++++++---------- 4 files changed, 139 insertions(+), 48 deletions(-) create mode 100644 src/catnaplib/platform/caching.nim diff --git a/src/catnap.nim b/src/catnap.nim index 2db075b..2463976 100644 --- a/src/catnap.nim +++ b/src/catnap.nim @@ -1,6 +1,6 @@ import "catnaplib/platform/fetch" import "catnaplib/drawing/render" -from "catnaplib/global/definitions" import CONFIGPATH, DISTROSPATH, Config, STATNAMES, CACHEPATH +from "catnaplib/global/definitions" import CONFIGPATH, DISTROSPATH, Config, STATNAMES, CACHEPATH, TEMPPATH import "catnaplib/global/config" import "catnaplib/terminal/logging" import parsetoml @@ -305,6 +305,9 @@ if paramCount() > 0: if not dirExists(CACHEPATH): createDir(CACHEPATH) +if not dirExists(TEMPPATH): + createDir(TEMPPATH) + # Getting config var cfg = LoadConfig(cfgPath, dstPath) diff --git a/src/catnaplib/global/definitions.nim b/src/catnaplib/global/definitions.nim index 4f10ebf..169af85 100644 --- a/src/catnaplib/global/definitions.nim +++ b/src/catnaplib/global/definitions.nim @@ -148,8 +148,13 @@ proc getCachePath*(): string = else: result = "/tmp/catnap" -let CACHEPATH* = getCachePath() +let CACHEPATH* = getCachePath() +let TEMPPATH* = "/tmp/catnap" + +proc toCachePath*(p: string): string = + # Converts a path [p] into a cahce path + return joinPath(CACHEPATH, p) proc toTmpPath*(p: string): string = # Converts a path [p] into a temp path - return joinPath(CACHEPATH, p) + return joinPath(TEMPPATH, p) diff --git a/src/catnaplib/platform/caching.nim b/src/catnaplib/platform/caching.nim new file mode 100644 index 0000000..723bafa --- /dev/null +++ b/src/catnaplib/platform/caching.nim @@ -0,0 +1,54 @@ +import times +import os +import strformat +import strutils + +const datetimeFormat = "YYYY-MM-dd HH:mm:ss" +let INFINITEDURATION* = initDuration( + nanoseconds = 4294967295, + microseconds = 4294967295, + milliseconds = 4294967295, + seconds = 4294967295, + minutes = 4294967295, + hours = 4294967295, + days = 4294967295, + weeks = 4294967295) + +proc writeCache*(filename: string, content: string, dur: Duration) = + if fileExists(filename): removeFile(filename) + + var expiration: string + if dur == INFINITEDURATION: + expiration = "NEVER" + else: + expiration = $(now() + dur).format(datetimeFormat) + + var filecontent = &"[CONTENT]\n{content}\n[EXPIRATION]\n{expiration}" + writeFile(filename, filecontent) + +proc readCache*(filename: string, default: string = ""): string = + if not fileExists(filename): return default + + var filecontent = readFile(filename).strip() + let lines = filecontent.split('\n') + + var content: seq[string] + var expiration: DateTime = now() + var partindex = 0 + for line in lines: + if line == "[CONTENT]" and partindex == 0: + partindex += 1 + continue + elif line == "[EXPIRATION]" and partindex == 1: + partindex += 1 + continue + + if partindex == 1: + content.add(line) + elif partindex == 2: + if line == "NEVER": expiration = (now() + 1.hours) + else: expiration = parse(line, datetimeFormat) + break + + if now() >= expiration: return default + return content.join("\n") \ No newline at end of file diff --git a/src/catnaplib/platform/probe.nim b/src/catnaplib/platform/probe.nim index dd2a53a..32bc9c0 100644 --- a/src/catnaplib/platform/probe.nim +++ b/src/catnaplib/platform/probe.nim @@ -4,23 +4,39 @@ import math import strutils import parsecfg import posix_utils +import times import tables import osproc import re from unicode import toLower -from "../global/definitions" import DistroId, PKGMANAGERS, PKGCOUNTCOMMANDS, toTmpPath +from "../global/definitions" import DistroId, PKGMANAGERS, PKGCOUNTCOMMANDS, toCachePath, toTmpPath import "../terminal/logging" +import "caching" import algorithm proc getDistro*(): string = + let cacheFile = "distroname".toCachePath + result = readCache(cacheFile) + if result != "": return + when defined(linux): # Returns the name of the running linux distro result = "/etc/os-release".loadConfig.getSectionValue("", "PRETTY_NAME") & " " & uname().machine elif defined(macos): result = "MacOS X" & " " & uname().machine + writeCache(cacheFile, result, INFINITEDURATION) + proc getDistroId*(): DistroId = - # Returns the DistroId of the running linux distro + let cacheFile = "distroid".toCachePath + let raw = readCache(cacheFile) + if raw != "": + let raw_vals = raw.split(':') + if raw_vals.len == 2: + result.id = raw_vals[0] + result.like = raw_vals[1] + + if fileExists("/boot/issue.txt"): # Check if raspbian else get distroid from /etc/os-release result.id = "raspbian" result.like = "debian" @@ -28,6 +44,8 @@ proc getDistroId*(): DistroId = result.id = "/etc/os-release".loadConfig.getSectionValue("", "ID").toLower() result.like = "/etc/os-release".loadConfig.getSectionValue("", "ID_LIKE").toLower() + writeCache(cacheFile, &"{result.id}|{result.like}", INFINITEDURATION) + proc getUptime*(): string = # Returns the system uptime as a string (DAYS, HOURS, MINUTES) @@ -178,7 +196,7 @@ proc getMounts*(): seq[string] = result.add(mount) proc getDisk*(mount: string): string = - # Returns disk space usage + # Returns diskinfo for the mounting point proc getTotalDiskSpace(mountingPoint: cstring): cfloat {.importc, varargs, header: "getDisk.h".} proc getUsedDiskSpace(mountingPoint: cstring): cfloat {.importc, varargs, header: "getDisk.h".} @@ -189,7 +207,12 @@ proc getDisk*(mount: string): string = result = &"{used} / {total} GB ({percentage}%)" proc getCpu*(): string = - # Returns CPU model + # Returns the cpu name + let cacheFile = "cpu".toCachePath + result = readCache(cacheFile) + if result != "": + return + let rawLines = readFile("/proc/cpuinfo").split("\n") var key_name = "model name" @@ -206,9 +229,10 @@ proc getCpu*(): string = if key == key_name: result = val break + + writeCache(cacheFile, result, initDuration(days=1)) proc getPkgManager(distroId: DistroId): string = - # Returns main package manager of distro for key in PKGMANAGERS.keys: if distroId.id == key: return PKGMANAGERS[key] @@ -217,13 +241,19 @@ proc getPkgManager(distroId: DistroId): string = if distroId.like == key: return PKGMANAGERS[key] - return "unknown" + return "Unknown" proc getPackages*(distroId: DistroId = getDistroId()): string = - # Return install package count of the main package manager of the distro + # Returns the installed package count + let cacheFile = "packages".toCachePath + + result = readCache(cacheFile) + if result != "": + return + let pkgManager = getPkgManager(distroId) - if pkgManager == "unknown": - return "unknown" + if pkgManager == "Unknown": + return "Unknown" var foundPkgCmd = false for key in PKGCOUNTCOMMANDS.keys: @@ -231,58 +261,57 @@ proc getPackages*(distroId: DistroId = getDistroId()): string = foundPkgCmd = true break if not foundPkgCmd: - return "unknown" + return "Unknown" - let tmpFile = "pkgcount.txt".toTmpPath - - if not fileExists(tmpFile): - let cmd: string = PKGCOUNTCOMMANDS[pkgManager] & " > " & tmpFile - if execCmd(cmd) != 0: - logError("Failed to fetch pkg count!") + let tmpFile = "packages.txt".toTmpPath + let cmd: string = PKGCOUNTCOMMANDS[pkgManager] & " > " & tmpFile + if execCmd(cmd) != 0: + logError("Failed to fetch pkg count!") let count = readFile(tmpFile).strip() - return count & " [" & pkgManager & "]" + result = count & " [" & pkgManager & "]" + writeCache(cacheFile, result, initDuration(hours=2)) proc getGpu*(): string = - # Returns the VGA line of lspci output + # Returns the gpu name + let cacheFile = "gpu".toCachePath + + result = readCache(cacheFile) + if result != "": + return + let tmpFile = "lspci.txt".toTmpPath - let gpuFile = "gpu.txt".toTmpPath - - if fileExists(gpuFile): - return readFile(gpuFile) - if not fileExists(tmpFile): - if execCmd("lspci > " & tmpFile) != 0: - logError("Failed to fetch GPU!") + if execCmd("lspci > " & tmpFile) != 0: + logError("Failed to fetch GPU!") - var vga = "" + var vga = "Unknown" let lspci = readFile(tmpFile) for line in lspci.split('\n'): if line.split(' ')[1] == "VGA": vga = line break - if vga == "": - writeFile(gpuFile, "Unknown") - return "Unknown" - let vga_parts = vga.split(":") - if vga_parts.len < 2: - writeFile(gpuFile, "Unknown") - return "Unknown" - - let gpu = vga_parts[vga_parts.len - 1].split("(")[0] - writeFile(gpuFile, gpu.strip()) - return gpu.strip() + if vga_parts.len >= 2 or vga != "Unknown": + result = vga_parts[vga_parts.len - 1].split("(")[0].strip() + else: + result = "Unknown" + + writeCache(cacheFile, result, initDuration(days=1)) proc getWeather*(): string = + # Returns current weather + let cacheFile = "weather".toCachePath + + result = readCache(cacheFile) + if result != "": + return + let tmpFile = "weather.txt".toTmpPath - if fileExists(tmpFile): - # Returns the weather and discards the annoying newline. - result = readFile(tmpFile).strip() - else: - if execCmd("curl -s wttr.in/?format=3 > " & tmpFile) != 0: - logError("Failed to fetch weather!") - # Returns the weather and discards the annoying newline. - result = readFile(tmpFile).strip() + if execCmd("curl -s wttr.in/?format=3 > " & tmpFile) != 0: + logError("Failed to fetch weather!") + + result = readFile(tmpFile).strip() + writeCache(cacheFile, result, initDuration(minutes=30))