UNPKG

nodeway-raft

Version:

It is an implementation of the Raft consensus algorithm in Nodeway.

125 lines (114 loc) 3.24 kB
#!/usr/bin/env node const readline = require('readline'); const require2 = require('require-from-url/async'); const colors = require('colors/safe'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true }), ctor = {}, node = {}, related = {} async function joint(...args) { let url = args.shift(), op = args.shift(); if(!ctor[url]) { let [API] = await require2([url]); ctor[url] = new API; } return ctor[url][op](...args); } async function _join(url) { try { await joint(url[0], 'join', url[1]); console.log(url[0], '->', url[1], 'ok'); } catch(e) { console.log(url[0], '->', url[1], colors.red(e.message)); } } async function join(url) { let o = await joint(url, 'info'); for(let v of o.polls) related[v.uuid] = url; for(let id in node) if(node[id].url===url) id!==o.id && delete node[id]; else { o.polls.find(v => id===v.link) || await _join([url, node[id].url]); o.pushs.find(v => id===v.link) || await _join([node[id].url, url]); } node[o.id] = Object.assign({url}, o); } async function _leave(url) { try { await joint(url[0], 'leave', url[1]); console.log(url[0], 'x>', url[2], 'ok'); } catch(e) { console.log(url[0], 'x>', url[2], colors.red(e.message)); } } async function leave(url) { let ID = Object.keys(node).find(id => node[id].url===url); if(!ID) console.log(url, colors.green('not in consensus')); else { delete node[ID]; for(let id in node) { await _leave([url, id, node[id].url]); await _leave([node[id].url, ID, url]); } } } rl.prompt(); rl.on('line', async line => { try { let word = line.split(/\s+/); switch(word[0]) { case 'show': for(let id in node) await join(node[id].url); for(let id in node) show(node[id]); break; case 'join': await join(word[1]); break; case 'leave': await leave(word[1]); break; case 'follower': case 'weakened': await joint(word[1], word[0]); break; case 'client': let result = await joint(word[1], 'client', JSON.parse(word.slice(2).join(' '))); console.log('result:', result); case '': break; case 'quit': process.exit(0); default: help(); } } catch(e) { console.log(colors.red(e.message)); } rl.prompt(); }).on('close', () => { console.log('quit'); process.exit(0); }); function help() { console.log('show'); console.log('join <url>'); console.log('leave <url>'); console.log('follower <url>'); console.log('weakened <url>'); console.log('client <url> <command>'); console.log('quit'); } function show(o) { console.log([ o.url+' ['+o.state+']', ' poll:', ...o.polls.map(v => ' '+v.url+' ['+!!v.link+']'), ' push:', ...o.pushs.map(v => ' '+related[v.uuid]+' ['+!!v.link+']') ].join('\n')); }