-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.ts
More file actions
140 lines (125 loc) · 5.06 KB
/
index.ts
File metadata and controls
140 lines (125 loc) · 5.06 KB
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
import { AddressPaymentInfo } from 'services/addressService'
import { PaybuttonWithAddresses } from 'services/paybuttonService'
import { TransactionsWithPaybuttonsAndPrices } from 'services/transactionService'
import { fetchUsersForAddress } from 'services/userService'
import { cacheBalanceForAddress, clearBalanceCache, getBalanceForAddress, updateBalanceCacheFromTx } from './balanceCache'
import { clearDashboardCache, getUserDashboardData } from './dashboardCache'
import { appendPaybuttonToAddressesCache, cacheGroupedPayments, cacheManyTxs, generateAndCacheGroupedPaymentsAndInfoForAddress, getCachedPaymentsCountForUser, getPaymentList, initPaymentCache, removePaybuttonToAddressesCache } from './paymentCache'
import { DashboardData, Payment } from './types'
import { Address } from '@prisma/client'
interface PaybuttonCreationParams {
paybutton: PaybuttonWithAddresses
addressStringList: string[]
userId: string
}
type PaybuttonUpdateParams = PaybuttonCreationParams
type PaybuttonDeletionParams = PaybuttonCreationParams
export const CacheSet = {
addressCreation: async (address: Address): Promise<void> => {
const groupedPaymentsAndInfo = await generateAndCacheGroupedPaymentsAndInfoForAddress(address)
await cacheGroupedPayments(groupedPaymentsAndInfo.groupedPayments)
await cacheBalanceForAddress(groupedPaymentsAndInfo.info, address.address)
},
txCreation: async (tx: TransactionsWithPaybuttonsAndPrices): Promise<void> => {
const cacheInitialized = await initPaymentCache(tx.address)
if (cacheInitialized) return
void await cacheManyTxs([tx])
const userIds = await fetchUsersForAddress(tx.address.address)
await updateBalanceCacheFromTx(tx)
await Promise.all(
userIds.map(async u => {
await clearDashboardCache(u.id)
})
)
},
txsCreation: async (txs: TransactionsWithPaybuttonsAndPrices[]): Promise<void> => {
void await cacheManyTxs(txs)
const differentAddresses = new Set(txs.map(tx => tx.address.address))
for (const addr of differentAddresses) {
const userIds = await fetchUsersForAddress(addr)
await Promise.all(
userIds.map(async u => {
await clearDashboardCache(u.id)
})
)
await clearBalanceCache(addr)
}
},
paybuttonCreation: async ({ paybutton, addressStringList, userId }: PaybuttonCreationParams): Promise<void> => {
await appendPaybuttonToAddressesCache(
addressStringList,
{
name: paybutton.name,
id: paybutton.id
}
)
await clearDashboardCache(userId)
},
paybuttonUpdate: async ({ paybutton, addressStringList, userId }: PaybuttonUpdateParams): Promise<void> => {
await appendPaybuttonToAddressesCache(
addressStringList,
{
name: paybutton.name,
id: paybutton.id
}
)
await clearDashboardCache(userId)
},
paybuttonDeletion: async ({ paybutton, addressStringList, userId }: PaybuttonDeletionParams): Promise<void> => {
await removePaybuttonToAddressesCache(addressStringList, paybutton.id)
await clearDashboardCache(userId)
}
}
type MethodName = 'dashboardData' | 'paymentList' | 'addressBalance' | 'paymentsCount'
type InFlightCalls = Partial<Record<MethodName, Promise<unknown>>>
interface PendingCalls {
[userId: string]: InFlightCalls
}
export class CacheGet {
private static pendingCalls: PendingCalls = {}
private static async executeCall<T>(
userId: string,
methodName: MethodName,
fn: () => Promise<T>
): Promise<T> {
if (this.pendingCalls[userId] === undefined) {
this.pendingCalls[userId] = {}
}
const existingCall = this.pendingCalls[userId][methodName]
if (existingCall !== undefined) {
return await (existingCall as Promise<T>)
}
const pendingCall = fn()
this.pendingCalls[userId][methodName] = pendingCall as Promise<unknown>
try {
return await pendingCall
} finally {
if (this.pendingCalls[userId]?.[methodName] === pendingCall) {
this.pendingCalls[userId][methodName] = undefined
}
if (this.pendingCalls[userId] !== undefined && Object.keys(this.pendingCalls[userId]).length === 0) {
this.pendingCalls[userId] = {}
}
}
}
static async dashboardData (userId: string, timezone: string, buttonIds?: string[]): Promise<DashboardData> {
return await this.executeCall(userId, 'dashboardData', async () => {
return await getUserDashboardData(userId, timezone, buttonIds)
})
}
static async paymentList (userId: string): Promise<Payment[]> {
return await this.executeCall(userId, 'paymentList', async () => {
return await getPaymentList(userId)
})
}
static async addressBalance (addressString: string): Promise<AddressPaymentInfo> {
return await this.executeCall(addressString, 'addressBalance', async () => {
return await getBalanceForAddress(addressString)
})
}
static async paymentsCount (userId: string, timezone: string): Promise<number> {
return await this.executeCall(userId, 'paymentsCount', async () => {
return await getCachedPaymentsCountForUser(userId, timezone)
})
}
}