main.go raw
1 // orly-sync-relaygroup is a standalone gRPC relay group service for ORLY.
2 // It provides relay group configuration discovery from Kind 39105 events.
3 package main
4
5 import (
6 "context"
7 "net"
8 "os"
9 "os/signal"
10 "syscall"
11 "time"
12
13 "google.golang.org/grpc"
14 "google.golang.org/grpc/reflection"
15 "next.orly.dev/pkg/lol"
16 "next.orly.dev/pkg/lol/chk"
17 "next.orly.dev/pkg/lol/log"
18
19 "next.orly.dev/pkg/database"
20 databasegrpc "next.orly.dev/pkg/database/grpc"
21 "next.orly.dev/pkg/sync/relaygroup"
22 relaygroupv1 "next.orly.dev/pkg/proto/orlysync/relaygroup/v1"
23 )
24
25 func main() {
26 cfg := loadConfig()
27
28 // Set log level
29 lol.SetLogLevel(cfg.LogLevel)
30 log.I.F("orly-sync-relaygroup starting with log level: %s", cfg.LogLevel)
31
32 ctx, cancel := context.WithCancel(context.Background())
33 defer cancel()
34
35 // Initialize database connection
36 var db database.Database
37 var dbCloser func()
38
39 if cfg.DBType == "grpc" {
40 log.I.F("connecting to gRPC database server at %s", cfg.GRPCDBServer)
41 dbClient, err := databasegrpc.New(ctx, &databasegrpc.ClientConfig{
42 ServerAddress: cfg.GRPCDBServer,
43 ConnectTimeout: 30 * time.Second,
44 })
45 if chk.E(err) {
46 log.E.F("failed to connect to database server: %v", err)
47 os.Exit(1)
48 }
49 db = dbClient
50 dbCloser = func() { dbClient.Close() }
51 } else {
52 log.E.F("badger mode not yet implemented for sync-relaygroup")
53 os.Exit(1)
54 }
55
56 // Wait for database to be ready
57 log.I.F("waiting for database to be ready...")
58 <-db.Ready()
59 log.I.F("database ready")
60
61 // Create relay group manager configuration
62 relaygroupCfg := &relaygroup.ManagerConfig{
63 AdminNpubs: cfg.AdminNpubs,
64 }
65
66 log.I.F("initializing relay group manager with %d admins", len(cfg.AdminNpubs))
67
68 // Create gRPC server
69 grpcServer := grpc.NewServer(
70 grpc.MaxRecvMsgSize(16<<20), // 16MB
71 grpc.MaxSendMsgSize(16<<20), // 16MB
72 )
73
74 // Register relay group service
75 // TODO: Create and register service once server implementation is done
76 // service := relaygroup.NewService(relaygroupMgr, cfg)
77 // relaygroupv1.RegisterRelayGroupServiceServer(grpcServer, service)
78 _ = relaygroupCfg
79 _ = db
80 _ = relaygroupv1.RelayGroupService_ServiceDesc
81
82 // Register reflection for debugging with grpcurl
83 reflection.Register(grpcServer)
84
85 // Start listening
86 lis, err := net.Listen("tcp", cfg.Listen)
87 if chk.E(err) {
88 log.E.F("failed to listen on %s: %v", cfg.Listen, err)
89 os.Exit(1)
90 }
91 log.I.F("gRPC server listening on %s", cfg.Listen)
92
93 // Handle graceful shutdown
94 go func() {
95 sigs := make(chan os.Signal, 1)
96 signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
97 sig := <-sigs
98 log.I.F("received signal %v, shutting down...", sig)
99
100 cancel()
101
102 stopped := make(chan struct{})
103 go func() {
104 grpcServer.GracefulStop()
105 close(stopped)
106 }()
107
108 select {
109 case <-stopped:
110 log.I.F("gRPC server stopped gracefully")
111 case <-time.After(5 * time.Second):
112 log.W.F("gRPC graceful stop timed out, forcing stop")
113 grpcServer.Stop()
114 }
115
116 if dbCloser != nil {
117 log.I.F("closing database connection...")
118 dbCloser()
119 }
120 log.I.F("shutdown complete")
121 }()
122
123 // Serve gRPC
124 if err := grpcServer.Serve(lis); err != nil {
125 log.E.F("gRPC server error: %v", err)
126 }
127 }
128