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 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.boxOrder.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.boxOrder.getOrderDb()), ) ); await this.updateDb(logClass, [ ['done', 1] ]); log.info(util.format('%s end orderDb:%s', logClass, JSON.stringify(this.boxOrder.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 () => { console.log(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 = doSync(); } 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.updateDb(logClass, [ ['state', C.ORDER_STATE_PAID] ]); if (!err) { break; } await utils.sleep(1000 * 3); } { const {err, boxDb} = await this.getBoxDb(logClass); if (err || !boxDb) { log.warning(util.format('%s box not found orderDb:%s err:%s', logClass, JSON.stringify(this.boxOrder.getOrderDb()), err ) ); return; } while (true) { const err = await this.setBoxPaidState(logClass, boxDb); 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 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.error(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;