diff --git a/app/modules/crawler/index.ts b/app/modules/crawler/index.ts index 8eff8439a3633275c32dcc25c4b45f99524e6ad7..cec5c2fe5e7db9867be5be055889124f399d0d77 100644 --- a/app/modules/crawler/index.ts +++ b/app/modules/crawler/index.ts @@ -21,6 +21,12 @@ import {rawer} from "../../lib/common-libs/index" import {PeerDTO} from "../../lib/dto/PeerDTO" import {Buid} from "../../lib/common-libs/buid" import {BlockDTO} from "../../lib/dto/BlockDTO" +import {NewLogger} from "../../lib/logger" +import {connect} from "./lib/connect" +import {applyMempoolRequirements, pullSandboxToLocalServer} from "./lib/sandbox" + +const HOST_PATTERN = /^[^:/]+(:[0-9]{1,5})?$/ +const FILE_PATTERN = /^(\/.+)$/ export const CrawlerDependency = { duniter: { @@ -168,6 +174,66 @@ export const CrawlerDependency = { } } }, { + name: 'sync-mempool <from>', + desc: 'Import all pending data from matching <search>', + onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => { + const source: string = params[0] + if (!source || !(source.match(HOST_PATTERN) || source.match(FILE_PATTERN))) { + throw 'Source of sync is required. (host[:port])' + } + const logger = NewLogger() + const from: string = params[0] + const { host, port } = extractHostPort(from) + try { + const peer = PeerDTO.fromJSONObject({ endpoints: [['BASIC_MERKLED_API', host, port].join(' ')] }) + const fromHost = peer.getHostPreferDNS(); + const fromPort = peer.getPort(); + logger.info('Looking at %s:%s...', fromHost, fromPort); + try { + const fromHost = await connect(peer, 60*1000) + await pullSandboxToLocalServer(server.conf.currency, fromHost, server, logger) + } catch (e) { + logger.error(e); + } + + await server.disconnect(); + } catch(e) { + logger.error(e); + throw Error("Exiting"); + } + } + }, { + name: 'sync-mempool-search <from> <search>', + desc: 'Import all pending data from matching <search>', + onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => { + const source: string = params[0] + const search: string = params[1] + if (!source || !(source.match(HOST_PATTERN) || source.match(FILE_PATTERN))) { + throw 'Source of sync is required. (host[:port])' + } + const logger = NewLogger() + const from: string = params[0] + const { host, port } = extractHostPort(from) + try { + const peer = PeerDTO.fromJSONObject({ endpoints: [['BASIC_MERKLED_API', host, port].join(' ')] }) + const fromHost = peer.getHostPreferDNS(); + const fromPort = peer.getPort(); + logger.info('Looking at %s:%s...', fromHost, fromPort); + try { + const fromHost = await connect(peer) + const res = await fromHost.getRequirements(search) + await applyMempoolRequirements(server.conf.currency, res, server, logger) + } catch (e) { + logger.error(e); + } + + await server.disconnect(); + } catch(e) { + logger.error(e); + throw Error("Exiting"); + } + } + }, { name: 'forward <number> <fromHost> <fromPort> <toHost> <toPort>', desc: 'Forward existing block <number> from a host to another', onDatabaseExecute: async (server:Server, conf:ConfDTO, program:any, params:any) => { @@ -357,3 +423,13 @@ export const CrawlerDependency = { }] } } + +function extractHostPort(source: string) { + const sp = source.split(':') + const onHost = sp[0] + const onPort = parseInt(sp[1] ? sp[1] : '443') // Defaults to 443 + return { + host: onHost, + port: onPort, + } +} \ No newline at end of file diff --git a/app/modules/crawler/lib/contacter.ts b/app/modules/crawler/lib/contacter.ts index c2e93c4e33f568f5147afa128f851723706e46ff..3742b09dd39ec8a28213701d954586e017a68eae 100644 --- a/app/modules/crawler/lib/contacter.ts +++ b/app/modules/crawler/lib/contacter.ts @@ -22,7 +22,7 @@ export class Contacter { options:{ timeout:number } fullyQualifiedHost:string - constructor(private host:string, private port:number, opts:any = {}) { + constructor(public host:string, public port:number, opts:any = {}) { this.options = { timeout: (opts && opts.timeout) || CrawlerConstants.DEFAULT_TIMEOUT } diff --git a/app/modules/crawler/lib/sandbox.ts b/app/modules/crawler/lib/sandbox.ts index 58d3d79a7a1f6bde1b4a37ebf106dcdff4d392c5..cf70e0ed1f93f6af7ddb5cc08d8b5b99937b9be1 100644 --- a/app/modules/crawler/lib/sandbox.ts +++ b/app/modules/crawler/lib/sandbox.ts @@ -12,75 +12,58 @@ // GNU Affero General Public License for more details. "use strict"; -import {Contacter} from "./contacter" import {Server} from "../../../../server" import {rawer} from "../../../lib/common-libs/index" import {parsers} from "../../../lib/common-libs/parsers/index" +import {HttpRequirements} from "../../bma/lib/dtos" -export const pullSandbox = async (currency:string, fromHost:string, fromPort:number, toHost:string, toPort:number, logger:any) => { - const from = new Contacter(fromHost, fromPort); - const to = new Contacter(toHost, toPort); - +export const pullSandboxToLocalServer = async (currency:string, fromHost: { + getRequirementsPending(minCert?: number): Promise<any> + host?: string + port?: number +}, toServer:Server, logger:any, watcher:any = null, nbCertsMin = 1, notify = true) => { let res try { - res = await from.getRequirementsPending(1) + res = await fromHost.getRequirementsPending(nbCertsMin || 1) } catch (e) { - // Silent error - logger && logger.trace('Sandbox pulling: could not fetch requirements on %s', [fromHost, fromPort].join(':')) + watcher && watcher.writeStatus('Sandbox pulling: could not fetch requirements on %s', [fromHost.host, fromHost.port].join(':')) } if (res) { - const docs = getDocumentsTree(currency, res) - for (const identity of docs.identities) { - await submitIdentity(identity, to) - } - for (const certification of docs.certifications) { - await submitCertification(certification, to) - } - for (const membership of docs.memberships) { - await submitMembership(membership, to) - } + await applyMempoolRequirements(currency, res, toServer) } } -export const pullSandboxToLocalServer = async (currency:string, fromHost:any, toServer:Server, logger:any, watcher:any = null, nbCertsMin = 1, notify = true) => { - let res - try { - res = await fromHost.getRequirementsPending(nbCertsMin || 1) - } catch (e) { - watcher && watcher.writeStatus('Sandbox pulling: could not fetch requirements on %s', [fromHost.host, fromHost.port].join(':')) - } +export async function applyMempoolRequirements(currency: string, res: HttpRequirements, toServer: Server, notify = true, logger?: any, watcher?: any) { - if (res) { - const docs = getDocumentsTree(currency, res) + const docs = getDocumentsTree(currency, res) - for (let i = 0; i < docs.identities.length; i++) { - const idty = docs.identities[i]; - watcher && watcher.writeStatus('Identity ' + (i+1) + '/' + docs.identities.length) - await submitIdentityToServer(idty, toServer, notify, logger) - } + for (let i = 0; i < docs.identities.length; i++) { + const idty = docs.identities[i]; + watcher && watcher.writeStatus('Identity ' + (i+1) + '/' + docs.identities.length) + await submitIdentityToServer(idty, toServer, notify, logger) + } - for (let i = 0; i < docs.revocations.length; i++) { - const idty = docs.revocations[i]; - watcher && watcher.writeStatus('Revocation ' + (i+1) + '/' + docs.revocations.length) - await submitRevocationToServer(idty, toServer, notify, logger) - } + for (let i = 0; i < docs.revocations.length; i++) { + const idty = docs.revocations[i]; + watcher && watcher.writeStatus('Revocation ' + (i+1) + '/' + docs.revocations.length) + await submitRevocationToServer(idty, toServer, notify, logger) + } - for (let i = 0; i < docs.certifications.length; i++) { - const cert = docs.certifications[i]; - watcher && watcher.writeStatus('Certification ' + (i+1) + '/' + docs.certifications.length) - await submitCertificationToServer(cert, toServer, notify, logger) - } + for (let i = 0; i < docs.certifications.length; i++) { + const cert = docs.certifications[i]; + watcher && watcher.writeStatus('Certification ' + (i+1) + '/' + docs.certifications.length) + await submitCertificationToServer(cert, toServer, notify, logger) + } - for (let i = 0; i < docs.memberships.length; i++) { - const ms = docs.memberships[i]; - watcher && watcher.writeStatus('Membership ' + (i+1) + '/' + docs.memberships.length) - await submitMembershipToServer(ms, toServer, notify, logger) - } + for (let i = 0; i < docs.memberships.length; i++) { + const ms = docs.memberships[i]; + watcher && watcher.writeStatus('Membership ' + (i+1) + '/' + docs.memberships.length) + await submitMembershipToServer(ms, toServer, notify, logger) } } -function getDocumentsTree(currency:string, res:any) { +function getDocumentsTree(currency:string, res:HttpRequirements) { const documents:any = { identities: [], certifications: [], @@ -136,33 +119,6 @@ function getDocumentsTree(currency:string, res:any) { return documents } -async function submitIdentity(idty:any, to:any, logger:any = null) { - try { - await to.postIdentity(idty) - logger && logger.trace('Sandbox pulling: success with identity \'%s\'', idty.uid) - } catch (e) { - // Silent error - } -} - -async function submitCertification(cert:any, to:any, logger:any = null) { - try { - await to.postCert(cert) - logger && logger.trace('Sandbox pulling: success with cert key %s => %s', cert.from.substr(0, 6), cert.idty_uid) - } catch (e) { - // Silent error - } -} - -async function submitMembership(ms:any, to:any, logger:any = null) { - try { - await to.postRenew(ms) - logger && logger.trace('Sandbox pulling: success with membership \'%s\'', ms.uid) - } catch (e) { - // Silent error - } -} - async function submitIdentityToServer(idty:any, toServer:any, notify:boolean, logger:any) { try { const obj = parsers.parseIdentity.syncWrite(idty)