forked from rsksmart/rsk-explorer-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathApi.js
179 lines (162 loc) · 5.63 KB
/
Api.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import { DataCollector } from './lib/DataCollector'
import { getEnabledApiModules } from './modules'
import { txTypes } from '../lib/types'
import { getDbBlocksCollections } from '../lib/blocksCollections'
import { filterParams, getDelayedFields, MODULES } from './lib/apiTools'
import config from '../lib/config'
import NativeContracts from '../lib/NativeContracts'
// It is used only in case Stats cannot provide the circulating supply
import getCirculatingSupply from './lib/getCirculatingSupply'
class Api extends DataCollector {
constructor ({ db, initConfig }, { modules, collectionsNames, lastBlocks } = {}) {
const collectionName = collectionsNames.Blocks
super(db, { collectionName })
this.collectionsNames = collectionsNames
this.collections = getDbBlocksCollections(db)
this.lastLimit = lastBlocks || 100
this.latest = undefined
this.lastBlocks = { data: [] }
this.lastTransactions = { data: [] }
this.balancesStatus = { data: {} }
this.circulatingSupply = null
this.stats = { timestamp: 0 }
this.loadModules(getEnabledApiModules(modules))
this.initConfig = initConfig
const { isNativeContract } = NativeContracts(initConfig)
this.isNativeContract = isNativeContract
this.tick()
}
tick () {
this.setLastBlocks()
this.updateBalancesStatus()
}
loadModules (modules) {
Object.keys(modules).forEach(name => {
const constructor = modules[name]
if (typeof constructor === 'function') {
const module = new constructor(this.collections, name)
this.log.info(`Loading module ${name}`)
this.addModule(module, name)
}
})
}
async run (payload) {
try {
if (Object.keys(payload).length < 1) throw new Error('invalid request')
let { module, action, params } = payload
if (!action) throw new Error('Missing action')
const moduleName = MODULES[module]
if (!moduleName) throw new Error('Unknown module')
const delayed = getDelayedFields(moduleName, action)
const time = Date.now()
params = filterParams(payload.params)
const result = await this.getModule(moduleName).run(action, params)
const queryTime = Date.now() - time
const logCmd = (queryTime > 1000) ? 'warn' : 'trace'
this.log[logCmd](`${module}.${action}(${JSON.stringify(params)}) ${queryTime} ms`)
const res = { module, action, params, result, delayed }
return res
} catch (err) {
this.log.debug(err)
return Promise.reject(err)
}
}
info () {
let info = Object.assign({}, this.initConfig)
info.txTypes = Object.assign({}, txTypes)
info.modules = config.api.modules
return info
}
async setLastBlocks () {
try {
const Block = this.getModule('Block')
const Tx = this.getModule('Tx')
let limit = this.lastLimit
let blocks = await Block.run('getBlocks', { limit, addMetadata: true })
let query = { txType: [txTypes.default, txTypes.contract] }
let transactions = await Tx.run('getTransactions', { query, limit })
this.updateLastBlocks(blocks, transactions)
} catch (err) {
this.log.debug(err)
}
}
getStats () {
return this.formatData(this.stats)
}
getCirculatingSupply () {
return this.formatData(this.circulatingSupply)
}
getLastBlocks () {
let data = this.lastBlocks
return this.formatData(data)
}
getLastTransactions () {
let data = this.lastTransactions
return this.formatData(data)
}
getLastBlock () {
let { data } = this.lastBlocks
return data[0] || null
}
getBalancesStatus () {
return this.balancesStatus
}
async updateBalancesStatus () {
let data = await this.getModule('Balances').run('getStatus')
this.balancesStatus = data
}
updateLastBlocks (blocks, transactions) {
let blockData = blocks.data
this.lastBlocks = blocks
this.lastTransactions = transactions
let latest
if (blockData && blockData[0]) latest = blockData[0].number
if (latest !== this.latest) {
this.latest = latest
this.events.emit('newBlocks', this.getLastBlocks())
this.updateStats()
}
}
async getAddress (address) {
return this.getModule('Address').run('getAddress', { address })
}
async addAddressData (address, data, key = '_addressData') {
const account = await this.getAddress(address)
if (data && data.data && account) data.data[key] = account.data
return data || account
}
getPendingTransaction (params) {
return this.getModule('TxPending').run('getPendingTransaction', params)
}
async updateStats () {
const oldStats = this.stats
const Stats = await this.getModule('Stats')
if (!Stats) return
const stats = await Stats.run('getLatest')
if (!stats) return
/* const ExtendedStats = this.getModule('ExtendedStats')
if (ExtendedStats) {
const blockNumber = parseInt(stats.blockNumber)
const extendedStats = await ExtendedStats.getExtendedStats(blockNumber)
Object.assign(stats, extendedStats)
} */
let circulatingSupply = stats.circulatingSupply || await this.getCirculatingSupplyFromDb()
this.circulatingSupply = circulatingSupply
this.stats = Object.assign({}, stats)
let timestamp = stats.timestamp || 0
if (timestamp > oldStats.timestamp) {
this.events.emit('newStats', this.getStats())
}
}
async getCirculatingSupplyFromDb () {
try {
const collection = this.collections.Addrs
const { nativeContracts } = this.initConfig
let circulating = await getCirculatingSupply(collection, nativeContracts)
return circulating
} catch (err) {
this.log.debug(err)
}
}
}
export default Api