aozhiwei cb11ef4fd1 1
2022-01-29 12:09:25 +08:00

363 lines
9.6 KiB
JavaScript

const util = require('util');
const utils = require('./utils');
const db = require("./db");
const dbhelper = require("./dbhelper");
const log = require("./log");
const bc = require('./blockchain');
const metamgr = require('./metamgr');
const C = require('./C');
class BoxOrder {
constructor(orderDb, isNewOrder) {
this.isNewOrder = isNewOrder;
this.orderDb = orderDb;
}
init () {
if (this.isNewOrder) {
setTimeout(this.start.bind(this), 1000 * 0.1 + Math.floor(Math.random() * 100));
} else {
setTimeout(this.start.bind(this), 1000 * 1 + Math.floor(Math.random() * 1000 * 3));
}
}
async start() {
if (this.isSuspend()) {
utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId());
return;
}
if (this.isPaid()) {
//修复已支付成功订单token_id
await this.repairPaidOrder();
utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId());
} else {
//等待同步
await this.sync();
//等待确认支付成功
await this.bcConfirm();
}
}
async sync() {
if (!this.isSynced()) {
//查询
const found = await this.bcSearch();
if (!found) {
//上链
const ok = await this.bcSync();
if (!ok) {
utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId());
return;
}
}
}
}
async repairPaidOrder() {
const logClass = 'repairPaidOrder';
log.info(util.format('%s begin orderDb:%s',
logClass,
JSON.stringify(this.getOrderDb()),
)
);
await this.bcMintHero();
await this.updateDbMustBeSuccess(logClass,
[
['done', 1]
]);
log.info(util.format('%s end orderDb:%s',
logClass,
JSON.stringify(this.getOrderDb()),
)
);
}
async bcSearch() {
const logClass = 'bcSearch';
let events = [];
if (this.getSyncBlockNumber() <= 0) {
return false;
}
while (true) {
try {
const fromBlock = Math.max(this.getSyncBlockNumber(), this.getBlockNumber());
events = await bc.mallInstance.getPastEvents(
'BEBoxPaid',
{
fromBlock: fromBlock,
toBlock: fromBlock + 5000 - 1,
filter: {
boxId: this.getOrderId()
}
});
break;
} catch (err) {
log.warning(util.format('%s getPastEvents orderDb:%s err:%s',
logClass,
JSON.stringify(this.getOrderDb()),
err
));
}
await utils.sleep(1000 * 3);
}
if (events.length > 0) {
const blockNumber = events[0]['blockNumber'];
if (!blockNumber) {
await this.doHangUp(logClass, 'blocNumber is empty');
}
await this.updateDbMustBeSuccess(
logClass,
[
['state', C.ORDER_STATE_PAID],
['bc_synced', 1],
['bc_result', 1],
['bc_block_number', blockNumber],
]);
this.orderDb['bc_synced'] = 1;
this.orderDb['bc_sync_count'] += 1;
this.orderDb['bc_sync_number'] = blockNumber;
}
return events.length > 0;
}
async bcSync() {
const logClass = 'bcSync';
await bc.active();
if (this.getSyncBlockNumber() <= 0) {
await this.updateDbMustBeSuccess(
logClass,
[
['bc_sync_block_number', bc.getCurrBlockNumber()],
]
);
this.orderDb['bc_sync_block_number'] = this.getSyncBlockNumber();
}
const nowTime = utils.getUtcTime();
const doSync = async () => {
let result = null;
try {
result = await bc.mallInstance.methods.payForBoxWithSignature(
this.orderDb['order_id'],
this.orderDb['type'],
this.orderDb['buyer_address'],
this.orderDb['price'],
this.orderDb['payment_token_address'],
this.orderDb['nonce'],
this.orderDb['signature']).send({gas: 1000000});
} catch (err) {
await this.updateDbMustBeSuccess(
logClass,
[
['suspend', 1],
['suspend_reason', '' . err],
]
);
await this.doHangUp(logClass, err);
}
return result;
};
try {
const result = await doSync();
const blockNumber = result['blockNumber'];
await this.updateDbMustBeSuccess(
logClass,
[
['state', C.ORDER_STATE_PAID],
['bc_synced', 1],
['bc_sync_count', this.orderDb['bc_sync_count'] + 1],
['bc_sync_time', nowTime],
['bc_result', 1],
['bc_block_number', blockNumber],
['bc_fail_reason', ''],
]
);
this.orderDb['state'] = C.ORDER_STATE_PAID;
this.orderDb['bc_synced'] = 1;
this.orderDb['bc_sync_count'] += 1;
this.orderDb['bc_sync_time'] = nowTime;
this.orderDb['bc_sync_number'] = blockNumber;
return true;
} catch (e) {
log.warning(util.format('%s end orderDb:%s err:%s',
logClass,
JSON.stringify(this.orderDb),
e
)
);
}
return false;
}
async bcConfirm() {
const logClass = 'bcConfirm';
while (true) {
if (bc.isComfirmed(this.getBlockNumber())) {
break;
}
await utils.sleep(1000 * 3);
}
while (true) {
const err = await this.bcMintHero();
if (!err) {
break;
}
await utils.sleep(1000 * 3);
}
await this.updateDbMustBeSuccess(
logClass,
[
['done', 1]
]);
utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId());
}
async bcMintHero() {
const logClass = 'bcMintHero';
const buyerAddress = this.getBuyerAddress();
const tokenId = this.getTokenId();
const result = await bc.factoryInstance.methods.mintHeroTo(
buyerAddress,
tokenId).send({ gas: 1000000 });
const nowTime = utils.getUtcTime();
await this.updateDbMustBeSuccess(
logClass,
[
['bc_minted', 1],
['bc_mint_time', nowTime],
]
);
{
const fieldList = [
['token_id', tokenId],
['item_id', this.orderDb['item_id']],
['owner_id', ''],
['owner_address', this.orderDb['buyer_address']],
['owner_name', ''],
['createtime', nowTime],
['modifytime', nowTime],
];
const err = await dbhelper.insert(
't_nft',
fieldList);
if (err) {
log.error(util.format('%s insert nft table orderDb:%s fieldList:%s err:%s',
logClass,
JSON.stringify(this.orderDb),
JSON.stringify(fieldList),
err
)
);
} else {
log.info(util.format('%s insert nft table orderDb:%s',
logClass,
JSON.stringify(this.orderDb),
JSON.stringify(fieldList)
)
);
}
}
}
async updateDbMustBeSuccess(logClass, fieldList) {
const err = await dbhelper.update(
't_box_order',
[
['order_id', this.getOrderId()]
],
fieldList);
if (err) {
log.error(util.format('%s updateDbMustBeSuccess orderDb:%s fieldList:%s err:%s',
logClass,
JSON.stringify(this.orderDb),
JSON.stringify(fieldList),
err
)
);
await this.doHangUp(logClass + ' updateDbMustBeSuccess ', err);
} else {
log.info(util.format('%s updateDbMustBeSuccess orderDb:%s',
logClass,
JSON.stringify(this.orderDb),
JSON.stringify(fieldList)
)
);
}
return err;
}
async doHangUp(logClass, reason) {
//挂起等待人工处理
try {
log.warning(util.format('%s doHangUp orderDb:%s reason:%s',
logClass,
JSON.stringify(this.orderDb),
reason
)
);
} catch (err) {
log.error(util.format('%s doHangUp orderDb:%s err:%s',
logClass,
JSON.stringify(this.orderDb),
err
)
);
}
while (true) {
await utils.sleep(1000 * 3600 * 24);
}
}
getOrderDb() {
return this.orderDb;
}
getOrderId() {
return this.orderDb['order_id'];
}
getBuyerAddress() {
return this.orderDb['buyer_address'];
}
getTokenId() {
return this.orderDb['token_id'];
}
getBlockNumber() {
return this.orderDb['bc_block_number'];
}
isPaid() {
return this.orderDb['state'] == C.ORDER_STATE_PAID;
}
isSynced() {
return this.orderDb['bc_synced'] != 0;
}
isSuspend() {
return this.orderDb['suspend'] != 0;
}
getSyncBlockNumber() {
return this.orderDb['bc_sync_block_number'];
}
isFail() {
return this.isSynced() && this.orderDb['bc_result'] != C.BC_RESULT_OK;
}
isNetError(err) {
const errStr = '' + err;
return errStr && errStr.indexOf('connection not open on send') >= 0;
}
};
exports.BoxOrder = BoxOrder;