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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
# 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 @@ |
|||||||
|
# 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
// Package sync provides NIP-11 relay information document fetching and caching
|
// Package common provides shared utilities for sync services
|
||||||
package sync |
package common |
||||||
|
|
||||||
import ( |
import ( |
||||||
"context" |
"context" |
||||||
@ -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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
#!/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 @@ |
|||||||
|
#!/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