UNPKG

2.37 kBPlain TextView Raw
1import { create as createLogger } from '../common/log'
2const log = createLogger('echo')
3import reduct = require('reduct')
4import { serializeIlpPrepare, IlpPrepare, Errors } from 'ilp-packet'
5import { Reader, Writer } from 'oer-utils'
6import Config from '../services/config'
7import RouteBuilder from '../services/route-builder'
8const { InvalidPacketError } = Errors
9
10const MINIMUM_ECHO_PACKET_DATA_LENGTH = 16 + 1
11const ECHO_DATA_PREFIX = Buffer.from('ECHOECHOECHOECHO', 'ascii')
12
13export default class EchoController {
14 private config: Config
15 private routeBuilder: RouteBuilder
16
17 constructor (deps: reduct.Injector) {
18 this.config = deps(Config)
19 this.routeBuilder = deps(RouteBuilder)
20 }
21
22 async handle (
23 data: Buffer,
24 sourceAccount: string,
25 { parsedPacket, outbound }: {
26 parsedPacket: IlpPrepare,
27 outbound: (data: Buffer, accountId: string) => Promise<Buffer>
28 }
29 ) {
30 if (parsedPacket.data.length < MINIMUM_ECHO_PACKET_DATA_LENGTH) {
31 throw new InvalidPacketError('packet data too short for echo request. length=' + parsedPacket.data.length)
32 }
33
34 if (!parsedPacket.data.slice(0, 16).equals(ECHO_DATA_PREFIX)) {
35 throw new InvalidPacketError('packet data does not start with ECHO prefix.')
36 }
37
38 const reader = new Reader(parsedPacket.data)
39
40 reader.skip(ECHO_DATA_PREFIX.length)
41
42 const type = reader.readUInt8Number()
43
44 if (type === 0) {
45 const sourceAddress = reader.readVarOctetString().toString('ascii')
46
47 log.trace('responding to ping. sourceAccount=%s sourceAddress=%s cond=%s', sourceAccount, sourceAddress, parsedPacket.executionCondition.slice(0, 9).toString('base64'))
48
49 const nextHop = this.routeBuilder.getNextHop(sourceAccount, sourceAddress)
50
51 const writer = new Writer()
52
53 writer.write(ECHO_DATA_PREFIX)
54
55 writer.writeUInt8(0x01) // type = response
56
57 return outbound(serializeIlpPrepare({
58 amount: parsedPacket.amount,
59 destination: sourceAddress,
60 executionCondition: parsedPacket.executionCondition,
61 expiresAt: new Date(Number(parsedPacket.expiresAt) - this.config.minMessageWindow),
62 data: writer.getBuffer()
63 }), nextHop)
64 } else {
65 log.error('received unexpected ping response. sourceAccount=%s', sourceAccount)
66 throw new InvalidPacketError('unexpected ping response.')
67 }
68 }
69}