mirror of
https://github.com/JustKato/drive-health.git
synced 2026-02-27 06:17:00 +02:00
Implemented frontend
+ Graph Generation as images for frontend performance + A new decent style
This commit is contained in:
@@ -67,8 +67,6 @@ func GetSystemHardDrives(db *gorm.DB, olderThan *time.Time, newerThan *time.Time
|
||||
q := db.Where("serial = ? AND model = ? AND type = ?", sysHDD.Serial, sysHDD.Model, sysHDD.Type)
|
||||
|
||||
if newerThan != nil && olderThan != nil {
|
||||
fmt.Printf("\nNewer Than: %s\n", newerThan)
|
||||
fmt.Printf("Older Than: %s\n\n", olderThan)
|
||||
q = q.Preload("Temperatures", "time_stamp < ? AND time_stamp > ?", newerThan, olderThan)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/wcharczuk/go-chart/v2"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"tea.chunkbyte.com/kato/drive-health/lib/config"
|
||||
@@ -66,3 +68,114 @@ func RunLoggerService() {
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func GetDiskGraphImage(hddID int, newerThan *time.Time, olderThan *time.Time) (*bytes.Buffer, error) {
|
||||
var hdd hardware.HardDrive
|
||||
// Fetch by a combination of fields
|
||||
q := db.Where("id = ?", hddID)
|
||||
|
||||
if newerThan == nil && olderThan == nil {
|
||||
q = q.Preload("Temperatures")
|
||||
} else {
|
||||
q = q.Preload("Temperatures", "time_stamp < ? AND time_stamp > ?", newerThan, olderThan)
|
||||
}
|
||||
|
||||
// Query for the instance
|
||||
result := q.First(&hdd)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
// Prepare slices for X (time) and Y (temperature) values
|
||||
var xValues []time.Time
|
||||
var yValues []float64
|
||||
for _, temp := range hdd.Temperatures {
|
||||
xValues = append(xValues, temp.TimeStamp)
|
||||
yValues = append(yValues, float64(temp.Temperature))
|
||||
}
|
||||
|
||||
// Allocate a buffer for the graph image
|
||||
graphImageBuffer := bytes.NewBuffer([]byte{})
|
||||
|
||||
// TODO: Graph dark theme
|
||||
|
||||
// Generate the chart
|
||||
graph := chart.Chart{
|
||||
Title: fmt.Sprintf("%s:%s[%s]", hdd.Name, hdd.Serial, hdd.Size),
|
||||
TitleStyle: chart.Style{
|
||||
FontSize: 14,
|
||||
},
|
||||
|
||||
// TODO: Implement customizable sizing
|
||||
Width: 1280,
|
||||
|
||||
Background: chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 20, Right: 20, Bottom: 20, Left: 20,
|
||||
},
|
||||
},
|
||||
|
||||
XAxis: chart.XAxis{
|
||||
Name: "Time",
|
||||
ValueFormatter: func(v interface{}) string {
|
||||
if ts, isValidTime := v.(float64); isValidTime {
|
||||
t := time.Unix(int64(ts/1e9), 0)
|
||||
|
||||
return t.Format("Jan 2 2006, 15:04")
|
||||
}
|
||||
|
||||
return ""
|
||||
},
|
||||
Style: chart.Style{},
|
||||
GridMajorStyle: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray,
|
||||
StrokeWidth: 0.5,
|
||||
},
|
||||
GridMinorStyle: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray.WithAlpha(64),
|
||||
StrokeWidth: 0.25,
|
||||
},
|
||||
},
|
||||
YAxis: chart.YAxis{
|
||||
Name: "Temperature (C)",
|
||||
Style: chart.Style{},
|
||||
GridMajorStyle: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray,
|
||||
StrokeWidth: 0.5,
|
||||
},
|
||||
GridMinorStyle: chart.Style{
|
||||
StrokeColor: chart.ColorAlternateGray.WithAlpha(64),
|
||||
StrokeWidth: 0.25,
|
||||
},
|
||||
},
|
||||
Series: []chart.Series{
|
||||
chart.TimeSeries{
|
||||
Name: "Temperature",
|
||||
XValues: xValues,
|
||||
YValues: yValues,
|
||||
Style: chart.Style{
|
||||
StrokeColor: chart.ColorCyan,
|
||||
StrokeWidth: 2.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Add a legend to the chart
|
||||
graph.Elements = []chart.Renderable{
|
||||
chart.Legend(&graph, chart.Style{
|
||||
Padding: chart.Box{
|
||||
Top: 5, Right: 5, Bottom: 5, Left: 5,
|
||||
},
|
||||
FontSize: 10,
|
||||
}),
|
||||
}
|
||||
|
||||
// Render the chart into the byte buffer
|
||||
err := graph.Render(chart.PNG, graphImageBuffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return graphImageBuffer, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -12,6 +13,44 @@ import (
|
||||
func setupApi(r *gin.Engine) {
|
||||
api := r.Group("/api/v1")
|
||||
|
||||
api.GET("/disks/:diskid/chart", func(ctx *gin.Context) {
|
||||
diskIDString := ctx.Param("diskid")
|
||||
diskId, err := strconv.Atoi(diskIDString)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(400, gin.H{
|
||||
"error": err.Error(),
|
||||
"message": "Invalid Disk ID",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
graphData, err := svc.GetDiskGraphImage(diskId, nil, nil)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
"message": "Graph generation issue",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Set the content type header
|
||||
ctx.Writer.Header().Set("Content-Type", "image/png")
|
||||
|
||||
// Write the image data to the response
|
||||
ctx.Writer.WriteHeader(http.StatusOK)
|
||||
_, err = graphData.WriteTo(ctx.Writer)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
"error": err.Error(),
|
||||
"message": "Write error",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
api.GET("/disks", func(ctx *gin.Context) {
|
||||
|
||||
olderThan := time.Now().Add(time.Minute * time.Duration(10) * -1)
|
||||
|
||||
Reference in New Issue
Block a user