187 lines
5.0 KiB
Go
187 lines
5.0 KiB
Go
// cmd/server/main.go
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/api"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/auth"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/config"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/crypto"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/db"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/media/prepare"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/media/upload/blossom"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/media/upload/nip94"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/nostr/events"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/nostr/poster"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/nostr/relay"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/scheduler"
|
|
"git.sovbit.dev/Enki/nostr-poster/internal/utils"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
)
|
|
|
|
func main() {
|
|
// Parse command line flags
|
|
configPath := flag.String("config", "", "Path to config file")
|
|
dbPath := flag.String("db", "", "Path to database file")
|
|
port := flag.Int("port", 0, "Port to listen on")
|
|
password := flag.String("password", "", "Password for encrypting private keys")
|
|
flag.Parse()
|
|
|
|
// Setup logger
|
|
logConfig := zap.NewProductionConfig()
|
|
logConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
logger, err := logConfig.Build()
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Failed to create logger: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
defer logger.Sync()
|
|
|
|
// Load config
|
|
cfg, err := config.LoadConfig(*configPath)
|
|
if err != nil {
|
|
logger.Fatal("Failed to load config", zap.Error(err))
|
|
}
|
|
|
|
// Override config with command line flags if provided
|
|
if *dbPath != "" {
|
|
cfg.DB.Path = *dbPath
|
|
}
|
|
if *port != 0 {
|
|
cfg.ServerPort = *port
|
|
}
|
|
|
|
// Ensure directories exist
|
|
if err := utils.EnsureDir(cfg.Bot.ContentDir); err != nil {
|
|
logger.Fatal("Failed to create content directory", zap.Error(err))
|
|
}
|
|
if err := utils.EnsureDir(cfg.Bot.ArchiveDir); err != nil {
|
|
logger.Fatal("Failed to create archive directory", zap.Error(err))
|
|
}
|
|
|
|
// Initialize database
|
|
database, err := db.New(cfg.DB.Path)
|
|
if err != nil {
|
|
logger.Fatal("Failed to connect to database", zap.Error(err))
|
|
}
|
|
if err := database.Initialize(); err != nil {
|
|
logger.Fatal("Failed to initialize database", zap.Error(err))
|
|
}
|
|
|
|
// Initialize key store
|
|
keyPassword := *password
|
|
if keyPassword == "" {
|
|
// Use a default password or prompt for one
|
|
// In a production environment, you'd want to handle this more securely
|
|
keyPassword = "nostr-poster-default-password"
|
|
}
|
|
keyStore, err := crypto.NewKeyStore(cfg.Bot.KeysFile, keyPassword)
|
|
if err != nil {
|
|
logger.Fatal("Failed to initialize key store", zap.Error(err))
|
|
}
|
|
|
|
// Initialize event manager
|
|
eventManager := events.NewEventManager(func(pubkey string) (string, error) {
|
|
return keyStore.GetPrivateKey(pubkey)
|
|
})
|
|
|
|
// Initialize relay manager
|
|
relayManager := relay.NewManager(logger)
|
|
|
|
// Initialize media preparation manager
|
|
mediaPrep := prepare.NewManager(logger)
|
|
|
|
// Initialize uploaders
|
|
// NIP-94 uploader
|
|
nip94Uploader := nip94.NewUploader(
|
|
cfg.Media.NIP94.ServerURL,
|
|
"", // Download URL will be discovered
|
|
nil, // Supported types will be discovered
|
|
logger,
|
|
func(url, method string, payload []byte) (string, error) {
|
|
// Replace with a valid bot's public key.
|
|
botPubkey := "your_valid_bot_pubkey_here"
|
|
privkey, err := keyStore.GetPrivateKey(botPubkey)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return nip94.CreateNIP98AuthHeader(url, method, payload, privkey)
|
|
},
|
|
)
|
|
|
|
// Blossom uploader
|
|
blossomUploader := blossom.NewUploader(
|
|
cfg.Media.Blossom.ServerURL,
|
|
logger,
|
|
func(url, method string) (string, error) {
|
|
// Replace with the appropriate bot's public key
|
|
botPubkey := "your_valid_bot_pubkey_here"
|
|
privkey, err := keyStore.GetPrivateKey(botPubkey)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return blossom.CreateBlossomAuthHeader(url, method, privkey)
|
|
},
|
|
)
|
|
|
|
// Initialize authentication service
|
|
authService := auth.NewService(
|
|
database,
|
|
logger,
|
|
keyPassword, // Use the same password for simplicity
|
|
24*time.Hour, // Token duration
|
|
)
|
|
|
|
// Initialize bot service
|
|
botService := api.NewBotService(
|
|
database,
|
|
keyStore,
|
|
eventManager,
|
|
relayManager,
|
|
logger,
|
|
)
|
|
|
|
// Create post content function
|
|
postContentFunc := poster.CreatePostContentFunc(
|
|
eventManager,
|
|
relayManager,
|
|
mediaPrep,
|
|
logger,
|
|
)
|
|
|
|
// Initialize scheduler
|
|
posterScheduler := scheduler.NewScheduler(
|
|
database,
|
|
logger,
|
|
cfg.Bot.ContentDir,
|
|
cfg.Bot.ArchiveDir,
|
|
nip94Uploader,
|
|
blossomUploader,
|
|
postContentFunc,
|
|
)
|
|
|
|
// Initialize API
|
|
apiServer := api.NewAPI(
|
|
logger,
|
|
botService,
|
|
authService,
|
|
posterScheduler,
|
|
)
|
|
|
|
// Start the scheduler
|
|
if err := posterScheduler.Start(); err != nil {
|
|
logger.Error("Failed to start scheduler", zap.Error(err))
|
|
}
|
|
|
|
// Start the server
|
|
addr := fmt.Sprintf(":%d", cfg.ServerPort)
|
|
logger.Info("Starting server", zap.String("address", addr))
|
|
if err := apiServer.Run(addr); err != nil {
|
|
logger.Fatal("Failed to start server", zap.Error(err))
|
|
}
|
|
} |