@moneypot/hub 1.22.0 → 1.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,6 +4,14 @@ const HASH_HERALD_OPTIONS = {
|
|
|
4
4
|
baseUrl: config.HASHCHAINSERVER_URL,
|
|
5
5
|
applicationSecret: config.HASHCHAINSERVER_APPLICATION_SECRET,
|
|
6
6
|
};
|
|
7
|
+
const HASH_HERALD_TIMEOUT_MS = 10_000;
|
|
8
|
+
function getHashWithTimeout(req) {
|
|
9
|
+
let timer;
|
|
10
|
+
const timeout = new Promise((_, reject) => {
|
|
11
|
+
timer = setTimeout(() => reject(new Error(`hash-herald did not answer within ${HASH_HERALD_TIMEOUT_MS}ms`)), HASH_HERALD_TIMEOUT_MS);
|
|
12
|
+
});
|
|
13
|
+
return Promise.race([getHash(HASH_HERALD_OPTIONS, req), timeout]).finally(() => clearTimeout(timer));
|
|
14
|
+
}
|
|
7
15
|
function resultFromGetHashResponse(response) {
|
|
8
16
|
if (!response.resp) {
|
|
9
17
|
return { type: "bad_hash_chain", reason: "empty_response" };
|
|
@@ -26,7 +34,7 @@ export async function getIntermediateHash({ hashChainId, iteration, }) {
|
|
|
26
34
|
iterations: iteration,
|
|
27
35
|
context: undefined,
|
|
28
36
|
};
|
|
29
|
-
return
|
|
37
|
+
return getHashWithTimeout(req).then(resultFromGetHashResponse);
|
|
30
38
|
}
|
|
31
39
|
export async function getPreimageHash({ hashChainId, }) {
|
|
32
40
|
const req = {
|
|
@@ -39,7 +47,7 @@ export async function getPreimageHash({ hashChainId, }) {
|
|
|
39
47
|
},
|
|
40
48
|
},
|
|
41
49
|
};
|
|
42
|
-
return
|
|
50
|
+
return getHashWithTimeout(req).then(resultFromGetHashResponse);
|
|
43
51
|
}
|
|
44
52
|
export async function getTerminalHash({ hashChainId, }) {
|
|
45
53
|
const iterations = config.HASHCHAINSERVER_MAX_ITERATIONS;
|
|
@@ -53,5 +61,5 @@ export async function getTerminalHash({ hashChainId, }) {
|
|
|
53
61
|
},
|
|
54
62
|
},
|
|
55
63
|
};
|
|
56
|
-
return
|
|
64
|
+
return getHashWithTimeout(req).then(resultFromGetHashResponse);
|
|
57
65
|
}
|
|
@@ -2,8 +2,10 @@ import * as pg from "pg";
|
|
|
2
2
|
import { type PgClientInTransaction } from "../../db/transaction.js";
|
|
3
3
|
import { LiabilityConfigInternal } from "../public/config.js";
|
|
4
4
|
import { QueryExecutor } from "../../db/util.js";
|
|
5
|
-
export declare function dbGetLiabilityIdsPastDeadline(pgClient: QueryExecutor, { limit }?: {
|
|
5
|
+
export declare function dbGetLiabilityIdsPastDeadline(pgClient: QueryExecutor, { limit, excludeIds, before, }?: {
|
|
6
6
|
limit?: number;
|
|
7
|
+
excludeIds?: string[];
|
|
8
|
+
before?: Date;
|
|
7
9
|
}): Promise<string[]>;
|
|
8
10
|
export declare function startLiabilityDeadlineProcessor<RefType extends string>({ signal, pool, liabilityConfig, }: {
|
|
9
11
|
signal: AbortSignal;
|
|
@@ -14,8 +16,11 @@ export declare function processOneDeadlinedLiability<RefType extends string>(pgC
|
|
|
14
16
|
liabilityConfig: LiabilityConfigInternal<RefType>;
|
|
15
17
|
liabilityId: string;
|
|
16
18
|
}): Promise<void>;
|
|
17
|
-
export declare function processDeadlinedLiabilities<RefType extends string>({ pool, liabilityConfig, signal, }: {
|
|
19
|
+
export declare function processDeadlinedLiabilities<RefType extends string>({ pool, liabilityConfig, signal, batchSize, }: {
|
|
18
20
|
pool: pg.Pool;
|
|
19
21
|
liabilityConfig: LiabilityConfigInternal<RefType>;
|
|
20
22
|
signal: AbortSignal;
|
|
21
|
-
|
|
23
|
+
batchSize?: number;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
failed: number;
|
|
26
|
+
}>;
|
|
@@ -4,17 +4,18 @@ import { dbLockHouseBankroll, dbLockPlayerBalance } from "../../db/public.js";
|
|
|
4
4
|
import { exactlyOneRow, maybeOneRow } from "../../db/util.js";
|
|
5
5
|
import { abortableTimeout } from "../../util.js";
|
|
6
6
|
const BATCH_SIZE = 100;
|
|
7
|
-
export async function dbGetLiabilityIdsPastDeadline(pgClient, { limit = 100 } = {}) {
|
|
7
|
+
export async function dbGetLiabilityIdsPastDeadline(pgClient, { limit = 100, excludeIds = [], before = new Date(), } = {}) {
|
|
8
8
|
const result = await pgClient.query({
|
|
9
9
|
text: `
|
|
10
10
|
SELECT id
|
|
11
11
|
FROM hub.liability
|
|
12
12
|
WHERE resolved_at IS NULL
|
|
13
|
-
AND deadline <
|
|
13
|
+
AND deadline < $3
|
|
14
|
+
AND NOT (id = ANY($2::uuid[]))
|
|
14
15
|
ORDER BY deadline ASC
|
|
15
16
|
LIMIT $1
|
|
16
17
|
`,
|
|
17
|
-
values: [limit],
|
|
18
|
+
values: [limit, excludeIds, before],
|
|
18
19
|
});
|
|
19
20
|
return result.rows.map((r) => r.id);
|
|
20
21
|
}
|
|
@@ -89,46 +90,55 @@ export async function processOneDeadlinedLiability(pgClient, { liabilityConfig,
|
|
|
89
90
|
logger.error(`No house bankroll found for liability ${dbLockedLiability.id}.`);
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
liabilityConfig: liabilityConfig,
|
|
99
|
-
});
|
|
100
|
-
const { resolved_at } = await pgClient
|
|
101
|
-
.query(`SELECT resolved_at FROM hub.liability WHERE id = $1`, [dbLockedLiability.id])
|
|
102
|
-
.then(exactlyOneRow);
|
|
103
|
-
if (!resolved_at) {
|
|
104
|
-
throw new Error(`Handler returned LIABILITY_RESOLVED but did not resolve liability ${dbLockedLiability.id} (ref_type: ${dbLockedLiability.ref_type}, ref_id: ${dbLockedLiability.ref_id}). ` +
|
|
105
|
-
`Handler must call dbResolveLiabilityByRef before returning.`);
|
|
106
|
-
}
|
|
107
|
-
logger.debug(`Resolved liability ${dbLockedLiability.id}`);
|
|
108
|
-
}
|
|
109
|
-
catch (e) {
|
|
110
|
-
logger.error(e, `Error handling deadline for liability ${dbLockedLiability.id}`);
|
|
111
|
-
throw e;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
export async function processDeadlinedLiabilities({ pool, liabilityConfig, signal, }) {
|
|
115
|
-
const liabilityIds = await dbGetLiabilityIdsPastDeadline(pool, {
|
|
116
|
-
limit: BATCH_SIZE,
|
|
93
|
+
await refTypeConfig.handleDeadline({
|
|
94
|
+
pgClientInTransaction: pgClient,
|
|
95
|
+
lockedLiability: dbLockedLiability,
|
|
96
|
+
lockedPlayerBalance: dbLockedPlayerBalance,
|
|
97
|
+
lockedHouseBankroll: dbLockedHouseBankroll,
|
|
98
|
+
liabilityConfig: liabilityConfig,
|
|
117
99
|
});
|
|
118
|
-
|
|
119
|
-
|
|
100
|
+
const { resolved_at } = await pgClient
|
|
101
|
+
.query(`SELECT resolved_at FROM hub.liability WHERE id = $1`, [dbLockedLiability.id])
|
|
102
|
+
.then(exactlyOneRow);
|
|
103
|
+
if (!resolved_at) {
|
|
104
|
+
throw new Error(`Handler returned LIABILITY_RESOLVED but did not resolve liability ${dbLockedLiability.id} (ref_type: ${dbLockedLiability.ref_type}, ref_id: ${dbLockedLiability.ref_id}). ` +
|
|
105
|
+
`Handler must call dbResolveLiabilityByRef before returning.`);
|
|
120
106
|
}
|
|
121
|
-
logger.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
logger.debug(`Resolved liability ${dbLockedLiability.id}`);
|
|
108
|
+
}
|
|
109
|
+
export async function processDeadlinedLiabilities({ pool, liabilityConfig, signal, batchSize = BATCH_SIZE, }) {
|
|
110
|
+
const before = new Date();
|
|
111
|
+
const tried = [];
|
|
112
|
+
let failed = 0;
|
|
113
|
+
while (!signal.aborted) {
|
|
114
|
+
const liabilityIds = await dbGetLiabilityIdsPastDeadline(pool, {
|
|
115
|
+
limit: batchSize,
|
|
116
|
+
excludeIds: tried,
|
|
117
|
+
before,
|
|
118
|
+
});
|
|
119
|
+
if (liabilityIds.length === 0) {
|
|
125
120
|
break;
|
|
126
121
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
logger.info(`Processor found ${liabilityIds.length} liability candidates...`);
|
|
123
|
+
for (const liabilityId of liabilityIds) {
|
|
124
|
+
if (signal.aborted) {
|
|
125
|
+
logger.info(`[processExpiredLiabilities] Aborted by graceful shutdown.`);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
tried.push(liabilityId);
|
|
129
|
+
try {
|
|
130
|
+
await withPgPoolTransaction(pool, async (pgClient) => {
|
|
131
|
+
await processOneDeadlinedLiability(pgClient, {
|
|
132
|
+
liabilityConfig,
|
|
133
|
+
liabilityId,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
failed++;
|
|
139
|
+
logger.error({ err: e, liabilityId }, `Error handling deadline for liability ${liabilityId}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
133
142
|
}
|
|
143
|
+
return { failed };
|
|
134
144
|
}
|
|
@@ -8,9 +8,16 @@ export async function dbCreateLiability(pgClient, { lockedBankrollId, casinoId,
|
|
|
8
8
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
9
9
|
RETURNING *
|
|
10
10
|
),
|
|
11
|
+
-- Sub-statements share one snapshot, so the sum can't see the
|
|
12
|
+
-- inserted row; its payout is added separately.
|
|
11
13
|
bankroll_update AS (
|
|
12
14
|
UPDATE hub.bankroll
|
|
13
|
-
SET liability =
|
|
15
|
+
SET liability = $8 + (
|
|
16
|
+
SELECT COALESCE(SUM(max_payout), 0)
|
|
17
|
+
FROM hub.liability
|
|
18
|
+
WHERE bankroll_id = $1
|
|
19
|
+
AND resolved_at IS NULL
|
|
20
|
+
)
|
|
14
21
|
WHERE id = $1
|
|
15
22
|
)
|
|
16
23
|
SELECT * FROM inserted
|
|
@@ -40,10 +47,18 @@ export async function dbResolveLiabilityByRef(pgClient, { refType, refId, locked
|
|
|
40
47
|
WHERE ref_type = $1
|
|
41
48
|
AND ref_id = $2
|
|
42
49
|
AND resolved_at IS NULL
|
|
43
|
-
RETURNING
|
|
50
|
+
RETURNING id, bankroll_id
|
|
44
51
|
)
|
|
52
|
+
-- The sum reads the statement's snapshot, where the resolved row is
|
|
53
|
+
-- still active, so it is excluded by id.
|
|
45
54
|
UPDATE hub.bankroll
|
|
46
|
-
SET liability =
|
|
55
|
+
SET liability = (
|
|
56
|
+
SELECT COALESCE(SUM(l.max_payout), 0)
|
|
57
|
+
FROM hub.liability l
|
|
58
|
+
WHERE l.bankroll_id = resolved.bankroll_id
|
|
59
|
+
AND l.resolved_at IS NULL
|
|
60
|
+
AND l.id <> resolved.id
|
|
61
|
+
)
|
|
47
62
|
FROM resolved
|
|
48
63
|
WHERE hub.bankroll.id = resolved.bankroll_id
|
|
49
64
|
`,
|