Initial commit: CarrotAssistant backend (Go + Gin + SQLite, OpenAI-compatible agent runtime)
This commit is contained in:
81
cmd/server/main.go
Normal file
81
cmd/server/main.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Package main is the CarrotAssistant backend entrypoint.
|
||||
//
|
||||
// It loads configuration, opens the database, bootstraps an initial admin
|
||||
// account if none exists, and serves HTTP until interrupted.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/config"
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/security"
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/server"
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/store"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("load config: %v", err)
|
||||
}
|
||||
log.Printf("data dir: %s", cfg.DataDir)
|
||||
|
||||
db, err := store.Open(cfg.DBPath)
|
||||
if err != nil {
|
||||
log.Fatalf("open db: %v", err)
|
||||
}
|
||||
|
||||
crypto, err := security.NewCrypto(cfg.MasterKey)
|
||||
if err != nil {
|
||||
log.Fatalf("init crypto: %v", err)
|
||||
}
|
||||
|
||||
// Bootstrap an admin account on first run so the console is reachable.
|
||||
// Production should set ADMIN_BOOTSTRAP_USER / ADMIN_BOOTSTRAP_PASSWORD.
|
||||
if cfg.AdminBootstrapUser != "" {
|
||||
if err := server.EnsureAdmin(db, cfg.AdminBootstrapUser, cfg.AdminBootstrapPassword); err != nil {
|
||||
log.Printf("ensure admin: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
deps := server.Deps{
|
||||
DB: db,
|
||||
Config: cfg,
|
||||
Crypto: crypto,
|
||||
SkillsDir: cfg.SkillsDir,
|
||||
}
|
||||
|
||||
handler := server.New(deps)
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.HTTPAddr,
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Printf("listening on %s", cfg.HTTPAddr)
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Graceful shutdown on SIGINT / SIGTERM.
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-stop
|
||||
log.Println("shutting down")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "shutdown: %v\n", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user