[enh] add BMA watcher + reorganize code
This commit is contained in:
@@ -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
69
src/lib/mail.ts
Normal 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>
|
||||
`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
51
src/lib/watchers/bma/bma-watcher.ts
Normal file
51
src/lib/watchers/bma/bma-watcher.ts
Normal 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)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
62
src/lib/watchers/ws2p/ws2p-watcher.ts
Normal file
62
src/lib/watchers/ws2p/ws2p-watcher.ts
Normal 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)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user