block logic
This commit is contained in:
77
api/block/handle.go
Normal file
77
api/block/handle.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package block
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.oblat.lv/alex/triggerssmith/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
JS string `json:"js"`
|
||||||
|
CSS string `json:"css"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadHtmlBlock(cfg *config.Config) func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !cfg.Server.BlockConfig.Enabled {
|
||||||
|
http.Error(w, "Block serving is disabled", http.StatusNotImplemented)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blockPath := r.URL.Path[len("/api/block/"):]
|
||||||
|
block, err := LoadBlock(blockPath, cfg)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte(block.ToJSON()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBlock loads a block from the filesystem given its path and configuration.
|
||||||
|
// It reads the content, JavaScript, and CSS files associated with the block.
|
||||||
|
// If err is not nil, it indicates a failure in reading the block files.
|
||||||
|
func LoadBlock(path string, cfg *config.Config) (*Block, error) {
|
||||||
|
slog.Debug("loading block", slog.String("path", path))
|
||||||
|
path = filepath.Join(cfg.Server.BlockConfig.BlockDir, path)
|
||||||
|
var block Block
|
||||||
|
var err error
|
||||||
|
contentPath := filepath.Join(path, "content.md")
|
||||||
|
jsPath := filepath.Join(path, "script.js")
|
||||||
|
cssPath := filepath.Join(path, "style.css")
|
||||||
|
if b, err := os.ReadFile(contentPath); err == nil {
|
||||||
|
block.Content = string(b)
|
||||||
|
} else {
|
||||||
|
slog.Warn("failed to read block content", slog.String("path", contentPath), slog.String("err", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, err := os.ReadFile(jsPath); err == nil {
|
||||||
|
block.JS = string(b)
|
||||||
|
} else {
|
||||||
|
slog.Warn("failed to read block JS", slog.String("path", contentPath), slog.String("err", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if b, err := os.ReadFile(cssPath); err == nil {
|
||||||
|
block.CSS = string(b)
|
||||||
|
} else {
|
||||||
|
slog.Warn("failed to read block CSS", slog.String("path", contentPath), slog.String("err", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &block, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) ToJSON() string {
|
||||||
|
jsonData, err := json.Marshal(b)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("failed to marshal block to JSON", slog.String("err", err.Error()))
|
||||||
|
return "{}"
|
||||||
|
}
|
||||||
|
return string(jsonData)
|
||||||
|
}
|
||||||
@@ -2,14 +2,16 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.oblat.lv/alex/triggerssmith/api/invoke"
|
"git.oblat.lv/alex/triggerssmith/api/block"
|
||||||
"git.oblat.lv/alex/triggerssmith/internal/config"
|
"git.oblat.lv/alex/triggerssmith/internal/config"
|
||||||
"git.oblat.lv/alex/triggerssmith/internal/vars"
|
"git.oblat.lv/alex/triggerssmith/internal/vars"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
@@ -26,12 +28,31 @@ func NewRouter(cfg *config.Config) *Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RouteHandler sets up the routes and middleware for the router.
|
||||||
|
// TODO: implement hot reload for static files enabled/disabled
|
||||||
func (r *Router) RouteHandler() chi.Router {
|
func (r *Router) RouteHandler() chi.Router {
|
||||||
r.r.Get("/", func(w http.ResponseWriter, req *http.Request) {
|
r.r.Use(middleware.Logger)
|
||||||
http.ServeFile(w, req, filepath.Join(r.cfg.Server.StaticFilesPath, "index.html"))
|
r.r.Use(middleware.Recoverer)
|
||||||
|
r.r.Use(middleware.Timeout(r.cfg.Server.TimeoutSeconds))
|
||||||
|
|
||||||
|
if r.cfg.Server.StaticConfig.Enabled {
|
||||||
|
slog.Debug("Static file serving is enabled",
|
||||||
|
slog.String("dir", r.cfg.Server.StaticConfig.Dir),
|
||||||
|
slog.String("index_file", r.cfg.Server.StaticConfig.IndexFile),
|
||||||
|
)
|
||||||
|
r.r.Get("/", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
http.ServeFile(w, req, filepath.Join(r.cfg.Server.StaticConfig.Dir, r.cfg.Server.StaticConfig.IndexFile))
|
||||||
|
})
|
||||||
|
fs := http.FileServer(http.Dir(r.cfg.Server.StaticConfig.Dir))
|
||||||
|
r.r.Handle("/static/*", http.StripPrefix("/static/", fs))
|
||||||
|
} else {
|
||||||
|
slog.Info("Static file serving is disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.r.Route("/api", func(api chi.Router) {
|
||||||
|
api.Get("/block/*", block.LoadHtmlBlock(r.cfg))
|
||||||
})
|
})
|
||||||
fs := http.FileServer(http.Dir("static"))
|
|
||||||
r.r.Handle("/static/*", http.StripPrefix("/static/", fs))
|
|
||||||
r.r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
r.r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
b, _ := json.Marshal(struct {
|
b, _ := json.Marshal(struct {
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
@@ -42,6 +63,6 @@ func (r *Router) RouteHandler() chi.Router {
|
|||||||
})
|
})
|
||||||
w.Write([]byte(b))
|
w.Write([]byte(b))
|
||||||
})
|
})
|
||||||
r.r.Handle("/invoke/function/{function_id}/{function_version}", invoke.InvokeHandler(r.cfg))
|
//r.r.Handle("/invoke/function/{function_id}/{function_version}", invoke.InvokeHandler(r.cfg))
|
||||||
return r.r
|
return r.r
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var optsServeCmd = struct {
|
var optsServeCmd = struct {
|
||||||
ConfigPath *string
|
ConfigPath *string
|
||||||
Debug *bool
|
Debug *bool
|
||||||
HideGreetings *bool
|
HideGreetings *bool
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,29 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/akyaiy/GSfass/core/config"
|
"github.com/akyaiy/GSfass/core/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StaticConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
Dir string `mapstructure:"static_dir"`
|
||||||
|
IndexFile string `mapstructure:"index_file"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
BlockDir string `mapstructure:"block_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Port int `mapstructure:"port"`
|
StaticConfig StaticConfig `mapstructure:"static"`
|
||||||
Addr string `mapstructure:"address"`
|
BlockConfig BlockConfig `mapstructure:"block"`
|
||||||
StaticFilesPath string `mapstructure:"static_dir"`
|
Port int `mapstructure:"port"`
|
||||||
LogPath string `mapstructure:"log_path"`
|
Addr string `mapstructure:"address"`
|
||||||
|
LogPath string `mapstructure:"log_path"`
|
||||||
|
TimeoutSeconds time.Duration `mapstructure:"timeout_seconds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FuncConfig struct {
|
type FuncConfig struct {
|
||||||
@@ -24,9 +38,15 @@ type Config struct {
|
|||||||
|
|
||||||
var configPath atomic.Value // string
|
var configPath atomic.Value // string
|
||||||
var defaults = map[string]any{
|
var defaults = map[string]any{
|
||||||
"server.port": 8080,
|
"server.port": 8080,
|
||||||
"server.address": "127.0.0.0",
|
"server.address": "127.0.0.0",
|
||||||
"server.static_dir": "./static",
|
"server.timeout_seconds": 5,
|
||||||
|
"server.log_path": "./logs/server.log",
|
||||||
|
"server.static.enabled": true,
|
||||||
|
"server.static.static_dir": "./static",
|
||||||
|
"server.static.index_file": "index.html",
|
||||||
|
"server.block.enabled": true,
|
||||||
|
"server.block.block_dir": "./blocks",
|
||||||
|
|
||||||
"functions.func_dir": "./functions",
|
"functions.func_dir": "./functions",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user