Explorar el Código

Moved completely to new tech

Florian Hoss hace 2 años
padre
commit
aa9227cda4
Se han modificado 12 ficheros con 116 adiciones y 76 borrados
  1. 1 0
      Dockerfile
  2. 12 12
      README.md
  3. 3 3
      bookmarks/bookmarks.json
  4. 2 2
      bookmarks/types.go
  5. 18 11
      hub/hub.go
  6. 1 0
      logger.go
  7. 42 22
      main.go
  8. 20 12
      routes.go
  9. 6 3
      system/system.go
  10. 3 3
      templates/index.gohtml
  11. 2 2
      weather/types.go
  12. 6 6
      weather/weather.go

+ 1 - 0
Dockerfile

@@ -28,6 +28,7 @@ COPY --from=logo /logo/logo.txt .
 COPY entrypoint.sh .
 COPY entrypoint.sh .
 RUN chmod +x entrypoint.sh
 RUN chmod +x entrypoint.sh
 
 
+COPY --from=go /backend/bookmarks/bookmarks.json ./bookmarks/bookmarks.json
 COPY --from=go /backend/templates ./templates/
 COPY --from=go /backend/templates ./templates/
 COPY --from=go /backend/static ./static/
 COPY --from=go /backend/static ./static/
 COPY --from=go /backend/app .
 COPY --from=go /backend/app .

+ 12 - 12
README.md

@@ -44,7 +44,7 @@ The name and related link can be provided as well.
 [
 [
   {
   {
     "CATEGORY": "First",
     "CATEGORY": "First",
-    "BOOKMARKS": [
+    "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
@@ -59,7 +59,7 @@ The name and related link can be provided as well.
   },
   },
   {
   {
     "CATEGORY": "",
     "CATEGORY": "",
-    "BOOKMARKS": [
+    "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
@@ -69,7 +69,7 @@ The name and related link can be provided as well.
   },
   },
   {
   {
     "CATEGORY": "Third",
     "CATEGORY": "Third",
-    "BOOKMARKS": [
+    "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
         "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
@@ -91,10 +91,10 @@ LOG_LEVEL = "info"
 
 
 LOCATION_LATITUDE = 48.780331609463815
 LOCATION_LATITUDE = 48.780331609463815
 LOCATION_LONGITUDE = 9.177968320179422
 LOCATION_LONGITUDE = 9.177968320179422
-OPEN_WEATHER_KEY = ""
-OPEN_WEATHER_UNITS = "metric"
-OPEN_WEATHER_LANG = "en"
-OPEN_WEATHER_DIGITS = true
+WEATHER_KEY = ""
+WEATHER_UNITS = "metric"
+WEATHER_LANG = "en"
+WEATHER_DIGITS = true
 
 
 LIVE_SYSTEM = true
 LIVE_SYSTEM = true
 ```
 ```
@@ -118,18 +118,18 @@ services:
       - PAGE_URL=https://home.example.com
       - PAGE_URL=https://home.example.com
       # change title to something else
       # change title to something else
       - TITLE=GoDash
       - TITLE=GoDash
-      # available log-levels: trace,debug,info,warn,error,fatal,panic
+      # available log-levels: debug,info,warn,error,panic,fatal
       - LOG_LEVEL=info
       - LOG_LEVEL=info
       # create account here to get free key:
       # create account here to get free key:
       # https://home.openweathermap.org/users/sign_up
       # https://home.openweathermap.org/users/sign_up
       # remove to disable weather
       # remove to disable weather
-      - OPEN_WEATHER_KEY=thisIsNoFunctioningKey
+      - WEATHER_KEY=thisIsNoFunctioningKey
       # standard, metric or imperial
       # standard, metric or imperial
-      - OPEN_WEATHER_UNITS=metric
+      - WEATHER_UNITS=metric
       # https://openweathermap.org/current#multi
       # https://openweathermap.org/current#multi
-      - OPEN_WEATHER_LANG=en
+      - WEATHER_LANG=en
       # Temp is normally xx.xx, can be rounded to xx if desired
       # Temp is normally xx.xx, can be rounded to xx if desired
-      - OPEN_WEATHER_DIGITS=true
+      - WEATHER_DIGITS=true
       # location is needed for weather
       # location is needed for weather
       - LOCATION_LATITUDE=48.644929601442485
       - LOCATION_LATITUDE=48.644929601442485
       - LOCATION_LONGITUDE=9.349618464869025
       - LOCATION_LONGITUDE=9.349618464869025

+ 3 - 3
bookmarks/bookmarks.json

@@ -1,6 +1,6 @@
 [
 [
   {
   {
-    "DESCRIPTION": "First",
+    "CATEGORY": "First",
     "ENTRIES": [
     "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",
@@ -10,7 +10,7 @@
     ]
     ]
   },
   },
   {
   {
-    "DESCRIPTION": "",
+    "CATEGORY": "",
     "ENTRIES": [
     "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",
@@ -20,7 +20,7 @@
     ]
     ]
   },
   },
   {
   {
-    "DESCRIPTION": "Third",
+    "CATEGORY": "Third",
     "ENTRIES": [
     "ENTRIES": [
       {
       {
         "NAME": "Github",
         "NAME": "Github",

+ 2 - 2
bookmarks/types.go

@@ -8,8 +8,8 @@ type Bookmarks struct {
 }
 }
 
 
 type Category struct {
 type Category struct {
-	Description string  `json:"description"`
-	Entries     []Entry `json:"entries"`
+	Category string  `json:"category"`
+	Entries  []Entry `json:"entries"`
 }
 }
 
 
 type Entry struct {
 type Entry struct {

+ 18 - 11
hub/hub.go

@@ -1,5 +1,7 @@
 package hub
 package hub
 
 
+import "go.uber.org/zap"
+
 const (
 const (
 	Weather WsType = iota
 	Weather WsType = iota
 	System
 	System
@@ -15,26 +17,29 @@ type (
 	}
 	}
 
 
 	Hub struct {
 	Hub struct {
-		Notifier          NotifierChan
+		LiveInformationCh chan Message
 		NewClients        chan NotifierChan
 		NewClients        chan NotifierChan
 		ClosingClients    chan NotifierChan
 		ClosingClients    chan NotifierChan
+		logger            *zap.SugaredLogger
+		notifier          NotifierChan
 		clients           map[NotifierChan]struct{}
 		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{})
+func NewHub(logger *zap.SugaredLogger) *Hub {
+	hub := Hub{
+		LiveInformationCh: make(chan Message),
+		NewClients:        make(chan NotifierChan),
+		ClosingClients:    make(chan NotifierChan),
+		logger:            logger,
+		notifier:          make(NotifierChan),
+		clients:           make(map[NotifierChan]struct{}),
+	}
 	go hub.listen()
 	go hub.listen()
 	go func() {
 	go func() {
 		for {
 		for {
 			if msg, ok := <-hub.LiveInformationCh; ok {
 			if msg, ok := <-hub.LiveInformationCh; ok {
-				hub.Notifier <- msg
+				hub.notifier <- msg
 			}
 			}
 		}
 		}
 	}()
 	}()
@@ -46,9 +51,11 @@ func (h *Hub) listen() {
 		select {
 		select {
 		case s := <-h.NewClients:
 		case s := <-h.NewClients:
 			h.clients[s] = struct{}{}
 			h.clients[s] = struct{}{}
+			h.logger.Debugw("websocket connection added", "total clients", len(h.clients))
 		case s := <-h.ClosingClients:
 		case s := <-h.ClosingClients:
 			delete(h.clients, s)
 			delete(h.clients, s)
-		case event := <-h.Notifier:
+			h.logger.Debugw("websocket connection removed", "total clients", len(h.clients))
+		case event := <-h.notifier:
 			for client := range h.clients {
 			for client := range h.clients {
 				select {
 				select {
 				case client <- event:
 				case client <- event:

+ 1 - 0
logger.go

@@ -20,4 +20,5 @@ func (g *goDash) setupLogger() {
 
 
 func (g *goDash) setupEchoLogging() {
 func (g *goDash) setupEchoLogging() {
 	g.router.HideBanner = true
 	g.router.HideBanner = true
+	g.router.HidePort = true
 }
 }

+ 42 - 22
main.go

@@ -1,6 +1,7 @@
 package main
 package main
 
 
 import (
 import (
+	"context"
 	"fmt"
 	"fmt"
 	"github.com/caarlos0/env/v6"
 	"github.com/caarlos0/env/v6"
 	"github.com/labstack/echo/v4"
 	"github.com/labstack/echo/v4"
@@ -13,6 +14,9 @@ import (
 	"html/template"
 	"html/template"
 	"net/http"
 	"net/http"
 	"net/url"
 	"net/url"
+	"os"
+	"os/signal"
+	"time"
 )
 )
 
 
 type goDash struct {
 type goDash struct {
@@ -20,6 +24,13 @@ type goDash struct {
 	logger *zap.SugaredLogger
 	logger *zap.SugaredLogger
 	hub    *hub.Hub
 	hub    *hub.Hub
 	config config
 	config config
+	info   info
+}
+
+type info struct {
+	weather   *weather.Weather
+	bookmarks *bookmarks.Bookmarks
+	system    *system.System
 }
 }
 
 
 type config struct {
 type config struct {
@@ -30,8 +41,17 @@ type config struct {
 	LiveSystem bool    `env:"LIVE_SYSTEM" envDefault:"true"`
 	LiveSystem bool    `env:"LIVE_SYSTEM" envDefault:"true"`
 }
 }
 
 
+func (g *goDash) createInfoServices() {
+	g.hub = hub.NewHub(g.logger)
+	g.info = info{
+		weather:   weather.NewWeatherService(g.logger, g.hub),
+		bookmarks: bookmarks.NewBookmarkService(g.logger),
+		system:    system.NewSystemService(g.config.LiveSystem, g.logger, g.hub),
+	}
+}
+
 func main() {
 func main() {
-	g := goDash{router: echo.New(), hub: hub.NewHub()}
+	g := goDash{router: echo.New()}
 	g.router.Renderer = &TemplateRenderer{
 	g.router.Renderer = &TemplateRenderer{
 		templates: template.Must(template.ParseGlob("templates/*.gohtml")),
 		templates: template.Must(template.ParseGlob("templates/*.gohtml")),
 	}
 	}
@@ -40,35 +60,35 @@ func main() {
 	}
 	}
 
 
 	g.setupLogger()
 	g.setupLogger()
-	defer g.logger.Sync()
+	defer func(logger *zap.SugaredLogger) {
+		_ = logger.Sync()
+	}(g.logger)
 	g.setupEchoLogging()
 	g.setupEchoLogging()
 
 
 	g.router.Use(middleware.Recover())
 	g.router.Use(middleware.Recover())
 	g.router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5}))
 	g.router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5}))
 	g.router.Pre(middleware.RemoveTrailingSlash())
 	g.router.Pre(middleware.RemoveTrailingSlash())
 
 
-	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, g.hub)
-	}
-
-	g.router.GET("/", func(c echo.Context) error {
-		return c.Render(http.StatusOK, "index.gohtml", map[string]interface{}{
-			"Title":     g.config.Title,
-			"Weather":   w.CurrentWeather,
-			"Bookmarks": b.Categories,
-			"System":    s.CurrentSystem,
-		})
-	})
+	g.createInfoServices()
+	g.router.GET("/", g.index)
 	g.router.GET("/ws", g.ws)
 	g.router.GET("/ws", g.ws)
+	g.router.GET("/robots.txt", robots)
 	g.router.Static("/static", "static")
 	g.router.Static("/static", "static")
 	g.router.Static("/storage/icons", "storage/icons")
 	g.router.Static("/storage/icons", "storage/icons")
+	g.router.RouteNotFound("/*", redirectHome)
 
 
-	g.router.GET("/robots.txt", func(c echo.Context) error {
-		return c.String(http.StatusOK, "User-agent: *\nDisallow: /")
-	})
-
-	g.router.Logger.Fatal(g.router.Start(fmt.Sprintf(":%d", g.config.Port)))
+	go func() {
+		if err := g.router.Start(fmt.Sprintf(":%d", g.config.Port)); err != nil && err != http.ErrServerClosed {
+			g.logger.Fatal("shutting down the server")
+		}
+	}()
+	g.logger.Infof("running on %s:%d", "http://localhost", g.config.Port)
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, os.Interrupt)
+	<-quit
+	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
+	defer cancel()
+	if err := g.router.Shutdown(ctx); err != nil {
+		g.logger.Fatal(err)
+	}
 }
 }

+ 20 - 12
routes.go

@@ -1,23 +1,29 @@
 package main
 package main
 
 
 import (
 import (
-	"errors"
 	"github.com/gorilla/websocket"
 	"github.com/gorilla/websocket"
 	"github.com/labstack/echo/v4"
 	"github.com/labstack/echo/v4"
 	"godash/hub"
 	"godash/hub"
+	"net/http"
 )
 )
 
 
 var (
 var (
 	upgrader = websocket.Upgrader{}
 	upgrader = websocket.Upgrader{}
 )
 )
 
 
+func (g *goDash) index(c echo.Context) error {
+	return c.Render(http.StatusOK, "index.gohtml", map[string]interface{}{
+		"Title":      g.config.Title,
+		"Weather":    g.info.weather.CurrentWeather,
+		"Categories": g.info.bookmarks.Categories,
+		"System":     g.info.system.CurrentSystem,
+	})
+}
+
 func (g *goDash) ws(c echo.Context) error {
 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)
 	ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil)
 	if err != nil {
 	if err != nil {
-		return err
+		return nil
 	}
 	}
 	messageChan := make(hub.NotifierChan)
 	messageChan := make(hub.NotifierChan)
 	g.hub.NewClients <- messageChan
 	g.hub.NewClients <- messageChan
@@ -27,7 +33,6 @@ func (g *goDash) ws(c echo.Context) error {
 	}()
 	}()
 
 
 	go func() {
 	go func() {
-		defer ws.Close()
 		for {
 		for {
 			_, _, err := ws.ReadMessage()
 			_, _, err := ws.ReadMessage()
 			if err != nil {
 			if err != nil {
@@ -40,17 +45,20 @@ func (g *goDash) ws(c echo.Context) error {
 		select {
 		select {
 		case msg, ok := <-messageChan:
 		case msg, ok := <-messageChan:
 			if !ok {
 			if !ok {
-				err := ws.WriteMessage(websocket.CloseMessage, []byte{})
-				if err != nil {
-					return err
-				}
-				return err
+				_ = ws.WriteMessage(websocket.CloseMessage, []byte{})
 			}
 			}
 			err := ws.WriteJSON(msg)
 			err := ws.WriteJSON(msg)
 			if err != nil {
 			if err != nil {
-				return err
+				return nil
 			}
 			}
 		}
 		}
 	}
 	}
+}
+
+func robots(c echo.Context) error {
+	return c.String(http.StatusOK, "User-agent: *\nDisallow: /")
+}
 
 
+func redirectHome(c echo.Context) error {
+	return c.Redirect(http.StatusMovedPermanently, "/")
 }
 }

+ 6 - 3
system/system.go

@@ -6,9 +6,12 @@ import (
 	"time"
 	"time"
 )
 )
 
 
-func NewSystemService(logging *zap.SugaredLogger, hub *hub.Hub) *System {
-	s := System{log: logging, hub: hub}
-	s.Initialize()
+func NewSystemService(enabled bool, logging *zap.SugaredLogger, hub *hub.Hub) *System {
+	var s System
+	if enabled {
+		s = System{log: logging, hub: hub}
+		s.Initialize()
+	}
 	return &s
 	return &s
 }
 }
 
 

+ 3 - 3
templates/index.gohtml

@@ -121,10 +121,10 @@
 
 
 
 
   <div class="grid gap-4">
   <div class="grid gap-4">
-    {{ range .Bookmarks }}
+    {{ range .Categories }}
       <div class="grid gap-1">
       <div class="grid gap-1">
-        {{ if .Description }}
-          <div class="text-lg text-primary select-none truncate">{{ .Description }}</div>
+        {{ if .Category }}
+          <div class="text-lg text-primary select-none truncate">{{ .Category }}</div>
         {{ end }}
         {{ end }}
         <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4">
         <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4">
           {{ range .Entries }}
           {{ range .Entries }}

+ 2 - 2
weather/types.go

@@ -5,7 +5,7 @@ import (
 	"godash/hub"
 	"godash/hub"
 )
 )
 
 
-type weather struct {
+type Weather struct {
 	CurrentWeather OpenWeather
 	CurrentWeather OpenWeather
 	hub            *hub.Hub
 	hub            *hub.Hub
 	config         config
 	config         config
@@ -32,7 +32,7 @@ type OpenWeather struct {
 }
 }
 
 
 type OpenWeatherApiResponse struct {
 type OpenWeatherApiResponse struct {
-	Weather []OpenWeatherApiWeather `json:"weather"`
+	Weather []OpenWeatherApiWeather `json:"Weather"`
 	Main    OpenWeatherApiMain      `json:"main"`
 	Main    OpenWeatherApiMain      `json:"main"`
 	Sys     OpenWeatherApiSys       `json:"sys"`
 	Sys     OpenWeatherApiSys       `json:"sys"`
 }
 }

+ 6 - 6
weather/weather.go

@@ -12,8 +12,8 @@ import (
 	"time"
 	"time"
 )
 )
 
 
-func NewWeatherService(logging *zap.SugaredLogger, hub *hub.Hub) *weather {
-	var w = weather{log: logging, hub: hub}
+func NewWeatherService(logging *zap.SugaredLogger, hub *hub.Hub) *Weather {
+	var w = Weather{log: logging, hub: hub}
 	if err := env.Parse(&w.config); err != nil {
 	if err := env.Parse(&w.config); err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
@@ -24,7 +24,7 @@ func NewWeatherService(logging *zap.SugaredLogger, hub *hub.Hub) *weather {
 	return &w
 	return &w
 }
 }
 
 
-func (w *weather) setWeatherUnits() {
+func (w *Weather) setWeatherUnits() {
 	if w.config.Units == "imperial" {
 	if w.config.Units == "imperial" {
 		w.CurrentWeather.Units = "°F"
 		w.CurrentWeather.Units = "°F"
 	} else {
 	} else {
@@ -32,7 +32,7 @@ func (w *weather) setWeatherUnits() {
 	}
 	}
 }
 }
 
 
-func (w *weather) copyWeatherValues(weatherResp *OpenWeatherApiResponse) {
+func (w *Weather) copyWeatherValues(weatherResp *OpenWeatherApiResponse) {
 	myTime := time.Unix(weatherResp.Sys.Sunrise, 0)
 	myTime := time.Unix(weatherResp.Sys.Sunrise, 0)
 	w.CurrentWeather.Sunrise = myTime.Format("15:04")
 	w.CurrentWeather.Sunrise = myTime.Format("15:04")
 	myTime = time.Unix(weatherResp.Sys.Sunset, 0)
 	myTime = time.Unix(weatherResp.Sys.Sunset, 0)
@@ -47,7 +47,7 @@ func (w *weather) copyWeatherValues(weatherResp *OpenWeatherApiResponse) {
 	w.CurrentWeather.Humidity = weatherResp.Main.Humidity
 	w.CurrentWeather.Humidity = weatherResp.Main.Humidity
 }
 }
 
 
-func (w *weather) updateWeather(interval time.Duration) {
+func (w *Weather) updateWeather(interval time.Duration) {
 	var weatherResponse OpenWeatherApiResponse
 	var weatherResponse OpenWeatherApiResponse
 	for {
 	for {
 		resp, err := http.Get(fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&appid=%s&units=%s&lang=%s",
 		resp, err := http.Get(fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&appid=%s&units=%s&lang=%s",
@@ -57,7 +57,7 @@ func (w *weather) updateWeather(interval time.Duration) {
 			w.config.Units,
 			w.config.Units,
 			w.config.Lang))
 			w.config.Lang))
 		if err != nil || resp.StatusCode != 200 {
 		if err != nil || resp.StatusCode != 200 {
-			w.log.Error("weather cannot be updated, please check OPEN_WEATHER_KEY")
+			w.log.Error("weather cannot be updated, please check WEATHER_KEY")
 		} else {
 		} else {
 			body, _ := io.ReadAll(resp.Body)
 			body, _ := io.ReadAll(resp.Body)
 			err = json.Unmarshal(body, &weatherResponse)
 			err = json.Unmarshal(body, &weatherResponse)