Skip to content

Commit 04d2e31

Browse files
authored
Merge pull request #200 from EdgeApp/sam/getTxInfo
Sam/get tx info
2 parents 7ab5e29 + 345911d commit 04d2e31

File tree

14 files changed

+798
-304
lines changed

14 files changed

+798
-304
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- added: Add Lifi reporting
6+
- added: Added `/v1/getTxInfo` route.
67
- added: Paybis support
78
- added: Kado reporting
89
- changed: Paginate caching engine to prevent timeouts

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
"csv-stringify": "^6.2.0",
5050
"date-fns": "^2.16.1",
5151
"date-fns-tz": "^1.1.4",
52+
"edge-server-tools": "^0.2.19",
5253
"express": "^4.17.3",
54+
"express-promise-router": "^4.1.1",
5355
"nano": "^10.1.0",
5456
"node-fetch": "^2.6.7",
5557
"prop-types": ">= 15.5.10 < 16.0.0",
@@ -65,6 +67,7 @@
6567
},
6668
"devDependencies": {
6769
"@types/chai": "^4.2.21",
70+
"@types/express": "^4.17.3",
6871
"@types/mocha": "^9.0.0",
6972
"@types/node-fetch": "^2.6.3",
7073
"@types/react": "^16.9.22",

src/indexApi.ts

Lines changed: 27 additions & 192 deletions
Original file line numberDiff line numberDiff line change
@@ -1,215 +1,50 @@
11
// import bodyParser from 'body-parser'
2-
import { asArray, asObject, asOptional, asString } from 'cleaners'
32
import cors from 'cors'
43
import express from 'express'
54
import nano from 'nano'
65

76
import { config } from './config'
8-
import { cacheAnalytic } from './dbutils'
9-
import { asApps, asDbTx } from './types'
7+
import { analyticsRouter } from './routes/v1/analytics'
8+
import { checkTxsRouter } from './routes/v1/checkTxs'
9+
import { getAppIdRouter } from './routes/v1/getAppId'
10+
import { getPluginIdsRouter } from './routes/v1/getPluginIds'
11+
import { getTxInfoRouter } from './routes/v1/getTxInfo'
12+
import { HttpError } from './util/httpErrors'
1013

11-
const asAnalyticsReq = asObject({
12-
start: asString,
13-
end: asString,
14-
appId: asString,
15-
pluginIds: asArray(asString),
16-
timePeriod: asString
17-
})
18-
19-
const asCheckTxsReq = asObject({
20-
apiKey: asString,
21-
data: asArray(
22-
asObject({
23-
pluginId: asString,
24-
orderId: asString
25-
})
26-
)
27-
})
28-
29-
const asCheckTxsFetch = asArray(
30-
asObject({
31-
key: asString,
32-
doc: asOptional(asDbTx),
33-
error: asOptional(asString)
34-
})
35-
)
36-
37-
const asPluginIdsReq = asObject({
38-
appId: asString
39-
})
40-
const asPartnerIdsDbReq = asObject({
41-
partnerIds: asObject(
42-
asObject({
43-
pluginId: asOptional(asString),
44-
apiKeys: asObject(asString)
45-
})
46-
)
47-
})
48-
49-
const asAppIdReq = asObject({
50-
apiKey: asString
51-
})
52-
const asAppIdDbReq = asObject({
53-
appId: asString
54-
})
55-
56-
interface CheckTxsResponse {
57-
pluginId: string
58-
orderId: string
59-
error?: string
60-
usdValue?: number
61-
}
62-
63-
const CHECKTXS_BATCH_LIMIT = 100
64-
65-
const nanoDb = nano(config.couchDbFullpath)
14+
export const nanoDb = nano(config.couchDbFullpath)
15+
export const reportsTransactions = nanoDb.use('reports_transactions')
16+
export const reportsApps = nanoDb.use('reports_apps')
6617

6718
async function main(): Promise<void> {
6819
// start express and couch db server
6920
const app = express()
70-
const reportsTransactions = nanoDb.use('reports_transactions')
71-
const reportsApps = nanoDb.use('reports_apps')
7221

7322
app.use(express.json())
7423
// app.use(bodyParser.json({ type: 'application/json' }))
7524
app.use(cors())
7625
app.use('/', express.static('dist'))
7726

78-
const query = {
79-
selector: {
80-
appId: { $exists: true }
81-
},
82-
limit: 1000000
83-
}
84-
85-
const rawApps = await reportsApps.find(query)
86-
const apps = asApps(rawApps.docs)
87-
88-
app.post(`/v1/analytics/`, async function(req, res) {
89-
let analyticsQuery: ReturnType<typeof asAnalyticsReq>
90-
try {
91-
analyticsQuery = asAnalyticsReq(req.body)
92-
} catch {
93-
res.status(400).send(`Missing Request Fields`)
94-
return
95-
}
96-
const { start, end, appId, pluginIds } = analyticsQuery
97-
const timePeriod = analyticsQuery.timePeriod.toLowerCase()
98-
const queryStart = new Date(start).getTime() / 1000
99-
const queryEnd = new Date(end).getTime() / 1000
100-
if (
101-
!(queryStart > 0) ||
102-
!(queryEnd > 0) ||
103-
(!timePeriod.includes('month') &&
104-
!timePeriod.includes('day') &&
105-
!timePeriod.includes('hour'))
106-
) {
107-
res.status(400).send(`Bad Request Fields`)
108-
return
109-
}
110-
if (queryStart > queryEnd) {
111-
res.status(400).send(`Start must be less than End`)
112-
return
113-
}
114-
115-
const result = await cacheAnalytic(
116-
queryStart,
117-
queryEnd,
118-
appId,
119-
pluginIds,
120-
timePeriod
121-
)
122-
123-
res.json(result)
124-
})
125-
126-
app.post('/v1/checkTxs/', async function(req, res) {
127-
let queryResult
128-
try {
129-
queryResult = asCheckTxsReq(req.body)
130-
} catch (e) {
131-
return res.status(400).send(`Missing Request fields.`)
132-
}
133-
if (queryResult.data.length > CHECKTXS_BATCH_LIMIT) {
134-
return res.status(400).send(`Exceeded Limit of ${CHECKTXS_BATCH_LIMIT}`)
135-
}
136-
const searchedAppId = apps.find(app => app._id === queryResult.apiKey)
137-
if (typeof searchedAppId === 'undefined') {
138-
return res.status(400).send(`API Key has no match.`)
139-
}
140-
const { appId } = searchedAppId
141-
const keys = queryResult.data.map(tx => {
142-
return `${appId}_${tx.pluginId}:${tx.orderId}`.toLowerCase()
143-
})
144-
try {
145-
const dbResult = await reportsTransactions.fetch({ keys })
146-
const cleanedResult = asCheckTxsFetch(dbResult.rows)
147-
const data: CheckTxsResponse[] = cleanedResult.map((result, index) => {
148-
const tx: CheckTxsResponse = {
149-
pluginId: queryResult.data[index].pluginId,
150-
orderId: queryResult.data[index].orderId,
151-
usdValue: undefined
152-
}
153-
if (result.error != null) {
154-
return {
155-
...tx,
156-
error: `Could not find transaction: ${result.key}`
157-
}
27+
app.use('/v1/analytics/', analyticsRouter)
28+
app.use('/v1/checkTxs/', checkTxsRouter)
29+
app.use('/v1/getAppId/', getAppIdRouter)
30+
app.use('/v1/getPluginIds/', getPluginIdsRouter)
31+
app.use('/v1/getTxInfo/', getTxInfoRouter)
32+
33+
// Error router
34+
app.use(function(err, _req, res, _next) {
35+
console.error(err.stack)
36+
if (err instanceof HttpError) {
37+
console.error(`HTTP status ${err.status}:`, err.error)
38+
res.status(err.status).send({
39+
error: {
40+
message: err.error.message
15841
}
159-
if (result.doc != null) tx.usdValue = result.doc.usdValue
160-
return tx
16142
})
162-
res.json({ appId, data })
163-
} catch (e) {
164-
console.log(e)
165-
return res.status(500).send(`Internal Server Error.`)
166-
}
167-
})
168-
169-
app.get('/v1/getPluginIds/', async function(req, res) {
170-
let queryResult
171-
try {
172-
queryResult = asPluginIdsReq(req.query)
173-
} catch (e) {
174-
res.status(400).send(`Missing Request fields.`)
175-
return
176-
}
177-
const query = {
178-
selector: {
179-
appId: { $eq: queryResult.appId.toLowerCase() }
180-
},
181-
fields: ['partnerIds'],
182-
limit: 1
183-
}
184-
let partnerIds
185-
try {
186-
const rawApp = await reportsApps.find(query)
187-
const app = asPartnerIdsDbReq(rawApp.docs[0])
188-
partnerIds = Object.keys(app.partnerIds)
189-
} catch (e) {
190-
res.status(404).send(`App ID not found.`)
191-
return
192-
}
193-
res.json(partnerIds)
194-
})
195-
196-
app.get('/v1/getAppId/', async function(req, res) {
197-
let queryResult
198-
try {
199-
queryResult = asAppIdReq(req.query)
200-
} catch (e) {
201-
res.status(400).send(`Missing Request fields.`)
202-
return
203-
}
204-
let appId
205-
try {
206-
const dbResult = await reportsApps.get(queryResult.apiKey)
207-
appId = asAppIdDbReq(dbResult).appId
208-
} catch (e) {
209-
res.status(400).send(`API KEY UNRECOGNIZED.`)
210-
return
43+
} else {
44+
res.status(500).send({
45+
error: 'Internal Server Error'
46+
})
21147
}
212-
res.json(appId)
21348
})
21449

21550
app.listen(config.httpPort, function() {

0 commit comments

Comments
 (0)