service.proto raw

   1  syntax = "proto3";
   2  package orlysync.negentropy.v1;
   3  option go_package = "next.orly.dev/pkg/proto/orlysync/negentropy/v1;negentropyv1";
   4  
   5  import "orlysync/common/v1/types.proto";
   6  
   7  // NegentropyService provides NIP-77 negentropy-based set reconciliation
   8  // for both relay-to-relay sync and client-facing WebSocket operations
   9  service NegentropyService {
  10    // === Lifecycle Methods ===
  11  
  12    // Ready returns whether the service is ready to serve requests
  13    rpc Ready(orlysync.common.v1.Empty) returns (orlysync.common.v1.ReadyResponse);
  14  
  15    // Start starts the background relay-to-relay sync
  16    rpc Start(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty);
  17  
  18    // Stop stops the background sync
  19    rpc Stop(orlysync.common.v1.Empty) returns (orlysync.common.v1.Empty);
  20  
  21    // === Client-Facing NIP-77 (WebSocket Message Handling) ===
  22    // These handle NEG-OPEN, NEG-MSG, NEG-CLOSE from WebSocket clients
  23  
  24    // HandleNegOpen processes a NEG-OPEN message from a client
  25    rpc HandleNegOpen(NegOpenRequest) returns (NegOpenResponse);
  26  
  27    // HandleNegMsg processes a NEG-MSG message from a client
  28    rpc HandleNegMsg(NegMsgRequest) returns (NegMsgResponse);
  29  
  30    // HandleNegClose processes a NEG-CLOSE message from a client
  31    rpc HandleNegClose(NegCloseRequest) returns (orlysync.common.v1.Empty);
  32  
  33    // === Relay-to-Relay Sync ===
  34  
  35    // SyncWithPeer initiates negentropy sync with a specific peer relay
  36    rpc SyncWithPeer(SyncPeerRequest) returns (stream SyncProgress);
  37  
  38    // GetSyncStatus returns the current sync status
  39    rpc GetSyncStatus(orlysync.common.v1.Empty) returns (SyncStatusResponse);
  40  
  41    // === Peer Management ===
  42  
  43    // GetPeers returns the list of negentropy sync peers
  44    rpc GetPeers(orlysync.common.v1.Empty) returns (PeersResponse);
  45  
  46    // AddPeer adds a peer for negentropy sync
  47    rpc AddPeer(AddPeerRequest) returns (orlysync.common.v1.Empty);
  48  
  49    // RemovePeer removes a peer from negentropy sync
  50    rpc RemovePeer(RemovePeerRequest) returns (orlysync.common.v1.Empty);
  51  
  52    // === Sync Control ===
  53  
  54    // TriggerSync manually triggers sync with a specific peer or all peers
  55    rpc TriggerSync(TriggerSyncRequest) returns (orlysync.common.v1.Empty);
  56  
  57    // GetPeerSyncState returns sync state for a specific peer
  58    rpc GetPeerSyncState(PeerSyncStateRequest) returns (PeerSyncStateResponse);
  59  
  60    // === Session Management ===
  61  
  62    // ListSessions returns active client negentropy sessions
  63    rpc ListSessions(orlysync.common.v1.Empty) returns (ListSessionsResponse);
  64  
  65    // CloseSession forcefully closes a client session
  66    rpc CloseSession(CloseSessionRequest) returns (orlysync.common.v1.Empty);
  67  }
  68  
  69  // === Client-Facing NIP-77 Messages ===
  70  
  71  // NegOpenRequest processes a NEG-OPEN from client
  72  // NEG-OPEN format: ["NEG-OPEN", subscription_id, filter, initial_message?]
  73  message NegOpenRequest {
  74    string subscription_id = 1;   // Client's subscription ID
  75    orlysync.common.v1.Filter filter = 2;  // Nostr filter for reconciliation
  76    bytes initial_message = 3;    // Optional initial negentropy message
  77    string connection_id = 4;     // Connection ID for session tracking
  78  }
  79  
  80  // NegOpenResponse returns the initial negentropy response
  81  message NegOpenResponse {
  82    bytes message = 1;            // Negentropy protocol message to send back
  83    repeated bytes have_ids = 2;  // Event IDs we have that client needs (if initial reconciliation completes)
  84    repeated bytes need_ids = 3;  // Event IDs we need from client (if initial reconciliation completes)
  85    bool complete = 4;            // True if reconciliation completed in first round
  86    string error = 5;             // Error message if failed
  87  }
  88  
  89  // NegMsgRequest processes a NEG-MSG from client
  90  // NEG-MSG format: ["NEG-MSG", subscription_id, message]
  91  message NegMsgRequest {
  92    string subscription_id = 1;
  93    bytes message = 2;            // Negentropy protocol message
  94    string connection_id = 3;
  95  }
  96  
  97  // NegMsgResponse returns reconciliation results
  98  message NegMsgResponse {
  99    bytes message = 1;            // Negentropy protocol message to send back
 100    repeated bytes have_ids = 2;  // Event IDs we have that client needs
 101    repeated bytes need_ids = 3;  // Event IDs we need from client
 102    bool complete = 4;            // True if reconciliation is complete
 103    string error = 5;             // Error message if failed
 104  }
 105  
 106  // NegCloseRequest processes a NEG-CLOSE from client
 107  // NEG-CLOSE format: ["NEG-CLOSE", subscription_id]
 108  message NegCloseRequest {
 109    string subscription_id = 1;
 110    string connection_id = 2;
 111  }
 112  
 113  // === Relay-to-Relay Sync Messages ===
 114  
 115  // SyncPeerRequest initiates sync with a peer
 116  message SyncPeerRequest {
 117    string peer_url = 1;          // WebSocket URL of peer relay
 118    orlysync.common.v1.Filter filter = 2;  // Optional filter to limit sync scope
 119    int64 since = 3;              // Optional: only sync events since timestamp
 120  }
 121  
 122  // SyncProgress streams sync progress updates
 123  message SyncProgress {
 124    string peer_url = 1;
 125    int32 round = 2;              // Reconciliation round number
 126    int64 have_count = 3;         // Events we have that peer needs
 127    int64 need_count = 4;         // Events we need from peer
 128    int64 fetched_count = 5;      // Events fetched so far
 129    int64 sent_count = 6;         // Events sent so far
 130    bool complete = 7;            // True when sync is complete
 131    string error = 8;             // Error message if failed
 132  }
 133  
 134  // SyncStatusResponse contains overall sync status
 135  message SyncStatusResponse {
 136    bool active = 1;              // Whether background sync is running
 137    int64 last_sync = 2;          // Timestamp of last sync
 138    int32 peer_count = 3;
 139    repeated PeerSyncState peer_states = 4;
 140  }
 141  
 142  // === Peer Management Messages ===
 143  
 144  // PeersResponse contains the list of peers
 145  message PeersResponse {
 146    repeated string peers = 1;    // List of peer WebSocket URLs
 147  }
 148  
 149  // AddPeerRequest adds a peer
 150  message AddPeerRequest {
 151    string peer_url = 1;
 152  }
 153  
 154  // RemovePeerRequest removes a peer
 155  message RemovePeerRequest {
 156    string peer_url = 1;
 157  }
 158  
 159  // TriggerSyncRequest triggers manual sync
 160  message TriggerSyncRequest {
 161    string peer_url = 1;          // Optional: specific peer (empty = all)
 162    orlysync.common.v1.Filter filter = 2;  // Optional: filter for sync scope
 163  }
 164  
 165  // PeerSyncStateRequest requests state for a peer
 166  message PeerSyncStateRequest {
 167    string peer_url = 1;
 168  }
 169  
 170  // PeerSyncStateResponse contains peer sync state
 171  message PeerSyncStateResponse {
 172    PeerSyncState state = 1;
 173    bool found = 2;
 174  }
 175  
 176  // PeerSyncState represents sync state for a peer
 177  message PeerSyncState {
 178    string peer_url = 1;
 179    int64 last_sync = 2;          // Timestamp of last successful sync
 180    int64 events_synced = 3;      // Total events synced from this peer
 181    string status = 4;            // "idle", "syncing", "error"
 182    string last_error = 5;        // Last error message
 183    int32 consecutive_failures = 6;
 184  }
 185  
 186  // === Session Management Messages ===
 187  
 188  // ClientSession represents an active client negentropy session
 189  message ClientSession {
 190    string subscription_id = 1;
 191    string connection_id = 2;
 192    int64 created_at = 3;
 193    int64 last_activity = 4;
 194    int32 round_count = 5;        // Number of reconciliation rounds
 195  }
 196  
 197  // ListSessionsResponse contains active sessions
 198  message ListSessionsResponse {
 199    repeated ClientSession sessions = 1;
 200  }
 201  
 202  // CloseSessionRequest closes a session
 203  message CloseSessionRequest {
 204    string subscription_id = 1;
 205    string connection_id = 2;     // Optional: if empty, close all with this sub_id
 206  }
 207