diff --git a/.changeset/shiny-tables-join.md b/.changeset/shiny-tables-join.md new file mode 100644 index 0000000000..af3e7790f0 --- /dev/null +++ b/.changeset/shiny-tables-join.md @@ -0,0 +1,8 @@ +--- +'@farcaster/hub-nodejs': patch +'@farcaster/hub-web': patch +'@farcaster/core': patch +'@farcaster/hubble': patch +--- + +Add a GetSyncStatus rpc call that exposes the hubs sync status with different peers diff --git a/apps/hubble/package.json b/apps/hubble/package.json index 0adee6d895..21da2050ae 100644 --- a/apps/hubble/package.json +++ b/apps/hubble/package.json @@ -25,6 +25,7 @@ "identity": "tsx src/cli.ts identity", "dbreset": "tsx src/cli.ts dbreset", "console": "tsx src/cli.ts console", + "status": "tsx src/cli.ts status", "test": "yarn build && NODE_OPTIONS=--experimental-vm-modules jest", "test:ci": "ENVIRONMENT=test NODE_OPTIONS=--experimental-vm-modules jest --ci --forceExit --coverage" }, diff --git a/apps/hubble/src/cli.ts b/apps/hubble/src/cli.ts index 9e69be3fcb..8ce14a1e0f 100644 --- a/apps/hubble/src/cli.ts +++ b/apps/hubble/src/cli.ts @@ -1,5 +1,11 @@ #!/usr/bin/env node -import { FarcasterNetwork } from '@farcaster/hub-nodejs'; +import { + FarcasterNetwork, + getInsecureHubRpcClient, + getSSLHubRpcClient, + HubInfoRequest, + SyncStatusRequest, +} from '@farcaster/hub-nodejs'; import { PeerId } from '@libp2p/interface-peer-id'; import { createEd25519PeerId, createFromProtobuf, exportToProtobuf } from '@libp2p/peer-id-factory'; import { Command } from 'commander'; @@ -437,6 +443,52 @@ app .addCommand(createIdCommand) .addCommand(verifyIdCommand); +app + .command('status') + .description('Reports the db and sync status of the hub') + .option( + '-s, --server ', + 'Farcaster RPC server address:port to connect to (eg. 127.0.0.1:2283)', + DEFAULT_RPC_CONSOLE + ) + .option('--insecure', 'Allow insecure connections to the RPC server', false) + .option('-p, --peerId ', 'Peer id of the hub to compare with (defaults to bootstrap peers)') + .action(async (cliOptions) => { + let rpcClient; + if (cliOptions.insecure) { + rpcClient = getInsecureHubRpcClient(cliOptions.server); + } else { + rpcClient = getSSLHubRpcClient(cliOptions.server); + } + const infoResult = await rpcClient.getInfo(HubInfoRequest.create({ dbStats: true })); + const syncStatusResult = await rpcClient.getSyncStatus(SyncStatusRequest.create({ peerId: cliOptions.peerId })); + if (syncStatusResult.isErr()) { + logger.error( + { errCode: syncStatusResult.error.errCode, errMsg: syncStatusResult.error.message }, + 'Failed to get hub status' + ); + exit(1); + } else if (infoResult.isErr()) { + logger.error({ errCode: infoResult.error.errCode, errMsg: infoResult.error.message }, 'Failed to get hub status'); + exit(1); + } + const dbStats = infoResult.value.dbStats; + logger.info( + `Hub Version: ${infoResult.value.version} Messages: ${dbStats?.numMessages} FIDs: ${dbStats?.numFidEvents} FNames: ${dbStats?.numFnameEvents}}` + ); + for (const peerStatus of syncStatusResult.value.syncStatus) { + const messageDelta = peerStatus.theirMessages - peerStatus.ourMessages; + if (syncStatusResult.value.isSyncing) { + logger.info(`Peer ${peerStatus.peerId}: Sync in progress. (msg delta: ${messageDelta})`); + } else { + logger.info( + `Peer ${peerStatus.peerId}: In Sync: ${peerStatus.inSync} (msg delta: ${messageDelta}, diverged ${peerStatus.divergenceSecondsAgo} seconds ago)` + ); + } + } + exit(0); + }); + app .command('console') .description('Start a REPL console') diff --git a/apps/hubble/src/console/console.ts b/apps/hubble/src/console/console.ts index 67b3735e86..aff057584d 100644 --- a/apps/hubble/src/console/console.ts +++ b/apps/hubble/src/console/console.ts @@ -88,7 +88,7 @@ export const startConsole = async (addressString: string, useInsecure: boolean) // Run the info command to start - const info = await rpcClient.getInfo(HubInfoRequest.create({ syncStats: true }), new Metadata(), { + const info = await rpcClient.getInfo(HubInfoRequest.create({ dbStats: true }), new Metadata(), { deadline: Date.now() + 2000, }); diff --git a/apps/hubble/src/hubble.ts b/apps/hubble/src/hubble.ts index 477ca00cab..8a4e48831a 100644 --- a/apps/hubble/src/hubble.ts +++ b/apps/hubble/src/hubble.ts @@ -73,6 +73,7 @@ export interface HubInterface { getHubState(): HubAsyncResult; putHubState(hubState: HubState): HubAsyncResult; gossipContactInfo(): HubAsyncResult; + getRPCClientForPeer(peerId: PeerId, peer: ContactInfoContent): Promise; } export interface HubOptions { diff --git a/apps/hubble/src/network/p2p/gossipNode.ts b/apps/hubble/src/network/p2p/gossipNode.ts index 98675559d2..0d09601b9a 100644 --- a/apps/hubble/src/network/p2p/gossipNode.ts +++ b/apps/hubble/src/network/p2p/gossipNode.ts @@ -69,10 +69,12 @@ export class GossipNode extends TypedEmitter { private _node?: Libp2p; private _periodicPeerCheckJob?: PeriodicPeerCheckScheduler; private _network: FarcasterNetwork; + private _bootstrapPeerIds: Set; constructor(network?: FarcasterNetwork) { super(); this._network = network ?? FarcasterNetwork.NONE; + this._bootstrapPeerIds = new Set(); } /** Returns the PeerId (public key) of this node */ @@ -259,13 +261,16 @@ export class GossipNode extends TypedEmitter { } /** Connect to a peer Gossip Node using a specific address */ - async connectAddress(address: Multiaddr): Promise> { + async connectAddress(address: Multiaddr, isBootstrapNode = false): Promise> { log.debug({ identity: this.identity, address }, `Attempting to connect to address ${address}`); try { const conn = await this._node?.dial(address); if (conn) { log.info({ identity: this.identity, address }, `Connected to peer at address: ${address}`); + if (isBootstrapNode) { + this._bootstrapPeerIds.add(conn.remotePeer.toString()); + } return ok(undefined); } } catch (error: any) { @@ -336,6 +341,10 @@ export class GossipNode extends TypedEmitter { return [this.primaryTopic(), this.contactInfoTopic()]; } + get bootstrapPeerIds(): Set { + return this._bootstrapPeerIds; + } + //TODO: Needs better typesafety static encodeMessage(message: GossipMessage): HubResult { return ok(GossipMessage.encode(message).finish()); @@ -363,7 +372,7 @@ export class GossipNode extends TypedEmitter { /* Attempts to dial all the addresses in the bootstrap list */ public async bootstrap(bootstrapAddrs: Multiaddr[]): Promise> { if (bootstrapAddrs.length == 0) return ok(undefined); - const results = await Promise.all(bootstrapAddrs.map((addr) => this.connectAddress(addr))); + const results = await Promise.all(bootstrapAddrs.map((addr) => this.connectAddress(addr, true))); const finalResults = Result.combineWithAllErrors(results) as Result; if (finalResults.isErr() && finalResults.error.length == bootstrapAddrs.length) { diff --git a/apps/hubble/src/network/sync/syncEngine.test.ts b/apps/hubble/src/network/sync/syncEngine.test.ts index 24e3e3ce9d..fa4914a153 100644 --- a/apps/hubble/src/network/sync/syncEngine.test.ts +++ b/apps/hubble/src/network/sync/syncEngine.test.ts @@ -246,7 +246,6 @@ describe('SyncEngine', () => { expect(shouldSync.isOk()).toBeTruthy(); expect(shouldSync._unsafeUnwrap().isSyncing).toBeTruthy(); expect(shouldSync._unsafeUnwrap().shouldSync).toBeFalsy(); - expect(shouldSync._unsafeUnwrap().ourSnapshot).toBeUndefined(); called = true; // Return an empty child map so sync will finish with a noop @@ -332,7 +331,7 @@ describe('SyncEngine', () => { await engine.mergeMessage(signerAdd); await addMessagesWithTimestamps([167, 169]); - const stats = await syncEngine.getSyncStats(); + const stats = await syncEngine.getDbStats(); expect(stats.numFids).toEqual(1); expect(stats.numFnames).toEqual(2); expect(stats.numMessages).toEqual(3); diff --git a/apps/hubble/src/network/sync/syncEngine.ts b/apps/hubble/src/network/sync/syncEngine.ts index c1931ab0e7..aa1385f977 100644 --- a/apps/hubble/src/network/sync/syncEngine.ts +++ b/apps/hubble/src/network/sync/syncEngine.ts @@ -22,13 +22,14 @@ import { TypedEmitter } from 'tiny-typed-emitter'; import { EthEventsProvider } from '~/eth/ethEventsProvider'; import { Hub, HubInterface } from '~/hubble'; import { MerkleTrie, NodeMetadata } from '~/network/sync/merkleTrie'; -import { SyncId, timestampToPaddedTimestampPrefix } from '~/network/sync/syncId'; +import { prefixToTimestamp, SyncId, timestampToPaddedTimestampPrefix } from '~/network/sync/syncId'; import { TrieSnapshot } from '~/network/sync/trieNode'; import { getManyMessages } from '~/storage/db/message'; import RocksDB from '~/storage/db/rocksdb'; import { sleepWhile } from '~/utils/crypto'; import { logger } from '~/utils/logger'; import { RootPrefix } from '~/storage/db/types'; +import { fromFarcasterTime } from '@farcaster/core'; // Number of seconds to wait for the network to "settle" before syncing. We will only // attempt to sync messages that are older than this time. @@ -65,13 +66,16 @@ type MergeResult = { type SyncStatus = { isSyncing: boolean; - inSync: 'true' | 'false' | 'unknown'; + inSync: 'true' | 'false' | 'unknown' | 'blocked'; shouldSync: boolean; theirSnapshot: TrieSnapshot; - ourSnapshot?: TrieSnapshot; + ourSnapshot: TrieSnapshot; + divergencePrefix: string; + divergenceSecondsAgo: number; + lastBadSync: number; }; -type SyncStats = { +type DbStats = { numMessages: number; numFids: number; numFnames: number; @@ -297,7 +301,9 @@ class SyncEngine extends TypedEmitter { ourMessages: syncStatus.ourSnapshot?.numMessages, peerNetwork: peerContact.network, peerVersion: peerContact.hubVersion, - lastBadSync: this._unproductivePeers.get(peerIdString)?.getTime(), + divergencePrefix: syncStatus.divergencePrefix, + divergenceSeconds: syncStatus.divergenceSecondsAgo, + lastBadSync: syncStatus.lastBadSync, }, 'SyncStatus' // Search for this string in the logs to get summary of sync status ); @@ -326,38 +332,65 @@ class SyncEngine extends TypedEmitter { } public async syncStatus(peerId: string, theirSnapshot: TrieSnapshot): HubAsyncResult { - if (this._isSyncing) { - log.info('shouldSync: already syncing'); - return ok({ isSyncing: true, inSync: 'unknown', shouldSync: false, theirSnapshot }); - } - const lastBadSync = this._unproductivePeers.get(peerId); - if (lastBadSync && Date.now() < lastBadSync.getTime() + BAD_PEER_BLOCK_TIMEOUT) { - log.info(`shouldSync: bad peer (blocked until ${lastBadSync.getTime() + BAD_PEER_BLOCK_TIMEOUT})`); - return ok({ isSyncing: false, inSync: 'false', shouldSync: false, theirSnapshot }); - } - const ourSnapshotResult = await this.getSnapshot(theirSnapshot.prefix); + if (ourSnapshotResult.isErr()) { return err(ourSnapshotResult.error); - } else { - const ourSnapshot = ourSnapshotResult.value; - const excludedHashesMatch = - ourSnapshot.excludedHashes.length === theirSnapshot.excludedHashes.length && - // NOTE: `index` is controlled by `every` and so not at risk of object injection. - // eslint-disable-next-line security/detect-object-injection - ourSnapshot.excludedHashes.every((value, index) => value === theirSnapshot.excludedHashes[index]); + } + const ourSnapshot = ourSnapshotResult.value; - log.info({ excludedHashesMatch }, `shouldSync: excluded hashes`); + if (this._isSyncing) { + return ok({ + isSyncing: true, + inSync: 'unknown', + shouldSync: false, + theirSnapshot, + ourSnapshot, + divergencePrefix: '', + divergenceSecondsAgo: -1, + lastBadSync: -1, + }); + } + if (lastBadSync && Date.now() < lastBadSync.getTime() + BAD_PEER_BLOCK_TIMEOUT) { return ok({ isSyncing: false, - inSync: excludedHashesMatch ? 'true' : 'false', - shouldSync: !excludedHashesMatch, - ourSnapshot, + inSync: 'blocked', + shouldSync: false, theirSnapshot, + ourSnapshot, + divergencePrefix: '', + divergenceSecondsAgo: -1, + lastBadSync: lastBadSync.getTime(), }); } + + const excludedHashesMatch = + ourSnapshot.excludedHashes.length === theirSnapshot.excludedHashes.length && + // NOTE: `index` is controlled by `every` and so not at risk of object injection. + // eslint-disable-next-line security/detect-object-injection + ourSnapshot.excludedHashes.every((value, index) => value === theirSnapshot.excludedHashes[index]); + + const divergencePrefix = Buffer.from(this.getDivergencePrefix(ourSnapshot, theirSnapshot.excludedHashes)).toString( + 'ascii' + ); + const divergedAt = fromFarcasterTime(prefixToTimestamp(divergencePrefix)); + let divergenceSecondsAgo = -1; + if (divergedAt.isOk()) { + divergenceSecondsAgo = Math.floor((Date.now() - divergedAt.value) / 1000); + } + + return ok({ + isSyncing: false, + inSync: excludedHashesMatch ? 'true' : 'false', + shouldSync: !excludedHashesMatch, + ourSnapshot, + theirSnapshot, + divergencePrefix, + divergenceSecondsAgo, + lastBadSync: lastBadSync?.getTime() ?? -1, + }); } async performSync(peerId: string, otherSnapshot: TrieSnapshot, rpcClient: HubRpcClient): Promise { @@ -371,7 +404,7 @@ class SyncEngine extends TypedEmitter { log.warn({ errCode: snapshot.error.errCode }, `Error performing sync: ${snapshot.error.message}}`); } else { const ourSnapshot = snapshot.value; - const divergencePrefix = await this.getDivergencePrefix(ourSnapshot, otherSnapshot.excludedHashes); + const divergencePrefix = this.getDivergencePrefix(ourSnapshot, otherSnapshot.excludedHashes); log.info( { divergencePrefix: Buffer.from(divergencePrefix).toString('ascii'), @@ -423,7 +456,7 @@ class SyncEngine extends TypedEmitter { * @param prefix - the prefix of the external trie. * @param otherExcludedHashes - the excluded hashes of the external trie. */ - async getDivergencePrefix(ourSnapshot: TrieSnapshot, otherExcludedHashes: string[]): Promise { + getDivergencePrefix(ourSnapshot: TrieSnapshot, otherExcludedHashes: string[]): Uint8Array { const { prefix, excludedHashes } = ourSnapshot; for (let i = 0; i < prefix.length; i++) { @@ -661,7 +694,7 @@ class SyncEngine extends TypedEmitter { return false; } - public async getSyncStats(): Promise { + public async getDbStats(): Promise { let numFids = 0, numFnames = 0; @@ -686,6 +719,28 @@ class SyncEngine extends TypedEmitter { }; } + public async getSyncStatusForPeer(peerId: string, hub: HubInterface): HubAsyncResult { + const c = this.currentHubPeerContacts.get(peerId); + if (!c?.peerId || !c?.contactInfo) { + return err(new HubError('unavailable.network_failure', `No contact info for peer ${peerId}`)); + } + const rpcClient = await hub.getRPCClientForPeer(c?.peerId, c?.contactInfo); + if (!rpcClient) { + return err(new HubError('unavailable.network_failure', `Could not create a RPC client for peer ${peerId}`)); + } + const peerStateResult = await rpcClient.getSyncSnapshotByPrefix( + TrieNodePrefix.create({ prefix: new Uint8Array() }), + new Metadata(), + rpcDeadline() + ); + if (peerStateResult.isErr()) { + return err(peerStateResult.error); + } + + const theirSnapshot = peerStateResult.value; + return this.syncStatus(peerId, theirSnapshot); + } + public get shouldCompactDb(): boolean { return this._messagesSinceLastCompaction > COMPACTION_THRESHOLD; } diff --git a/apps/hubble/src/network/sync/syncId.ts b/apps/hubble/src/network/sync/syncId.ts index 7ad4b2efef..fcca268ba0 100644 --- a/apps/hubble/src/network/sync/syncId.ts +++ b/apps/hubble/src/network/sync/syncId.ts @@ -64,4 +64,8 @@ const timestampToPaddedTimestampPrefix = (timestamp: number): string => { return Math.floor(timestamp).toString().padStart(TIMESTAMP_LENGTH, '0'); }; -export { SyncId, timestampToPaddedTimestampPrefix, TIMESTAMP_LENGTH, HASH_LENGTH }; +const prefixToTimestamp = (prefix: string): number => { + return parseInt(prefix.padEnd(TIMESTAMP_LENGTH, '0'), 10); +}; + +export { SyncId, timestampToPaddedTimestampPrefix, prefixToTimestamp, TIMESTAMP_LENGTH, HASH_LENGTH }; diff --git a/apps/hubble/src/rpc/server.ts b/apps/hubble/src/rpc/server.ts index f2157212a1..754177f331 100644 --- a/apps/hubble/src/rpc/server.ts +++ b/apps/hubble/src/rpc/server.ts @@ -25,12 +25,14 @@ import { SignerRemoveMessage, status, SyncIds, - SyncStats, + DbStats, TrieNodeMetadataResponse, TrieNodeSnapshotResponse, UserDataAddMessage, VerificationAddEthAddressMessage, VerificationRemoveMessage, + SyncStatusResponse, + SyncStatus, } from '@farcaster/hub-nodejs'; import { err, ok, Result, ResultAsync } from 'neverthrow'; import { APP_NICKNAME, APP_VERSION, HubInterface } from '~/hubble'; @@ -275,9 +277,9 @@ export default class Server { rootHash: (await this.syncEngine?.trie.rootHash()) ?? '', }); - if (call.request.syncStats && this.syncEngine) { - const stats = await this.syncEngine.getSyncStats(); - info.syncStats = SyncStats.create({ + if (call.request.dbStats && this.syncEngine) { + const stats = await this.syncEngine.getDbStats(); + info.dbStats = DbStats.create({ numMessages: stats?.numMessages, numFidEvents: stats?.numFids, numFnameEvents: stats?.numFnames, @@ -287,6 +289,46 @@ export default class Server { callback(null, info); })(); }, + getSyncStatus: (call, callback) => { + (async () => { + if (!this.gossipNode || !this.syncEngine || !this.hub) { + callback(toServiceError(new HubError('bad_request', "Hub isn't initialized"))); + return; + } + let peersToCheck: string[]; + if (call.request.peerId && call.request.peerId.length > 0) { + peersToCheck = [call.request.peerId]; + } else { + peersToCheck = Array.from(this.gossipNode.bootstrapPeerIds.values()); + } + + const response = SyncStatusResponse.create({ + isSyncing: false, + syncStatus: [], + }); + + for (const peerId of peersToCheck) { + const statusResult = await this.syncEngine.getSyncStatusForPeer(peerId, this.hub); + if (statusResult.isOk()) { + const status = statusResult.value; + response.isSyncing = status.isSyncing; + const peerStatus = SyncStatus.create({ + peerId, + inSync: status.inSync, + shouldSync: status.shouldSync, + lastBadSync: status.lastBadSync, + divergencePrefix: status.divergencePrefix, + divergenceSecondsAgo: status.divergenceSecondsAgo, + ourMessages: status.ourSnapshot.numMessages, + theirMessages: status.theirSnapshot.numMessages, + }); + response.syncStatus.push(peerStatus); + } + } + + callback(null, response); + })(); + }, getAllSyncIdsByPrefix: (call, callback) => { const request = call.request; diff --git a/apps/hubble/src/rpc/test/syncService.test.ts b/apps/hubble/src/rpc/test/syncService.test.ts new file mode 100644 index 0000000000..49d50743af --- /dev/null +++ b/apps/hubble/src/rpc/test/syncService.test.ts @@ -0,0 +1,88 @@ +import { jestRocksDB } from '~/storage/db/jestUtils'; +import { + CastAddMessage, + Factories, + FarcasterNetwork, + getInsecureHubRpcClient, + HubInfoRequest, + HubRpcClient, + IdRegistryEvent, + SignerAddMessage, + SyncStatusRequest, +} from '@farcaster/hub-nodejs'; +import Engine from '~/storage/engine'; +import { MockHub } from '~/test/mocks'; +import Server from '~/rpc/server'; +import SyncEngine from '~/network/sync/syncEngine'; +import { GossipNode } from '~/network/p2p/gossipNode'; + +const db = jestRocksDB('protobufs.rpc.syncService.test'); +const network = FarcasterNetwork.TESTNET; +const mockGossipNode = { + bootstrapPeerIds: ['test'], +} as unknown as GossipNode; +const engine = new Engine(db, network); +const hub = new MockHub(db, engine, mockGossipNode); + +let server: Server; +let client: HubRpcClient; + +beforeAll(async () => { + server = new Server(hub, engine, new SyncEngine(hub, db), mockGossipNode); + const port = await server.start(); + client = getInsecureHubRpcClient(`127.0.0.1:${port}`); +}); + +afterAll(async () => { + client.close(); + await server.stop(); + await engine.stop(); +}); + +const fid = Factories.Fid.build(); +const signer = Factories.Ed25519Signer.build(); +const custodySigner = Factories.Eip712Signer.build(); + +let custodyEvent: IdRegistryEvent; +let signerAdd: SignerAddMessage; +let castAdd: CastAddMessage; + +beforeAll(async () => { + const signerKey = (await signer.getSignerKey())._unsafeUnwrap(); + const custodySignerKey = (await custodySigner.getSignerKey())._unsafeUnwrap(); + custodyEvent = Factories.IdRegistryEvent.build({ fid, to: custodySignerKey }); + + signerAdd = await Factories.SignerAddMessage.create( + { data: { fid, network, signerAddBody: { signer: signerKey } } }, + { transient: { signer: custodySigner } } + ); + + castAdd = await Factories.CastAddMessage.create({ data: { fid, network } }, { transient: { signer } }); +}); + +describe('getInfo', () => { + test('succeeds', async () => { + await engine.mergeIdRegistryEvent(custodyEvent); + await engine.mergeMessage(signerAdd); + await engine.mergeMessage(castAdd); + + const result = await client.getInfo(HubInfoRequest.create({ dbStats: true })); + expect(result.isOk()).toBeTruthy(); + expect(result._unsafeUnwrap().dbStats?.numMessages).toEqual(2); + expect(result._unsafeUnwrap().dbStats?.numFidEvents).toEqual(1); + expect(result._unsafeUnwrap().dbStats?.numFnameEvents).toEqual(0); + }); +}); + +describe('getSyncStatus', () => { + test('succeeds', async () => { + await engine.mergeIdRegistryEvent(custodyEvent); + await engine.mergeMessage(signerAdd); + await engine.mergeMessage(castAdd); + + const result = await client.getSyncStatus(SyncStatusRequest.create()); + expect(result.isOk()).toBeTruthy(); + expect(result._unsafeUnwrap().isSyncing).toEqual(false); + expect(result._unsafeUnwrap().syncStatus).toHaveLength(0); + }); +}); diff --git a/apps/hubble/src/test/mocks.ts b/apps/hubble/src/test/mocks.ts index 1200a5be2d..a720141181 100644 --- a/apps/hubble/src/test/mocks.ts +++ b/apps/hubble/src/test/mocks.ts @@ -2,6 +2,7 @@ import { FarcasterNetwork, HubAsyncResult, HubError, + HubRpcClient, HubState, IdRegistryEvent, Message, @@ -13,6 +14,8 @@ import { GossipNode } from '~/network/p2p/gossipNode'; import RocksDB from '~/storage/db/rocksdb'; import Engine from '~/storage/engine'; import { AbstractProvider } from 'ethers'; +import { PeerId } from '@libp2p/interface-peer-id'; +import { ContactInfoContent } from '@farcaster/core'; export class MockHub implements HubInterface { public db: RocksDB; @@ -60,6 +63,10 @@ export class MockHub implements HubInterface { this.gossipCount += 1; return ok(undefined); } + + async getRPCClientForPeer(_peerId: PeerId, _peer: ContactInfoContent): Promise { + return undefined; + } } /** A Mock RPC provider */ diff --git a/packages/core/src/protobufs/generated/request_response.ts b/packages/core/src/protobufs/generated/request_response.ts index 5f3f162a2b..f20c832e18 100644 --- a/packages/core/src/protobufs/generated/request_response.ts +++ b/packages/core/src/protobufs/generated/request_response.ts @@ -25,7 +25,7 @@ export interface EventRequest { } export interface HubInfoRequest { - syncStats: boolean; + dbStats: boolean; } /** Response Types for the Sync RPC Methods */ @@ -34,15 +34,35 @@ export interface HubInfoResponse { isSyncing: boolean; nickname: string; rootHash: string; - syncStats: SyncStats | undefined; + dbStats: DbStats | undefined; } -export interface SyncStats { +export interface DbStats { numMessages: number; numFidEvents: number; numFnameEvents: number; } +export interface SyncStatusRequest { + peerId?: string | undefined; +} + +export interface SyncStatusResponse { + isSyncing: boolean; + syncStatus: SyncStatus[]; +} + +export interface SyncStatus { + peerId: string; + inSync: string; + shouldSync: boolean; + divergencePrefix: string; + divergenceSecondsAgo: number; + theirMessages: number; + ourMessages: number; + lastBadSync: number; +} + export interface TrieNodeMetadataResponse { prefix: Uint8Array; numMessages: number; @@ -334,13 +354,13 @@ export const EventRequest = { }; function createBaseHubInfoRequest(): HubInfoRequest { - return { syncStats: false }; + return { dbStats: false }; } export const HubInfoRequest = { encode(message: HubInfoRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.syncStats === true) { - writer.uint32(8).bool(message.syncStats); + if (message.dbStats === true) { + writer.uint32(8).bool(message.dbStats); } return writer; }, @@ -357,7 +377,7 @@ export const HubInfoRequest = { break; } - message.syncStats = reader.bool(); + message.dbStats = reader.bool(); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -369,12 +389,12 @@ export const HubInfoRequest = { }, fromJSON(object: any): HubInfoRequest { - return { syncStats: isSet(object.syncStats) ? Boolean(object.syncStats) : false }; + return { dbStats: isSet(object.dbStats) ? Boolean(object.dbStats) : false }; }, toJSON(message: HubInfoRequest): unknown { const obj: any = {}; - message.syncStats !== undefined && (obj.syncStats = message.syncStats); + message.dbStats !== undefined && (obj.dbStats = message.dbStats); return obj; }, @@ -384,13 +404,13 @@ export const HubInfoRequest = { fromPartial, I>>(object: I): HubInfoRequest { const message = createBaseHubInfoRequest(); - message.syncStats = object.syncStats ?? false; + message.dbStats = object.dbStats ?? false; return message; }, }; function createBaseHubInfoResponse(): HubInfoResponse { - return { version: '', isSyncing: false, nickname: '', rootHash: '', syncStats: undefined }; + return { version: '', isSyncing: false, nickname: '', rootHash: '', dbStats: undefined }; } export const HubInfoResponse = { @@ -407,8 +427,8 @@ export const HubInfoResponse = { if (message.rootHash !== '') { writer.uint32(34).string(message.rootHash); } - if (message.syncStats !== undefined) { - SyncStats.encode(message.syncStats, writer.uint32(42).fork()).ldelim(); + if (message.dbStats !== undefined) { + DbStats.encode(message.dbStats, writer.uint32(42).fork()).ldelim(); } return writer; }, @@ -453,7 +473,7 @@ export const HubInfoResponse = { break; } - message.syncStats = SyncStats.decode(reader, reader.uint32()); + message.dbStats = DbStats.decode(reader, reader.uint32()); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -470,7 +490,7 @@ export const HubInfoResponse = { isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, nickname: isSet(object.nickname) ? String(object.nickname) : '', rootHash: isSet(object.rootHash) ? String(object.rootHash) : '', - syncStats: isSet(object.syncStats) ? SyncStats.fromJSON(object.syncStats) : undefined, + dbStats: isSet(object.dbStats) ? DbStats.fromJSON(object.dbStats) : undefined, }; }, @@ -480,8 +500,7 @@ export const HubInfoResponse = { message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); message.nickname !== undefined && (obj.nickname = message.nickname); message.rootHash !== undefined && (obj.rootHash = message.rootHash); - message.syncStats !== undefined && - (obj.syncStats = message.syncStats ? SyncStats.toJSON(message.syncStats) : undefined); + message.dbStats !== undefined && (obj.dbStats = message.dbStats ? DbStats.toJSON(message.dbStats) : undefined); return obj; }, @@ -495,18 +514,18 @@ export const HubInfoResponse = { message.isSyncing = object.isSyncing ?? false; message.nickname = object.nickname ?? ''; message.rootHash = object.rootHash ?? ''; - message.syncStats = - object.syncStats !== undefined && object.syncStats !== null ? SyncStats.fromPartial(object.syncStats) : undefined; + message.dbStats = + object.dbStats !== undefined && object.dbStats !== null ? DbStats.fromPartial(object.dbStats) : undefined; return message; }, }; -function createBaseSyncStats(): SyncStats { +function createBaseDbStats(): DbStats { return { numMessages: 0, numFidEvents: 0, numFnameEvents: 0 }; } -export const SyncStats = { - encode(message: SyncStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { +export const DbStats = { + encode(message: DbStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.numMessages !== 0) { writer.uint32(8).uint64(message.numMessages); } @@ -519,10 +538,10 @@ export const SyncStats = { return writer; }, - decode(input: _m0.Reader | Uint8Array, length?: number): SyncStats { + decode(input: _m0.Reader | Uint8Array, length?: number): DbStats { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseSyncStats(); + const message = createBaseDbStats(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -556,7 +575,7 @@ export const SyncStats = { return message; }, - fromJSON(object: any): SyncStats { + fromJSON(object: any): DbStats { return { numMessages: isSet(object.numMessages) ? Number(object.numMessages) : 0, numFidEvents: isSet(object.numFidEvents) ? Number(object.numFidEvents) : 0, @@ -564,7 +583,7 @@ export const SyncStats = { }; }, - toJSON(message: SyncStats): unknown { + toJSON(message: DbStats): unknown { const obj: any = {}; message.numMessages !== undefined && (obj.numMessages = Math.round(message.numMessages)); message.numFidEvents !== undefined && (obj.numFidEvents = Math.round(message.numFidEvents)); @@ -572,12 +591,12 @@ export const SyncStats = { return obj; }, - create, I>>(base?: I): SyncStats { - return SyncStats.fromPartial(base ?? {}); + create, I>>(base?: I): DbStats { + return DbStats.fromPartial(base ?? {}); }, - fromPartial, I>>(object: I): SyncStats { - const message = createBaseSyncStats(); + fromPartial, I>>(object: I): DbStats { + const message = createBaseDbStats(); message.numMessages = object.numMessages ?? 0; message.numFidEvents = object.numFidEvents ?? 0; message.numFnameEvents = object.numFnameEvents ?? 0; @@ -585,6 +604,295 @@ export const SyncStats = { }, }; +function createBaseSyncStatusRequest(): SyncStatusRequest { + return { peerId: undefined }; +} + +export const SyncStatusRequest = { + encode(message: SyncStatusRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== undefined) { + writer.uint32(10).string(message.peerId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusRequest { + return { peerId: isSet(object.peerId) ? String(object.peerId) : undefined }; + }, + + toJSON(message: SyncStatusRequest): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + return obj; + }, + + create, I>>(base?: I): SyncStatusRequest { + return SyncStatusRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusRequest { + const message = createBaseSyncStatusRequest(); + message.peerId = object.peerId ?? undefined; + return message; + }, +}; + +function createBaseSyncStatusResponse(): SyncStatusResponse { + return { isSyncing: false, syncStatus: [] }; +} + +export const SyncStatusResponse = { + encode(message: SyncStatusResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.isSyncing === true) { + writer.uint32(8).bool(message.isSyncing); + } + for (const v of message.syncStatus) { + SyncStatus.encode(v!, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 8) { + break; + } + + message.isSyncing = reader.bool(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.syncStatus.push(SyncStatus.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusResponse { + return { + isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, + syncStatus: Array.isArray(object?.syncStatus) ? object.syncStatus.map((e: any) => SyncStatus.fromJSON(e)) : [], + }; + }, + + toJSON(message: SyncStatusResponse): unknown { + const obj: any = {}; + message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); + if (message.syncStatus) { + obj.syncStatus = message.syncStatus.map((e) => (e ? SyncStatus.toJSON(e) : undefined)); + } else { + obj.syncStatus = []; + } + return obj; + }, + + create, I>>(base?: I): SyncStatusResponse { + return SyncStatusResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusResponse { + const message = createBaseSyncStatusResponse(); + message.isSyncing = object.isSyncing ?? false; + message.syncStatus = object.syncStatus?.map((e) => SyncStatus.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseSyncStatus(): SyncStatus { + return { + peerId: '', + inSync: '', + shouldSync: false, + divergencePrefix: '', + divergenceSecondsAgo: 0, + theirMessages: 0, + ourMessages: 0, + lastBadSync: 0, + }; +} + +export const SyncStatus = { + encode(message: SyncStatus, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== '') { + writer.uint32(10).string(message.peerId); + } + if (message.inSync !== '') { + writer.uint32(18).string(message.inSync); + } + if (message.shouldSync === true) { + writer.uint32(24).bool(message.shouldSync); + } + if (message.divergencePrefix !== '') { + writer.uint32(34).string(message.divergencePrefix); + } + if (message.divergenceSecondsAgo !== 0) { + writer.uint32(40).int32(message.divergenceSecondsAgo); + } + if (message.theirMessages !== 0) { + writer.uint32(48).uint64(message.theirMessages); + } + if (message.ourMessages !== 0) { + writer.uint32(56).uint64(message.ourMessages); + } + if (message.lastBadSync !== 0) { + writer.uint32(64).int64(message.lastBadSync); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatus { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatus(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.inSync = reader.string(); + continue; + case 3: + if (tag != 24) { + break; + } + + message.shouldSync = reader.bool(); + continue; + case 4: + if (tag != 34) { + break; + } + + message.divergencePrefix = reader.string(); + continue; + case 5: + if (tag != 40) { + break; + } + + message.divergenceSecondsAgo = reader.int32(); + continue; + case 6: + if (tag != 48) { + break; + } + + message.theirMessages = longToNumber(reader.uint64() as Long); + continue; + case 7: + if (tag != 56) { + break; + } + + message.ourMessages = longToNumber(reader.uint64() as Long); + continue; + case 8: + if (tag != 64) { + break; + } + + message.lastBadSync = longToNumber(reader.int64() as Long); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatus { + return { + peerId: isSet(object.peerId) ? String(object.peerId) : '', + inSync: isSet(object.inSync) ? String(object.inSync) : '', + shouldSync: isSet(object.shouldSync) ? Boolean(object.shouldSync) : false, + divergencePrefix: isSet(object.divergencePrefix) ? String(object.divergencePrefix) : '', + divergenceSecondsAgo: isSet(object.divergenceSecondsAgo) ? Number(object.divergenceSecondsAgo) : 0, + theirMessages: isSet(object.theirMessages) ? Number(object.theirMessages) : 0, + ourMessages: isSet(object.ourMessages) ? Number(object.ourMessages) : 0, + lastBadSync: isSet(object.lastBadSync) ? Number(object.lastBadSync) : 0, + }; + }, + + toJSON(message: SyncStatus): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + message.inSync !== undefined && (obj.inSync = message.inSync); + message.shouldSync !== undefined && (obj.shouldSync = message.shouldSync); + message.divergencePrefix !== undefined && (obj.divergencePrefix = message.divergencePrefix); + message.divergenceSecondsAgo !== undefined && (obj.divergenceSecondsAgo = Math.round(message.divergenceSecondsAgo)); + message.theirMessages !== undefined && (obj.theirMessages = Math.round(message.theirMessages)); + message.ourMessages !== undefined && (obj.ourMessages = Math.round(message.ourMessages)); + message.lastBadSync !== undefined && (obj.lastBadSync = Math.round(message.lastBadSync)); + return obj; + }, + + create, I>>(base?: I): SyncStatus { + return SyncStatus.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatus { + const message = createBaseSyncStatus(); + message.peerId = object.peerId ?? ''; + message.inSync = object.inSync ?? ''; + message.shouldSync = object.shouldSync ?? false; + message.divergencePrefix = object.divergencePrefix ?? ''; + message.divergenceSecondsAgo = object.divergenceSecondsAgo ?? 0; + message.theirMessages = object.theirMessages ?? 0; + message.ourMessages = object.ourMessages ?? 0; + message.lastBadSync = object.lastBadSync ?? 0; + return message; + }, +}; + function createBaseTrieNodeMetadataResponse(): TrieNodeMetadataResponse { return { prefix: new Uint8Array(), numMessages: 0, hash: '', children: [] }; } diff --git a/packages/hub-nodejs/src/generated/request_response.ts b/packages/hub-nodejs/src/generated/request_response.ts index 5f3f162a2b..f20c832e18 100644 --- a/packages/hub-nodejs/src/generated/request_response.ts +++ b/packages/hub-nodejs/src/generated/request_response.ts @@ -25,7 +25,7 @@ export interface EventRequest { } export interface HubInfoRequest { - syncStats: boolean; + dbStats: boolean; } /** Response Types for the Sync RPC Methods */ @@ -34,15 +34,35 @@ export interface HubInfoResponse { isSyncing: boolean; nickname: string; rootHash: string; - syncStats: SyncStats | undefined; + dbStats: DbStats | undefined; } -export interface SyncStats { +export interface DbStats { numMessages: number; numFidEvents: number; numFnameEvents: number; } +export interface SyncStatusRequest { + peerId?: string | undefined; +} + +export interface SyncStatusResponse { + isSyncing: boolean; + syncStatus: SyncStatus[]; +} + +export interface SyncStatus { + peerId: string; + inSync: string; + shouldSync: boolean; + divergencePrefix: string; + divergenceSecondsAgo: number; + theirMessages: number; + ourMessages: number; + lastBadSync: number; +} + export interface TrieNodeMetadataResponse { prefix: Uint8Array; numMessages: number; @@ -334,13 +354,13 @@ export const EventRequest = { }; function createBaseHubInfoRequest(): HubInfoRequest { - return { syncStats: false }; + return { dbStats: false }; } export const HubInfoRequest = { encode(message: HubInfoRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.syncStats === true) { - writer.uint32(8).bool(message.syncStats); + if (message.dbStats === true) { + writer.uint32(8).bool(message.dbStats); } return writer; }, @@ -357,7 +377,7 @@ export const HubInfoRequest = { break; } - message.syncStats = reader.bool(); + message.dbStats = reader.bool(); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -369,12 +389,12 @@ export const HubInfoRequest = { }, fromJSON(object: any): HubInfoRequest { - return { syncStats: isSet(object.syncStats) ? Boolean(object.syncStats) : false }; + return { dbStats: isSet(object.dbStats) ? Boolean(object.dbStats) : false }; }, toJSON(message: HubInfoRequest): unknown { const obj: any = {}; - message.syncStats !== undefined && (obj.syncStats = message.syncStats); + message.dbStats !== undefined && (obj.dbStats = message.dbStats); return obj; }, @@ -384,13 +404,13 @@ export const HubInfoRequest = { fromPartial, I>>(object: I): HubInfoRequest { const message = createBaseHubInfoRequest(); - message.syncStats = object.syncStats ?? false; + message.dbStats = object.dbStats ?? false; return message; }, }; function createBaseHubInfoResponse(): HubInfoResponse { - return { version: '', isSyncing: false, nickname: '', rootHash: '', syncStats: undefined }; + return { version: '', isSyncing: false, nickname: '', rootHash: '', dbStats: undefined }; } export const HubInfoResponse = { @@ -407,8 +427,8 @@ export const HubInfoResponse = { if (message.rootHash !== '') { writer.uint32(34).string(message.rootHash); } - if (message.syncStats !== undefined) { - SyncStats.encode(message.syncStats, writer.uint32(42).fork()).ldelim(); + if (message.dbStats !== undefined) { + DbStats.encode(message.dbStats, writer.uint32(42).fork()).ldelim(); } return writer; }, @@ -453,7 +473,7 @@ export const HubInfoResponse = { break; } - message.syncStats = SyncStats.decode(reader, reader.uint32()); + message.dbStats = DbStats.decode(reader, reader.uint32()); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -470,7 +490,7 @@ export const HubInfoResponse = { isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, nickname: isSet(object.nickname) ? String(object.nickname) : '', rootHash: isSet(object.rootHash) ? String(object.rootHash) : '', - syncStats: isSet(object.syncStats) ? SyncStats.fromJSON(object.syncStats) : undefined, + dbStats: isSet(object.dbStats) ? DbStats.fromJSON(object.dbStats) : undefined, }; }, @@ -480,8 +500,7 @@ export const HubInfoResponse = { message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); message.nickname !== undefined && (obj.nickname = message.nickname); message.rootHash !== undefined && (obj.rootHash = message.rootHash); - message.syncStats !== undefined && - (obj.syncStats = message.syncStats ? SyncStats.toJSON(message.syncStats) : undefined); + message.dbStats !== undefined && (obj.dbStats = message.dbStats ? DbStats.toJSON(message.dbStats) : undefined); return obj; }, @@ -495,18 +514,18 @@ export const HubInfoResponse = { message.isSyncing = object.isSyncing ?? false; message.nickname = object.nickname ?? ''; message.rootHash = object.rootHash ?? ''; - message.syncStats = - object.syncStats !== undefined && object.syncStats !== null ? SyncStats.fromPartial(object.syncStats) : undefined; + message.dbStats = + object.dbStats !== undefined && object.dbStats !== null ? DbStats.fromPartial(object.dbStats) : undefined; return message; }, }; -function createBaseSyncStats(): SyncStats { +function createBaseDbStats(): DbStats { return { numMessages: 0, numFidEvents: 0, numFnameEvents: 0 }; } -export const SyncStats = { - encode(message: SyncStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { +export const DbStats = { + encode(message: DbStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.numMessages !== 0) { writer.uint32(8).uint64(message.numMessages); } @@ -519,10 +538,10 @@ export const SyncStats = { return writer; }, - decode(input: _m0.Reader | Uint8Array, length?: number): SyncStats { + decode(input: _m0.Reader | Uint8Array, length?: number): DbStats { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseSyncStats(); + const message = createBaseDbStats(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -556,7 +575,7 @@ export const SyncStats = { return message; }, - fromJSON(object: any): SyncStats { + fromJSON(object: any): DbStats { return { numMessages: isSet(object.numMessages) ? Number(object.numMessages) : 0, numFidEvents: isSet(object.numFidEvents) ? Number(object.numFidEvents) : 0, @@ -564,7 +583,7 @@ export const SyncStats = { }; }, - toJSON(message: SyncStats): unknown { + toJSON(message: DbStats): unknown { const obj: any = {}; message.numMessages !== undefined && (obj.numMessages = Math.round(message.numMessages)); message.numFidEvents !== undefined && (obj.numFidEvents = Math.round(message.numFidEvents)); @@ -572,12 +591,12 @@ export const SyncStats = { return obj; }, - create, I>>(base?: I): SyncStats { - return SyncStats.fromPartial(base ?? {}); + create, I>>(base?: I): DbStats { + return DbStats.fromPartial(base ?? {}); }, - fromPartial, I>>(object: I): SyncStats { - const message = createBaseSyncStats(); + fromPartial, I>>(object: I): DbStats { + const message = createBaseDbStats(); message.numMessages = object.numMessages ?? 0; message.numFidEvents = object.numFidEvents ?? 0; message.numFnameEvents = object.numFnameEvents ?? 0; @@ -585,6 +604,295 @@ export const SyncStats = { }, }; +function createBaseSyncStatusRequest(): SyncStatusRequest { + return { peerId: undefined }; +} + +export const SyncStatusRequest = { + encode(message: SyncStatusRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== undefined) { + writer.uint32(10).string(message.peerId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusRequest { + return { peerId: isSet(object.peerId) ? String(object.peerId) : undefined }; + }, + + toJSON(message: SyncStatusRequest): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + return obj; + }, + + create, I>>(base?: I): SyncStatusRequest { + return SyncStatusRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusRequest { + const message = createBaseSyncStatusRequest(); + message.peerId = object.peerId ?? undefined; + return message; + }, +}; + +function createBaseSyncStatusResponse(): SyncStatusResponse { + return { isSyncing: false, syncStatus: [] }; +} + +export const SyncStatusResponse = { + encode(message: SyncStatusResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.isSyncing === true) { + writer.uint32(8).bool(message.isSyncing); + } + for (const v of message.syncStatus) { + SyncStatus.encode(v!, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 8) { + break; + } + + message.isSyncing = reader.bool(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.syncStatus.push(SyncStatus.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusResponse { + return { + isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, + syncStatus: Array.isArray(object?.syncStatus) ? object.syncStatus.map((e: any) => SyncStatus.fromJSON(e)) : [], + }; + }, + + toJSON(message: SyncStatusResponse): unknown { + const obj: any = {}; + message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); + if (message.syncStatus) { + obj.syncStatus = message.syncStatus.map((e) => (e ? SyncStatus.toJSON(e) : undefined)); + } else { + obj.syncStatus = []; + } + return obj; + }, + + create, I>>(base?: I): SyncStatusResponse { + return SyncStatusResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusResponse { + const message = createBaseSyncStatusResponse(); + message.isSyncing = object.isSyncing ?? false; + message.syncStatus = object.syncStatus?.map((e) => SyncStatus.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseSyncStatus(): SyncStatus { + return { + peerId: '', + inSync: '', + shouldSync: false, + divergencePrefix: '', + divergenceSecondsAgo: 0, + theirMessages: 0, + ourMessages: 0, + lastBadSync: 0, + }; +} + +export const SyncStatus = { + encode(message: SyncStatus, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== '') { + writer.uint32(10).string(message.peerId); + } + if (message.inSync !== '') { + writer.uint32(18).string(message.inSync); + } + if (message.shouldSync === true) { + writer.uint32(24).bool(message.shouldSync); + } + if (message.divergencePrefix !== '') { + writer.uint32(34).string(message.divergencePrefix); + } + if (message.divergenceSecondsAgo !== 0) { + writer.uint32(40).int32(message.divergenceSecondsAgo); + } + if (message.theirMessages !== 0) { + writer.uint32(48).uint64(message.theirMessages); + } + if (message.ourMessages !== 0) { + writer.uint32(56).uint64(message.ourMessages); + } + if (message.lastBadSync !== 0) { + writer.uint32(64).int64(message.lastBadSync); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatus { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatus(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.inSync = reader.string(); + continue; + case 3: + if (tag != 24) { + break; + } + + message.shouldSync = reader.bool(); + continue; + case 4: + if (tag != 34) { + break; + } + + message.divergencePrefix = reader.string(); + continue; + case 5: + if (tag != 40) { + break; + } + + message.divergenceSecondsAgo = reader.int32(); + continue; + case 6: + if (tag != 48) { + break; + } + + message.theirMessages = longToNumber(reader.uint64() as Long); + continue; + case 7: + if (tag != 56) { + break; + } + + message.ourMessages = longToNumber(reader.uint64() as Long); + continue; + case 8: + if (tag != 64) { + break; + } + + message.lastBadSync = longToNumber(reader.int64() as Long); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatus { + return { + peerId: isSet(object.peerId) ? String(object.peerId) : '', + inSync: isSet(object.inSync) ? String(object.inSync) : '', + shouldSync: isSet(object.shouldSync) ? Boolean(object.shouldSync) : false, + divergencePrefix: isSet(object.divergencePrefix) ? String(object.divergencePrefix) : '', + divergenceSecondsAgo: isSet(object.divergenceSecondsAgo) ? Number(object.divergenceSecondsAgo) : 0, + theirMessages: isSet(object.theirMessages) ? Number(object.theirMessages) : 0, + ourMessages: isSet(object.ourMessages) ? Number(object.ourMessages) : 0, + lastBadSync: isSet(object.lastBadSync) ? Number(object.lastBadSync) : 0, + }; + }, + + toJSON(message: SyncStatus): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + message.inSync !== undefined && (obj.inSync = message.inSync); + message.shouldSync !== undefined && (obj.shouldSync = message.shouldSync); + message.divergencePrefix !== undefined && (obj.divergencePrefix = message.divergencePrefix); + message.divergenceSecondsAgo !== undefined && (obj.divergenceSecondsAgo = Math.round(message.divergenceSecondsAgo)); + message.theirMessages !== undefined && (obj.theirMessages = Math.round(message.theirMessages)); + message.ourMessages !== undefined && (obj.ourMessages = Math.round(message.ourMessages)); + message.lastBadSync !== undefined && (obj.lastBadSync = Math.round(message.lastBadSync)); + return obj; + }, + + create, I>>(base?: I): SyncStatus { + return SyncStatus.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatus { + const message = createBaseSyncStatus(); + message.peerId = object.peerId ?? ''; + message.inSync = object.inSync ?? ''; + message.shouldSync = object.shouldSync ?? false; + message.divergencePrefix = object.divergencePrefix ?? ''; + message.divergenceSecondsAgo = object.divergenceSecondsAgo ?? 0; + message.theirMessages = object.theirMessages ?? 0; + message.ourMessages = object.ourMessages ?? 0; + message.lastBadSync = object.lastBadSync ?? 0; + return message; + }, +}; + function createBaseTrieNodeMetadataResponse(): TrieNodeMetadataResponse { return { prefix: new Uint8Array(), numMessages: 0, hash: '', children: [] }; } diff --git a/packages/hub-nodejs/src/generated/rpc.ts b/packages/hub-nodejs/src/generated/rpc.ts index 2e529181d0..458c796c83 100644 --- a/packages/hub-nodejs/src/generated/rpc.ts +++ b/packages/hub-nodejs/src/generated/rpc.ts @@ -36,6 +36,8 @@ import { SignerRequest, SubscribeRequest, SyncIds, + SyncStatusRequest, + SyncStatusResponse, TrieNodeMetadataResponse, TrieNodePrefix, TrieNodeSnapshotResponse, @@ -299,6 +301,15 @@ export const HubServiceService = { responseSerialize: (value: HubInfoResponse) => Buffer.from(HubInfoResponse.encode(value).finish()), responseDeserialize: (value: Buffer) => HubInfoResponse.decode(value), }, + getSyncStatus: { + path: '/HubService/GetSyncStatus', + requestStream: false, + responseStream: false, + requestSerialize: (value: SyncStatusRequest) => Buffer.from(SyncStatusRequest.encode(value).finish()), + requestDeserialize: (value: Buffer) => SyncStatusRequest.decode(value), + responseSerialize: (value: SyncStatusResponse) => Buffer.from(SyncStatusResponse.encode(value).finish()), + responseDeserialize: (value: Buffer) => SyncStatusResponse.decode(value), + }, getAllSyncIdsByPrefix: { path: '/HubService/GetAllSyncIdsByPrefix', requestStream: false, @@ -377,6 +388,7 @@ export interface HubServiceServer extends UntypedServiceImplementation { getAllUserDataMessagesByFid: handleUnaryCall; /** Sync Methods */ getInfo: handleUnaryCall; + getSyncStatus: handleUnaryCall; getAllSyncIdsByPrefix: handleUnaryCall; getAllMessagesBySyncIds: handleUnaryCall; getSyncMetadataByPrefix: handleUnaryCall; @@ -778,6 +790,21 @@ export interface HubServiceClient extends Client { options: Partial, callback: (error: ServiceError | null, response: HubInfoResponse) => void ): ClientUnaryCall; + getSyncStatus( + request: SyncStatusRequest, + callback: (error: ServiceError | null, response: SyncStatusResponse) => void + ): ClientUnaryCall; + getSyncStatus( + request: SyncStatusRequest, + metadata: Metadata, + callback: (error: ServiceError | null, response: SyncStatusResponse) => void + ): ClientUnaryCall; + getSyncStatus( + request: SyncStatusRequest, + metadata: Metadata, + options: Partial, + callback: (error: ServiceError | null, response: SyncStatusResponse) => void + ): ClientUnaryCall; getAllSyncIdsByPrefix( request: TrieNodePrefix, callback: (error: ServiceError | null, response: SyncIds) => void diff --git a/packages/hub-web/src/generated/request_response.ts b/packages/hub-web/src/generated/request_response.ts index 5f3f162a2b..48a6b8c22b 100644 --- a/packages/hub-web/src/generated/request_response.ts +++ b/packages/hub-web/src/generated/request_response.ts @@ -25,7 +25,7 @@ export interface EventRequest { } export interface HubInfoRequest { - syncStats: boolean; + dbStats: boolean; } /** Response Types for the Sync RPC Methods */ @@ -34,15 +34,35 @@ export interface HubInfoResponse { isSyncing: boolean; nickname: string; rootHash: string; - syncStats: SyncStats | undefined; + dbStats: DbStats | undefined; } -export interface SyncStats { +export interface DbStats { numMessages: number; numFidEvents: number; numFnameEvents: number; } +export interface SyncStatusRequest { + peerId?: string | undefined; +} + +export interface SyncStatusResponse { + isSyncing: boolean; + syncStatus: SyncStatus[]; +} + +export interface SyncStatus { + peerId: string; + inSync: string; + shouldSync: boolean; + divergencePrefix: string; + divergenceSecondsAgo: number; + theirMessages: number; + ourMessages: number; + lastBadSync: number; +} + export interface TrieNodeMetadataResponse { prefix: Uint8Array; numMessages: number; @@ -334,13 +354,13 @@ export const EventRequest = { }; function createBaseHubInfoRequest(): HubInfoRequest { - return { syncStats: false }; + return { dbStats: false }; } export const HubInfoRequest = { encode(message: HubInfoRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.syncStats === true) { - writer.uint32(8).bool(message.syncStats); + if (message.dbStats === true) { + writer.uint32(8).bool(message.dbStats); } return writer; }, @@ -357,7 +377,7 @@ export const HubInfoRequest = { break; } - message.syncStats = reader.bool(); + message.dbStats = reader.bool(); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -369,12 +389,12 @@ export const HubInfoRequest = { }, fromJSON(object: any): HubInfoRequest { - return { syncStats: isSet(object.syncStats) ? Boolean(object.syncStats) : false }; + return { dbStats: isSet(object.dbStats) ? Boolean(object.dbStats) : false }; }, toJSON(message: HubInfoRequest): unknown { const obj: any = {}; - message.syncStats !== undefined && (obj.syncStats = message.syncStats); + message.dbStats !== undefined && (obj.dbStats = message.dbStats); return obj; }, @@ -384,13 +404,13 @@ export const HubInfoRequest = { fromPartial, I>>(object: I): HubInfoRequest { const message = createBaseHubInfoRequest(); - message.syncStats = object.syncStats ?? false; + message.dbStats = object.dbStats ?? false; return message; }, }; function createBaseHubInfoResponse(): HubInfoResponse { - return { version: '', isSyncing: false, nickname: '', rootHash: '', syncStats: undefined }; + return { version: '', isSyncing: false, nickname: '', rootHash: '', dbStats: undefined }; } export const HubInfoResponse = { @@ -407,8 +427,8 @@ export const HubInfoResponse = { if (message.rootHash !== '') { writer.uint32(34).string(message.rootHash); } - if (message.syncStats !== undefined) { - SyncStats.encode(message.syncStats, writer.uint32(42).fork()).ldelim(); + if (message.dbStats !== undefined) { + DbStats.encode(message.dbStats, writer.uint32(42).fork()).ldelim(); } return writer; }, @@ -453,7 +473,7 @@ export const HubInfoResponse = { break; } - message.syncStats = SyncStats.decode(reader, reader.uint32()); + message.dbStats = DbStats.decode(reader, reader.uint32()); continue; } if ((tag & 7) == 4 || tag == 0) { @@ -470,7 +490,7 @@ export const HubInfoResponse = { isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, nickname: isSet(object.nickname) ? String(object.nickname) : '', rootHash: isSet(object.rootHash) ? String(object.rootHash) : '', - syncStats: isSet(object.syncStats) ? SyncStats.fromJSON(object.syncStats) : undefined, + dbStats: isSet(object.dbStats) ? DbStats.fromJSON(object.dbStats) : undefined, }; }, @@ -480,8 +500,7 @@ export const HubInfoResponse = { message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); message.nickname !== undefined && (obj.nickname = message.nickname); message.rootHash !== undefined && (obj.rootHash = message.rootHash); - message.syncStats !== undefined && - (obj.syncStats = message.syncStats ? SyncStats.toJSON(message.syncStats) : undefined); + message.dbStats !== undefined && (obj.dbStats = message.dbStats ? DbStats.toJSON(message.dbStats) : undefined); return obj; }, @@ -495,18 +514,18 @@ export const HubInfoResponse = { message.isSyncing = object.isSyncing ?? false; message.nickname = object.nickname ?? ''; message.rootHash = object.rootHash ?? ''; - message.syncStats = - object.syncStats !== undefined && object.syncStats !== null ? SyncStats.fromPartial(object.syncStats) : undefined; + message.dbStats = + object.dbStats !== undefined && object.dbStats !== null ? DbStats.fromPartial(object.dbStats) : undefined; return message; }, }; -function createBaseSyncStats(): SyncStats { +function createBaseDbStats(): DbStats { return { numMessages: 0, numFidEvents: 0, numFnameEvents: 0 }; } -export const SyncStats = { - encode(message: SyncStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { +export const DbStats = { + encode(message: DbStats, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.numMessages !== 0) { writer.uint32(8).uint64(message.numMessages); } @@ -519,10 +538,10 @@ export const SyncStats = { return writer; }, - decode(input: _m0.Reader | Uint8Array, length?: number): SyncStats { + decode(input: _m0.Reader | Uint8Array, length?: number): DbStats { const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseSyncStats(); + const message = createBaseDbStats(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -556,7 +575,7 @@ export const SyncStats = { return message; }, - fromJSON(object: any): SyncStats { + fromJSON(object: any): DbStats { return { numMessages: isSet(object.numMessages) ? Number(object.numMessages) : 0, numFidEvents: isSet(object.numFidEvents) ? Number(object.numFidEvents) : 0, @@ -564,7 +583,7 @@ export const SyncStats = { }; }, - toJSON(message: SyncStats): unknown { + toJSON(message: DbStats): unknown { const obj: any = {}; message.numMessages !== undefined && (obj.numMessages = Math.round(message.numMessages)); message.numFidEvents !== undefined && (obj.numFidEvents = Math.round(message.numFidEvents)); @@ -572,12 +591,12 @@ export const SyncStats = { return obj; }, - create, I>>(base?: I): SyncStats { - return SyncStats.fromPartial(base ?? {}); + create, I>>(base?: I): DbStats { + return DbStats.fromPartial(base ?? {}); }, - fromPartial, I>>(object: I): SyncStats { - const message = createBaseSyncStats(); + fromPartial, I>>(object: I): DbStats { + const message = createBaseDbStats(); message.numMessages = object.numMessages ?? 0; message.numFidEvents = object.numFidEvents ?? 0; message.numFnameEvents = object.numFnameEvents ?? 0; @@ -585,6 +604,295 @@ export const SyncStats = { }, }; +function createBaseSyncStatusRequest(): SyncStatusRequest { + return { peerId: undefined }; +} + +export const SyncStatusRequest = { + encode(message: SyncStatusRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== undefined) { + writer.uint32(10).string(message.peerId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusRequest { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusRequest { + return { peerId: isSet(object.peerId) ? String(object.peerId) : undefined }; + }, + + toJSON(message: SyncStatusRequest): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + return obj; + }, + + create, I>>(base?: I): SyncStatusRequest { + return SyncStatusRequest.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusRequest { + const message = createBaseSyncStatusRequest(); + message.peerId = object.peerId ?? undefined; + return message; + }, +}; + +function createBaseSyncStatusResponse(): SyncStatusResponse { + return { isSyncing: false, syncStatus: [] }; +} + +export const SyncStatusResponse = { + encode(message: SyncStatusResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.isSyncing === true) { + writer.uint32(8).bool(message.isSyncing); + } + for (const v of message.syncStatus) { + SyncStatus.encode(v!, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatusResponse { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatusResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 8) { + break; + } + + message.isSyncing = reader.bool(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.syncStatus.push(SyncStatus.decode(reader, reader.uint32())); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatusResponse { + return { + isSyncing: isSet(object.isSyncing) ? Boolean(object.isSyncing) : false, + syncStatus: Array.isArray(object?.syncStatus) ? object.syncStatus.map((e: any) => SyncStatus.fromJSON(e)) : [], + }; + }, + + toJSON(message: SyncStatusResponse): unknown { + const obj: any = {}; + message.isSyncing !== undefined && (obj.isSyncing = message.isSyncing); + if (message.syncStatus) { + obj.syncStatus = message.syncStatus.map((e) => (e ? SyncStatus.toJSON(e) : undefined)); + } else { + obj.syncStatus = []; + } + return obj; + }, + + create, I>>(base?: I): SyncStatusResponse { + return SyncStatusResponse.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatusResponse { + const message = createBaseSyncStatusResponse(); + message.isSyncing = object.isSyncing ?? false; + message.syncStatus = object.syncStatus?.map((e) => SyncStatus.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseSyncStatus(): SyncStatus { + return { + peerId: '', + inSync: '', + shouldSync: false, + divergencePrefix: '', + divergenceSecondsAgo: 0, + theirMessages: 0, + ourMessages: 0, + lastBadSync: 0, + }; +} + +export const SyncStatus = { + encode(message: SyncStatus, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.peerId !== '') { + writer.uint32(10).string(message.peerId); + } + if (message.inSync !== '') { + writer.uint32(18).string(message.inSync); + } + if (message.shouldSync === true) { + writer.uint32(24).bool(message.shouldSync); + } + if (message.divergencePrefix !== '') { + writer.uint32(34).string(message.divergencePrefix); + } + if (message.divergenceSecondsAgo !== 0) { + writer.uint32(40).uint64(message.divergenceSecondsAgo); + } + if (message.theirMessages !== 0) { + writer.uint32(48).uint64(message.theirMessages); + } + if (message.ourMessages !== 0) { + writer.uint32(56).uint64(message.ourMessages); + } + if (message.lastBadSync !== 0) { + writer.uint32(64).uint64(message.lastBadSync); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): SyncStatus { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseSyncStatus(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag != 10) { + break; + } + + message.peerId = reader.string(); + continue; + case 2: + if (tag != 18) { + break; + } + + message.inSync = reader.string(); + continue; + case 3: + if (tag != 24) { + break; + } + + message.shouldSync = reader.bool(); + continue; + case 4: + if (tag != 34) { + break; + } + + message.divergencePrefix = reader.string(); + continue; + case 5: + if (tag != 40) { + break; + } + + message.divergenceSecondsAgo = longToNumber(reader.uint64() as Long); + continue; + case 6: + if (tag != 48) { + break; + } + + message.theirMessages = longToNumber(reader.uint64() as Long); + continue; + case 7: + if (tag != 56) { + break; + } + + message.ourMessages = longToNumber(reader.uint64() as Long); + continue; + case 8: + if (tag != 64) { + break; + } + + message.lastBadSync = longToNumber(reader.uint64() as Long); + continue; + } + if ((tag & 7) == 4 || tag == 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): SyncStatus { + return { + peerId: isSet(object.peerId) ? String(object.peerId) : '', + inSync: isSet(object.inSync) ? String(object.inSync) : '', + shouldSync: isSet(object.shouldSync) ? Boolean(object.shouldSync) : false, + divergencePrefix: isSet(object.divergencePrefix) ? String(object.divergencePrefix) : '', + divergenceSecondsAgo: isSet(object.divergenceSecondsAgo) ? Number(object.divergenceSecondsAgo) : 0, + theirMessages: isSet(object.theirMessages) ? Number(object.theirMessages) : 0, + ourMessages: isSet(object.ourMessages) ? Number(object.ourMessages) : 0, + lastBadSync: isSet(object.lastBadSync) ? Number(object.lastBadSync) : 0, + }; + }, + + toJSON(message: SyncStatus): unknown { + const obj: any = {}; + message.peerId !== undefined && (obj.peerId = message.peerId); + message.inSync !== undefined && (obj.inSync = message.inSync); + message.shouldSync !== undefined && (obj.shouldSync = message.shouldSync); + message.divergencePrefix !== undefined && (obj.divergencePrefix = message.divergencePrefix); + message.divergenceSecondsAgo !== undefined && (obj.divergenceSecondsAgo = Math.round(message.divergenceSecondsAgo)); + message.theirMessages !== undefined && (obj.theirMessages = Math.round(message.theirMessages)); + message.ourMessages !== undefined && (obj.ourMessages = Math.round(message.ourMessages)); + message.lastBadSync !== undefined && (obj.lastBadSync = Math.round(message.lastBadSync)); + return obj; + }, + + create, I>>(base?: I): SyncStatus { + return SyncStatus.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): SyncStatus { + const message = createBaseSyncStatus(); + message.peerId = object.peerId ?? ''; + message.inSync = object.inSync ?? ''; + message.shouldSync = object.shouldSync ?? false; + message.divergencePrefix = object.divergencePrefix ?? ''; + message.divergenceSecondsAgo = object.divergenceSecondsAgo ?? 0; + message.theirMessages = object.theirMessages ?? 0; + message.ourMessages = object.ourMessages ?? 0; + message.lastBadSync = object.lastBadSync ?? 0; + return message; + }, +}; + function createBaseTrieNodeMetadataResponse(): TrieNodeMetadataResponse { return { prefix: new Uint8Array(), numMessages: 0, hash: '', children: [] }; } diff --git a/packages/hub-web/src/generated/rpc.ts b/packages/hub-web/src/generated/rpc.ts index 532359ecc8..953e40b134 100644 --- a/packages/hub-web/src/generated/rpc.ts +++ b/packages/hub-web/src/generated/rpc.ts @@ -1,4 +1,5 @@ /* eslint-disable */ +// This must be manually change to a default import right now import grpcWeb from '@improbable-eng/grpc-web'; import { BrowserHeaders } from 'browser-headers'; import { Observable } from 'rxjs'; @@ -26,6 +27,8 @@ import { SignerRequest, SubscribeRequest, SyncIds, + SyncStatusRequest, + SyncStatusResponse, TrieNodeMetadataResponse, TrieNodePrefix, TrieNodeSnapshotResponse, @@ -107,6 +110,7 @@ export interface HubService { ): Promise; /** Sync Methods */ getInfo(request: DeepPartial, metadata?: grpcWeb.grpc.Metadata): Promise; + getSyncStatus(request: DeepPartial, metadata?: grpcWeb.grpc.Metadata): Promise; getAllSyncIdsByPrefix(request: DeepPartial, metadata?: grpcWeb.grpc.Metadata): Promise; getAllMessagesBySyncIds(request: DeepPartial, metadata?: grpcWeb.grpc.Metadata): Promise; getSyncMetadataByPrefix( @@ -151,6 +155,7 @@ export class HubServiceClientImpl implements HubService { this.getAllSignerMessagesByFid = this.getAllSignerMessagesByFid.bind(this); this.getAllUserDataMessagesByFid = this.getAllUserDataMessagesByFid.bind(this); this.getInfo = this.getInfo.bind(this); + this.getSyncStatus = this.getSyncStatus.bind(this); this.getAllSyncIdsByPrefix = this.getAllSyncIdsByPrefix.bind(this); this.getAllMessagesBySyncIds = this.getAllMessagesBySyncIds.bind(this); this.getSyncMetadataByPrefix = this.getSyncMetadataByPrefix.bind(this); @@ -305,6 +310,13 @@ export class HubServiceClientImpl implements HubService { return this.rpc.unary(HubServiceGetInfoDesc, HubInfoRequest.fromPartial(request), metadata); } + getSyncStatus( + request: DeepPartial, + metadata?: grpcWeb.grpc.Metadata + ): Promise { + return this.rpc.unary(HubServiceGetSyncStatusDesc, SyncStatusRequest.fromPartial(request), metadata); + } + getAllSyncIdsByPrefix(request: DeepPartial, metadata?: grpcWeb.grpc.Metadata): Promise { return this.rpc.unary(HubServiceGetAllSyncIdsByPrefixDesc, TrieNodePrefix.fromPartial(request), metadata); } @@ -951,6 +963,29 @@ export const HubServiceGetInfoDesc: UnaryMethodDefinitionish = { } as any, }; +export const HubServiceGetSyncStatusDesc: UnaryMethodDefinitionish = { + methodName: 'GetSyncStatus', + service: HubServiceDesc, + requestStream: false, + responseStream: false, + requestType: { + serializeBinary() { + return SyncStatusRequest.encode(this).finish(); + }, + } as any, + responseType: { + deserializeBinary(data: Uint8Array) { + const value = SyncStatusResponse.decode(data); + return { + ...value, + toObject() { + return value; + }, + }; + }, + } as any, +}; + export const HubServiceGetAllSyncIdsByPrefixDesc: UnaryMethodDefinitionish = { methodName: 'GetAllSyncIdsByPrefix', service: HubServiceDesc, diff --git a/protobufs/schemas/request_response.proto b/protobufs/schemas/request_response.proto index 14866b33d3..5cdfc91f21 100644 --- a/protobufs/schemas/request_response.proto +++ b/protobufs/schemas/request_response.proto @@ -15,7 +15,7 @@ message EventRequest { } message HubInfoRequest { - bool sync_stats = 1; + bool db_stats = 1; } // Response Types for the Sync RPC Methods @@ -24,15 +24,35 @@ message HubInfoResponse { bool is_syncing = 2; string nickname = 3; string root_hash = 4; - SyncStats sync_stats = 5; + DbStats db_stats = 5; } -message SyncStats { +message DbStats { uint64 num_messages = 1; uint64 num_fid_events = 2; uint64 num_fname_events = 3; } +message SyncStatusRequest { + optional string peerId = 1; +} + +message SyncStatusResponse { + bool is_syncing = 1; + repeated SyncStatus sync_status = 2; +} + +message SyncStatus { + string peerId = 1; + string inSync = 2; + bool shouldSync = 3; + string divergencePrefix = 4; + int32 divergenceSecondsAgo = 5; + uint64 theirMessages = 6; + uint64 ourMessages = 7; + int64 lastBadSync = 8; +} + message TrieNodeMetadataResponse { bytes prefix = 1; uint64 num_messages = 2; diff --git a/protobufs/schemas/rpc.proto b/protobufs/schemas/rpc.proto index 7da18f1da7..5dde1647d6 100644 --- a/protobufs/schemas/rpc.proto +++ b/protobufs/schemas/rpc.proto @@ -51,6 +51,7 @@ service HubService { // Sync Methods rpc GetInfo(HubInfoRequest) returns (HubInfoResponse); + rpc GetSyncStatus(SyncStatusRequest) returns (SyncStatusResponse); rpc GetAllSyncIdsByPrefix(TrieNodePrefix) returns (SyncIds); rpc GetAllMessagesBySyncIds(SyncIds) returns (MessagesResponse); rpc GetSyncMetadataByPrefix(TrieNodePrefix) returns (TrieNodeMetadataResponse);