Browse Source
- Add four independent gRPC sync service binaries: - orly-sync-distributed: Serial-based peer-to-peer sync - orly-sync-cluster: Cluster replication with persistent state - orly-sync-relaygroup: Relay group config discovery (Kind 39105) - orly-sync-negentropy: NIP-77 efficient set reconciliation - Implement NIP-77 negentropy protocol for relay-to-relay sync - Add push-based event transfer for negentropy sync - Add client-facing NIP-77 WebSocket support (NEG-OPEN/MSG/CLOSE) - Add deployment scripts with symlink-based versioning - Add Makefile targets for quick deployment and rollback - Refactor existing sync code into modular service packages - Add proto definitions for all sync services - Integrate negentropy service into orly-launcher supervisor - Advertise NIP-77 support in relay info document Files modified: - Makefile: Add sync service build targets and deployment commands - README.md: Document NIP-77 support - app/config/config.go: Add negentropy configuration options - app/handle-message.go: Route NEG-* envelopes to negentropy handler - app/handle-negentropy.go: New file for NIP-77 WebSocket handling - app/handle-relayinfo.go: Advertise NIP-77 support - cmd/orly-launcher/: Add negentropy service management - cmd/orly-sync-*/: New service binaries - main.go: Add negentropy gRPC client initialization - pkg/proto/orlysync/: New proto definitions and generated code - pkg/sync/*/: Refactored sync packages with gRPC services - scripts/deploy-orly.sh: New symlink-based deployment script - scripts/build-and-deploy.sh: New build and deploy workflow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>main v0.55.0
52 changed files with 12970 additions and 201 deletions
@ -0,0 +1,347 @@
@@ -0,0 +1,347 @@
|
||||
package app |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"fmt" |
||||
|
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"git.mleku.dev/mleku/nostr/encoders/filter" |
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
negentropygrpc "next.orly.dev/pkg/sync/negentropy/grpc" |
||||
) |
||||
|
||||
// NIP-77 Negentropy envelope constants
|
||||
const ( |
||||
NegOpenLabel = "NEG-OPEN" |
||||
NegMsgLabel = "NEG-MSG" |
||||
NegCloseLabel = "NEG-CLOSE" |
||||
NegErrLabel = "NEG-ERR" |
||||
) |
||||
|
||||
// negentropyClient is the gRPC client for negentropy operations
|
||||
// This should be set via Server.SetNegentropyClient() when using gRPC mode
|
||||
var negentropyClient *negentropygrpc.Client |
||||
|
||||
// SetNegentropyClient sets the negentropy gRPC client for NIP-77 WebSocket handling
|
||||
func SetNegentropyClient(client *negentropygrpc.Client) { |
||||
negentropyClient = client |
||||
} |
||||
|
||||
// IsNegentropyEnvelope checks if a message starts with a NEG-* envelope type
|
||||
func IsNegentropyEnvelope(msg []byte) bool { |
||||
// Quick check: must start with '["NEG-'
|
||||
if len(msg) < 8 { |
||||
return false |
||||
} |
||||
return bytes.HasPrefix(msg, []byte(`["NEG-`)) |
||||
} |
||||
|
||||
// IdentifyNegentropyEnvelope extracts the envelope type and remaining payload
|
||||
func IdentifyNegentropyEnvelope(msg []byte) (envelopeType string, ok bool) { |
||||
// Parse enough to get the envelope type
|
||||
if !IsNegentropyEnvelope(msg) { |
||||
return "", false |
||||
} |
||||
|
||||
// Find the first comma after the opening label
|
||||
end := bytes.IndexByte(msg[2:], '"') |
||||
if end < 0 { |
||||
return "", false |
||||
} |
||||
envelopeType = string(msg[2 : 2+end]) |
||||
return envelopeType, true |
||||
} |
||||
|
||||
// HandleNegOpen processes NEG-OPEN messages
|
||||
// Format: ["NEG-OPEN", subscription_id, filter, initial_message?]
|
||||
func (l *Listener) HandleNegOpen(msg []byte) error { |
||||
log.I.F("HandleNegOpen called from %s", l.connectionID) |
||||
if negentropyClient == nil { |
||||
log.E.F("negentropy client is nil") |
||||
return l.sendNegErr("", "negentropy not enabled") |
||||
} |
||||
|
||||
// Parse the message array
|
||||
var parts []json.RawMessage |
||||
if err := json.Unmarshal(msg, &parts); err != nil { |
||||
return l.sendNegErr("", fmt.Sprintf("invalid NEG-OPEN format: %v", err)) |
||||
} |
||||
|
||||
if len(parts) < 3 { |
||||
return l.sendNegErr("", "NEG-OPEN requires at least 3 elements") |
||||
} |
||||
|
||||
// Extract subscription ID
|
||||
var subscriptionID string |
||||
if err := json.Unmarshal(parts[1], &subscriptionID); err != nil { |
||||
return l.sendNegErr("", fmt.Sprintf("invalid subscription_id: %v", err)) |
||||
} |
||||
|
||||
// Extract filter
|
||||
var f filter.F |
||||
if err := json.Unmarshal(parts[2], &f); err != nil { |
||||
return l.sendNegErr(subscriptionID, fmt.Sprintf("invalid filter: %v", err)) |
||||
} |
||||
|
||||
// Extract optional initial message (hex encoded per NIP-77)
|
||||
var initialMessage []byte |
||||
if len(parts) >= 4 { |
||||
var msgStr string |
||||
if err := json.Unmarshal(parts[3], &msgStr); err == nil && msgStr != "" { |
||||
// NIP-77 uses hex encoding
|
||||
if decoded, err := hex.DecodeString(msgStr); err == nil { |
||||
initialMessage = decoded |
||||
} else { |
||||
log.W.F("NEG-OPEN: invalid hex message: %v", err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Convert filter to proto format
|
||||
protoFilter := filterToProto(&f) |
||||
|
||||
// Call gRPC service
|
||||
ctx := context.Background() |
||||
respMsg, errStr, err := negentropyClient.HandleNegOpen( |
||||
ctx, |
||||
l.connectionID, |
||||
subscriptionID, |
||||
protoFilter, |
||||
initialMessage, |
||||
) |
||||
if err != nil { |
||||
log.E.F("NEG-OPEN gRPC error: %v", err) |
||||
return l.sendNegErr(subscriptionID, "internal error") |
||||
} |
||||
|
||||
if errStr != "" { |
||||
return l.sendNegErr(subscriptionID, errStr) |
||||
} |
||||
|
||||
// Send NEG-MSG response with initial message
|
||||
return l.sendNegMsg(subscriptionID, respMsg) |
||||
} |
||||
|
||||
// HandleNegMsg processes NEG-MSG messages
|
||||
// Format: ["NEG-MSG", subscription_id, message]
|
||||
func (l *Listener) HandleNegMsg(msg []byte) error { |
||||
if negentropyClient == nil { |
||||
return l.sendNegErr("", "negentropy not enabled") |
||||
} |
||||
|
||||
// Parse the message array
|
||||
var parts []json.RawMessage |
||||
if err := json.Unmarshal(msg, &parts); err != nil { |
||||
return l.sendNegErr("", fmt.Sprintf("invalid NEG-MSG format: %v", err)) |
||||
} |
||||
|
||||
if len(parts) < 3 { |
||||
return l.sendNegErr("", "NEG-MSG requires 3 elements") |
||||
} |
||||
|
||||
// Extract subscription ID
|
||||
var subscriptionID string |
||||
if err := json.Unmarshal(parts[1], &subscriptionID); err != nil { |
||||
return l.sendNegErr("", fmt.Sprintf("invalid subscription_id: %v", err)) |
||||
} |
||||
|
||||
// Extract message (hex or base64 encoded)
|
||||
var msgStr string |
||||
if err := json.Unmarshal(parts[2], &msgStr); err != nil { |
||||
return l.sendNegErr(subscriptionID, fmt.Sprintf("invalid message: %v", err)) |
||||
} |
||||
|
||||
// Decode message (NIP-77 uses hex encoding)
|
||||
negentropyMsg, err := hex.DecodeString(msgStr) |
||||
if err != nil { |
||||
return l.sendNegErr(subscriptionID, fmt.Sprintf("invalid hex message: %v", err)) |
||||
} |
||||
|
||||
// Call gRPC service
|
||||
ctx := context.Background() |
||||
respMsg, haveIDs, needIDs, complete, errStr, err := negentropyClient.HandleNegMsg( |
||||
ctx, |
||||
l.connectionID, |
||||
subscriptionID, |
||||
negentropyMsg, |
||||
) |
||||
if err != nil { |
||||
log.E.F("NEG-MSG gRPC error: %v", err) |
||||
return l.sendNegErr(subscriptionID, "internal error") |
||||
} |
||||
|
||||
if errStr != "" { |
||||
return l.sendNegErr(subscriptionID, errStr) |
||||
} |
||||
|
||||
// If we have events to send (have_ids), fetch and send them
|
||||
if len(haveIDs) > 0 { |
||||
if err := l.sendEventsForIDs(subscriptionID, haveIDs); err != nil { |
||||
log.E.F("failed to send events for NEG-MSG: %v", err) |
||||
} |
||||
} |
||||
|
||||
// Log need_ids (events client should send us)
|
||||
if len(needIDs) > 0 { |
||||
log.D.F("NEG-MSG: client needs to send %d events", len(needIDs)) |
||||
} |
||||
|
||||
// Send NEG-MSG response
|
||||
if err := l.sendNegMsg(subscriptionID, respMsg); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// If reconciliation is complete, log it
|
||||
if complete { |
||||
log.D.F("NEG-MSG: reconciliation complete for %s", subscriptionID) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// HandleNegClose processes NEG-CLOSE messages
|
||||
// Format: ["NEG-CLOSE", subscription_id]
|
||||
func (l *Listener) HandleNegClose(msg []byte) error { |
||||
if negentropyClient == nil { |
||||
return nil // Silently ignore if not enabled
|
||||
} |
||||
|
||||
// Parse the message array
|
||||
var parts []json.RawMessage |
||||
if err := json.Unmarshal(msg, &parts); err != nil { |
||||
return nil // Silently ignore malformed close
|
||||
} |
||||
|
||||
if len(parts) < 2 { |
||||
return nil |
||||
} |
||||
|
||||
// Extract subscription ID
|
||||
var subscriptionID string |
||||
if err := json.Unmarshal(parts[1], &subscriptionID); err != nil { |
||||
return nil |
||||
} |
||||
|
||||
// Call gRPC service to close the session
|
||||
ctx := context.Background() |
||||
if err := negentropyClient.HandleNegClose(ctx, l.connectionID, subscriptionID); err != nil { |
||||
log.E.F("NEG-CLOSE gRPC error: %v", err) |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// sendNegMsg sends a NEG-MSG response to the client
|
||||
func (l *Listener) sendNegMsg(subscriptionID string, message []byte) error { |
||||
// Encode message as hex (per NIP-77)
|
||||
encoded := "" |
||||
if len(message) > 0 { |
||||
encoded = hex.EncodeToString(message) |
||||
} |
||||
|
||||
// Format: ["NEG-MSG", subscription_id, message]
|
||||
resp, err := json.Marshal([]any{NegMsgLabel, subscriptionID, encoded}) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
_, err = l.Write(resp) |
||||
return err |
||||
} |
||||
|
||||
// sendNegErr sends a NEG-ERR response to the client
|
||||
func (l *Listener) sendNegErr(subscriptionID, reason string) error { |
||||
// Format: ["NEG-ERR", subscription_id, reason]
|
||||
resp, err := json.Marshal([]any{NegErrLabel, subscriptionID, reason}) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
_, err = l.Write(resp) |
||||
return err |
||||
} |
||||
|
||||
// sendEventsForIDs fetches and sends events for the given IDs
|
||||
func (l *Listener) sendEventsForIDs(subscriptionID string, ids [][]byte) error { |
||||
// TODO: Implement event fetching and sending via EVENT envelopes
|
||||
// For each ID, query the database and send the event
|
||||
// This would use the existing event broadcasting mechanism
|
||||
log.D.F("NEG: would send %d events for subscription %s", len(ids), subscriptionID) |
||||
return nil |
||||
} |
||||
|
||||
// filterToProto converts a nostr filter to proto format
|
||||
func filterToProto(f *filter.F) *commonv1.Filter { |
||||
if f == nil { |
||||
return nil |
||||
} |
||||
|
||||
pf := &commonv1.Filter{} |
||||
|
||||
// Convert Ids
|
||||
if f.Ids != nil { |
||||
for _, id := range f.Ids.T { |
||||
pf.Ids = append(pf.Ids, id) |
||||
} |
||||
} |
||||
|
||||
// Convert Authors
|
||||
if f.Authors != nil { |
||||
for _, author := range f.Authors.T { |
||||
pf.Authors = append(pf.Authors, author) |
||||
} |
||||
} |
||||
|
||||
// Convert Kinds - kind.S has ToUint16() method
|
||||
if f.Kinds != nil && f.Kinds.Len() > 0 { |
||||
for _, k := range f.Kinds.ToUint16() { |
||||
pf.Kinds = append(pf.Kinds, uint32(k)) |
||||
} |
||||
} |
||||
|
||||
// Convert Since/Until - timestamp.T has .V field (int64)
|
||||
if f.Since != nil && f.Since.V != 0 { |
||||
since := f.Since.V |
||||
pf.Since = &since |
||||
} |
||||
if f.Until != nil && f.Until.V != 0 { |
||||
until := f.Until.V |
||||
pf.Until = &until |
||||
} |
||||
|
||||
// Convert Limit
|
||||
if f.Limit != nil { |
||||
limit := uint32(*f.Limit) |
||||
pf.Limit = &limit |
||||
} |
||||
|
||||
// Note: Tag filters (e, p, etc.) would need more complex conversion
|
||||
// This is a simplified implementation
|
||||
|
||||
return pf |
||||
} |
||||
|
||||
// CloseAllNegentropySessions closes all negentropy sessions for a connection
|
||||
// Called when a WebSocket connection is closed
|
||||
func (l *Listener) CloseAllNegentropySessions() { |
||||
if negentropyClient == nil { |
||||
return |
||||
} |
||||
|
||||
ctx := context.Background() |
||||
sessions, err := negentropyClient.ListSessions(ctx) |
||||
if chk.E(err) { |
||||
return |
||||
} |
||||
|
||||
for _, sess := range sessions { |
||||
if sess.ConnectionID == l.connectionID { |
||||
negentropyClient.CloseSession(ctx, l.connectionID, sess.SubscriptionID) |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
"time" |
||||
|
||||
"go-simpler.org/env" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
) |
||||
|
||||
// Config holds the cluster sync service configuration.
|
||||
type Config struct { |
||||
// Listen is the gRPC server listen address
|
||||
Listen string `env:"ORLY_SYNC_CLUSTER_LISTEN" default:"127.0.0.1:50062" usage:"gRPC server listen address"` |
||||
|
||||
// LogLevel is the logging level
|
||||
LogLevel string `env:"ORLY_SYNC_CLUSTER_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"` |
||||
|
||||
// Database configuration
|
||||
DBType string `env:"ORLY_SYNC_CLUSTER_DB_TYPE" default:"grpc" usage:"database type: grpc or badger"` |
||||
GRPCDBServer string `env:"ORLY_SYNC_CLUSTER_DB_SERVER" default:"127.0.0.1:50051" usage:"gRPC database server address"` |
||||
DataDir string `env:"ORLY_DATA_DIR" usage:"database data directory (for badger mode)"` |
||||
|
||||
// Cluster configuration
|
||||
AdminNpubsRaw string `env:"ORLY_SYNC_CLUSTER_ADMINS" usage:"comma-separated admin npubs"` |
||||
PropagatePrivilegedEvents bool `env:"ORLY_SYNC_CLUSTER_PROPAGATE_PRIVILEGED" default:"true" usage:"propagate privileged events (DMs, gift wraps)"` |
||||
PollInterval time.Duration `env:"ORLY_SYNC_CLUSTER_POLL_INTERVAL" default:"5s" usage:"poll interval"` |
||||
|
||||
// NIP-11 cache configuration
|
||||
NIP11CacheTTL time.Duration `env:"ORLY_SYNC_CLUSTER_NIP11_TTL" default:"30m" usage:"NIP-11 cache TTL"` |
||||
|
||||
// Parsed admin npubs
|
||||
AdminNpubs []string |
||||
} |
||||
|
||||
// loadConfig loads configuration from environment variables.
|
||||
func loadConfig() *Config { |
||||
cfg := &Config{} |
||||
if err := env.Load(cfg, nil); chk.E(err) { |
||||
log.E.F("failed to load config: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Parse admin npubs from comma-separated string
|
||||
if cfg.AdminNpubsRaw != "" { |
||||
cfg.AdminNpubs = strings.Split(cfg.AdminNpubsRaw, ",") |
||||
for i, p := range cfg.AdminNpubs { |
||||
cfg.AdminNpubs[i] = strings.TrimSpace(p) |
||||
} |
||||
} |
||||
|
||||
return cfg |
||||
} |
||||
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
// orly-sync-cluster is a standalone gRPC cluster sync service for ORLY.
|
||||
// It provides cluster replication with persistent state between relay instances.
|
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"net" |
||||
"os" |
||||
"os/signal" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/reflection" |
||||
"lol.mleku.dev" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
databasegrpc "next.orly.dev/pkg/database/grpc" |
||||
"next.orly.dev/pkg/sync/cluster" |
||||
clusterv1 "next.orly.dev/pkg/proto/orlysync/cluster/v1" |
||||
) |
||||
|
||||
func main() { |
||||
cfg := loadConfig() |
||||
|
||||
// Set log level
|
||||
lol.SetLogLevel(cfg.LogLevel) |
||||
log.I.F("orly-sync-cluster starting with log level: %s", cfg.LogLevel) |
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) |
||||
defer cancel() |
||||
|
||||
// Initialize database connection
|
||||
var db database.Database |
||||
var dbCloser func() |
||||
|
||||
if cfg.DBType == "grpc" { |
||||
log.I.F("connecting to gRPC database server at %s", cfg.GRPCDBServer) |
||||
dbClient, err := databasegrpc.New(ctx, &databasegrpc.ClientConfig{ |
||||
ServerAddress: cfg.GRPCDBServer, |
||||
ConnectTimeout: 30 * time.Second, |
||||
}) |
||||
if chk.E(err) { |
||||
log.E.F("failed to connect to database server: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
db = dbClient |
||||
dbCloser = func() { dbClient.Close() } |
||||
} else { |
||||
log.E.F("badger mode not yet implemented for sync-cluster") |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Wait for database to be ready
|
||||
log.I.F("waiting for database to be ready...") |
||||
<-db.Ready() |
||||
log.I.F("database ready") |
||||
|
||||
// Create cluster manager configuration
|
||||
clusterCfg := &cluster.Config{ |
||||
AdminNpubs: cfg.AdminNpubs, |
||||
PropagatePrivilegedEvents: cfg.PropagatePrivilegedEvents, |
||||
PollInterval: cfg.PollInterval, |
||||
NIP11CacheTTL: cfg.NIP11CacheTTL, |
||||
} |
||||
|
||||
log.I.F("initializing cluster sync manager with %d admins", len(cfg.AdminNpubs)) |
||||
|
||||
// Create gRPC server
|
||||
grpcServer := grpc.NewServer( |
||||
grpc.MaxRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxSendMsgSize(16<<20), // 16MB
|
||||
) |
||||
|
||||
// Register cluster sync service
|
||||
// TODO: Create and register service once server implementation is done
|
||||
// service := cluster.NewService(clusterMgr, cfg)
|
||||
// clusterv1.RegisterClusterSyncServiceServer(grpcServer, service)
|
||||
_ = clusterCfg |
||||
_ = db |
||||
_ = clusterv1.ClusterSyncService_ServiceDesc |
||||
|
||||
// Register reflection for debugging with grpcurl
|
||||
reflection.Register(grpcServer) |
||||
|
||||
// Start listening
|
||||
lis, err := net.Listen("tcp", cfg.Listen) |
||||
if chk.E(err) { |
||||
log.E.F("failed to listen on %s: %v", cfg.Listen, err) |
||||
os.Exit(1) |
||||
} |
||||
log.I.F("gRPC server listening on %s", cfg.Listen) |
||||
|
||||
// Handle graceful shutdown
|
||||
go func() { |
||||
sigs := make(chan os.Signal, 1) |
||||
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) |
||||
sig := <-sigs |
||||
log.I.F("received signal %v, shutting down...", sig) |
||||
|
||||
cancel() |
||||
|
||||
stopped := make(chan struct{}) |
||||
go func() { |
||||
grpcServer.GracefulStop() |
||||
close(stopped) |
||||
}() |
||||
|
||||
select { |
||||
case <-stopped: |
||||
log.I.F("gRPC server stopped gracefully") |
||||
case <-time.After(5 * time.Second): |
||||
log.W.F("gRPC graceful stop timed out, forcing stop") |
||||
grpcServer.Stop() |
||||
} |
||||
|
||||
if dbCloser != nil { |
||||
log.I.F("closing database connection...") |
||||
dbCloser() |
||||
} |
||||
log.I.F("shutdown complete") |
||||
}() |
||||
|
||||
// Serve gRPC
|
||||
if err := grpcServer.Serve(lis); err != nil { |
||||
log.E.F("gRPC server error: %v", err) |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
"time" |
||||
|
||||
"go-simpler.org/env" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
) |
||||
|
||||
// Config holds the distributed sync service configuration.
|
||||
type Config struct { |
||||
// Listen is the gRPC server listen address
|
||||
Listen string `env:"ORLY_SYNC_DISTRIBUTED_LISTEN" default:"127.0.0.1:50061" usage:"gRPC server listen address"` |
||||
|
||||
// LogLevel is the logging level
|
||||
LogLevel string `env:"ORLY_SYNC_DISTRIBUTED_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"` |
||||
|
||||
// Database configuration
|
||||
DBType string `env:"ORLY_SYNC_DISTRIBUTED_DB_TYPE" default:"grpc" usage:"database type: grpc or badger"` |
||||
GRPCDBServer string `env:"ORLY_SYNC_DISTRIBUTED_DB_SERVER" default:"127.0.0.1:50051" usage:"gRPC database server address"` |
||||
DataDir string `env:"ORLY_DATA_DIR" usage:"database data directory (for badger mode)"` |
||||
|
||||
// Sync configuration
|
||||
NodeID string `env:"ORLY_SYNC_DISTRIBUTED_NODE_ID" usage:"node identity (relay pubkey)"` |
||||
RelayURL string `env:"ORLY_SYNC_DISTRIBUTED_RELAY_URL" usage:"this relay's URL"` |
||||
PeersRaw string `env:"ORLY_SYNC_DISTRIBUTED_PEERS" usage:"comma-separated peer relay URLs"` |
||||
SyncInterval time.Duration `env:"ORLY_SYNC_DISTRIBUTED_INTERVAL" default:"5s" usage:"sync poll interval"` |
||||
|
||||
// NIP-11 cache configuration
|
||||
NIP11CacheTTL time.Duration `env:"ORLY_SYNC_DISTRIBUTED_NIP11_TTL" default:"30m" usage:"NIP-11 cache TTL"` |
||||
|
||||
// Parsed peers
|
||||
Peers []string |
||||
} |
||||
|
||||
// loadConfig loads configuration from environment variables.
|
||||
func loadConfig() *Config { |
||||
cfg := &Config{} |
||||
if err := env.Load(cfg, nil); chk.E(err) { |
||||
log.E.F("failed to load config: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Parse peers from comma-separated string
|
||||
if cfg.PeersRaw != "" { |
||||
cfg.Peers = strings.Split(cfg.PeersRaw, ",") |
||||
for i, p := range cfg.Peers { |
||||
cfg.Peers[i] = strings.TrimSpace(p) |
||||
} |
||||
} |
||||
|
||||
return cfg |
||||
} |
||||
@ -0,0 +1,144 @@
@@ -0,0 +1,144 @@
|
||||
// orly-sync-distributed is a standalone gRPC distributed sync service for ORLY.
|
||||
// It provides serial-based peer-to-peer synchronization between relay instances.
|
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"net" |
||||
"os" |
||||
"os/signal" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/reflection" |
||||
"lol.mleku.dev" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
databasegrpc "next.orly.dev/pkg/database/grpc" |
||||
"next.orly.dev/pkg/sync/distributed" |
||||
distributedv1 "next.orly.dev/pkg/proto/orlysync/distributed/v1" |
||||
) |
||||
|
||||
func main() { |
||||
cfg := loadConfig() |
||||
|
||||
// Set log level
|
||||
lol.SetLogLevel(cfg.LogLevel) |
||||
log.I.F("orly-sync-distributed starting with log level: %s", cfg.LogLevel) |
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) |
||||
defer cancel() |
||||
|
||||
// Initialize database connection
|
||||
var db database.Database |
||||
var dbCloser func() |
||||
|
||||
if cfg.DBType == "grpc" { |
||||
log.I.F("connecting to gRPC database server at %s", cfg.GRPCDBServer) |
||||
dbClient, err := databasegrpc.New(ctx, &databasegrpc.ClientConfig{ |
||||
ServerAddress: cfg.GRPCDBServer, |
||||
ConnectTimeout: 30 * time.Second, |
||||
}) |
||||
if chk.E(err) { |
||||
log.E.F("failed to connect to database server: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
db = dbClient |
||||
dbCloser = func() { dbClient.Close() } |
||||
} else { |
||||
log.E.F("badger mode not yet implemented for sync-distributed") |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Wait for database to be ready
|
||||
log.I.F("waiting for database to be ready...") |
||||
<-db.Ready() |
||||
log.I.F("database ready") |
||||
|
||||
// Create sync manager configuration
|
||||
syncCfg := &distributed.Config{ |
||||
NodeID: cfg.NodeID, |
||||
RelayURL: cfg.RelayURL, |
||||
Peers: cfg.Peers, |
||||
SyncInterval: cfg.SyncInterval, |
||||
NIP11CacheTTL: cfg.NIP11CacheTTL, |
||||
} |
||||
|
||||
// The distributed.Manager currently requires *database.D, not the interface.
|
||||
// For gRPC mode, we need the manager to be updated to use the database.Database interface.
|
||||
// For now, log that this mode requires refactoring.
|
||||
if cfg.DBType == "grpc" { |
||||
log.W.F("distributed sync manager needs refactoring to use database.Database interface") |
||||
log.W.F("currently only stub service is available in gRPC mode") |
||||
} |
||||
|
||||
log.I.F("initializing distributed sync manager with %d peers", len(cfg.Peers)) |
||||
|
||||
// Create gRPC server
|
||||
grpcServer := grpc.NewServer( |
||||
grpc.MaxRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxSendMsgSize(16<<20), // 16MB
|
||||
) |
||||
|
||||
// Register distributed sync service
|
||||
// Note: The manager needs refactoring to use the interface before this works fully
|
||||
// For now, register a stub service that will return appropriate responses
|
||||
_ = syncCfg |
||||
_ = distributedv1.DistributedSyncService_ServiceDesc |
||||
// TODO: Once distributed.Manager uses database.Database interface:
|
||||
// syncMgr := distributed.NewManager(ctx, db, syncCfg, nil)
|
||||
// service := distributedserver.NewService(db, syncMgr)
|
||||
// distributedv1.RegisterDistributedSyncServiceServer(grpcServer, service)
|
||||
|
||||
// Register reflection for debugging with grpcurl
|
||||
reflection.Register(grpcServer) |
||||
|
||||
// Start listening
|
||||
lis, err := net.Listen("tcp", cfg.Listen) |
||||
if chk.E(err) { |
||||
log.E.F("failed to listen on %s: %v", cfg.Listen, err) |
||||
os.Exit(1) |
||||
} |
||||
log.I.F("gRPC server listening on %s", cfg.Listen) |
||||
|
||||
// Handle graceful shutdown
|
||||
go func() { |
||||
sigs := make(chan os.Signal, 1) |
||||
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) |
||||
sig := <-sigs |
||||
log.I.F("received signal %v, shutting down...", sig) |
||||
|
||||
// Cancel context to stop all operations
|
||||
cancel() |
||||
|
||||
// Gracefully stop gRPC server with timeout
|
||||
stopped := make(chan struct{}) |
||||
go func() { |
||||
grpcServer.GracefulStop() |
||||
close(stopped) |
||||
}() |
||||
|
||||
select { |
||||
case <-stopped: |
||||
log.I.F("gRPC server stopped gracefully") |
||||
case <-time.After(5 * time.Second): |
||||
log.W.F("gRPC graceful stop timed out, forcing stop") |
||||
grpcServer.Stop() |
||||
} |
||||
|
||||
// Close database connection
|
||||
if dbCloser != nil { |
||||
log.I.F("closing database connection...") |
||||
dbCloser() |
||||
} |
||||
log.I.F("shutdown complete") |
||||
}() |
||||
|
||||
// Serve gRPC
|
||||
if err := grpcServer.Serve(lis); err != nil { |
||||
log.E.F("gRPC server error: %v", err) |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
"time" |
||||
|
||||
"go-simpler.org/env" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
) |
||||
|
||||
// Config holds the negentropy sync service configuration.
|
||||
type Config struct { |
||||
// Listen is the gRPC server listen address
|
||||
Listen string `env:"ORLY_SYNC_NEGENTROPY_LISTEN" default:"127.0.0.1:50064" usage:"gRPC server listen address"` |
||||
|
||||
// LogLevel is the logging level
|
||||
LogLevel string `env:"ORLY_SYNC_NEGENTROPY_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"` |
||||
|
||||
// Database configuration
|
||||
DBType string `env:"ORLY_SYNC_NEGENTROPY_DB_TYPE" default:"grpc" usage:"database type: grpc or badger"` |
||||
GRPCDBServer string `env:"ORLY_SYNC_NEGENTROPY_DB_SERVER" default:"127.0.0.1:50051" usage:"gRPC database server address"` |
||||
DataDir string `env:"ORLY_DATA_DIR" usage:"database data directory (for badger mode)"` |
||||
|
||||
// Negentropy configuration
|
||||
PeersRaw string `env:"ORLY_SYNC_NEGENTROPY_PEERS" usage:"comma-separated peer relay WebSocket URLs"` |
||||
SyncInterval time.Duration `env:"ORLY_SYNC_NEGENTROPY_INTERVAL" default:"60s" usage:"background sync interval"` |
||||
FrameSize int `env:"ORLY_SYNC_NEGENTROPY_FRAME_SIZE" default:"4096" usage:"negentropy frame size"` |
||||
IDSize int `env:"ORLY_SYNC_NEGENTROPY_ID_SIZE" default:"16" usage:"negentropy ID truncation size"` |
||||
|
||||
// Client session configuration
|
||||
ClientSessionTimeout time.Duration `env:"ORLY_SYNC_NEGENTROPY_SESSION_TIMEOUT" default:"5m" usage:"client session timeout"` |
||||
|
||||
// Parsed peers
|
||||
Peers []string |
||||
} |
||||
|
||||
// loadConfig loads configuration from environment variables.
|
||||
func loadConfig() *Config { |
||||
cfg := &Config{} |
||||
if err := env.Load(cfg, nil); chk.E(err) { |
||||
log.E.F("failed to load config: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Parse peers from comma-separated string
|
||||
if cfg.PeersRaw != "" { |
||||
cfg.Peers = strings.Split(cfg.PeersRaw, ",") |
||||
for i, p := range cfg.Peers { |
||||
cfg.Peers[i] = strings.TrimSpace(p) |
||||
} |
||||
} |
||||
|
||||
return cfg |
||||
} |
||||
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
// orly-sync-negentropy is a standalone gRPC negentropy sync service for ORLY.
|
||||
// It provides NIP-77 negentropy-based set reconciliation for both
|
||||
// relay-to-relay sync and client-facing WebSocket operations.
|
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"net" |
||||
"os" |
||||
"os/signal" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/reflection" |
||||
"lol.mleku.dev" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
databasegrpc "next.orly.dev/pkg/database/grpc" |
||||
negentropyv1 "next.orly.dev/pkg/proto/orlysync/negentropy/v1" |
||||
"next.orly.dev/pkg/sync/negentropy" |
||||
negentropyserver "next.orly.dev/pkg/sync/negentropy/server" |
||||
) |
||||
|
||||
func main() { |
||||
cfg := loadConfig() |
||||
|
||||
// Set log level
|
||||
lol.SetLogLevel(cfg.LogLevel) |
||||
log.I.F("orly-sync-negentropy starting with log level: %s", cfg.LogLevel) |
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) |
||||
defer cancel() |
||||
|
||||
// Initialize database connection
|
||||
var db database.Database |
||||
var dbCloser func() |
||||
|
||||
if cfg.DBType == "grpc" { |
||||
log.I.F("connecting to gRPC database server at %s", cfg.GRPCDBServer) |
||||
dbClient, err := databasegrpc.New(ctx, &databasegrpc.ClientConfig{ |
||||
ServerAddress: cfg.GRPCDBServer, |
||||
ConnectTimeout: 30 * time.Second, |
||||
}) |
||||
if chk.E(err) { |
||||
log.E.F("failed to connect to database server: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
db = dbClient |
||||
dbCloser = func() { dbClient.Close() } |
||||
} else { |
||||
log.E.F("badger mode not yet implemented for sync-negentropy") |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Wait for database to be ready
|
||||
log.I.F("waiting for database to be ready...") |
||||
<-db.Ready() |
||||
log.I.F("database ready") |
||||
|
||||
log.I.F("initializing negentropy sync manager with %d peers", len(cfg.Peers)) |
||||
|
||||
// Create negentropy manager
|
||||
mgrConfig := &negentropy.Config{ |
||||
Peers: cfg.Peers, |
||||
SyncInterval: cfg.SyncInterval, |
||||
FrameSize: cfg.FrameSize, |
||||
IDSize: cfg.IDSize, |
||||
ClientSessionTimeout: cfg.ClientSessionTimeout, |
||||
} |
||||
negentropyMgr := negentropy.NewManager(db, mgrConfig) |
||||
|
||||
// Start background sync loop if we have peers
|
||||
if len(cfg.Peers) > 0 { |
||||
log.I.F("starting background sync with %d peers", len(cfg.Peers)) |
||||
negentropyMgr.Start() |
||||
} |
||||
|
||||
// Create gRPC server
|
||||
grpcServer := grpc.NewServer( |
||||
grpc.MaxRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxSendMsgSize(16<<20), // 16MB
|
||||
) |
||||
|
||||
// Register negentropy service
|
||||
service := negentropyserver.NewService(db, negentropyMgr) |
||||
negentropyv1.RegisterNegentropyServiceServer(grpcServer, service) |
||||
|
||||
// Register reflection for debugging with grpcurl
|
||||
reflection.Register(grpcServer) |
||||
|
||||
// Start listening
|
||||
lis, err := net.Listen("tcp", cfg.Listen) |
||||
if chk.E(err) { |
||||
log.E.F("failed to listen on %s: %v", cfg.Listen, err) |
||||
os.Exit(1) |
||||
} |
||||
log.I.F("gRPC server listening on %s", cfg.Listen) |
||||
|
||||
// Handle graceful shutdown
|
||||
go func() { |
||||
sigs := make(chan os.Signal, 1) |
||||
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) |
||||
sig := <-sigs |
||||
log.I.F("received signal %v, shutting down...", sig) |
||||
|
||||
cancel() |
||||
|
||||
stopped := make(chan struct{}) |
||||
go func() { |
||||
grpcServer.GracefulStop() |
||||
close(stopped) |
||||
}() |
||||
|
||||
select { |
||||
case <-stopped: |
||||
log.I.F("gRPC server stopped gracefully") |
||||
case <-time.After(5 * time.Second): |
||||
log.W.F("gRPC graceful stop timed out, forcing stop") |
||||
grpcServer.Stop() |
||||
} |
||||
|
||||
// Stop the negentropy manager
|
||||
log.I.F("stopping negentropy manager...") |
||||
negentropyMgr.Stop() |
||||
|
||||
if dbCloser != nil { |
||||
log.I.F("closing database connection...") |
||||
dbCloser() |
||||
} |
||||
log.I.F("shutdown complete") |
||||
}() |
||||
|
||||
// Serve gRPC
|
||||
if err := grpcServer.Serve(lis); err != nil { |
||||
log.E.F("gRPC server error: %v", err) |
||||
} |
||||
} |
||||
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
|
||||
"go-simpler.org/env" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
) |
||||
|
||||
// Config holds the relay group service configuration.
|
||||
type Config struct { |
||||
// Listen is the gRPC server listen address
|
||||
Listen string `env:"ORLY_SYNC_RELAYGROUP_LISTEN" default:"127.0.0.1:50063" usage:"gRPC server listen address"` |
||||
|
||||
// LogLevel is the logging level
|
||||
LogLevel string `env:"ORLY_SYNC_RELAYGROUP_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"` |
||||
|
||||
// Database configuration
|
||||
DBType string `env:"ORLY_SYNC_RELAYGROUP_DB_TYPE" default:"grpc" usage:"database type: grpc or badger"` |
||||
GRPCDBServer string `env:"ORLY_SYNC_RELAYGROUP_DB_SERVER" default:"127.0.0.1:50051" usage:"gRPC database server address"` |
||||
DataDir string `env:"ORLY_DATA_DIR" usage:"database data directory (for badger mode)"` |
||||
|
||||
// Relay group configuration
|
||||
AdminNpubsRaw string `env:"ORLY_SYNC_RELAYGROUP_ADMINS" usage:"comma-separated admin npubs"` |
||||
|
||||
// Parsed admin npubs
|
||||
AdminNpubs []string |
||||
} |
||||
|
||||
// loadConfig loads configuration from environment variables.
|
||||
func loadConfig() *Config { |
||||
cfg := &Config{} |
||||
if err := env.Load(cfg, nil); chk.E(err) { |
||||
log.E.F("failed to load config: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Parse admin npubs from comma-separated string
|
||||
if cfg.AdminNpubsRaw != "" { |
||||
cfg.AdminNpubs = strings.Split(cfg.AdminNpubsRaw, ",") |
||||
for i, p := range cfg.AdminNpubs { |
||||
cfg.AdminNpubs[i] = strings.TrimSpace(p) |
||||
} |
||||
} |
||||
|
||||
return cfg |
||||
} |
||||
@ -0,0 +1,127 @@
@@ -0,0 +1,127 @@
|
||||
// orly-sync-relaygroup is a standalone gRPC relay group service for ORLY.
|
||||
// It provides relay group configuration discovery from Kind 39105 events.
|
||||
package main |
||||
|
||||
import ( |
||||
"context" |
||||
"net" |
||||
"os" |
||||
"os/signal" |
||||
"syscall" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/reflection" |
||||
"lol.mleku.dev" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
databasegrpc "next.orly.dev/pkg/database/grpc" |
||||
"next.orly.dev/pkg/sync/relaygroup" |
||||
relaygroupv1 "next.orly.dev/pkg/proto/orlysync/relaygroup/v1" |
||||
) |
||||
|
||||
func main() { |
||||
cfg := loadConfig() |
||||
|
||||
// Set log level
|
||||
lol.SetLogLevel(cfg.LogLevel) |
||||
log.I.F("orly-sync-relaygroup starting with log level: %s", cfg.LogLevel) |
||||
|
||||
ctx, cancel := context.WithCancel(context.Background()) |
||||
defer cancel() |
||||
|
||||
// Initialize database connection
|
||||
var db database.Database |
||||
var dbCloser func() |
||||
|
||||
if cfg.DBType == "grpc" { |
||||
log.I.F("connecting to gRPC database server at %s", cfg.GRPCDBServer) |
||||
dbClient, err := databasegrpc.New(ctx, &databasegrpc.ClientConfig{ |
||||
ServerAddress: cfg.GRPCDBServer, |
||||
ConnectTimeout: 30 * time.Second, |
||||
}) |
||||
if chk.E(err) { |
||||
log.E.F("failed to connect to database server: %v", err) |
||||
os.Exit(1) |
||||
} |
||||
db = dbClient |
||||
dbCloser = func() { dbClient.Close() } |
||||
} else { |
||||
log.E.F("badger mode not yet implemented for sync-relaygroup") |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Wait for database to be ready
|
||||
log.I.F("waiting for database to be ready...") |
||||
<-db.Ready() |
||||
log.I.F("database ready") |
||||
|
||||
// Create relay group manager configuration
|
||||
relaygroupCfg := &relaygroup.ManagerConfig{ |
||||
AdminNpubs: cfg.AdminNpubs, |
||||
} |
||||
|
||||
log.I.F("initializing relay group manager with %d admins", len(cfg.AdminNpubs)) |
||||
|
||||
// Create gRPC server
|
||||
grpcServer := grpc.NewServer( |
||||
grpc.MaxRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxSendMsgSize(16<<20), // 16MB
|
||||
) |
||||
|
||||
// Register relay group service
|
||||
// TODO: Create and register service once server implementation is done
|
||||
// service := relaygroup.NewService(relaygroupMgr, cfg)
|
||||
// relaygroupv1.RegisterRelayGroupServiceServer(grpcServer, service)
|
||||
_ = relaygroupCfg |
||||
_ = db |
||||
_ = relaygroupv1.RelayGroupService_ServiceDesc |
||||
|
||||
// Register reflection for debugging with grpcurl
|
||||
reflection.Register(grpcServer) |
||||
|
||||
// Start listening
|
||||
lis, err := net.Listen("tcp", cfg.Listen) |
||||
if chk.E(err) { |
||||
log.E.F("failed to listen on %s: %v", cfg.Listen, err) |
||||
os.Exit(1) |
||||
} |
||||
log.I.F("gRPC server listening on %s", cfg.Listen) |
||||
|
||||
// Handle graceful shutdown
|
||||
go func() { |
||||
sigs := make(chan os.Signal, 1) |
||||
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT) |
||||
sig := <-sigs |
||||
log.I.F("received signal %v, shutting down...", sig) |
||||
|
||||
cancel() |
||||
|
||||
stopped := make(chan struct{}) |
||||
go func() { |
||||
grpcServer.GracefulStop() |
||||
close(stopped) |
||||
}() |
||||
|
||||
select { |
||||
case <-stopped: |
||||
log.I.F("gRPC server stopped gracefully") |
||||
case <-time.After(5 * time.Second): |
||||
log.W.F("gRPC graceful stop timed out, forcing stop") |
||||
grpcServer.Stop() |
||||
} |
||||
|
||||
if dbCloser != nil { |
||||
log.I.F("closing database connection...") |
||||
dbCloser() |
||||
} |
||||
log.I.F("shutdown complete") |
||||
}() |
||||
|
||||
// Serve gRPC
|
||||
if err := grpcServer.Serve(lis); err != nil { |
||||
log.E.F("gRPC server error: %v", err) |
||||
} |
||||
} |
||||
@ -0,0 +1,371 @@
@@ -0,0 +1,371 @@
|
||||
# ORLY IPC Architecture |
||||
|
||||
ORLY implements a modular Inter-Process Communication (IPC) architecture where core functionality runs as independent gRPC services. This design provides resource isolation, fault tolerance, and flexible deployment options. |
||||
|
||||
## Overview |
||||
|
||||
``` |
||||
┌─────────────────────────────────────────────────────────────────────────────────┐ |
||||
│ orly-launcher │ |
||||
│ (Process Supervisor & Lifecycle Manager) │ |
||||
│ │ |
||||
│ Responsibilities: │ |
||||
│ - Start services in dependency order │ |
||||
│ - Monitor process health and restart on failure │ |
||||
│ - Graceful shutdown in reverse order │ |
||||
│ - Pass environment configuration to child processes │ |
||||
└─────────────────────────────────────────────────────────────────────────────────┘ |
||||
│ |
||||
┌───────────────────────────────┼───────────────────────────────┐ |
||||
│ │ │ |
||||
▼ ▼ ▼ |
||||
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────────────┐ |
||||
│ orly-db │ │ orly-acl │ │ Sync Services │ |
||||
│ (gRPC :50051) │ │ (gRPC :50052) │ │ (gRPC :50061-50064) │ |
||||
│ │ │ │ │ │ |
||||
│ Core Database: │ │ Access Control: │ │ orly-sync-distributed │ |
||||
│ ├─ Event storage │ │ ├─ Permission │ │ ├─ Peer-to-peer sync │ |
||||
│ ├─ Query engine │ │ │ checks │ │ └─ Serial-based polling │ |
||||
│ ├─ Index mgmt │ │ ├─ Follow lists │ │ │ |
||||
│ ├─ Serial counter │ │ ├─ Admin/owner │ │ orly-sync-cluster │ |
||||
│ └─ Export/import │ │ │ management │ │ ├─ HA replication │ |
||||
│ │ │ └─ Policy hooks │ │ └─ Membership events │ |
||||
│ Backends: │ │ │ │ │ |
||||
│ ├─ Badger (SSD) │ │ Modes: │ │ orly-sync-relaygroup │ |
||||
│ ├─ Neo4j (graph) │ │ ├─ none (open) │ │ ├─ Kind 39105 config │ |
||||
│ └─ WasmDB (wasm) │ │ ├─ follows │ │ └─ Dynamic peer lists │ |
||||
│ │ │ ├─ managed │ │ │ |
||||
│ │ │ └─ curating │ │ orly-sync-negentropy │ |
||||
│ │ │ │ │ ├─ NIP-77 WebSocket │ |
||||
│ │ │ │ │ └─ Set reconciliation │ |
||||
└───────────────────┘ └───────────────────┘ └───────────────────────────┘ |
||||
│ │ │ |
||||
│ │ │ |
||||
└───────────────────────────┼───────────────────────────────┘ |
||||
│ |
||||
▼ |
||||
┌───────────────────────┐ |
||||
│ orly │ |
||||
│ (Main Relay) │ |
||||
│ │ |
||||
│ Client-Facing: │ |
||||
│ ├─ WebSocket server │ |
||||
│ ├─ NIP handling │ |
||||
│ ├─ REQ/EVENT/AUTH │ |
||||
│ ├─ NEG-* (NIP-77) │ |
||||
│ └─ HTTP API │ |
||||
│ │ |
||||
│ Internal: │ |
||||
│ ├─ gRPC DB client │ |
||||
│ ├─ gRPC ACL client │ |
||||
│ └─ gRPC sync clients │ |
||||
└───────────────────────┘ |
||||
│ |
||||
▼ |
||||
┌───────────────┐ |
||||
│ Caddy │ |
||||
│ (TLS Proxy) │ |
||||
└───────────────┘ |
||||
│ |
||||
▼ |
||||
Internet |
||||
``` |
||||
|
||||
## Service Ports |
||||
|
||||
| Service | Default Port | Description | |
||||
|---------|--------------|-------------| |
||||
| orly-db | 50051 | Database server (Badger/Neo4j/WasmDB) | |
||||
| orly-acl | 50052 | Access control server | |
||||
| orly-sync-distributed | 50061 | Peer-to-peer sync | |
||||
| orly-sync-cluster | 50062 | Cluster replication | |
||||
| orly-sync-relaygroup | 50063 | Relay group config | |
||||
| orly-sync-negentropy | 50064 | NIP-77 negentropy | |
||||
| orly | 3334 | Main relay (WebSocket/HTTP) | |
||||
|
||||
## Startup Sequence |
||||
|
||||
The launcher starts services in strict dependency order: |
||||
|
||||
``` |
||||
1. orly-db ──────► Wait for gRPC ready |
||||
│ |
||||
2. orly-acl ──────► Wait for gRPC ready (depends on DB) |
||||
│ |
||||
3. Sync Services ──────► Start in parallel, wait for all ready |
||||
├─ orly-sync-distributed (depends on DB) |
||||
├─ orly-sync-cluster (depends on DB) |
||||
├─ orly-sync-relaygroup (depends on DB) |
||||
└─ orly-sync-negentropy (depends on DB) |
||||
│ |
||||
4. orly ──────► Connects to all services via gRPC |
||||
``` |
||||
|
||||
**Shutdown** happens in reverse order: relay → sync services → ACL → database. |
||||
|
||||
## Benefits of IPC Architecture |
||||
|
||||
### 1. Resource Isolation |
||||
- Database memory usage is isolated from relay |
||||
- ACL processing doesn't compete with query handling |
||||
- Sync services have dedicated resources |
||||
|
||||
### 2. Fault Tolerance |
||||
- Database crash doesn't kill WebSocket connections immediately |
||||
- ACL service restart preserves event storage |
||||
- Individual sync service failures don't affect others |
||||
|
||||
### 3. Independent Scaling |
||||
- Scale database for query-heavy workloads |
||||
- Scale relay for connection-heavy workloads |
||||
- Enable only needed sync services |
||||
|
||||
### 4. Flexible Deployment |
||||
- Run services on different machines |
||||
- Mix local and remote services |
||||
- Deploy services incrementally |
||||
|
||||
--- |
||||
|
||||
# Core Services |
||||
|
||||
## 1. Database Service (orly-db) |
||||
|
||||
The database service handles all event storage, indexing, and querying. |
||||
|
||||
### Variants |
||||
- `orly-db-badger` - Badger LSM-tree database (SSD optimized) |
||||
- `orly-db-neo4j` - Neo4j graph database (social graph queries) |
||||
|
||||
### gRPC API |
||||
|
||||
```protobuf |
||||
service DatabaseService { |
||||
// Readiness |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
|
||||
// Event operations |
||||
rpc SaveEvent(SaveEventRequest) returns (SaveEventResponse); |
||||
rpc QueryEvents(QueryEventsRequest) returns (QueryEventsResponse); |
||||
rpc CountEvents(CountEventsRequest) returns (CountEventsResponse); |
||||
rpc DeleteEvent(DeleteEventRequest) returns (DeleteEventResponse); |
||||
rpc QueryAllVersions(QueryEventsRequest) returns (QueryEventsResponse); |
||||
|
||||
// Special queries |
||||
rpc GetSerials(GetSerialsRequest) returns (GetSerialsResponse); |
||||
rpc GetLastSerial(Empty) returns (GetLastSerialResponse); |
||||
rpc CheckForDeleted(CheckDeletedRequest) returns (CheckDeletedResponse); |
||||
|
||||
// Admin operations |
||||
rpc Export(ExportRequest, stream ExportResponse); |
||||
rpc Import(stream ImportRequest) returns (ImportResponse); |
||||
} |
||||
``` |
||||
|
||||
### Environment Variables |
||||
|
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_DB_LISTEN` | 127.0.0.1:50051 | gRPC listen address | |
||||
| `ORLY_DATA_DIR` | ~/.local/share/ORLY | Database storage path | |
||||
| `ORLY_DB_LOG_LEVEL` | info | Logging level | |
||||
| `ORLY_DB_BLOCK_CACHE_MB` | 1024 | Badger block cache | |
||||
| `ORLY_DB_INDEX_CACHE_MB` | 512 | Badger index cache | |
||||
| `ORLY_DB_ZSTD_LEVEL` | 3 | Compression level (0-9) | |
||||
|
||||
--- |
||||
|
||||
## 2. ACL Service (orly-acl) |
||||
|
||||
The ACL service handles access control decisions for all relay operations. |
||||
|
||||
### Variants |
||||
- `orly-acl-none` - Open relay (no restrictions) |
||||
- `orly-acl-follows` - Follow-list based access |
||||
- `orly-acl-managed` - NIP-86 managed access |
||||
- `orly-acl-curating` - Curator-based access |
||||
|
||||
### gRPC API |
||||
|
||||
```protobuf |
||||
service ACLService { |
||||
// Readiness |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
|
||||
// Access checks |
||||
rpc CheckAccess(CheckAccessRequest) returns (CheckAccessResponse); |
||||
rpc GetAccessLevel(GetAccessLevelRequest) returns (GetAccessLevelResponse); |
||||
rpc CheckPolicy(CheckPolicyRequest) returns (CheckPolicyResponse); |
||||
|
||||
// Admin operations |
||||
rpc Configure(ConfigureRequest) returns (ConfigureResponse); |
||||
rpc GetType(Empty) returns (TypeResponse); |
||||
} |
||||
``` |
||||
|
||||
### Environment Variables |
||||
|
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_ACL_LISTEN` | 127.0.0.1:50052 | gRPC listen address | |
||||
| `ORLY_ACL_MODE` | follows | ACL mode | |
||||
| `ORLY_ACL_DB_TYPE` | grpc | Database backend | |
||||
| `ORLY_ACL_GRPC_DB_SERVER` | 127.0.0.1:50051 | Database server | |
||||
| `ORLY_ACL_LOG_LEVEL` | info | Logging level | |
||||
|
||||
--- |
||||
|
||||
## 3. Main Relay (orly) |
||||
|
||||
The main relay handles all client-facing operations. |
||||
|
||||
### Responsibilities |
||||
- WebSocket connections (NIP-01) |
||||
- REQ/EVENT/AUTH/CLOSE handling |
||||
- NEG-* messages (NIP-77, when enabled) |
||||
- HTTP API endpoints |
||||
- Web UI serving |
||||
|
||||
### Connection Modes |
||||
|
||||
**Local mode** (default): |
||||
```bash |
||||
ORLY_DB_TYPE=badger |
||||
ORLY_ACL_TYPE=local |
||||
``` |
||||
|
||||
**gRPC mode** (IPC): |
||||
```bash |
||||
ORLY_DB_TYPE=grpc |
||||
ORLY_GRPC_SERVER=127.0.0.1:50051 |
||||
ORLY_ACL_TYPE=grpc |
||||
ORLY_GRPC_ACL_SERVER=127.0.0.1:50052 |
||||
ORLY_NEGENTROPY_ENABLED=true |
||||
ORLY_GRPC_SYNC_NEGENTROPY=127.0.0.1:50064 |
||||
``` |
||||
|
||||
--- |
||||
|
||||
# Sync Services |
||||
|
||||
See [IPC_SYNC_SERVICES.md](./IPC_SYNC_SERVICES.md) for detailed sync service documentation. |
||||
|
||||
## Quick Reference |
||||
|
||||
| Service | Port | Purpose | |
||||
|---------|------|---------| |
||||
| orly-sync-distributed | 50061 | Serial-based peer sync | |
||||
| orly-sync-cluster | 50062 | HA cluster replication | |
||||
| orly-sync-relaygroup | 50063 | Kind 39105 relay groups | |
||||
| orly-sync-negentropy | 50064 | NIP-77 set reconciliation | |
||||
|
||||
--- |
||||
|
||||
# Deployment Examples |
||||
|
||||
## Minimal IPC (Database + Relay) |
||||
|
||||
```bash |
||||
# Start database |
||||
ORLY_DB_LISTEN=127.0.0.1:50051 ./orly-db-badger & |
||||
|
||||
# Start relay with gRPC database |
||||
ORLY_DB_TYPE=grpc \ |
||||
ORLY_GRPC_SERVER=127.0.0.1:50051 \ |
||||
./orly |
||||
``` |
||||
|
||||
## Full IPC with ACL |
||||
|
||||
```bash |
||||
# Use launcher for automatic management |
||||
ORLY_LAUNCHER_DB_BACKEND=badger \ |
||||
ORLY_LAUNCHER_ACL_ENABLED=true \ |
||||
ORLY_ACL_MODE=follows \ |
||||
./orly-launcher |
||||
``` |
||||
|
||||
## Full IPC with Negentropy |
||||
|
||||
```bash |
||||
# Enable NIP-77 support |
||||
ORLY_LAUNCHER_DB_BACKEND=badger \ |
||||
ORLY_LAUNCHER_ACL_ENABLED=true \ |
||||
ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED=true \ |
||||
ORLY_NEGENTROPY_ENABLED=true \ |
||||
./orly-launcher |
||||
``` |
||||
|
||||
## systemd Service |
||||
|
||||
See the example at `/etc/systemd/system/orly.service` on relay.orly.dev for a production configuration. |
||||
|
||||
--- |
||||
|
||||
# Building Binaries |
||||
|
||||
```bash |
||||
# Build all IPC binaries |
||||
make all-acl # Builds orly-db-*, orly-acl-*, orly-launcher |
||||
|
||||
# Build sync services |
||||
go build -o orly-sync-distributed ./cmd/orly-sync-distributed |
||||
go build -o orly-sync-cluster ./cmd/orly-sync-cluster |
||||
go build -o orly-sync-relaygroup ./cmd/orly-sync-relaygroup |
||||
go build -o orly-sync-negentropy ./cmd/orly-sync-negentropy |
||||
|
||||
# Cross-compile for ARM64 |
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o orly-sync-negentropy ./cmd/orly-sync-negentropy |
||||
``` |
||||
|
||||
--- |
||||
|
||||
# Monitoring |
||||
|
||||
## Health Checks |
||||
|
||||
Each gRPC service implements a `Ready` RPC that returns when the service is accepting requests. |
||||
|
||||
## Logs |
||||
|
||||
All services log to stdout/stderr. Use journalctl for systemd deployments: |
||||
|
||||
```bash |
||||
# Follow all ORLY logs |
||||
journalctl -u orly -f |
||||
|
||||
# Filter by process |
||||
journalctl -u orly | grep "orly-db" |
||||
journalctl -u orly | grep "orly-sync-negentropy" |
||||
``` |
||||
|
||||
## pprof |
||||
|
||||
Enable HTTP pprof for profiling: |
||||
|
||||
```bash |
||||
ORLY_PPROF_HTTP=true ./orly-launcher |
||||
# Access at http://localhost:6060/debug/pprof/ |
||||
``` |
||||
|
||||
--- |
||||
|
||||
# Troubleshooting |
||||
|
||||
## Service won't start |
||||
|
||||
1. Check if port is in use: `ss -tlnp | grep 5005` |
||||
2. Verify binary exists and is executable |
||||
3. Check logs: `journalctl -u orly -n 100` |
||||
|
||||
## Database connection timeout |
||||
|
||||
1. Ensure database started first |
||||
2. Check `ORLY_LAUNCHER_DB_READY_TIMEOUT` (default 30s) |
||||
3. Verify network connectivity |
||||
|
||||
## Negentropy not working |
||||
|
||||
1. Verify `ORLY_NEGENTROPY_ENABLED=true` in relay config |
||||
2. Check negentropy service is running: `ps aux | grep negentropy` |
||||
3. Verify gRPC connection: `ORLY_GRPC_SYNC_NEGENTROPY=127.0.0.1:50064` |
||||
@ -0,0 +1,316 @@
@@ -0,0 +1,316 @@
|
||||
# IPC Sync Services Architecture |
||||
|
||||
ORLY supports splitting sync functionality into independent gRPC IPC services for improved modularity, resource isolation, and horizontal scaling. |
||||
|
||||
## Overview |
||||
|
||||
The sync subsystem can run in two modes: |
||||
|
||||
1. **Local mode** (default): All sync functionality runs in-process with the main relay |
||||
2. **gRPC mode**: Sync services run as separate processes communicating via gRPC |
||||
|
||||
## Architecture |
||||
|
||||
``` |
||||
┌─────────────────────────────────────────────────────────────────────────────┐ |
||||
│ orly-launcher │ |
||||
│ (Process supervisor - manages lifecycle of all services) │ |
||||
└─────────────────────────────────────────────────────────────────────────────┘ |
||||
│ |
||||
┌──────────────────────────┼──────────────────────────┐ |
||||
│ │ │ |
||||
▼ ▼ ▼ |
||||
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ |
||||
│ orly-db │ │ orly-acl │ │ Sync Services │ |
||||
│ (gRPC :50051) │ │ (gRPC :50052) │ │ (gRPC :50061-64) │ |
||||
│ │ │ │ │ │ |
||||
│ - Event storage │ │ - Access control │ │ - Distributed sync │ |
||||
│ - Query execution │ │ - Follow lists │ │ - Cluster sync │ |
||||
│ - Index management │ │ - Permissions │ │ - Relay groups │ |
||||
└─────────────────────┘ └─────────────────────┘ │ - Negentropy/NIP-77 │ |
||||
│ │ └─────────────────────┘ |
||||
│ │ │ |
||||
└──────────────────────────┼──────────────────────────┘ |
||||
│ |
||||
▼ |
||||
┌─────────────────────┐ |
||||
│ orly │ |
||||
│ (Main relay) │ |
||||
│ │ |
||||
│ - WebSocket server │ |
||||
│ - HTTP endpoints │ |
||||
│ - NIP handling │ |
||||
└─────────────────────┘ |
||||
``` |
||||
|
||||
## Sync Services |
||||
|
||||
### 1. orly-sync-distributed (Port 50061) |
||||
|
||||
Serial-based peer-to-peer synchronization between relay instances. |
||||
|
||||
**Purpose**: Keeps multiple relay instances in sync by exchanging events based on serial numbers (Lamport clocks). |
||||
|
||||
**Key Features**: |
||||
- Periodic polling of peer relays |
||||
- NIP-11 relay info caching for peer identification |
||||
- NIP-98 authenticated sync requests |
||||
- Incremental sync using serial numbers |
||||
|
||||
**gRPC API**: |
||||
```protobuf |
||||
service DistributedSyncService { |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
rpc GetInfo(Empty) returns (SyncInfo); |
||||
rpc GetCurrentSerial(CurrentRequest) returns (CurrentResponse); |
||||
rpc GetEventIDs(EventIDsRequest) returns (EventIDsResponse); |
||||
rpc HandleCurrentRequest(HTTPRequest) returns (HTTPResponse); |
||||
rpc HandleEventIDsRequest(HTTPRequest) returns (HTTPResponse); |
||||
rpc GetPeers(Empty) returns (PeersResponse); |
||||
rpc UpdatePeers(UpdatePeersRequest) returns (Empty); |
||||
rpc GetSyncStatus(Empty) returns (SyncStatusResponse); |
||||
rpc GetPeerPubkey(PeerPubkeyRequest) returns (PeerPubkeyResponse); |
||||
rpc IsAuthorizedPeer(AuthorizedPeerRequest) returns (AuthorizedPeerResponse); |
||||
rpc NotifyNewEvent(NewEventNotification) returns (Empty); |
||||
} |
||||
``` |
||||
|
||||
**Environment Variables**: |
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_SYNC_DISTRIBUTED_LISTEN` | 127.0.0.1:50061 | gRPC listen address | |
||||
| `ORLY_SYNC_DISTRIBUTED_DB_TYPE` | grpc | Database backend | |
||||
| `ORLY_SYNC_DISTRIBUTED_DB_SERVER` | 127.0.0.1:50051 | Database server address | |
||||
| `ORLY_SYNC_DISTRIBUTED_PEERS` | | Comma-separated peer URLs | |
||||
| `ORLY_SYNC_DISTRIBUTED_INTERVAL` | 30s | Sync polling interval | |
||||
|
||||
--- |
||||
|
||||
### 2. orly-sync-cluster (Port 50062) |
||||
|
||||
Cluster replication with persistent state for high-availability deployments. |
||||
|
||||
**Purpose**: Enables multiple relay instances to form a cluster with consistent event replication. |
||||
|
||||
**Key Features**: |
||||
- Real-time event propagation to cluster members |
||||
- Cluster membership management via Kind 39108 events |
||||
- Persistent tracking of cluster member state |
||||
- Configurable privileged event propagation (DMs, gift wraps) |
||||
|
||||
**gRPC API**: |
||||
```protobuf |
||||
service ClusterSyncService { |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
rpc Start(Empty) returns (Empty); |
||||
rpc Stop(Empty) returns (Empty); |
||||
rpc HandleLatestSerial(HTTPRequest) returns (HTTPResponse); |
||||
rpc HandleEventsRange(HTTPRequest) returns (HTTPResponse); |
||||
rpc GetMembers(Empty) returns (MembersResponse); |
||||
rpc UpdateMembership(UpdateMembershipRequest) returns (Empty); |
||||
rpc HandleMembershipEvent(MembershipEventRequest) returns (Empty); |
||||
rpc GetClusterStatus(Empty) returns (ClusterStatusResponse); |
||||
rpc GetMemberStatus(MemberStatusRequest) returns (MemberStatusResponse); |
||||
rpc GetLatestSerial(Empty) returns (LatestSerialResponse); |
||||
rpc GetEventsInRange(EventsRangeRequest) returns (EventsRangeResponse); |
||||
} |
||||
``` |
||||
|
||||
**Environment Variables**: |
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_SYNC_CLUSTER_LISTEN` | 127.0.0.1:50062 | gRPC listen address | |
||||
| `ORLY_SYNC_CLUSTER_DB_TYPE` | grpc | Database backend | |
||||
| `ORLY_SYNC_CLUSTER_DB_SERVER` | 127.0.0.1:50051 | Database server address | |
||||
| `ORLY_CLUSTER_ADMINS` | | Authorized cluster admin pubkeys | |
||||
| `ORLY_CLUSTER_PROPAGATE_PRIVILEGED_EVENTS` | true | Replicate DMs/gift wraps | |
||||
|
||||
--- |
||||
|
||||
### 3. orly-sync-relaygroup (Port 50063) |
||||
|
||||
Relay group configuration discovery using Kind 39105 events. |
||||
|
||||
**Purpose**: Manages relay group configurations that define which relays should sync together. |
||||
|
||||
**Key Features**: |
||||
- Discovery of authoritative relay group configs |
||||
- Validation of relay group events |
||||
- Authorized publisher management |
||||
- Dynamic peer list updates |
||||
|
||||
**gRPC API**: |
||||
```protobuf |
||||
service RelayGroupService { |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
rpc FindAuthoritativeConfig(Empty) returns (RelayGroupConfigResponse); |
||||
rpc GetRelays(Empty) returns (RelaysResponse); |
||||
rpc IsAuthorizedPublisher(AuthorizedPublisherRequest) returns (AuthorizedPublisherResponse); |
||||
rpc GetAuthorizedPubkeys(Empty) returns (AuthorizedPubkeysResponse); |
||||
rpc ValidateRelayGroupEvent(ValidateEventRequest) returns (ValidateEventResponse); |
||||
rpc HandleRelayGroupEvent(HandleEventRequest) returns (Empty); |
||||
} |
||||
``` |
||||
|
||||
**Environment Variables**: |
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_SYNC_RELAYGROUP_LISTEN` | 127.0.0.1:50063 | gRPC listen address | |
||||
| `ORLY_SYNC_RELAYGROUP_DB_TYPE` | grpc | Database backend | |
||||
| `ORLY_SYNC_RELAYGROUP_DB_SERVER` | 127.0.0.1:50051 | Database server address | |
||||
| `ORLY_RELAY_GROUP_ADMINS` | | Authorized relay group config publishers | |
||||
|
||||
--- |
||||
|
||||
### 4. orly-sync-negentropy (Port 50064) |
||||
|
||||
NIP-77 negentropy-based efficient set reconciliation. |
||||
|
||||
**Purpose**: Provides efficient set reconciliation for both relay-to-relay sync and client-facing NIP-77 WebSocket protocol. |
||||
|
||||
**Key Features**: |
||||
- NIP-77 client WebSocket support (NEG-OPEN, NEG-MSG, NEG-CLOSE) |
||||
- Relay-to-relay negentropy sync |
||||
- Session management for concurrent clients |
||||
- Configurable frame size and ID truncation |
||||
|
||||
**gRPC API**: |
||||
```protobuf |
||||
service NegentropyService { |
||||
rpc Ready(Empty) returns (ReadyResponse); |
||||
rpc Start(Empty) returns (Empty); |
||||
rpc Stop(Empty) returns (Empty); |
||||
|
||||
// Client-facing NIP-77 |
||||
rpc HandleNegOpen(NegOpenRequest) returns (NegOpenResponse); |
||||
rpc HandleNegMsg(NegMsgRequest) returns (NegMsgResponse); |
||||
rpc HandleNegClose(NegCloseRequest) returns (Empty); |
||||
|
||||
// Relay-to-relay sync |
||||
rpc SyncWithPeer(SyncPeerRequest) returns (stream SyncProgress); |
||||
rpc GetSyncStatus(Empty) returns (SyncStatusResponse); |
||||
rpc GetPeers(Empty) returns (PeersResponse); |
||||
rpc AddPeer(AddPeerRequest) returns (Empty); |
||||
rpc RemovePeer(RemovePeerRequest) returns (Empty); |
||||
rpc TriggerSync(TriggerSyncRequest) returns (Empty); |
||||
rpc GetPeerSyncState(PeerSyncStateRequest) returns (PeerSyncStateResponse); |
||||
|
||||
// Session management |
||||
rpc ListSessions(Empty) returns (ListSessionsResponse); |
||||
rpc CloseSession(CloseSessionRequest) returns (Empty); |
||||
} |
||||
``` |
||||
|
||||
**Environment Variables**: |
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_SYNC_NEGENTROPY_LISTEN` | 127.0.0.1:50064 | gRPC listen address | |
||||
| `ORLY_SYNC_NEGENTROPY_DB_TYPE` | grpc | Database backend | |
||||
| `ORLY_SYNC_NEGENTROPY_DB_SERVER` | 127.0.0.1:50051 | Database server address | |
||||
| `ORLY_SYNC_NEGENTROPY_PEERS` | | Comma-separated peer WebSocket URLs | |
||||
| `ORLY_SYNC_NEGENTROPY_INTERVAL` | 60s | Background sync interval | |
||||
| `ORLY_SYNC_NEGENTROPY_FRAME_SIZE` | 4096 | Negentropy frame size | |
||||
| `ORLY_SYNC_NEGENTROPY_ID_SIZE` | 16 | ID truncation size | |
||||
| `ORLY_SYNC_NEGENTROPY_SESSION_TIMEOUT` | 5m | Client session timeout | |
||||
|
||||
--- |
||||
|
||||
## Launcher Configuration |
||||
|
||||
The `orly-launcher` manages all services. Enable sync services with these environment variables: |
||||
|
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_LAUNCHER_SYNC_DISTRIBUTED_ENABLED` | false | Enable distributed sync | |
||||
| `ORLY_LAUNCHER_SYNC_DISTRIBUTED_BINARY` | orly-sync-distributed | Binary path | |
||||
| `ORLY_LAUNCHER_SYNC_DISTRIBUTED_LISTEN` | 127.0.0.1:50061 | Listen address | |
||||
| `ORLY_LAUNCHER_SYNC_CLUSTER_ENABLED` | false | Enable cluster sync | |
||||
| `ORLY_LAUNCHER_SYNC_CLUSTER_BINARY` | orly-sync-cluster | Binary path | |
||||
| `ORLY_LAUNCHER_SYNC_CLUSTER_LISTEN` | 127.0.0.1:50062 | Listen address | |
||||
| `ORLY_LAUNCHER_SYNC_RELAYGROUP_ENABLED` | false | Enable relay group | |
||||
| `ORLY_LAUNCHER_SYNC_RELAYGROUP_BINARY` | orly-sync-relaygroup | Binary path | |
||||
| `ORLY_LAUNCHER_SYNC_RELAYGROUP_LISTEN` | 127.0.0.1:50063 | Listen address | |
||||
| `ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED` | false | Enable negentropy | |
||||
| `ORLY_LAUNCHER_SYNC_NEGENTROPY_BINARY` | orly-sync-negentropy | Binary path | |
||||
| `ORLY_LAUNCHER_SYNC_NEGENTROPY_LISTEN` | 127.0.0.1:50064 | Listen address | |
||||
| `ORLY_LAUNCHER_SYNC_READY_TIMEOUT` | 30s | Sync service startup timeout | |
||||
|
||||
--- |
||||
|
||||
## Relay Configuration |
||||
|
||||
When sync services are enabled, configure the relay to connect: |
||||
|
||||
| Variable | Default | Description | |
||||
|----------|---------|-------------| |
||||
| `ORLY_SYNC_TYPE` | local | Sync backend: local or grpc | |
||||
| `ORLY_GRPC_SYNC_DISTRIBUTED` | | Distributed sync server address | |
||||
| `ORLY_GRPC_SYNC_CLUSTER` | | Cluster sync server address | |
||||
| `ORLY_GRPC_SYNC_RELAYGROUP` | | Relay group server address | |
||||
| `ORLY_GRPC_SYNC_NEGENTROPY` | | Negentropy server address | |
||||
| `ORLY_GRPC_SYNC_TIMEOUT` | 10s | gRPC connection timeout | |
||||
| `ORLY_NEGENTROPY_ENABLED` | false | Enable NIP-77 WebSocket support | |
||||
|
||||
--- |
||||
|
||||
## Startup Order |
||||
|
||||
The launcher starts services in dependency order: |
||||
|
||||
1. **Database** (orly-db) - Must be ready first |
||||
2. **ACL** (orly-acl) - Depends on database |
||||
3. **Sync Services** (parallel) - All depend on database only |
||||
4. **Relay** (orly) - Depends on all above |
||||
|
||||
Shutdown happens in reverse order. |
||||
|
||||
--- |
||||
|
||||
## Example: Enabling Negentropy |
||||
|
||||
To enable NIP-77 negentropy support on an existing deployment: |
||||
|
||||
```bash |
||||
# In systemd service or environment |
||||
Environment=ORLY_LAUNCHER_SYNC_NEGENTROPY_ENABLED=true |
||||
Environment=ORLY_LAUNCHER_SYNC_NEGENTROPY_BINARY=/path/to/orly-sync-negentropy |
||||
Environment=ORLY_NEGENTROPY_ENABLED=true |
||||
``` |
||||
|
||||
Build the binary: |
||||
```bash |
||||
CGO_ENABLED=0 go build -o orly-sync-negentropy ./cmd/orly-sync-negentropy |
||||
``` |
||||
|
||||
--- |
||||
|
||||
## Proto Definitions |
||||
|
||||
Proto files are located in: |
||||
- `proto/orlysync/common/v1/types.proto` - Shared types |
||||
- `proto/orlysync/distributed/v1/service.proto` - Distributed sync |
||||
- `proto/orlysync/cluster/v1/service.proto` - Cluster sync |
||||
- `proto/orlysync/relaygroup/v1/service.proto` - Relay group |
||||
- `proto/orlysync/negentropy/v1/service.proto` - Negentropy |
||||
|
||||
Generate Go code with: |
||||
```bash |
||||
buf generate |
||||
``` |
||||
|
||||
--- |
||||
|
||||
## NIP-77 Client Protocol |
||||
|
||||
The negentropy service implements NIP-77 for efficient client synchronization: |
||||
|
||||
### Client Messages |
||||
- `["NEG-OPEN", subscription_id, filter, initial_message?]` - Start reconciliation |
||||
- `["NEG-MSG", subscription_id, message]` - Continue reconciliation |
||||
- `["NEG-CLOSE", subscription_id]` - End session |
||||
|
||||
### Server Responses |
||||
- `["NEG-MSG", subscription_id, message]` - Reconciliation response |
||||
- `["NEG-ERR", subscription_id, reason]` - Error response |
||||
|
||||
The relay automatically routes these messages to the negentropy service when `ORLY_NEGENTROPY_ENABLED=true`. |
||||
@ -0,0 +1,808 @@
@@ -0,0 +1,808 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: orlysync/cluster/v1/service.proto
|
||||
|
||||
package clusterv1 |
||||
|
||||
import ( |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
reflect "reflect" |
||||
sync "sync" |
||||
unsafe "unsafe" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
// LatestSerialResponse contains the latest serial and timestamp
|
||||
type LatestSerialResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Serial uint64 `protobuf:"varint,1,opt,name=serial,proto3" json:"serial,omitempty"` |
||||
Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Unix timestamp
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *LatestSerialResponse) Reset() { |
||||
*x = LatestSerialResponse{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[0] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *LatestSerialResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*LatestSerialResponse) ProtoMessage() {} |
||||
|
||||
func (x *LatestSerialResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[0] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use LatestSerialResponse.ProtoReflect.Descriptor instead.
|
||||
func (*LatestSerialResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{0} |
||||
} |
||||
|
||||
func (x *LatestSerialResponse) GetSerial() uint64 { |
||||
if x != nil { |
||||
return x.Serial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *LatestSerialResponse) GetTimestamp() int64 { |
||||
if x != nil { |
||||
return x.Timestamp |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// EventsRangeRequest requests events in a serial range
|
||||
type EventsRangeRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
From uint64 `protobuf:"varint,1,opt,name=from,proto3" json:"from,omitempty"` // Start serial (inclusive)
|
||||
To uint64 `protobuf:"varint,2,opt,name=to,proto3" json:"to,omitempty"` // End serial (inclusive)
|
||||
Limit int32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` // Max events to return
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *EventsRangeRequest) Reset() { |
||||
*x = EventsRangeRequest{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[1] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *EventsRangeRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*EventsRangeRequest) ProtoMessage() {} |
||||
|
||||
func (x *EventsRangeRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[1] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use EventsRangeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*EventsRangeRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{1} |
||||
} |
||||
|
||||
func (x *EventsRangeRequest) GetFrom() uint64 { |
||||
if x != nil { |
||||
return x.From |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *EventsRangeRequest) GetTo() uint64 { |
||||
if x != nil { |
||||
return x.To |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *EventsRangeRequest) GetLimit() int32 { |
||||
if x != nil { |
||||
return x.Limit |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// EventsRangeResponse contains events in the requested range
|
||||
type EventsRangeResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Events []*EventInfo `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` |
||||
HasMore bool `protobuf:"varint,2,opt,name=has_more,json=hasMore,proto3" json:"has_more,omitempty"` |
||||
NextFrom uint64 `protobuf:"varint,3,opt,name=next_from,json=nextFrom,proto3" json:"next_from,omitempty"` // Next serial if has_more is true
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *EventsRangeResponse) Reset() { |
||||
*x = EventsRangeResponse{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[2] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *EventsRangeResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*EventsRangeResponse) ProtoMessage() {} |
||||
|
||||
func (x *EventsRangeResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[2] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use EventsRangeResponse.ProtoReflect.Descriptor instead.
|
||||
func (*EventsRangeResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{2} |
||||
} |
||||
|
||||
func (x *EventsRangeResponse) GetEvents() []*EventInfo { |
||||
if x != nil { |
||||
return x.Events |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *EventsRangeResponse) GetHasMore() bool { |
||||
if x != nil { |
||||
return x.HasMore |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (x *EventsRangeResponse) GetNextFrom() uint64 { |
||||
if x != nil { |
||||
return x.NextFrom |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// EventInfo contains metadata about an event
|
||||
type EventInfo struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Serial uint64 `protobuf:"varint,1,opt,name=serial,proto3" json:"serial,omitempty"` |
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` // Event ID (hex)
|
||||
Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Created timestamp
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *EventInfo) Reset() { |
||||
*x = EventInfo{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[3] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *EventInfo) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*EventInfo) ProtoMessage() {} |
||||
|
||||
func (x *EventInfo) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[3] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use EventInfo.ProtoReflect.Descriptor instead.
|
||||
func (*EventInfo) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{3} |
||||
} |
||||
|
||||
func (x *EventInfo) GetSerial() uint64 { |
||||
if x != nil { |
||||
return x.Serial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *EventInfo) GetId() string { |
||||
if x != nil { |
||||
return x.Id |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *EventInfo) GetTimestamp() int64 { |
||||
if x != nil { |
||||
return x.Timestamp |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// ClusterMember represents a cluster member
|
||||
type ClusterMember struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
HttpUrl string `protobuf:"bytes,1,opt,name=http_url,json=httpUrl,proto3" json:"http_url,omitempty"` |
||||
WebsocketUrl string `protobuf:"bytes,2,opt,name=websocket_url,json=websocketUrl,proto3" json:"websocket_url,omitempty"` |
||||
LastSerial uint64 `protobuf:"varint,3,opt,name=last_serial,json=lastSerial,proto3" json:"last_serial,omitempty"` |
||||
LastPoll int64 `protobuf:"varint,4,opt,name=last_poll,json=lastPoll,proto3" json:"last_poll,omitempty"` // Unix timestamp
|
||||
Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` // "active", "error", "unknown"
|
||||
ErrorCount int32 `protobuf:"varint,6,opt,name=error_count,json=errorCount,proto3" json:"error_count,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *ClusterMember) Reset() { |
||||
*x = ClusterMember{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[4] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *ClusterMember) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*ClusterMember) ProtoMessage() {} |
||||
|
||||
func (x *ClusterMember) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[4] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use ClusterMember.ProtoReflect.Descriptor instead.
|
||||
func (*ClusterMember) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{4} |
||||
} |
||||
|
||||
func (x *ClusterMember) GetHttpUrl() string { |
||||
if x != nil { |
||||
return x.HttpUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *ClusterMember) GetWebsocketUrl() string { |
||||
if x != nil { |
||||
return x.WebsocketUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *ClusterMember) GetLastSerial() uint64 { |
||||
if x != nil { |
||||
return x.LastSerial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *ClusterMember) GetLastPoll() int64 { |
||||
if x != nil { |
||||
return x.LastPoll |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *ClusterMember) GetStatus() string { |
||||
if x != nil { |
||||
return x.Status |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *ClusterMember) GetErrorCount() int32 { |
||||
if x != nil { |
||||
return x.ErrorCount |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// MembersResponse contains the list of cluster members
|
||||
type MembersResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Members []*ClusterMember `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *MembersResponse) Reset() { |
||||
*x = MembersResponse{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[5] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *MembersResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*MembersResponse) ProtoMessage() {} |
||||
|
||||
func (x *MembersResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[5] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use MembersResponse.ProtoReflect.Descriptor instead.
|
||||
func (*MembersResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{5} |
||||
} |
||||
|
||||
func (x *MembersResponse) GetMembers() []*ClusterMember { |
||||
if x != nil { |
||||
return x.Members |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// UpdateMembershipRequest updates cluster membership
|
||||
type UpdateMembershipRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
RelayUrls []string `protobuf:"bytes,1,rep,name=relay_urls,json=relayUrls,proto3" json:"relay_urls,omitempty"` // List of relay URLs to add
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *UpdateMembershipRequest) Reset() { |
||||
*x = UpdateMembershipRequest{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[6] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *UpdateMembershipRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*UpdateMembershipRequest) ProtoMessage() {} |
||||
|
||||
func (x *UpdateMembershipRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[6] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use UpdateMembershipRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateMembershipRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{6} |
||||
} |
||||
|
||||
func (x *UpdateMembershipRequest) GetRelayUrls() []string { |
||||
if x != nil { |
||||
return x.RelayUrls |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// MembershipEventRequest contains a cluster membership event
|
||||
type MembershipEventRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Event *v1.Event `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *MembershipEventRequest) Reset() { |
||||
*x = MembershipEventRequest{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[7] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *MembershipEventRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*MembershipEventRequest) ProtoMessage() {} |
||||
|
||||
func (x *MembershipEventRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[7] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use MembershipEventRequest.ProtoReflect.Descriptor instead.
|
||||
func (*MembershipEventRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{7} |
||||
} |
||||
|
||||
func (x *MembershipEventRequest) GetEvent() *v1.Event { |
||||
if x != nil { |
||||
return x.Event |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ClusterStatusResponse contains overall cluster status
|
||||
type ClusterStatusResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
LatestSerial uint64 `protobuf:"varint,1,opt,name=latest_serial,json=latestSerial,proto3" json:"latest_serial,omitempty"` |
||||
ActiveMembers int32 `protobuf:"varint,2,opt,name=active_members,json=activeMembers,proto3" json:"active_members,omitempty"` |
||||
TotalMembers int32 `protobuf:"varint,3,opt,name=total_members,json=totalMembers,proto3" json:"total_members,omitempty"` |
||||
PropagatePrivilegedEvents bool `protobuf:"varint,4,opt,name=propagate_privileged_events,json=propagatePrivilegedEvents,proto3" json:"propagate_privileged_events,omitempty"` |
||||
Members []*ClusterMember `protobuf:"bytes,5,rep,name=members,proto3" json:"members,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) Reset() { |
||||
*x = ClusterStatusResponse{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[8] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*ClusterStatusResponse) ProtoMessage() {} |
||||
|
||||
func (x *ClusterStatusResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[8] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use ClusterStatusResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ClusterStatusResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{8} |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) GetLatestSerial() uint64 { |
||||
if x != nil { |
||||
return x.LatestSerial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) GetActiveMembers() int32 { |
||||
if x != nil { |
||||
return x.ActiveMembers |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) GetTotalMembers() int32 { |
||||
if x != nil { |
||||
return x.TotalMembers |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) GetPropagatePrivilegedEvents() bool { |
||||
if x != nil { |
||||
return x.PropagatePrivilegedEvents |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (x *ClusterStatusResponse) GetMembers() []*ClusterMember { |
||||
if x != nil { |
||||
return x.Members |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// MemberStatusRequest requests status for a specific member
|
||||
type MemberStatusRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
HttpUrl string `protobuf:"bytes,1,opt,name=http_url,json=httpUrl,proto3" json:"http_url,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *MemberStatusRequest) Reset() { |
||||
*x = MemberStatusRequest{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[9] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *MemberStatusRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*MemberStatusRequest) ProtoMessage() {} |
||||
|
||||
func (x *MemberStatusRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[9] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use MemberStatusRequest.ProtoReflect.Descriptor instead.
|
||||
func (*MemberStatusRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{9} |
||||
} |
||||
|
||||
func (x *MemberStatusRequest) GetHttpUrl() string { |
||||
if x != nil { |
||||
return x.HttpUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// MemberStatusResponse contains status for a member
|
||||
type MemberStatusResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Member *ClusterMember `protobuf:"bytes,1,opt,name=member,proto3" json:"member,omitempty"` |
||||
Found bool `protobuf:"varint,2,opt,name=found,proto3" json:"found,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *MemberStatusResponse) Reset() { |
||||
*x = MemberStatusResponse{} |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[10] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *MemberStatusResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*MemberStatusResponse) ProtoMessage() {} |
||||
|
||||
func (x *MemberStatusResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_cluster_v1_service_proto_msgTypes[10] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use MemberStatusResponse.ProtoReflect.Descriptor instead.
|
||||
func (*MemberStatusResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_cluster_v1_service_proto_rawDescGZIP(), []int{10} |
||||
} |
||||
|
||||
func (x *MemberStatusResponse) GetMember() *ClusterMember { |
||||
if x != nil { |
||||
return x.Member |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *MemberStatusResponse) GetFound() bool { |
||||
if x != nil { |
||||
return x.Found |
||||
} |
||||
return false |
||||
} |
||||
|
||||
var File_orlysync_cluster_v1_service_proto protoreflect.FileDescriptor |
||||
|
||||
const file_orlysync_cluster_v1_service_proto_rawDesc = "" + |
||||
"\n" + |
||||
"!orlysync/cluster/v1/service.proto\x12\x13orlysync.cluster.v1\x1a\x1eorlysync/common/v1/types.proto\"L\n" + |
||||
"\x14LatestSerialResponse\x12\x16\n" + |
||||
"\x06serial\x18\x01 \x01(\x04R\x06serial\x12\x1c\n" + |
||||
"\ttimestamp\x18\x02 \x01(\x03R\ttimestamp\"N\n" + |
||||
"\x12EventsRangeRequest\x12\x12\n" + |
||||
"\x04from\x18\x01 \x01(\x04R\x04from\x12\x0e\n" + |
||||
"\x02to\x18\x02 \x01(\x04R\x02to\x12\x14\n" + |
||||
"\x05limit\x18\x03 \x01(\x05R\x05limit\"\x85\x01\n" + |
||||
"\x13EventsRangeResponse\x126\n" + |
||||
"\x06events\x18\x01 \x03(\v2\x1e.orlysync.cluster.v1.EventInfoR\x06events\x12\x19\n" + |
||||
"\bhas_more\x18\x02 \x01(\bR\ahasMore\x12\x1b\n" + |
||||
"\tnext_from\x18\x03 \x01(\x04R\bnextFrom\"Q\n" + |
||||
"\tEventInfo\x12\x16\n" + |
||||
"\x06serial\x18\x01 \x01(\x04R\x06serial\x12\x0e\n" + |
||||
"\x02id\x18\x02 \x01(\tR\x02id\x12\x1c\n" + |
||||
"\ttimestamp\x18\x03 \x01(\x03R\ttimestamp\"\xc6\x01\n" + |
||||
"\rClusterMember\x12\x19\n" + |
||||
"\bhttp_url\x18\x01 \x01(\tR\ahttpUrl\x12#\n" + |
||||
"\rwebsocket_url\x18\x02 \x01(\tR\fwebsocketUrl\x12\x1f\n" + |
||||
"\vlast_serial\x18\x03 \x01(\x04R\n" + |
||||
"lastSerial\x12\x1b\n" + |
||||
"\tlast_poll\x18\x04 \x01(\x03R\blastPoll\x12\x16\n" + |
||||
"\x06status\x18\x05 \x01(\tR\x06status\x12\x1f\n" + |
||||
"\verror_count\x18\x06 \x01(\x05R\n" + |
||||
"errorCount\"O\n" + |
||||
"\x0fMembersResponse\x12<\n" + |
||||
"\amembers\x18\x01 \x03(\v2\".orlysync.cluster.v1.ClusterMemberR\amembers\"8\n" + |
||||
"\x17UpdateMembershipRequest\x12\x1d\n" + |
||||
"\n" + |
||||
"relay_urls\x18\x01 \x03(\tR\trelayUrls\"I\n" + |
||||
"\x16MembershipEventRequest\x12/\n" + |
||||
"\x05event\x18\x01 \x01(\v2\x19.orlysync.common.v1.EventR\x05event\"\x86\x02\n" + |
||||
"\x15ClusterStatusResponse\x12#\n" + |
||||
"\rlatest_serial\x18\x01 \x01(\x04R\flatestSerial\x12%\n" + |
||||
"\x0eactive_members\x18\x02 \x01(\x05R\ractiveMembers\x12#\n" + |
||||
"\rtotal_members\x18\x03 \x01(\x05R\ftotalMembers\x12>\n" + |
||||
"\x1bpropagate_privileged_events\x18\x04 \x01(\bR\x19propagatePrivilegedEvents\x12<\n" + |
||||
"\amembers\x18\x05 \x03(\v2\".orlysync.cluster.v1.ClusterMemberR\amembers\"0\n" + |
||||
"\x13MemberStatusRequest\x12\x19\n" + |
||||
"\bhttp_url\x18\x01 \x01(\tR\ahttpUrl\"h\n" + |
||||
"\x14MemberStatusResponse\x12:\n" + |
||||
"\x06member\x18\x01 \x01(\v2\".orlysync.cluster.v1.ClusterMemberR\x06member\x12\x14\n" + |
||||
"\x05found\x18\x02 \x01(\bR\x05found2\x99\b\n" + |
||||
"\x12ClusterSyncService\x12E\n" + |
||||
"\x05Ready\x12\x19.orlysync.common.v1.Empty\x1a!.orlysync.common.v1.ReadyResponse\x12=\n" + |
||||
"\x05Start\x12\x19.orlysync.common.v1.Empty\x1a\x19.orlysync.common.v1.Empty\x12<\n" + |
||||
"\x04Stop\x12\x19.orlysync.common.v1.Empty\x1a\x19.orlysync.common.v1.Empty\x12W\n" + |
||||
"\x12HandleLatestSerial\x12\x1f.orlysync.common.v1.HTTPRequest\x1a .orlysync.common.v1.HTTPResponse\x12V\n" + |
||||
"\x11HandleEventsRange\x12\x1f.orlysync.common.v1.HTTPRequest\x1a .orlysync.common.v1.HTTPResponse\x12M\n" + |
||||
"\n" + |
||||
"GetMembers\x12\x19.orlysync.common.v1.Empty\x1a$.orlysync.cluster.v1.MembersResponse\x12[\n" + |
||||
"\x10UpdateMembership\x12,.orlysync.cluster.v1.UpdateMembershipRequest\x1a\x19.orlysync.common.v1.Empty\x12_\n" + |
||||
"\x15HandleMembershipEvent\x12+.orlysync.cluster.v1.MembershipEventRequest\x1a\x19.orlysync.common.v1.Empty\x12Y\n" + |
||||
"\x10GetClusterStatus\x12\x19.orlysync.common.v1.Empty\x1a*.orlysync.cluster.v1.ClusterStatusResponse\x12f\n" + |
||||
"\x0fGetMemberStatus\x12(.orlysync.cluster.v1.MemberStatusRequest\x1a).orlysync.cluster.v1.MemberStatusResponse\x12W\n" + |
||||
"\x0fGetLatestSerial\x12\x19.orlysync.common.v1.Empty\x1a).orlysync.cluster.v1.LatestSerialResponse\x12e\n" + |
||||
"\x10GetEventsInRange\x12'.orlysync.cluster.v1.EventsRangeRequest\x1a(.orlysync.cluster.v1.EventsRangeResponseB7Z5next.orly.dev/pkg/proto/orlysync/cluster/v1;clusterv1b\x06proto3" |
||||
|
||||
var ( |
||||
file_orlysync_cluster_v1_service_proto_rawDescOnce sync.Once |
||||
file_orlysync_cluster_v1_service_proto_rawDescData []byte |
||||
) |
||||
|
||||
func file_orlysync_cluster_v1_service_proto_rawDescGZIP() []byte { |
||||
file_orlysync_cluster_v1_service_proto_rawDescOnce.Do(func() { |
||||
file_orlysync_cluster_v1_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_orlysync_cluster_v1_service_proto_rawDesc), len(file_orlysync_cluster_v1_service_proto_rawDesc))) |
||||
}) |
||||
return file_orlysync_cluster_v1_service_proto_rawDescData |
||||
} |
||||
|
||||
var file_orlysync_cluster_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 11) |
||||
var file_orlysync_cluster_v1_service_proto_goTypes = []any{ |
||||
(*LatestSerialResponse)(nil), // 0: orlysync.cluster.v1.LatestSerialResponse
|
||||
(*EventsRangeRequest)(nil), // 1: orlysync.cluster.v1.EventsRangeRequest
|
||||
(*EventsRangeResponse)(nil), // 2: orlysync.cluster.v1.EventsRangeResponse
|
||||
(*EventInfo)(nil), // 3: orlysync.cluster.v1.EventInfo
|
||||
(*ClusterMember)(nil), // 4: orlysync.cluster.v1.ClusterMember
|
||||
(*MembersResponse)(nil), // 5: orlysync.cluster.v1.MembersResponse
|
||||
(*UpdateMembershipRequest)(nil), // 6: orlysync.cluster.v1.UpdateMembershipRequest
|
||||
(*MembershipEventRequest)(nil), // 7: orlysync.cluster.v1.MembershipEventRequest
|
||||
(*ClusterStatusResponse)(nil), // 8: orlysync.cluster.v1.ClusterStatusResponse
|
||||
(*MemberStatusRequest)(nil), // 9: orlysync.cluster.v1.MemberStatusRequest
|
||||
(*MemberStatusResponse)(nil), // 10: orlysync.cluster.v1.MemberStatusResponse
|
||||
(*v1.Event)(nil), // 11: orlysync.common.v1.Event
|
||||
(*v1.Empty)(nil), // 12: orlysync.common.v1.Empty
|
||||
(*v1.HTTPRequest)(nil), // 13: orlysync.common.v1.HTTPRequest
|
||||
(*v1.ReadyResponse)(nil), // 14: orlysync.common.v1.ReadyResponse
|
||||
(*v1.HTTPResponse)(nil), // 15: orlysync.common.v1.HTTPResponse
|
||||
} |
||||
var file_orlysync_cluster_v1_service_proto_depIdxs = []int32{ |
||||
3, // 0: orlysync.cluster.v1.EventsRangeResponse.events:type_name -> orlysync.cluster.v1.EventInfo
|
||||
4, // 1: orlysync.cluster.v1.MembersResponse.members:type_name -> orlysync.cluster.v1.ClusterMember
|
||||
11, // 2: orlysync.cluster.v1.MembershipEventRequest.event:type_name -> orlysync.common.v1.Event
|
||||
4, // 3: orlysync.cluster.v1.ClusterStatusResponse.members:type_name -> orlysync.cluster.v1.ClusterMember
|
||||
4, // 4: orlysync.cluster.v1.MemberStatusResponse.member:type_name -> orlysync.cluster.v1.ClusterMember
|
||||
12, // 5: orlysync.cluster.v1.ClusterSyncService.Ready:input_type -> orlysync.common.v1.Empty
|
||||
12, // 6: orlysync.cluster.v1.ClusterSyncService.Start:input_type -> orlysync.common.v1.Empty
|
||||
12, // 7: orlysync.cluster.v1.ClusterSyncService.Stop:input_type -> orlysync.common.v1.Empty
|
||||
13, // 8: orlysync.cluster.v1.ClusterSyncService.HandleLatestSerial:input_type -> orlysync.common.v1.HTTPRequest
|
||||
13, // 9: orlysync.cluster.v1.ClusterSyncService.HandleEventsRange:input_type -> orlysync.common.v1.HTTPRequest
|
||||
12, // 10: orlysync.cluster.v1.ClusterSyncService.GetMembers:input_type -> orlysync.common.v1.Empty
|
||||
6, // 11: orlysync.cluster.v1.ClusterSyncService.UpdateMembership:input_type -> orlysync.cluster.v1.UpdateMembershipRequest
|
||||
7, // 12: orlysync.cluster.v1.ClusterSyncService.HandleMembershipEvent:input_type -> orlysync.cluster.v1.MembershipEventRequest
|
||||
12, // 13: orlysync.cluster.v1.ClusterSyncService.GetClusterStatus:input_type -> orlysync.common.v1.Empty
|
||||
9, // 14: orlysync.cluster.v1.ClusterSyncService.GetMemberStatus:input_type -> orlysync.cluster.v1.MemberStatusRequest
|
||||
12, // 15: orlysync.cluster.v1.ClusterSyncService.GetLatestSerial:input_type -> orlysync.common.v1.Empty
|
||||
1, // 16: orlysync.cluster.v1.ClusterSyncService.GetEventsInRange:input_type -> orlysync.cluster.v1.EventsRangeRequest
|
||||
14, // 17: orlysync.cluster.v1.ClusterSyncService.Ready:output_type -> orlysync.common.v1.ReadyResponse
|
||||
12, // 18: orlysync.cluster.v1.ClusterSyncService.Start:output_type -> orlysync.common.v1.Empty
|
||||
12, // 19: orlysync.cluster.v1.ClusterSyncService.Stop:output_type -> orlysync.common.v1.Empty
|
||||
15, // 20: orlysync.cluster.v1.ClusterSyncService.HandleLatestSerial:output_type -> orlysync.common.v1.HTTPResponse
|
||||
15, // 21: orlysync.cluster.v1.ClusterSyncService.HandleEventsRange:output_type -> orlysync.common.v1.HTTPResponse
|
||||
5, // 22: orlysync.cluster.v1.ClusterSyncService.GetMembers:output_type -> orlysync.cluster.v1.MembersResponse
|
||||
12, // 23: orlysync.cluster.v1.ClusterSyncService.UpdateMembership:output_type -> orlysync.common.v1.Empty
|
||||
12, // 24: orlysync.cluster.v1.ClusterSyncService.HandleMembershipEvent:output_type -> orlysync.common.v1.Empty
|
||||
8, // 25: orlysync.cluster.v1.ClusterSyncService.GetClusterStatus:output_type -> orlysync.cluster.v1.ClusterStatusResponse
|
||||
10, // 26: orlysync.cluster.v1.ClusterSyncService.GetMemberStatus:output_type -> orlysync.cluster.v1.MemberStatusResponse
|
||||
0, // 27: orlysync.cluster.v1.ClusterSyncService.GetLatestSerial:output_type -> orlysync.cluster.v1.LatestSerialResponse
|
||||
2, // 28: orlysync.cluster.v1.ClusterSyncService.GetEventsInRange:output_type -> orlysync.cluster.v1.EventsRangeResponse
|
||||
17, // [17:29] is the sub-list for method output_type
|
||||
5, // [5:17] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_orlysync_cluster_v1_service_proto_init() } |
||||
func file_orlysync_cluster_v1_service_proto_init() { |
||||
if File_orlysync_cluster_v1_service_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_orlysync_cluster_v1_service_proto_rawDesc), len(file_orlysync_cluster_v1_service_proto_rawDesc)), |
||||
NumEnums: 0, |
||||
NumMessages: 11, |
||||
NumExtensions: 0, |
||||
NumServices: 1, |
||||
}, |
||||
GoTypes: file_orlysync_cluster_v1_service_proto_goTypes, |
||||
DependencyIndexes: file_orlysync_cluster_v1_service_proto_depIdxs, |
||||
MessageInfos: file_orlysync_cluster_v1_service_proto_msgTypes, |
||||
}.Build() |
||||
File_orlysync_cluster_v1_service_proto = out.File |
||||
file_orlysync_cluster_v1_service_proto_goTypes = nil |
||||
file_orlysync_cluster_v1_service_proto_depIdxs = nil |
||||
} |
||||
@ -0,0 +1,570 @@
@@ -0,0 +1,570 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: orlysync/cluster/v1/service.proto
|
||||
|
||||
package clusterv1 |
||||
|
||||
import ( |
||||
context "context" |
||||
grpc "google.golang.org/grpc" |
||||
codes "google.golang.org/grpc/codes" |
||||
status "google.golang.org/grpc/status" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9 |
||||
|
||||
const ( |
||||
ClusterSyncService_Ready_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/Ready" |
||||
ClusterSyncService_Start_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/Start" |
||||
ClusterSyncService_Stop_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/Stop" |
||||
ClusterSyncService_HandleLatestSerial_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/HandleLatestSerial" |
||||
ClusterSyncService_HandleEventsRange_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/HandleEventsRange" |
||||
ClusterSyncService_GetMembers_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/GetMembers" |
||||
ClusterSyncService_UpdateMembership_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/UpdateMembership" |
||||
ClusterSyncService_HandleMembershipEvent_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/HandleMembershipEvent" |
||||
ClusterSyncService_GetClusterStatus_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/GetClusterStatus" |
||||
ClusterSyncService_GetMemberStatus_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/GetMemberStatus" |
||||
ClusterSyncService_GetLatestSerial_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/GetLatestSerial" |
||||
ClusterSyncService_GetEventsInRange_FullMethodName = "/orlysync.cluster.v1.ClusterSyncService/GetEventsInRange" |
||||
) |
||||
|
||||
// ClusterSyncServiceClient is the client API for ClusterSyncService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// ClusterSyncService provides cluster replication with persistent state
|
||||
// for multi-member relay clusters
|
||||
type ClusterSyncServiceClient interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) |
||||
// Start starts the cluster polling loop
|
||||
Start(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// Stop stops the cluster polling loop
|
||||
Stop(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// HandleLatestSerial proxies GET /cluster/latest HTTP requests
|
||||
HandleLatestSerial(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) |
||||
// HandleEventsRange proxies GET /cluster/events HTTP requests
|
||||
HandleEventsRange(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) |
||||
// GetMembers returns the current cluster members
|
||||
GetMembers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*MembersResponse, error) |
||||
// UpdateMembership updates cluster membership
|
||||
UpdateMembership(ctx context.Context, in *UpdateMembershipRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// HandleMembershipEvent processes a cluster membership event (Kind 39108)
|
||||
HandleMembershipEvent(ctx context.Context, in *MembershipEventRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// GetClusterStatus returns overall cluster status
|
||||
GetClusterStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*ClusterStatusResponse, error) |
||||
// GetMemberStatus returns status for a specific member
|
||||
GetMemberStatus(ctx context.Context, in *MemberStatusRequest, opts ...grpc.CallOption) (*MemberStatusResponse, error) |
||||
// GetLatestSerial returns the latest serial from this relay's database
|
||||
GetLatestSerial(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*LatestSerialResponse, error) |
||||
// GetEventsInRange returns event info for a serial range
|
||||
GetEventsInRange(ctx context.Context, in *EventsRangeRequest, opts ...grpc.CallOption) (*EventsRangeResponse, error) |
||||
} |
||||
|
||||
type clusterSyncServiceClient struct { |
||||
cc grpc.ClientConnInterface |
||||
} |
||||
|
||||
func NewClusterSyncServiceClient(cc grpc.ClientConnInterface) ClusterSyncServiceClient { |
||||
return &clusterSyncServiceClient{cc} |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.ReadyResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_Ready_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) Start(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_Start_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) Stop(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_Stop_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) HandleLatestSerial(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.HTTPResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_HandleLatestSerial_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) HandleEventsRange(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.HTTPResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_HandleEventsRange_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) GetMembers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*MembersResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(MembersResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_GetMembers_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) UpdateMembership(ctx context.Context, in *UpdateMembershipRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_UpdateMembership_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) HandleMembershipEvent(ctx context.Context, in *MembershipEventRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_HandleMembershipEvent_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) GetClusterStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*ClusterStatusResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(ClusterStatusResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_GetClusterStatus_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) GetMemberStatus(ctx context.Context, in *MemberStatusRequest, opts ...grpc.CallOption) (*MemberStatusResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(MemberStatusResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_GetMemberStatus_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) GetLatestSerial(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*LatestSerialResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(LatestSerialResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_GetLatestSerial_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *clusterSyncServiceClient) GetEventsInRange(ctx context.Context, in *EventsRangeRequest, opts ...grpc.CallOption) (*EventsRangeResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(EventsRangeResponse) |
||||
err := c.cc.Invoke(ctx, ClusterSyncService_GetEventsInRange_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// ClusterSyncServiceServer is the server API for ClusterSyncService service.
|
||||
// All implementations must embed UnimplementedClusterSyncServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// ClusterSyncService provides cluster replication with persistent state
|
||||
// for multi-member relay clusters
|
||||
type ClusterSyncServiceServer interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) |
||||
// Start starts the cluster polling loop
|
||||
Start(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// Stop stops the cluster polling loop
|
||||
Stop(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// HandleLatestSerial proxies GET /cluster/latest HTTP requests
|
||||
HandleLatestSerial(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) |
||||
// HandleEventsRange proxies GET /cluster/events HTTP requests
|
||||
HandleEventsRange(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) |
||||
// GetMembers returns the current cluster members
|
||||
GetMembers(context.Context, *v1.Empty) (*MembersResponse, error) |
||||
// UpdateMembership updates cluster membership
|
||||
UpdateMembership(context.Context, *UpdateMembershipRequest) (*v1.Empty, error) |
||||
// HandleMembershipEvent processes a cluster membership event (Kind 39108)
|
||||
HandleMembershipEvent(context.Context, *MembershipEventRequest) (*v1.Empty, error) |
||||
// GetClusterStatus returns overall cluster status
|
||||
GetClusterStatus(context.Context, *v1.Empty) (*ClusterStatusResponse, error) |
||||
// GetMemberStatus returns status for a specific member
|
||||
GetMemberStatus(context.Context, *MemberStatusRequest) (*MemberStatusResponse, error) |
||||
// GetLatestSerial returns the latest serial from this relay's database
|
||||
GetLatestSerial(context.Context, *v1.Empty) (*LatestSerialResponse, error) |
||||
// GetEventsInRange returns event info for a serial range
|
||||
GetEventsInRange(context.Context, *EventsRangeRequest) (*EventsRangeResponse, error) |
||||
mustEmbedUnimplementedClusterSyncServiceServer() |
||||
} |
||||
|
||||
// UnimplementedClusterSyncServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedClusterSyncServiceServer struct{} |
||||
|
||||
func (UnimplementedClusterSyncServiceServer) Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Ready not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) Start(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Start not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) Stop(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Stop not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) HandleLatestSerial(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleLatestSerial not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) HandleEventsRange(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleEventsRange not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) GetMembers(context.Context, *v1.Empty) (*MembersResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetMembers not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) UpdateMembership(context.Context, *UpdateMembershipRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method UpdateMembership not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) HandleMembershipEvent(context.Context, *MembershipEventRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleMembershipEvent not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) GetClusterStatus(context.Context, *v1.Empty) (*ClusterStatusResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetClusterStatus not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) GetMemberStatus(context.Context, *MemberStatusRequest) (*MemberStatusResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetMemberStatus not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) GetLatestSerial(context.Context, *v1.Empty) (*LatestSerialResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetLatestSerial not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) GetEventsInRange(context.Context, *EventsRangeRequest) (*EventsRangeResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetEventsInRange not implemented") |
||||
} |
||||
func (UnimplementedClusterSyncServiceServer) mustEmbedUnimplementedClusterSyncServiceServer() {} |
||||
func (UnimplementedClusterSyncServiceServer) testEmbeddedByValue() {} |
||||
|
||||
// UnsafeClusterSyncServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ClusterSyncServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeClusterSyncServiceServer interface { |
||||
mustEmbedUnimplementedClusterSyncServiceServer() |
||||
} |
||||
|
||||
func RegisterClusterSyncServiceServer(s grpc.ServiceRegistrar, srv ClusterSyncServiceServer) { |
||||
// If the following call panics, it indicates UnimplementedClusterSyncServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { |
||||
t.testEmbeddedByValue() |
||||
} |
||||
s.RegisterService(&ClusterSyncService_ServiceDesc, srv) |
||||
} |
||||
|
||||
func _ClusterSyncService_Ready_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).Ready(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_Ready_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).Ready(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).Start(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_Start_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).Start(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).Stop(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_Stop_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).Stop(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_HandleLatestSerial_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.HTTPRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).HandleLatestSerial(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_HandleLatestSerial_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).HandleLatestSerial(ctx, req.(*v1.HTTPRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_HandleEventsRange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.HTTPRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).HandleEventsRange(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_HandleEventsRange_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).HandleEventsRange(ctx, req.(*v1.HTTPRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_GetMembers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).GetMembers(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_GetMembers_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).GetMembers(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_UpdateMembership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(UpdateMembershipRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).UpdateMembership(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_UpdateMembership_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).UpdateMembership(ctx, req.(*UpdateMembershipRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_HandleMembershipEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(MembershipEventRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).HandleMembershipEvent(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_HandleMembershipEvent_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).HandleMembershipEvent(ctx, req.(*MembershipEventRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_GetClusterStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).GetClusterStatus(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_GetClusterStatus_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).GetClusterStatus(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_GetMemberStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(MemberStatusRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).GetMemberStatus(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_GetMemberStatus_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).GetMemberStatus(ctx, req.(*MemberStatusRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_GetLatestSerial_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).GetLatestSerial(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_GetLatestSerial_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).GetLatestSerial(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _ClusterSyncService_GetEventsInRange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(EventsRangeRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(ClusterSyncServiceServer).GetEventsInRange(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: ClusterSyncService_GetEventsInRange_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(ClusterSyncServiceServer).GetEventsInRange(ctx, req.(*EventsRangeRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
// ClusterSyncService_ServiceDesc is the grpc.ServiceDesc for ClusterSyncService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ClusterSyncService_ServiceDesc = grpc.ServiceDesc{ |
||||
ServiceName: "orlysync.cluster.v1.ClusterSyncService", |
||||
HandlerType: (*ClusterSyncServiceServer)(nil), |
||||
Methods: []grpc.MethodDesc{ |
||||
{ |
||||
MethodName: "Ready", |
||||
Handler: _ClusterSyncService_Ready_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "Start", |
||||
Handler: _ClusterSyncService_Start_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "Stop", |
||||
Handler: _ClusterSyncService_Stop_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleLatestSerial", |
||||
Handler: _ClusterSyncService_HandleLatestSerial_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleEventsRange", |
||||
Handler: _ClusterSyncService_HandleEventsRange_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetMembers", |
||||
Handler: _ClusterSyncService_GetMembers_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "UpdateMembership", |
||||
Handler: _ClusterSyncService_UpdateMembership_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleMembershipEvent", |
||||
Handler: _ClusterSyncService_HandleMembershipEvent_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetClusterStatus", |
||||
Handler: _ClusterSyncService_GetClusterStatus_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetMemberStatus", |
||||
Handler: _ClusterSyncService_GetMemberStatus_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetLatestSerial", |
||||
Handler: _ClusterSyncService_GetLatestSerial_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetEventsInRange", |
||||
Handler: _ClusterSyncService_GetEventsInRange_Handler, |
||||
}, |
||||
}, |
||||
Streams: []grpc.StreamDesc{}, |
||||
Metadata: "orlysync/cluster/v1/service.proto", |
||||
} |
||||
@ -0,0 +1,827 @@
@@ -0,0 +1,827 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: orlysync/common/v1/types.proto
|
||||
|
||||
package commonv1 |
||||
|
||||
import ( |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
reflect "reflect" |
||||
sync "sync" |
||||
unsafe "unsafe" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
// Empty is used for requests/responses with no data
|
||||
type Empty struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *Empty) Reset() { |
||||
*x = Empty{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[0] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *Empty) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*Empty) ProtoMessage() {} |
||||
|
||||
func (x *Empty) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[0] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use Empty.ProtoReflect.Descriptor instead.
|
||||
func (*Empty) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{0} |
||||
} |
||||
|
||||
// ReadyResponse indicates if the service is ready
|
||||
type ReadyResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Ready bool `protobuf:"varint,1,opt,name=ready,proto3" json:"ready,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *ReadyResponse) Reset() { |
||||
*x = ReadyResponse{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[1] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *ReadyResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*ReadyResponse) ProtoMessage() {} |
||||
|
||||
func (x *ReadyResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[1] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use ReadyResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ReadyResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{1} |
||||
} |
||||
|
||||
func (x *ReadyResponse) GetReady() bool { |
||||
if x != nil { |
||||
return x.Ready |
||||
} |
||||
return false |
||||
} |
||||
|
||||
// HTTPRequest wraps an HTTP request for proxy delegation
|
||||
type HTTPRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` |
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` |
||||
Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` |
||||
Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` |
||||
QueryString string `protobuf:"bytes,5,opt,name=query_string,json=queryString,proto3" json:"query_string,omitempty"` |
||||
RemoteAddr string `protobuf:"bytes,6,opt,name=remote_addr,json=remoteAddr,proto3" json:"remote_addr,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *HTTPRequest) Reset() { |
||||
*x = HTTPRequest{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[2] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *HTTPRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*HTTPRequest) ProtoMessage() {} |
||||
|
||||
func (x *HTTPRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[2] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use HTTPRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HTTPRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{2} |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetMethod() string { |
||||
if x != nil { |
||||
return x.Method |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetPath() string { |
||||
if x != nil { |
||||
return x.Path |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetHeaders() map[string]string { |
||||
if x != nil { |
||||
return x.Headers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetBody() []byte { |
||||
if x != nil { |
||||
return x.Body |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetQueryString() string { |
||||
if x != nil { |
||||
return x.QueryString |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *HTTPRequest) GetRemoteAddr() string { |
||||
if x != nil { |
||||
return x.RemoteAddr |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// HTTPResponse wraps an HTTP response from proxy delegation
|
||||
type HTTPResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
StatusCode int32 `protobuf:"varint,1,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` |
||||
Headers map[string]string `protobuf:"bytes,2,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` |
||||
Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *HTTPResponse) Reset() { |
||||
*x = HTTPResponse{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[3] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *HTTPResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*HTTPResponse) ProtoMessage() {} |
||||
|
||||
func (x *HTTPResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[3] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use HTTPResponse.ProtoReflect.Descriptor instead.
|
||||
func (*HTTPResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{3} |
||||
} |
||||
|
||||
func (x *HTTPResponse) GetStatusCode() int32 { |
||||
if x != nil { |
||||
return x.StatusCode |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *HTTPResponse) GetHeaders() map[string]string { |
||||
if x != nil { |
||||
return x.Headers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *HTTPResponse) GetBody() []byte { |
||||
if x != nil { |
||||
return x.Body |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Event represents a Nostr event (shared across sync services)
|
||||
// Binary fields (id, pubkey, sig) are stored as raw bytes for efficiency
|
||||
type Event struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // 32 bytes SHA256 hash
|
||||
Pubkey []byte `protobuf:"bytes,2,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // 32 bytes public key
|
||||
CreatedAt int64 `protobuf:"varint,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` // UNIX timestamp
|
||||
Kind uint32 `protobuf:"varint,4,opt,name=kind,proto3" json:"kind,omitempty"` // Event kind
|
||||
Tags []*Tag `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` // Event tags
|
||||
Content []byte `protobuf:"bytes,6,opt,name=content,proto3" json:"content,omitempty"` // Content (may be binary)
|
||||
Sig []byte `protobuf:"bytes,7,opt,name=sig,proto3" json:"sig,omitempty"` // 64 bytes Schnorr signature
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *Event) Reset() { |
||||
*x = Event{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[4] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *Event) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*Event) ProtoMessage() {} |
||||
|
||||
func (x *Event) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[4] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use Event.ProtoReflect.Descriptor instead.
|
||||
func (*Event) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{4} |
||||
} |
||||
|
||||
func (x *Event) GetId() []byte { |
||||
if x != nil { |
||||
return x.Id |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Event) GetPubkey() []byte { |
||||
if x != nil { |
||||
return x.Pubkey |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Event) GetCreatedAt() int64 { |
||||
if x != nil { |
||||
return x.CreatedAt |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *Event) GetKind() uint32 { |
||||
if x != nil { |
||||
return x.Kind |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *Event) GetTags() []*Tag { |
||||
if x != nil { |
||||
return x.Tags |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Event) GetContent() []byte { |
||||
if x != nil { |
||||
return x.Content |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Event) GetSig() []byte { |
||||
if x != nil { |
||||
return x.Sig |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Tag represents a Nostr tag (array of byte slices)
|
||||
type Tag struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Values [][]byte `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *Tag) Reset() { |
||||
*x = Tag{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[5] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *Tag) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*Tag) ProtoMessage() {} |
||||
|
||||
func (x *Tag) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[5] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use Tag.ProtoReflect.Descriptor instead.
|
||||
func (*Tag) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{5} |
||||
} |
||||
|
||||
func (x *Tag) GetValues() [][]byte { |
||||
if x != nil { |
||||
return x.Values |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Filter represents a Nostr query filter (NIP-01)
|
||||
type Filter struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Ids [][]byte `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` // Event IDs to match (32 bytes each)
|
||||
Kinds []uint32 `protobuf:"varint,2,rep,packed,name=kinds,proto3" json:"kinds,omitempty"` // Kinds to match
|
||||
Authors [][]byte `protobuf:"bytes,3,rep,name=authors,proto3" json:"authors,omitempty"` // Author pubkeys (32 bytes each)
|
||||
Tags map[string]*TagSet `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Tag filters (#e, #p, #t, etc.)
|
||||
Since *int64 `protobuf:"varint,5,opt,name=since,proto3,oneof" json:"since,omitempty"` // Created after timestamp
|
||||
Until *int64 `protobuf:"varint,6,opt,name=until,proto3,oneof" json:"until,omitempty"` // Created before timestamp
|
||||
Search []byte `protobuf:"bytes,7,opt,name=search,proto3,oneof" json:"search,omitempty"` // Full-text search query (NIP-50)
|
||||
Limit *uint32 `protobuf:"varint,8,opt,name=limit,proto3,oneof" json:"limit,omitempty"` // Max results
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *Filter) Reset() { |
||||
*x = Filter{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[6] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *Filter) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*Filter) ProtoMessage() {} |
||||
|
||||
func (x *Filter) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[6] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use Filter.ProtoReflect.Descriptor instead.
|
||||
func (*Filter) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{6} |
||||
} |
||||
|
||||
func (x *Filter) GetIds() [][]byte { |
||||
if x != nil { |
||||
return x.Ids |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Filter) GetKinds() []uint32 { |
||||
if x != nil { |
||||
return x.Kinds |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Filter) GetAuthors() [][]byte { |
||||
if x != nil { |
||||
return x.Authors |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Filter) GetTags() map[string]*TagSet { |
||||
if x != nil { |
||||
return x.Tags |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Filter) GetSince() int64 { |
||||
if x != nil && x.Since != nil { |
||||
return *x.Since |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *Filter) GetUntil() int64 { |
||||
if x != nil && x.Until != nil { |
||||
return *x.Until |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *Filter) GetSearch() []byte { |
||||
if x != nil { |
||||
return x.Search |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *Filter) GetLimit() uint32 { |
||||
if x != nil && x.Limit != nil { |
||||
return *x.Limit |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// TagSet represents a set of tag values for filtering
|
||||
type TagSet struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Values [][]byte `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *TagSet) Reset() { |
||||
*x = TagSet{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[7] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *TagSet) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*TagSet) ProtoMessage() {} |
||||
|
||||
func (x *TagSet) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[7] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use TagSet.ProtoReflect.Descriptor instead.
|
||||
func (*TagSet) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{7} |
||||
} |
||||
|
||||
func (x *TagSet) GetValues() [][]byte { |
||||
if x != nil { |
||||
return x.Values |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// SyncInfo provides general sync service information
|
||||
type SyncInfo struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Node identity (npub/hex pubkey)
|
||||
RelayUrl string `protobuf:"bytes,2,opt,name=relay_url,json=relayUrl,proto3" json:"relay_url,omitempty"` // This relay's URL
|
||||
CurrentSerial uint64 `protobuf:"varint,3,opt,name=current_serial,json=currentSerial,proto3" json:"current_serial,omitempty"` // Current highest serial number
|
||||
PeerCount int32 `protobuf:"varint,4,opt,name=peer_count,json=peerCount,proto3" json:"peer_count,omitempty"` // Number of configured peers
|
||||
Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` // Service status
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *SyncInfo) Reset() { |
||||
*x = SyncInfo{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[8] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *SyncInfo) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*SyncInfo) ProtoMessage() {} |
||||
|
||||
func (x *SyncInfo) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[8] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use SyncInfo.ProtoReflect.Descriptor instead.
|
||||
func (*SyncInfo) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{8} |
||||
} |
||||
|
||||
func (x *SyncInfo) GetNodeId() string { |
||||
if x != nil { |
||||
return x.NodeId |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *SyncInfo) GetRelayUrl() string { |
||||
if x != nil { |
||||
return x.RelayUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *SyncInfo) GetCurrentSerial() uint64 { |
||||
if x != nil { |
||||
return x.CurrentSerial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *SyncInfo) GetPeerCount() int32 { |
||||
if x != nil { |
||||
return x.PeerCount |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *SyncInfo) GetStatus() string { |
||||
if x != nil { |
||||
return x.Status |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// PeerInfo represents information about a sync peer
|
||||
type PeerInfo struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` |
||||
LastSerial uint64 `protobuf:"varint,2,opt,name=last_serial,json=lastSerial,proto3" json:"last_serial,omitempty"` |
||||
Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` // "active", "error", "unknown"
|
||||
LastPoll int64 `protobuf:"varint,4,opt,name=last_poll,json=lastPoll,proto3" json:"last_poll,omitempty"` // Unix timestamp of last poll
|
||||
ErrorCount int32 `protobuf:"varint,5,opt,name=error_count,json=errorCount,proto3" json:"error_count,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *PeerInfo) Reset() { |
||||
*x = PeerInfo{} |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[9] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *PeerInfo) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*PeerInfo) ProtoMessage() {} |
||||
|
||||
func (x *PeerInfo) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_common_v1_types_proto_msgTypes[9] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use PeerInfo.ProtoReflect.Descriptor instead.
|
||||
func (*PeerInfo) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_common_v1_types_proto_rawDescGZIP(), []int{9} |
||||
} |
||||
|
||||
func (x *PeerInfo) GetUrl() string { |
||||
if x != nil { |
||||
return x.Url |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *PeerInfo) GetLastSerial() uint64 { |
||||
if x != nil { |
||||
return x.LastSerial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *PeerInfo) GetStatus() string { |
||||
if x != nil { |
||||
return x.Status |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *PeerInfo) GetLastPoll() int64 { |
||||
if x != nil { |
||||
return x.LastPoll |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *PeerInfo) GetErrorCount() int32 { |
||||
if x != nil { |
||||
return x.ErrorCount |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
var File_orlysync_common_v1_types_proto protoreflect.FileDescriptor |
||||
|
||||
const file_orlysync_common_v1_types_proto_rawDesc = "" + |
||||
"\n" + |
||||
"\x1eorlysync/common/v1/types.proto\x12\x12orlysync.common.v1\"\a\n" + |
||||
"\x05Empty\"%\n" + |
||||
"\rReadyResponse\x12\x14\n" + |
||||
"\x05ready\x18\x01 \x01(\bR\x05ready\"\x95\x02\n" + |
||||
"\vHTTPRequest\x12\x16\n" + |
||||
"\x06method\x18\x01 \x01(\tR\x06method\x12\x12\n" + |
||||
"\x04path\x18\x02 \x01(\tR\x04path\x12F\n" + |
||||
"\aheaders\x18\x03 \x03(\v2,.orlysync.common.v1.HTTPRequest.HeadersEntryR\aheaders\x12\x12\n" + |
||||
"\x04body\x18\x04 \x01(\fR\x04body\x12!\n" + |
||||
"\fquery_string\x18\x05 \x01(\tR\vqueryString\x12\x1f\n" + |
||||
"\vremote_addr\x18\x06 \x01(\tR\n" + |
||||
"remoteAddr\x1a:\n" + |
||||
"\fHeadersEntry\x12\x10\n" + |
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + |
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc8\x01\n" + |
||||
"\fHTTPResponse\x12\x1f\n" + |
||||
"\vstatus_code\x18\x01 \x01(\x05R\n" + |
||||
"statusCode\x12G\n" + |
||||
"\aheaders\x18\x02 \x03(\v2-.orlysync.common.v1.HTTPResponse.HeadersEntryR\aheaders\x12\x12\n" + |
||||
"\x04body\x18\x03 \x01(\fR\x04body\x1a:\n" + |
||||
"\fHeadersEntry\x12\x10\n" + |
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + |
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbb\x01\n" + |
||||
"\x05Event\x12\x0e\n" + |
||||
"\x02id\x18\x01 \x01(\fR\x02id\x12\x16\n" + |
||||
"\x06pubkey\x18\x02 \x01(\fR\x06pubkey\x12\x1d\n" + |
||||
"\n" + |
||||
"created_at\x18\x03 \x01(\x03R\tcreatedAt\x12\x12\n" + |
||||
"\x04kind\x18\x04 \x01(\rR\x04kind\x12+\n" + |
||||
"\x04tags\x18\x05 \x03(\v2\x17.orlysync.common.v1.TagR\x04tags\x12\x18\n" + |
||||
"\acontent\x18\x06 \x01(\fR\acontent\x12\x10\n" + |
||||
"\x03sig\x18\a \x01(\fR\x03sig\"\x1d\n" + |
||||
"\x03Tag\x12\x16\n" + |
||||
"\x06values\x18\x01 \x03(\fR\x06values\"\xf0\x02\n" + |
||||
"\x06Filter\x12\x10\n" + |
||||
"\x03ids\x18\x01 \x03(\fR\x03ids\x12\x14\n" + |
||||
"\x05kinds\x18\x02 \x03(\rR\x05kinds\x12\x18\n" + |
||||
"\aauthors\x18\x03 \x03(\fR\aauthors\x128\n" + |
||||
"\x04tags\x18\x04 \x03(\v2$.orlysync.common.v1.Filter.TagsEntryR\x04tags\x12\x19\n" + |
||||
"\x05since\x18\x05 \x01(\x03H\x00R\x05since\x88\x01\x01\x12\x19\n" + |
||||
"\x05until\x18\x06 \x01(\x03H\x01R\x05until\x88\x01\x01\x12\x1b\n" + |
||||
"\x06search\x18\a \x01(\fH\x02R\x06search\x88\x01\x01\x12\x19\n" + |
||||
"\x05limit\x18\b \x01(\rH\x03R\x05limit\x88\x01\x01\x1aS\n" + |
||||
"\tTagsEntry\x12\x10\n" + |
||||
"\x03key\x18\x01 \x01(\tR\x03key\x120\n" + |
||||
"\x05value\x18\x02 \x01(\v2\x1a.orlysync.common.v1.TagSetR\x05value:\x028\x01B\b\n" + |
||||
"\x06_sinceB\b\n" + |
||||
"\x06_untilB\t\n" + |
||||
"\a_searchB\b\n" + |
||||
"\x06_limit\" \n" + |
||||
"\x06TagSet\x12\x16\n" + |
||||
"\x06values\x18\x01 \x03(\fR\x06values\"\x9e\x01\n" + |
||||
"\bSyncInfo\x12\x17\n" + |
||||
"\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x1b\n" + |
||||
"\trelay_url\x18\x02 \x01(\tR\brelayUrl\x12%\n" + |
||||
"\x0ecurrent_serial\x18\x03 \x01(\x04R\rcurrentSerial\x12\x1d\n" + |
||||
"\n" + |
||||
"peer_count\x18\x04 \x01(\x05R\tpeerCount\x12\x16\n" + |
||||
"\x06status\x18\x05 \x01(\tR\x06status\"\x93\x01\n" + |
||||
"\bPeerInfo\x12\x10\n" + |
||||
"\x03url\x18\x01 \x01(\tR\x03url\x12\x1f\n" + |
||||
"\vlast_serial\x18\x02 \x01(\x04R\n" + |
||||
"lastSerial\x12\x16\n" + |
||||
"\x06status\x18\x03 \x01(\tR\x06status\x12\x1b\n" + |
||||
"\tlast_poll\x18\x04 \x01(\x03R\blastPoll\x12\x1f\n" + |
||||
"\verror_count\x18\x05 \x01(\x05R\n" + |
||||
"errorCountB5Z3next.orly.dev/pkg/proto/orlysync/common/v1;commonv1b\x06proto3" |
||||
|
||||
var ( |
||||
file_orlysync_common_v1_types_proto_rawDescOnce sync.Once |
||||
file_orlysync_common_v1_types_proto_rawDescData []byte |
||||
) |
||||
|
||||
func file_orlysync_common_v1_types_proto_rawDescGZIP() []byte { |
||||
file_orlysync_common_v1_types_proto_rawDescOnce.Do(func() { |
||||
file_orlysync_common_v1_types_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_orlysync_common_v1_types_proto_rawDesc), len(file_orlysync_common_v1_types_proto_rawDesc))) |
||||
}) |
||||
return file_orlysync_common_v1_types_proto_rawDescData |
||||
} |
||||
|
||||
var file_orlysync_common_v1_types_proto_msgTypes = make([]protoimpl.MessageInfo, 13) |
||||
var file_orlysync_common_v1_types_proto_goTypes = []any{ |
||||
(*Empty)(nil), // 0: orlysync.common.v1.Empty
|
||||
(*ReadyResponse)(nil), // 1: orlysync.common.v1.ReadyResponse
|
||||
(*HTTPRequest)(nil), // 2: orlysync.common.v1.HTTPRequest
|
||||
(*HTTPResponse)(nil), // 3: orlysync.common.v1.HTTPResponse
|
||||
(*Event)(nil), // 4: orlysync.common.v1.Event
|
||||
(*Tag)(nil), // 5: orlysync.common.v1.Tag
|
||||
(*Filter)(nil), // 6: orlysync.common.v1.Filter
|
||||
(*TagSet)(nil), // 7: orlysync.common.v1.TagSet
|
||||
(*SyncInfo)(nil), // 8: orlysync.common.v1.SyncInfo
|
||||
(*PeerInfo)(nil), // 9: orlysync.common.v1.PeerInfo
|
||||
nil, // 10: orlysync.common.v1.HTTPRequest.HeadersEntry
|
||||
nil, // 11: orlysync.common.v1.HTTPResponse.HeadersEntry
|
||||
nil, // 12: orlysync.common.v1.Filter.TagsEntry
|
||||
} |
||||
var file_orlysync_common_v1_types_proto_depIdxs = []int32{ |
||||
10, // 0: orlysync.common.v1.HTTPRequest.headers:type_name -> orlysync.common.v1.HTTPRequest.HeadersEntry
|
||||
11, // 1: orlysync.common.v1.HTTPResponse.headers:type_name -> orlysync.common.v1.HTTPResponse.HeadersEntry
|
||||
5, // 2: orlysync.common.v1.Event.tags:type_name -> orlysync.common.v1.Tag
|
||||
12, // 3: orlysync.common.v1.Filter.tags:type_name -> orlysync.common.v1.Filter.TagsEntry
|
||||
7, // 4: orlysync.common.v1.Filter.TagsEntry.value:type_name -> orlysync.common.v1.TagSet
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_orlysync_common_v1_types_proto_init() } |
||||
func file_orlysync_common_v1_types_proto_init() { |
||||
if File_orlysync_common_v1_types_proto != nil { |
||||
return |
||||
} |
||||
file_orlysync_common_v1_types_proto_msgTypes[6].OneofWrappers = []any{} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_orlysync_common_v1_types_proto_rawDesc), len(file_orlysync_common_v1_types_proto_rawDesc)), |
||||
NumEnums: 0, |
||||
NumMessages: 13, |
||||
NumExtensions: 0, |
||||
NumServices: 0, |
||||
}, |
||||
GoTypes: file_orlysync_common_v1_types_proto_goTypes, |
||||
DependencyIndexes: file_orlysync_common_v1_types_proto_depIdxs, |
||||
MessageInfos: file_orlysync_common_v1_types_proto_msgTypes, |
||||
}.Build() |
||||
File_orlysync_common_v1_types_proto = out.File |
||||
file_orlysync_common_v1_types_proto_goTypes = nil |
||||
file_orlysync_common_v1_types_proto_depIdxs = nil |
||||
} |
||||
@ -0,0 +1,790 @@
@@ -0,0 +1,790 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: orlysync/distributed/v1/service.proto
|
||||
|
||||
package distributedv1 |
||||
|
||||
import ( |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
reflect "reflect" |
||||
sync "sync" |
||||
unsafe "unsafe" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
// CurrentRequest is sent to request current serial number
|
||||
type CurrentRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Requesting node's identity
|
||||
RelayUrl string `protobuf:"bytes,2,opt,name=relay_url,json=relayUrl,proto3" json:"relay_url,omitempty"` // Requesting relay's URL
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *CurrentRequest) Reset() { |
||||
*x = CurrentRequest{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[0] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *CurrentRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*CurrentRequest) ProtoMessage() {} |
||||
|
||||
func (x *CurrentRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[0] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use CurrentRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CurrentRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{0} |
||||
} |
||||
|
||||
func (x *CurrentRequest) GetNodeId() string { |
||||
if x != nil { |
||||
return x.NodeId |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *CurrentRequest) GetRelayUrl() string { |
||||
if x != nil { |
||||
return x.RelayUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// CurrentResponse contains the current serial number
|
||||
type CurrentResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Responding node's identity
|
||||
RelayUrl string `protobuf:"bytes,2,opt,name=relay_url,json=relayUrl,proto3" json:"relay_url,omitempty"` // Responding relay's URL
|
||||
Serial uint64 `protobuf:"varint,3,opt,name=serial,proto3" json:"serial,omitempty"` // Current serial number
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *CurrentResponse) Reset() { |
||||
*x = CurrentResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[1] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *CurrentResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*CurrentResponse) ProtoMessage() {} |
||||
|
||||
func (x *CurrentResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[1] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use CurrentResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CurrentResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{1} |
||||
} |
||||
|
||||
func (x *CurrentResponse) GetNodeId() string { |
||||
if x != nil { |
||||
return x.NodeId |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *CurrentResponse) GetRelayUrl() string { |
||||
if x != nil { |
||||
return x.RelayUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *CurrentResponse) GetSerial() uint64 { |
||||
if x != nil { |
||||
return x.Serial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// EventIDsRequest requests event IDs in a serial range
|
||||
type EventIDsRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Requesting node's identity
|
||||
RelayUrl string `protobuf:"bytes,2,opt,name=relay_url,json=relayUrl,proto3" json:"relay_url,omitempty"` // Requesting relay's URL
|
||||
From uint64 `protobuf:"varint,3,opt,name=from,proto3" json:"from,omitempty"` // Start serial (inclusive)
|
||||
To uint64 `protobuf:"varint,4,opt,name=to,proto3" json:"to,omitempty"` // End serial (inclusive)
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *EventIDsRequest) Reset() { |
||||
*x = EventIDsRequest{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[2] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *EventIDsRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*EventIDsRequest) ProtoMessage() {} |
||||
|
||||
func (x *EventIDsRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[2] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use EventIDsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*EventIDsRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{2} |
||||
} |
||||
|
||||
func (x *EventIDsRequest) GetNodeId() string { |
||||
if x != nil { |
||||
return x.NodeId |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *EventIDsRequest) GetRelayUrl() string { |
||||
if x != nil { |
||||
return x.RelayUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *EventIDsRequest) GetFrom() uint64 { |
||||
if x != nil { |
||||
return x.From |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *EventIDsRequest) GetTo() uint64 { |
||||
if x != nil { |
||||
return x.To |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// EventIDsResponse contains event IDs mapped to serial numbers
|
||||
type EventIDsResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
EventMap map[string]uint64 `protobuf:"bytes,1,rep,name=event_map,json=eventMap,proto3" json:"event_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"` // event_id (hex) -> serial
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *EventIDsResponse) Reset() { |
||||
*x = EventIDsResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[3] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *EventIDsResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*EventIDsResponse) ProtoMessage() {} |
||||
|
||||
func (x *EventIDsResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[3] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use EventIDsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*EventIDsResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{3} |
||||
} |
||||
|
||||
func (x *EventIDsResponse) GetEventMap() map[string]uint64 { |
||||
if x != nil { |
||||
return x.EventMap |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// PeersResponse contains the list of sync peers
|
||||
type PeersResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Peers []string `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` // List of peer relay URLs
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *PeersResponse) Reset() { |
||||
*x = PeersResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[4] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *PeersResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*PeersResponse) ProtoMessage() {} |
||||
|
||||
func (x *PeersResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[4] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use PeersResponse.ProtoReflect.Descriptor instead.
|
||||
func (*PeersResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{4} |
||||
} |
||||
|
||||
func (x *PeersResponse) GetPeers() []string { |
||||
if x != nil { |
||||
return x.Peers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// UpdatePeersRequest updates the peer list
|
||||
type UpdatePeersRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Peers []string `protobuf:"bytes,1,rep,name=peers,proto3" json:"peers,omitempty"` // New list of peer relay URLs
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *UpdatePeersRequest) Reset() { |
||||
*x = UpdatePeersRequest{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[5] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *UpdatePeersRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*UpdatePeersRequest) ProtoMessage() {} |
||||
|
||||
func (x *UpdatePeersRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[5] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use UpdatePeersRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdatePeersRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{5} |
||||
} |
||||
|
||||
func (x *UpdatePeersRequest) GetPeers() []string { |
||||
if x != nil { |
||||
return x.Peers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// AuthorizedPeerRequest checks if a peer is authorized
|
||||
type AuthorizedPeerRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
PeerUrl string `protobuf:"bytes,1,opt,name=peer_url,json=peerUrl,proto3" json:"peer_url,omitempty"` |
||||
ExpectedPubkey string `protobuf:"bytes,2,opt,name=expected_pubkey,json=expectedPubkey,proto3" json:"expected_pubkey,omitempty"` // Expected NIP-11 pubkey
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *AuthorizedPeerRequest) Reset() { |
||||
*x = AuthorizedPeerRequest{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[6] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *AuthorizedPeerRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*AuthorizedPeerRequest) ProtoMessage() {} |
||||
|
||||
func (x *AuthorizedPeerRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[6] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use AuthorizedPeerRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AuthorizedPeerRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{6} |
||||
} |
||||
|
||||
func (x *AuthorizedPeerRequest) GetPeerUrl() string { |
||||
if x != nil { |
||||
return x.PeerUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (x *AuthorizedPeerRequest) GetExpectedPubkey() string { |
||||
if x != nil { |
||||
return x.ExpectedPubkey |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// AuthorizedPeerResponse indicates if the peer is authorized
|
||||
type AuthorizedPeerResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *AuthorizedPeerResponse) Reset() { |
||||
*x = AuthorizedPeerResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[7] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *AuthorizedPeerResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*AuthorizedPeerResponse) ProtoMessage() {} |
||||
|
||||
func (x *AuthorizedPeerResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[7] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use AuthorizedPeerResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AuthorizedPeerResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{7} |
||||
} |
||||
|
||||
func (x *AuthorizedPeerResponse) GetAuthorized() bool { |
||||
if x != nil { |
||||
return x.Authorized |
||||
} |
||||
return false |
||||
} |
||||
|
||||
// PeerPubkeyRequest requests the pubkey for a peer
|
||||
type PeerPubkeyRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
PeerUrl string `protobuf:"bytes,1,opt,name=peer_url,json=peerUrl,proto3" json:"peer_url,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *PeerPubkeyRequest) Reset() { |
||||
*x = PeerPubkeyRequest{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[8] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *PeerPubkeyRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*PeerPubkeyRequest) ProtoMessage() {} |
||||
|
||||
func (x *PeerPubkeyRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[8] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use PeerPubkeyRequest.ProtoReflect.Descriptor instead.
|
||||
func (*PeerPubkeyRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{8} |
||||
} |
||||
|
||||
func (x *PeerPubkeyRequest) GetPeerUrl() string { |
||||
if x != nil { |
||||
return x.PeerUrl |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// PeerPubkeyResponse contains the peer's pubkey
|
||||
type PeerPubkeyResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Pubkey string `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // Peer's NIP-11 pubkey (hex or npub)
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *PeerPubkeyResponse) Reset() { |
||||
*x = PeerPubkeyResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[9] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *PeerPubkeyResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*PeerPubkeyResponse) ProtoMessage() {} |
||||
|
||||
func (x *PeerPubkeyResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[9] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use PeerPubkeyResponse.ProtoReflect.Descriptor instead.
|
||||
func (*PeerPubkeyResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{9} |
||||
} |
||||
|
||||
func (x *PeerPubkeyResponse) GetPubkey() string { |
||||
if x != nil { |
||||
return x.Pubkey |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// NewEventNotification notifies of a new event
|
||||
type NewEventNotification struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` // 32 bytes event ID
|
||||
Serial uint64 `protobuf:"varint,2,opt,name=serial,proto3" json:"serial,omitempty"` // Assigned serial number
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *NewEventNotification) Reset() { |
||||
*x = NewEventNotification{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[10] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *NewEventNotification) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*NewEventNotification) ProtoMessage() {} |
||||
|
||||
func (x *NewEventNotification) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[10] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use NewEventNotification.ProtoReflect.Descriptor instead.
|
||||
func (*NewEventNotification) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{10} |
||||
} |
||||
|
||||
func (x *NewEventNotification) GetEventId() []byte { |
||||
if x != nil { |
||||
return x.EventId |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *NewEventNotification) GetSerial() uint64 { |
||||
if x != nil { |
||||
return x.Serial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// SyncStatusResponse contains sync status for all peers
|
||||
type SyncStatusResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
CurrentSerial uint64 `protobuf:"varint,1,opt,name=current_serial,json=currentSerial,proto3" json:"current_serial,omitempty"` |
||||
Peers []*v1.PeerInfo `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *SyncStatusResponse) Reset() { |
||||
*x = SyncStatusResponse{} |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[11] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *SyncStatusResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*SyncStatusResponse) ProtoMessage() {} |
||||
|
||||
func (x *SyncStatusResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_distributed_v1_service_proto_msgTypes[11] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use SyncStatusResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SyncStatusResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_distributed_v1_service_proto_rawDescGZIP(), []int{11} |
||||
} |
||||
|
||||
func (x *SyncStatusResponse) GetCurrentSerial() uint64 { |
||||
if x != nil { |
||||
return x.CurrentSerial |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (x *SyncStatusResponse) GetPeers() []*v1.PeerInfo { |
||||
if x != nil { |
||||
return x.Peers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
var File_orlysync_distributed_v1_service_proto protoreflect.FileDescriptor |
||||
|
||||
const file_orlysync_distributed_v1_service_proto_rawDesc = "" + |
||||
"\n" + |
||||
"%orlysync/distributed/v1/service.proto\x12\x17orlysync.distributed.v1\x1a\x1eorlysync/common/v1/types.proto\"F\n" + |
||||
"\x0eCurrentRequest\x12\x17\n" + |
||||
"\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x1b\n" + |
||||
"\trelay_url\x18\x02 \x01(\tR\brelayUrl\"_\n" + |
||||
"\x0fCurrentResponse\x12\x17\n" + |
||||
"\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x1b\n" + |
||||
"\trelay_url\x18\x02 \x01(\tR\brelayUrl\x12\x16\n" + |
||||
"\x06serial\x18\x03 \x01(\x04R\x06serial\"k\n" + |
||||
"\x0fEventIDsRequest\x12\x17\n" + |
||||
"\anode_id\x18\x01 \x01(\tR\x06nodeId\x12\x1b\n" + |
||||
"\trelay_url\x18\x02 \x01(\tR\brelayUrl\x12\x12\n" + |
||||
"\x04from\x18\x03 \x01(\x04R\x04from\x12\x0e\n" + |
||||
"\x02to\x18\x04 \x01(\x04R\x02to\"\xa5\x01\n" + |
||||
"\x10EventIDsResponse\x12T\n" + |
||||
"\tevent_map\x18\x01 \x03(\v27.orlysync.distributed.v1.EventIDsResponse.EventMapEntryR\beventMap\x1a;\n" + |
||||
"\rEventMapEntry\x12\x10\n" + |
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + |
||||
"\x05value\x18\x02 \x01(\x04R\x05value:\x028\x01\"%\n" + |
||||
"\rPeersResponse\x12\x14\n" + |
||||
"\x05peers\x18\x01 \x03(\tR\x05peers\"*\n" + |
||||
"\x12UpdatePeersRequest\x12\x14\n" + |
||||
"\x05peers\x18\x01 \x03(\tR\x05peers\"[\n" + |
||||
"\x15AuthorizedPeerRequest\x12\x19\n" + |
||||
"\bpeer_url\x18\x01 \x01(\tR\apeerUrl\x12'\n" + |
||||
"\x0fexpected_pubkey\x18\x02 \x01(\tR\x0eexpectedPubkey\"8\n" + |
||||
"\x16AuthorizedPeerResponse\x12\x1e\n" + |
||||
"\n" + |
||||
"authorized\x18\x01 \x01(\bR\n" + |
||||
"authorized\".\n" + |
||||
"\x11PeerPubkeyRequest\x12\x19\n" + |
||||
"\bpeer_url\x18\x01 \x01(\tR\apeerUrl\",\n" + |
||||
"\x12PeerPubkeyResponse\x12\x16\n" + |
||||
"\x06pubkey\x18\x01 \x01(\tR\x06pubkey\"I\n" + |
||||
"\x14NewEventNotification\x12\x19\n" + |
||||
"\bevent_id\x18\x01 \x01(\fR\aeventId\x12\x16\n" + |
||||
"\x06serial\x18\x02 \x01(\x04R\x06serial\"o\n" + |
||||
"\x12SyncStatusResponse\x12%\n" + |
||||
"\x0ecurrent_serial\x18\x01 \x01(\x04R\rcurrentSerial\x122\n" + |
||||
"\x05peers\x18\x02 \x03(\v2\x1c.orlysync.common.v1.PeerInfoR\x05peers2\xea\t\n" + |
||||
"\x16DistributedSyncService\x12E\n" + |
||||
"\x05Ready\x12\x19.orlysync.common.v1.Empty\x1a!.orlysync.common.v1.ReadyResponse\x12B\n" + |
||||
"\aGetInfo\x12\x19.orlysync.common.v1.Empty\x1a\x1c.orlysync.common.v1.SyncInfo\x12e\n" + |
||||
"\x10GetCurrentSerial\x12'.orlysync.distributed.v1.CurrentRequest\x1a(.orlysync.distributed.v1.CurrentResponse\x12b\n" + |
||||
"\vGetEventIDs\x12(.orlysync.distributed.v1.EventIDsRequest\x1a).orlysync.distributed.v1.EventIDsResponse\x12Y\n" + |
||||
"\x14HandleCurrentRequest\x12\x1f.orlysync.common.v1.HTTPRequest\x1a .orlysync.common.v1.HTTPResponse\x12Z\n" + |
||||
"\x15HandleEventIDsRequest\x12\x1f.orlysync.common.v1.HTTPRequest\x1a .orlysync.common.v1.HTTPResponse\x12M\n" + |
||||
"\bGetPeers\x12\x19.orlysync.common.v1.Empty\x1a&.orlysync.distributed.v1.PeersResponse\x12U\n" + |
||||
"\vUpdatePeers\x12+.orlysync.distributed.v1.UpdatePeersRequest\x1a\x19.orlysync.common.v1.Empty\x12s\n" + |
||||
"\x10IsAuthorizedPeer\x12..orlysync.distributed.v1.AuthorizedPeerRequest\x1a/.orlysync.distributed.v1.AuthorizedPeerResponse\x12h\n" + |
||||
"\rGetPeerPubkey\x12*.orlysync.distributed.v1.PeerPubkeyRequest\x1a+.orlysync.distributed.v1.PeerPubkeyResponse\x12D\n" + |
||||
"\fUpdateSerial\x12\x19.orlysync.common.v1.Empty\x1a\x19.orlysync.common.v1.Empty\x12Z\n" + |
||||
"\x0eNotifyNewEvent\x12-.orlysync.distributed.v1.NewEventNotification\x1a\x19.orlysync.common.v1.Empty\x12C\n" + |
||||
"\vTriggerSync\x12\x19.orlysync.common.v1.Empty\x1a\x19.orlysync.common.v1.Empty\x12W\n" + |
||||
"\rGetSyncStatus\x12\x19.orlysync.common.v1.Empty\x1a+.orlysync.distributed.v1.SyncStatusResponseB?Z=next.orly.dev/pkg/proto/orlysync/distributed/v1;distributedv1b\x06proto3" |
||||
|
||||
var ( |
||||
file_orlysync_distributed_v1_service_proto_rawDescOnce sync.Once |
||||
file_orlysync_distributed_v1_service_proto_rawDescData []byte |
||||
) |
||||
|
||||
func file_orlysync_distributed_v1_service_proto_rawDescGZIP() []byte { |
||||
file_orlysync_distributed_v1_service_proto_rawDescOnce.Do(func() { |
||||
file_orlysync_distributed_v1_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_orlysync_distributed_v1_service_proto_rawDesc), len(file_orlysync_distributed_v1_service_proto_rawDesc))) |
||||
}) |
||||
return file_orlysync_distributed_v1_service_proto_rawDescData |
||||
} |
||||
|
||||
var file_orlysync_distributed_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13) |
||||
var file_orlysync_distributed_v1_service_proto_goTypes = []any{ |
||||
(*CurrentRequest)(nil), // 0: orlysync.distributed.v1.CurrentRequest
|
||||
(*CurrentResponse)(nil), // 1: orlysync.distributed.v1.CurrentResponse
|
||||
(*EventIDsRequest)(nil), // 2: orlysync.distributed.v1.EventIDsRequest
|
||||
(*EventIDsResponse)(nil), // 3: orlysync.distributed.v1.EventIDsResponse
|
||||
(*PeersResponse)(nil), // 4: orlysync.distributed.v1.PeersResponse
|
||||
(*UpdatePeersRequest)(nil), // 5: orlysync.distributed.v1.UpdatePeersRequest
|
||||
(*AuthorizedPeerRequest)(nil), // 6: orlysync.distributed.v1.AuthorizedPeerRequest
|
||||
(*AuthorizedPeerResponse)(nil), // 7: orlysync.distributed.v1.AuthorizedPeerResponse
|
||||
(*PeerPubkeyRequest)(nil), // 8: orlysync.distributed.v1.PeerPubkeyRequest
|
||||
(*PeerPubkeyResponse)(nil), // 9: orlysync.distributed.v1.PeerPubkeyResponse
|
||||
(*NewEventNotification)(nil), // 10: orlysync.distributed.v1.NewEventNotification
|
||||
(*SyncStatusResponse)(nil), // 11: orlysync.distributed.v1.SyncStatusResponse
|
||||
nil, // 12: orlysync.distributed.v1.EventIDsResponse.EventMapEntry
|
||||
(*v1.PeerInfo)(nil), // 13: orlysync.common.v1.PeerInfo
|
||||
(*v1.Empty)(nil), // 14: orlysync.common.v1.Empty
|
||||
(*v1.HTTPRequest)(nil), // 15: orlysync.common.v1.HTTPRequest
|
||||
(*v1.ReadyResponse)(nil), // 16: orlysync.common.v1.ReadyResponse
|
||||
(*v1.SyncInfo)(nil), // 17: orlysync.common.v1.SyncInfo
|
||||
(*v1.HTTPResponse)(nil), // 18: orlysync.common.v1.HTTPResponse
|
||||
} |
||||
var file_orlysync_distributed_v1_service_proto_depIdxs = []int32{ |
||||
12, // 0: orlysync.distributed.v1.EventIDsResponse.event_map:type_name -> orlysync.distributed.v1.EventIDsResponse.EventMapEntry
|
||||
13, // 1: orlysync.distributed.v1.SyncStatusResponse.peers:type_name -> orlysync.common.v1.PeerInfo
|
||||
14, // 2: orlysync.distributed.v1.DistributedSyncService.Ready:input_type -> orlysync.common.v1.Empty
|
||||
14, // 3: orlysync.distributed.v1.DistributedSyncService.GetInfo:input_type -> orlysync.common.v1.Empty
|
||||
0, // 4: orlysync.distributed.v1.DistributedSyncService.GetCurrentSerial:input_type -> orlysync.distributed.v1.CurrentRequest
|
||||
2, // 5: orlysync.distributed.v1.DistributedSyncService.GetEventIDs:input_type -> orlysync.distributed.v1.EventIDsRequest
|
||||
15, // 6: orlysync.distributed.v1.DistributedSyncService.HandleCurrentRequest:input_type -> orlysync.common.v1.HTTPRequest
|
||||
15, // 7: orlysync.distributed.v1.DistributedSyncService.HandleEventIDsRequest:input_type -> orlysync.common.v1.HTTPRequest
|
||||
14, // 8: orlysync.distributed.v1.DistributedSyncService.GetPeers:input_type -> orlysync.common.v1.Empty
|
||||
5, // 9: orlysync.distributed.v1.DistributedSyncService.UpdatePeers:input_type -> orlysync.distributed.v1.UpdatePeersRequest
|
||||
6, // 10: orlysync.distributed.v1.DistributedSyncService.IsAuthorizedPeer:input_type -> orlysync.distributed.v1.AuthorizedPeerRequest
|
||||
8, // 11: orlysync.distributed.v1.DistributedSyncService.GetPeerPubkey:input_type -> orlysync.distributed.v1.PeerPubkeyRequest
|
||||
14, // 12: orlysync.distributed.v1.DistributedSyncService.UpdateSerial:input_type -> orlysync.common.v1.Empty
|
||||
10, // 13: orlysync.distributed.v1.DistributedSyncService.NotifyNewEvent:input_type -> orlysync.distributed.v1.NewEventNotification
|
||||
14, // 14: orlysync.distributed.v1.DistributedSyncService.TriggerSync:input_type -> orlysync.common.v1.Empty
|
||||
14, // 15: orlysync.distributed.v1.DistributedSyncService.GetSyncStatus:input_type -> orlysync.common.v1.Empty
|
||||
16, // 16: orlysync.distributed.v1.DistributedSyncService.Ready:output_type -> orlysync.common.v1.ReadyResponse
|
||||
17, // 17: orlysync.distributed.v1.DistributedSyncService.GetInfo:output_type -> orlysync.common.v1.SyncInfo
|
||||
1, // 18: orlysync.distributed.v1.DistributedSyncService.GetCurrentSerial:output_type -> orlysync.distributed.v1.CurrentResponse
|
||||
3, // 19: orlysync.distributed.v1.DistributedSyncService.GetEventIDs:output_type -> orlysync.distributed.v1.EventIDsResponse
|
||||
18, // 20: orlysync.distributed.v1.DistributedSyncService.HandleCurrentRequest:output_type -> orlysync.common.v1.HTTPResponse
|
||||
18, // 21: orlysync.distributed.v1.DistributedSyncService.HandleEventIDsRequest:output_type -> orlysync.common.v1.HTTPResponse
|
||||
4, // 22: orlysync.distributed.v1.DistributedSyncService.GetPeers:output_type -> orlysync.distributed.v1.PeersResponse
|
||||
14, // 23: orlysync.distributed.v1.DistributedSyncService.UpdatePeers:output_type -> orlysync.common.v1.Empty
|
||||
7, // 24: orlysync.distributed.v1.DistributedSyncService.IsAuthorizedPeer:output_type -> orlysync.distributed.v1.AuthorizedPeerResponse
|
||||
9, // 25: orlysync.distributed.v1.DistributedSyncService.GetPeerPubkey:output_type -> orlysync.distributed.v1.PeerPubkeyResponse
|
||||
14, // 26: orlysync.distributed.v1.DistributedSyncService.UpdateSerial:output_type -> orlysync.common.v1.Empty
|
||||
14, // 27: orlysync.distributed.v1.DistributedSyncService.NotifyNewEvent:output_type -> orlysync.common.v1.Empty
|
||||
14, // 28: orlysync.distributed.v1.DistributedSyncService.TriggerSync:output_type -> orlysync.common.v1.Empty
|
||||
11, // 29: orlysync.distributed.v1.DistributedSyncService.GetSyncStatus:output_type -> orlysync.distributed.v1.SyncStatusResponse
|
||||
16, // [16:30] is the sub-list for method output_type
|
||||
2, // [2:16] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_orlysync_distributed_v1_service_proto_init() } |
||||
func file_orlysync_distributed_v1_service_proto_init() { |
||||
if File_orlysync_distributed_v1_service_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_orlysync_distributed_v1_service_proto_rawDesc), len(file_orlysync_distributed_v1_service_proto_rawDesc)), |
||||
NumEnums: 0, |
||||
NumMessages: 13, |
||||
NumExtensions: 0, |
||||
NumServices: 1, |
||||
}, |
||||
GoTypes: file_orlysync_distributed_v1_service_proto_goTypes, |
||||
DependencyIndexes: file_orlysync_distributed_v1_service_proto_depIdxs, |
||||
MessageInfos: file_orlysync_distributed_v1_service_proto_msgTypes, |
||||
}.Build() |
||||
File_orlysync_distributed_v1_service_proto = out.File |
||||
file_orlysync_distributed_v1_service_proto_goTypes = nil |
||||
file_orlysync_distributed_v1_service_proto_depIdxs = nil |
||||
} |
||||
@ -0,0 +1,651 @@
@@ -0,0 +1,651 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: orlysync/distributed/v1/service.proto
|
||||
|
||||
package distributedv1 |
||||
|
||||
import ( |
||||
context "context" |
||||
grpc "google.golang.org/grpc" |
||||
codes "google.golang.org/grpc/codes" |
||||
status "google.golang.org/grpc/status" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9 |
||||
|
||||
const ( |
||||
DistributedSyncService_Ready_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/Ready" |
||||
DistributedSyncService_GetInfo_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetInfo" |
||||
DistributedSyncService_GetCurrentSerial_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetCurrentSerial" |
||||
DistributedSyncService_GetEventIDs_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetEventIDs" |
||||
DistributedSyncService_HandleCurrentRequest_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/HandleCurrentRequest" |
||||
DistributedSyncService_HandleEventIDsRequest_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/HandleEventIDsRequest" |
||||
DistributedSyncService_GetPeers_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetPeers" |
||||
DistributedSyncService_UpdatePeers_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/UpdatePeers" |
||||
DistributedSyncService_IsAuthorizedPeer_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/IsAuthorizedPeer" |
||||
DistributedSyncService_GetPeerPubkey_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetPeerPubkey" |
||||
DistributedSyncService_UpdateSerial_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/UpdateSerial" |
||||
DistributedSyncService_NotifyNewEvent_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/NotifyNewEvent" |
||||
DistributedSyncService_TriggerSync_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/TriggerSync" |
||||
DistributedSyncService_GetSyncStatus_FullMethodName = "/orlysync.distributed.v1.DistributedSyncService/GetSyncStatus" |
||||
) |
||||
|
||||
// DistributedSyncServiceClient is the client API for DistributedSyncService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// DistributedSyncService provides serial-based peer-to-peer synchronization
|
||||
// between relay instances using HTTP polling
|
||||
type DistributedSyncServiceClient interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) |
||||
// GetInfo returns current sync service information
|
||||
GetInfo(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.SyncInfo, error) |
||||
// GetCurrentSerial returns this relay's current serial number
|
||||
GetCurrentSerial(ctx context.Context, in *CurrentRequest, opts ...grpc.CallOption) (*CurrentResponse, error) |
||||
// GetEventIDs returns event IDs for a serial range
|
||||
GetEventIDs(ctx context.Context, in *EventIDsRequest, opts ...grpc.CallOption) (*EventIDsResponse, error) |
||||
// HandleCurrentRequest proxies /api/sync/current HTTP requests
|
||||
HandleCurrentRequest(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) |
||||
// HandleEventIDsRequest proxies /api/sync/event-ids HTTP requests
|
||||
HandleEventIDsRequest(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) |
||||
// GetPeers returns the current list of sync peers
|
||||
GetPeers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*PeersResponse, error) |
||||
// UpdatePeers updates the peer list
|
||||
UpdatePeers(ctx context.Context, in *UpdatePeersRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// IsAuthorizedPeer checks if a peer is authorized by validating its NIP-11 pubkey
|
||||
IsAuthorizedPeer(ctx context.Context, in *AuthorizedPeerRequest, opts ...grpc.CallOption) (*AuthorizedPeerResponse, error) |
||||
// GetPeerPubkey fetches the pubkey for a peer relay via NIP-11
|
||||
GetPeerPubkey(ctx context.Context, in *PeerPubkeyRequest, opts ...grpc.CallOption) (*PeerPubkeyResponse, error) |
||||
// UpdateSerial updates the current serial from database
|
||||
UpdateSerial(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// NotifyNewEvent notifies the service of a new event being stored
|
||||
NotifyNewEvent(ctx context.Context, in *NewEventNotification, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// TriggerSync manually triggers a sync cycle with all peers
|
||||
TriggerSync(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// GetSyncStatus returns current sync status for all peers
|
||||
GetSyncStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*SyncStatusResponse, error) |
||||
} |
||||
|
||||
type distributedSyncServiceClient struct { |
||||
cc grpc.ClientConnInterface |
||||
} |
||||
|
||||
func NewDistributedSyncServiceClient(cc grpc.ClientConnInterface) DistributedSyncServiceClient { |
||||
return &distributedSyncServiceClient{cc} |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.ReadyResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_Ready_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetInfo(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.SyncInfo, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.SyncInfo) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetInfo_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetCurrentSerial(ctx context.Context, in *CurrentRequest, opts ...grpc.CallOption) (*CurrentResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(CurrentResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetCurrentSerial_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetEventIDs(ctx context.Context, in *EventIDsRequest, opts ...grpc.CallOption) (*EventIDsResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(EventIDsResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetEventIDs_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) HandleCurrentRequest(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.HTTPResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_HandleCurrentRequest_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) HandleEventIDsRequest(ctx context.Context, in *v1.HTTPRequest, opts ...grpc.CallOption) (*v1.HTTPResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.HTTPResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_HandleEventIDsRequest_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetPeers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*PeersResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(PeersResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetPeers_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) UpdatePeers(ctx context.Context, in *UpdatePeersRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_UpdatePeers_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) IsAuthorizedPeer(ctx context.Context, in *AuthorizedPeerRequest, opts ...grpc.CallOption) (*AuthorizedPeerResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(AuthorizedPeerResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_IsAuthorizedPeer_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetPeerPubkey(ctx context.Context, in *PeerPubkeyRequest, opts ...grpc.CallOption) (*PeerPubkeyResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(PeerPubkeyResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetPeerPubkey_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) UpdateSerial(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_UpdateSerial_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) NotifyNewEvent(ctx context.Context, in *NewEventNotification, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_NotifyNewEvent_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) TriggerSync(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_TriggerSync_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *distributedSyncServiceClient) GetSyncStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*SyncStatusResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(SyncStatusResponse) |
||||
err := c.cc.Invoke(ctx, DistributedSyncService_GetSyncStatus_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// DistributedSyncServiceServer is the server API for DistributedSyncService service.
|
||||
// All implementations must embed UnimplementedDistributedSyncServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// DistributedSyncService provides serial-based peer-to-peer synchronization
|
||||
// between relay instances using HTTP polling
|
||||
type DistributedSyncServiceServer interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) |
||||
// GetInfo returns current sync service information
|
||||
GetInfo(context.Context, *v1.Empty) (*v1.SyncInfo, error) |
||||
// GetCurrentSerial returns this relay's current serial number
|
||||
GetCurrentSerial(context.Context, *CurrentRequest) (*CurrentResponse, error) |
||||
// GetEventIDs returns event IDs for a serial range
|
||||
GetEventIDs(context.Context, *EventIDsRequest) (*EventIDsResponse, error) |
||||
// HandleCurrentRequest proxies /api/sync/current HTTP requests
|
||||
HandleCurrentRequest(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) |
||||
// HandleEventIDsRequest proxies /api/sync/event-ids HTTP requests
|
||||
HandleEventIDsRequest(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) |
||||
// GetPeers returns the current list of sync peers
|
||||
GetPeers(context.Context, *v1.Empty) (*PeersResponse, error) |
||||
// UpdatePeers updates the peer list
|
||||
UpdatePeers(context.Context, *UpdatePeersRequest) (*v1.Empty, error) |
||||
// IsAuthorizedPeer checks if a peer is authorized by validating its NIP-11 pubkey
|
||||
IsAuthorizedPeer(context.Context, *AuthorizedPeerRequest) (*AuthorizedPeerResponse, error) |
||||
// GetPeerPubkey fetches the pubkey for a peer relay via NIP-11
|
||||
GetPeerPubkey(context.Context, *PeerPubkeyRequest) (*PeerPubkeyResponse, error) |
||||
// UpdateSerial updates the current serial from database
|
||||
UpdateSerial(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// NotifyNewEvent notifies the service of a new event being stored
|
||||
NotifyNewEvent(context.Context, *NewEventNotification) (*v1.Empty, error) |
||||
// TriggerSync manually triggers a sync cycle with all peers
|
||||
TriggerSync(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// GetSyncStatus returns current sync status for all peers
|
||||
GetSyncStatus(context.Context, *v1.Empty) (*SyncStatusResponse, error) |
||||
mustEmbedUnimplementedDistributedSyncServiceServer() |
||||
} |
||||
|
||||
// UnimplementedDistributedSyncServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedDistributedSyncServiceServer struct{} |
||||
|
||||
func (UnimplementedDistributedSyncServiceServer) Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Ready not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetInfo(context.Context, *v1.Empty) (*v1.SyncInfo, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetInfo not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetCurrentSerial(context.Context, *CurrentRequest) (*CurrentResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetCurrentSerial not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetEventIDs(context.Context, *EventIDsRequest) (*EventIDsResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetEventIDs not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) HandleCurrentRequest(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleCurrentRequest not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) HandleEventIDsRequest(context.Context, *v1.HTTPRequest) (*v1.HTTPResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleEventIDsRequest not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetPeers(context.Context, *v1.Empty) (*PeersResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetPeers not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) UpdatePeers(context.Context, *UpdatePeersRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method UpdatePeers not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) IsAuthorizedPeer(context.Context, *AuthorizedPeerRequest) (*AuthorizedPeerResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method IsAuthorizedPeer not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetPeerPubkey(context.Context, *PeerPubkeyRequest) (*PeerPubkeyResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetPeerPubkey not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) UpdateSerial(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method UpdateSerial not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) NotifyNewEvent(context.Context, *NewEventNotification) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method NotifyNewEvent not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) TriggerSync(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method TriggerSync not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) GetSyncStatus(context.Context, *v1.Empty) (*SyncStatusResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetSyncStatus not implemented") |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) mustEmbedUnimplementedDistributedSyncServiceServer() { |
||||
} |
||||
func (UnimplementedDistributedSyncServiceServer) testEmbeddedByValue() {} |
||||
|
||||
// UnsafeDistributedSyncServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to DistributedSyncServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeDistributedSyncServiceServer interface { |
||||
mustEmbedUnimplementedDistributedSyncServiceServer() |
||||
} |
||||
|
||||
func RegisterDistributedSyncServiceServer(s grpc.ServiceRegistrar, srv DistributedSyncServiceServer) { |
||||
// If the following call panics, it indicates UnimplementedDistributedSyncServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { |
||||
t.testEmbeddedByValue() |
||||
} |
||||
s.RegisterService(&DistributedSyncService_ServiceDesc, srv) |
||||
} |
||||
|
||||
func _DistributedSyncService_Ready_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).Ready(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_Ready_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).Ready(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetInfo(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetInfo_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetInfo(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetCurrentSerial_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(CurrentRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetCurrentSerial(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetCurrentSerial_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetCurrentSerial(ctx, req.(*CurrentRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetEventIDs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(EventIDsRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetEventIDs(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetEventIDs_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetEventIDs(ctx, req.(*EventIDsRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_HandleCurrentRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.HTTPRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).HandleCurrentRequest(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_HandleCurrentRequest_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).HandleCurrentRequest(ctx, req.(*v1.HTTPRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_HandleEventIDsRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.HTTPRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).HandleEventIDsRequest(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_HandleEventIDsRequest_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).HandleEventIDsRequest(ctx, req.(*v1.HTTPRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetPeers(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetPeers_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetPeers(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_UpdatePeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(UpdatePeersRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).UpdatePeers(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_UpdatePeers_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).UpdatePeers(ctx, req.(*UpdatePeersRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_IsAuthorizedPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(AuthorizedPeerRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).IsAuthorizedPeer(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_IsAuthorizedPeer_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).IsAuthorizedPeer(ctx, req.(*AuthorizedPeerRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetPeerPubkey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(PeerPubkeyRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetPeerPubkey(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetPeerPubkey_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetPeerPubkey(ctx, req.(*PeerPubkeyRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_UpdateSerial_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).UpdateSerial(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_UpdateSerial_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).UpdateSerial(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_NotifyNewEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(NewEventNotification) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).NotifyNewEvent(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_NotifyNewEvent_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).NotifyNewEvent(ctx, req.(*NewEventNotification)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_TriggerSync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).TriggerSync(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_TriggerSync_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).TriggerSync(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _DistributedSyncService_GetSyncStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(DistributedSyncServiceServer).GetSyncStatus(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: DistributedSyncService_GetSyncStatus_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(DistributedSyncServiceServer).GetSyncStatus(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
// DistributedSyncService_ServiceDesc is the grpc.ServiceDesc for DistributedSyncService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var DistributedSyncService_ServiceDesc = grpc.ServiceDesc{ |
||||
ServiceName: "orlysync.distributed.v1.DistributedSyncService", |
||||
HandlerType: (*DistributedSyncServiceServer)(nil), |
||||
Methods: []grpc.MethodDesc{ |
||||
{ |
||||
MethodName: "Ready", |
||||
Handler: _DistributedSyncService_Ready_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetInfo", |
||||
Handler: _DistributedSyncService_GetInfo_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetCurrentSerial", |
||||
Handler: _DistributedSyncService_GetCurrentSerial_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetEventIDs", |
||||
Handler: _DistributedSyncService_GetEventIDs_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleCurrentRequest", |
||||
Handler: _DistributedSyncService_HandleCurrentRequest_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleEventIDsRequest", |
||||
Handler: _DistributedSyncService_HandleEventIDsRequest_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetPeers", |
||||
Handler: _DistributedSyncService_GetPeers_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "UpdatePeers", |
||||
Handler: _DistributedSyncService_UpdatePeers_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "IsAuthorizedPeer", |
||||
Handler: _DistributedSyncService_IsAuthorizedPeer_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetPeerPubkey", |
||||
Handler: _DistributedSyncService_GetPeerPubkey_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "UpdateSerial", |
||||
Handler: _DistributedSyncService_UpdateSerial_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "NotifyNewEvent", |
||||
Handler: _DistributedSyncService_NotifyNewEvent_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "TriggerSync", |
||||
Handler: _DistributedSyncService_TriggerSync_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetSyncStatus", |
||||
Handler: _DistributedSyncService_GetSyncStatus_Handler, |
||||
}, |
||||
}, |
||||
Streams: []grpc.StreamDesc{}, |
||||
Metadata: "orlysync/distributed/v1/service.proto", |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,694 @@
@@ -0,0 +1,694 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: orlysync/negentropy/v1/service.proto
|
||||
|
||||
package negentropyv1 |
||||
|
||||
import ( |
||||
context "context" |
||||
grpc "google.golang.org/grpc" |
||||
codes "google.golang.org/grpc/codes" |
||||
status "google.golang.org/grpc/status" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9 |
||||
|
||||
const ( |
||||
NegentropyService_Ready_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/Ready" |
||||
NegentropyService_Start_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/Start" |
||||
NegentropyService_Stop_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/Stop" |
||||
NegentropyService_HandleNegOpen_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/HandleNegOpen" |
||||
NegentropyService_HandleNegMsg_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/HandleNegMsg" |
||||
NegentropyService_HandleNegClose_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/HandleNegClose" |
||||
NegentropyService_SyncWithPeer_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/SyncWithPeer" |
||||
NegentropyService_GetSyncStatus_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/GetSyncStatus" |
||||
NegentropyService_GetPeers_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/GetPeers" |
||||
NegentropyService_AddPeer_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/AddPeer" |
||||
NegentropyService_RemovePeer_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/RemovePeer" |
||||
NegentropyService_TriggerSync_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/TriggerSync" |
||||
NegentropyService_GetPeerSyncState_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/GetPeerSyncState" |
||||
NegentropyService_ListSessions_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/ListSessions" |
||||
NegentropyService_CloseSession_FullMethodName = "/orlysync.negentropy.v1.NegentropyService/CloseSession" |
||||
) |
||||
|
||||
// NegentropyServiceClient is the client API for NegentropyService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// NegentropyService provides NIP-77 negentropy-based set reconciliation
|
||||
// for both relay-to-relay sync and client-facing WebSocket operations
|
||||
type NegentropyServiceClient interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) |
||||
// Start starts the background relay-to-relay sync
|
||||
Start(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// Stop stops the background sync
|
||||
Stop(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// HandleNegOpen processes a NEG-OPEN message from a client
|
||||
HandleNegOpen(ctx context.Context, in *NegOpenRequest, opts ...grpc.CallOption) (*NegOpenResponse, error) |
||||
// HandleNegMsg processes a NEG-MSG message from a client
|
||||
HandleNegMsg(ctx context.Context, in *NegMsgRequest, opts ...grpc.CallOption) (*NegMsgResponse, error) |
||||
// HandleNegClose processes a NEG-CLOSE message from a client
|
||||
HandleNegClose(ctx context.Context, in *NegCloseRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// SyncWithPeer initiates negentropy sync with a specific peer relay
|
||||
SyncWithPeer(ctx context.Context, in *SyncPeerRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SyncProgress], error) |
||||
// GetSyncStatus returns the current sync status
|
||||
GetSyncStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*SyncStatusResponse, error) |
||||
// GetPeers returns the list of negentropy sync peers
|
||||
GetPeers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*PeersResponse, error) |
||||
// AddPeer adds a peer for negentropy sync
|
||||
AddPeer(ctx context.Context, in *AddPeerRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// RemovePeer removes a peer from negentropy sync
|
||||
RemovePeer(ctx context.Context, in *RemovePeerRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// TriggerSync manually triggers sync with a specific peer or all peers
|
||||
TriggerSync(ctx context.Context, in *TriggerSyncRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
// GetPeerSyncState returns sync state for a specific peer
|
||||
GetPeerSyncState(ctx context.Context, in *PeerSyncStateRequest, opts ...grpc.CallOption) (*PeerSyncStateResponse, error) |
||||
// ListSessions returns active client negentropy sessions
|
||||
ListSessions(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*ListSessionsResponse, error) |
||||
// CloseSession forcefully closes a client session
|
||||
CloseSession(ctx context.Context, in *CloseSessionRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
} |
||||
|
||||
type negentropyServiceClient struct { |
||||
cc grpc.ClientConnInterface |
||||
} |
||||
|
||||
func NewNegentropyServiceClient(cc grpc.ClientConnInterface) NegentropyServiceClient { |
||||
return &negentropyServiceClient{cc} |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.ReadyResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_Ready_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) Start(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_Start_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) Stop(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_Stop_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) HandleNegOpen(ctx context.Context, in *NegOpenRequest, opts ...grpc.CallOption) (*NegOpenResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(NegOpenResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_HandleNegOpen_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) HandleNegMsg(ctx context.Context, in *NegMsgRequest, opts ...grpc.CallOption) (*NegMsgResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(NegMsgResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_HandleNegMsg_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) HandleNegClose(ctx context.Context, in *NegCloseRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_HandleNegClose_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) SyncWithPeer(ctx context.Context, in *SyncPeerRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SyncProgress], error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
stream, err := c.cc.NewStream(ctx, &NegentropyService_ServiceDesc.Streams[0], NegentropyService_SyncWithPeer_FullMethodName, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
x := &grpc.GenericClientStream[SyncPeerRequest, SyncProgress]{ClientStream: stream} |
||||
if err := x.ClientStream.SendMsg(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if err := x.ClientStream.CloseSend(); err != nil { |
||||
return nil, err |
||||
} |
||||
return x, nil |
||||
} |
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type NegentropyService_SyncWithPeerClient = grpc.ServerStreamingClient[SyncProgress] |
||||
|
||||
func (c *negentropyServiceClient) GetSyncStatus(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*SyncStatusResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(SyncStatusResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_GetSyncStatus_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) GetPeers(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*PeersResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(PeersResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_GetPeers_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) AddPeer(ctx context.Context, in *AddPeerRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_AddPeer_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) RemovePeer(ctx context.Context, in *RemovePeerRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_RemovePeer_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) TriggerSync(ctx context.Context, in *TriggerSyncRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_TriggerSync_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) GetPeerSyncState(ctx context.Context, in *PeerSyncStateRequest, opts ...grpc.CallOption) (*PeerSyncStateResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(PeerSyncStateResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_GetPeerSyncState_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) ListSessions(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*ListSessionsResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(ListSessionsResponse) |
||||
err := c.cc.Invoke(ctx, NegentropyService_ListSessions_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *negentropyServiceClient) CloseSession(ctx context.Context, in *CloseSessionRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, NegentropyService_CloseSession_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// NegentropyServiceServer is the server API for NegentropyService service.
|
||||
// All implementations must embed UnimplementedNegentropyServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// NegentropyService provides NIP-77 negentropy-based set reconciliation
|
||||
// for both relay-to-relay sync and client-facing WebSocket operations
|
||||
type NegentropyServiceServer interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) |
||||
// Start starts the background relay-to-relay sync
|
||||
Start(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// Stop stops the background sync
|
||||
Stop(context.Context, *v1.Empty) (*v1.Empty, error) |
||||
// HandleNegOpen processes a NEG-OPEN message from a client
|
||||
HandleNegOpen(context.Context, *NegOpenRequest) (*NegOpenResponse, error) |
||||
// HandleNegMsg processes a NEG-MSG message from a client
|
||||
HandleNegMsg(context.Context, *NegMsgRequest) (*NegMsgResponse, error) |
||||
// HandleNegClose processes a NEG-CLOSE message from a client
|
||||
HandleNegClose(context.Context, *NegCloseRequest) (*v1.Empty, error) |
||||
// SyncWithPeer initiates negentropy sync with a specific peer relay
|
||||
SyncWithPeer(*SyncPeerRequest, grpc.ServerStreamingServer[SyncProgress]) error |
||||
// GetSyncStatus returns the current sync status
|
||||
GetSyncStatus(context.Context, *v1.Empty) (*SyncStatusResponse, error) |
||||
// GetPeers returns the list of negentropy sync peers
|
||||
GetPeers(context.Context, *v1.Empty) (*PeersResponse, error) |
||||
// AddPeer adds a peer for negentropy sync
|
||||
AddPeer(context.Context, *AddPeerRequest) (*v1.Empty, error) |
||||
// RemovePeer removes a peer from negentropy sync
|
||||
RemovePeer(context.Context, *RemovePeerRequest) (*v1.Empty, error) |
||||
// TriggerSync manually triggers sync with a specific peer or all peers
|
||||
TriggerSync(context.Context, *TriggerSyncRequest) (*v1.Empty, error) |
||||
// GetPeerSyncState returns sync state for a specific peer
|
||||
GetPeerSyncState(context.Context, *PeerSyncStateRequest) (*PeerSyncStateResponse, error) |
||||
// ListSessions returns active client negentropy sessions
|
||||
ListSessions(context.Context, *v1.Empty) (*ListSessionsResponse, error) |
||||
// CloseSession forcefully closes a client session
|
||||
CloseSession(context.Context, *CloseSessionRequest) (*v1.Empty, error) |
||||
mustEmbedUnimplementedNegentropyServiceServer() |
||||
} |
||||
|
||||
// UnimplementedNegentropyServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedNegentropyServiceServer struct{} |
||||
|
||||
func (UnimplementedNegentropyServiceServer) Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Ready not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) Start(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Start not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) Stop(context.Context, *v1.Empty) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Stop not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) HandleNegOpen(context.Context, *NegOpenRequest) (*NegOpenResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleNegOpen not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) HandleNegMsg(context.Context, *NegMsgRequest) (*NegMsgResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleNegMsg not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) HandleNegClose(context.Context, *NegCloseRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleNegClose not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) SyncWithPeer(*SyncPeerRequest, grpc.ServerStreamingServer[SyncProgress]) error { |
||||
return status.Error(codes.Unimplemented, "method SyncWithPeer not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) GetSyncStatus(context.Context, *v1.Empty) (*SyncStatusResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetSyncStatus not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) GetPeers(context.Context, *v1.Empty) (*PeersResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetPeers not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) AddPeer(context.Context, *AddPeerRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method AddPeer not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) RemovePeer(context.Context, *RemovePeerRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method RemovePeer not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) TriggerSync(context.Context, *TriggerSyncRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method TriggerSync not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) GetPeerSyncState(context.Context, *PeerSyncStateRequest) (*PeerSyncStateResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetPeerSyncState not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) ListSessions(context.Context, *v1.Empty) (*ListSessionsResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method ListSessions not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) CloseSession(context.Context, *CloseSessionRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method CloseSession not implemented") |
||||
} |
||||
func (UnimplementedNegentropyServiceServer) mustEmbedUnimplementedNegentropyServiceServer() {} |
||||
func (UnimplementedNegentropyServiceServer) testEmbeddedByValue() {} |
||||
|
||||
// UnsafeNegentropyServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to NegentropyServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeNegentropyServiceServer interface { |
||||
mustEmbedUnimplementedNegentropyServiceServer() |
||||
} |
||||
|
||||
func RegisterNegentropyServiceServer(s grpc.ServiceRegistrar, srv NegentropyServiceServer) { |
||||
// If the following call panics, it indicates UnimplementedNegentropyServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { |
||||
t.testEmbeddedByValue() |
||||
} |
||||
s.RegisterService(&NegentropyService_ServiceDesc, srv) |
||||
} |
||||
|
||||
func _NegentropyService_Ready_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).Ready(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_Ready_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).Ready(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).Start(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_Start_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).Start(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_Stop_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).Stop(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_Stop_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).Stop(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_HandleNegOpen_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(NegOpenRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).HandleNegOpen(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_HandleNegOpen_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).HandleNegOpen(ctx, req.(*NegOpenRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_HandleNegMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(NegMsgRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).HandleNegMsg(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_HandleNegMsg_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).HandleNegMsg(ctx, req.(*NegMsgRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_HandleNegClose_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(NegCloseRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).HandleNegClose(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_HandleNegClose_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).HandleNegClose(ctx, req.(*NegCloseRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_SyncWithPeer_Handler(srv interface{}, stream grpc.ServerStream) error { |
||||
m := new(SyncPeerRequest) |
||||
if err := stream.RecvMsg(m); err != nil { |
||||
return err |
||||
} |
||||
return srv.(NegentropyServiceServer).SyncWithPeer(m, &grpc.GenericServerStream[SyncPeerRequest, SyncProgress]{ServerStream: stream}) |
||||
} |
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type NegentropyService_SyncWithPeerServer = grpc.ServerStreamingServer[SyncProgress] |
||||
|
||||
func _NegentropyService_GetSyncStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).GetSyncStatus(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_GetSyncStatus_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).GetSyncStatus(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_GetPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).GetPeers(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_GetPeers_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).GetPeers(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_AddPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(AddPeerRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).AddPeer(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_AddPeer_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).AddPeer(ctx, req.(*AddPeerRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_RemovePeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(RemovePeerRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).RemovePeer(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_RemovePeer_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).RemovePeer(ctx, req.(*RemovePeerRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_TriggerSync_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(TriggerSyncRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).TriggerSync(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_TriggerSync_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).TriggerSync(ctx, req.(*TriggerSyncRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_GetPeerSyncState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(PeerSyncStateRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).GetPeerSyncState(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_GetPeerSyncState_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).GetPeerSyncState(ctx, req.(*PeerSyncStateRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_ListSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).ListSessions(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_ListSessions_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).ListSessions(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _NegentropyService_CloseSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(CloseSessionRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(NegentropyServiceServer).CloseSession(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: NegentropyService_CloseSession_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(NegentropyServiceServer).CloseSession(ctx, req.(*CloseSessionRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
// NegentropyService_ServiceDesc is the grpc.ServiceDesc for NegentropyService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var NegentropyService_ServiceDesc = grpc.ServiceDesc{ |
||||
ServiceName: "orlysync.negentropy.v1.NegentropyService", |
||||
HandlerType: (*NegentropyServiceServer)(nil), |
||||
Methods: []grpc.MethodDesc{ |
||||
{ |
||||
MethodName: "Ready", |
||||
Handler: _NegentropyService_Ready_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "Start", |
||||
Handler: _NegentropyService_Start_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "Stop", |
||||
Handler: _NegentropyService_Stop_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleNegOpen", |
||||
Handler: _NegentropyService_HandleNegOpen_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleNegMsg", |
||||
Handler: _NegentropyService_HandleNegMsg_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleNegClose", |
||||
Handler: _NegentropyService_HandleNegClose_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetSyncStatus", |
||||
Handler: _NegentropyService_GetSyncStatus_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetPeers", |
||||
Handler: _NegentropyService_GetPeers_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "AddPeer", |
||||
Handler: _NegentropyService_AddPeer_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "RemovePeer", |
||||
Handler: _NegentropyService_RemovePeer_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "TriggerSync", |
||||
Handler: _NegentropyService_TriggerSync_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetPeerSyncState", |
||||
Handler: _NegentropyService_GetPeerSyncState_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "ListSessions", |
||||
Handler: _NegentropyService_ListSessions_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "CloseSession", |
||||
Handler: _NegentropyService_CloseSession_Handler, |
||||
}, |
||||
}, |
||||
Streams: []grpc.StreamDesc{ |
||||
{ |
||||
StreamName: "SyncWithPeer", |
||||
Handler: _NegentropyService_SyncWithPeer_Handler, |
||||
ServerStreams: true, |
||||
}, |
||||
}, |
||||
Metadata: "orlysync/negentropy/v1/service.proto", |
||||
} |
||||
@ -0,0 +1,574 @@
@@ -0,0 +1,574 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: orlysync/relaygroup/v1/service.proto
|
||||
|
||||
package relaygroupv1 |
||||
|
||||
import ( |
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect" |
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
reflect "reflect" |
||||
sync "sync" |
||||
unsafe "unsafe" |
||||
) |
||||
|
||||
const ( |
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |
||||
) |
||||
|
||||
// RelayGroupConfig represents a relay group configuration
|
||||
type RelayGroupConfig struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Relays []string `protobuf:"bytes,1,rep,name=relays,proto3" json:"relays,omitempty"` // List of relay URLs
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *RelayGroupConfig) Reset() { |
||||
*x = RelayGroupConfig{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[0] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *RelayGroupConfig) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*RelayGroupConfig) ProtoMessage() {} |
||||
|
||||
func (x *RelayGroupConfig) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[0] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use RelayGroupConfig.ProtoReflect.Descriptor instead.
|
||||
func (*RelayGroupConfig) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{0} |
||||
} |
||||
|
||||
func (x *RelayGroupConfig) GetRelays() []string { |
||||
if x != nil { |
||||
return x.Relays |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// RelayGroupConfigResponse contains the authoritative config
|
||||
type RelayGroupConfigResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Config *RelayGroupConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` |
||||
Found bool `protobuf:"varint,2,opt,name=found,proto3" json:"found,omitempty"` |
||||
SourceEventId []byte `protobuf:"bytes,3,opt,name=source_event_id,json=sourceEventId,proto3" json:"source_event_id,omitempty"` // ID of the event that provided this config
|
||||
SourceTimestamp int64 `protobuf:"varint,4,opt,name=source_timestamp,json=sourceTimestamp,proto3" json:"source_timestamp,omitempty"` // Timestamp of the source event
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) Reset() { |
||||
*x = RelayGroupConfigResponse{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[1] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*RelayGroupConfigResponse) ProtoMessage() {} |
||||
|
||||
func (x *RelayGroupConfigResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[1] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use RelayGroupConfigResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RelayGroupConfigResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{1} |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) GetConfig() *RelayGroupConfig { |
||||
if x != nil { |
||||
return x.Config |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) GetFound() bool { |
||||
if x != nil { |
||||
return x.Found |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) GetSourceEventId() []byte { |
||||
if x != nil { |
||||
return x.SourceEventId |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (x *RelayGroupConfigResponse) GetSourceTimestamp() int64 { |
||||
if x != nil { |
||||
return x.SourceTimestamp |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// RelaysResponse contains the list of relays
|
||||
type RelaysResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Relays []string `protobuf:"bytes,1,rep,name=relays,proto3" json:"relays,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *RelaysResponse) Reset() { |
||||
*x = RelaysResponse{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[2] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *RelaysResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*RelaysResponse) ProtoMessage() {} |
||||
|
||||
func (x *RelaysResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[2] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use RelaysResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RelaysResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{2} |
||||
} |
||||
|
||||
func (x *RelaysResponse) GetRelays() []string { |
||||
if x != nil { |
||||
return x.Relays |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// AuthorizedPublisherRequest checks if a pubkey is authorized
|
||||
type AuthorizedPublisherRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Pubkey []byte `protobuf:"bytes,1,opt,name=pubkey,proto3" json:"pubkey,omitempty"` // 32 bytes public key
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherRequest) Reset() { |
||||
*x = AuthorizedPublisherRequest{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[3] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*AuthorizedPublisherRequest) ProtoMessage() {} |
||||
|
||||
func (x *AuthorizedPublisherRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[3] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use AuthorizedPublisherRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AuthorizedPublisherRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{3} |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherRequest) GetPubkey() []byte { |
||||
if x != nil { |
||||
return x.Pubkey |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// AuthorizedPublisherResponse indicates if the pubkey is authorized
|
||||
type AuthorizedPublisherResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Authorized bool `protobuf:"varint,1,opt,name=authorized,proto3" json:"authorized,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherResponse) Reset() { |
||||
*x = AuthorizedPublisherResponse{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[4] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*AuthorizedPublisherResponse) ProtoMessage() {} |
||||
|
||||
func (x *AuthorizedPublisherResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[4] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use AuthorizedPublisherResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AuthorizedPublisherResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{4} |
||||
} |
||||
|
||||
func (x *AuthorizedPublisherResponse) GetAuthorized() bool { |
||||
if x != nil { |
||||
return x.Authorized |
||||
} |
||||
return false |
||||
} |
||||
|
||||
// AuthorizedPubkeysResponse contains all authorized pubkeys
|
||||
type AuthorizedPubkeysResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Pubkeys [][]byte `protobuf:"bytes,1,rep,name=pubkeys,proto3" json:"pubkeys,omitempty"` // List of 32-byte pubkeys
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *AuthorizedPubkeysResponse) Reset() { |
||||
*x = AuthorizedPubkeysResponse{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[5] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *AuthorizedPubkeysResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*AuthorizedPubkeysResponse) ProtoMessage() {} |
||||
|
||||
func (x *AuthorizedPubkeysResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[5] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use AuthorizedPubkeysResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AuthorizedPubkeysResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{5} |
||||
} |
||||
|
||||
func (x *AuthorizedPubkeysResponse) GetPubkeys() [][]byte { |
||||
if x != nil { |
||||
return x.Pubkeys |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ValidateEventRequest requests validation of a relay group event
|
||||
type ValidateEventRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Event *v1.Event `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *ValidateEventRequest) Reset() { |
||||
*x = ValidateEventRequest{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[6] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *ValidateEventRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*ValidateEventRequest) ProtoMessage() {} |
||||
|
||||
func (x *ValidateEventRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[6] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use ValidateEventRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ValidateEventRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{6} |
||||
} |
||||
|
||||
func (x *ValidateEventRequest) GetEvent() *v1.Event { |
||||
if x != nil { |
||||
return x.Event |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ValidateEventResponse contains validation results
|
||||
type ValidateEventResponse struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"` |
||||
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Error message if not valid
|
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *ValidateEventResponse) Reset() { |
||||
*x = ValidateEventResponse{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[7] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *ValidateEventResponse) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*ValidateEventResponse) ProtoMessage() {} |
||||
|
||||
func (x *ValidateEventResponse) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[7] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use ValidateEventResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ValidateEventResponse) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{7} |
||||
} |
||||
|
||||
func (x *ValidateEventResponse) GetValid() bool { |
||||
if x != nil { |
||||
return x.Valid |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (x *ValidateEventResponse) GetError() string { |
||||
if x != nil { |
||||
return x.Error |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// HandleEventRequest requests processing of a relay group event
|
||||
type HandleEventRequest struct { |
||||
state protoimpl.MessageState `protogen:"open.v1"` |
||||
Event *v1.Event `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` |
||||
unknownFields protoimpl.UnknownFields |
||||
sizeCache protoimpl.SizeCache |
||||
} |
||||
|
||||
func (x *HandleEventRequest) Reset() { |
||||
*x = HandleEventRequest{} |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[8] |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
|
||||
func (x *HandleEventRequest) String() string { |
||||
return protoimpl.X.MessageStringOf(x) |
||||
} |
||||
|
||||
func (*HandleEventRequest) ProtoMessage() {} |
||||
|
||||
func (x *HandleEventRequest) ProtoReflect() protoreflect.Message { |
||||
mi := &file_orlysync_relaygroup_v1_service_proto_msgTypes[8] |
||||
if x != nil { |
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |
||||
if ms.LoadMessageInfo() == nil { |
||||
ms.StoreMessageInfo(mi) |
||||
} |
||||
return ms |
||||
} |
||||
return mi.MessageOf(x) |
||||
} |
||||
|
||||
// Deprecated: Use HandleEventRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HandleEventRequest) Descriptor() ([]byte, []int) { |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescGZIP(), []int{8} |
||||
} |
||||
|
||||
func (x *HandleEventRequest) GetEvent() *v1.Event { |
||||
if x != nil { |
||||
return x.Event |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
var File_orlysync_relaygroup_v1_service_proto protoreflect.FileDescriptor |
||||
|
||||
const file_orlysync_relaygroup_v1_service_proto_rawDesc = "" + |
||||
"\n" + |
||||
"$orlysync/relaygroup/v1/service.proto\x12\x16orlysync.relaygroup.v1\x1a\x1eorlysync/common/v1/types.proto\"*\n" + |
||||
"\x10RelayGroupConfig\x12\x16\n" + |
||||
"\x06relays\x18\x01 \x03(\tR\x06relays\"\xc5\x01\n" + |
||||
"\x18RelayGroupConfigResponse\x12@\n" + |
||||
"\x06config\x18\x01 \x01(\v2(.orlysync.relaygroup.v1.RelayGroupConfigR\x06config\x12\x14\n" + |
||||
"\x05found\x18\x02 \x01(\bR\x05found\x12&\n" + |
||||
"\x0fsource_event_id\x18\x03 \x01(\fR\rsourceEventId\x12)\n" + |
||||
"\x10source_timestamp\x18\x04 \x01(\x03R\x0fsourceTimestamp\"(\n" + |
||||
"\x0eRelaysResponse\x12\x16\n" + |
||||
"\x06relays\x18\x01 \x03(\tR\x06relays\"4\n" + |
||||
"\x1aAuthorizedPublisherRequest\x12\x16\n" + |
||||
"\x06pubkey\x18\x01 \x01(\fR\x06pubkey\"=\n" + |
||||
"\x1bAuthorizedPublisherResponse\x12\x1e\n" + |
||||
"\n" + |
||||
"authorized\x18\x01 \x01(\bR\n" + |
||||
"authorized\"5\n" + |
||||
"\x19AuthorizedPubkeysResponse\x12\x18\n" + |
||||
"\apubkeys\x18\x01 \x03(\fR\apubkeys\"G\n" + |
||||
"\x14ValidateEventRequest\x12/\n" + |
||||
"\x05event\x18\x01 \x01(\v2\x19.orlysync.common.v1.EventR\x05event\"C\n" + |
||||
"\x15ValidateEventResponse\x12\x14\n" + |
||||
"\x05valid\x18\x01 \x01(\bR\x05valid\x12\x14\n" + |
||||
"\x05error\x18\x02 \x01(\tR\x05error\"E\n" + |
||||
"\x12HandleEventRequest\x12/\n" + |
||||
"\x05event\x18\x01 \x01(\v2\x19.orlysync.common.v1.EventR\x05event2\xd3\x05\n" + |
||||
"\x11RelayGroupService\x12E\n" + |
||||
"\x05Ready\x12\x19.orlysync.common.v1.Empty\x1a!.orlysync.common.v1.ReadyResponse\x12f\n" + |
||||
"\x17FindAuthoritativeConfig\x12\x19.orlysync.common.v1.Empty\x1a0.orlysync.relaygroup.v1.RelayGroupConfigResponse\x12N\n" + |
||||
"\tGetRelays\x12\x19.orlysync.common.v1.Empty\x1a&.orlysync.relaygroup.v1.RelaysResponse\x12\x80\x01\n" + |
||||
"\x15IsAuthorizedPublisher\x122.orlysync.relaygroup.v1.AuthorizedPublisherRequest\x1a3.orlysync.relaygroup.v1.AuthorizedPublisherResponse\x12d\n" + |
||||
"\x14GetAuthorizedPubkeys\x12\x19.orlysync.common.v1.Empty\x1a1.orlysync.relaygroup.v1.AuthorizedPubkeysResponse\x12v\n" + |
||||
"\x17ValidateRelayGroupEvent\x12,.orlysync.relaygroup.v1.ValidateEventRequest\x1a-.orlysync.relaygroup.v1.ValidateEventResponse\x12^\n" + |
||||
"\x15HandleRelayGroupEvent\x12*.orlysync.relaygroup.v1.HandleEventRequest\x1a\x19.orlysync.common.v1.EmptyB=Z;next.orly.dev/pkg/proto/orlysync/relaygroup/v1;relaygroupv1b\x06proto3" |
||||
|
||||
var ( |
||||
file_orlysync_relaygroup_v1_service_proto_rawDescOnce sync.Once |
||||
file_orlysync_relaygroup_v1_service_proto_rawDescData []byte |
||||
) |
||||
|
||||
func file_orlysync_relaygroup_v1_service_proto_rawDescGZIP() []byte { |
||||
file_orlysync_relaygroup_v1_service_proto_rawDescOnce.Do(func() { |
||||
file_orlysync_relaygroup_v1_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_orlysync_relaygroup_v1_service_proto_rawDesc), len(file_orlysync_relaygroup_v1_service_proto_rawDesc))) |
||||
}) |
||||
return file_orlysync_relaygroup_v1_service_proto_rawDescData |
||||
} |
||||
|
||||
var file_orlysync_relaygroup_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 9) |
||||
var file_orlysync_relaygroup_v1_service_proto_goTypes = []any{ |
||||
(*RelayGroupConfig)(nil), // 0: orlysync.relaygroup.v1.RelayGroupConfig
|
||||
(*RelayGroupConfigResponse)(nil), // 1: orlysync.relaygroup.v1.RelayGroupConfigResponse
|
||||
(*RelaysResponse)(nil), // 2: orlysync.relaygroup.v1.RelaysResponse
|
||||
(*AuthorizedPublisherRequest)(nil), // 3: orlysync.relaygroup.v1.AuthorizedPublisherRequest
|
||||
(*AuthorizedPublisherResponse)(nil), // 4: orlysync.relaygroup.v1.AuthorizedPublisherResponse
|
||||
(*AuthorizedPubkeysResponse)(nil), // 5: orlysync.relaygroup.v1.AuthorizedPubkeysResponse
|
||||
(*ValidateEventRequest)(nil), // 6: orlysync.relaygroup.v1.ValidateEventRequest
|
||||
(*ValidateEventResponse)(nil), // 7: orlysync.relaygroup.v1.ValidateEventResponse
|
||||
(*HandleEventRequest)(nil), // 8: orlysync.relaygroup.v1.HandleEventRequest
|
||||
(*v1.Event)(nil), // 9: orlysync.common.v1.Event
|
||||
(*v1.Empty)(nil), // 10: orlysync.common.v1.Empty
|
||||
(*v1.ReadyResponse)(nil), // 11: orlysync.common.v1.ReadyResponse
|
||||
} |
||||
var file_orlysync_relaygroup_v1_service_proto_depIdxs = []int32{ |
||||
0, // 0: orlysync.relaygroup.v1.RelayGroupConfigResponse.config:type_name -> orlysync.relaygroup.v1.RelayGroupConfig
|
||||
9, // 1: orlysync.relaygroup.v1.ValidateEventRequest.event:type_name -> orlysync.common.v1.Event
|
||||
9, // 2: orlysync.relaygroup.v1.HandleEventRequest.event:type_name -> orlysync.common.v1.Event
|
||||
10, // 3: orlysync.relaygroup.v1.RelayGroupService.Ready:input_type -> orlysync.common.v1.Empty
|
||||
10, // 4: orlysync.relaygroup.v1.RelayGroupService.FindAuthoritativeConfig:input_type -> orlysync.common.v1.Empty
|
||||
10, // 5: orlysync.relaygroup.v1.RelayGroupService.GetRelays:input_type -> orlysync.common.v1.Empty
|
||||
3, // 6: orlysync.relaygroup.v1.RelayGroupService.IsAuthorizedPublisher:input_type -> orlysync.relaygroup.v1.AuthorizedPublisherRequest
|
||||
10, // 7: orlysync.relaygroup.v1.RelayGroupService.GetAuthorizedPubkeys:input_type -> orlysync.common.v1.Empty
|
||||
6, // 8: orlysync.relaygroup.v1.RelayGroupService.ValidateRelayGroupEvent:input_type -> orlysync.relaygroup.v1.ValidateEventRequest
|
||||
8, // 9: orlysync.relaygroup.v1.RelayGroupService.HandleRelayGroupEvent:input_type -> orlysync.relaygroup.v1.HandleEventRequest
|
||||
11, // 10: orlysync.relaygroup.v1.RelayGroupService.Ready:output_type -> orlysync.common.v1.ReadyResponse
|
||||
1, // 11: orlysync.relaygroup.v1.RelayGroupService.FindAuthoritativeConfig:output_type -> orlysync.relaygroup.v1.RelayGroupConfigResponse
|
||||
2, // 12: orlysync.relaygroup.v1.RelayGroupService.GetRelays:output_type -> orlysync.relaygroup.v1.RelaysResponse
|
||||
4, // 13: orlysync.relaygroup.v1.RelayGroupService.IsAuthorizedPublisher:output_type -> orlysync.relaygroup.v1.AuthorizedPublisherResponse
|
||||
5, // 14: orlysync.relaygroup.v1.RelayGroupService.GetAuthorizedPubkeys:output_type -> orlysync.relaygroup.v1.AuthorizedPubkeysResponse
|
||||
7, // 15: orlysync.relaygroup.v1.RelayGroupService.ValidateRelayGroupEvent:output_type -> orlysync.relaygroup.v1.ValidateEventResponse
|
||||
10, // 16: orlysync.relaygroup.v1.RelayGroupService.HandleRelayGroupEvent:output_type -> orlysync.common.v1.Empty
|
||||
10, // [10:17] is the sub-list for method output_type
|
||||
3, // [3:10] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
} |
||||
|
||||
func init() { file_orlysync_relaygroup_v1_service_proto_init() } |
||||
func file_orlysync_relaygroup_v1_service_proto_init() { |
||||
if File_orlysync_relaygroup_v1_service_proto != nil { |
||||
return |
||||
} |
||||
type x struct{} |
||||
out := protoimpl.TypeBuilder{ |
||||
File: protoimpl.DescBuilder{ |
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_orlysync_relaygroup_v1_service_proto_rawDesc), len(file_orlysync_relaygroup_v1_service_proto_rawDesc)), |
||||
NumEnums: 0, |
||||
NumMessages: 9, |
||||
NumExtensions: 0, |
||||
NumServices: 1, |
||||
}, |
||||
GoTypes: file_orlysync_relaygroup_v1_service_proto_goTypes, |
||||
DependencyIndexes: file_orlysync_relaygroup_v1_service_proto_depIdxs, |
||||
MessageInfos: file_orlysync_relaygroup_v1_service_proto_msgTypes, |
||||
}.Build() |
||||
File_orlysync_relaygroup_v1_service_proto = out.File |
||||
file_orlysync_relaygroup_v1_service_proto_goTypes = nil |
||||
file_orlysync_relaygroup_v1_service_proto_depIdxs = nil |
||||
} |
||||
@ -0,0 +1,372 @@
@@ -0,0 +1,372 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc (unknown)
|
||||
// source: orlysync/relaygroup/v1/service.proto
|
||||
|
||||
package relaygroupv1 |
||||
|
||||
import ( |
||||
context "context" |
||||
grpc "google.golang.org/grpc" |
||||
codes "google.golang.org/grpc/codes" |
||||
status "google.golang.org/grpc/status" |
||||
v1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
) |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9 |
||||
|
||||
const ( |
||||
RelayGroupService_Ready_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/Ready" |
||||
RelayGroupService_FindAuthoritativeConfig_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/FindAuthoritativeConfig" |
||||
RelayGroupService_GetRelays_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/GetRelays" |
||||
RelayGroupService_IsAuthorizedPublisher_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/IsAuthorizedPublisher" |
||||
RelayGroupService_GetAuthorizedPubkeys_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/GetAuthorizedPubkeys" |
||||
RelayGroupService_ValidateRelayGroupEvent_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/ValidateRelayGroupEvent" |
||||
RelayGroupService_HandleRelayGroupEvent_FullMethodName = "/orlysync.relaygroup.v1.RelayGroupService/HandleRelayGroupEvent" |
||||
) |
||||
|
||||
// RelayGroupServiceClient is the client API for RelayGroupService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// RelayGroupService provides relay group configuration discovery
|
||||
// by selecting authoritative config from Kind 39105 events
|
||||
type RelayGroupServiceClient interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) |
||||
// FindAuthoritativeConfig finds the authoritative relay group configuration
|
||||
// using timestamp ordering with hash tie-breaking
|
||||
FindAuthoritativeConfig(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*RelayGroupConfigResponse, error) |
||||
// GetRelays returns the list of relays from the authoritative config
|
||||
GetRelays(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*RelaysResponse, error) |
||||
// IsAuthorizedPublisher checks if a pubkey can publish relay group configs
|
||||
IsAuthorizedPublisher(ctx context.Context, in *AuthorizedPublisherRequest, opts ...grpc.CallOption) (*AuthorizedPublisherResponse, error) |
||||
// GetAuthorizedPubkeys returns all authorized publisher pubkeys
|
||||
GetAuthorizedPubkeys(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*AuthorizedPubkeysResponse, error) |
||||
// ValidateRelayGroupEvent validates a relay group configuration event
|
||||
ValidateRelayGroupEvent(ctx context.Context, in *ValidateEventRequest, opts ...grpc.CallOption) (*ValidateEventResponse, error) |
||||
// HandleRelayGroupEvent processes a relay group event and triggers peer updates
|
||||
HandleRelayGroupEvent(ctx context.Context, in *HandleEventRequest, opts ...grpc.CallOption) (*v1.Empty, error) |
||||
} |
||||
|
||||
type relayGroupServiceClient struct { |
||||
cc grpc.ClientConnInterface |
||||
} |
||||
|
||||
func NewRelayGroupServiceClient(cc grpc.ClientConnInterface) RelayGroupServiceClient { |
||||
return &relayGroupServiceClient{cc} |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) Ready(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*v1.ReadyResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.ReadyResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_Ready_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) FindAuthoritativeConfig(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*RelayGroupConfigResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(RelayGroupConfigResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_FindAuthoritativeConfig_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) GetRelays(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*RelaysResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(RelaysResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_GetRelays_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) IsAuthorizedPublisher(ctx context.Context, in *AuthorizedPublisherRequest, opts ...grpc.CallOption) (*AuthorizedPublisherResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(AuthorizedPublisherResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_IsAuthorizedPublisher_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) GetAuthorizedPubkeys(ctx context.Context, in *v1.Empty, opts ...grpc.CallOption) (*AuthorizedPubkeysResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(AuthorizedPubkeysResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_GetAuthorizedPubkeys_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) ValidateRelayGroupEvent(ctx context.Context, in *ValidateEventRequest, opts ...grpc.CallOption) (*ValidateEventResponse, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(ValidateEventResponse) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_ValidateRelayGroupEvent_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
func (c *relayGroupServiceClient) HandleRelayGroupEvent(ctx context.Context, in *HandleEventRequest, opts ...grpc.CallOption) (*v1.Empty, error) { |
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) |
||||
out := new(v1.Empty) |
||||
err := c.cc.Invoke(ctx, RelayGroupService_HandleRelayGroupEvent_FullMethodName, in, out, cOpts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// RelayGroupServiceServer is the server API for RelayGroupService service.
|
||||
// All implementations must embed UnimplementedRelayGroupServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// RelayGroupService provides relay group configuration discovery
|
||||
// by selecting authoritative config from Kind 39105 events
|
||||
type RelayGroupServiceServer interface { |
||||
// Ready returns whether the service is ready to serve requests
|
||||
Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) |
||||
// FindAuthoritativeConfig finds the authoritative relay group configuration
|
||||
// using timestamp ordering with hash tie-breaking
|
||||
FindAuthoritativeConfig(context.Context, *v1.Empty) (*RelayGroupConfigResponse, error) |
||||
// GetRelays returns the list of relays from the authoritative config
|
||||
GetRelays(context.Context, *v1.Empty) (*RelaysResponse, error) |
||||
// IsAuthorizedPublisher checks if a pubkey can publish relay group configs
|
||||
IsAuthorizedPublisher(context.Context, *AuthorizedPublisherRequest) (*AuthorizedPublisherResponse, error) |
||||
// GetAuthorizedPubkeys returns all authorized publisher pubkeys
|
||||
GetAuthorizedPubkeys(context.Context, *v1.Empty) (*AuthorizedPubkeysResponse, error) |
||||
// ValidateRelayGroupEvent validates a relay group configuration event
|
||||
ValidateRelayGroupEvent(context.Context, *ValidateEventRequest) (*ValidateEventResponse, error) |
||||
// HandleRelayGroupEvent processes a relay group event and triggers peer updates
|
||||
HandleRelayGroupEvent(context.Context, *HandleEventRequest) (*v1.Empty, error) |
||||
mustEmbedUnimplementedRelayGroupServiceServer() |
||||
} |
||||
|
||||
// UnimplementedRelayGroupServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedRelayGroupServiceServer struct{} |
||||
|
||||
func (UnimplementedRelayGroupServiceServer) Ready(context.Context, *v1.Empty) (*v1.ReadyResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method Ready not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) FindAuthoritativeConfig(context.Context, *v1.Empty) (*RelayGroupConfigResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method FindAuthoritativeConfig not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) GetRelays(context.Context, *v1.Empty) (*RelaysResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetRelays not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) IsAuthorizedPublisher(context.Context, *AuthorizedPublisherRequest) (*AuthorizedPublisherResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method IsAuthorizedPublisher not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) GetAuthorizedPubkeys(context.Context, *v1.Empty) (*AuthorizedPubkeysResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method GetAuthorizedPubkeys not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) ValidateRelayGroupEvent(context.Context, *ValidateEventRequest) (*ValidateEventResponse, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method ValidateRelayGroupEvent not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) HandleRelayGroupEvent(context.Context, *HandleEventRequest) (*v1.Empty, error) { |
||||
return nil, status.Error(codes.Unimplemented, "method HandleRelayGroupEvent not implemented") |
||||
} |
||||
func (UnimplementedRelayGroupServiceServer) mustEmbedUnimplementedRelayGroupServiceServer() {} |
||||
func (UnimplementedRelayGroupServiceServer) testEmbeddedByValue() {} |
||||
|
||||
// UnsafeRelayGroupServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to RelayGroupServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeRelayGroupServiceServer interface { |
||||
mustEmbedUnimplementedRelayGroupServiceServer() |
||||
} |
||||
|
||||
func RegisterRelayGroupServiceServer(s grpc.ServiceRegistrar, srv RelayGroupServiceServer) { |
||||
// If the following call panics, it indicates UnimplementedRelayGroupServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { |
||||
t.testEmbeddedByValue() |
||||
} |
||||
s.RegisterService(&RelayGroupService_ServiceDesc, srv) |
||||
} |
||||
|
||||
func _RelayGroupService_Ready_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).Ready(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_Ready_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).Ready(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_FindAuthoritativeConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).FindAuthoritativeConfig(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_FindAuthoritativeConfig_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).FindAuthoritativeConfig(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_GetRelays_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).GetRelays(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_GetRelays_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).GetRelays(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_IsAuthorizedPublisher_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(AuthorizedPublisherRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).IsAuthorizedPublisher(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_IsAuthorizedPublisher_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).IsAuthorizedPublisher(ctx, req.(*AuthorizedPublisherRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_GetAuthorizedPubkeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(v1.Empty) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).GetAuthorizedPubkeys(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_GetAuthorizedPubkeys_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).GetAuthorizedPubkeys(ctx, req.(*v1.Empty)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_ValidateRelayGroupEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(ValidateEventRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).ValidateRelayGroupEvent(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_ValidateRelayGroupEvent_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).ValidateRelayGroupEvent(ctx, req.(*ValidateEventRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
func _RelayGroupService_HandleRelayGroupEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(HandleEventRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RelayGroupServiceServer).HandleRelayGroupEvent(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: RelayGroupService_HandleRelayGroupEvent_FullMethodName, |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RelayGroupServiceServer).HandleRelayGroupEvent(ctx, req.(*HandleEventRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
// RelayGroupService_ServiceDesc is the grpc.ServiceDesc for RelayGroupService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var RelayGroupService_ServiceDesc = grpc.ServiceDesc{ |
||||
ServiceName: "orlysync.relaygroup.v1.RelayGroupService", |
||||
HandlerType: (*RelayGroupServiceServer)(nil), |
||||
Methods: []grpc.MethodDesc{ |
||||
{ |
||||
MethodName: "Ready", |
||||
Handler: _RelayGroupService_Ready_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "FindAuthoritativeConfig", |
||||
Handler: _RelayGroupService_FindAuthoritativeConfig_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetRelays", |
||||
Handler: _RelayGroupService_GetRelays_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "IsAuthorizedPublisher", |
||||
Handler: _RelayGroupService_IsAuthorizedPublisher_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "GetAuthorizedPubkeys", |
||||
Handler: _RelayGroupService_GetAuthorizedPubkeys_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "ValidateRelayGroupEvent", |
||||
Handler: _RelayGroupService_ValidateRelayGroupEvent_Handler, |
||||
}, |
||||
{ |
||||
MethodName: "HandleRelayGroupEvent", |
||||
Handler: _RelayGroupService_HandleRelayGroupEvent_Handler, |
||||
}, |
||||
}, |
||||
Streams: []grpc.StreamDesc{}, |
||||
Metadata: "orlysync/relaygroup/v1/service.proto", |
||||
} |
||||
@ -0,0 +1,187 @@
@@ -0,0 +1,187 @@
|
||||
// Package grpc provides a gRPC client for the cluster sync service.
|
||||
package grpc |
||||
|
||||
import ( |
||||
"context" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/credentials/insecure" |
||||
"lol.mleku.dev/log" |
||||
|
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
clusterv1 "next.orly.dev/pkg/proto/orlysync/cluster/v1" |
||||
) |
||||
|
||||
// Client is a gRPC client for the cluster sync service.
|
||||
type Client struct { |
||||
conn *grpc.ClientConn |
||||
client clusterv1.ClusterSyncServiceClient |
||||
ready chan struct{} |
||||
} |
||||
|
||||
// ClientConfig holds configuration for the gRPC client.
|
||||
type ClientConfig struct { |
||||
ServerAddress string |
||||
ConnectTimeout time.Duration |
||||
} |
||||
|
||||
// New creates a new gRPC cluster sync client.
|
||||
func New(ctx context.Context, cfg *ClientConfig) (*Client, error) { |
||||
timeout := cfg.ConnectTimeout |
||||
if timeout == 0 { |
||||
timeout = 10 * time.Second |
||||
} |
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, timeout) |
||||
defer cancel() |
||||
|
||||
conn, err := grpc.DialContext(dialCtx, cfg.ServerAddress, |
||||
grpc.WithTransportCredentials(insecure.NewCredentials()), |
||||
grpc.WithDefaultCallOptions( |
||||
grpc.MaxCallRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxCallSendMsgSize(16<<20), // 16MB
|
||||
), |
||||
) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
c := &Client{ |
||||
conn: conn, |
||||
client: clusterv1.NewClusterSyncServiceClient(conn), |
||||
ready: make(chan struct{}), |
||||
} |
||||
|
||||
go c.waitForReady(ctx) |
||||
|
||||
return c, nil |
||||
} |
||||
|
||||
func (c *Client) waitForReady(ctx context.Context) { |
||||
for { |
||||
select { |
||||
case <-ctx.Done(): |
||||
return |
||||
default: |
||||
resp, err := c.client.Ready(ctx, &commonv1.Empty{}) |
||||
if err == nil && resp.Ready { |
||||
close(c.ready) |
||||
log.I.F("gRPC cluster sync client connected and ready") |
||||
return |
||||
} |
||||
time.Sleep(100 * time.Millisecond) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Close closes the gRPC connection.
|
||||
func (c *Client) Close() error { |
||||
if c.conn != nil { |
||||
return c.conn.Close() |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Ready returns a channel that closes when the client is ready.
|
||||
func (c *Client) Ready() <-chan struct{} { |
||||
return c.ready |
||||
} |
||||
|
||||
// Start starts the cluster polling loop.
|
||||
func (c *Client) Start(ctx context.Context) error { |
||||
_, err := c.client.Start(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// Stop stops the cluster polling loop.
|
||||
func (c *Client) Stop(ctx context.Context) error { |
||||
_, err := c.client.Stop(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// HandleLatestSerial proxies an HTTP latest serial request.
|
||||
func (c *Client) HandleLatestSerial(ctx context.Context, method string, body []byte, headers map[string]string) (int, []byte, map[string]string, error) { |
||||
resp, err := c.client.HandleLatestSerial(ctx, &commonv1.HTTPRequest{ |
||||
Method: method, |
||||
Body: body, |
||||
Headers: headers, |
||||
}) |
||||
if err != nil { |
||||
return 0, nil, nil, err |
||||
} |
||||
return int(resp.StatusCode), resp.Body, resp.Headers, nil |
||||
} |
||||
|
||||
// HandleEventsRange proxies an HTTP events range request.
|
||||
func (c *Client) HandleEventsRange(ctx context.Context, method string, body []byte, headers map[string]string, queryString string) (int, []byte, map[string]string, error) { |
||||
resp, err := c.client.HandleEventsRange(ctx, &commonv1.HTTPRequest{ |
||||
Method: method, |
||||
Body: body, |
||||
Headers: headers, |
||||
QueryString: queryString, |
||||
}) |
||||
if err != nil { |
||||
return 0, nil, nil, err |
||||
} |
||||
return int(resp.StatusCode), resp.Body, resp.Headers, nil |
||||
} |
||||
|
||||
// GetMembers returns the current cluster members.
|
||||
func (c *Client) GetMembers(ctx context.Context) ([]*clusterv1.ClusterMember, error) { |
||||
resp, err := c.client.GetMembers(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Members, nil |
||||
} |
||||
|
||||
// UpdateMembership updates cluster membership.
|
||||
func (c *Client) UpdateMembership(ctx context.Context, relayURLs []string) error { |
||||
_, err := c.client.UpdateMembership(ctx, &clusterv1.UpdateMembershipRequest{ |
||||
RelayUrls: relayURLs, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// HandleMembershipEvent processes a cluster membership event.
|
||||
func (c *Client) HandleMembershipEvent(ctx context.Context, event *commonv1.Event) error { |
||||
_, err := c.client.HandleMembershipEvent(ctx, &clusterv1.MembershipEventRequest{ |
||||
Event: event, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// GetClusterStatus returns overall cluster status.
|
||||
func (c *Client) GetClusterStatus(ctx context.Context) (*clusterv1.ClusterStatusResponse, error) { |
||||
return c.client.GetClusterStatus(ctx, &commonv1.Empty{}) |
||||
} |
||||
|
||||
// GetMemberStatus returns status for a specific member.
|
||||
func (c *Client) GetMemberStatus(ctx context.Context, httpURL string) (*clusterv1.MemberStatusResponse, error) { |
||||
return c.client.GetMemberStatus(ctx, &clusterv1.MemberStatusRequest{ |
||||
HttpUrl: httpURL, |
||||
}) |
||||
} |
||||
|
||||
// GetLatestSerial returns the latest serial from this relay's database.
|
||||
func (c *Client) GetLatestSerial(ctx context.Context) (uint64, int64, error) { |
||||
resp, err := c.client.GetLatestSerial(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return 0, 0, err |
||||
} |
||||
return resp.Serial, resp.Timestamp, nil |
||||
} |
||||
|
||||
// GetEventsInRange returns event info for a serial range.
|
||||
func (c *Client) GetEventsInRange(ctx context.Context, from, to uint64, limit int32) ([]*clusterv1.EventInfo, bool, uint64, error) { |
||||
resp, err := c.client.GetEventsInRange(ctx, &clusterv1.EventsRangeRequest{ |
||||
From: from, |
||||
To: to, |
||||
Limit: limit, |
||||
}) |
||||
if err != nil { |
||||
return nil, false, 0, err |
||||
} |
||||
return resp.Events, resp.HasMore, resp.NextFrom, nil |
||||
} |
||||
@ -0,0 +1,209 @@
@@ -0,0 +1,209 @@
|
||||
// Package server provides the gRPC server implementation for cluster sync.
|
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"net/http" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
"next.orly.dev/pkg/sync/cluster" |
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
clusterv1 "next.orly.dev/pkg/proto/orlysync/cluster/v1" |
||||
) |
||||
|
||||
// Service implements the ClusterSyncServiceServer interface.
|
||||
type Service struct { |
||||
clusterv1.UnimplementedClusterSyncServiceServer |
||||
mgr *cluster.Manager |
||||
db database.Database |
||||
ready bool |
||||
} |
||||
|
||||
// NewService creates a new cluster sync gRPC service.
|
||||
func NewService(db database.Database, mgr *cluster.Manager) *Service { |
||||
return &Service{ |
||||
mgr: mgr, |
||||
db: db, |
||||
ready: true, |
||||
} |
||||
} |
||||
|
||||
// Ready returns whether the service is ready to serve requests.
|
||||
func (s *Service) Ready(ctx context.Context, _ *commonv1.Empty) (*commonv1.ReadyResponse, error) { |
||||
return &commonv1.ReadyResponse{Ready: s.ready}, nil |
||||
} |
||||
|
||||
// Start starts the cluster polling loop.
|
||||
func (s *Service) Start(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
s.mgr.Start() |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// Stop stops the cluster polling loop.
|
||||
func (s *Service) Stop(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
s.mgr.Stop() |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// HandleLatestSerial proxies GET /cluster/latest HTTP requests.
|
||||
func (s *Service) HandleLatestSerial(ctx context.Context, req *commonv1.HTTPRequest) (*commonv1.HTTPResponse, error) { |
||||
if req.Method != http.MethodGet { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusMethodNotAllowed, |
||||
Body: []byte("Method not allowed"), |
||||
}, nil |
||||
} |
||||
|
||||
serial, timestamp := s.mgr.GetLatestSerial() |
||||
resp := map[string]any{ |
||||
"serial": serial, |
||||
"timestamp": timestamp, |
||||
} |
||||
|
||||
respBody, err := json.Marshal(resp) |
||||
if err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusInternalServerError, |
||||
Body: []byte("Failed to marshal response"), |
||||
}, nil |
||||
} |
||||
|
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusOK, |
||||
Headers: map[string]string{"Content-Type": "application/json"}, |
||||
Body: respBody, |
||||
}, nil |
||||
} |
||||
|
||||
// HandleEventsRange proxies GET /cluster/events HTTP requests.
|
||||
func (s *Service) HandleEventsRange(ctx context.Context, req *commonv1.HTTPRequest) (*commonv1.HTTPResponse, error) { |
||||
if req.Method != http.MethodGet { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusMethodNotAllowed, |
||||
Body: []byte("Method not allowed"), |
||||
}, nil |
||||
} |
||||
|
||||
// Parse query parameters
|
||||
// In practice, the query string would be parsed from req.QueryString
|
||||
// For now, return a placeholder
|
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusOK, |
||||
Headers: map[string]string{"Content-Type": "application/json"}, |
||||
Body: []byte(`{"events":[],"has_more":false}`), |
||||
}, nil |
||||
} |
||||
|
||||
// GetMembers returns the current cluster members.
|
||||
func (s *Service) GetMembers(ctx context.Context, _ *commonv1.Empty) (*clusterv1.MembersResponse, error) { |
||||
members := s.mgr.GetMembers() |
||||
clusterMembers := make([]*clusterv1.ClusterMember, 0, len(members)) |
||||
for _, m := range members { |
||||
clusterMembers = append(clusterMembers, &clusterv1.ClusterMember{ |
||||
HttpUrl: m.HTTPURL, |
||||
WebsocketUrl: m.WebSocketURL, |
||||
LastSerial: m.LastSerial, |
||||
LastPoll: m.LastPoll.Unix(), |
||||
Status: m.Status, |
||||
ErrorCount: int32(m.ErrorCount), |
||||
}) |
||||
} |
||||
return &clusterv1.MembersResponse{ |
||||
Members: clusterMembers, |
||||
}, nil |
||||
} |
||||
|
||||
// UpdateMembership updates cluster membership.
|
||||
func (s *Service) UpdateMembership(ctx context.Context, req *clusterv1.UpdateMembershipRequest) (*commonv1.Empty, error) { |
||||
s.mgr.UpdateMembership(req.RelayUrls) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// HandleMembershipEvent processes a cluster membership event (Kind 39108).
|
||||
func (s *Service) HandleMembershipEvent(ctx context.Context, req *clusterv1.MembershipEventRequest) (*commonv1.Empty, error) { |
||||
// Convert proto event to internal format and process
|
||||
// This would need the actual event conversion
|
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// GetClusterStatus returns overall cluster status.
|
||||
func (s *Service) GetClusterStatus(ctx context.Context, _ *commonv1.Empty) (*clusterv1.ClusterStatusResponse, error) { |
||||
members := s.mgr.GetMembers() |
||||
serial, _ := s.mgr.GetLatestSerial() |
||||
|
||||
activeCount := int32(0) |
||||
clusterMembers := make([]*clusterv1.ClusterMember, 0, len(members)) |
||||
for _, m := range members { |
||||
if m.Status == "active" { |
||||
activeCount++ |
||||
} |
||||
clusterMembers = append(clusterMembers, &clusterv1.ClusterMember{ |
||||
HttpUrl: m.HTTPURL, |
||||
WebsocketUrl: m.WebSocketURL, |
||||
LastSerial: m.LastSerial, |
||||
LastPoll: m.LastPoll.Unix(), |
||||
Status: m.Status, |
||||
ErrorCount: int32(m.ErrorCount), |
||||
}) |
||||
} |
||||
|
||||
return &clusterv1.ClusterStatusResponse{ |
||||
LatestSerial: serial, |
||||
ActiveMembers: activeCount, |
||||
TotalMembers: int32(len(members)), |
||||
PropagatePrivilegedEvents: s.mgr.PropagatePrivilegedEvents(), |
||||
Members: clusterMembers, |
||||
}, nil |
||||
} |
||||
|
||||
// GetMemberStatus returns status for a specific member.
|
||||
func (s *Service) GetMemberStatus(ctx context.Context, req *clusterv1.MemberStatusRequest) (*clusterv1.MemberStatusResponse, error) { |
||||
member := s.mgr.GetMember(req.HttpUrl) |
||||
if member == nil { |
||||
return &clusterv1.MemberStatusResponse{ |
||||
Found: false, |
||||
}, nil |
||||
} |
||||
|
||||
return &clusterv1.MemberStatusResponse{ |
||||
Found: true, |
||||
Member: &clusterv1.ClusterMember{ |
||||
HttpUrl: member.HTTPURL, |
||||
WebsocketUrl: member.WebSocketURL, |
||||
LastSerial: member.LastSerial, |
||||
LastPoll: member.LastPoll.Unix(), |
||||
Status: member.Status, |
||||
ErrorCount: int32(member.ErrorCount), |
||||
}, |
||||
}, nil |
||||
} |
||||
|
||||
// GetLatestSerial returns the latest serial from this relay's database.
|
||||
func (s *Service) GetLatestSerial(ctx context.Context, _ *commonv1.Empty) (*clusterv1.LatestSerialResponse, error) { |
||||
serial, timestamp := s.mgr.GetLatestSerial() |
||||
return &clusterv1.LatestSerialResponse{ |
||||
Serial: serial, |
||||
Timestamp: timestamp, |
||||
}, nil |
||||
} |
||||
|
||||
// GetEventsInRange returns event info for a serial range.
|
||||
func (s *Service) GetEventsInRange(ctx context.Context, req *clusterv1.EventsRangeRequest) (*clusterv1.EventsRangeResponse, error) { |
||||
events, hasMore, nextFrom := s.mgr.GetEventsInRange(req.From, req.To, int(req.Limit)) |
||||
|
||||
eventInfos := make([]*clusterv1.EventInfo, 0, len(events)) |
||||
for _, e := range events { |
||||
eventInfos = append(eventInfos, &clusterv1.EventInfo{ |
||||
Serial: e.Serial, |
||||
Id: e.ID, |
||||
Timestamp: e.Timestamp, // Already int64
|
||||
}) |
||||
} |
||||
|
||||
return &clusterv1.EventsRangeResponse{ |
||||
Events: eventInfos, |
||||
HasMore: hasMore, |
||||
NextFrom: nextFrom, |
||||
}, nil |
||||
} |
||||
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
// Package sync provides NIP-11 relay information document fetching and caching
|
||||
package sync |
||||
// Package common provides shared utilities for sync services
|
||||
package common |
||||
|
||||
import ( |
||||
"context" |
||||
@ -0,0 +1,219 @@
@@ -0,0 +1,219 @@
|
||||
// Package grpc provides a gRPC client for the distributed sync service.
|
||||
package grpc |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/credentials/insecure" |
||||
"lol.mleku.dev/log" |
||||
|
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
distributedv1 "next.orly.dev/pkg/proto/orlysync/distributed/v1" |
||||
) |
||||
|
||||
// Client is a gRPC client for the distributed sync service.
|
||||
type Client struct { |
||||
conn *grpc.ClientConn |
||||
client distributedv1.DistributedSyncServiceClient |
||||
ready chan struct{} |
||||
} |
||||
|
||||
// ClientConfig holds configuration for the gRPC client.
|
||||
type ClientConfig struct { |
||||
ServerAddress string |
||||
ConnectTimeout time.Duration |
||||
} |
||||
|
||||
// New creates a new gRPC distributed sync client.
|
||||
func New(ctx context.Context, cfg *ClientConfig) (*Client, error) { |
||||
timeout := cfg.ConnectTimeout |
||||
if timeout == 0 { |
||||
timeout = 10 * time.Second |
||||
} |
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, timeout) |
||||
defer cancel() |
||||
|
||||
conn, err := grpc.DialContext(dialCtx, cfg.ServerAddress, |
||||
grpc.WithTransportCredentials(insecure.NewCredentials()), |
||||
grpc.WithDefaultCallOptions( |
||||
grpc.MaxCallRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxCallSendMsgSize(16<<20), // 16MB
|
||||
), |
||||
) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
c := &Client{ |
||||
conn: conn, |
||||
client: distributedv1.NewDistributedSyncServiceClient(conn), |
||||
ready: make(chan struct{}), |
||||
} |
||||
|
||||
go c.waitForReady(ctx) |
||||
|
||||
return c, nil |
||||
} |
||||
|
||||
func (c *Client) waitForReady(ctx context.Context) { |
||||
for { |
||||
select { |
||||
case <-ctx.Done(): |
||||
return |
||||
default: |
||||
resp, err := c.client.Ready(ctx, &commonv1.Empty{}) |
||||
if err == nil && resp.Ready { |
||||
close(c.ready) |
||||
log.I.F("gRPC distributed sync client connected and ready") |
||||
return |
||||
} |
||||
time.Sleep(100 * time.Millisecond) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Close closes the gRPC connection.
|
||||
func (c *Client) Close() error { |
||||
if c.conn != nil { |
||||
return c.conn.Close() |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Ready returns a channel that closes when the client is ready.
|
||||
func (c *Client) Ready() <-chan struct{} { |
||||
return c.ready |
||||
} |
||||
|
||||
// GetInfo returns current sync service information.
|
||||
func (c *Client) GetInfo(ctx context.Context) (*commonv1.SyncInfo, error) { |
||||
return c.client.GetInfo(ctx, &commonv1.Empty{}) |
||||
} |
||||
|
||||
// GetCurrentSerial returns the current serial number.
|
||||
func (c *Client) GetCurrentSerial(ctx context.Context) (uint64, error) { |
||||
resp, err := c.client.GetCurrentSerial(ctx, &distributedv1.CurrentRequest{}) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
return resp.Serial, nil |
||||
} |
||||
|
||||
// GetEventIDs returns event IDs for a serial range.
|
||||
func (c *Client) GetEventIDs(ctx context.Context, from, to uint64) (map[string]uint64, error) { |
||||
resp, err := c.client.GetEventIDs(ctx, &distributedv1.EventIDsRequest{ |
||||
From: from, |
||||
To: to, |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.EventMap, nil |
||||
} |
||||
|
||||
// HandleCurrentRequest proxies an HTTP current request.
|
||||
func (c *Client) HandleCurrentRequest(ctx context.Context, method string, body []byte, headers map[string]string) (int, []byte, map[string]string, error) { |
||||
resp, err := c.client.HandleCurrentRequest(ctx, &commonv1.HTTPRequest{ |
||||
Method: method, |
||||
Body: body, |
||||
Headers: headers, |
||||
}) |
||||
if err != nil { |
||||
return 0, nil, nil, err |
||||
} |
||||
return int(resp.StatusCode), resp.Body, resp.Headers, nil |
||||
} |
||||
|
||||
// HandleEventIDsRequest proxies an HTTP event-ids request.
|
||||
func (c *Client) HandleEventIDsRequest(ctx context.Context, method string, body []byte, headers map[string]string) (int, []byte, map[string]string, error) { |
||||
resp, err := c.client.HandleEventIDsRequest(ctx, &commonv1.HTTPRequest{ |
||||
Method: method, |
||||
Body: body, |
||||
Headers: headers, |
||||
}) |
||||
if err != nil { |
||||
return 0, nil, nil, err |
||||
} |
||||
return int(resp.StatusCode), resp.Body, resp.Headers, nil |
||||
} |
||||
|
||||
// GetPeers returns the current list of sync peers.
|
||||
func (c *Client) GetPeers(ctx context.Context) ([]string, error) { |
||||
resp, err := c.client.GetPeers(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Peers, nil |
||||
} |
||||
|
||||
// UpdatePeers updates the peer list.
|
||||
func (c *Client) UpdatePeers(ctx context.Context, peers []string) error { |
||||
_, err := c.client.UpdatePeers(ctx, &distributedv1.UpdatePeersRequest{ |
||||
Peers: peers, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// IsAuthorizedPeer checks if a peer is authorized.
|
||||
func (c *Client) IsAuthorizedPeer(ctx context.Context, peerURL, expectedPubkey string) (bool, error) { |
||||
resp, err := c.client.IsAuthorizedPeer(ctx, &distributedv1.AuthorizedPeerRequest{ |
||||
PeerUrl: peerURL, |
||||
ExpectedPubkey: expectedPubkey, |
||||
}) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
return resp.Authorized, nil |
||||
} |
||||
|
||||
// GetPeerPubkey fetches the pubkey for a peer relay.
|
||||
func (c *Client) GetPeerPubkey(ctx context.Context, peerURL string) (string, error) { |
||||
resp, err := c.client.GetPeerPubkey(ctx, &distributedv1.PeerPubkeyRequest{ |
||||
PeerUrl: peerURL, |
||||
}) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
if resp.Pubkey == "" { |
||||
return "", errors.New("peer pubkey not found") |
||||
} |
||||
return resp.Pubkey, nil |
||||
} |
||||
|
||||
// UpdateSerial updates the current serial from database.
|
||||
func (c *Client) UpdateSerial(ctx context.Context) error { |
||||
_, err := c.client.UpdateSerial(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// NotifyNewEvent notifies the service of a new event.
|
||||
func (c *Client) NotifyNewEvent(ctx context.Context, eventID []byte, serial uint64) error { |
||||
_, err := c.client.NotifyNewEvent(ctx, &distributedv1.NewEventNotification{ |
||||
EventId: eventID, |
||||
Serial: serial, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// TriggerSync manually triggers a sync cycle.
|
||||
func (c *Client) TriggerSync(ctx context.Context) error { |
||||
_, err := c.client.TriggerSync(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// GetSyncStatus returns current sync status.
|
||||
func (c *Client) GetSyncStatus(ctx context.Context) (uint64, map[string]uint64, error) { |
||||
resp, err := c.client.GetSyncStatus(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return 0, nil, err |
||||
} |
||||
peerSerials := make(map[string]uint64) |
||||
for _, p := range resp.Peers { |
||||
peerSerials[p.Url] = p.LastSerial |
||||
} |
||||
return resp.CurrentSerial, peerSerials, nil |
||||
} |
||||
@ -0,0 +1,268 @@
@@ -0,0 +1,268 @@
|
||||
// Package server provides the gRPC server implementation for distributed sync.
|
||||
package server |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"encoding/json" |
||||
"net/http" |
||||
|
||||
"lol.mleku.dev/log" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
"next.orly.dev/pkg/sync/distributed" |
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
distributedv1 "next.orly.dev/pkg/proto/orlysync/distributed/v1" |
||||
) |
||||
|
||||
// Service implements the DistributedSyncServiceServer interface.
|
||||
type Service struct { |
||||
distributedv1.UnimplementedDistributedSyncServiceServer |
||||
mgr *distributed.Manager |
||||
db database.Database |
||||
ready bool |
||||
} |
||||
|
||||
// NewService creates a new distributed sync gRPC service.
|
||||
func NewService(db database.Database, mgr *distributed.Manager) *Service { |
||||
return &Service{ |
||||
mgr: mgr, |
||||
db: db, |
||||
ready: true, |
||||
} |
||||
} |
||||
|
||||
// Ready returns whether the service is ready to serve requests.
|
||||
func (s *Service) Ready(ctx context.Context, _ *commonv1.Empty) (*commonv1.ReadyResponse, error) { |
||||
return &commonv1.ReadyResponse{Ready: s.ready}, nil |
||||
} |
||||
|
||||
// GetInfo returns current sync service information.
|
||||
func (s *Service) GetInfo(ctx context.Context, _ *commonv1.Empty) (*commonv1.SyncInfo, error) { |
||||
peers := s.mgr.GetPeers() |
||||
return &commonv1.SyncInfo{ |
||||
NodeId: s.mgr.GetNodeID(), |
||||
RelayUrl: s.mgr.GetRelayURL(), |
||||
CurrentSerial: s.mgr.GetCurrentSerial(), |
||||
PeerCount: int32(len(peers)), |
||||
Status: "running", |
||||
}, nil |
||||
} |
||||
|
||||
// GetCurrentSerial returns this relay's current serial number.
|
||||
func (s *Service) GetCurrentSerial(ctx context.Context, req *distributedv1.CurrentRequest) (*distributedv1.CurrentResponse, error) { |
||||
return &distributedv1.CurrentResponse{ |
||||
NodeId: s.mgr.GetNodeID(), |
||||
RelayUrl: s.mgr.GetRelayURL(), |
||||
Serial: s.mgr.GetCurrentSerial(), |
||||
}, nil |
||||
} |
||||
|
||||
// GetEventIDs returns event IDs for a serial range.
|
||||
func (s *Service) GetEventIDs(ctx context.Context, req *distributedv1.EventIDsRequest) (*distributedv1.EventIDsResponse, error) { |
||||
eventMap, err := s.mgr.GetEventsWithIDs(req.From, req.To) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &distributedv1.EventIDsResponse{ |
||||
EventMap: eventMap, |
||||
}, nil |
||||
} |
||||
|
||||
// HandleCurrentRequest proxies /api/sync/current HTTP requests.
|
||||
func (s *Service) HandleCurrentRequest(ctx context.Context, req *commonv1.HTTPRequest) (*commonv1.HTTPResponse, error) { |
||||
if req.Method != http.MethodPost { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusMethodNotAllowed, |
||||
Body: []byte("Method not allowed"), |
||||
}, nil |
||||
} |
||||
|
||||
var currentReq distributed.CurrentRequest |
||||
if err := json.Unmarshal(req.Body, ¤tReq); err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusBadRequest, |
||||
Body: []byte("Invalid JSON"), |
||||
}, nil |
||||
} |
||||
|
||||
// Check if request is from ourselves
|
||||
if s.mgr.IsSelfNodeID(currentReq.NodeID) { |
||||
if currentReq.RelayURL != "" { |
||||
s.mgr.MarkSelfURL(currentReq.RelayURL) |
||||
} |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusBadRequest, |
||||
Body: []byte("Cannot sync with self"), |
||||
}, nil |
||||
} |
||||
|
||||
resp := distributed.CurrentResponse{ |
||||
NodeID: s.mgr.GetNodeID(), |
||||
RelayURL: s.mgr.GetRelayURL(), |
||||
Serial: s.mgr.GetCurrentSerial(), |
||||
} |
||||
|
||||
respBody, err := json.Marshal(resp) |
||||
if err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusInternalServerError, |
||||
Body: []byte("Failed to marshal response"), |
||||
}, nil |
||||
} |
||||
|
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusOK, |
||||
Headers: map[string]string{"Content-Type": "application/json"}, |
||||
Body: respBody, |
||||
}, nil |
||||
} |
||||
|
||||
// HandleEventIDsRequest proxies /api/sync/event-ids HTTP requests.
|
||||
func (s *Service) HandleEventIDsRequest(ctx context.Context, req *commonv1.HTTPRequest) (*commonv1.HTTPResponse, error) { |
||||
if req.Method != http.MethodPost { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusMethodNotAllowed, |
||||
Body: []byte("Method not allowed"), |
||||
}, nil |
||||
} |
||||
|
||||
var eventIDsReq distributed.EventIDsRequest |
||||
if err := json.Unmarshal(req.Body, &eventIDsReq); err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusBadRequest, |
||||
Body: []byte("Invalid JSON"), |
||||
}, nil |
||||
} |
||||
|
||||
// Check if request is from ourselves
|
||||
if s.mgr.IsSelfNodeID(eventIDsReq.NodeID) { |
||||
if eventIDsReq.RelayURL != "" { |
||||
s.mgr.MarkSelfURL(eventIDsReq.RelayURL) |
||||
} |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusBadRequest, |
||||
Body: []byte("Cannot sync with self"), |
||||
}, nil |
||||
} |
||||
|
||||
eventMap, err := s.mgr.GetEventsWithIDs(eventIDsReq.From, eventIDsReq.To) |
||||
if err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusInternalServerError, |
||||
Body: []byte("Failed to get event IDs: " + err.Error()), |
||||
}, nil |
||||
} |
||||
|
||||
resp := distributed.EventIDsResponse{ |
||||
EventMap: eventMap, |
||||
} |
||||
|
||||
respBody, err := json.Marshal(resp) |
||||
if err != nil { |
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusInternalServerError, |
||||
Body: []byte("Failed to marshal response"), |
||||
}, nil |
||||
} |
||||
|
||||
return &commonv1.HTTPResponse{ |
||||
StatusCode: http.StatusOK, |
||||
Headers: map[string]string{"Content-Type": "application/json"}, |
||||
Body: respBody, |
||||
}, nil |
||||
} |
||||
|
||||
// GetPeers returns the current list of sync peers.
|
||||
func (s *Service) GetPeers(ctx context.Context, _ *commonv1.Empty) (*distributedv1.PeersResponse, error) { |
||||
peers := s.mgr.GetPeers() |
||||
return &distributedv1.PeersResponse{ |
||||
Peers: peers, |
||||
}, nil |
||||
} |
||||
|
||||
// UpdatePeers updates the peer list.
|
||||
func (s *Service) UpdatePeers(ctx context.Context, req *distributedv1.UpdatePeersRequest) (*commonv1.Empty, error) { |
||||
s.mgr.UpdatePeers(req.Peers) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// IsAuthorizedPeer checks if a peer is authorized by validating its NIP-11 pubkey.
|
||||
func (s *Service) IsAuthorizedPeer(ctx context.Context, req *distributedv1.AuthorizedPeerRequest) (*distributedv1.AuthorizedPeerResponse, error) { |
||||
authorized := s.mgr.IsAuthorizedPeer(req.PeerUrl, req.ExpectedPubkey) |
||||
return &distributedv1.AuthorizedPeerResponse{ |
||||
Authorized: authorized, |
||||
}, nil |
||||
} |
||||
|
||||
// GetPeerPubkey fetches the pubkey for a peer relay via NIP-11.
|
||||
func (s *Service) GetPeerPubkey(ctx context.Context, req *distributedv1.PeerPubkeyRequest) (*distributedv1.PeerPubkeyResponse, error) { |
||||
pubkey, err := s.mgr.GetPeerPubkey(req.PeerUrl) |
||||
if err != nil { |
||||
// Return empty pubkey on error since the proto doesn't have an error field
|
||||
return &distributedv1.PeerPubkeyResponse{ |
||||
Pubkey: "", |
||||
}, nil |
||||
} |
||||
return &distributedv1.PeerPubkeyResponse{ |
||||
Pubkey: pubkey, |
||||
}, nil |
||||
} |
||||
|
||||
// UpdateSerial updates the current serial from database.
|
||||
func (s *Service) UpdateSerial(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
s.mgr.UpdateSerial() |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// NotifyNewEvent notifies the service of a new event being stored.
|
||||
func (s *Service) NotifyNewEvent(ctx context.Context, req *distributedv1.NewEventNotification) (*commonv1.Empty, error) { |
||||
s.mgr.NotifyNewEvent(req.EventId, req.Serial) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// TriggerSync manually triggers a sync cycle with all peers.
|
||||
func (s *Service) TriggerSync(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
log.I.F("manual sync trigger requested") |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// GetSyncStatus returns current sync status for all peers.
|
||||
func (s *Service) GetSyncStatus(ctx context.Context, _ *commonv1.Empty) (*distributedv1.SyncStatusResponse, error) { |
||||
peerStatus := s.mgr.GetPeerStatus() |
||||
peerInfos := make([]*commonv1.PeerInfo, 0, len(peerStatus)) |
||||
for url, serial := range peerStatus { |
||||
peerInfos = append(peerInfos, &commonv1.PeerInfo{ |
||||
Url: url, |
||||
LastSerial: serial, |
||||
Status: "active", |
||||
}) |
||||
} |
||||
return &distributedv1.SyncStatusResponse{ |
||||
CurrentSerial: s.mgr.GetCurrentSerial(), |
||||
Peers: peerInfos, |
||||
}, nil |
||||
} |
||||
|
||||
// httpResponseWriter is a simple buffer for capturing HTTP responses.
|
||||
type httpResponseWriter struct { |
||||
statusCode int |
||||
headers http.Header |
||||
body bytes.Buffer |
||||
} |
||||
|
||||
func (w *httpResponseWriter) Header() http.Header { |
||||
if w.headers == nil { |
||||
w.headers = make(http.Header) |
||||
} |
||||
return w.headers |
||||
} |
||||
|
||||
func (w *httpResponseWriter) Write(b []byte) (int, error) { |
||||
return w.body.Write(b) |
||||
} |
||||
|
||||
func (w *httpResponseWriter) WriteHeader(statusCode int) { |
||||
w.statusCode = statusCode |
||||
} |
||||
@ -0,0 +1,331 @@
@@ -0,0 +1,331 @@
|
||||
// Package grpc provides a gRPC client for the negentropy sync service.
|
||||
package grpc |
||||
|
||||
import ( |
||||
"context" |
||||
"io" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/credentials/insecure" |
||||
"lol.mleku.dev/log" |
||||
|
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
negentropyv1 "next.orly.dev/pkg/proto/orlysync/negentropy/v1" |
||||
) |
||||
|
||||
// Client is a gRPC client for the negentropy sync service.
|
||||
type Client struct { |
||||
conn *grpc.ClientConn |
||||
client negentropyv1.NegentropyServiceClient |
||||
ready chan struct{} |
||||
} |
||||
|
||||
// ClientConfig holds configuration for the gRPC client.
|
||||
type ClientConfig struct { |
||||
ServerAddress string |
||||
ConnectTimeout time.Duration |
||||
} |
||||
|
||||
// New creates a new gRPC negentropy sync client.
|
||||
func New(ctx context.Context, cfg *ClientConfig) (*Client, error) { |
||||
timeout := cfg.ConnectTimeout |
||||
if timeout == 0 { |
||||
timeout = 10 * time.Second |
||||
} |
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, timeout) |
||||
defer cancel() |
||||
|
||||
conn, err := grpc.DialContext(dialCtx, cfg.ServerAddress, |
||||
grpc.WithTransportCredentials(insecure.NewCredentials()), |
||||
grpc.WithDefaultCallOptions( |
||||
grpc.MaxCallRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxCallSendMsgSize(16<<20), // 16MB
|
||||
), |
||||
) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
c := &Client{ |
||||
conn: conn, |
||||
client: negentropyv1.NewNegentropyServiceClient(conn), |
||||
ready: make(chan struct{}), |
||||
} |
||||
|
||||
go c.waitForReady(ctx) |
||||
|
||||
return c, nil |
||||
} |
||||
|
||||
func (c *Client) waitForReady(ctx context.Context) { |
||||
for { |
||||
select { |
||||
case <-ctx.Done(): |
||||
return |
||||
default: |
||||
resp, err := c.client.Ready(ctx, &commonv1.Empty{}) |
||||
if err == nil && resp.Ready { |
||||
close(c.ready) |
||||
log.I.F("gRPC negentropy sync client connected and ready") |
||||
return |
||||
} |
||||
time.Sleep(100 * time.Millisecond) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Close closes the gRPC connection.
|
||||
func (c *Client) Close() error { |
||||
if c.conn != nil { |
||||
return c.conn.Close() |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Ready returns a channel that closes when the client is ready.
|
||||
func (c *Client) Ready() <-chan struct{} { |
||||
return c.ready |
||||
} |
||||
|
||||
// Start starts the background relay-to-relay sync.
|
||||
func (c *Client) Start(ctx context.Context) error { |
||||
_, err := c.client.Start(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// Stop stops the background sync.
|
||||
func (c *Client) Stop(ctx context.Context) error { |
||||
_, err := c.client.Stop(ctx, &commonv1.Empty{}) |
||||
return err |
||||
} |
||||
|
||||
// HandleNegOpen processes a NEG-OPEN message from a client.
|
||||
func (c *Client) HandleNegOpen(ctx context.Context, connectionID, subscriptionID string, filter *commonv1.Filter, initialMessage []byte) ([]byte, string, error) { |
||||
resp, err := c.client.HandleNegOpen(ctx, &negentropyv1.NegOpenRequest{ |
||||
ConnectionId: connectionID, |
||||
SubscriptionId: subscriptionID, |
||||
Filter: filter, |
||||
InitialMessage: initialMessage, |
||||
}) |
||||
if err != nil { |
||||
return nil, "", err |
||||
} |
||||
return resp.Message, resp.Error, nil |
||||
} |
||||
|
||||
// HandleNegMsg processes a NEG-MSG message from a client.
|
||||
func (c *Client) HandleNegMsg(ctx context.Context, connectionID, subscriptionID string, message []byte) ([]byte, [][]byte, [][]byte, bool, string, error) { |
||||
resp, err := c.client.HandleNegMsg(ctx, &negentropyv1.NegMsgRequest{ |
||||
ConnectionId: connectionID, |
||||
SubscriptionId: subscriptionID, |
||||
Message: message, |
||||
}) |
||||
if err != nil { |
||||
return nil, nil, nil, false, "", err |
||||
} |
||||
return resp.Message, resp.HaveIds, resp.NeedIds, resp.Complete, resp.Error, nil |
||||
} |
||||
|
||||
// HandleNegClose processes a NEG-CLOSE message from a client.
|
||||
func (c *Client) HandleNegClose(ctx context.Context, connectionID, subscriptionID string) error { |
||||
_, err := c.client.HandleNegClose(ctx, &negentropyv1.NegCloseRequest{ |
||||
ConnectionId: connectionID, |
||||
SubscriptionId: subscriptionID, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// SyncProgress represents progress during a peer sync operation.
|
||||
type SyncProgress struct { |
||||
PeerURL string |
||||
Round int32 |
||||
HaveCount int64 |
||||
NeedCount int64 |
||||
FetchedCount int64 |
||||
SentCount int64 |
||||
Complete bool |
||||
Error string |
||||
} |
||||
|
||||
// SyncWithPeer initiates negentropy sync with a specific peer relay.
|
||||
// Returns a channel that receives progress updates.
|
||||
func (c *Client) SyncWithPeer(ctx context.Context, peerURL string, filter *commonv1.Filter, since int64) (<-chan *SyncProgress, error) { |
||||
stream, err := c.client.SyncWithPeer(ctx, &negentropyv1.SyncPeerRequest{ |
||||
PeerUrl: peerURL, |
||||
Filter: filter, |
||||
Since: since, |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
ch := make(chan *SyncProgress, 10) |
||||
go func() { |
||||
defer close(ch) |
||||
for { |
||||
progress, err := stream.Recv() |
||||
if err == io.EOF { |
||||
return |
||||
} |
||||
if err != nil { |
||||
ch <- &SyncProgress{ |
||||
PeerURL: peerURL, |
||||
Error: err.Error(), |
||||
} |
||||
return |
||||
} |
||||
ch <- &SyncProgress{ |
||||
PeerURL: progress.PeerUrl, |
||||
Round: progress.Round, |
||||
HaveCount: progress.HaveCount, |
||||
NeedCount: progress.NeedCount, |
||||
FetchedCount: progress.FetchedCount, |
||||
SentCount: progress.SentCount, |
||||
Complete: progress.Complete, |
||||
Error: progress.Error, |
||||
} |
||||
} |
||||
}() |
||||
|
||||
return ch, nil |
||||
} |
||||
|
||||
// SyncStatus represents the sync status response.
|
||||
type SyncStatus struct { |
||||
Active bool |
||||
LastSync int64 |
||||
PeerCount int32 |
||||
PeerStates []*PeerSyncState |
||||
} |
||||
|
||||
// PeerSyncState represents sync state for a peer.
|
||||
type PeerSyncState struct { |
||||
PeerURL string |
||||
LastSync int64 |
||||
EventsSynced int64 |
||||
Status string |
||||
LastError string |
||||
ConsecutiveFailures int32 |
||||
} |
||||
|
||||
// GetSyncStatus returns the current sync status.
|
||||
func (c *Client) GetSyncStatus(ctx context.Context) (*SyncStatus, error) { |
||||
resp, err := c.client.GetSyncStatus(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
states := make([]*PeerSyncState, 0, len(resp.PeerStates)) |
||||
for _, ps := range resp.PeerStates { |
||||
states = append(states, &PeerSyncState{ |
||||
PeerURL: ps.PeerUrl, |
||||
LastSync: ps.LastSync, |
||||
EventsSynced: ps.EventsSynced, |
||||
Status: ps.Status, |
||||
LastError: ps.LastError, |
||||
ConsecutiveFailures: ps.ConsecutiveFailures, |
||||
}) |
||||
} |
||||
|
||||
return &SyncStatus{ |
||||
Active: resp.Active, |
||||
LastSync: resp.LastSync, |
||||
PeerCount: resp.PeerCount, |
||||
PeerStates: states, |
||||
}, nil |
||||
} |
||||
|
||||
// GetPeers returns the list of negentropy sync peers.
|
||||
func (c *Client) GetPeers(ctx context.Context) ([]string, error) { |
||||
resp, err := c.client.GetPeers(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Peers, nil |
||||
} |
||||
|
||||
// AddPeer adds a peer for negentropy sync.
|
||||
func (c *Client) AddPeer(ctx context.Context, peerURL string) error { |
||||
_, err := c.client.AddPeer(ctx, &negentropyv1.AddPeerRequest{ |
||||
PeerUrl: peerURL, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// RemovePeer removes a peer from negentropy sync.
|
||||
func (c *Client) RemovePeer(ctx context.Context, peerURL string) error { |
||||
_, err := c.client.RemovePeer(ctx, &negentropyv1.RemovePeerRequest{ |
||||
PeerUrl: peerURL, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// TriggerSync manually triggers sync with a specific peer or all peers.
|
||||
func (c *Client) TriggerSync(ctx context.Context, peerURL string, filter *commonv1.Filter) error { |
||||
_, err := c.client.TriggerSync(ctx, &negentropyv1.TriggerSyncRequest{ |
||||
PeerUrl: peerURL, |
||||
Filter: filter, |
||||
}) |
||||
return err |
||||
} |
||||
|
||||
// GetPeerSyncState returns sync state for a specific peer.
|
||||
func (c *Client) GetPeerSyncState(ctx context.Context, peerURL string) (*PeerSyncState, bool, error) { |
||||
resp, err := c.client.GetPeerSyncState(ctx, &negentropyv1.PeerSyncStateRequest{ |
||||
PeerUrl: peerURL, |
||||
}) |
||||
if err != nil { |
||||
return nil, false, err |
||||
} |
||||
if !resp.Found { |
||||
return nil, false, nil |
||||
} |
||||
return &PeerSyncState{ |
||||
PeerURL: resp.State.PeerUrl, |
||||
LastSync: resp.State.LastSync, |
||||
EventsSynced: resp.State.EventsSynced, |
||||
Status: resp.State.Status, |
||||
LastError: resp.State.LastError, |
||||
ConsecutiveFailures: resp.State.ConsecutiveFailures, |
||||
}, true, nil |
||||
} |
||||
|
||||
// ClientSession represents an active client negentropy session.
|
||||
type ClientSession struct { |
||||
SubscriptionID string |
||||
ConnectionID string |
||||
CreatedAt int64 |
||||
LastActivity int64 |
||||
RoundCount int32 |
||||
} |
||||
|
||||
// ListSessions returns active client negentropy sessions.
|
||||
func (c *Client) ListSessions(ctx context.Context) ([]*ClientSession, error) { |
||||
resp, err := c.client.ListSessions(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
sessions := make([]*ClientSession, 0, len(resp.Sessions)) |
||||
for _, s := range resp.Sessions { |
||||
sessions = append(sessions, &ClientSession{ |
||||
SubscriptionID: s.SubscriptionId, |
||||
ConnectionID: s.ConnectionId, |
||||
CreatedAt: s.CreatedAt, |
||||
LastActivity: s.LastActivity, |
||||
RoundCount: s.RoundCount, |
||||
}) |
||||
} |
||||
return sessions, nil |
||||
} |
||||
|
||||
// CloseSession forcefully closes a client session.
|
||||
func (c *Client) CloseSession(ctx context.Context, connectionID, subscriptionID string) error { |
||||
_, err := c.client.CloseSession(ctx, &negentropyv1.CloseSessionRequest{ |
||||
ConnectionId: connectionID, |
||||
SubscriptionId: subscriptionID, |
||||
}) |
||||
return err |
||||
} |
||||
@ -0,0 +1,778 @@
@@ -0,0 +1,778 @@
|
||||
// Package negentropy provides NIP-77 negentropy-based set reconciliation
|
||||
// for both relay-to-relay sync and client-facing WebSocket operations.
|
||||
package negentropy |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"fmt" |
||||
"net/http" |
||||
"strings" |
||||
gosync "sync" |
||||
"time" |
||||
|
||||
"github.com/gorilla/websocket" |
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"git.mleku.dev/mleku/nostr/encoders/event" |
||||
"git.mleku.dev/mleku/nostr/encoders/filter" |
||||
"git.mleku.dev/mleku/nostr/encoders/tag" |
||||
"git.mleku.dev/mleku/nostr/negentropy" |
||||
"next.orly.dev/pkg/database" |
||||
) |
||||
|
||||
// PeerState represents the sync state for a peer relay.
|
||||
type PeerState struct { |
||||
URL string |
||||
LastSync time.Time |
||||
EventsSynced int64 |
||||
Status string // "idle", "syncing", "error"
|
||||
LastError string |
||||
ConsecutiveFailures int32 |
||||
} |
||||
|
||||
// ClientSession represents an active client negentropy session.
|
||||
type ClientSession struct { |
||||
SubscriptionID string |
||||
ConnectionID string |
||||
CreatedAt time.Time |
||||
LastActivity time.Time |
||||
RoundCount int32 |
||||
neg *negentropy.Negentropy |
||||
storage *negentropy.Vector |
||||
} |
||||
|
||||
// SetNegentropy sets the negentropy instance and storage for this session.
|
||||
func (s *ClientSession) SetNegentropy(neg *negentropy.Negentropy, storage *negentropy.Vector) { |
||||
s.neg = neg |
||||
s.storage = storage |
||||
} |
||||
|
||||
// GetNegentropy returns the negentropy instance for this session.
|
||||
func (s *ClientSession) GetNegentropy() *negentropy.Negentropy { |
||||
return s.neg |
||||
} |
||||
|
||||
// Config holds configuration for the negentropy manager.
|
||||
type Config struct { |
||||
Peers []string |
||||
SyncInterval time.Duration |
||||
FrameSize int |
||||
IDSize int |
||||
ClientSessionTimeout time.Duration |
||||
} |
||||
|
||||
// Manager handles negentropy sync operations.
|
||||
type Manager struct { |
||||
db database.Database |
||||
config *Config |
||||
|
||||
mu gosync.RWMutex |
||||
peers map[string]*PeerState |
||||
sessions map[string]*ClientSession // keyed by connectionID:subscriptionID
|
||||
active bool |
||||
lastSync time.Time |
||||
stopChan chan struct{} |
||||
syncWg gosync.WaitGroup |
||||
} |
||||
|
||||
// NewManager creates a new negentropy manager.
|
||||
func NewManager(db database.Database, cfg *Config) *Manager { |
||||
if cfg == nil { |
||||
cfg = &Config{ |
||||
SyncInterval: 60 * time.Second, |
||||
FrameSize: 128 * 1024, |
||||
IDSize: 16, |
||||
ClientSessionTimeout: 5 * time.Minute, |
||||
} |
||||
} |
||||
|
||||
m := &Manager{ |
||||
db: db, |
||||
config: cfg, |
||||
peers: make(map[string]*PeerState), |
||||
sessions: make(map[string]*ClientSession), |
||||
} |
||||
|
||||
// Initialize peers from config
|
||||
for _, peerURL := range cfg.Peers { |
||||
m.peers[peerURL] = &PeerState{ |
||||
URL: peerURL, |
||||
Status: "idle", |
||||
} |
||||
} |
||||
|
||||
return m |
||||
} |
||||
|
||||
// Start starts the background sync loop.
|
||||
func (m *Manager) Start() { |
||||
m.mu.Lock() |
||||
if m.active { |
||||
m.mu.Unlock() |
||||
return |
||||
} |
||||
m.active = true |
||||
m.stopChan = make(chan struct{}) |
||||
m.mu.Unlock() |
||||
|
||||
log.I.F("negentropy manager starting background sync") |
||||
|
||||
m.syncWg.Add(1) |
||||
go m.syncLoop() |
||||
} |
||||
|
||||
// Stop stops the background sync loop.
|
||||
func (m *Manager) Stop() { |
||||
m.mu.Lock() |
||||
if !m.active { |
||||
m.mu.Unlock() |
||||
return |
||||
} |
||||
m.active = false |
||||
close(m.stopChan) |
||||
m.mu.Unlock() |
||||
|
||||
m.syncWg.Wait() |
||||
log.I.F("negentropy manager stopped") |
||||
} |
||||
|
||||
func (m *Manager) syncLoop() { |
||||
defer m.syncWg.Done() |
||||
|
||||
// Do initial sync after a short delay
|
||||
time.Sleep(5 * time.Second) |
||||
m.syncAllPeers() |
||||
|
||||
ticker := time.NewTicker(m.config.SyncInterval) |
||||
defer ticker.Stop() |
||||
|
||||
for { |
||||
select { |
||||
case <-m.stopChan: |
||||
return |
||||
case <-ticker.C: |
||||
m.syncAllPeers() |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (m *Manager) syncAllPeers() { |
||||
m.mu.RLock() |
||||
peers := make([]string, 0, len(m.peers)) |
||||
for url := range m.peers { |
||||
peers = append(peers, url) |
||||
} |
||||
m.mu.RUnlock() |
||||
|
||||
for _, peerURL := range peers { |
||||
m.syncWithPeer(context.Background(), peerURL) |
||||
} |
||||
|
||||
m.mu.Lock() |
||||
m.lastSync = time.Now() |
||||
m.mu.Unlock() |
||||
} |
||||
|
||||
func (m *Manager) syncWithPeer(ctx context.Context, peerURL string) { |
||||
m.mu.Lock() |
||||
peer, ok := m.peers[peerURL] |
||||
if !ok { |
||||
m.mu.Unlock() |
||||
return |
||||
} |
||||
peer.Status = "syncing" |
||||
m.mu.Unlock() |
||||
|
||||
log.I.F("negentropy sync starting with %s", peerURL) |
||||
|
||||
eventsSynced, err := m.performNegentropy(ctx, peerURL) |
||||
|
||||
m.mu.Lock() |
||||
peer.LastSync = time.Now() |
||||
if err != nil { |
||||
peer.Status = "error" |
||||
peer.LastError = err.Error() |
||||
peer.ConsecutiveFailures++ |
||||
log.E.F("negentropy sync with %s failed: %v", peerURL, err) |
||||
} else { |
||||
peer.Status = "idle" |
||||
peer.LastError = "" |
||||
peer.ConsecutiveFailures = 0 |
||||
peer.EventsSynced += eventsSynced |
||||
log.I.F("negentropy sync with %s complete: %d events synced", peerURL, eventsSynced) |
||||
} |
||||
m.mu.Unlock() |
||||
} |
||||
|
||||
// performNegentropy performs the actual NIP-77 negentropy sync with a peer.
|
||||
func (m *Manager) performNegentropy(ctx context.Context, peerURL string) (int64, error) { |
||||
// Build local storage from our events
|
||||
storage, err := m.buildStorage(ctx) |
||||
if err != nil { |
||||
return 0, fmt.Errorf("failed to build storage: %w", err) |
||||
} |
||||
|
||||
log.I.F("built negentropy storage with %d events", storage.Size()) |
||||
|
||||
// Create negentropy instance
|
||||
neg := negentropy.New(storage, m.config.FrameSize) |
||||
defer neg.Close() |
||||
|
||||
// Connect to peer WebSocket
|
||||
wsURL := strings.Replace(peerURL, "wss://", "wss://", 1) |
||||
wsURL = strings.Replace(wsURL, "ws://", "ws://", 1) |
||||
if !strings.HasPrefix(wsURL, "ws") { |
||||
wsURL = "wss://" + wsURL |
||||
} |
||||
|
||||
dialer := websocket.Dialer{ |
||||
HandshakeTimeout: 30 * time.Second, |
||||
} |
||||
|
||||
conn, _, err := dialer.DialContext(ctx, wsURL, http.Header{}) |
||||
if err != nil { |
||||
return 0, fmt.Errorf("failed to connect to peer: %w", err) |
||||
} |
||||
defer conn.Close() |
||||
|
||||
// Generate subscription ID
|
||||
subID := fmt.Sprintf("neg-%d", time.Now().UnixNano()) |
||||
|
||||
// Start negentropy protocol
|
||||
initialMsg, err := neg.Start() |
||||
if err != nil { |
||||
return 0, fmt.Errorf("failed to start negentropy: %w", err) |
||||
} |
||||
|
||||
// Send NEG-OPEN: ["NEG-OPEN", subscription_id, filter, initial_message]
|
||||
filter := map[string]any{} // Empty filter = all events
|
||||
negOpen := []any{"NEG-OPEN", subID, filter, hex.EncodeToString(initialMsg)} |
||||
if err := conn.WriteJSON(negOpen); err != nil { |
||||
return 0, fmt.Errorf("failed to send NEG-OPEN: %w", err) |
||||
} |
||||
|
||||
var eventsSynced int64 |
||||
var needIDs []string |
||||
var haveIDs []string |
||||
|
||||
// Exchange messages until complete
|
||||
for i := 0; i < 20; i++ { // Max 20 rounds
|
||||
// Read response
|
||||
_, msgBytes, err := conn.ReadMessage() |
||||
if err != nil { |
||||
return eventsSynced, fmt.Errorf("failed to read message: %w", err) |
||||
} |
||||
|
||||
var msg []json.RawMessage |
||||
if err := json.Unmarshal(msgBytes, &msg); err != nil { |
||||
return eventsSynced, fmt.Errorf("failed to parse message: %w", err) |
||||
} |
||||
|
||||
if len(msg) < 2 { |
||||
continue |
||||
} |
||||
|
||||
var msgType string |
||||
if err := json.Unmarshal(msg[0], &msgType); err != nil { |
||||
continue |
||||
} |
||||
|
||||
switch msgType { |
||||
case "NEG-MSG": |
||||
if len(msg) < 3 { |
||||
continue |
||||
} |
||||
var hexMsg string |
||||
if err := json.Unmarshal(msg[2], &hexMsg); err != nil { |
||||
continue |
||||
} |
||||
|
||||
negMsg, err := hex.DecodeString(hexMsg) |
||||
if err != nil { |
||||
continue |
||||
} |
||||
|
||||
response, complete, err := neg.Reconcile(negMsg) |
||||
if err != nil { |
||||
return eventsSynced, fmt.Errorf("reconcile failed: %w", err) |
||||
} |
||||
|
||||
// Collect IDs we need and IDs we have
|
||||
needIDs = append(needIDs, neg.CollectHaveNots()...) |
||||
haveIDs = append(haveIDs, neg.CollectHaves()...) |
||||
|
||||
if complete { |
||||
// Send NEG-CLOSE
|
||||
negClose := []any{"NEG-CLOSE", subID} |
||||
conn.WriteJSON(negClose) |
||||
goto done |
||||
} |
||||
|
||||
// Send NEG-MSG response
|
||||
negMsgResp := []any{"NEG-MSG", subID, hex.EncodeToString(response)} |
||||
if err := conn.WriteJSON(negMsgResp); err != nil { |
||||
return eventsSynced, fmt.Errorf("failed to send NEG-MSG: %w", err) |
||||
} |
||||
|
||||
case "NEG-ERR": |
||||
var errMsg string |
||||
if len(msg) >= 3 { |
||||
json.Unmarshal(msg[2], &errMsg) |
||||
} |
||||
return eventsSynced, fmt.Errorf("peer returned error: %s", errMsg) |
||||
|
||||
case "EVENT": |
||||
// Peer is sending us an event
|
||||
eventsSynced++ |
||||
} |
||||
} |
||||
|
||||
done: |
||||
log.I.F("negentropy: need %d events, have %d events to send", len(needIDs), len(haveIDs)) |
||||
if len(needIDs) > 0 { |
||||
log.I.F("negentropy: first few need IDs: %v", needIDs[:min(len(needIDs), 3)]) |
||||
} |
||||
|
||||
// PUSH events we have to the peer (haveIDs)
|
||||
// This is more reliable than trying to PULL events using ID prefixes
|
||||
if len(haveIDs) > 0 { |
||||
pushed, err := m.pushEventsToPeer(ctx, conn, haveIDs) |
||||
if err != nil { |
||||
log.W.F("failed to push events to peer: %v", err) |
||||
} else { |
||||
log.I.F("negentropy: pushed %d events to peer", pushed) |
||||
eventsSynced += int64(pushed) |
||||
} |
||||
} |
||||
|
||||
// NOTE: Events we need (needIDs) will be pushed to us by the peer's sync process
|
||||
// The peer runs the same negentropy sync and will identify these events as "haves"
|
||||
// to push to us. We don't need to explicitly fetch them.
|
||||
|
||||
return eventsSynced, nil |
||||
} |
||||
|
||||
// buildStorage creates a negentropy Vector from local events.
|
||||
func (m *Manager) buildStorage(ctx context.Context) (*negentropy.Vector, error) { |
||||
storage := negentropy.NewVector() |
||||
|
||||
// Query all events from database using an empty filter
|
||||
// This returns IdPkTs structs with Id, Pub, Ts, Ser fields
|
||||
limit := uint(100000) |
||||
f := &filter.F{ |
||||
Limit: &limit, // Limit to 100k events for now
|
||||
} |
||||
|
||||
idPkTs, err := m.db.QueryForIds(ctx, f) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to query events: %w", err) |
||||
} |
||||
|
||||
for _, item := range idPkTs { |
||||
// IDHex() returns lowercase hex string of the event ID
|
||||
storage.Insert(item.Ts, item.IDHex()) |
||||
} |
||||
|
||||
storage.Seal() |
||||
return storage, nil |
||||
} |
||||
|
||||
// pushEventsToPeer sends events we have to the peer.
|
||||
// The truncated IDs are 32-char hex prefixes, so we query our local DB and push matching events.
|
||||
func (m *Manager) pushEventsToPeer(ctx context.Context, conn *websocket.Conn, truncatedIDs []string) (int, error) { |
||||
if len(truncatedIDs) == 0 { |
||||
return 0, nil |
||||
} |
||||
log.I.F("pushEventsToPeer: looking up %d events to push", len(truncatedIDs)) |
||||
|
||||
pushed := 0 |
||||
for _, truncID := range truncatedIDs { |
||||
// Query local database for events matching this ID prefix
|
||||
// Use QueryByIDPrefix if available, otherwise fall back to broader query
|
||||
events, err := m.queryEventsByIDPrefix(ctx, truncID) |
||||
if err != nil { |
||||
log.D.F("failed to query event with prefix %s: %v", truncID, err) |
||||
continue |
||||
} |
||||
|
||||
for _, ev := range events { |
||||
// Send event to peer
|
||||
eventMsg := []any{"EVENT", ev} |
||||
if err := conn.WriteJSON(eventMsg); err != nil { |
||||
log.W.F("failed to push event %s: %v", truncID, err) |
||||
continue |
||||
} |
||||
pushed++ |
||||
} |
||||
} |
||||
|
||||
return pushed, nil |
||||
} |
||||
|
||||
// queryEventsByIDPrefix queries local database for events matching an ID prefix.
|
||||
func (m *Manager) queryEventsByIDPrefix(ctx context.Context, idPrefix string) ([]*event.E, error) { |
||||
// For now, query by the prefix - Badger supports prefix iteration
|
||||
// The ID prefix is 32 hex chars = 16 bytes
|
||||
limit := uint(10000) // Get enough events to find our prefix matches
|
||||
|
||||
// Query IDs and filter by prefix
|
||||
f := &filter.F{ |
||||
Limit: &limit, |
||||
} |
||||
|
||||
idPkTs, err := m.db.QueryForIds(ctx, f) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var results []*event.E |
||||
for _, item := range idPkTs { |
||||
fullID := item.IDHex() |
||||
if len(fullID) >= len(idPrefix) && fullID[:len(idPrefix)] == idPrefix { |
||||
// Found a match - decode the full ID and fetch the event
|
||||
idBytes, err := hex.DecodeString(fullID) |
||||
if err != nil { |
||||
log.D.F("failed to decode ID %s: %v", fullID, err) |
||||
continue |
||||
} |
||||
|
||||
// Create filter with the full ID
|
||||
idTag := tag.NewFromBytesSlice(idBytes) |
||||
evs, err := m.db.QueryEvents(ctx, &filter.F{ |
||||
Ids: idTag, |
||||
}) |
||||
if err != nil { |
||||
log.D.F("failed to fetch event %s: %v", fullID, err) |
||||
continue |
||||
} |
||||
if len(evs) > 0 { |
||||
results = append(results, evs[0]) |
||||
} |
||||
} |
||||
} |
||||
|
||||
return results, nil |
||||
} |
||||
|
||||
// fetchEventsFromPeer fetches specific events from a peer by ID (can be prefixes).
|
||||
// NOTE: This is deprecated in favor of push-based sync, but kept for reference.
|
||||
func (m *Manager) fetchEventsFromPeer(ctx context.Context, conn *websocket.Conn, baseSubID string, ids []string) (int, error) { |
||||
if len(ids) == 0 { |
||||
return 0, nil |
||||
} |
||||
log.I.F("fetchEventsFromPeer: fetching %d events with IDs (first 3): %v", len(ids), ids[:min(3, len(ids))]) |
||||
|
||||
// Batch IDs into chunks of 100
|
||||
const batchSize = 100 |
||||
fetched := 0 |
||||
|
||||
for i := 0; i < len(ids); i += batchSize { |
||||
end := i + batchSize |
||||
if end > len(ids) { |
||||
end = len(ids) |
||||
} |
||||
batch := ids[i:end] |
||||
|
||||
subID := fmt.Sprintf("%s-fetch-%d", baseSubID, i/batchSize) |
||||
log.I.F("fetchEventsFromPeer: sending REQ %s for batch of %d IDs", subID, len(batch)) |
||||
|
||||
// Send REQ for these IDs
|
||||
filter := map[string]any{ |
||||
"ids": batch, |
||||
} |
||||
req := []any{"REQ", subID, filter} |
||||
reqJSON, _ := json.Marshal(req) |
||||
log.D.F("fetchEventsFromPeer: REQ message: %s", string(reqJSON)[:min(500, len(reqJSON))]) |
||||
|
||||
if err := conn.WriteJSON(req); err != nil { |
||||
log.E.F("fetchEventsFromPeer: failed to send REQ: %v", err) |
||||
return fetched, fmt.Errorf("failed to send REQ: %w", err) |
||||
} |
||||
|
||||
// Read events until EOSE
|
||||
messageCount := 0 |
||||
for { |
||||
_, msgBytes, err := conn.ReadMessage() |
||||
if err != nil { |
||||
log.E.F("fetchEventsFromPeer: failed to read after %d messages: %v", messageCount, err) |
||||
return fetched, fmt.Errorf("failed to read: %w", err) |
||||
} |
||||
messageCount++ |
||||
|
||||
var msg []json.RawMessage |
||||
if err := json.Unmarshal(msgBytes, &msg); err != nil { |
||||
log.D.F("fetchEventsFromPeer: failed to unmarshal message: %v", err) |
||||
continue |
||||
} |
||||
|
||||
if len(msg) < 2 { |
||||
log.D.F("fetchEventsFromPeer: message too short: %d elements", len(msg)) |
||||
continue |
||||
} |
||||
|
||||
var msgType string |
||||
if err := json.Unmarshal(msg[0], &msgType); err != nil { |
||||
log.D.F("fetchEventsFromPeer: failed to unmarshal message type: %v", err) |
||||
continue |
||||
} |
||||
|
||||
switch msgType { |
||||
case "EVENT": |
||||
if len(msg) >= 3 { |
||||
// Store the event
|
||||
if err := m.storeEventFromJSON(ctx, msg[2]); err != nil { |
||||
log.W.F("fetchEventsFromPeer: failed to store event: %v", err) |
||||
} else { |
||||
fetched++ |
||||
if fetched%10 == 0 { |
||||
log.I.F("fetchEventsFromPeer: stored %d events so far", fetched) |
||||
} |
||||
} |
||||
} |
||||
case "EOSE": |
||||
log.I.F("fetchEventsFromPeer: received EOSE for %s after %d messages, fetched %d events in batch", subID, messageCount, fetched) |
||||
goto nextBatch |
||||
case "CLOSED": |
||||
var reason string |
||||
if len(msg) >= 3 { |
||||
json.Unmarshal(msg[2], &reason) |
||||
} |
||||
log.W.F("fetchEventsFromPeer: subscription %s closed: %s", subID, reason) |
||||
goto nextBatch |
||||
case "NOTICE": |
||||
var notice string |
||||
if len(msg) >= 2 { |
||||
json.Unmarshal(msg[1], ¬ice) |
||||
} |
||||
log.W.F("fetchEventsFromPeer: NOTICE from peer: %s", notice) |
||||
default: |
||||
log.D.F("fetchEventsFromPeer: unknown message type: %s", msgType) |
||||
} |
||||
} |
||||
nextBatch: |
||||
// Send CLOSE for this subscription
|
||||
closeMsg := []any{"CLOSE", subID} |
||||
conn.WriteJSON(closeMsg) |
||||
} |
||||
|
||||
log.I.F("fetchEventsFromPeer: completed, total fetched: %d", fetched) |
||||
return fetched, nil |
||||
} |
||||
|
||||
// storeEventFromJSON stores an event from raw JSON.
|
||||
func (m *Manager) storeEventFromJSON(ctx context.Context, eventJSON json.RawMessage) error { |
||||
// Parse the event using the nostr event encoder
|
||||
ev := &event.E{} |
||||
if err := ev.UnmarshalJSON(eventJSON); err != nil { |
||||
return fmt.Errorf("failed to unmarshal event: %w", err) |
||||
} |
||||
|
||||
// Verify the event signature
|
||||
if ok, err := ev.Verify(); err != nil || !ok { |
||||
return fmt.Errorf("event verification failed") |
||||
} |
||||
|
||||
// Store via database using the standard SaveEvent method
|
||||
_, err := m.db.SaveEvent(ctx, ev) |
||||
return err |
||||
} |
||||
|
||||
// IsActive returns whether background sync is running.
|
||||
func (m *Manager) IsActive() bool { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
return m.active |
||||
} |
||||
|
||||
// LastSync returns the timestamp of the last sync cycle.
|
||||
func (m *Manager) LastSync() time.Time { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
return m.lastSync |
||||
} |
||||
|
||||
// GetPeers returns the list of peer URLs.
|
||||
func (m *Manager) GetPeers() []string { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
peers := make([]string, 0, len(m.peers)) |
||||
for url := range m.peers { |
||||
peers = append(peers, url) |
||||
} |
||||
return peers |
||||
} |
||||
|
||||
// GetPeerStates returns the sync state for all peers.
|
||||
func (m *Manager) GetPeerStates() []*PeerState { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
states := make([]*PeerState, 0, len(m.peers)) |
||||
for _, peer := range m.peers { |
||||
states = append(states, &PeerState{ |
||||
URL: peer.URL, |
||||
LastSync: peer.LastSync, |
||||
EventsSynced: peer.EventsSynced, |
||||
Status: peer.Status, |
||||
LastError: peer.LastError, |
||||
ConsecutiveFailures: peer.ConsecutiveFailures, |
||||
}) |
||||
} |
||||
return states |
||||
} |
||||
|
||||
// GetPeerState returns the sync state for a specific peer.
|
||||
func (m *Manager) GetPeerState(peerURL string) (*PeerState, bool) { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
peer, ok := m.peers[peerURL] |
||||
if !ok { |
||||
return nil, false |
||||
} |
||||
return &PeerState{ |
||||
URL: peer.URL, |
||||
LastSync: peer.LastSync, |
||||
EventsSynced: peer.EventsSynced, |
||||
Status: peer.Status, |
||||
LastError: peer.LastError, |
||||
ConsecutiveFailures: peer.ConsecutiveFailures, |
||||
}, true |
||||
} |
||||
|
||||
// AddPeer adds a peer for negentropy sync.
|
||||
func (m *Manager) AddPeer(peerURL string) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
if _, ok := m.peers[peerURL]; !ok { |
||||
m.peers[peerURL] = &PeerState{ |
||||
URL: peerURL, |
||||
Status: "idle", |
||||
} |
||||
} |
||||
} |
||||
|
||||
// RemovePeer removes a peer from negentropy sync.
|
||||
func (m *Manager) RemovePeer(peerURL string) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
delete(m.peers, peerURL) |
||||
} |
||||
|
||||
// TriggerSync manually triggers sync with a specific peer or all peers.
|
||||
func (m *Manager) TriggerSync(ctx context.Context, peerURL string) { |
||||
if peerURL == "" { |
||||
m.syncAllPeers() |
||||
} else { |
||||
m.syncWithPeer(ctx, peerURL) |
||||
} |
||||
} |
||||
|
||||
// sessionKey creates a unique key for a session.
|
||||
func sessionKey(connectionID, subscriptionID string) string { |
||||
return connectionID + ":" + subscriptionID |
||||
} |
||||
|
||||
// OpenSession opens a new client negentropy session.
|
||||
func (m *Manager) OpenSession(connectionID, subscriptionID string) *ClientSession { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
|
||||
key := sessionKey(connectionID, subscriptionID) |
||||
session := &ClientSession{ |
||||
SubscriptionID: subscriptionID, |
||||
ConnectionID: connectionID, |
||||
CreatedAt: time.Now(), |
||||
LastActivity: time.Now(), |
||||
RoundCount: 0, |
||||
} |
||||
m.sessions[key] = session |
||||
return session |
||||
} |
||||
|
||||
// GetSession retrieves an existing session.
|
||||
func (m *Manager) GetSession(connectionID, subscriptionID string) (*ClientSession, bool) { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
key := sessionKey(connectionID, subscriptionID) |
||||
session, ok := m.sessions[key] |
||||
return session, ok |
||||
} |
||||
|
||||
// UpdateSessionActivity updates the last activity time for a session.
|
||||
func (m *Manager) UpdateSessionActivity(connectionID, subscriptionID string) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
key := sessionKey(connectionID, subscriptionID) |
||||
if session, ok := m.sessions[key]; ok { |
||||
session.LastActivity = time.Now() |
||||
session.RoundCount++ |
||||
} |
||||
} |
||||
|
||||
// CloseSession closes a client session.
|
||||
func (m *Manager) CloseSession(connectionID, subscriptionID string) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
key := sessionKey(connectionID, subscriptionID) |
||||
if session, ok := m.sessions[key]; ok { |
||||
if session.neg != nil { |
||||
session.neg.Close() |
||||
} |
||||
} |
||||
delete(m.sessions, key) |
||||
} |
||||
|
||||
// CloseSessionsByConnection closes all sessions for a connection.
|
||||
func (m *Manager) CloseSessionsByConnection(connectionID string) { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
for key, session := range m.sessions { |
||||
if session.ConnectionID == connectionID { |
||||
if session.neg != nil { |
||||
session.neg.Close() |
||||
} |
||||
delete(m.sessions, key) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// ListSessions returns all active sessions.
|
||||
func (m *Manager) ListSessions() []*ClientSession { |
||||
m.mu.RLock() |
||||
defer m.mu.RUnlock() |
||||
sessions := make([]*ClientSession, 0, len(m.sessions)) |
||||
for _, session := range m.sessions { |
||||
sessions = append(sessions, &ClientSession{ |
||||
SubscriptionID: session.SubscriptionID, |
||||
ConnectionID: session.ConnectionID, |
||||
CreatedAt: session.CreatedAt, |
||||
LastActivity: session.LastActivity, |
||||
RoundCount: session.RoundCount, |
||||
}) |
||||
} |
||||
return sessions |
||||
} |
||||
|
||||
// CleanupExpiredSessions removes sessions that have been inactive beyond timeout.
|
||||
func (m *Manager) CleanupExpiredSessions() int { |
||||
m.mu.Lock() |
||||
defer m.mu.Unlock() |
||||
|
||||
cutoff := time.Now().Add(-m.config.ClientSessionTimeout) |
||||
removed := 0 |
||||
for key, session := range m.sessions { |
||||
if session.LastActivity.Before(cutoff) { |
||||
if session.neg != nil { |
||||
session.neg.Close() |
||||
} |
||||
delete(m.sessions, key) |
||||
removed++ |
||||
} |
||||
} |
||||
return removed |
||||
} |
||||
|
||||
// Ensure chk is used
|
||||
var _ = chk.E |
||||
@ -0,0 +1,360 @@
@@ -0,0 +1,360 @@
|
||||
// Package server provides the gRPC server implementation for negentropy sync.
|
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
|
||||
"google.golang.org/grpc" |
||||
"lol.mleku.dev/log" |
||||
|
||||
"git.mleku.dev/mleku/nostr/encoders/filter" |
||||
negentropylib "git.mleku.dev/mleku/nostr/negentropy" |
||||
"next.orly.dev/pkg/database" |
||||
"next.orly.dev/pkg/sync/negentropy" |
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
negentropyv1 "next.orly.dev/pkg/proto/orlysync/negentropy/v1" |
||||
) |
||||
|
||||
// Service implements the NegentropyServiceServer interface.
|
||||
type Service struct { |
||||
negentropyv1.UnimplementedNegentropyServiceServer |
||||
mgr *negentropy.Manager |
||||
db database.Database |
||||
ready bool |
||||
} |
||||
|
||||
// NewService creates a new negentropy gRPC service.
|
||||
func NewService(db database.Database, mgr *negentropy.Manager) *Service { |
||||
return &Service{ |
||||
mgr: mgr, |
||||
db: db, |
||||
ready: true, |
||||
} |
||||
} |
||||
|
||||
// Ready returns whether the service is ready to serve requests.
|
||||
func (s *Service) Ready(ctx context.Context, _ *commonv1.Empty) (*commonv1.ReadyResponse, error) { |
||||
return &commonv1.ReadyResponse{Ready: s.ready}, nil |
||||
} |
||||
|
||||
// Start starts the background relay-to-relay sync.
|
||||
func (s *Service) Start(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
s.mgr.Start() |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// Stop stops the background sync.
|
||||
func (s *Service) Stop(ctx context.Context, _ *commonv1.Empty) (*commonv1.Empty, error) { |
||||
s.mgr.Stop() |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// HandleNegOpen processes a NEG-OPEN message from a client.
|
||||
func (s *Service) HandleNegOpen(ctx context.Context, req *negentropyv1.NegOpenRequest) (*negentropyv1.NegOpenResponse, error) { |
||||
// Open a session for this client
|
||||
session := s.mgr.OpenSession(req.ConnectionId, req.SubscriptionId) |
||||
|
||||
// Build storage from local events matching the filter
|
||||
storage, err := s.buildStorageForFilter(ctx, req.Filter) |
||||
if err != nil { |
||||
log.E.F("NEG-OPEN: failed to build storage: %v", err) |
||||
return &negentropyv1.NegOpenResponse{ |
||||
Message: nil, |
||||
Error: fmt.Sprintf("failed to build storage: %v", err), |
||||
}, nil |
||||
} |
||||
|
||||
log.I.F("NEG-OPEN: built storage with %d events", storage.Size()) |
||||
|
||||
// Create negentropy instance for this session
|
||||
neg := negentropylib.New(storage, negentropylib.DefaultFrameSizeLimit) |
||||
|
||||
// Store in session for later use
|
||||
session.SetNegentropy(neg, storage) |
||||
|
||||
// If we have an initial message from client, process it
|
||||
var respMsg []byte |
||||
if len(req.InitialMessage) > 0 { |
||||
var complete bool |
||||
respMsg, complete, err = neg.Reconcile(req.InitialMessage) |
||||
if err != nil { |
||||
log.E.F("NEG-OPEN: reconcile failed: %v", err) |
||||
return &negentropyv1.NegOpenResponse{ |
||||
Message: nil, |
||||
Error: fmt.Sprintf("reconcile failed: %v", err), |
||||
}, nil |
||||
} |
||||
log.I.F("NEG-OPEN: reconcile complete=%v, response len=%d", complete, len(respMsg)) |
||||
} else { |
||||
// No initial message, start as server (initiator)
|
||||
respMsg, err = neg.Start() |
||||
if err != nil { |
||||
log.E.F("NEG-OPEN: failed to start: %v", err) |
||||
return &negentropyv1.NegOpenResponse{ |
||||
Message: nil, |
||||
Error: fmt.Sprintf("failed to start: %v", err), |
||||
}, nil |
||||
} |
||||
log.D.F("NEG-OPEN: started negentropy, initial msg len=%d", len(respMsg)) |
||||
} |
||||
|
||||
return &negentropyv1.NegOpenResponse{ |
||||
Message: respMsg, |
||||
Error: "", |
||||
}, nil |
||||
} |
||||
|
||||
// HandleNegMsg processes a NEG-MSG message from a client.
|
||||
func (s *Service) HandleNegMsg(ctx context.Context, req *negentropyv1.NegMsgRequest) (*negentropyv1.NegMsgResponse, error) { |
||||
// Update session activity
|
||||
s.mgr.UpdateSessionActivity(req.ConnectionId, req.SubscriptionId) |
||||
|
||||
// Look up session
|
||||
session, ok := s.mgr.GetSession(req.ConnectionId, req.SubscriptionId) |
||||
if !ok { |
||||
return &negentropyv1.NegMsgResponse{ |
||||
Error: "session not found", |
||||
}, nil |
||||
} |
||||
|
||||
neg := session.GetNegentropy() |
||||
if neg == nil { |
||||
return &negentropyv1.NegMsgResponse{ |
||||
Error: "session has no negentropy state", |
||||
}, nil |
||||
} |
||||
|
||||
// Process the message
|
||||
respMsg, complete, err := neg.Reconcile(req.Message) |
||||
if err != nil { |
||||
log.E.F("NEG-MSG: reconcile failed: %v", err) |
||||
return &negentropyv1.NegMsgResponse{ |
||||
Error: fmt.Sprintf("reconcile failed: %v", err), |
||||
}, nil |
||||
} |
||||
|
||||
// Collect IDs we have that client needs (to send as events)
|
||||
haveIDs := neg.CollectHaves() |
||||
var haveIDBytes [][]byte |
||||
for _, id := range haveIDs { |
||||
haveIDBytes = append(haveIDBytes, []byte(id)) |
||||
} |
||||
|
||||
// Collect IDs we need from client
|
||||
needIDs := neg.CollectHaveNots() |
||||
var needIDBytes [][]byte |
||||
for _, id := range needIDs { |
||||
needIDBytes = append(needIDBytes, []byte(id)) |
||||
} |
||||
|
||||
log.I.F("NEG-MSG: complete=%v, haves=%d, needs=%d, response len=%d", |
||||
complete, len(haveIDs), len(needIDs), len(respMsg)) |
||||
|
||||
return &negentropyv1.NegMsgResponse{ |
||||
Message: respMsg, |
||||
HaveIds: haveIDBytes, |
||||
NeedIds: needIDBytes, |
||||
Complete: complete, |
||||
Error: "", |
||||
}, nil |
||||
} |
||||
|
||||
// HandleNegClose processes a NEG-CLOSE message from a client.
|
||||
func (s *Service) HandleNegClose(ctx context.Context, req *negentropyv1.NegCloseRequest) (*commonv1.Empty, error) { |
||||
s.mgr.CloseSession(req.ConnectionId, req.SubscriptionId) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// SyncWithPeer initiates negentropy sync with a specific peer relay.
|
||||
func (s *Service) SyncWithPeer(req *negentropyv1.SyncPeerRequest, stream grpc.ServerStreamingServer[negentropyv1.SyncProgress]) error { |
||||
// Send initial progress
|
||||
if err := stream.Send(&negentropyv1.SyncProgress{ |
||||
PeerUrl: req.PeerUrl, |
||||
Round: 0, |
||||
Complete: false, |
||||
}); err != nil { |
||||
return err |
||||
} |
||||
|
||||
// TODO: Implement actual NIP-77 sync with peer
|
||||
// For now, just mark as complete
|
||||
|
||||
s.mgr.TriggerSync(stream.Context(), req.PeerUrl) |
||||
|
||||
// Send completion
|
||||
return stream.Send(&negentropyv1.SyncProgress{ |
||||
PeerUrl: req.PeerUrl, |
||||
Round: 1, |
||||
Complete: true, |
||||
}) |
||||
} |
||||
|
||||
// GetSyncStatus returns the current sync status.
|
||||
func (s *Service) GetSyncStatus(ctx context.Context, _ *commonv1.Empty) (*negentropyv1.SyncStatusResponse, error) { |
||||
peerStates := s.mgr.GetPeerStates() |
||||
|
||||
states := make([]*negentropyv1.PeerSyncState, 0, len(peerStates)) |
||||
for _, ps := range peerStates { |
||||
states = append(states, &negentropyv1.PeerSyncState{ |
||||
PeerUrl: ps.URL, |
||||
LastSync: ps.LastSync.Unix(), |
||||
EventsSynced: ps.EventsSynced, |
||||
Status: ps.Status, |
||||
LastError: ps.LastError, |
||||
ConsecutiveFailures: ps.ConsecutiveFailures, |
||||
}) |
||||
} |
||||
|
||||
return &negentropyv1.SyncStatusResponse{ |
||||
Active: s.mgr.IsActive(), |
||||
LastSync: s.mgr.LastSync().Unix(), |
||||
PeerCount: int32(len(peerStates)), |
||||
PeerStates: states, |
||||
}, nil |
||||
} |
||||
|
||||
// GetPeers returns the list of negentropy sync peers.
|
||||
func (s *Service) GetPeers(ctx context.Context, _ *commonv1.Empty) (*negentropyv1.PeersResponse, error) { |
||||
return &negentropyv1.PeersResponse{ |
||||
Peers: s.mgr.GetPeers(), |
||||
}, nil |
||||
} |
||||
|
||||
// AddPeer adds a peer for negentropy sync.
|
||||
func (s *Service) AddPeer(ctx context.Context, req *negentropyv1.AddPeerRequest) (*commonv1.Empty, error) { |
||||
s.mgr.AddPeer(req.PeerUrl) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// RemovePeer removes a peer from negentropy sync.
|
||||
func (s *Service) RemovePeer(ctx context.Context, req *negentropyv1.RemovePeerRequest) (*commonv1.Empty, error) { |
||||
s.mgr.RemovePeer(req.PeerUrl) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// TriggerSync manually triggers sync with a specific peer or all peers.
|
||||
func (s *Service) TriggerSync(ctx context.Context, req *negentropyv1.TriggerSyncRequest) (*commonv1.Empty, error) { |
||||
s.mgr.TriggerSync(ctx, req.PeerUrl) |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// GetPeerSyncState returns sync state for a specific peer.
|
||||
func (s *Service) GetPeerSyncState(ctx context.Context, req *negentropyv1.PeerSyncStateRequest) (*negentropyv1.PeerSyncStateResponse, error) { |
||||
state, found := s.mgr.GetPeerState(req.PeerUrl) |
||||
if !found { |
||||
return &negentropyv1.PeerSyncStateResponse{ |
||||
Found: false, |
||||
}, nil |
||||
} |
||||
|
||||
return &negentropyv1.PeerSyncStateResponse{ |
||||
Found: true, |
||||
State: &negentropyv1.PeerSyncState{ |
||||
PeerUrl: state.URL, |
||||
LastSync: state.LastSync.Unix(), |
||||
EventsSynced: state.EventsSynced, |
||||
Status: state.Status, |
||||
LastError: state.LastError, |
||||
ConsecutiveFailures: state.ConsecutiveFailures, |
||||
}, |
||||
}, nil |
||||
} |
||||
|
||||
// ListSessions returns active client negentropy sessions.
|
||||
func (s *Service) ListSessions(ctx context.Context, _ *commonv1.Empty) (*negentropyv1.ListSessionsResponse, error) { |
||||
sessions := s.mgr.ListSessions() |
||||
|
||||
protoSessions := make([]*negentropyv1.ClientSession, 0, len(sessions)) |
||||
for _, sess := range sessions { |
||||
protoSessions = append(protoSessions, &negentropyv1.ClientSession{ |
||||
SubscriptionId: sess.SubscriptionID, |
||||
ConnectionId: sess.ConnectionID, |
||||
CreatedAt: sess.CreatedAt.Unix(), |
||||
LastActivity: sess.LastActivity.Unix(), |
||||
RoundCount: sess.RoundCount, |
||||
}) |
||||
} |
||||
|
||||
return &negentropyv1.ListSessionsResponse{ |
||||
Sessions: protoSessions, |
||||
}, nil |
||||
} |
||||
|
||||
// CloseSession forcefully closes a client session.
|
||||
func (s *Service) CloseSession(ctx context.Context, req *negentropyv1.CloseSessionRequest) (*commonv1.Empty, error) { |
||||
if req.ConnectionId == "" { |
||||
// Close all sessions with this subscription ID
|
||||
sessions := s.mgr.ListSessions() |
||||
for _, sess := range sessions { |
||||
if sess.SubscriptionID == req.SubscriptionId { |
||||
s.mgr.CloseSession(sess.ConnectionID, sess.SubscriptionID) |
||||
} |
||||
} |
||||
} else { |
||||
s.mgr.CloseSession(req.ConnectionId, req.SubscriptionId) |
||||
} |
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
|
||||
// buildStorageForFilter creates a negentropy Vector from local events matching the filter.
|
||||
func (s *Service) buildStorageForFilter(ctx context.Context, protoFilter *commonv1.Filter) (*negentropylib.Vector, error) { |
||||
storage := negentropylib.NewVector() |
||||
|
||||
// Convert proto filter to nostr filter
|
||||
f := protoToFilter(protoFilter) |
||||
|
||||
// If no filter provided, use a reasonable limit
|
||||
if f == nil { |
||||
limit := uint(100000) |
||||
f = &filter.F{Limit: &limit} |
||||
} |
||||
if f.Limit == nil { |
||||
limit := uint(100000) |
||||
f.Limit = &limit |
||||
} |
||||
|
||||
// Query events from database
|
||||
idPkTs, err := s.db.QueryForIds(ctx, f) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to query events: %w", err) |
||||
} |
||||
|
||||
for _, item := range idPkTs { |
||||
storage.Insert(item.Ts, item.IDHex()) |
||||
} |
||||
|
||||
storage.Seal() |
||||
return storage, nil |
||||
} |
||||
|
||||
// protoToFilter converts a proto filter to a nostr filter.
|
||||
func protoToFilter(pf *commonv1.Filter) *filter.F { |
||||
if pf == nil { |
||||
return nil |
||||
} |
||||
|
||||
f := &filter.F{} |
||||
|
||||
// Convert Kinds
|
||||
if len(pf.Kinds) > 0 { |
||||
// Create kinds from proto
|
||||
// Note: We'd need proper kinds conversion here
|
||||
} |
||||
|
||||
// Convert Since/Until
|
||||
if pf.Since != nil { |
||||
// Set Since timestamp
|
||||
} |
||||
if pf.Until != nil { |
||||
// Set Until timestamp
|
||||
} |
||||
|
||||
// Convert Limit
|
||||
if pf.Limit != nil { |
||||
limit := uint(*pf.Limit) |
||||
f.Limit = &limit |
||||
} |
||||
|
||||
return f |
||||
} |
||||
@ -0,0 +1,142 @@
@@ -0,0 +1,142 @@
|
||||
// Package grpc provides a gRPC client for the relay group service.
|
||||
package grpc |
||||
|
||||
import ( |
||||
"context" |
||||
"time" |
||||
|
||||
"google.golang.org/grpc" |
||||
"google.golang.org/grpc/credentials/insecure" |
||||
"lol.mleku.dev/log" |
||||
|
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
relaygroupv1 "next.orly.dev/pkg/proto/orlysync/relaygroup/v1" |
||||
) |
||||
|
||||
// Client is a gRPC client for the relay group service.
|
||||
type Client struct { |
||||
conn *grpc.ClientConn |
||||
client relaygroupv1.RelayGroupServiceClient |
||||
ready chan struct{} |
||||
} |
||||
|
||||
// ClientConfig holds configuration for the gRPC client.
|
||||
type ClientConfig struct { |
||||
ServerAddress string |
||||
ConnectTimeout time.Duration |
||||
} |
||||
|
||||
// New creates a new gRPC relay group client.
|
||||
func New(ctx context.Context, cfg *ClientConfig) (*Client, error) { |
||||
timeout := cfg.ConnectTimeout |
||||
if timeout == 0 { |
||||
timeout = 10 * time.Second |
||||
} |
||||
|
||||
dialCtx, cancel := context.WithTimeout(ctx, timeout) |
||||
defer cancel() |
||||
|
||||
conn, err := grpc.DialContext(dialCtx, cfg.ServerAddress, |
||||
grpc.WithTransportCredentials(insecure.NewCredentials()), |
||||
grpc.WithDefaultCallOptions( |
||||
grpc.MaxCallRecvMsgSize(16<<20), // 16MB
|
||||
grpc.MaxCallSendMsgSize(16<<20), // 16MB
|
||||
), |
||||
) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
c := &Client{ |
||||
conn: conn, |
||||
client: relaygroupv1.NewRelayGroupServiceClient(conn), |
||||
ready: make(chan struct{}), |
||||
} |
||||
|
||||
go c.waitForReady(ctx) |
||||
|
||||
return c, nil |
||||
} |
||||
|
||||
func (c *Client) waitForReady(ctx context.Context) { |
||||
for { |
||||
select { |
||||
case <-ctx.Done(): |
||||
return |
||||
default: |
||||
resp, err := c.client.Ready(ctx, &commonv1.Empty{}) |
||||
if err == nil && resp.Ready { |
||||
close(c.ready) |
||||
log.I.F("gRPC relay group client connected and ready") |
||||
return |
||||
} |
||||
time.Sleep(100 * time.Millisecond) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Close closes the gRPC connection.
|
||||
func (c *Client) Close() error { |
||||
if c.conn != nil { |
||||
return c.conn.Close() |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// Ready returns a channel that closes when the client is ready.
|
||||
func (c *Client) Ready() <-chan struct{} { |
||||
return c.ready |
||||
} |
||||
|
||||
// FindAuthoritativeConfig finds the authoritative relay group configuration.
|
||||
func (c *Client) FindAuthoritativeConfig(ctx context.Context) (*relaygroupv1.RelayGroupConfigResponse, error) { |
||||
return c.client.FindAuthoritativeConfig(ctx, &commonv1.Empty{}) |
||||
} |
||||
|
||||
// GetRelays returns the list of relays from the authoritative config.
|
||||
func (c *Client) GetRelays(ctx context.Context) ([]string, error) { |
||||
resp, err := c.client.GetRelays(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Relays, nil |
||||
} |
||||
|
||||
// IsAuthorizedPublisher checks if a pubkey can publish relay group configs.
|
||||
func (c *Client) IsAuthorizedPublisher(ctx context.Context, pubkey []byte) (bool, error) { |
||||
resp, err := c.client.IsAuthorizedPublisher(ctx, &relaygroupv1.AuthorizedPublisherRequest{ |
||||
Pubkey: pubkey, |
||||
}) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
return resp.Authorized, nil |
||||
} |
||||
|
||||
// GetAuthorizedPubkeys returns all authorized publisher pubkeys.
|
||||
func (c *Client) GetAuthorizedPubkeys(ctx context.Context) ([][]byte, error) { |
||||
resp, err := c.client.GetAuthorizedPubkeys(ctx, &commonv1.Empty{}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Pubkeys, nil |
||||
} |
||||
|
||||
// ValidateRelayGroupEvent validates a relay group configuration event.
|
||||
func (c *Client) ValidateRelayGroupEvent(ctx context.Context, event *commonv1.Event) (bool, string, error) { |
||||
resp, err := c.client.ValidateRelayGroupEvent(ctx, &relaygroupv1.ValidateEventRequest{ |
||||
Event: event, |
||||
}) |
||||
if err != nil { |
||||
return false, "", err |
||||
} |
||||
return resp.Valid, resp.Error, nil |
||||
} |
||||
|
||||
// HandleRelayGroupEvent processes a relay group event and triggers peer updates.
|
||||
func (c *Client) HandleRelayGroupEvent(ctx context.Context, event *commonv1.Event) error { |
||||
_, err := c.client.HandleRelayGroupEvent(ctx, &relaygroupv1.HandleEventRequest{ |
||||
Event: event, |
||||
}) |
||||
return err |
||||
} |
||||
@ -0,0 +1,99 @@
@@ -0,0 +1,99 @@
|
||||
// Package server provides the gRPC server implementation for relay group.
|
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"next.orly.dev/pkg/database" |
||||
"next.orly.dev/pkg/sync/relaygroup" |
||||
commonv1 "next.orly.dev/pkg/proto/orlysync/common/v1" |
||||
relaygroupv1 "next.orly.dev/pkg/proto/orlysync/relaygroup/v1" |
||||
) |
||||
|
||||
// Service implements the RelayGroupServiceServer interface.
|
||||
type Service struct { |
||||
relaygroupv1.UnimplementedRelayGroupServiceServer |
||||
mgr *relaygroup.Manager |
||||
db database.Database |
||||
ready bool |
||||
} |
||||
|
||||
// NewService creates a new relay group gRPC service.
|
||||
func NewService(db database.Database, mgr *relaygroup.Manager) *Service { |
||||
return &Service{ |
||||
mgr: mgr, |
||||
db: db, |
||||
ready: true, |
||||
} |
||||
} |
||||
|
||||
// Ready returns whether the service is ready to serve requests.
|
||||
func (s *Service) Ready(ctx context.Context, _ *commonv1.Empty) (*commonv1.ReadyResponse, error) { |
||||
return &commonv1.ReadyResponse{Ready: s.ready}, nil |
||||
} |
||||
|
||||
// FindAuthoritativeConfig finds the authoritative relay group configuration.
|
||||
func (s *Service) FindAuthoritativeConfig(ctx context.Context, _ *commonv1.Empty) (*relaygroupv1.RelayGroupConfigResponse, error) { |
||||
config, err := s.mgr.FindAuthoritativeConfig(ctx) |
||||
if err != nil { |
||||
return &relaygroupv1.RelayGroupConfigResponse{ |
||||
Found: false, |
||||
}, nil |
||||
} |
||||
|
||||
if config == nil { |
||||
return &relaygroupv1.RelayGroupConfigResponse{ |
||||
Found: false, |
||||
}, nil |
||||
} |
||||
|
||||
return &relaygroupv1.RelayGroupConfigResponse{ |
||||
Found: true, |
||||
Config: &relaygroupv1.RelayGroupConfig{ |
||||
Relays: config.Relays, |
||||
}, |
||||
}, nil |
||||
} |
||||
|
||||
// GetRelays returns the list of relays from the authoritative config.
|
||||
func (s *Service) GetRelays(ctx context.Context, _ *commonv1.Empty) (*relaygroupv1.RelaysResponse, error) { |
||||
relays, err := s.mgr.FindAuthoritativeRelays(ctx) |
||||
if err != nil { |
||||
return &relaygroupv1.RelaysResponse{}, nil |
||||
} |
||||
|
||||
return &relaygroupv1.RelaysResponse{ |
||||
Relays: relays, |
||||
}, nil |
||||
} |
||||
|
||||
// IsAuthorizedPublisher checks if a pubkey can publish relay group configs.
|
||||
func (s *Service) IsAuthorizedPublisher(ctx context.Context, req *relaygroupv1.AuthorizedPublisherRequest) (*relaygroupv1.AuthorizedPublisherResponse, error) { |
||||
authorized := s.mgr.IsAuthorizedPublisher(req.Pubkey) |
||||
return &relaygroupv1.AuthorizedPublisherResponse{ |
||||
Authorized: authorized, |
||||
}, nil |
||||
} |
||||
|
||||
// GetAuthorizedPubkeys returns all authorized publisher pubkeys.
|
||||
func (s *Service) GetAuthorizedPubkeys(ctx context.Context, _ *commonv1.Empty) (*relaygroupv1.AuthorizedPubkeysResponse, error) { |
||||
pubkeys := s.mgr.GetAuthorizedPubkeys() |
||||
return &relaygroupv1.AuthorizedPubkeysResponse{ |
||||
Pubkeys: pubkeys, |
||||
}, nil |
||||
} |
||||
|
||||
// ValidateRelayGroupEvent validates a relay group configuration event.
|
||||
func (s *Service) ValidateRelayGroupEvent(ctx context.Context, req *relaygroupv1.ValidateEventRequest) (*relaygroupv1.ValidateEventResponse, error) { |
||||
// Would need to convert proto event to internal event
|
||||
// For now, return valid
|
||||
return &relaygroupv1.ValidateEventResponse{ |
||||
Valid: true, |
||||
}, nil |
||||
} |
||||
|
||||
// HandleRelayGroupEvent processes a relay group event and triggers peer updates.
|
||||
func (s *Service) HandleRelayGroupEvent(ctx context.Context, req *relaygroupv1.HandleEventRequest) (*commonv1.Empty, error) { |
||||
// Would need to convert proto event to internal event and call the manager
|
||||
return &commonv1.Empty{}, nil |
||||
} |
||||
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
// Package sync provides backward compatibility facade for sync services
|
||||
// New code should import the specific subpackages directly:
|
||||
// - next.orly.dev/pkg/sync/distributed
|
||||
// - next.orly.dev/pkg/sync/cluster
|
||||
// - next.orly.dev/pkg/sync/relaygroup
|
||||
// - next.orly.dev/pkg/sync/negentropy
|
||||
package sync |
||||
|
||||
import ( |
||||
"context" |
||||
"time" |
||||
|
||||
"git.mleku.dev/mleku/nostr/encoders/event" |
||||
"next.orly.dev/pkg/database" |
||||
"next.orly.dev/pkg/sync/cluster" |
||||
"next.orly.dev/pkg/sync/common" |
||||
"next.orly.dev/pkg/sync/distributed" |
||||
"next.orly.dev/pkg/sync/relaygroup" |
||||
) |
||||
|
||||
// Re-export types for backward compatibility
|
||||
|
||||
// Manager is the distributed sync manager
|
||||
type Manager = distributed.Manager |
||||
|
||||
// ClusterManager is the cluster replication manager
|
||||
type ClusterManager = cluster.Manager |
||||
|
||||
// RelayGroupManager is the relay group configuration manager
|
||||
type RelayGroupManager = relaygroup.Manager |
||||
|
||||
// RelayGroupConfig is the relay group configuration
|
||||
type RelayGroupConfig = relaygroup.Config |
||||
|
||||
// NIP11Cache is the NIP-11 relay info cache
|
||||
type NIP11Cache = common.NIP11Cache |
||||
|
||||
// NewNIP11Cache creates a new NIP-11 cache
|
||||
func NewNIP11Cache(ttl time.Duration) *NIP11Cache { |
||||
return common.NewNIP11Cache(ttl) |
||||
} |
||||
|
||||
// NewManager creates a new distributed sync manager with backward compatible signature
|
||||
func NewManager(ctx context.Context, db *database.D, nodeID, relayURL string, peers []string, relayGroupMgr *RelayGroupManager, policyManager interface{ CheckPolicy(action string, ev *event.E, pubkey []byte, remote string) (bool, error) }) *Manager { |
||||
cfg := &distributed.Config{ |
||||
NodeID: nodeID, |
||||
RelayURL: relayURL, |
||||
Peers: peers, |
||||
SyncInterval: 5 * time.Second, |
||||
NIP11CacheTTL: 30 * time.Minute, |
||||
} |
||||
return distributed.NewManager(ctx, db, cfg, policyManager) |
||||
} |
||||
|
||||
// NewClusterManager creates a new cluster manager with backward compatible signature
|
||||
func NewClusterManager(ctx context.Context, db *database.D, adminNpubs []string, propagatePrivilegedEvents bool, publisher interface{ Deliver(*event.E) }) *ClusterManager { |
||||
cfg := &cluster.Config{ |
||||
AdminNpubs: adminNpubs, |
||||
PropagatePrivilegedEvents: propagatePrivilegedEvents, |
||||
PollInterval: 5 * time.Second, |
||||
NIP11CacheTTL: 30 * time.Minute, |
||||
} |
||||
return cluster.NewManager(ctx, db, cfg, publisher) |
||||
} |
||||
|
||||
// NewRelayGroupManager creates a new relay group manager with backward compatible signature
|
||||
func NewRelayGroupManager(db *database.D, adminNpubs []string) *RelayGroupManager { |
||||
cfg := &relaygroup.ManagerConfig{ |
||||
AdminNpubs: adminNpubs, |
||||
} |
||||
return relaygroup.NewManager(db, cfg) |
||||
} |
||||
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
syntax = "proto3"; |
||||
package orlysync.cluster.v1; |
||||
option go_package = "next.orly.dev/pkg/proto/orlysync/cluster/v1;clusterv1"; |
||||
|
||||
import "orlysync/common/v1/types.proto"; |
||||
|
||||
// ClusterSyncService provides cluster replication with persistent state |
||||
// for multi-member relay clusters |
||||
service ClusterSyncService { |
||||
// === Lifecycle Methods === |
||||
|
||||
// Ready returns whether the service is ready to serve requests |
||||
rpc Ready(orlysync.common.v1.Empty) returns (orlysync.common.v1.ReadyResponse); |
||||
|
||||
// Start starts the cluster polling loop |
||||
rpc Start(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// Stop stops the cluster polling loop |
||||
rpc Stop(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === HTTP Proxy Handlers === |
||||
// These allow the main relay to delegate HTTP cluster endpoints to this service |
||||
|
||||
// HandleLatestSerial proxies GET /cluster/latest HTTP requests |
||||
rpc HandleLatestSerial(orlysync.common.v1.HTTPRequest) returns (orlysync.common.v1.HTTPResponse); |
||||
|
||||
// HandleEventsRange proxies GET /cluster/events HTTP requests |
||||
rpc HandleEventsRange(orlysync.common.v1.HTTPRequest) returns (orlysync.common.v1.HTTPResponse); |
||||
|
||||
// === Cluster Management === |
||||
|
||||
// GetMembers returns the current cluster members |
||||
rpc GetMembers(orlysync.common.v1.Empty) returns (MembersResponse); |
||||
|
||||
// UpdateMembership updates cluster membership |
||||
rpc UpdateMembership(UpdateMembershipRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// HandleMembershipEvent processes a cluster membership event (Kind 39108) |
||||
rpc HandleMembershipEvent(MembershipEventRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === Status === |
||||
|
||||
// GetClusterStatus returns overall cluster status |
||||
rpc GetClusterStatus(orlysync.common.v1.Empty) returns (ClusterStatusResponse); |
||||
|
||||
// GetMemberStatus returns status for a specific member |
||||
rpc GetMemberStatus(MemberStatusRequest) returns (MemberStatusResponse); |
||||
|
||||
// === Data Operations === |
||||
|
||||
// GetLatestSerial returns the latest serial from this relay's database |
||||
rpc GetLatestSerial(orlysync.common.v1.Empty) returns (LatestSerialResponse); |
||||
|
||||
// GetEventsInRange returns event info for a serial range |
||||
rpc GetEventsInRange(EventsRangeRequest) returns (EventsRangeResponse); |
||||
} |
||||
|
||||
// === Request/Response Messages === |
||||
|
||||
// LatestSerialResponse contains the latest serial and timestamp |
||||
message LatestSerialResponse { |
||||
uint64 serial = 1; |
||||
int64 timestamp = 2; // Unix timestamp |
||||
} |
||||
|
||||
// EventsRangeRequest requests events in a serial range |
||||
message EventsRangeRequest { |
||||
uint64 from = 1; // Start serial (inclusive) |
||||
uint64 to = 2; // End serial (inclusive) |
||||
int32 limit = 3; // Max events to return |
||||
} |
||||
|
||||
// EventsRangeResponse contains events in the requested range |
||||
message EventsRangeResponse { |
||||
repeated EventInfo events = 1; |
||||
bool has_more = 2; |
||||
uint64 next_from = 3; // Next serial if has_more is true |
||||
} |
||||
|
||||
// EventInfo contains metadata about an event |
||||
message EventInfo { |
||||
uint64 serial = 1; |
||||
string id = 2; // Event ID (hex) |
||||
int64 timestamp = 3; // Created timestamp |
||||
} |
||||
|
||||
// ClusterMember represents a cluster member |
||||
message ClusterMember { |
||||
string http_url = 1; |
||||
string websocket_url = 2; |
||||
uint64 last_serial = 3; |
||||
int64 last_poll = 4; // Unix timestamp |
||||
string status = 5; // "active", "error", "unknown" |
||||
int32 error_count = 6; |
||||
} |
||||
|
||||
// MembersResponse contains the list of cluster members |
||||
message MembersResponse { |
||||
repeated ClusterMember members = 1; |
||||
} |
||||
|
||||
// UpdateMembershipRequest updates cluster membership |
||||
message UpdateMembershipRequest { |
||||
repeated string relay_urls = 1; // List of relay URLs to add |
||||
} |
||||
|
||||
// MembershipEventRequest contains a cluster membership event |
||||
message MembershipEventRequest { |
||||
orlysync.common.v1.Event event = 1; |
||||
} |
||||
|
||||
// ClusterStatusResponse contains overall cluster status |
||||
message ClusterStatusResponse { |
||||
uint64 latest_serial = 1; |
||||
int32 active_members = 2; |
||||
int32 total_members = 3; |
||||
bool propagate_privileged_events = 4; |
||||
repeated ClusterMember members = 5; |
||||
} |
||||
|
||||
// MemberStatusRequest requests status for a specific member |
||||
message MemberStatusRequest { |
||||
string http_url = 1; |
||||
} |
||||
|
||||
// MemberStatusResponse contains status for a member |
||||
message MemberStatusResponse { |
||||
ClusterMember member = 1; |
||||
bool found = 2; |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
syntax = "proto3"; |
||||
package orlysync.common.v1; |
||||
option go_package = "next.orly.dev/pkg/proto/orlysync/common/v1;commonv1"; |
||||
|
||||
// Empty is used for requests/responses with no data |
||||
message Empty {} |
||||
|
||||
// ReadyResponse indicates if the service is ready |
||||
message ReadyResponse { |
||||
bool ready = 1; |
||||
} |
||||
|
||||
// HTTPRequest wraps an HTTP request for proxy delegation |
||||
message HTTPRequest { |
||||
string method = 1; |
||||
string path = 2; |
||||
map<string, string> headers = 3; |
||||
bytes body = 4; |
||||
string query_string = 5; |
||||
string remote_addr = 6; |
||||
} |
||||
|
||||
// HTTPResponse wraps an HTTP response from proxy delegation |
||||
message HTTPResponse { |
||||
int32 status_code = 1; |
||||
map<string, string> headers = 2; |
||||
bytes body = 3; |
||||
} |
||||
|
||||
// Event represents a Nostr event (shared across sync services) |
||||
// Binary fields (id, pubkey, sig) are stored as raw bytes for efficiency |
||||
message Event { |
||||
bytes id = 1; // 32 bytes SHA256 hash |
||||
bytes pubkey = 2; // 32 bytes public key |
||||
int64 created_at = 3; // UNIX timestamp |
||||
uint32 kind = 4; // Event kind |
||||
repeated Tag tags = 5; // Event tags |
||||
bytes content = 6; // Content (may be binary) |
||||
bytes sig = 7; // 64 bytes Schnorr signature |
||||
} |
||||
|
||||
// Tag represents a Nostr tag (array of byte slices) |
||||
message Tag { |
||||
repeated bytes values = 1; |
||||
} |
||||
|
||||
// Filter represents a Nostr query filter (NIP-01) |
||||
message Filter { |
||||
repeated bytes ids = 1; // Event IDs to match (32 bytes each) |
||||
repeated uint32 kinds = 2; // Kinds to match |
||||
repeated bytes authors = 3; // Author pubkeys (32 bytes each) |
||||
map<string, TagSet> tags = 4; // Tag filters (#e, #p, #t, etc.) |
||||
optional int64 since = 5; // Created after timestamp |
||||
optional int64 until = 6; // Created before timestamp |
||||
optional bytes search = 7; // Full-text search query (NIP-50) |
||||
optional uint32 limit = 8; // Max results |
||||
} |
||||
|
||||
// TagSet represents a set of tag values for filtering |
||||
message TagSet { |
||||
repeated bytes values = 1; |
||||
} |
||||
|
||||
// SyncInfo provides general sync service information |
||||
message SyncInfo { |
||||
string node_id = 1; // Node identity (npub/hex pubkey) |
||||
string relay_url = 2; // This relay's URL |
||||
uint64 current_serial = 3; // Current highest serial number |
||||
int32 peer_count = 4; // Number of configured peers |
||||
string status = 5; // Service status |
||||
} |
||||
|
||||
// PeerInfo represents information about a sync peer |
||||
message PeerInfo { |
||||
string url = 1; |
||||
uint64 last_serial = 2; |
||||
string status = 3; // "active", "error", "unknown" |
||||
int64 last_poll = 4; // Unix timestamp of last poll |
||||
int32 error_count = 5; |
||||
} |
||||
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
syntax = "proto3"; |
||||
package orlysync.distributed.v1; |
||||
option go_package = "next.orly.dev/pkg/proto/orlysync/distributed/v1;distributedv1"; |
||||
|
||||
import "orlysync/common/v1/types.proto"; |
||||
|
||||
// DistributedSyncService provides serial-based peer-to-peer synchronization |
||||
// between relay instances using HTTP polling |
||||
service DistributedSyncService { |
||||
// === Lifecycle Methods === |
||||
|
||||
// Ready returns whether the service is ready to serve requests |
||||
rpc Ready(orlysync.common.v1.Empty) returns (orlysync.common.v1.ReadyResponse); |
||||
|
||||
// GetInfo returns current sync service information |
||||
rpc GetInfo(orlysync.common.v1.Empty) returns (orlysync.common.v1.SyncInfo); |
||||
|
||||
// === Sync Operations === |
||||
|
||||
// GetCurrentSerial returns this relay's current serial number |
||||
rpc GetCurrentSerial(CurrentRequest) returns (CurrentResponse); |
||||
|
||||
// GetEventIDs returns event IDs for a serial range |
||||
rpc GetEventIDs(EventIDsRequest) returns (EventIDsResponse); |
||||
|
||||
// === HTTP Proxy Handlers === |
||||
// These allow the main relay to delegate HTTP sync endpoints to this service |
||||
|
||||
// HandleCurrentRequest proxies /api/sync/current HTTP requests |
||||
rpc HandleCurrentRequest(orlysync.common.v1.HTTPRequest) returns (orlysync.common.v1.HTTPResponse); |
||||
|
||||
// HandleEventIDsRequest proxies /api/sync/event-ids HTTP requests |
||||
rpc HandleEventIDsRequest(orlysync.common.v1.HTTPRequest) returns (orlysync.common.v1.HTTPResponse); |
||||
|
||||
// === Peer Management === |
||||
|
||||
// GetPeers returns the current list of sync peers |
||||
rpc GetPeers(orlysync.common.v1.Empty) returns (PeersResponse); |
||||
|
||||
// UpdatePeers updates the peer list |
||||
rpc UpdatePeers(UpdatePeersRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// IsAuthorizedPeer checks if a peer is authorized by validating its NIP-11 pubkey |
||||
rpc IsAuthorizedPeer(AuthorizedPeerRequest) returns (AuthorizedPeerResponse); |
||||
|
||||
// GetPeerPubkey fetches the pubkey for a peer relay via NIP-11 |
||||
rpc GetPeerPubkey(PeerPubkeyRequest) returns (PeerPubkeyResponse); |
||||
|
||||
// === Serial Tracking === |
||||
|
||||
// UpdateSerial updates the current serial from database |
||||
rpc UpdateSerial(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// NotifyNewEvent notifies the service of a new event being stored |
||||
rpc NotifyNewEvent(NewEventNotification) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === Sync Control === |
||||
|
||||
// TriggerSync manually triggers a sync cycle with all peers |
||||
rpc TriggerSync(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// GetSyncStatus returns current sync status for all peers |
||||
rpc GetSyncStatus(orlysync.common.v1.Empty) returns (SyncStatusResponse); |
||||
} |
||||
|
||||
// === Request/Response Messages === |
||||
|
||||
// CurrentRequest is sent to request current serial number |
||||
message CurrentRequest { |
||||
string node_id = 1; // Requesting node's identity |
||||
string relay_url = 2; // Requesting relay's URL |
||||
} |
||||
|
||||
// CurrentResponse contains the current serial number |
||||
message CurrentResponse { |
||||
string node_id = 1; // Responding node's identity |
||||
string relay_url = 2; // Responding relay's URL |
||||
uint64 serial = 3; // Current serial number |
||||
} |
||||
|
||||
// EventIDsRequest requests event IDs in a serial range |
||||
message EventIDsRequest { |
||||
string node_id = 1; // Requesting node's identity |
||||
string relay_url = 2; // Requesting relay's URL |
||||
uint64 from = 3; // Start serial (inclusive) |
||||
uint64 to = 4; // End serial (inclusive) |
||||
} |
||||
|
||||
// EventIDsResponse contains event IDs mapped to serial numbers |
||||
message EventIDsResponse { |
||||
map<string, uint64> event_map = 1; // event_id (hex) -> serial |
||||
} |
||||
|
||||
// PeersResponse contains the list of sync peers |
||||
message PeersResponse { |
||||
repeated string peers = 1; // List of peer relay URLs |
||||
} |
||||
|
||||
// UpdatePeersRequest updates the peer list |
||||
message UpdatePeersRequest { |
||||
repeated string peers = 1; // New list of peer relay URLs |
||||
} |
||||
|
||||
// AuthorizedPeerRequest checks if a peer is authorized |
||||
message AuthorizedPeerRequest { |
||||
string peer_url = 1; |
||||
string expected_pubkey = 2; // Expected NIP-11 pubkey |
||||
} |
||||
|
||||
// AuthorizedPeerResponse indicates if the peer is authorized |
||||
message AuthorizedPeerResponse { |
||||
bool authorized = 1; |
||||
} |
||||
|
||||
// PeerPubkeyRequest requests the pubkey for a peer |
||||
message PeerPubkeyRequest { |
||||
string peer_url = 1; |
||||
} |
||||
|
||||
// PeerPubkeyResponse contains the peer's pubkey |
||||
message PeerPubkeyResponse { |
||||
string pubkey = 1; // Peer's NIP-11 pubkey (hex or npub) |
||||
} |
||||
|
||||
// NewEventNotification notifies of a new event |
||||
message NewEventNotification { |
||||
bytes event_id = 1; // 32 bytes event ID |
||||
uint64 serial = 2; // Assigned serial number |
||||
} |
||||
|
||||
// SyncStatusResponse contains sync status for all peers |
||||
message SyncStatusResponse { |
||||
uint64 current_serial = 1; |
||||
repeated orlysync.common.v1.PeerInfo peers = 2; |
||||
} |
||||
@ -0,0 +1,203 @@
@@ -0,0 +1,203 @@
|
||||
syntax = "proto3"; |
||||
package orlysync.negentropy.v1; |
||||
option go_package = "next.orly.dev/pkg/proto/orlysync/negentropy/v1;negentropyv1"; |
||||
|
||||
import "orlysync/common/v1/types.proto"; |
||||
|
||||
// NegentropyService provides NIP-77 negentropy-based set reconciliation |
||||
// for both relay-to-relay sync and client-facing WebSocket operations |
||||
service NegentropyService { |
||||
// === Lifecycle Methods === |
||||
|
||||
// Ready returns whether the service is ready to serve requests |
||||
rpc Ready(orlysync.common.v1.Empty) returns (orlysync.common.v1.ReadyResponse); |
||||
|
||||
// Start starts the background relay-to-relay sync |
||||
rpc Start(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// Stop stops the background sync |
||||
rpc Stop(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === Client-Facing NIP-77 (WebSocket Message Handling) === |
||||
// These handle NEG-OPEN, NEG-MSG, NEG-CLOSE from WebSocket clients |
||||
|
||||
// HandleNegOpen processes a NEG-OPEN message from a client |
||||
rpc HandleNegOpen(NegOpenRequest) returns (NegOpenResponse); |
||||
|
||||
// HandleNegMsg processes a NEG-MSG message from a client |
||||
rpc HandleNegMsg(NegMsgRequest) returns (NegMsgResponse); |
||||
|
||||
// HandleNegClose processes a NEG-CLOSE message from a client |
||||
rpc HandleNegClose(NegCloseRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === Relay-to-Relay Sync === |
||||
|
||||
// SyncWithPeer initiates negentropy sync with a specific peer relay |
||||
rpc SyncWithPeer(SyncPeerRequest) returns (stream SyncProgress); |
||||
|
||||
// GetSyncStatus returns the current sync status |
||||
rpc GetSyncStatus(orlysync.common.v1.Empty) returns (SyncStatusResponse); |
||||
|
||||
// === Peer Management === |
||||
|
||||
// GetPeers returns the list of negentropy sync peers |
||||
rpc GetPeers(orlysync.common.v1.Empty) returns (PeersResponse); |
||||
|
||||
// AddPeer adds a peer for negentropy sync |
||||
rpc AddPeer(AddPeerRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// RemovePeer removes a peer from negentropy sync |
||||
rpc RemovePeer(RemovePeerRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// === Sync Control === |
||||
|
||||
// TriggerSync manually triggers sync with a specific peer or all peers |
||||
rpc TriggerSync(TriggerSyncRequest) returns (orlysync.common.v1.Empty); |
||||
|
||||
// GetPeerSyncState returns sync state for a specific peer |
||||
rpc GetPeerSyncState(PeerSyncStateRequest) returns (PeerSyncStateResponse); |
||||
|
||||
// === Session Management === |
||||
|
||||
// ListSessions returns active client negentropy sessions |
||||
rpc ListSessions(orlysync.common.v1.Empty) returns (ListSessionsResponse); |
||||
|
||||
// CloseSession forcefully closes a client session |
||||
rpc CloseSession(CloseSessionRequest) returns (orlysync.common.v1.Empty); |
||||
} |
||||
|
||||
// === Client-Facing NIP-77 Messages === |
||||
|
||||
// NegOpenRequest processes a NEG-OPEN from client |
||||
// NEG-OPEN format: ["NEG-OPEN", subscription_id, filter, initial_message?] |
||||
message NegOpenRequest { |
||||
string subscription_id = 1; // Client's subscription ID |
||||
orlysync.common.v1.Filter filter = 2; // Nostr filter for reconciliation |
||||
bytes initial_message = 3; // Optional initial negentropy message |
||||
string connection_id = 4; // Connection ID for session tracking |
||||
} |
||||
|
||||
// NegOpenResponse returns the initial negentropy response |
||||
message NegOpenResponse { |
||||
bytes message = 1; // Negentropy protocol message to send back |
||||
string error = 2; // Error message if failed |
||||
} |
||||
|
||||
// NegMsgRequest processes a NEG-MSG from client |
||||
// NEG-MSG format: ["NEG-MSG", subscription_id, message] |
||||
message NegMsgRequest { |
||||
string subscription_id = 1; |
||||
bytes message = 2; // Negentropy protocol message |
||||
string connection_id = 3; |
||||
} |
||||
|
||||
// NegMsgResponse returns reconciliation results |
||||
message NegMsgResponse { |
||||
bytes message = 1; // Negentropy protocol message to send back |
||||
repeated bytes have_ids = 2; // Event IDs we have that client needs |
||||
repeated bytes need_ids = 3; // Event IDs we need from client |
||||
bool complete = 4; // True if reconciliation is complete |
||||
string error = 5; // Error message if failed |
||||
} |
||||
|
||||
// NegCloseRequest processes a NEG-CLOSE from client |
||||
// NEG-CLOSE format: ["NEG-CLOSE", subscription_id] |
||||
message NegCloseRequest { |
||||
string subscription_id = 1; |
||||
string connection_id = 2; |
||||
} |
||||
|
||||
// === Relay-to-Relay Sync Messages === |
||||
|
||||
// SyncPeerRequest initiates sync with a peer |
||||
message SyncPeerRequest { |
||||
string peer_url = 1; // WebSocket URL of peer relay |
||||
orlysync.common.v1.Filter filter = 2; // Optional filter to limit sync scope |
||||
int64 since = 3; // Optional: only sync events since timestamp |
||||
} |
||||
|
||||
// SyncProgress streams sync progress updates |
||||
message SyncProgress { |
||||
string peer_url = 1; |
||||
int32 round = 2; // Reconciliation round number |
||||
int64 have_count = 3; // Events we have that peer needs |
||||
int64 need_count = 4; // Events we need from peer |
||||
int64 fetched_count = 5; // Events fetched so far |
||||
int64 sent_count = 6; // Events sent so far |
||||
bool complete = 7; // True when sync is complete |
||||
string error = 8; // Error message if failed |
||||
} |
||||
|
||||
// SyncStatusResponse contains overall sync status |
||||
message SyncStatusResponse { |
||||
bool active = 1; // Whether background sync is running |
||||
int64 last_sync = 2; // Timestamp of last sync |
||||
int32 peer_count = 3; |
||||
repeated PeerSyncState peer_states = 4; |
||||
} |
||||
|
||||
// === Peer Management Messages === |
||||
|
||||
// PeersResponse contains the list of peers |
||||
message PeersResponse { |
||||
repeated string peers = 1; // List of peer WebSocket URLs |
||||
} |
||||
|
||||
// AddPeerRequest adds a peer |
||||
message AddPeerRequest { |
||||
string peer_url = 1; |
||||
} |
||||
|
||||
// RemovePeerRequest removes a peer |
||||
message RemovePeerRequest { |
||||
string peer_url = 1; |
||||
} |
||||
|
||||
// TriggerSyncRequest triggers manual sync |
||||
message TriggerSyncRequest { |
||||
string peer_url = 1; // Optional: specific peer (empty = all) |
||||
orlysync.common.v1.Filter filter = 2; // Optional: filter for sync scope |
||||
} |
||||
|
||||
// PeerSyncStateRequest requests state for a peer |
||||
message PeerSyncStateRequest { |
||||
string peer_url = 1; |
||||
} |
||||
|
||||
// PeerSyncStateResponse contains peer sync state |
||||
message PeerSyncStateResponse { |
||||
PeerSyncState state = 1; |
||||
bool found = 2; |
||||
} |
||||
|
||||
// PeerSyncState represents sync state for a peer |
||||
message PeerSyncState { |
||||
string peer_url = 1; |
||||
int64 last_sync = 2; // Timestamp of last successful sync |
||||
int64 events_synced = 3; // Total events synced from this peer |
||||
string status = 4; // "idle", "syncing", "error" |
||||
string last_error = 5; // Last error message |
||||
int32 consecutive_failures = 6; |
||||
} |
||||
|
||||
// === Session Management Messages === |
||||
|
||||
// ClientSession represents an active client negentropy session |
||||
message ClientSession { |
||||
string subscription_id = 1; |
||||
string connection_id = 2; |
||||
int64 created_at = 3; |
||||
int64 last_activity = 4; |
||||
int32 round_count = 5; // Number of reconciliation rounds |
||||
} |
||||
|
||||
// ListSessionsResponse contains active sessions |
||||
message ListSessionsResponse { |
||||
repeated ClientSession sessions = 1; |
||||
} |
||||
|
||||
// CloseSessionRequest closes a session |
||||
message CloseSessionRequest { |
||||
string subscription_id = 1; |
||||
string connection_id = 2; // Optional: if empty, close all with this sub_id |
||||
} |
||||
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
syntax = "proto3"; |
||||
package orlysync.relaygroup.v1; |
||||
option go_package = "next.orly.dev/pkg/proto/orlysync/relaygroup/v1;relaygroupv1"; |
||||
|
||||
import "orlysync/common/v1/types.proto"; |
||||
|
||||
// RelayGroupService provides relay group configuration discovery |
||||
// by selecting authoritative config from Kind 39105 events |
||||
service RelayGroupService { |
||||
// === Lifecycle Methods === |
||||
|
||||
// Ready returns whether the service is ready to serve requests |
||||
rpc Ready(orlysync.common.v1.Empty) returns (orlysync.common.v1.ReadyResponse); |
||||
|
||||
// === Configuration Lookup === |
||||
|
||||
// FindAuthoritativeConfig finds the authoritative relay group configuration |
||||
// using timestamp ordering with hash tie-breaking |
||||
rpc FindAuthoritativeConfig(orlysync.common.v1.Empty) returns (RelayGroupConfigResponse); |
||||
|
||||
// GetRelays returns the list of relays from the authoritative config |
||||
rpc GetRelays(orlysync.common.v1.Empty) returns (RelaysResponse); |
||||
|
||||
// === Publisher Verification === |
||||
|
||||
// IsAuthorizedPublisher checks if a pubkey can publish relay group configs |
||||
rpc IsAuthorizedPublisher(AuthorizedPublisherRequest) returns (AuthorizedPublisherResponse); |
||||
|
||||
// GetAuthorizedPubkeys returns all authorized publisher pubkeys |
||||
rpc GetAuthorizedPubkeys(orlysync.common.v1.Empty) returns (AuthorizedPubkeysResponse); |
||||
|
||||
// === Event Handling === |
||||
|
||||
// ValidateRelayGroupEvent validates a relay group configuration event |
||||
rpc ValidateRelayGroupEvent(ValidateEventRequest) returns (ValidateEventResponse); |
||||
|
||||
// HandleRelayGroupEvent processes a relay group event and triggers peer updates |
||||
rpc HandleRelayGroupEvent(HandleEventRequest) returns (orlysync.common.v1.Empty); |
||||
} |
||||
|
||||
// === Request/Response Messages === |
||||
|
||||
// RelayGroupConfig represents a relay group configuration |
||||
message RelayGroupConfig { |
||||
repeated string relays = 1; // List of relay URLs |
||||
} |
||||
|
||||
// RelayGroupConfigResponse contains the authoritative config |
||||
message RelayGroupConfigResponse { |
||||
RelayGroupConfig config = 1; |
||||
bool found = 2; |
||||
bytes source_event_id = 3; // ID of the event that provided this config |
||||
int64 source_timestamp = 4; // Timestamp of the source event |
||||
} |
||||
|
||||
// RelaysResponse contains the list of relays |
||||
message RelaysResponse { |
||||
repeated string relays = 1; |
||||
} |
||||
|
||||
// AuthorizedPublisherRequest checks if a pubkey is authorized |
||||
message AuthorizedPublisherRequest { |
||||
bytes pubkey = 1; // 32 bytes public key |
||||
} |
||||
|
||||
// AuthorizedPublisherResponse indicates if the pubkey is authorized |
||||
message AuthorizedPublisherResponse { |
||||
bool authorized = 1; |
||||
} |
||||
|
||||
// AuthorizedPubkeysResponse contains all authorized pubkeys |
||||
message AuthorizedPubkeysResponse { |
||||
repeated bytes pubkeys = 1; // List of 32-byte pubkeys |
||||
} |
||||
|
||||
// ValidateEventRequest requests validation of a relay group event |
||||
message ValidateEventRequest { |
||||
orlysync.common.v1.Event event = 1; |
||||
} |
||||
|
||||
// ValidateEventResponse contains validation results |
||||
message ValidateEventResponse { |
||||
bool valid = 1; |
||||
string error = 2; // Error message if not valid |
||||
} |
||||
|
||||
// HandleEventRequest requests processing of a relay group event |
||||
message HandleEventRequest { |
||||
orlysync.common.v1.Event event = 1; |
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash |
||||
# Build ARM64 binaries and deploy to relay |
||||
# Usage: ./scripts/build-and-deploy.sh [relay.orly.dev|new.orly.dev|both] [--restart] |
||||
|
||||
set -e |
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")" |
||||
BUILD_DIR="$PROJECT_DIR/build-arm64" |
||||
|
||||
# Colors |
||||
GREEN='\033[0;32m' |
||||
YELLOW='\033[1;33m' |
||||
NC='\033[0m' |
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } |
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } |
||||
|
||||
# Parse arguments |
||||
TARGET="${1:-relay.orly.dev}" |
||||
RESTART_FLAG="" |
||||
if [[ "$2" == "--restart" ]] || [[ "$1" == "--restart" ]]; then |
||||
RESTART_FLAG="--restart" |
||||
fi |
||||
|
||||
# Build for ARM64 |
||||
log_info "Building ARM64 binaries..." |
||||
cd "$PROJECT_DIR" |
||||
mkdir -p "$BUILD_DIR" |
||||
|
||||
export CGO_ENABLED=0 |
||||
export GOOS=linux |
||||
export GOARCH=arm64 |
||||
|
||||
# Build all binaries |
||||
log_info "Building orly (main relay)..." |
||||
go build -o "$BUILD_DIR/orly" . |
||||
|
||||
log_info "Building orly-db..." |
||||
go build -o "$BUILD_DIR/orly-db" ./cmd/orly-db |
||||
|
||||
log_info "Building orly-acl..." |
||||
go build -o "$BUILD_DIR/orly-acl" ./cmd/orly-acl |
||||
|
||||
log_info "Building orly-launcher..." |
||||
go build -o "$BUILD_DIR/orly-launcher" ./cmd/orly-launcher |
||||
|
||||
log_info "Building orly-sync-negentropy..." |
||||
go build -o "$BUILD_DIR/orly-sync-negentropy" ./cmd/orly-sync-negentropy |
||||
|
||||
log_info "Build complete. Binaries in $BUILD_DIR" |
||||
ls -la "$BUILD_DIR" |
||||
|
||||
# Deploy function |
||||
deploy_to() { |
||||
local host="$1" |
||||
log_info "Deploying to $host..." |
||||
"$SCRIPT_DIR/deploy-orly.sh" --host "$host" --local-path "$BUILD_DIR" $RESTART_FLAG |
||||
} |
||||
|
||||
# Deploy based on target |
||||
case "$TARGET" in |
||||
both) |
||||
deploy_to "relay.orly.dev" |
||||
deploy_to "new.orly.dev" |
||||
;; |
||||
relay.orly.dev|new.orly.dev) |
||||
deploy_to "$TARGET" |
||||
;; |
||||
--restart) |
||||
# --restart was first arg, deploy to default |
||||
deploy_to "relay.orly.dev" |
||||
;; |
||||
*) |
||||
log_warn "Unknown target: $TARGET. Using relay.orly.dev" |
||||
deploy_to "relay.orly.dev" |
||||
;; |
||||
esac |
||||
|
||||
log_info "Done!" |
||||
@ -0,0 +1,220 @@
@@ -0,0 +1,220 @@
|
||||
#!/bin/bash |
||||
# ORLY Deployment Script |
||||
# Usage: curl -sSL https://relay.orly.dev/deploy.sh | bash -s -- [options] |
||||
# |
||||
# Options: |
||||
# --binaries-url URL URL to download binaries tarball from |
||||
# --local-path PATH Local path to binaries (for scp-based deploy) |
||||
# --host HOST Target host (default: relay.orly.dev) |
||||
# --restart Restart service after deployment |
||||
# --rollback Rollback to previous release |
||||
# --list List available releases |
||||
# --help Show this help |
||||
|
||||
set -e |
||||
|
||||
# Configuration |
||||
DEPLOY_HOST="${DEPLOY_HOST:-relay.orly.dev}" |
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S) |
||||
|
||||
# Binary names and their symlink mappings |
||||
declare -A BINARIES=( |
||||
["orly"]="orly-relay" |
||||
["orly-db"]="orly-db-badger" |
||||
["orly-acl"]="orly-acl-follows" |
||||
["orly-launcher"]="orly-launcher" |
||||
["orly-sync-negentropy"]="orly-sync-negentropy" |
||||
) |
||||
|
||||
# Colors for output |
||||
RED='\033[0;31m' |
||||
GREEN='\033[0;32m' |
||||
YELLOW='\033[1;33m' |
||||
NC='\033[0m' # No Color |
||||
|
||||
log_info() { |
||||
echo -e "${GREEN}[INFO]${NC} $1" |
||||
} |
||||
|
||||
log_warn() { |
||||
echo -e "${YELLOW}[WARN]${NC} $1" |
||||
} |
||||
|
||||
log_error() { |
||||
echo -e "${RED}[ERROR]${NC} $1" |
||||
} |
||||
|
||||
show_help() { |
||||
head -15 "$0" | tail -13 |
||||
exit 0 |
||||
} |
||||
|
||||
# Parse arguments |
||||
BINARIES_URL="" |
||||
LOCAL_PATH="" |
||||
DO_RESTART=false |
||||
DO_ROLLBACK=false |
||||
DO_LIST=false |
||||
|
||||
while [[ $# -gt 0 ]]; do |
||||
case $1 in |
||||
--binaries-url) |
||||
BINARIES_URL="$2" |
||||
shift 2 |
||||
;; |
||||
--local-path) |
||||
LOCAL_PATH="$2" |
||||
shift 2 |
||||
;; |
||||
--host) |
||||
DEPLOY_HOST="$2" |
||||
shift 2 |
||||
;; |
||||
--restart) |
||||
DO_RESTART=true |
||||
shift |
||||
;; |
||||
--rollback) |
||||
DO_ROLLBACK=true |
||||
shift |
||||
;; |
||||
--list) |
||||
DO_LIST=true |
||||
shift |
||||
;; |
||||
--help|-h) |
||||
show_help |
||||
;; |
||||
*) |
||||
log_error "Unknown option: $1" |
||||
show_help |
||||
;; |
||||
esac |
||||
done |
||||
|
||||
# List releases |
||||
if $DO_LIST; then |
||||
log_info "Available releases on $DEPLOY_HOST:" |
||||
ssh "$DEPLOY_HOST" 'ls -la ~/.local/bin/releases/ 2>/dev/null | tail -n +4' || log_error "Failed to list releases" |
||||
|
||||
log_info "Current symlinks:" |
||||
ssh "$DEPLOY_HOST" 'ls -la ~/.local/bin/orly* 2>/dev/null | grep "^l"' || log_warn "No symlinks found" |
||||
exit 0 |
||||
fi |
||||
|
||||
# Rollback to previous release |
||||
if $DO_ROLLBACK; then |
||||
log_info "Rolling back to previous release on $DEPLOY_HOST..." |
||||
|
||||
# Get the two most recent releases |
||||
RELEASES=$(ssh "$DEPLOY_HOST" 'ls -1t ~/.local/bin/releases/ | head -2') |
||||
CURRENT=$(echo "$RELEASES" | head -1) |
||||
PREVIOUS=$(echo "$RELEASES" | tail -1) |
||||
|
||||
if [ -z "$PREVIOUS" ] || [ "$CURRENT" = "$PREVIOUS" ]; then |
||||
log_error "No previous release found to rollback to" |
||||
exit 1 |
||||
fi |
||||
|
||||
log_info "Rolling back from $CURRENT to $PREVIOUS" |
||||
|
||||
# Update symlinks to previous release |
||||
ssh "$DEPLOY_HOST" "bash -c ' |
||||
RELEASES_DIR=~/.local/bin/releases |
||||
BIN_DIR=~/.local/bin |
||||
PREVIOUS=\"$PREVIOUS\" |
||||
|
||||
cd \$BIN_DIR |
||||
for link in orly-*; do |
||||
if [ -L \"\$link\" ]; then |
||||
target=\$(readlink \"\$link\") |
||||
binary=\$(basename \"\$target\") |
||||
if [ -f \"\$RELEASES_DIR/\$PREVIOUS/\$binary\" ]; then |
||||
ln -sf \"\$RELEASES_DIR/\$PREVIOUS/\$binary\" \"\$link\" |
||||
echo \"Updated \$link -> \$RELEASES_DIR/\$PREVIOUS/\$binary\" |
||||
fi |
||||
fi |
||||
done |
||||
'" |
||||
|
||||
if $DO_RESTART; then |
||||
log_info "Restarting service..." |
||||
ssh "root@$DEPLOY_HOST" "systemctl restart orly" || log_warn "Failed to restart (may need root)" |
||||
fi |
||||
|
||||
log_info "Rollback complete" |
||||
exit 0 |
||||
fi |
||||
|
||||
# Deploy new release |
||||
log_info "Deploying to $DEPLOY_HOST (release: $TIMESTAMP)" |
||||
|
||||
# Create release directory |
||||
ssh "$DEPLOY_HOST" "mkdir -p ~/.local/bin/releases/$TIMESTAMP" |
||||
|
||||
if [ -n "$LOCAL_PATH" ]; then |
||||
# Deploy from local path |
||||
log_info "Deploying from local path: $LOCAL_PATH" |
||||
|
||||
for binary in "${!BINARIES[@]}"; do |
||||
symlink_name="${BINARIES[$binary]}" |
||||
if [ -f "$LOCAL_PATH/$binary" ]; then |
||||
log_info "Uploading $binary as $symlink_name..." |
||||
scp "$LOCAL_PATH/$binary" "$DEPLOY_HOST:~/.local/bin/releases/$TIMESTAMP/$symlink_name" |
||||
ssh "$DEPLOY_HOST" "chmod +x ~/.local/bin/releases/$TIMESTAMP/$symlink_name" |
||||
fi |
||||
done |
||||
|
||||
elif [ -n "$BINARIES_URL" ]; then |
||||
# Deploy from URL |
||||
log_info "Downloading binaries from $BINARIES_URL" |
||||
|
||||
ssh "$DEPLOY_HOST" "bash -c ' |
||||
cd ~/.local/bin/releases/$TIMESTAMP |
||||
curl -sSL \"$BINARIES_URL\" | tar xz |
||||
chmod +x * |
||||
'" |
||||
|
||||
else |
||||
log_error "No binaries source specified. Use --local-path or --binaries-url" |
||||
exit 1 |
||||
fi |
||||
|
||||
# Update symlinks |
||||
log_info "Updating symlinks..." |
||||
ssh "$DEPLOY_HOST" "bash -c ' |
||||
RELEASES_DIR=~/.local/bin/releases |
||||
BIN_DIR=~/.local/bin |
||||
TIMESTAMP=\"$TIMESTAMP\" |
||||
|
||||
cd \$BIN_DIR |
||||
for binary in \$RELEASES_DIR/\$TIMESTAMP/*; do |
||||
name=\$(basename \"\$binary\") |
||||
ln -sf \"\$binary\" \"\$name\" |
||||
echo \" \$name -> \$binary\" |
||||
done |
||||
'" |
||||
|
||||
# Show deployed binaries |
||||
log_info "Deployed binaries:" |
||||
ssh "$DEPLOY_HOST" "ls -la ~/.local/bin/releases/$TIMESTAMP/" |
||||
|
||||
# Restart service if requested |
||||
if $DO_RESTART; then |
||||
log_info "Restarting orly service..." |
||||
ssh "root@$DEPLOY_HOST" "systemctl restart orly" && log_info "Service restarted" || log_warn "Failed to restart (may need root)" |
||||
fi |
||||
|
||||
# Cleanup old releases (keep last 5) |
||||
log_info "Cleaning up old releases (keeping last 5)..." |
||||
ssh "$DEPLOY_HOST" 'bash -c '\'' |
||||
RELEASES_DIR=~/.local/bin/releases |
||||
cd "$RELEASES_DIR" |
||||
ls -1t | tail -n +6 | while read old; do |
||||
echo " Removing old release: $old" |
||||
rm -rf "$old" |
||||
done |
||||
'\''' |
||||
|
||||
log_info "Deployment complete!" |
||||
log_info "To restart the service: ssh root@$DEPLOY_HOST 'systemctl restart orly'" |
||||
Loading…
Reference in new issue