Moved completely to new tech
This commit is contained in:
parent
c85dab3573
commit
aa9227cda4
12 changed files with 117 additions and 77 deletions
|
@ -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 .
|
||||
|
|
24
README.md
24
README.md
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 {
|
||||
|
|
29
hub/hub.go
29
hub/hub.go
|
@ -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:
|
||||
|
|
|
@ -20,4 +20,5 @@ func (g *goDash) setupLogger() {
|
|||
|
||||
func (g *goDash) setupEchoLogging() {
|
||||
g.router.HideBanner = true
|
||||
g.router.HidePort = true
|
||||
}
|
||||
|
|
64
main.go
64
main.go
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
34
routes.go
34
routes.go
|
@ -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, "/")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue