1 | import { create as createLogger } from '../common/log'
|
2 | const log = createLogger('echo')
|
3 | import reduct = require('reduct')
|
4 | import { serializeIlpPrepare, IlpPrepare, Errors } from 'ilp-packet'
|
5 | import { Reader, Writer } from 'oer-utils'
|
6 | import Config from '../services/config'
|
7 | import RouteBuilder from '../services/route-builder'
|
8 | const { InvalidPacketError } = Errors
|
9 |
|
10 | const MINIMUM_ECHO_PACKET_DATA_LENGTH = 16 + 1
|
11 | const ECHO_DATA_PREFIX = Buffer.from('ECHOECHOECHOECHO', 'ascii')
|
12 |
|
13 | export 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)
|
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 | }
|