@bsv/overlay
Version:
BSV Blockchain Overlay Services Engine
109 lines (92 loc) • 3.36 kB
text/typescript
import { GASPInitialReply, GASPInitialRequest, GASPInitialResponse, GASPNode, GASPNodeResponse, GASPRemote } from '@bsv/gasp'
export class OverlayGASPRemote implements GASPRemote {
constructor (public endpointURL: string, public topic: string) { }
/**
* Given an outgoing initial request, sends the request to the foreign instance and obtains their initial response.
* @param request
* @returns
*/
async getInitialResponse (request: GASPInitialRequest): Promise<GASPInitialResponse> {
// Send out an HTTP request to the URL (current host for topic)
// Include the topic in the request
// Parse out response and return correct format
const url = `${this.endpointURL}/requestSyncResponse`
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-BSV-Topic': this.topic
},
body: JSON.stringify(request)
})
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
const result: GASPInitialResponse = await response.json()
// Validate and return the response in the correct format
if (!Array.isArray(result.UTXOList) || typeof result.since !== 'number') {
throw new Error('Invalid response format')
}
return {
UTXOList: result.UTXOList.map((utxo: any) => ({
txid: utxo.txid,
outputIndex: utxo.outputIndex,
score: utxo.score ?? 0
})),
since: result.since
}
}
/**
* Given an outgoing txid, outputIndex and optional metadata, request the associated GASP node from the foreign instance.
* @param graphID
* @param txid
* @param outputIndex
* @param metadata
* @returns
*/
async requestNode (graphID: string, txid: string, outputIndex: number, metadata: boolean): Promise<GASPNode> {
// Send an HTTP request with the provided info and get back a gaspNode
const url = `${this.endpointURL}/requestForeignGASPNode`
const body = {
graphID,
txid,
outputIndex,
metadata
}
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
const result = await response.json()
// Validate and return the response in the correct format
if (typeof result.graphID !== 'string' || typeof result.rawTx !== 'string' || typeof result.outputIndex !== 'number') {
throw new Error('Invalid response format')
}
const gaspNode: GASPNode = {
graphID: result.graphID,
rawTx: result.rawTx,
outputIndex: result.outputIndex,
proof: result.proof,
txMetadata: result.txMetadata,
outputMetadata: result.outputMetadata,
inputs: result.inputs
}
return gaspNode
}
// ---- Now optional methods ----
// When are only syncing to them
async getInitialReply (response: GASPInitialResponse): Promise<GASPInitialReply> {
throw new Error('Function not supported!')
}
// Only used when supporting bidirectional sync.
// Overlay services does not support this.
async submitNode (node: GASPNode): Promise<GASPNodeResponse | undefined> {
throw new Error('Node submission not supported!')
}
}