This commit is contained in:
@@ -13,32 +13,14 @@ import (
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/mrhid6/vantage/sitesvc/internal/api"
|
||||
"github.com/mrhid6/vantage/sitesvc/internal/mail"
|
||||
"github.com/mrhid6/vantage/sitesvc/internal/store"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
godotenv.Load()
|
||||
|
||||
mongoURI := getEnv("MONGO_URI", "mongodb://localhost:27017/vantage")
|
||||
addr := ":" + getEnv("PORT", "8082")
|
||||
|
||||
if err := store.Connect(mongoURI); err != nil {
|
||||
log.Fatalf("failed to connect to MongoDB: %v", err)
|
||||
}
|
||||
log.Printf("connected to MongoDB (database %q)", store.DatabaseName())
|
||||
|
||||
guardCtx, guardCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
guardErr := store.RequireMigratedDatabase(guardCtx)
|
||||
guardCancel()
|
||||
if guardErr != nil {
|
||||
log.Fatalf("database check failed: %v", guardErr)
|
||||
}
|
||||
|
||||
if err := store.EnsureIndexes(); err != nil {
|
||||
log.Fatalf("failed to ensure indexes: %v", err)
|
||||
}
|
||||
|
||||
mailCfg := mail.FromEnv()
|
||||
if mailCfg.Enabled() {
|
||||
log.Printf("smtp enabled (%s) contact form delivers to %s", mailCfg.Host, mailCfg.To)
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mrhid6/vantage/shared/indexes"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/connstring"
|
||||
)
|
||||
|
||||
var database *mongo.Database
|
||||
|
||||
func Connect(uri string) error {
|
||||
cs, err := connstring.ParseAndValidate(uri)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse MONGO_URI: %w", err)
|
||||
}
|
||||
if cs.Database == "" {
|
||||
return errors.New("MONGO_URI must name a database, e.g. mongodb://host:27017/vantage")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
client, err := mongo.Connect(options.Client().ApplyURI(uri))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := client.Ping(ctx, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
database = client.Database(cs.Database)
|
||||
return nil
|
||||
}
|
||||
|
||||
func DatabaseName() string {
|
||||
if database == nil {
|
||||
return ""
|
||||
}
|
||||
return database.Name()
|
||||
}
|
||||
|
||||
func col(name string) *mongo.Collection { return database.Collection(name) }
|
||||
|
||||
func EnsureIndexes() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// users.email and instances.slug are declared in the shared module so both
|
||||
// services agree. Re-declaring at boot means sitesvc does not depend on the
|
||||
// control plane having started first.
|
||||
return indexes.EnsureCoreIndexes(ctx, database)
|
||||
}
|
||||
|
||||
// RequireMigratedDatabase refuses to start against a control-plane database
|
||||
// that has not run migration 0004.
|
||||
//
|
||||
// Provisioning into `orgs` while the control plane reads `instances` would
|
||||
// create tenants nobody can see — the exact skew failure the shared module was
|
||||
// built to prevent. Failing to start is strictly better.
|
||||
func RequireMigratedDatabase(ctx context.Context) error {
|
||||
names, err := database.ListCollectionNames(ctx, bson.M{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("list collections: %w", err)
|
||||
}
|
||||
|
||||
var hasInstances, hasOrgs bool
|
||||
for _, n := range names {
|
||||
switch n {
|
||||
case "instances":
|
||||
hasInstances = true
|
||||
case "orgs":
|
||||
hasOrgs = true
|
||||
}
|
||||
}
|
||||
|
||||
// A brand-new database has neither. That is fine — whichever service starts
|
||||
// first creates `instances`.
|
||||
if !hasInstances && !hasOrgs {
|
||||
return nil
|
||||
}
|
||||
if !hasInstances {
|
||||
return errors.New("instances collection not found; deploy the control plane first")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user