-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add proto * add rpc and interfaces * add protocol implementation * update faulty proto def * add rpc and interfaces * refactor implementation & write test * setup the metadata protocol as a service * fix cases where metadata service needs to be undefined * remove redundant catch block * remove addressed TODO * update import path * log errors * remove redundant code from handling incoming metadata request * update tests * add test to check for active connections * change expects * save remote peer's shard info after successful connection
- Loading branch information
1 parent
12a5534
commit 9ac2a3f
Showing
10 changed files
with
501 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import type { PeerId } from "@libp2p/interface/peer-id"; | ||
import { IncomingStreamData } from "@libp2p/interface/stream-handler"; | ||
import { encodeRelayShard } from "@waku/enr"; | ||
import type { IMetadata, Libp2pComponents, ShardInfo } from "@waku/interfaces"; | ||
import { proto_metadata } from "@waku/proto"; | ||
import { Logger } from "@waku/utils"; | ||
import all from "it-all"; | ||
import * as lp from "it-length-prefixed"; | ||
import { pipe } from "it-pipe"; | ||
import { Uint8ArrayList } from "uint8arraylist"; | ||
|
||
import { BaseProtocol } from "../base_protocol.js"; | ||
|
||
const log = new Logger("metadata"); | ||
|
||
export const MetadataCodec = "/vac/waku/metadata/1.0.0"; | ||
|
||
class Metadata extends BaseProtocol { | ||
private readonly shardInfo: ShardInfo; | ||
private libp2pComponents: Libp2pComponents; | ||
constructor(shardInfo: ShardInfo, libp2p: Libp2pComponents) { | ||
super(MetadataCodec, libp2p.components); | ||
this.libp2pComponents = libp2p; | ||
this.shardInfo = shardInfo; | ||
void libp2p.registrar.handle(MetadataCodec, (streamData) => { | ||
void this.onRequest(streamData); | ||
}); | ||
} | ||
|
||
/** | ||
* Handle an incoming metadata request | ||
*/ | ||
private async onRequest(streamData: IncomingStreamData): Promise<void> { | ||
try { | ||
const { stream, connection } = streamData; | ||
const encodedShardInfo = proto_metadata.WakuMetadataResponse.encode( | ||
this.shardInfo | ||
); | ||
|
||
const encodedResponse = await pipe( | ||
[encodedShardInfo], | ||
lp.encode, | ||
stream, | ||
lp.decode, | ||
async (source) => await all(source) | ||
); | ||
|
||
const remoteShardInfoResponse = | ||
this.decodeMetadataResponse(encodedResponse); | ||
|
||
// add or update the shardInfo to peer store | ||
await this.libp2pComponents.peerStore.merge(connection.remotePeer, { | ||
metadata: { | ||
shardInfo: encodeRelayShard(remoteShardInfoResponse) | ||
} | ||
}); | ||
} catch (error) { | ||
log.error("Error handling metadata request", error); | ||
} | ||
} | ||
|
||
/** | ||
* Make a metadata query to a peer | ||
*/ | ||
async query(peerId: PeerId): Promise<ShardInfo> { | ||
const request = proto_metadata.WakuMetadataRequest.encode(this.shardInfo); | ||
|
||
const peer = await this.getPeer(peerId); | ||
|
||
const stream = await this.getStream(peer); | ||
|
||
const encodedResponse = await pipe( | ||
[request], | ||
lp.encode, | ||
stream, | ||
lp.decode, | ||
async (source) => await all(source) | ||
); | ||
|
||
const decodedResponse = this.decodeMetadataResponse(encodedResponse); | ||
|
||
return decodedResponse; | ||
} | ||
|
||
private decodeMetadataResponse(encodedResponse: Uint8ArrayList[]): ShardInfo { | ||
const bytes = new Uint8ArrayList(); | ||
|
||
encodedResponse.forEach((chunk) => { | ||
bytes.append(chunk); | ||
}); | ||
const response = proto_metadata.WakuMetadataResponse.decode( | ||
bytes | ||
) as ShardInfo; | ||
|
||
if (!response) log.error("Error decoding metadata response"); | ||
|
||
return response; | ||
} | ||
} | ||
|
||
export function wakuMetadata( | ||
shardInfo: ShardInfo | ||
): (components: Libp2pComponents) => IMetadata { | ||
return (components: Libp2pComponents) => new Metadata(shardInfo, components); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import type { PeerId } from "@libp2p/interface/peer-id"; | ||
|
||
import type { ShardInfo } from "./enr.js"; | ||
import type { IBaseProtocol } from "./protocols.js"; | ||
|
||
export interface IMetadata extends IBaseProtocol { | ||
query(peerId: PeerId): Promise<ShardInfo | undefined>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
syntax = "proto3"; | ||
|
||
|
||
message WakuMetadataRequest { | ||
optional uint32 cluster_id = 1; | ||
repeated uint32 shards = 2; | ||
} | ||
|
||
message WakuMetadataResponse { | ||
optional uint32 cluster_id = 1; | ||
repeated uint32 shards = 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/* eslint-disable import/export */ | ||
/* eslint-disable complexity */ | ||
/* eslint-disable @typescript-eslint/no-namespace */ | ||
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */ | ||
/* eslint-disable @typescript-eslint/no-empty-interface */ | ||
|
||
import { encodeMessage, decodeMessage, message } from 'protons-runtime' | ||
import type { Codec } from 'protons-runtime' | ||
import type { Uint8ArrayList } from 'uint8arraylist' | ||
|
||
export interface WakuMetadataRequest { | ||
clusterId?: number | ||
shards: number[] | ||
} | ||
|
||
export namespace WakuMetadataRequest { | ||
let _codec: Codec<WakuMetadataRequest> | ||
|
||
export const codec = (): Codec<WakuMetadataRequest> => { | ||
if (_codec == null) { | ||
_codec = message<WakuMetadataRequest>((obj, w, opts = {}) => { | ||
if (opts.lengthDelimited !== false) { | ||
w.fork() | ||
} | ||
|
||
if (obj.clusterId != null) { | ||
w.uint32(8) | ||
w.uint32(obj.clusterId) | ||
} | ||
|
||
if (obj.shards != null) { | ||
for (const value of obj.shards) { | ||
w.uint32(16) | ||
w.uint32(value) | ||
} | ||
} | ||
|
||
if (opts.lengthDelimited !== false) { | ||
w.ldelim() | ||
} | ||
}, (reader, length) => { | ||
const obj: any = { | ||
shards: [] | ||
} | ||
|
||
const end = length == null ? reader.len : reader.pos + length | ||
|
||
while (reader.pos < end) { | ||
const tag = reader.uint32() | ||
|
||
switch (tag >>> 3) { | ||
case 1: | ||
obj.clusterId = reader.uint32() | ||
break | ||
case 2: | ||
obj.shards.push(reader.uint32()) | ||
break | ||
default: | ||
reader.skipType(tag & 7) | ||
break | ||
} | ||
} | ||
|
||
return obj | ||
}) | ||
} | ||
|
||
return _codec | ||
} | ||
|
||
export const encode = (obj: Partial<WakuMetadataRequest>): Uint8Array => { | ||
return encodeMessage(obj, WakuMetadataRequest.codec()) | ||
} | ||
|
||
export const decode = (buf: Uint8Array | Uint8ArrayList): WakuMetadataRequest => { | ||
return decodeMessage(buf, WakuMetadataRequest.codec()) | ||
} | ||
} | ||
|
||
export interface WakuMetadataResponse { | ||
clusterId?: number | ||
shards: number[] | ||
} | ||
|
||
export namespace WakuMetadataResponse { | ||
let _codec: Codec<WakuMetadataResponse> | ||
|
||
export const codec = (): Codec<WakuMetadataResponse> => { | ||
if (_codec == null) { | ||
_codec = message<WakuMetadataResponse>((obj, w, opts = {}) => { | ||
if (opts.lengthDelimited !== false) { | ||
w.fork() | ||
} | ||
|
||
if (obj.clusterId != null) { | ||
w.uint32(8) | ||
w.uint32(obj.clusterId) | ||
} | ||
|
||
if (obj.shards != null) { | ||
for (const value of obj.shards) { | ||
w.uint32(16) | ||
w.uint32(value) | ||
} | ||
} | ||
|
||
if (opts.lengthDelimited !== false) { | ||
w.ldelim() | ||
} | ||
}, (reader, length) => { | ||
const obj: any = { | ||
shards: [] | ||
} | ||
|
||
const end = length == null ? reader.len : reader.pos + length | ||
|
||
while (reader.pos < end) { | ||
const tag = reader.uint32() | ||
|
||
switch (tag >>> 3) { | ||
case 1: | ||
obj.clusterId = reader.uint32() | ||
break | ||
case 2: | ||
obj.shards.push(reader.uint32()) | ||
break | ||
default: | ||
reader.skipType(tag & 7) | ||
break | ||
} | ||
} | ||
|
||
return obj | ||
}) | ||
} | ||
|
||
return _codec | ||
} | ||
|
||
export const encode = (obj: Partial<WakuMetadataResponse>): Uint8Array => { | ||
return encodeMessage(obj, WakuMetadataResponse.codec()) | ||
} | ||
|
||
export const decode = (buf: Uint8Array | Uint8ArrayList): WakuMetadataResponse => { | ||
return decodeMessage(buf, WakuMetadataResponse.codec()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.