1 2
import { create as createLogger } from '../common/log'
2 2
const log = createLogger('alert-middleware')
3
import { Middleware, MiddlewareCallback, Pipelines } from '../types/middleware'
4 2
import * as IlpPacket from 'ilp-packet'
5

6 2
const { T04_INSUFFICIENT_LIQUIDITY } = IlpPacket.Errors.codes
7

8
export interface Alert {
9
  id: number
10
  accountId: string
11
  triggeredBy: string
12
  message: string
13
  count: number
14
  createdAt: Date
15
  updatedAt: Date
16
}
17

18 2
export default class AlertMiddleware implements Middleware {
19 2
  private alerts: {[id: number]: Alert} = {}
20 2
  private nextAlertId: number = Date.now()
21

22
  async applyToPipelines (pipelines: Pipelines, accountId: string) {
23 2
    pipelines.outgoingData.insertLast({
24
      name: 'alert',
25
      method: async (data: Buffer, next: MiddlewareCallback<Buffer, Buffer>) => {
26 2
        const result = await next(data)
27 2
        if (result[0] !== IlpPacket.Type.TYPE_ILP_REJECT) return result
28

29 2
        const rejectPacket = IlpPacket.deserializeIlpReject(result)
30 2
        if (rejectPacket.code !== T04_INSUFFICIENT_LIQUIDITY) return result
31

32
        // The peer rejected a packet which, according to the local balance, should
33
        // have succeeded. This can happen when our local connector owes the peer
34
        // money but restarted before it was settled.
35 2
        if (rejectPacket.message !== 'exceeded maximum balance.') return result
36

37 2
        const { triggeredBy } = rejectPacket
38 2
        log.warn('generating alert for account=%s triggeredBy=%s message="%s"', accountId, triggeredBy, rejectPacket.message)
39 2
        this.addAlert(accountId, triggeredBy, rejectPacket.message)
40

41 2
        return result
42
      }
43
    })
44
  }
45

46
  getAlerts (): Alert[] {
47 2
    return Object.keys(this.alerts)
48 2
      .map((id) => this.alerts[id])
49 0
      .sort((a, b) => a.id - b.id)
50
  }
51

52
  dismissAlert (id: number) {
53 2
    delete this.alerts[id]
54
  }
55

56
  private addAlert (accountId: string, triggeredBy: string, message: string) {
57 2
    const alert = Object.keys(this.alerts)
58 2
      .map((alertId) => this.alerts[alertId])
59
      .find((alert) =>
60 2
        alert.accountId === accountId &&
61
        alert.triggeredBy === triggeredBy &&
62
        alert.message === message)
63 2
    if (alert) {
64 2
      alert.count++
65 2
      alert.updatedAt = new Date()
66 2
      return
67
    }
68

69 2
    const id = this.nextAlertId++
70 2
    const now = new Date()
71 2
    this.alerts[id] = {
72
      id,
73
      accountId,
74
      triggeredBy,
75
      message,
76
      count: 1,
77
      createdAt: now,
78
      updatedAt: now
79
    }
80
  }
81
}

Read our documentation on viewing source code .

Loading