wip
This commit is contained in:
140
server/main.go
Normal file
140
server/main.go
Normal file
@@ -0,0 +1,140 @@
|
||||
// cctv server entrypoint
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gst/go-gst/gst"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
||||
|
||||
"git.koval.net/cyclane/cctv/server/config"
|
||||
"git.koval.net/cyclane/cctv/server/ingest"
|
||||
_ "git.koval.net/cyclane/cctv/server/migrations"
|
||||
)
|
||||
|
||||
var (
|
||||
ingestService *ingest.Ingest
|
||||
)
|
||||
|
||||
func loadEnvFile(filenames ...string) {
|
||||
for _, filename := range filenames {
|
||||
if err := godotenv.Load(filename); err == nil {
|
||||
log.Printf("Loaded environment variables from %s", filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func exportCollectionsJSON(e *core.BootstrapEvent) error {
|
||||
if err := e.Next(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collections, err := e.App.FindAllCollections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to export collections: %w", err)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile("collections.json", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open collections.json: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
log.Printf("Failed to close collections.json: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
encoder := json.NewEncoder(f)
|
||||
encoder.SetIndent("", "\t")
|
||||
if err := encoder.Encode(collections); err != nil {
|
||||
return fmt.Errorf("failed to write collections to JSON: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
loadEnvFile(".env.local", ".env", ".env.default")
|
||||
config, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load configuration: %v", err)
|
||||
}
|
||||
|
||||
app := pocketbase.NewWithConfig(pocketbase.Config{
|
||||
DefaultDev: config.IsDev(),
|
||||
DefaultDataDir: config.DbDataDir,
|
||||
DefaultEncryptionEnv: config.DbEncryptionKey,
|
||||
})
|
||||
|
||||
migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{
|
||||
// enable auto creation of migration files when making collection changes in the Dashboard
|
||||
Automigrate: config.IsDev(),
|
||||
})
|
||||
|
||||
if config.IsDev() {
|
||||
app.OnBootstrap().BindFunc(exportCollectionsJSON)
|
||||
}
|
||||
var proxy *httputil.ReverseProxy
|
||||
if config.ExternalWebApp != "" {
|
||||
proxyURL, err := url.Parse(config.ExternalWebApp)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse external web app URL: %v", err)
|
||||
}
|
||||
proxy = httputil.NewSingleHostReverseProxy(proxyURL)
|
||||
proxy.ErrorLog = slog.NewLogLogger(app.Logger().With("svc", "proxy").Handler(), slog.LevelDebug)
|
||||
}
|
||||
ingestCtx, cancelIngestCtx := context.WithCancel(context.Background())
|
||||
app.OnServe().BindFunc(func(se *core.ServeEvent) error {
|
||||
gst.Init(nil)
|
||||
ingestService = ingest.BeginIngest(ingestCtx, app)
|
||||
|
||||
if !config.IsDev() {
|
||||
se.Router.BindFunc(func(e *core.RequestEvent) error {
|
||||
if strings.HasPrefix(e.Request.URL.Path, "/_/") {
|
||||
return e.NotFoundError("Page not found", nil)
|
||||
} else {
|
||||
return e.Next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if proxy == nil {
|
||||
// TODO: serve bundled (static) files
|
||||
} else {
|
||||
se.Router.GET("/{path...}", func(e *core.RequestEvent) error {
|
||||
proxy.ServeHTTP(e.Response, e.Request)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
registerAPI(se)
|
||||
|
||||
return se.Next()
|
||||
})
|
||||
|
||||
app.OnTerminate().BindFunc(func(e *core.TerminateEvent) error {
|
||||
app.Logger().Info("Shutting down ingest service")
|
||||
cancelIngestCtx()
|
||||
return nil
|
||||
})
|
||||
|
||||
app.OnRecordCreateExecute().BindFunc(handleCameraUpdate)
|
||||
app.OnRecordUpdateExecute().BindFunc(handleCameraUpdate)
|
||||
|
||||
if err := app.Start(); err != nil {
|
||||
app.Logger().Info("Application terminated with error")
|
||||
cancelIngestCtx()
|
||||
log.Fatal(err)
|
||||
}
|
||||
ingestService.Wait()
|
||||
}
|
||||
Reference in New Issue
Block a user