mirror of https://github.com/embarklabs/embark.git
fix(@embark/blockchain-api): add back contract event listen and log
Adds back the watch on contract events and writes them to a file with the same method as contract logs from transaction-logger, so I extracted those methods to utils/file so that both could use the same functions.
This commit is contained in:
parent
87a04cd5db
commit
5592753116
|
@ -3,12 +3,15 @@ pragma solidity ^0.6.0;
|
|||
contract SimpleStorage {
|
||||
uint public storedData;
|
||||
|
||||
event Set(address caller, uint _value);
|
||||
|
||||
constructor(uint initialValue) public {
|
||||
storedData = initialValue;
|
||||
}
|
||||
|
||||
function set(uint x) public {
|
||||
storedData = x;
|
||||
emit Set(msg.sender, x);
|
||||
}
|
||||
|
||||
function get() public view returns (uint retVal) {
|
||||
|
|
|
@ -180,7 +180,7 @@ export const contractLogs = {
|
|||
export const CONTRACT_EVENTS = createRequestTypes('CONTRACT_EVENTS');
|
||||
export const contractEvents = {
|
||||
request: () => action(CONTRACT_EVENTS[REQUEST]),
|
||||
success: (contractEvents) => action(CONTRACT_EVENTS[SUCCESS], {contractEvents}),
|
||||
success: (contractEvents) => action(CONTRACT_EVENTS[SUCCESS], {contractEvents: contractEvents ? contractEvents.reverse() : []}),
|
||||
failure: (error) => action(CONTRACT_EVENTS[FAILURE], {error, name: 'contractEvents'})
|
||||
};
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Logger } from 'embark-logger';
|
||||
import { __ } from 'embark-i18n';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { downloadFile } from './network';
|
||||
import { dappPath, embarkPath } from './pathUtils';
|
||||
import { ImportRemapping, prepareForCompilation } from './solidity/remapImports';
|
||||
import { cargo } from 'async';
|
||||
|
||||
const HTTP_CONTRACTS_DIRECTORY = '.embark/contracts/';
|
||||
|
||||
|
@ -179,3 +181,53 @@ export function getExternalContractUrl(file: string, providerUrl: string) {
|
|||
url,
|
||||
};
|
||||
}
|
||||
|
||||
export function getCircularReplacer() {
|
||||
const seen = new WeakSet();
|
||||
return (key, value) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return;
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
export function getAppendLogFileCargo(logFilePath: string, logger: Logger) {
|
||||
return cargo((tasks, callback) => {
|
||||
let appendThis = '';
|
||||
tasks.forEach(task => {
|
||||
// Write each line to a JSON string. The replacer is to avoid circular dependencies
|
||||
// Add a comma at the end to be able to make an array off of it when reading
|
||||
appendThis += `${JSON.stringify(task, getCircularReplacer())},\n`;
|
||||
});
|
||||
fs.appendFile(logFilePath, appendThis, (err) => {
|
||||
if (err) {
|
||||
logger.error('Error writing to the log file', err.message);
|
||||
logger.trace(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function readAppendedLogs(logFile: string, asString: boolean = false) {
|
||||
await fs.ensureFile(logFile);
|
||||
const data = await fs.readFile(logFile);
|
||||
|
||||
let stringData = data.toString();
|
||||
|
||||
if (!stringData) {
|
||||
return asString ? '[]' : [];
|
||||
}
|
||||
|
||||
// remove last comma and add brackets around to make it an array of object logs
|
||||
stringData = `[${stringData.substring(0, stringData.length - 2)}]`;
|
||||
if (asString) {
|
||||
return stringData;
|
||||
}
|
||||
|
||||
return JSON.parse(stringData);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ const { extendZeroAddressShorthand, replaceZeroAddressShorthand } = AddressUtils
|
|||
|
||||
export { compact, last, recursiveMerge, groupBy } from './collections';
|
||||
export { prepareForCompilation } from './solidity/remapImports';
|
||||
export { File, getExternalContractUrl, Types } from './file';
|
||||
export { File, getExternalContractUrl, Types, getAppendLogFileCargo, getCircularReplacer, readAppendedLogs } from './file';
|
||||
|
||||
export {
|
||||
findMonorepoPackageFromRoot,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import async from "async";
|
||||
import {dappPath} from 'embark-utils';
|
||||
import {dappPath, getAppendLogFileCargo, readAppendedLogs} from 'embark-utils';
|
||||
const embarkJsUtils = require('embarkjs').Utils;
|
||||
const {bigNumberify} = require('ethers/utils/bignumber');
|
||||
const RLP = require('ethers/utils/rlp');
|
||||
|
@ -11,11 +11,20 @@ const BLOCK_LIMIT = 100;
|
|||
export default class EthereumAPI {
|
||||
constructor(embark, web3, blockchainName) {
|
||||
this.embark = embark;
|
||||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
this.blockchainName = blockchainName;
|
||||
this.web3 = web3;
|
||||
this.requestManager = new Manager(web3.currentProvider);
|
||||
this.fs = embark.fs;
|
||||
this.logFile = dappPath(".embark", "contractEvents.json");
|
||||
this.logFile = dappPath(".embark", "contractEvents.json.txt");
|
||||
this.contractsSubscriptions = [];
|
||||
this.contractsEvents = [];
|
||||
|
||||
this.writeLogFile = getAppendLogFileCargo(this.logFile, this.logger);
|
||||
this.events.on('contractsDeployed', () => {
|
||||
this.subscribeToContractEvents();
|
||||
});
|
||||
}
|
||||
|
||||
registerAPIs() {
|
||||
|
@ -26,7 +35,7 @@ export default class EthereumAPI {
|
|||
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactions", this.getTransactions.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactionByHash", this.getTransactionByHash.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "getTransactionByRawTransactionHash", this.getTransactionByRawTransactionHash.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "getEvents", this.getEvents.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "getEvents", this.readEvents.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "signMessage", this.signMessage.bind(this));
|
||||
this.embark.events.request("blockchain:api:register", this.blockchainName, "verifyMessage", this.verifyMessage.bind(this));
|
||||
}
|
||||
|
@ -356,7 +365,7 @@ export default class EthereumAPI {
|
|||
});
|
||||
}
|
||||
|
||||
subscribeToContractEvents(callback) {
|
||||
subscribeToContractEvents() {
|
||||
this.contractsSubscriptions.forEach((eventEmitter) => {
|
||||
const reqMgr = eventEmitter.options.requestManager;
|
||||
// attempting an eth_unsubscribe when not connected throws an
|
||||
|
@ -378,28 +387,24 @@ export default class EthereumAPI {
|
|||
eventEmitter.on('data', (data) => {
|
||||
const dataWithName = Object.assign(data, {name: contractObject.className});
|
||||
this.contractsEvents.push(dataWithName);
|
||||
this.saveEvent(dataWithName);
|
||||
this.events.emit('blockchain:contracts:event', dataWithName);
|
||||
});
|
||||
});
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
getEvents() {
|
||||
const data = this.readEvents();
|
||||
return Object.values(data).reverse();
|
||||
}
|
||||
|
||||
saveEvent(event) {
|
||||
this.writeLogFile.push(event);
|
||||
}
|
||||
|
||||
readEvents() {
|
||||
this.fs.ensureFileSync(this.logFile);
|
||||
async readEvents(asString) {
|
||||
try {
|
||||
return JSON.parse(this.fs.readFileSync(this.logFile));
|
||||
} catch (_error) {
|
||||
return {};
|
||||
return readAppendedLogs(this.logFile, asString);
|
||||
} catch (e) {
|
||||
this.logger.error('Error reading contract log file', e.message);
|
||||
this.logger.trace(e.trace);
|
||||
return asString ? '[]' : [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,6 @@ class EthereumBlockchainClient {
|
|||
this.events = embark.events;
|
||||
this.logger = embark.logger;
|
||||
this.fs = embark.fs;
|
||||
this.contractsSubscriptions = [];
|
||||
this.contractsEvents = [];
|
||||
|
||||
this.logFile = dappPath(".embark", "contractEvents.json");
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
const async = require('async');
|
||||
import { __ } from 'embark-i18n';
|
||||
const Web3 = require('web3');
|
||||
const util = require('util');
|
||||
|
||||
const { blockchain: blockchainConstants } = require('embark-core/constants');
|
||||
import { dappPath, hexToNumber } from 'embark-utils';
|
||||
import { dappPath, hexToNumber, getAppendLogFileCargo, readAppendedLogs } from 'embark-utils';
|
||||
import { getAddressToContract, getTransactionParams } from './transactionUtils';
|
||||
export { getAddressToContract, getTransactionParams };
|
||||
|
||||
|
@ -18,19 +17,6 @@ const LISTENED_METHODS = [
|
|||
blockchainConstants.transactionMethods.eth_sendRawTransaction
|
||||
];
|
||||
|
||||
const getCircularReplacer = () => {
|
||||
const seen = new WeakSet();
|
||||
return (key, value) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return;
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
export default class TransactionLogger {
|
||||
constructor(embark, _options) {
|
||||
this.embark = embark;
|
||||
|
@ -60,21 +46,7 @@ export default class TransactionLogger {
|
|||
});
|
||||
});
|
||||
|
||||
this.writeLogFile = async.cargo((tasks, callback) => {
|
||||
let appendThis = '';
|
||||
tasks.forEach(task => {
|
||||
// Write each line to a JSON string. The replacer is to avoid circular dependencies
|
||||
// Add a comma at the end to be able to make an array off of it when reading
|
||||
appendThis += `${JSON.stringify(task, getCircularReplacer())},\n`;
|
||||
});
|
||||
this.fs.appendFile(this.logFile, appendThis, (err) => {
|
||||
if (err) {
|
||||
this.logger.error('Error writing to the log file', err.message);
|
||||
this.logger.trace(err);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
});
|
||||
this.writeLogFile = getAppendLogFileCargo(this.logFile, this.logger);
|
||||
}
|
||||
|
||||
get web3() {
|
||||
|
@ -272,25 +244,10 @@ export default class TransactionLogger {
|
|||
|
||||
async _readLogs(asString = false) {
|
||||
try {
|
||||
await this.fs.ensureFile(this.logFile);
|
||||
let data = await this.fs.readFile(this.logFile);
|
||||
|
||||
data = data.toString();
|
||||
|
||||
if (!data) {
|
||||
return asString ? '[]' : [];
|
||||
}
|
||||
|
||||
// remove last comma and add brackets around to make it an array of object logs
|
||||
data = `[${data.substring(0, data.length - 2)}]`;
|
||||
if (asString) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return JSON.parse(data);
|
||||
} catch (error) {
|
||||
this.logger.error('Error reading contract log file', error.message);
|
||||
this.logger.trace(error.trace);
|
||||
return readAppendedLogs(this.logFile, asString);
|
||||
} catch (e) {
|
||||
this.logger.error('Error reading contract log file', e.message);
|
||||
this.logger.trace(e.trace);
|
||||
return asString ? '[]' : [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,10 +248,10 @@ export default class BlockchainAPI {
|
|||
this.embark.registerAPICall(
|
||||
"get",
|
||||
"/embark-api/blockchain/contracts/events",
|
||||
(_req, res) => {
|
||||
async (_req, res) => {
|
||||
try {
|
||||
const getEvents = this.getCallForBlockchain(blockchainName, "getEvents");
|
||||
res.send(JSON.stringify(getEvents()));
|
||||
res.send(await getEvents(true));
|
||||
} catch (error) {
|
||||
res.status(500).send({ error });
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue