initial webapp
This commit is contained in:
1 parent
6c989c338c
commit
d32f2b3a66
18 files changed
+1145
-16
No files matched your search
@@ -0,0 +1,82 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/nmoniz/any2anexoj/internal/ofigi"
|
||||
)
|
||||
|
||||
// Server wires the HTTP handlers, embedded static assets, and shared state
|
||||
// behind a single http.Handler. Use NewServer to construct one.
|
||||
type Server struct {
|
||||
state *State
|
||||
router *http.ServeMux
|
||||
staticFS fs.FS
|
||||
indexHTML []byte
|
||||
figiClient *ofigi.Client
|
||||
}
|
||||
|
||||
// Option mutates a Server during construction. Use WithFigiClient (mainly in
|
||||
// tests) to inject a custom OpenFIGI client so tests can run offline against
|
||||
// a stub while production uses a real network client.
|
||||
type Option func(*Server)
|
||||
|
||||
// WithFigiClient overrides the OpenFIGI client used by the report pipeline.
|
||||
// Production should leave this unset so NewServer constructs a real client
|
||||
// (no API key, 5 s timeout) that gracefully falls back to NatureUnknown
|
||||
// when OpenFIGI calls fail. Tests pass a stub backed by an httptest-style
|
||||
// transport to keep the test suite offline and deterministic.
|
||||
func WithFigiClient(c *ofigi.Client) Option {
|
||||
return func(s *Server) {
|
||||
s.figiClient = c
|
||||
}
|
||||
}
|
||||
|
||||
// NewServer constructs a Server with all routes registered. The staticFS is
|
||||
// the embedded subtree rooted at the directory that should be served under
|
||||
// /static/* (i.e. it must contain an "index.html" file). The returned
|
||||
// Server's Handler() method exposes the configured http.Handler.
|
||||
func NewServer(state *State, staticFS fs.FS, opts ...Option) (*Server, error) {
|
||||
indexBytes, err := fs.ReadFile(staticFS, "index.html")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("web: missing index.html in static FS: %w", err)
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
state: state,
|
||||
router: http.NewServeMux(),
|
||||
staticFS: staticFS,
|
||||
indexHTML: indexBytes,
|
||||
figiClient: ofigi.NewOpenFIGI(&http.Client{Timeout: 5 * time.Second}, ""),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
s.routes()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Handler returns the configured HTTP handler, wrapped in the auth middleware
|
||||
// stub so future auth wiring only has to change auth.go.
|
||||
func (s *Server) Handler() http.Handler {
|
||||
return AuthMiddleware(s.router)
|
||||
}
|
||||
|
||||
// routes registers the HTTP routes handled by this server.
|
||||
func (s *Server) routes() {
|
||||
// API routes.
|
||||
s.router.HandleFunc("POST /api/upload", s.handleUpload)
|
||||
s.router.HandleFunc("GET /api/table", s.handleGetTable)
|
||||
|
||||
// Serve the embedded static assets under /static/*.
|
||||
s.router.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.FS(s.staticFS))))
|
||||
|
||||
// Serve the embedded index page at "/".
|
||||
s.router.HandleFunc("GET /{$}", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = w.Write(s.indexHTML)
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user