فهرست منبع

Websocket working again

Florian Hoss 2 سال پیش
والد
کامیت
c85dab3573
13فایلهای تغییر یافته به همراه166 افزوده شده و 26 حذف شده
  1. 1 0
      go.mod
  2. 2 0
      go.sum
  3. 62 0
      hub/hub.go
  4. 7 4
      main.go
  5. 56 0
      routes.go
  6. 1 1
      system/cpu.go
  7. 2 2
      system/disk.go
  8. 2 2
      system/ram.go
  9. 9 7
      system/system.go
  10. 10 2
      system/types.go
  11. 5 5
      system/uptime.go
  12. 5 1
      weather/types.go
  13. 4 2
      weather/weather.go

+ 1 - 0
go.mod

@@ -6,6 +6,7 @@ require (
 	github.com/caarlos0/env/v6 v6.10.1
 	github.com/dariubs/percent v1.0.0
 	github.com/fsnotify/fsnotify v1.6.0
+	github.com/gorilla/websocket v1.5.0
 	github.com/labstack/echo/v4 v4.9.1
 	github.com/shirou/gopsutil/v3 v3.22.11
 	github.com/unjx-de/go-folder v1.0.7

+ 2 - 0
go.sum

@@ -16,6 +16,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
 github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
 github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=

+ 62 - 0
hub/hub.go

@@ -0,0 +1,62 @@
+package hub
+
+const (
+	Weather WsType = iota
+	System
+)
+
+type (
+	NotifierChan chan Message
+
+	WsType  uint
+	Message struct {
+		WsType  WsType      `json:"ws_type"`
+		Message interface{} `json:"message"`
+	}
+
+	Hub struct {
+		Notifier          NotifierChan
+		NewClients        chan NotifierChan
+		ClosingClients    chan NotifierChan
+		clients           map[NotifierChan]struct{}
+		LiveInformationCh chan Message
+	}
+)
+
+func NewHub() *Hub {
+	hub := Hub{}
+	hub.LiveInformationCh = make(chan Message)
+	hub.Notifier = make(NotifierChan)
+	hub.NewClients = make(chan NotifierChan)
+	hub.ClosingClients = make(chan NotifierChan)
+	hub.clients = make(map[NotifierChan]struct{})
+	go hub.listen()
+	go func() {
+		for {
+			if msg, ok := <-hub.LiveInformationCh; ok {
+				hub.Notifier <- msg
+			}
+		}
+	}()
+	return &hub
+}
+
+func (h *Hub) listen() {
+	for {
+		select {
+		case s := <-h.NewClients:
+			h.clients[s] = struct{}{}
+		case s := <-h.ClosingClients:
+			delete(h.clients, s)
+		case event := <-h.Notifier:
+			for client := range h.clients {
+				select {
+				case client <- event:
+				default:
+					close(client)
+					delete(h.clients, client)
+				}
+			}
+		}
+	}
+}

+ 7 - 4
main.go

@@ -7,6 +7,7 @@ import (
 	"github.com/labstack/echo/v4/middleware"
 	"go.uber.org/zap"
 	"godash/bookmarks"
+	"godash/hub"
 	"godash/system"
 	"godash/weather"
 	"html/template"
@@ -17,6 +18,7 @@ import (
 type goDash struct {
 	router *echo.Echo
 	logger *zap.SugaredLogger
+	hub    *hub.Hub
 	config config
 }
 
@@ -29,7 +31,7 @@ type config struct {
 }
 
 func main() {
-	g := goDash{router: echo.New()}
+	g := goDash{router: echo.New(), hub: hub.NewHub()}
 	g.router.Renderer = &TemplateRenderer{
 		templates: template.Must(template.ParseGlob("templates/*.gohtml")),
 	}
@@ -45,11 +47,11 @@ func main() {
 	g.router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5}))
 	g.router.Pre(middleware.RemoveTrailingSlash())
 
-	w := weather.NewWeatherService(g.logger)
+	w := weather.NewWeatherService(g.logger, g.hub)
 	b := bookmarks.NewBookmarkService(g.logger)
 	var s *system.System
 	if g.config.LiveSystem {
-		s = system.NewSystemService(g.logger)
+		s = system.NewSystemService(g.logger, g.hub)
 	}
 
 	g.router.GET("/", func(c echo.Context) error {
@@ -57,9 +59,10 @@ func main() {
 			"Title":     g.config.Title,
 			"Weather":   w.CurrentWeather,
 			"Bookmarks": b.Categories,
-			"System":    s,
+			"System":    s.CurrentSystem,
 		})
 	})
+	g.router.GET("/ws", g.ws)
 	g.router.Static("/static", "static")
 	g.router.Static("/storage/icons", "storage/icons")
 

+ 56 - 0
routes.go

@@ -0,0 +1,56 @@
+package main
+
+import (
+	"errors"
+	"github.com/gorilla/websocket"
+	"github.com/labstack/echo/v4"
+	"godash/hub"
+)
+
+var (
+	upgrader = websocket.Upgrader{}
+)
+
+func (g *goDash) ws(c echo.Context) error {
+	if g.config.PageUrl.String() != c.Request().Header.Get("Origin") {
+		return errors.New("bad request")
+	}
+	ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
+	if err != nil {
+		return err
+	}
+	messageChan := make(hub.NotifierChan)
+	g.hub.NewClients <- messageChan
+	defer func() {
+		g.hub.ClosingClients <- messageChan
+		ws.Close()
+	}()
+
+	go func() {
+		defer ws.Close()
+		for {
+			_, _, err := ws.ReadMessage()
+			if err != nil {
+				break
+			}
+		}
+	}()
+
+	for {
+		select {
+		case msg, ok := <-messageChan:
+			if !ok {
+				err := ws.WriteMessage(websocket.CloseMessage, []byte{})
+				if err != nil {
+					return err
+				}
+				return err
+			}
+			err := ws.WriteJSON(msg)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+}

+ 1 - 1
system/cpu.go

@@ -24,5 +24,5 @@ func (s *System) liveCpu() {
 	if err != nil {
 		return
 	}
-	s.Live.CPU = math.RoundToEven(p[0])
+	s.CurrentSystem.Live.CPU = math.RoundToEven(p[0])
 }

+ 2 - 2
system/disk.go

@@ -24,6 +24,6 @@ func (s *System) liveDisk() {
 	if err != nil {
 		return
 	}
-	s.Live.Disk.Value = readableSize(d.Used)
-	s.Live.Disk.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(d.Used), float64(d.Total)))
+	s.CurrentSystem.Live.Disk.Value = readableSize(d.Used)
+	s.CurrentSystem.Live.Disk.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(d.Used), float64(d.Total)))
 }

+ 2 - 2
system/ram.go

@@ -26,6 +26,6 @@ func (s *System) liveRam() {
 	if err != nil {
 		return
 	}
-	s.Live.Ram.Value = readableSize(r.Used)
-	s.Live.Ram.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(r.Used), float64(r.Total)))
+	s.CurrentSystem.Live.Ram.Value = readableSize(r.Used)
+	s.CurrentSystem.Live.Ram.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(r.Used), float64(r.Total)))
 }

+ 9 - 7
system/system.go

@@ -2,11 +2,12 @@ package system
 
 import (
 	"go.uber.org/zap"
+	"godash/hub"
 	"time"
 )
 
-func NewSystemService(logging *zap.SugaredLogger) *System {
-	s := System{log: logging}
+func NewSystemService(logging *zap.SugaredLogger, hub *hub.Hub) *System {
+	s := System{log: logging, hub: hub}
 	s.Initialize()
 	return &s
 }
@@ -17,15 +18,16 @@ func (s *System) UpdateLiveInformation() {
 		s.liveRam()
 		s.liveDisk()
 		s.uptime()
+		s.hub.LiveInformationCh <- hub.Message{WsType: hub.System, Message: s.CurrentSystem.Live}
 		time.Sleep(1 * time.Second)
 	}
 }
 
 func (s *System) Initialize() {
-	s.Static.Host = staticHost()
-	s.Static.CPU = staticCpu()
-	s.Static.Ram = staticRam()
-	s.Static.Disk = staticDisk()
+	s.CurrentSystem.Static.Host = staticHost()
+	s.CurrentSystem.Static.CPU = staticCpu()
+	s.CurrentSystem.Static.Ram = staticRam()
+	s.CurrentSystem.Static.Disk = staticDisk()
 	go s.UpdateLiveInformation()
-	s.log.Debugw("system updated", "cpu", s.Static.CPU.Name, "arch", s.Static.Host.Architecture)
+	s.log.Debugw("system updated", "cpu", s.CurrentSystem.Static.CPU.Name, "arch", s.CurrentSystem.Static.Host.Architecture)
 }

+ 10 - 2
system/types.go

@@ -1,9 +1,17 @@
 package system
 
-import "go.uber.org/zap"
+import (
+	"go.uber.org/zap"
+	"godash/hub"
+)
 
 type System struct {
-	log    *zap.SugaredLogger
+	hub           *hub.Hub
+	log           *zap.SugaredLogger
+	CurrentSystem CurrentSystem
+}
+
+type CurrentSystem struct {
 	Live   LiveInformation   `json:"live"`
 	Static StaticInformation `json:"static"`
 }

+ 5 - 5
system/uptime.go

@@ -9,9 +9,9 @@ func (s *System) uptime() {
 	if err != nil {
 		return
 	}
-	s.Live.Uptime.Days = i.Uptime / 84600
-	s.Live.Uptime.Hours = uint16((i.Uptime % 86400) / 3600)
-	s.Live.Uptime.Minutes = uint16(((i.Uptime % 86400) % 3600) / 60)
-	s.Live.Uptime.Seconds = uint16(((i.Uptime % 86400) % 3600) % 60)
-	s.Live.Uptime.Percentage = float32((s.Live.Uptime.Minutes*100)+s.Live.Uptime.Seconds) / 60
+	s.CurrentSystem.Live.Uptime.Days = i.Uptime / 84600
+	s.CurrentSystem.Live.Uptime.Hours = uint16((i.Uptime % 86400) / 3600)
+	s.CurrentSystem.Live.Uptime.Minutes = uint16(((i.Uptime % 86400) % 3600) / 60)
+	s.CurrentSystem.Live.Uptime.Seconds = uint16(((i.Uptime % 86400) % 3600) % 60)
+	s.CurrentSystem.Live.Uptime.Percentage = float32((s.CurrentSystem.Live.Uptime.Minutes*100)+s.CurrentSystem.Live.Uptime.Seconds) / 60
 }

+ 5 - 1
weather/types.go

@@ -1,9 +1,13 @@
 package weather
 
-import "go.uber.org/zap"
+import (
+	"go.uber.org/zap"
+	"godash/hub"
+)
 
 type weather struct {
 	CurrentWeather OpenWeather
+	hub            *hub.Hub
 	config         config
 	log            *zap.SugaredLogger
 }

+ 4 - 2
weather/weather.go

@@ -5,14 +5,15 @@ import (
 	"fmt"
 	"github.com/caarlos0/env/v6"
 	"go.uber.org/zap"
+	"godash/hub"
 	"io"
 	"math"
 	"net/http"
 	"time"
 )
 
-func NewWeatherService(logging *zap.SugaredLogger) *weather {
-	var w = weather{log: logging}
+func NewWeatherService(logging *zap.SugaredLogger, hub *hub.Hub) *weather {
+	var w = weather{log: logging, hub: hub}
 	if err := env.Parse(&w.config); err != nil {
 		panic(err)
 	}
@@ -67,6 +68,7 @@ func (w *weather) updateWeather(interval time.Duration) {
 				w.log.Debugw("weather updated", "temp", w.CurrentWeather.Temp)
 			}
 			resp.Body.Close()
+			w.hub.LiveInformationCh <- hub.Message{WsType: hub.Weather, Message: w.CurrentWeather}
 		}
 		time.Sleep(interval)
 	}