Implemented remaining stubs for api
This commit is contained in:
parent
e832874891
commit
6b43434f53
|
@ -6,10 +6,8 @@ WORKDIR /api-server
|
|||
|
||||
COPY --from=testnet-binaries /binaries/cli/testnet/${BNC_VERSION}/linux/tbnbcli ./
|
||||
|
||||
COPY ./package.json ./
|
||||
RUN echo 12345678 | ./tbnbcli keys add key
|
||||
|
||||
RUN npm install
|
||||
EXPOSE 8080
|
||||
|
||||
COPY ./index.js ./
|
||||
|
||||
ENTRYPOINT ["node", "./index.js"]
|
||||
ENTRYPOINT ["./tbnbcli", "api-server", "--chain-id", "Binance-Dev", "--node", "http://node:26657", "--laddr", "tcp://0.0.0.0:8080"]
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
const fs = require('fs')
|
||||
const express = require('express')
|
||||
const axios = require('axios')
|
||||
const { execSync } = require('child_process')
|
||||
|
||||
const rpcClient = axios.create({
|
||||
baseURL: process.env.FOREIGN_RPC_URL,
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
async function delay(ms) {
|
||||
await new Promise((res) => setTimeout(res, ms))
|
||||
}
|
||||
|
||||
async function retry(getPromise, n = -1, sleep = 3000) {
|
||||
while (n) {
|
||||
try {
|
||||
return await getPromise()
|
||||
} catch (e) {
|
||||
console.debug(`Promise failed, retrying, ${n - 1} attempts left`)
|
||||
await delay(sleep)
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
n -= 1
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
async function sendRpcRequest(subUrl, method, params) {
|
||||
console.trace(`Request to ${subUrl}, method ${method}, params `, params)
|
||||
const response = await retry(() => rpcClient.post(subUrl, {
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params,
|
||||
id: 1
|
||||
}))
|
||||
console.trace('Response, ', response.data)
|
||||
return response.data
|
||||
}
|
||||
|
||||
const app = express()
|
||||
|
||||
// GET
|
||||
// /api/v1/tx/:hash
|
||||
// /api/v1/time
|
||||
// /api/v1/transactions
|
||||
// ?address=a&side=RECEIVE&txAsset=FOREIGN_ASSET&txType=TRANSFER&startTime=111&endTime=222
|
||||
// /api/v1/account/:account
|
||||
// /api/v1/account/:account/sequence
|
||||
// POST
|
||||
// /api/v1/broadcast?sync=true
|
||||
|
||||
app.get('/api/v1/tx/:hash', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
tx, hash, height, result
|
||||
} = JSON.parse(
|
||||
execSync(`./tbnbcli tx ${req.params.hash} --node "http://node:26657" --chain-id Binance-Dev`)
|
||||
)
|
||||
res.send({
|
||||
code: 0,
|
||||
hash,
|
||||
height,
|
||||
log: result.log,
|
||||
ok: true,
|
||||
tx
|
||||
})
|
||||
} catch (e) {
|
||||
res.status(404).end()
|
||||
}
|
||||
})
|
||||
|
||||
app.listen(8000, () => {
|
||||
console.log('Listening on port 8000')
|
||||
})
|
|
@ -10,15 +10,25 @@ services:
|
|||
volumes:
|
||||
- 'marketdata:/root/.bnbchaind/marketdata'
|
||||
api-server:
|
||||
build: ./api-server
|
||||
build: api-server
|
||||
image: bnc-api-server
|
||||
networks:
|
||||
- binance_rpc_net
|
||||
ports:
|
||||
- '8080:8080'
|
||||
http-api:
|
||||
build: http-api
|
||||
image: bnc-http-api
|
||||
environment:
|
||||
FOREIGN_RPC_URL: 'http://node:26657'
|
||||
FOREIGN_API_SERVER_URL: 'http://api-server:8080'
|
||||
networks:
|
||||
- binance_net
|
||||
- binance_rpc_net
|
||||
ports:
|
||||
- '8000:8000'
|
||||
volumes:
|
||||
- 'marketdata:/api-server/marketdata'
|
||||
- 'marketdata:/http-api/marketdata'
|
||||
networks:
|
||||
binance_net:
|
||||
external: true
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
FROM node:10.16.0-alpine
|
||||
|
||||
ARG BNC_VERSION=0.6.2
|
||||
|
||||
WORKDIR /http-api
|
||||
|
||||
COPY --from=testnet-binaries /binaries/cli/testnet/${BNC_VERSION}/linux/tbnbcli ./
|
||||
|
||||
COPY ./package.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY ./index.js ./parser.js ./
|
||||
|
||||
ENTRYPOINT ["node", "./index.js"]
|
|
@ -0,0 +1,125 @@
|
|||
const { execSync } = require('child_process')
|
||||
|
||||
const express = require('express')
|
||||
const axios = require('axios')
|
||||
const BN = require('bignumber.js')
|
||||
|
||||
const createParser = require('./parser')
|
||||
|
||||
const rpcClient = axios.create({
|
||||
baseURL: process.env.FOREIGN_RPC_URL,
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: process.env.FOREIGN_API_SERVER_URL,
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
const transfers = []
|
||||
|
||||
const parser = createParser('/http-api/marketdata/marketdata.json', 20 * 1024)
|
||||
parser.eventEmitter.on('object', (obj) => {
|
||||
obj.Transfers.forEach((event) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
event.Timestamp = Math.ceil(obj.Timestamp / 1000)
|
||||
transfers.push(event)
|
||||
})
|
||||
})
|
||||
|
||||
const app = express()
|
||||
app.use(express.json())
|
||||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
function wrap(f) {
|
||||
return async (req, res) => {
|
||||
try {
|
||||
await f(req, res)
|
||||
} catch (e) {
|
||||
res.status(404).end()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTx(req, res) {
|
||||
const {
|
||||
tx, hash, height, result
|
||||
} = JSON.parse(
|
||||
execSync(`./tbnbcli tx ${req.params.hash} --node "http://node:26657" --chain-id Binance-Dev`)
|
||||
)
|
||||
res.send({
|
||||
code: 0,
|
||||
hash,
|
||||
height,
|
||||
log: result.log,
|
||||
ok: true,
|
||||
tx
|
||||
})
|
||||
}
|
||||
|
||||
async function handleTransactions(req, res) {
|
||||
// eslint-disable-next-line no-empty
|
||||
while (parser.update()) {}
|
||||
const {
|
||||
address, side, txAsset, txType, startTime, endTime
|
||||
} = req.query
|
||||
if (txType !== 'TRANSFER' || side !== 'RECEIVE') {
|
||||
res.status(400).send('Given parameters are not supported')
|
||||
}
|
||||
const filtered = transfers.filter((event) => event.Timestamp >= parseInt(startTime, 10)
|
||||
&& event.Timestamp <= parseInt(endTime, 10)
|
||||
&& event.To.length === 1
|
||||
&& event.To[0].Addr === address
|
||||
&& event.To[0].Coins.length === 1
|
||||
&& event.To[0].Coins[0].denom === txAsset)
|
||||
res.send({
|
||||
tx: filtered.map((tx) => ({
|
||||
txHash: tx.TxHash,
|
||||
memo: tx.Memo,
|
||||
value: new BN(tx.To[0].Coins[0].amount).dividedBy(10 ** 8).toFixed(8, 3)
|
||||
})),
|
||||
total: filtered.length
|
||||
})
|
||||
}
|
||||
|
||||
async function handleTime(req, res) {
|
||||
const response = (await rpcClient.get('/status')).data
|
||||
res.send({
|
||||
ap_time: response.result.sync_info.latest_block_time,
|
||||
block_time: response.result.sync_info.latest_block_time
|
||||
})
|
||||
}
|
||||
|
||||
async function handleAccount(req, res) {
|
||||
const response = (await apiClient.get(`/api/v1/account/${req.params.account}`)).data
|
||||
res.send(response)
|
||||
}
|
||||
|
||||
async function handleAccountSequence(req, res) {
|
||||
const response = (await apiClient.get(`/api/v1/account/${req.params.account}`)).data
|
||||
res.send(response.sequence.toString())
|
||||
}
|
||||
|
||||
async function handleBroadcast(req, res) {
|
||||
if (req.query.sync !== 'true') {
|
||||
res.status(400).send('Async broadcast is not supported')
|
||||
} else {
|
||||
const response = (await rpcClient.get('/broadcast_tx_sync', {
|
||||
params: {
|
||||
tx: req.body
|
||||
}
|
||||
})).data
|
||||
res.send(response.result)
|
||||
}
|
||||
}
|
||||
|
||||
app.get('/api/v1/tx/:hash', wrap(handleTx))
|
||||
app.get('/api/v1/time', wrap(handleTime))
|
||||
app.get('/api/v1/transactions', wrap(handleTransactions))
|
||||
app.get('/api/v1/account/:account', wrap(handleAccount))
|
||||
app.get('/api/v1/account/:account/sequence', wrap(handleAccountSequence))
|
||||
app.post('/api/v1/broadcast', wrap(handleBroadcast))
|
||||
|
||||
app.listen(8000, () => {
|
||||
console.log('Listening on port 8000')
|
||||
})
|
|
@ -3,7 +3,8 @@
|
|||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"express": "4.17.1",
|
||||
"axios": "0.19.0"
|
||||
"axios": "0.19.0",
|
||||
"bignumber.js": "9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.6.0"
|
|
@ -0,0 +1,44 @@
|
|||
const events = require('events')
|
||||
const fs = require('fs')
|
||||
|
||||
function createParser(file, bufferSize) {
|
||||
const buf = Buffer.alloc(bufferSize)
|
||||
const eventEmitter = new events.EventEmitter()
|
||||
let fd
|
||||
let position = 0
|
||||
let end = 0
|
||||
|
||||
return {
|
||||
update() {
|
||||
if (!fd) {
|
||||
try {
|
||||
fd = fs.openSync(file, 'r')
|
||||
} catch (e) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
const bytesRead = fs.readSync(fd, buf, position, buf.length - position, null)
|
||||
for (let i = position; i < position + bytesRead; i += 1) {
|
||||
if (buf[i] === 10) {
|
||||
const obj = buf.slice(end, i)
|
||||
end = i + 1
|
||||
eventEmitter.emit('object', JSON.parse(obj))
|
||||
}
|
||||
}
|
||||
position += bytesRead
|
||||
|
||||
if (buf.length - position < bufferSize / 2) {
|
||||
buf.copy(buf, 0, end, position)
|
||||
position -= end
|
||||
end = 0
|
||||
}
|
||||
return bytesRead
|
||||
},
|
||||
close() {
|
||||
fs.closeSync(fd)
|
||||
},
|
||||
eventEmitter
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = createParser
|
Loading…
Reference in New Issue