diff --git a/.gitignore b/.gitignore index e2857a7..1928d6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # NodeJS node_modules/ +dist/ # Server server diff --git a/_frontend/dist/assets/index.37324337.js b/_frontend/dist/assets/index.37324337.js deleted file mode 100644 index 88ff448..0000000 --- a/_frontend/dist/assets/index.37324337.js +++ /dev/null @@ -1 +0,0 @@ -const l=function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))r(e);new MutationObserver(e=>{for(const i of e)if(i.type==="childList")for(const n of i.addedNodes)n.tagName==="LINK"&&n.rel==="modulepreload"&&r(n)}).observe(document,{childList:!0,subtree:!0});function s(e){const i={};return e.integrity&&(i.integrity=e.integrity),e.referrerpolicy&&(i.referrerPolicy=e.referrerpolicy),e.crossorigin==="use-credentials"?i.credentials="include":e.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(e){if(e.ep)return;e.ep=!0;const i=s(e);fetch(e.href,i)}};l();async function f(){(await fetch("/api/status")).ok&&console.log("Server online")}f(); diff --git a/_frontend/dist/assets/index.9acd5e50.css b/_frontend/dist/assets/index.9acd5e50.css deleted file mode 100644 index 292cd3e..0000000 --- a/_frontend/dist/assets/index.9acd5e50.css +++ /dev/null @@ -1 +0,0 @@ -*,*:before,*:after{box-sizing:border-box}body{margin:0;width:100%;min-height:100vh;font-family:Inter,Segoe UI,Helvetica,Arial,sans-serif;font-size:16px}h1{margin:0;font-size:56.32212978px;line-height:1.5}h2{margin:0;font-size:42.347466px;line-height:1.5}h3{margin:0;font-size:31.8402px;line-height:1.5}h4{margin:0;font-size:23.94px;line-height:1.5}h5{margin:0;font-size:18px;line-height:1.5} diff --git a/_frontend/dist/index.html b/_frontend/dist/index.html deleted file mode 100644 index 71ed660..0000000 --- a/_frontend/dist/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - Homepage - - - - - - -

Homepage

- - - - \ No newline at end of file diff --git a/_frontend/src/util.jsx b/_frontend/src/util.jsx index 99aa67d..1b11e23 100644 --- a/_frontend/src/util.jsx +++ b/_frontend/src/util.jsx @@ -1,5 +1,5 @@ -import { toChildArray } from 'preact' -import { useCallback, useEffect, useRef, useState } from 'preact/hooks' +import { createContext, toChildArray } from 'preact' +import { useCallback, useContext, useEffect, useRef, useState } from 'preact/hooks' export function hashCode(s) { s = s.toString() + "seed iniziale dell'hash" diff --git a/config/config.go b/config/config.go index be63724..1b93d8f 100644 --- a/config/config.go +++ b/config/config.go @@ -3,6 +3,7 @@ package config import ( "log" "os" + "time" "github.com/joho/godotenv" ) @@ -13,19 +14,37 @@ var ( BaseURL string AdminPassword string + + MonitorScriptsDir string + MonitorCacheTimeout time.Duration ) func loadEnv(key string, defaultValue ...string) string { - env := os.Getenv(key) + env, present := os.LookupEnv(key) - if len(defaultValue) > 0 && env == "" { + if len(defaultValue) > 0 && !present { env = defaultValue[0] } - log.Printf("Environment variable %s = %q", key, env) + log.Printf("Env variable %s = %q", key, env) return env } +func parseEnv[T any](key, defaultValue string, parseFunc func(string) (T, error)) T { + env := loadEnv(key, defaultValue) + + v, err := parseFunc(env) + if err != nil { + v, err = parseFunc(defaultValue) + if err != nil { + log.Fatalf("Unable to parse default value %q to type %T", defaultValue, v) + } + } + + log.Printf(`Env variable %s parsed from %q to %T of value %v`, key, env, v, v) + return v +} + func init() { // Setup logger log.SetFlags(log.Lshortfile | log.Ltime | log.Ldate) @@ -33,9 +52,12 @@ func init() { // Load Config godotenv.Load() - Mode = loadEnv(os.Getenv("MODE"), "development") - Host = loadEnv(os.Getenv("HOST"), ":4000") - BaseURL = loadEnv(os.Getenv("HOST"), "http://localhost:4000") + Mode = loadEnv("MODE", "development") + Host = loadEnv("HOST", ":4000") + BaseURL = loadEnv("HOST", "http://localhost:4000") + + AdminPassword = loadEnv("ADMIN_PASSWORD", "secret") - AdminPassword = loadEnv(os.Getenv("ADMIN_PASSWORD"), "secret") + MonitorScriptsDir = loadEnv("MONITOR_SCRIPTS_DIR", "./scripts") + MonitorCacheTimeout = parseEnv("MONITOR_CACHE_TIMEOUT", "5s", time.ParseDuration) } diff --git a/main.go b/main.go index 3a87be1..7df1e2e 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,8 @@ func main() { db := database.NewJSON("database.local.json") monitorService := monitor.NewService(&monitor.Config{ - ScriptsDir: "./scripts", + ScriptsDir: "./scripts", + CacheTimeout: config.MonitorCacheTimeout, }) if err := monitorService.LoadScripts(); err != nil { diff --git a/monitor/service.go b/monitor/service.go index 138e8c8..8a2c85d 100644 --- a/monitor/service.go +++ b/monitor/service.go @@ -1,27 +1,38 @@ package monitor import ( - "bytes" "log" "os" "os/exec" "path" "strings" + "time" ) type Config struct { - ScriptsDir string `json:"scriptsDir"` + ScriptsDir string + CacheTimeout time.Duration +} + +type cacheEntry struct { + creationTime time.Time + + output string } type Service struct { Config *Config - scriptPaths map[string]string + scriptPaths map[string]string + scriptOutputCache map[string]cacheEntry } func NewService(config *Config) *Service { return &Service{ Config: config, + + scriptPaths: map[string]string{}, + scriptOutputCache: map[string]cacheEntry{}, } } @@ -41,21 +52,31 @@ func (s *Service) LoadScripts() error { return nil } -// TODO: Add caching -func (s *Service) GetLastOutput(command string) (string, error) { +func (s *Service) GetOutput(command string) (string, error) { + // check if output is present in cache + if entry, found := s.scriptOutputCache[command]; found { + // check if cached value is expired + if time.Now().Before(entry.creationTime.Add(s.Config.CacheTimeout)) { + log.Printf("Retrieving output of %q from cache", command) + return entry.output, nil + } + } + args := strings.Fields(command) log.Printf("Running script %q with args %v", args[0], args[1:]) scriptPath := s.scriptPaths[args[0]] - cmd := exec.Command(scriptPath, args[1:]...) - var b bytes.Buffer - cmd.Stdout = &b - - if err := cmd.Run(); err != nil { + bytes, err := exec.Command(scriptPath, args[1:]...).Output() + if err != nil { return "", err } - return b.String(), nil + output := string(bytes) + + log.Printf("Caching output of %q", command) + s.scriptOutputCache[command] = cacheEntry{time.Now(), output} + + return output, nil } diff --git a/routes/monitor.go b/routes/monitor.go index de7e1ff..f97314b 100644 --- a/routes/monitor.go +++ b/routes/monitor.go @@ -11,8 +11,7 @@ func (r *Router) ApiMonitor(api fiber.Router) { // - "/api/monitor/status?script=SCRIPT_NAME" where SCRIPT_NAME is the name of a file inside "./scripts" api.Get("/status", func(c *fiber.Ctx) error { if qScript := c.Query("script"); qScript != "" { - - output, err := r.Monitor.GetLastOutput(qScript) + output, err := r.Monitor.GetOutput(qScript) if err != nil { return err }