int-cli
Version:
INT is the new generation of bottom-up created system of IoT and blockchain
196 lines (195 loc) • 8.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const error_code_1 = require("../error_code");
const net_1 = require("../net");
const connection_1 = require("./connection");
const { P2P, Util, DHTAPPID } = require('bdt-p2p');
class BdtNode extends net_1.INode {
// 初始化传入tcp port和udp port,传入0就不监听对应协议
// @param options {
// logger.level ['off', 'all', 'debug', 'info', 'trace', 'warn']
// }
constructor(options) {
super(options);
// vport 只是提供给bdt connect的一个抽象,可以不用在调用时传入
// 先定死, bdt connect 和 listen都先用这个
this.m_vport = 3000;
this.m_skipList = [];
this.m_tcpListenPort = options.tcpport;
this.m_udpListenPort = options.udpport;
this.m_host = options.host;
this.m_options = Object.create(null);
Object.assign(this.m_options, options);
this.m_skipList.push(options.peerid);
this.m_skipList.push(this.m_options.snPeer.peerid);
this.m_bdtStack = undefined;
}
async init() {
if (this.m_bdtStack) {
return;
}
// bdt 的log控制参数
P2P.debug({
level: this.m_options.bdtLoggerOptions.level,
file_dir: this.m_options.bdtLoggerOptions.file_dir,
file_name: this.m_options.bdtLoggerOptions.file_name,
});
// 初始化 bdt
await this.createBDTStack();
}
async createBDTStack() {
// let randomPort = DHTUtil.RandomGenerator.integer(65525, 2048);
// bdt 里0.0.0.0 只能找到公网ip, 这样会导致单机多进程或单机单进程的节点找不到对方
// 为了方便测试, 补充加入本机的内网192 IP
// 从配置文件里读取初始的DHT表
let ips = Util.NetHelper.getLocalIPV4().filter((ip) => ip.match(/^192.168.\d+.\d+/));
let addrList = [this.m_host, ...ips];
let dhtEntry = [this.m_options.snPeer];
if (this.m_options.initDHTEntry) {
dhtEntry = dhtEntry.concat(this.m_options.initDHTEntry);
}
let bdtInitParams = {};
bdtInitParams['peerid'] = this.m_peerid;
if (this.m_tcpListenPort !== 0) {
bdtInitParams['tcp'] = {
addrList,
initPort: this.m_tcpListenPort,
maxPortOffset: 0,
};
}
if (this.m_udpListenPort !== 0) {
bdtInitParams['udp'] = {
addrList,
initPort: this.m_udpListenPort,
maxPortOffset: 0,
};
}
// 增加指定地址
// 部分机器会因为监听'0.0.0.0'相同端口,监听本地IP时发生冲突,最终漏掉本地地址,导致同局域网地址连接不上
let listenerEPList = [];
addrList.forEach((host) => {
listenerEPList.push(Util.EndPoint.toString({ address: host, port: this.m_tcpListenPort, family: Util.EndPoint.FAMILY.IPv4, protocol: Util.EndPoint.PROTOCOL.tcp }));
listenerEPList.push(Util.EndPoint.toString({ address: host, port: this.m_udpListenPort, family: Util.EndPoint.FAMILY.IPv4, protocol: Util.EndPoint.PROTOCOL.udp }));
});
bdtInitParams['listenerEPList'] = listenerEPList;
let { result, p2p } = await P2P.create(bdtInitParams);
if (result !== 0) {
throw Error(`init p2p peer error ${result}. please check the params`);
}
// 加入区块链应用DHT网络,并做为默认DHT网络,准备妥当再正式提供服务
p2p.joinDHT(dhtEntry, { manualActiveLocalPeer: true, dhtAppID: this.m_options.dhtAppID, asDefault: true });
this.m_logger.info(`bdt add network use id ${this.m_options.dhtAppID}`);
// 加入SN的DHT网络,用于通信穿透,但不参与SN服务
p2p.joinDHT(dhtEntry, { manualActiveLocalPeer: true, dhtAppID: DHTAPPID.sn });
result = await p2p.startupBDTStack(bdtInitParams.options);
if (result !== 0) {
throw Error(`init p2p peer error ${result}. please check the params`);
}
this.m_dht = p2p.dht;
this.m_bdtStack = p2p.bdtStack;
this.m_p2p = p2p;
}
_ready() {
this.m_dht.rootDHT.activeLocalPeer();
}
// 将某个connection加入黑名单:addBlackList(conn.remote.peerid, conn.remote.endpoint)
// ban掉某个IP地址:addBlackList(ipstring)
// ban掉某个PEERID:addBlackList(undefined, peerid)
addBlackList(peerid, ip) {
if (this.m_p2p) {
this.m_p2p.forbid(ip ? ip : P2P.FORBID.all, peerid ? peerid : P2P.FORBID.all);
}
}
async randomPeers(count, excludes) {
// 过滤掉自己和种子peer
const filter = (peer) => {
if (!peer.peerid) {
// this.m_logger.debug(`exclude undefined peerid, ${JSON.stringify(peer)}`);
return false;
}
if (this.m_skipList.includes(peer.peerid)) {
// this.m_logger.debug(`exclude ${peer.peerid} from skipList`);
return false;
}
if (excludes.has(peer.peerid)) {
// this.m_logger.debug(`exclude ${peer.peerid} from excludesList`);
return false;
}
return true;
};
let res = await this.m_dht.getRandomPeers(count, false, { filter });
// this.m_logger.info(`first find ${res.peerlist.length} peers, ${JSON.stringify(res.peerlist.map((value: any) => value.peerid))}`);
const ignore0 = !res || !res.peerlist || res.peerlist.length === 0;
const peers = (res && res.peerlist) ? res.peerlist : [];
let peerids = peers.map((value) => value.peerid);
// this.m_logger.info(`find ${peerids.length} peers after filter, count ${count}, ${JSON.stringify(peerids)}`);
// 如果peer数量比传入的count多, 需要随机截取
if (peerids.length > count) {
let temp_peerids = [];
for (let i = 0; i < count - 1; i++) {
let idx = Math.floor(Math.random() * peerids.length);
temp_peerids.push(peerids[idx]);
peerids.splice(idx, 1);
}
peerids = temp_peerids;
}
let errCode = peerids.length > 0 ? error_code_1.ErrorCode.RESULT_OK : error_code_1.ErrorCode.RESULT_SKIPPED;
return { err: errCode, peers: peerids, ignore0 };
}
_connectTo(peerid) {
let vport = this.m_vport;
let connection = this.m_bdtStack.newConnection();
connection.bind(null);
return new Promise((resolve, reject) => {
connection.connect({
peerid,
vport,
});
connection.on(P2P.Connection.EVENT.close, () => {
resolve({ err: error_code_1.ErrorCode.RESULT_EXCEPTION });
});
connection.on(P2P.Connection.EVENT.error, (error) => {
console.log('Connection error', peerid, error);
resolve({ err: error_code_1.ErrorCode.RESULT_EXCEPTION });
});
connection.on(P2P.Connection.EVENT.connect, () => {
let connNodeType = this._nodeConnectionType();
let connNode = (new connNodeType(this, { bdt_connection: connection, remote: peerid }));
resolve({ err: error_code_1.ErrorCode.RESULT_OK, conn: connNode });
});
});
}
_connectionType() {
return connection_1.BdtConnection;
}
uninit() {
// TODO:
return super.uninit();
}
listen() {
return new Promise((resolve, reject) => {
const acceptor = this.m_bdtStack.newAcceptor({
vport: this.m_vport,
});
acceptor.listen();
// listen 之后 peer ready(上层chain node 已经准备好,被发现)
this._ready();
acceptor.on(P2P.Acceptor.EVENT.close, () => {
acceptor.close();
});
acceptor.on(P2P.Acceptor.EVENT.connection, (bdt_connection) => {
const remoteObject = bdt_connection.remote;
const remote = `${remoteObject.peerid}:${remoteObject.vport}`;
let connNodeType = this._nodeConnectionType();
let connNode = (new connNodeType(this, { bdt_connection, remote }));
// 调用_onInbound, 将成功的连接保存
this._onInbound(connNode);
});
acceptor.on('error', () => {
reject(error_code_1.ErrorCode.RESULT_EXCEPTION);
});
resolve(error_code_1.ErrorCode.RESULT_OK);
});
}
}
exports.BdtNode = BdtNode;