Moved completely to new tech

This commit is contained in:
Florian Hoss 2022-12-19 11:03:56 +01:00
parent c85dab3573
commit aa9227cda4
12 changed files with 117 additions and 77 deletions

View file

@ -28,6 +28,7 @@ COPY --from=logo /logo/logo.txt .
COPY 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/static ./static/
COPY --from=go /backend/app .

View file

@ -44,7 +44,7 @@ The name and related link can be provided as well.
[
{
"CATEGORY": "First",
"BOOKMARKS": [
"ENTRIES": [
{
"NAME": "Github",
"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": "",
"BOOKMARKS": [
"ENTRIES": [
{
"NAME": "Github",
"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",
"BOOKMARKS": [
"ENTRIES": [
{
"NAME": "Github",
"ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
@ -91,10 +91,10 @@ LOG_LEVEL = "info"
LOCATION_LATITUDE = 48.780331609463815
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
```
@ -118,18 +118,18 @@ services:
- PAGE_URL=https://home.example.com
# change title to something else
- TITLE=GoDash
# available log-levels: trace,debug,info,warn,error,fatal,panic
# available log-levels: debug,info,warn,error,panic,fatal
- LOG_LEVEL=info
# create account here to get free key:
# https://home.openweathermap.org/users/sign_up
# remove to disable weather
- OPEN_WEATHER_KEY=thisIsNoFunctioningKey
- WEATHER_KEY=thisIsNoFunctioningKey
# standard, metric or imperial
- OPEN_WEATHER_UNITS=metric
- WEATHER_UNITS=metric
# https://openweathermap.org/current#multi
- OPEN_WEATHER_LANG=en
- WEATHER_LANG=en
# 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_LATITUDE=48.644929601442485
- LOCATION_LONGITUDE=9.349618464869025

View file

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

View file

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

View file

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

View file

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

64
main.go
View file

@ -1,6 +1,7 @@
package main
import (
"context"
"fmt"
"github.com/caarlos0/env/v6"
"github.com/labstack/echo/v4"
@ -13,6 +14,9 @@ import (
"html/template"
"net/http"
"net/url"
"os"
"os/signal"
"time"
)
type goDash struct {
@ -20,6 +24,13 @@ type goDash struct {
logger *zap.SugaredLogger
hub *hub.Hub
config config
info info
}
type info struct {
weather *weather.Weather
bookmarks *bookmarks.Bookmarks
system *system.System
}
type config struct {
@ -30,8 +41,17 @@ type config struct {
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() {
g := goDash{router: echo.New(), hub: hub.NewHub()}
g := goDash{router: echo.New()}
g.router.Renderer = &TemplateRenderer{
templates: template.Must(template.ParseGlob("templates/*.gohtml")),
}
@ -40,35 +60,35 @@ func main() {
}
g.setupLogger()
defer g.logger.Sync()
defer func(logger *zap.SugaredLogger) {
_ = logger.Sync()
}(g.logger)
g.setupEchoLogging()
g.router.Use(middleware.Recover())
g.router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5}))
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("/robots.txt", robots)
g.router.Static("/static", "static")
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)
}
}

View file

@ -1,23 +1,29 @@
package main
import (
"errors"
"github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
"godash/hub"
"net/http"
)
var (
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 {
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
return nil
}
messageChan := make(hub.NotifierChan)
g.hub.NewClients <- messageChan
@ -27,7 +33,6 @@ func (g *goDash) ws(c echo.Context) error {
}()
go func() {
defer ws.Close()
for {
_, _, err := ws.ReadMessage()
if err != nil {
@ -40,17 +45,20 @@ func (g *goDash) ws(c echo.Context) error {
select {
case msg, ok := <-messageChan:
if !ok {
err := ws.WriteMessage(websocket.CloseMessage, []byte{})
if err != nil {
return err
}
return err
_ = ws.WriteMessage(websocket.CloseMessage, []byte{})
}
err := ws.WriteJSON(msg)
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, "/")
}

View file

@ -6,9 +6,12 @@ import (
"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
}

View file

@ -121,10 +121,10 @@
<div class="grid gap-4">
{{ range .Bookmarks }}
{{ range .Categories }}
<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 }}
<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 }}

View file

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

View file

@ -12,8 +12,8 @@ import (
"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 {
panic(err)
}
@ -24,7 +24,7 @@ func NewWeatherService(logging *zap.SugaredLogger, hub *hub.Hub) *weather {
return &w
}
func (w *weather) setWeatherUnits() {
func (w *Weather) setWeatherUnits() {
if w.config.Units == "imperial" {
w.CurrentWeather.Units = "°F"
} 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)
w.CurrentWeather.Sunrise = myTime.Format("15:04")
myTime = time.Unix(weatherResp.Sys.Sunset, 0)
@ -47,7 +47,7 @@ func (w *weather) copyWeatherValues(weatherResp *OpenWeatherApiResponse) {
w.CurrentWeather.Humidity = weatherResp.Main.Humidity
}
func (w *weather) updateWeather(interval time.Duration) {
func (w *Weather) updateWeather(interval time.Duration) {
var weatherResponse OpenWeatherApiResponse
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",
@ -57,7 +57,7 @@ func (w *weather) updateWeather(interval time.Duration) {
w.config.Units,
w.config.Lang))
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 {
body, _ := io.ReadAll(resp.Body)
err = json.Unmarshal(body, &weatherResponse)