tera/src/core/code.ts

204 lines
7.6 KiB
TypeScript

/*
* @project: TERA
* @version: Development (beta)
* @license: MIT (not for evil)
* @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com]
* Web: https://terafoundation.org
* Twitter: https://twitter.com/terafoundation
* Telegram: https://t.me/terafoundation
*/
"use strict";
import * as fs from 'fs'
import { secp256k1 } from '../core/library'
import * as crypto from 'crypto'
const FORMAT_EVAL_SEND = "{MaxBlockNum:uint,Code:str,Sign:arr64}";
import CCommon from './base'
import CNode from './node';
import { SocketSendInfo } from '../interfaces/server';
export default class CCode extends CCommon {
LastEvalCodeNum: number
constructor(SetKeyPair: crypto.ECDH, RunIP: string, RunPort: number, UseRNDHeader: boolean, bVirtual: boolean) {
super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual)
if (!global.ADDRLIST_MODE && !this.VirtualMode) {
setInterval(this.CheckLoadCodeTime.bind(this), 10 * 1000)
}
this.LastEvalCodeNum = 0
global.CheckCreateDir(global.GetDataPath("Update"))
}
CheckLoadCodeTime() {
if (global.START_LOAD_CODE.StartLoadNode && global.START_LOAD_CODE.StartLoadVersionNum) {
var Delta = (new Date() as any) - global.START_LOAD_CODE.StartLoadVersionNumTime;
if (Delta > 20 * 1000) {
global.ToError("Cannot load code version:" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + global.START_LOAD_CODE.StartLoadNode.ip + ":" + global.START_LOAD_CODE.StartLoadNode.port)
this.ClearLoadCode()
}
}
}
ClearLoadCode() {
global.START_LOAD_CODE.StartLoad = undefined
global.START_LOAD_CODE.StartLoadVersionNum = 0
global.START_LOAD_CODE.StartLoadVersionNumTime = 0
}
StartLoadCode(Node: CNode, CodeVersion: { VersionNum: any; }) {
var VersionNum = CodeVersion.VersionNum;
global.START_LOAD_CODE.StartLoad = CodeVersion
global.START_LOAD_CODE.StartLoadNode = Node
global.START_LOAD_CODE.StartLoadVersionNum = VersionNum
global.START_LOAD_CODE.StartLoadVersionNumTime = new Date()
var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip");
if (fs.existsSync(fname)) {
this.UseCode(VersionNum, false)
return;
}
var Context = { "VersionNum": VersionNum };
this.SendF(Node, { "Method": "GETCODE", "Context": Context, "Data": VersionNum })
}
static GETCODE_F() {
return "uint";
}
RETCODE(Info: SocketSendInfo) {
var VersionNum = Info.Context.VersionNum;
if (!VersionNum || !global.START_LOAD_CODE.StartLoad)
return;
var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip");
if (!fs.existsSync(fname)) {
var Hash = global.shaarr(Info.Data);
if (global.CompareArr(Hash, global.START_LOAD_CODE.StartLoad.Hash) === 0) {
var file_handle = fs.openSync(fname, "w");
fs.writeSync(file_handle, Info.Data, 0, Info.Data.length)
fs.closeSync(file_handle)
this.UseCode(VersionNum, global.USE_AUTO_UPDATE)
} else {
global.ToError("Error check hash of version code :" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + Info.Node.ip + ":" + Info.Node.port)
this.ClearLoadCode()
this.AddCheckErrCount(Info.Node, 1, "Error check hash of version code")
}
}
}
UseCode(VersionNum: string, bUpdate: boolean) {
if (bUpdate) {
UpdateCodeFiles(VersionNum)
}
if (global.START_LOAD_CODE.StartLoad) {
global.CODE_VERSION = global.START_LOAD_CODE.StartLoad
this.ClearLoadCode()
}
}
SetNewCodeVersion(Data, PrivateKey) {
var fname = global.GetDataPath("ToUpdate/wallet.zip");
if (fs.existsSync(fname)) {
var fname2 = global.GetDataPath("Update/wallet-" + Data.VersionNum + ".zip");
if (fs.existsSync(fname2)) {
fs.unlinkSync(fname2)
}
var data = fs.readFileSync(fname);
var Hash = global.shaarr(data);
var file_handle = fs.openSync(fname2, "w");
fs.writeSync(file_handle, data, 0, data.length)
fs.closeSync(file_handle)
var SignArr = global.arr2(Hash, global.GetArrFromValue(Data.VersionNum));
var Sign = secp256k1.sign(global.SHA3BUF(SignArr), PrivateKey).signature;
global.CODE_VERSION = Data
global.CODE_VERSION.Hash = Hash
global.CODE_VERSION.Sign = Sign
return "OK Set new code version=" + Data.VersionNum;
} else {
return "File not exist: " + fname;
}
}
};
function UpdateCodeFiles(StartNum) {
var fname = global.GetDataPath("Update");
if (!fs.existsSync(fname))
return 0;
var arr = fs.readdirSync(fname);
var arr2 = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i].substr(0, 7) === "wallet-") {
arr2.push(parseInt(arr[i].substr(7)));
}
}
arr2.sort(function(a, b) {
return a - b;
});
for (var i = 0; i < arr2.length; i++) {
var Num = arr2[i];
var Name = "wallet-" + Num + ".zip";
var Path = fname + "/" + Name;
global.ToLog("Check file:" + Name);
if (fs.existsSync(Path)) {
if (StartNum === Num) {
global.ToLog("UnpackCodeFile:" + Name);
UnpackCodeFile(Path);
if (StartNum % 2 === 0) {
global.RestartNode(1);
} else {
}
return 1;
} else {
global.ToLog("Delete old file update:" + Name);
fs.unlinkSync(Path);
}
}
}
return 0;
};
global.UnpackCodeFile = UnpackCodeFile;
function UnpackCodeFile(fname) {
var data = fs.readFileSync(fname);
var reader = global.ZIP.Reader(data);
reader.forEach(function(entry) {
var Name = entry.getName();
var Path = global.GetCodePath(Name);
if (entry.isFile()) {
var buf = entry.getData();
global.CheckCreateDir(Path, true, true);
var file_handle = fs.openSync(Path, "w");
fs.writeSync(file_handle, buf, 0, buf.length);
fs.closeSync(file_handle);
}
else {
}
});
reader.close();
};
global.RestartNode = function RestartNode(bForce) {
global.NeedRestart = 1;
setTimeout(DoExit, 5000);
if (global.nw || global.NWMODE) {
} else {
global.StopChildProcess();
global.ToLog("********************************** FORCE RESTART!!!");
return;
}
if (this.ActualNodes) {
var it = this.ActualNodes.iterator(), Node;
while ((Node = it.next()) !== null) {
if (Node.Socket)
global.CloseSocket(Node.Socket, "Restart");
}
}
global.SERVER.StopServer();
global.SERVER.StopNode();
global.StopChildProcess();
global.ToLog("****************************************** RESTART!!!");
global.ToLog("EXIT 1");
};
function DoExit() {
global.ToLog("EXIT 2");
if (global.nw || global.NWMODE) {
global.ToLog("RESTART NW");
var StrRun = '"' + process.argv[0] + '" .\n';
StrRun += '"' + process.argv[0] + '" .\n';
global.SaveToFile("run-next.bat", StrRun);
const child_process = require('child_process');
child_process.exec("run-next.bat", { shell: true });
}
global.ToLog("EXIT 3");
process.exit(0);
};