1 | import * as IlpPacket from 'ilp-packet'
|
2 | import { create as createLogger } from '../common/log'
|
3 | const log = createLogger('ilp-prepare')
|
4 | import reduct = require('reduct')
|
5 |
|
6 | import Accounts from '../services/accounts'
|
7 | import RouteBuilder from '../services/route-builder'
|
8 | import RateBackend from '../services/rate-backend'
|
9 | import PeerProtocolController from '../controllers/peer-protocol'
|
10 | import EchoController from '../controllers/echo'
|
11 |
|
12 | const PEER_PROTOCOL_PREFIX = 'peer.'
|
13 |
|
14 | export default class IlpPrepareController {
|
15 | private accounts: Accounts
|
16 | private routeBuilder: RouteBuilder
|
17 | private backend: RateBackend
|
18 | private peerProtocolController: PeerProtocolController
|
19 | private echoController: EchoController
|
20 |
|
21 | constructor (deps: reduct.Injector) {
|
22 | this.accounts = deps(Accounts)
|
23 | this.routeBuilder = deps(RouteBuilder)
|
24 | this.backend = deps(RateBackend)
|
25 | this.peerProtocolController = deps(PeerProtocolController)
|
26 | this.echoController = deps(EchoController)
|
27 | }
|
28 |
|
29 | async sendData (
|
30 | packet: Buffer,
|
31 | sourceAccount: string,
|
32 | outbound: (data: Buffer, accountId: string) => Promise<Buffer>
|
33 | ) {
|
34 | const parsedPacket = IlpPacket.deserializeIlpPrepare(packet)
|
35 | const { amount, executionCondition, destination, expiresAt } = parsedPacket
|
36 |
|
37 | log.trace('handling ilp prepare. sourceAccount=%s destination=%s amount=%s condition=%s expiry=%s packet=%s', sourceAccount, destination, amount, executionCondition.toString('base64'), expiresAt.toISOString(), packet.toString('base64'))
|
38 |
|
39 | if (destination.startsWith(PEER_PROTOCOL_PREFIX)) {
|
40 | return this.peerProtocolController.handle(packet, sourceAccount, { parsedPacket })
|
41 | } else if (destination === this.accounts.getOwnAddress()) {
|
42 | return this.echoController.handle(packet, sourceAccount, { parsedPacket, outbound })
|
43 | }
|
44 |
|
45 | const { nextHop, nextHopPacket } = await this.routeBuilder.getNextHopPacket(sourceAccount, parsedPacket)
|
46 |
|
47 | log.trace('sending outbound ilp prepare. destination=%s amount=%s', destination, nextHopPacket.amount)
|
48 | const result = await outbound(IlpPacket.serializeIlpPrepare(nextHopPacket), nextHop)
|
49 |
|
50 | this.backend.submitPacket({
|
51 | sourceAccount: sourceAccount,
|
52 | sourceAmount: amount,
|
53 | destinationAccount: nextHop,
|
54 | destinationAmount: nextHopPacket.amount,
|
55 | parsedPacket,
|
56 | result
|
57 | }).catch(err => {
|
58 | const errInfo = (err && typeof err === 'object' && err.stack) ? err.stack : String(err)
|
59 | log.error('error while submitting packet to backend. error=%s', errInfo)
|
60 | })
|
61 |
|
62 | if (result[0] === IlpPacket.Type.TYPE_ILP_FULFILL) {
|
63 | log.trace('got fulfillment. cond=%s nextHop=%s amount=%s', executionCondition.slice(0, 6).toString('base64'), nextHop, nextHopPacket.amount)
|
64 |
|
65 | this.backend.submitPayment({
|
66 | sourceAccount: sourceAccount,
|
67 | sourceAmount: amount,
|
68 | destinationAccount: nextHop,
|
69 | destinationAmount: nextHopPacket.amount
|
70 | })
|
71 | .catch(err => {
|
72 | const errInfo = (err && typeof err === 'object' && err.stack) ? err.stack : String(err)
|
73 | log.error('error while submitting payment to backend. error=%s', errInfo)
|
74 | })
|
75 | } else if (result[0] === IlpPacket.Type.TYPE_ILP_REJECT) {
|
76 | const parsed = IlpPacket.deserializeIlpReject(result)
|
77 |
|
78 | log.trace('got rejection. cond=%s nextHop=%s amount=%s code=%s triggeredBy=%s message=%s', executionCondition.slice(0, 6).toString('base64'), nextHop, nextHopPacket.amount, parsed.code, parsed.triggeredBy, parsed.message)
|
79 | }
|
80 |
|
81 | return result
|
82 | }
|
83 | }
|