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.isPaid()) { //修复已支付成功订单token_id await this.repairPaidOrder(); utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId()); } else { 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; } } } //等待确认支付成功 await this.bcConfirm(); } } async repairPaidOrder() { const logClass = 'repairPaidOrder'; log.info(util.format('%s begin orderDb:%s', logClass, JSON.stringify(this.getOrderDb()), ) ); await this.bcMintHero(); await this.updateDb(logClass, [ ['done', 1] ]); log.info(util.format('%s end orderDb:%s', logClass, JSON.stringify(this.getOrderDb()), ) ); } async bcSearch() { const logClass = 'bcSearch'; const events = await bc.mallInstance.getPastEvents( 'BEBoxPaid', { fromBlock: 0, toBlock: 'latest', filter: { boxId: this.getOrderId() } }); if (events.length > 0) { while (true) { const err = await this.updateDb(logClass, [ ['bc_synced', 1] ]); if (!err) { break; } await utils.sleep(1000 * 3); } this.orderDb['bc_synced'] = 1; } return events.length > 0; } async bcSync() { const logClass = 'bcSync'; const doSync = async () => { //log.debug(JSON.stringify(this.orderDb)); const result = await bc.mallInstance.methods.buyBoxWithSignature( this.orderDb['order_id'], this.orderDb['item_id'], this.orderDb['buyer_address'], this.orderDb['price'], this.orderDb['payment_token_address'], this.orderDb['nonce'], this.orderDb['signature']).send({gas: 1000000}); return result; }; while (true) { try { const result = await doSync(); const nowTime = utils.getUtcTime(); const blockNumber = result['blockNumber']; const err = await this.updateDb( logClass, [ ['state', C.ORDER_STATE_PAID], ['bc_synced', 1], ['bc_sync_count', 1], ['bc_sync_time', nowTime], ['bc_result', 1], ['bc_block_number', blockNumber], ['bc_fail_reason', ''], ] ); 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 ) ); } await utils.sleep(1000 * 3 + Math.random() * 1000); } } 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); } while (true) { const err = await this.updateDb(logClass, [ ['done', 1] ]); if (!err) { break; } await utils.sleep(1000 * 3); } utils.emitEvent(C.REMOVE_PENDING_ORDER_EVENT, this.getOrderId()); } async bcMintHero() { const logClass = 'bcMintHero'; const userAddress = metamgr.getUserAddress(); const tokenId = this.getOrderId(); const result = await bc.factoryInstance.methods.mintHeroTo( userAddress, tokenId).send({ gas: 1000000 }); { const err = await this.updateDb( logClass, [ ['token_id', tokenId] ] ); } { const nowTime = utils.getUtcTime(); 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 updateDb(logClass, fieldList) { const err = await dbhelper.update( 't_box_order', [ ['order_id', this.getOrderId()] ], fieldList); if (err) { log.error(util.format('%s updateDb orderDb:%s fieldList:%s err:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(fieldList), err ) ); } else { log.info(util.format('%s updateDb orderDb:%s', logClass, JSON.stringify(this.orderDb), JSON.stringify(fieldList) ) ); } return err; } getOrderDb() { return this.orderDb; } getOrderId() { return this.orderDb['order_id']; } getBlockNumber() { return this.orderDb['bc_block_number']; } isPaid() { return this.orderDb['state'] == C.ORDER_STATE_PAID; } isSynced() { return this.orderDb['bc_synced'] != 0; } isFail() { return this.isSynced() && this.orderDb['bc_result'] != C.BC_RESULT_OK; } }; exports.BoxOrder = BoxOrder;