- Add Server.Shutdown() method delegating to X402Server - Wire main-server graceful shutdown with 15s bounded timeout - Derive long-lived clients (bluesky, ollama) from backgroundCtx instead of signal context to prevent poisoned sessions on SIGTERM during startup - Remove empty errgroup goroutine that only logged on cancellation - Bind readyz sidecar to configurable READYZ_ADDRESS (default 127.0.0.1) instead of 0.0.0.0 - Validate port strings (ReadyzPort, MetricsPort, ListenPort) at config load - Fix ready-check Ollama probe: use defer for body drain, guard nil resp
120 lines
3.6 KiB
Go
120 lines
3.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
log "github.com/nacorid/logger"
|
|
"github.com/nacorid/naco-api/internal/activitypub"
|
|
"github.com/nacorid/naco-api/internal/bluesky"
|
|
"github.com/nacorid/naco-api/internal/config"
|
|
"github.com/nacorid/naco-api/internal/nostr"
|
|
"github.com/nacorid/naco-api/internal/ollama"
|
|
"github.com/nacorid/naco-api/internal/store"
|
|
"github.com/nacorid/naco-api/internal/twitter"
|
|
"github.com/nacorid/naco-api/internal/x402"
|
|
)
|
|
|
|
type Server struct {
|
|
// Transport & middleware
|
|
listenAddress string
|
|
permissions os.FileMode
|
|
mcpHandler *x402.X402Server
|
|
metrics *MetricsMiddleware
|
|
|
|
// Dependencies
|
|
db Store
|
|
apClient apBackend
|
|
bskyClient blueskyBackend
|
|
nostrClient nostrBackend
|
|
twitterClient twitterBackend
|
|
ollama ollamaBackend
|
|
|
|
// Cache & background work
|
|
postCache *ttlCache
|
|
enrichSem chan struct{}
|
|
prewarmAuthors []string
|
|
prewarmFeedURI string
|
|
enrichEnabled bool
|
|
|
|
// Payments & analytics tuning
|
|
x402Wallet string
|
|
activeNetworks []NetworkInfo
|
|
analyticsTTLEngagement time.Duration
|
|
analyticsTTLPatterns time.Duration
|
|
analyticsTTLTopics time.Duration
|
|
analyticsTTLSentiment time.Duration
|
|
analyticsTTLDrivers time.Duration
|
|
|
|
// twitterEnabled reports whether the Twitter API is available (a bearer
|
|
// token is configured). It flips the Twitter-capable tools to upto
|
|
// variable pricing so the realized Twitter API costs are passed on to
|
|
// callers (see registerTools).
|
|
twitterEnabled bool
|
|
}
|
|
|
|
func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky *bluesky.BlueskyClient, n *nostr.Client, t *twitter.Client, o *ollama.OllamaClient, cfg *config.Config) *Server {
|
|
toolchain, metrics := buildMiddleware()
|
|
srv := newX402Server(ctx, db, cfg, toolchain, metrics)
|
|
activeNetworks := resolveActiveNetworks(ctx, cfg.ActiveNetworks)
|
|
|
|
s := &Server{
|
|
listenAddress: cfg.ListenAddress,
|
|
permissions: cfg.UnixSocketPermissions,
|
|
mcpHandler: srv,
|
|
db: db,
|
|
apClient: ap,
|
|
bskyClient: bsky,
|
|
nostrClient: n,
|
|
twitterClient: t,
|
|
ollama: o,
|
|
metrics: metrics,
|
|
postCache: newTTLCache(postCacheTTL),
|
|
prewarmAuthors: cfg.PrewarmAuthors,
|
|
prewarmFeedURI: cfg.PrewarmFeedURI,
|
|
enrichEnabled: cfg.EnrichCrossPlatform,
|
|
x402Wallet: cfg.X402WalletAddress,
|
|
activeNetworks: activeNetworks,
|
|
enrichSem: make(chan struct{}, 4),
|
|
analyticsTTLEngagement: cfg.AnalyticsTTLEngagement,
|
|
analyticsTTLPatterns: cfg.AnalyticsTTLPatterns,
|
|
analyticsTTLTopics: cfg.AnalyticsTTLTopics,
|
|
analyticsTTLSentiment: cfg.AnalyticsTTLSentiment,
|
|
analyticsTTLDrivers: cfg.AnalyticsTTLDrivers,
|
|
twitterEnabled: cfg.TwitterBearerToken != "",
|
|
}
|
|
|
|
// Combine address and port for TCP (not unix socket) if port not already present
|
|
if !strings.HasPrefix(cfg.ListenAddress, "unix:") && !strings.Contains(cfg.ListenAddress, ":") {
|
|
s.listenAddress = fmt.Sprintf("%s:%s", cfg.ListenAddress, cfg.ListenPort)
|
|
}
|
|
|
|
log.DebugWithContext(ctx, "server initialized",
|
|
"networks", len(activeNetworks),
|
|
"enrich", s.enrichEnabled,
|
|
"prewarm_authors", len(s.prewarmAuthors),
|
|
)
|
|
|
|
s.registerTools()
|
|
|
|
return s
|
|
}
|
|
|
|
func (s *Server) MetricsText() string {
|
|
if s.metrics == nil {
|
|
return ""
|
|
}
|
|
return s.metrics.MetricsText()
|
|
}
|
|
|
|
func (s *Server) Start() error {
|
|
//go s.startPostPruner()
|
|
return s.mcpHandler.Start(s.listenAddress, s.permissions)
|
|
}
|
|
|
|
func (s *Server) Shutdown(ctx context.Context) error {
|
|
return s.mcpHandler.Shutdown(ctx)
|
|
}
|