[enh] add BMA watcher + reorganize code

This commit is contained in:
2019-06-08 18:34:39 +02:00
parent d02de7842f
commit 5544d56ebb
13 changed files with 232 additions and 606 deletions

View File

@@ -1,12 +1,14 @@
import {Conf} from './conf'
import {Conf} from './types/conf'
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import {ws2pWatcher} from "./ws2p/ws2p-watcher";
import {ws2pWatcher} from "./watchers/ws2p/ws2p-watcher";
import {bmaWatcher} from "./watchers/bma/bma-watcher";
export async function dwatch(confFile: string) {
const yml = fs.readFileSync(confFile, 'utf8')
const conf = yaml.load(yml) as Conf
await Promise.all(conf.ws2pServers.map(ws2pWatcher(conf)))
await Promise.all((conf.ws2pServers || []).map(ws2pWatcher(conf)))
await Promise.all((conf.bmaServers || []).map(bmaWatcher(conf)))
}

69
src/lib/mail.ts Normal file
View File

@@ -0,0 +1,69 @@
import {moment} from "duniter/app/lib/common-libs/moment";
import {Conf} from "./types/conf";
import {ConfMail} from './types/conf'
import * as nodemailer from 'nodemailer'
export async function sendMail(conf: ConfMail, subject: string, html: string) {
if (conf.enabled) {
let transporter = nodemailer.createTransport({
host: conf.host,
port: conf.port,
secure: false, // true for 465, false for other ports
auth: {
user: conf.username, // generated ethereal user
pass: conf.apikey // generated ethereal password
},
authMethod: conf.auth,
requireTLS: true,
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: conf.from,
to: conf.to,
subject,
html
})
}
}
export const mail = {
onEstablished: (conf: Conf, target: string) => {
return async () => {
console.log('Connection established')
await sendMail(conf.mail, '[dwatcher] Connection established', `
<p>
Connection to ${target} established on ${moment().format('DD-MM-YYYY HH:mm:ss')}.
</p>
`)
}
},
onDisconnect: (conf: Conf, target: string) => {
return async (waitingDelay: number) => {
console.log('Connection closed')
console.log('Waiting %s seconds...', waitingDelay)
await sendMail(conf.mail, '[dwatcher] Connection closed', `
<p>
Connection to ${target} was lost on ${moment().format('dd-MM-YYYY HH:mm:ss')}.
</p>
<p>
Waiting ${(waitingDelay / 1000).toFixed(0)} seconds before trying to reconnect.
</p>
`)
}
},
onRestartSuccess: (conf: Conf, target: string) => {
return async () => {
console.log('Connection recovered')
await sendMail(conf.mail, '[dwatcher] Connection recovered', `
<p>
Connection to ${target} was lost on ${moment().format('dd-MM-YYYY HH:mm:ss')}.
</p>
`)
}
}
}

View File

@@ -1,27 +0,0 @@
import * as nodemailer from 'nodemailer'
import {ConfMail} from './conf'
export async function sendMail(conf: ConfMail, subject: string, html: string) {
if (conf.enabled) {
let transporter = nodemailer.createTransport({
host: conf.host,
port: conf.port,
secure: false, // true for 465, false for other ports
auth: {
user: conf.username, // generated ethereal user
pass: conf.apikey // generated ethereal password
},
authMethod: conf.auth,
requireTLS: true,
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: conf.from,
to: conf.to,
subject,
html
})
}
}

View File

@@ -1,11 +1,12 @@
export interface Conf {
connectionTimeout: number
reconnectionDelays: number[]
ws2pServers: ConfServers[]
ws2pServers: ConfWS2P[]
bmaServers: ConfBMA[]
mail: ConfMail
}
export interface ConfServers {
export interface ConfWS2P {
address: string
expectedKey: string
salt: string
@@ -13,6 +14,11 @@ export interface ConfServers {
currency: string
}
export interface ConfBMA {
address: string
frequency: number
}
export interface ConfMail {
enabled: boolean
host: string

View File

@@ -1,6 +1,4 @@
import {WS2PConnection} from 'duniter/app/modules/ws2p/lib/WS2PConnection'
export async function processHandler(
export async function watcherLoop(
connect: () => Promise<void>,
onConnectionClosed: () => Promise<void>,
reconnectionDelays: number[],
@@ -12,7 +10,6 @@ export async function processHandler(
) {
let hasStarted = false
let connecting = await connect()
;(async () => {
@@ -23,11 +20,10 @@ export async function processHandler(
if (hasStarted) {
await onRestart()
connecting = await connect()
}
// Connection trial
await connecting
await connect()
if (!hasStarted) {
hasStarted = true

View File

@@ -0,0 +1,51 @@
import {watcherLoop} from "../../watcherLoop";
import {Conf, ConfBMA} from "../../types/conf";
import Axios from "axios";
import {mail} from "../../mail";
export function bmaWatcher(conf: Conf) {
const URL_PATH = '/blockchain/current'
return async (bmaServer: ConfBMA) => {
let nodeDownRes: () => void
let nodeDownPromise: Promise<void> = new Promise(res => nodeDownRes = res)
await watcherLoop(
async () => {
await Axios.get(bmaServer.address + URL_PATH)
let interval = setInterval(async () => {
try {
await Axios.get(bmaServer.address + URL_PATH)
} catch (e) {
clearInterval(interval)
nodeDownRes()
// Re-create down promise for future connection trial
nodeDownPromise = new Promise(res => nodeDownRes = res)
}
}, bmaServer.frequency)
},
() => nodeDownPromise,
conf.reconnectionDelays,
mail.onEstablished(conf, bmaServer.address),
// When a disconnection is detected
mail.onDisconnect(conf, bmaServer.address),
async () => {
console.log('Trying to connect to %s', bmaServer.address)
},
mail.onRestartSuccess(conf, bmaServer.address),
async (e) => {
console.error(e.message)
}
)
}
}

View File

@@ -0,0 +1,62 @@
import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "duniter/app/modules/ws2p/lib/WS2PConnection";
import {watcherLoop} from "../../watcherLoop";
import {MessageHandler} from "./message-handler";
import {Conf, ConfWS2P} from "../../types/conf";
import {Scrypt} from "duniter/app/modules/keypair/lib/scrypt";
import {Key} from "duniter/app/lib/common-libs/crypto/keyring";
import {mail} from "../../mail";
export function ws2pWatcher(conf: Conf) {
let c: WS2PConnection
return async (wserver: ConfWS2P) => {
const keys = await Scrypt(wserver.salt, wserver.passwd)
const keypair = new Key(keys.pub, keys.sec)
await watcherLoop(
async () => {
const localAuth = new WS2PPubkeyLocalAuth(wserver.currency, keypair, "", async () => true)
const remoteAuth = new WS2PPubkeyRemoteAuth(wserver.currency, keypair, async () => true)
c = WS2PConnection.newConnectionToAddress(
1,
wserver.address,
new MessageHandler(),
localAuth,
remoteAuth,
undefined,
{
connectionTimeout: conf.connectionTimeout,
requestTimeout: 0 // No request anyway
},
wserver.expectedKey
)
await c.connectAsInitiator()
},
() => c.closed,
conf.reconnectionDelays,
mail.onEstablished(conf, wserver.expectedKey),
// When a disconnection is detected
mail.onDisconnect(conf, wserver.expectedKey),
async () => {
console.log('Trying to connect to %s', wserver.expectedKey)
},
mail.onRestartSuccess(conf, wserver.expectedKey),
async (e) => {
console.error(e)
}
)
}
}

View File

@@ -1,88 +0,0 @@
import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "duniter/app/modules/ws2p/lib/WS2PConnection";
import {processHandler} from "../processHandler";
import {MessageHandler} from "../message-handler";
import {sendMail} from "../sendMail";
import {moment} from "duniter/app/lib/common-libs/moment";
import {Conf, ConfServers} from "../conf";
import {Scrypt} from "duniter/app/modules/keypair/lib/scrypt";
import {Key} from "duniter/app/lib/common-libs/crypto/keyring";
export function ws2pWatcher(conf: Conf) {
return async (wserver: ConfServers) => {
const keys = await Scrypt(wserver.salt, wserver.passwd)
const keypair = new Key(keys.pub, keys.sec)
let c: WS2PConnection
await processHandler(
async () => {
const localAuth = new WS2PPubkeyLocalAuth(wserver.currency, keypair, "", async () => true)
const remoteAuth = new WS2PPubkeyRemoteAuth(wserver.currency, keypair, async () => true)
c = WS2PConnection.newConnectionToAddress(
1,
wserver.address,
new MessageHandler(),
localAuth,
remoteAuth,
undefined,
{
connectionTimeout: conf.connectionTimeout,
requestTimeout: 0 // No request anyway
},
wserver.expectedKey
)
await c.connectAsInitiator()
},
() => c.closed,
conf.reconnectionDelays,
async () => {
console.log('Connection established')
await sendMail(conf.mail, '[dwatcher] Connection established', `
<p>
Connection to ${c.pubkey} established on ${moment().format('DD-MM-YYYY HH:mm:ss')}.
</p>
`)
},
// When a disconnection is detected
async (waitingDelay) => {
console.log('Connection closed')
console.log('Waiting %s seconds...', waitingDelay)
await sendMail(conf.mail, '[dwatcher] Connection closed', `
<p>
Connection to ${c.pubkey} was lost on ${moment().format('dd-MM-YYYY HH:mm:ss')}.
</p>
<p>
Waiting ${(waitingDelay / 1000).toFixed(0)} seconds before trying to reconnect.
</p>
`)
},
async () => {
console.log('Trying to connect to %s', c.pubkey)
},
async () => {
console.log('Connection recovered')
await sendMail(conf.mail, '[dwatcher] Connection recovered', `
<p>
Connection to ${c.pubkey} was lost on ${moment().format('dd-MM-YYYY HH:mm:ss')}.
</p>
`)
},
async (e) => {
console.error(e)
}
)
}
}