Implemented the hardware service

+ Started working on web interface
This commit is contained in:
Daniel Legt 2024-01-20 01:27:10 +02:00
parent fbee33bf00
commit 81ca5ddf28
13 changed files with 398 additions and 12 deletions

View File

@ -1,4 +1,11 @@
## About
## Disclaimer
This software is only meant to run on linux, it's something I threw together all at once in one sitting without really thinking about structure or even caring about anything but making it work.
It's actually meant to run on my own server just so I can track the temperature of my harddrives in a live environment, I just want this service to run, record the status of the harddrives, and be able via my VPN to access it in a private manner, it's not meant to be dockerized, it's not meant to be ran in a VM, it's meant to be ran either as a `service` or in a [screen](https://git.savannah.gnu.org/cgit/screen.git) in the background.
It's not really meant to run all the time or anything like that, I just wanted to write this disclaimer, feel free to use the code any way you want to :)
## How to use

27
go.mod
View File

@ -4,5 +4,30 @@ go 1.21.6
require (
github.com/anatol/smart.go v0.0.0-20230705044831-c3b27137baa3 // indirect
golang.org/x/sys v0.9.0 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.17.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

84
go.sum
View File

@ -1,4 +1,88 @@
github.com/anatol/smart.go v0.0.0-20230705044831-c3b27137baa3 h1:kAF2MWFD8tyDqD74OQizymjj2cnZAURwSzBrEslCDnI=
github.com/anatol/smart.go v0.0.0-20230705044831-c3b27137baa3/go.mod h1:llkexGSe52bW0OjNva0kvIqGZxfSnVfpKHrnKBI2+pU=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74=
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

19
lib/config/config.go Normal file
View File

@ -0,0 +1,19 @@
package config
type DHConfig struct {
DiskFetchFrequency int `json:"diskFetchFrequency" comment:"How often should a snapshot be taken of the current state of the disks"`
MemoryDumpFrequency int `json:"memoryDumpFrequency" comment:"How often should we save the snapshots from memory to disk"`
MaxHistoryAge int
}
func GetConfiguration() DHConfig {
// TODO: Read from os.environment or simply load the defaults
return DHConfig{
DiskFetchFrequency: 5,
MemoryDumpFrequency: 36,
MaxHistoryAge: 2592000,
}
}

View File

@ -8,7 +8,7 @@ import (
"strings"
)
func GetSystemHardDrives() ([]HardDrive, error) {
func GetSystemHardDrives() ([]*HardDrive, error) {
// Execute the lsblk command to get detailed block device information
cmd := exec.Command("lsblk", "-d", "-o", "NAME,TRAN,SIZE,MODEL,SERIAL,TYPE")
@ -20,7 +20,7 @@ func GetSystemHardDrives() ([]HardDrive, error) {
return nil, err
}
var hardDrives []HardDrive
var hardDrives []*HardDrive
// Scan the output line by line
scanner := bufio.NewScanner(&out)
@ -40,7 +40,7 @@ func GetSystemHardDrives() ([]HardDrive, error) {
// Filter out nvme drives (M.2)
if cols[1] != "nvme" {
hd := HardDrive{
hd := &HardDrive{
Name: cols[0],
Transport: cols[1],
Size: cols[2],

131
lib/svc/service.go Normal file
View File

@ -0,0 +1,131 @@
package svc
import (
"encoding/gob"
"fmt"
"io"
"os"
"time"
"tea.chunkbyte.com/kato/drive-health/lib/config"
"tea.chunkbyte.com/kato/drive-health/lib/hardware"
)
// The path to where the snapshot database is located
const SNAPSHOT_LIST_PATH = "./snapshots.dat"
// A simple in-memory buffer for the history of snapshots
var snapShotBuffer []*HardwareSnapshot
// A snapshot in time of the current state of the harddrives
type HardwareSnapshot struct {
TimeStamp time.Time
HDD []*hardware.HardDrive
}
type Snapshots struct {
List []*HardwareSnapshot
}
// The function itterates through all hard disks and takes a snapshot of their state,
// returns a struct which contains metadata as well as the harddrives themselves.
func TakeHardwareSnapshot() (*HardwareSnapshot, error) {
drives, err := hardware.GetSystemHardDrives()
if err != nil {
return nil, err
}
snapShot := &HardwareSnapshot{
TimeStamp: time.Now(),
HDD: []*hardware.HardDrive{},
}
for _, hdd := range drives {
hdd.GetTemperature(true)
snapShot.HDD = append(snapShot.HDD, hdd)
}
// Append to the in-memory listing
snapShotBuffer = append(snapShotBuffer, snapShot)
// Return the snapshot just in case there is any need to modify it,
// any modification to it will also affect the current buffer from memory.
return snapShot, nil
}
// The function wil check if the `.dat` file is present, if it is then it will load it into memory
func UpdateHardwareSnapshotsFromFile() {
file, err := os.Open(SNAPSHOT_LIST_PATH)
if err != nil {
if os.IsNotExist(err) {
return // File does not exist, no snapshots to load
}
panic(err) // Handle error according to your error handling policy
}
defer file.Close()
decoder := gob.NewDecoder(file)
var snapshots Snapshots
if err := decoder.Decode(&snapshots); err != nil {
if err == io.EOF {
return // End of file reached
}
panic(err) // Handle error according to your error handling policy
}
snapShotBuffer = snapshots.List
fmt.Printf("Loaded %v snapshots from .dat", len(snapShotBuffer))
}
// Get the list of snapshots that have been buffered in memory
func GetHardwareSnapshot() []*HardwareSnapshot {
return snapShotBuffer
}
// Dump the current snapshot history from memory to file
func SaveSnapshotsToFile() error {
file, err := os.Create(SNAPSHOT_LIST_PATH)
if err != nil {
return err
}
defer file.Close()
encoder := gob.NewEncoder(file)
snapshots := Snapshots{List: snapShotBuffer}
if err := encoder.Encode(snapshots); err != nil {
return err
}
return nil
}
func RunService() {
// Snapshot taking routine
go func() {
for {
time.Sleep(time.Duration(config.GetConfiguration().DiskFetchFrequency) * time.Second)
data, err := TakeHardwareSnapshot()
if err != nil {
fmt.Printf("Hardware Fetch Error: %s", err)
} else {
fmt.Println("Got Snapshot for " + data.TimeStamp.Format("02/01/2006"))
for _, hdd := range data.HDD {
fmt.Printf("%s[%s]: %v\n", hdd.Model, hdd.Size, hdd.Temperature)
}
}
}
}()
// Periodic saving routine
go func() {
for {
time.Sleep(time.Duration(config.GetConfiguration().MemoryDumpFrequency) * time.Second)
err := SaveSnapshotsToFile()
if err != nil {
fmt.Printf("Memory Dump Error: %s", err)
}
}
}()
}

34
lib/web/api.go Normal file
View File

@ -0,0 +1,34 @@
package web
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"tea.chunkbyte.com/kato/drive-health/lib/hardware"
)
func setupApi(r *gin.Engine) {
api := r.Group("/v1/api")
api.GET("/disks", func(ctx *gin.Context) {
// Fetch the disk list
disks, err := hardware.GetSystemHardDrives()
if err != nil {
ctx.Error(err)
}
if ctx.Request.URL.Query().Get("temp") != "" {
for _, d := range disks {
temp := d.GetTemperature(true)
fmt.Printf("Disk Temp: %v", temp)
}
}
ctx.JSON(http.StatusOK, gin.H{
"message": "Disk List",
"disks": disks,
})
})
}

7
lib/web/frontend.go Normal file
View File

@ -0,0 +1,7 @@
package web
import "github.com/gin-gonic/gin"
func setupFrontend(r *gin.Engine) {
}

16
lib/web/health.go Normal file
View File

@ -0,0 +1,16 @@
package web
import (
"net/http"
"github.com/gin-gonic/gin"
)
func setupHealth(r *gin.Engine) {
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "Pong",
})
})
}

19
lib/web/net.go Normal file
View File

@ -0,0 +1,19 @@
package web
import (
"github.com/gin-gonic/gin"
)
func SetupRouter() *gin.Engine {
// Initialize the Gin engine
r := gin.Default()
// Setup Health Pings
setupHealth(r)
// Setup Api
setupApi(r)
// Setup Frontend
setupFrontend(r)
return r
}

47
main.go
View File

@ -1,20 +1,53 @@
package main
import (
"fmt"
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"tea.chunkbyte.com/kato/drive-health/lib/hardware"
"tea.chunkbyte.com/kato/drive-health/lib/svc"
"tea.chunkbyte.com/kato/drive-health/lib/web"
)
func main() {
// Load existing snapshots from file
svc.UpdateHardwareSnapshotsFromFile()
hardDrives, err := hardware.GetSystemHardDrives()
if err != nil {
panic(err)
router := web.SetupRouter()
srv := &http.Server{
Addr: ":8080",
Handler: router,
}
for _, hdd := range hardDrives {
fmt.Printf("%s %s [%s]: %vC\n", hdd.Model, hdd.Serial, hdd.Size, hdd.GetTemperature(true))
// Run the server in a goroutine
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
// Run the hardware service
svc.RunService()
// Setting up signal capturing
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
// Block until a signal is received
<-quit
log.Println("Shutting down server...")
// Graceful shutdown
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exiting")
}

BIN
snapshots.dat Normal file

Binary file not shown.

11
templates/index.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drive Health</title>
</head>
<body>
</body>
</html>