108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"time"
|
|
|
|
"gitea.entroia.com/Zayden-Jung/foundry-core/internal/auth"
|
|
"gitea.entroia.com/Zayden-Jung/foundry-core/internal/codex"
|
|
"gitea.entroia.com/Zayden-Jung/foundry-core/internal/platform"
|
|
"gitea.entroia.com/Zayden-Jung/foundry-core/internal/research"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/stdlib"
|
|
)
|
|
|
|
func env(key, fallback string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) == 2 && os.Args[1] == "codex-worker" {
|
|
log.Fatal(codex.ServeWorker("/run/foundry-codex/worker.sock"))
|
|
}
|
|
origin, err := url.Parse(os.Getenv("PUBLIC_ORIGIN"))
|
|
if err != nil || origin.Scheme != "https" || origin.Hostname() == "" || origin.User != nil ||
|
|
(origin.Path != "" && origin.Path != "/") || origin.RawQuery != "" || origin.Fragment != "" {
|
|
log.Fatal("PUBLIC_ORIGIN must be an HTTPS origin")
|
|
}
|
|
var callbacks map[string]string
|
|
if err := json.Unmarshal([]byte(os.Getenv("FOUNDRY_PROJECTS")), &callbacks); err != nil || len(callbacks) == 0 {
|
|
log.Fatal("FOUNDRY_PROJECTS must configure at least one project")
|
|
}
|
|
id, secret, dsn := os.Getenv("GOOGLE_CLIENT_ID"), os.Getenv("GOOGLE_CLIENT_SECRET"), os.Getenv("DATABASE_URL")
|
|
if id == "" || secret == "" || dsn == "" {
|
|
log.Fatal("Google credentials and DATABASE_URL are required")
|
|
}
|
|
config, err := pgx.ParseConfig(dsn)
|
|
if err != nil {
|
|
log.Fatal("Invalid DATABASE_URL")
|
|
}
|
|
db := stdlib.OpenDB(*config)
|
|
defer db.Close()
|
|
email, err := auth.EmailConfigFromEnv()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
go email.Run(context.Background(), db)
|
|
slack, err := auth.SlackConfigFromEnv(origin.ResolveReference(&url.URL{Path: "/auth/slack/callback"}).String())
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
handler, err := auth.New(db, callbacks, origin.ResolveReference(&url.URL{Path: "/auth/google/callback"}).String(), id, secret, email, slack)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
mux := http.NewServeMux()
|
|
var papers research.Repository
|
|
if researchDSN := os.Getenv("FOUNDRY_RESEARCH_DATABASE_URL"); researchDSN != "" {
|
|
researchConfig, err := pgx.ParseConfig(researchDSN)
|
|
if err != nil {
|
|
log.Fatal("Invalid research database configuration")
|
|
}
|
|
researchConfig.RuntimeParams["default_transaction_read_only"] = "on"
|
|
researchConfig.RuntimeParams["application_name"] = "foundry-research"
|
|
researchDB := stdlib.OpenDB(*researchConfig)
|
|
defer researchDB.Close()
|
|
researchDB.SetMaxOpenConns(2)
|
|
researchDB.SetMaxIdleConns(2)
|
|
researchDB.SetConnMaxIdleTime(5 * time.Minute)
|
|
researchDB.SetConnMaxLifetime(30 * time.Minute)
|
|
repository, err := research.NewPostgresRepository(researchDB, env("FOUNDRY_RESEARCH_SCHEMA", "research"))
|
|
if err != nil {
|
|
log.Fatal("Invalid research database configuration")
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
err = repository.Check(ctx)
|
|
cancel()
|
|
if err != nil {
|
|
log.Fatal("Research database is unavailable or not published")
|
|
}
|
|
papers = repository
|
|
}
|
|
research.Register(mux, papers, callbacks)
|
|
if err := codex.Register(mux, callbacks, os.Getenv("FOUNDRY_CODEX_SOCKET"), os.Getenv("FOUNDRY_CODEX_GRANTS")); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
onboarding, err := platform.ParseOnboarding(os.Getenv("FOUNDRY_ONBOARDING"), callbacks)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
platform.Register(mux, db, callbacks, origin.Scheme+"://"+origin.Host, onboarding, codex.NewCanvasClient(os.Getenv("FOUNDRY_CODEX_SOCKET")))
|
|
mux.Handle("/", handler)
|
|
server := &http.Server{
|
|
Addr: net.JoinHostPort(env("HOST", "127.0.0.1"), env("PORT", "8080")),
|
|
Handler: mux, ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 10 * time.Second,
|
|
WriteTimeout: 110 * time.Second, IdleTimeout: 60 * time.Second,
|
|
}
|
|
log.Fatal(server.ListenAndServe())
|
|
}
|