Files
eng-pad-server/internal/grpcserver/server.go
Kyle Isom 7d4e52ae92 Implement Phase 4: gRPC sync service
- Proto definitions (engpad.v1.EngPadSync) with 6 RPCs
- Generated Go gRPC code
- Auth interceptor: username/password from metadata
- SyncNotebook: upsert with full page/stroke replacement in a tx
- DeleteNotebook, ListNotebooks handlers
- Share link RPCs: CreateShareLink, RevokeShareLink, ListShareLinks
- Share link token management (32-byte random, optional expiry)
- gRPC server with TLS 1.3

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:52:47 -07:00

49 lines
979 B
Go

package grpcserver
import (
"crypto/tls"
"database/sql"
"fmt"
"net"
pb "git.wntrmute.dev/kyle/eng-pad-server/gen/engpad/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
type Config struct {
Addr string
TLSCert string
TLSKey string
DB *sql.DB
BaseURL string
}
func Start(cfg Config) error {
cert, err := tls.LoadX509KeyPair(cfg.TLSCert, cfg.TLSKey)
if err != nil {
return fmt.Errorf("load TLS cert: %w", err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
}
lis, err := net.Listen("tcp", cfg.Addr)
if err != nil {
return fmt.Errorf("listen %s: %w", cfg.Addr, err)
}
srv := grpc.NewServer(
grpc.Creds(credentials.NewTLS(tlsConfig)),
grpc.UnaryInterceptor(AuthInterceptor(cfg.DB)),
)
syncSvc := &SyncService{DB: cfg.DB, BaseURL: cfg.BaseURL}
pb.RegisterEngPadSyncServer(srv, syncSvc)
fmt.Printf("gRPC listening on %s\n", cfg.Addr)
return srv.Serve(lis)
}