mirror of
https://github.com/renorris/openfsd
synced 2026-08-13 04:55:42 +08:00
refactor: internal/web importable; cmd/openfsd-web; Docker embed-safe
Move web package; no init panic; Dockerfile_web builds cmd/openfsd-web as fsdweb.
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -4,5 +4,8 @@
|
||||
*.db
|
||||
**tmp**
|
||||
build-and-push.sh
|
||||
cover.out
|
||||
coverage.out
|
||||
|
||||
# Local binaries
|
||||
/openfsd-web
|
||||
/fsdweb
|
||||
/fsd
|
||||
|
||||
@@ -13,8 +13,7 @@ COPY . .
|
||||
# Cache builds
|
||||
ENV GOCACHE=/root/.cache/go-build
|
||||
RUN --mount=type=cache,target="/root/.cache/go-build" \
|
||||
cd web && \
|
||||
CGO_ENABLED=0 go build -o /go/bin/fsdweb
|
||||
CGO_ENABLED=0 go build -o /go/bin/fsdweb ./cmd/openfsd-web
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ The preferred way to run openfsd is using **Docker** and **Docker Compose**. See
|
||||
|
||||
## API
|
||||
|
||||
The web server exposes APIs under `/api/v1` for authentication, user management, and configuration. Although a basic web interface is provided, users are encouraged to call this API from their own external applications. See the [API](https://github.com/renorris/openfsd/tree/main/web) documentation.
|
||||
The web server exposes APIs under `/api/v1` for authentication, user management, and configuration. Although a basic web interface is provided, users are encouraged to call this API from their own external applications. See the [API](https://github.com/renorris/openfsd/tree/main/internal/web) documentation.
|
||||
|
||||
## Docs
|
||||
|
||||
|
||||
@@ -2,17 +2,17 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/renorris/openfsd/internal/web"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
|
||||
server, err := NewDefaultServer(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if err := web.Main(ctx); err != nil {
|
||||
slog.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
server.Run(ctx)
|
||||
}
|
||||
@@ -30,6 +30,7 @@ func TestImportGraph(t *testing.T) {
|
||||
postofficePkg,
|
||||
"github.com/renorris/openfsd/fsd",
|
||||
"github.com/renorris/openfsd/web",
|
||||
"github.com/renorris/openfsd/internal/web",
|
||||
"github.com/renorris/openfsd/internal/server",
|
||||
})
|
||||
|
||||
@@ -37,6 +38,7 @@ func TestImportGraph(t *testing.T) {
|
||||
assertNoDeps(t, postofficePkg, []string{
|
||||
"github.com/renorris/openfsd/fsd",
|
||||
"github.com/renorris/openfsd/web",
|
||||
"github.com/renorris/openfsd/internal/web",
|
||||
"github.com/renorris/openfsd/internal/server",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -25,23 +25,22 @@ import (
|
||||
|
||||
//go:embed data_templates/status.txt
|
||||
var statusTxtRawTemplate string
|
||||
var statusTxtTemplate *template.Template
|
||||
|
||||
//go:embed data_templates/servers.txt
|
||||
var serversTxtRawTemplate string
|
||||
var serversTxtTemplate *template.Template
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
statusTxtTemplate = template.New("statustxt")
|
||||
if statusTxtTemplate, err = statusTxtTemplate.Parse(statusTxtRawTemplate); err != nil {
|
||||
panic("Unable to parse status.txt template: " + err.Error())
|
||||
// parseDataTemplates parses the embedded status/servers text templates.
|
||||
// Called from NewServer so construction fails with an error instead of init panic.
|
||||
func parseDataTemplates() (statusTxt, serversTxt *template.Template, err error) {
|
||||
statusTxt, err = template.New("statustxt").Parse(statusTxtRawTemplate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
serversTxtTemplate = template.New("serverstxt")
|
||||
if serversTxtTemplate, err = serversTxtTemplate.Parse(serversTxtRawTemplate); err != nil {
|
||||
panic("Unable to parse servers.txt template: " + err.Error())
|
||||
serversTxt, err = template.New("serverstxt").Parse(serversTxtRawTemplate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return statusTxt, serversTxt, nil
|
||||
}
|
||||
|
||||
func (s *Server) handleGetStatusTxt(c *gin.Context) {
|
||||
@@ -51,7 +50,7 @@ func (s *Server) handleGetStatusTxt(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Generate a new status.txt
|
||||
statusTxt, err := generateStatusTxt(baseURL)
|
||||
statusTxt, err := s.generateStatusTxt(baseURL)
|
||||
if err != nil {
|
||||
c.Writer.WriteHeader(http.StatusInternalServerError)
|
||||
c.Writer.WriteString("Error generating status.txt")
|
||||
@@ -63,7 +62,7 @@ func (s *Server) handleGetStatusTxt(c *gin.Context) {
|
||||
c.Writer.WriteString(statusTxt)
|
||||
}
|
||||
|
||||
func generateStatusTxt(baseURL string) (txt string, err error) {
|
||||
func (s *Server) generateStatusTxt(baseURL string) (txt string, err error) {
|
||||
type TemplateData struct {
|
||||
ApiServerBaseURL string
|
||||
}
|
||||
@@ -72,7 +71,7 @@ func generateStatusTxt(baseURL string) (txt string, err error) {
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
buf.Grow(1024)
|
||||
if err = statusTxtTemplate.Execute(&buf, &tmplData); err != nil {
|
||||
if err = s.statusTxtTemplate.Execute(&buf, &tmplData); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -217,7 +216,7 @@ func (s *Server) generateServersTxt() (txt string, err error) {
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
buf.Grow(1024)
|
||||
if err = serversTxtTemplate.Execute(&buf, &tmplData); err != nil {
|
||||
if err = s.serversTxtTemplate.Execute(&buf, &tmplData); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
15
internal/web/main.go
Normal file
15
internal/web/main.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Main constructs the default web server and runs it until ctx is cancelled.
|
||||
// It is the library entrypoint used by cmd/openfsd-web.
|
||||
func Main(ctx context.Context) error {
|
||||
server, err := NewDefaultServer(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return server.Run(ctx)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"embed"
|
||||
@@ -1,17 +1,21 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/renorris/openfsd/internal/db"
|
||||
"log/slog"
|
||||
"net"
|
||||
"text/template"
|
||||
|
||||
"github.com/renorris/openfsd/internal/db"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
cfg *ServerConfig
|
||||
dbRepo *db.Repositories
|
||||
cfg *ServerConfig
|
||||
dbRepo *db.Repositories
|
||||
statusTxtTemplate *template.Template
|
||||
serversTxtTemplate *template.Template
|
||||
}
|
||||
|
||||
func NewDefaultServer(ctx context.Context) (server *Server, err error) {
|
||||
@@ -44,9 +48,16 @@ func NewDefaultServer(ctx context.Context) (server *Server, err error) {
|
||||
}
|
||||
|
||||
func NewServer(cfg *ServerConfig, dbRepo *db.Repositories) (server *Server, err error) {
|
||||
statusTxt, serversTxt, err := parseDataTemplates()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse data templates: %w", err)
|
||||
}
|
||||
|
||||
server = &Server{
|
||||
cfg: cfg,
|
||||
dbRepo: dbRepo,
|
||||
cfg: cfg,
|
||||
dbRepo: dbRepo,
|
||||
statusTxtTemplate: statusTxt,
|
||||
serversTxtTemplate: serversTxt,
|
||||
}
|
||||
|
||||
return
|
||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package web
|
||||
|
||||
// safeStr returns an empty string if the pointer is nil, or the underlying string value if not nil.
|
||||
func safeStr(str *string) string {
|
||||
@@ -6,4 +6,4 @@ start /b cmd /c "set DATABASE_AUTO_MIGRATE=true&& set DATABASE_SOURCE_NAME=openf
|
||||
|
||||
powershell -Command "$ProgressPreference = 'SilentlyContinue'; while (-not (Test-NetConnection -ComputerName localhost -Port 13618 -InformationLevel Quiet)) { Start-Sleep -Seconds 1 }" >nul 2>&1
|
||||
|
||||
cmd /c "cd web&& set FSD_HTTP_SERVICE_ADDRESS=http://localhost:13618&& set DATABASE_SOURCE_NAME=../openfsd.db?_pragma=busy_timeout(5000)^&_pragma=journal_mode(WAL)&& go run ."
|
||||
cmd /c "set FSD_HTTP_SERVICE_ADDRESS=http://localhost:13618&& set DATABASE_SOURCE_NAME=openfsd.db?_pragma=busy_timeout(5000)^&_pragma=journal_mode(WAL)&& go run ./cmd/openfsd-web"
|
||||
|
||||
Reference in New Issue
Block a user