mirror of
https://github.com/glanceapp/glance.git
synced 2024-11-22 08:23:52 +01:00
Allow widgets to handle HTTP requests
This commit is contained in:
parent
c041197f3f
commit
795caa5d9d
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -24,6 +25,7 @@ type Application struct {
|
|||||||
Version string
|
Version string
|
||||||
Config Config
|
Config Config
|
||||||
slugToPage map[string]*Page
|
slugToPage map[string]*Page
|
||||||
|
widgetByID map[uint64]widget.Widget
|
||||||
}
|
}
|
||||||
|
|
||||||
type Theme struct {
|
type Theme struct {
|
||||||
@ -106,16 +108,24 @@ func NewApplication(config *Config) (*Application, error) {
|
|||||||
Version: buildVersion,
|
Version: buildVersion,
|
||||||
Config: *config,
|
Config: *config,
|
||||||
slugToPage: make(map[string]*Page),
|
slugToPage: make(map[string]*Page),
|
||||||
|
widgetByID: make(map[uint64]widget.Widget),
|
||||||
}
|
}
|
||||||
|
|
||||||
app.slugToPage[""] = &config.Pages[0]
|
app.slugToPage[""] = &config.Pages[0]
|
||||||
|
|
||||||
for i := range config.Pages {
|
for p := range config.Pages {
|
||||||
if config.Pages[i].Slug == "" {
|
if config.Pages[p].Slug == "" {
|
||||||
config.Pages[i].Slug = titleToSlug(config.Pages[i].Title)
|
config.Pages[p].Slug = titleToSlug(config.Pages[p].Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.slugToPage[config.Pages[i].Slug] = &config.Pages[i]
|
app.slugToPage[config.Pages[p].Slug] = &config.Pages[p]
|
||||||
|
|
||||||
|
for c := range config.Pages[p].Columns {
|
||||||
|
for w := range config.Pages[p].Columns[c].Widgets {
|
||||||
|
widget := config.Pages[p].Columns[c].Widgets[w]
|
||||||
|
app.widgetByID[widget.GetID()] = widget
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return app, nil
|
return app, nil
|
||||||
@ -190,6 +200,26 @@ func FileServerWithCache(fs http.FileSystem, cacheDuration time.Duration) http.H
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Application) HandleWidgetRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
widgetValue := r.PathValue("widget")
|
||||||
|
|
||||||
|
widgetID, err := strconv.ParseUint(widgetValue, 10, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
a.HandleNotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
widget, exists := a.widgetByID[widgetID]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
a.HandleNotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.HandleRequest(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Application) AssetPath(asset string) string {
|
func (a *Application) AssetPath(asset string) string {
|
||||||
return "/static/" + a.Config.Server.AssetsHash + "/" + asset
|
return "/static/" + a.Config.Server.AssetsHash + "/" + asset
|
||||||
}
|
}
|
||||||
@ -203,7 +233,10 @@ func (a *Application) Serve() error {
|
|||||||
|
|
||||||
mux.HandleFunc("GET /{$}", a.HandlePageRequest)
|
mux.HandleFunc("GET /{$}", a.HandlePageRequest)
|
||||||
mux.HandleFunc("GET /{page}", a.HandlePageRequest)
|
mux.HandleFunc("GET /{page}", a.HandlePageRequest)
|
||||||
|
|
||||||
mux.HandleFunc("GET /api/pages/{page}/content/{$}", a.HandlePageContentRequest)
|
mux.HandleFunc("GET /api/pages/{page}/content/{$}", a.HandlePageContentRequest)
|
||||||
|
mux.HandleFunc("/api/widgets/{widget}/{path...}", a.HandleWidgetRequest)
|
||||||
|
|
||||||
mux.Handle(
|
mux.Handle(
|
||||||
fmt.Sprintf("GET /static/%s/{path...}", a.Config.Server.AssetsHash),
|
fmt.Sprintf("GET /static/%s/{path...}", a.Config.Server.AssetsHash),
|
||||||
http.StripPrefix("/static/"+a.Config.Server.AssetsHash, FileServerWithCache(http.FS(assets.PublicFS), 8*time.Hour)),
|
http.StripPrefix("/static/"+a.Config.Server.AssetsHash, FileServerWithCache(http.FS(assets.PublicFS), 8*time.Hour)),
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/glanceapp/glance/internal/feed"
|
"github.com/glanceapp/glance/internal/feed"
|
||||||
@ -15,51 +17,59 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var uniqueID atomic.Uint64
|
||||||
|
|
||||||
func New(widgetType string) (Widget, error) {
|
func New(widgetType string) (Widget, error) {
|
||||||
|
var widget Widget
|
||||||
|
|
||||||
switch widgetType {
|
switch widgetType {
|
||||||
case "calendar":
|
case "calendar":
|
||||||
return &Calendar{}, nil
|
widget = &Calendar{}
|
||||||
case "clock":
|
case "clock":
|
||||||
return &Clock{}, nil
|
widget = &Clock{}
|
||||||
case "weather":
|
case "weather":
|
||||||
return &Weather{}, nil
|
widget = &Weather{}
|
||||||
case "bookmarks":
|
case "bookmarks":
|
||||||
return &Bookmarks{}, nil
|
widget = &Bookmarks{}
|
||||||
case "iframe":
|
case "iframe":
|
||||||
return &IFrame{}, nil
|
widget = &IFrame{}
|
||||||
case "html":
|
case "html":
|
||||||
return &HTML{}, nil
|
widget = &HTML{}
|
||||||
case "hacker-news":
|
case "hacker-news":
|
||||||
return &HackerNews{}, nil
|
widget = &HackerNews{}
|
||||||
case "releases":
|
case "releases":
|
||||||
return &Releases{}, nil
|
widget = &Releases{}
|
||||||
case "videos":
|
case "videos":
|
||||||
return &Videos{}, nil
|
widget = &Videos{}
|
||||||
case "markets", "stocks":
|
case "markets", "stocks":
|
||||||
return &Markets{}, nil
|
widget = &Markets{}
|
||||||
case "reddit":
|
case "reddit":
|
||||||
return &Reddit{}, nil
|
widget = &Reddit{}
|
||||||
case "rss":
|
case "rss":
|
||||||
return &RSS{}, nil
|
widget = &RSS{}
|
||||||
case "monitor":
|
case "monitor":
|
||||||
return &Monitor{}, nil
|
widget = &Monitor{}
|
||||||
case "twitch-top-games":
|
case "twitch-top-games":
|
||||||
return &TwitchGames{}, nil
|
widget = &TwitchGames{}
|
||||||
case "twitch-channels":
|
case "twitch-channels":
|
||||||
return &TwitchChannels{}, nil
|
widget = &TwitchChannels{}
|
||||||
case "lobsters":
|
case "lobsters":
|
||||||
return &Lobsters{}, nil
|
widget = &Lobsters{}
|
||||||
case "change-detection":
|
case "change-detection":
|
||||||
return &ChangeDetection{}, nil
|
widget = &ChangeDetection{}
|
||||||
case "repository":
|
case "repository":
|
||||||
return &Repository{}, nil
|
widget = &Repository{}
|
||||||
case "search":
|
case "search":
|
||||||
return &Search{}, nil
|
widget = &Search{}
|
||||||
case "extension":
|
case "extension":
|
||||||
return &Extension{}, nil
|
widget = &Extension{}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown widget type: %s", widgetType)
|
return nil, fmt.Errorf("unknown widget type: %s", widgetType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
widget.SetID(uniqueID.Add(1))
|
||||||
|
|
||||||
|
return widget, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Widgets []Widget
|
type Widgets []Widget
|
||||||
@ -90,7 +100,7 @@ func (w *Widgets) UnmarshalYAML(node *yaml.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = widget.Initialize(); err != nil {
|
if err := widget.Initialize(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,6 +116,9 @@ type Widget interface {
|
|||||||
Update(context.Context)
|
Update(context.Context)
|
||||||
Render() template.HTML
|
Render() template.HTML
|
||||||
GetType() string
|
GetType() string
|
||||||
|
GetID() uint64
|
||||||
|
SetID(uint64)
|
||||||
|
HandleRequest(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
type cacheType int
|
type cacheType int
|
||||||
@ -117,6 +130,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type widgetBase struct {
|
type widgetBase struct {
|
||||||
|
ID uint64 `yaml:"-"`
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Title string `yaml:"title"`
|
Title string `yaml:"title"`
|
||||||
TitleURL string `yaml:"title-url"`
|
TitleURL string `yaml:"title-url"`
|
||||||
@ -148,6 +162,18 @@ func (w *widgetBase) Update(ctx context.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *widgetBase) GetID() uint64 {
|
||||||
|
return w.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *widgetBase) SetID(id uint64) {
|
||||||
|
w.ID = id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (widget *widgetBase) HandleRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.Error(w, "not implemented", http.StatusNotImplemented)
|
||||||
|
}
|
||||||
|
|
||||||
func (w *widgetBase) GetType() string {
|
func (w *widgetBase) GetType() string {
|
||||||
return w.Type
|
return w.Type
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user