diff --git a/go.mod b/go.mod index 486b93a..8858568 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,9 @@ go 1.22.2 require ( github.com/a-h/templ v0.2.707 github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.3 github.com/joho/godotenv v1.5.1 + github.com/shirou/gopsutil/v3 v3.24.5 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/xlzd/gotp v0.1.0 golang.org/x/crypto v0.24.0 @@ -17,6 +19,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -24,7 +27,14 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect ) diff --git a/go.sum b/go.sum index 955def5..33922a0 100644 --- a/go.sum +++ b/go.sum @@ -5,13 +5,18 @@ github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydL github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= @@ -26,23 +31,46 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po= github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/public/websocket.js b/public/websocket.js new file mode 100644 index 0000000..63092da --- /dev/null +++ b/public/websocket.js @@ -0,0 +1,43 @@ +const socket = new WebSocket('ws://localhost:27000/ws'); + +socket.onopen = function(event) { + console.log('WebSocket is open now.'); + socket.send('Hello Server!'); +}; + +socket.onmessage = function(event) { + try { + const data = JSON.parse(event.data); + console.log('Message from server:', data); + + const cpuElement = document.getElementById('cpu_usage'); + if (cpuElement) { + cpuElement.textContent = `${data.cpu_usage_percent.toFixed(2)}%`; + } + + const memoryElement = document.getElementById('memory_usage'); + if (memoryElement) { + memoryElement.textContent = `${data.memory_used_gb.toFixed(2)}/${data.total_memory_gb.toFixed(2)} GB`; + } + + const uploadElement = document.getElementById('upload_speed'); + if (uploadElement) { + uploadElement.textContent = `${data.upload_speed_mbps.toFixed(2)}Mbps`; + } + + const downloadElement = document.getElementById('download_speed'); + if (downloadElement) { + downloadElement.textContent = `${data.download_speed_mbps.toFixed(2)}Mbps`; + } + } catch (error) { + console.error('Error parsing message data:', error); + } +}; + +socket.onerror = function(event) { + console.error('WebSocket error observed:', event); +}; + +socket.onclose = function(event) { + console.log('WebSocket is closed now.'); +}; \ No newline at end of file diff --git a/routes/admin/routes.go b/routes/admin/routes.go index ddda602..1236115 100644 --- a/routes/admin/routes.go +++ b/routes/admin/routes.go @@ -1,13 +1,30 @@ package admin import ( - "github.com/fossyy/filekeeper/app" + "encoding/json" adminIndex "github.com/fossyy/filekeeper/view/admin/index" + "github.com/gorilla/websocket" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/mem" + "github.com/shirou/gopsutil/v3/net" + "log" "net/http" - "os" - "path/filepath" + "time" ) +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +type SystemStats struct { + TotalMemoryGB float64 `json:"total_memory_gb"` + MemoryUsedGB float64 `json:"memory_used_gb"` + CpuUsagePercent float64 `json:"cpu_usage_percent"` + UploadSpeedMbps float64 `json:"upload_speed_mbps"` + DownloadSpeedMbps float64 `json:"download_speed_mbps"` +} + func SetupRoutes() *http.ServeMux { handler := http.NewServeMux() handler.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { @@ -24,21 +41,59 @@ func SetupRoutes() *http.ServeMux { adminIndex.Main().Render(r.Context(), w) return }) - handler.HandleFunc("/public/output.css", func(w http.ResponseWriter, r *http.Request) { - openFile, err := os.OpenFile(filepath.Join("public", "output.css"), os.O_RDONLY, 0) + + handler.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - app.Server.Logger.Error(err.Error()) + log.Println(err) return } - defer openFile.Close() - stat, err := openFile.Stat() - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - app.Server.Logger.Error(err.Error()) - return + for { + handlerWS(conn) } - http.ServeContent(w, r, openFile.Name(), stat.ModTime(), openFile) }) + + fileServer := http.FileServer(http.Dir("./public")) + handler.Handle("/public/", http.StripPrefix("/public", fileServer)) return handler } + +func handlerWS(conn *websocket.Conn) { + prevCounters, _ := net.IOCounters(false) + for { + vMem, _ := mem.VirtualMemory() + + totalMemoryGB := float64(vMem.Total) / (1024 * 1024 * 1024) + memoryUsedGB := float64(vMem.Used) / (1024 * 1024 * 1024) + + cpuPercent, _ := cpu.Percent(time.Second, false) + + currentCounters, _ := net.IOCounters(false) + + uploadBytes := currentCounters[0].BytesSent - prevCounters[0].BytesSent + downloadBytes := currentCounters[0].BytesRecv - prevCounters[0].BytesRecv + uploadSpeedMbps := float64(uploadBytes) * 8 / (1024 * 1024) / 2 + downloadSpeedMbps := float64(downloadBytes) * 8 / (1024 * 1024) / 2 + + prevCounters = currentCounters + + stats := SystemStats{ + TotalMemoryGB: totalMemoryGB, + MemoryUsedGB: memoryUsedGB, + CpuUsagePercent: cpuPercent[0], + UploadSpeedMbps: uploadSpeedMbps, + DownloadSpeedMbps: downloadSpeedMbps, + } + + statsJson, _ := json.Marshal(stats) + + err := conn.WriteMessage(websocket.TextMessage, statsJson) + if err != nil { + conn.Close() + return + } + + time.Sleep(2 * time.Second) + } + +} diff --git a/view/admin/index/index.templ b/view/admin/index/index.templ index 5cc2d96..9420cd0 100644 --- a/view/admin/index/index.templ +++ b/view/admin/index/index.templ @@ -13,7 +13,7 @@ templ Main() {

Real-time metrics for your server.

-
+
-
75%
+
0%
CPU Usage
@@ -64,31 +64,49 @@ templ Main() { -
8GB
+
0GB
Memory Usage
- - - - - - -
100Mbps
-
Network Usage
+ xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + class="h-8 w-8" + > + + + + +
0Mbps
+
Upload Speed
+
+ + + + + +
0Mbps
+
Download Speed
+
@@ -425,5 +443,6 @@ templ Main() { +