@moneypot/hub 1.7.0 → 1.8.0-dev.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.
- package/dist/src/config.d.ts +2 -0
- package/dist/src/config.js +47 -13
- package/dist/src/db/index.js +3 -3
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +7 -13
- package/dist/src/logger.d.ts +3 -9
- package/dist/src/logger.js +27 -18
- package/dist/src/plugins/debug.js +4 -1
- package/dist/src/plugins/hub-add-casino.js +2 -6
- package/dist/src/plugins/hub-authenticate.js +12 -3
- package/dist/src/plugins/hub-make-outcome-bet.js +8 -11
- package/dist/src/plugins/hub-put-alert.js +2 -1
- package/dist/src/process-transfers/index.js +3 -3
- package/dist/src/process-transfers/polling-processor.js +2 -2
- package/dist/src/process-transfers/process-transfer.js +3 -3
- package/dist/src/process-transfers/websocket-processor.js +5 -5
- package/dist/src/server/graphile.config.js +1 -1
- package/dist/src/take-request/process-take-request.js +19 -19
- package/package.json +3 -1
package/dist/src/config.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
export declare const NODE_ENV: string;
|
|
3
3
|
export declare const PORT: number;
|
|
4
|
+
export declare const LOG_LEVEL: string;
|
|
5
|
+
export declare const LOG_PRETTY: boolean | undefined;
|
|
4
6
|
export declare const MP_GRAPHQL_URL: string;
|
|
5
7
|
export declare const DATABASE_URL: string;
|
|
6
8
|
export declare const SUPERUSER_DATABASE_URL: string;
|
package/dist/src/config.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
import pgConnectionString from "pg-connection-string";
|
|
3
|
-
import { logger } from "./logger.js";
|
|
4
3
|
import { assert } from "tsafe";
|
|
5
4
|
function getEnvVariable(key, transform = (value) => value) {
|
|
6
5
|
return transform(process.env[key] || "");
|
|
7
6
|
}
|
|
8
7
|
export const NODE_ENV = getEnvVariable("NODE_ENV", (value) => {
|
|
9
8
|
if (!value) {
|
|
10
|
-
|
|
9
|
+
console.warn("Missing NODE_ENV env var. Defaulting to 'development'");
|
|
11
10
|
return "development";
|
|
12
11
|
}
|
|
13
12
|
return value;
|
|
@@ -16,22 +15,57 @@ export const PORT = getEnvVariable("PORT", (value) => {
|
|
|
16
15
|
const parsed = Number.parseInt(value, 10);
|
|
17
16
|
if (!parsed || parsed <= 0 || !Number.isSafeInteger(parsed)) {
|
|
18
17
|
const DEFAULT_PORT = 4000;
|
|
19
|
-
|
|
18
|
+
console.warn(`Warning: PORT missing or invalid, defaulting to ${DEFAULT_PORT}`);
|
|
20
19
|
return DEFAULT_PORT;
|
|
21
20
|
}
|
|
22
21
|
return parsed;
|
|
23
22
|
});
|
|
23
|
+
const logLevels = [
|
|
24
|
+
"silent",
|
|
25
|
+
"trace",
|
|
26
|
+
"debug",
|
|
27
|
+
"info",
|
|
28
|
+
"warn",
|
|
29
|
+
"error",
|
|
30
|
+
];
|
|
31
|
+
export const LOG_LEVEL = getEnvVariable("LOG_LEVEL", (value) => {
|
|
32
|
+
if (logLevels.includes(value)) {
|
|
33
|
+
if (value === "silent") {
|
|
34
|
+
console.log("LOG_LEVEL is set to silent. No logging will be done.");
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
if (value === "") {
|
|
39
|
+
console.log(`Defaulting LOG_LEVEL to "info". (Options: ${logLevels.join(", ")})`);
|
|
40
|
+
return "info";
|
|
41
|
+
}
|
|
42
|
+
console.warn(`Unknown LOG_LEVEL: "${value}". Defaulting to "info".`);
|
|
43
|
+
return "info";
|
|
44
|
+
});
|
|
45
|
+
export const LOG_PRETTY = getEnvVariable("LOG_PRETTY", (value) => {
|
|
46
|
+
switch (value) {
|
|
47
|
+
case "":
|
|
48
|
+
return undefined;
|
|
49
|
+
case "true":
|
|
50
|
+
return true;
|
|
51
|
+
case "false":
|
|
52
|
+
return false;
|
|
53
|
+
default:
|
|
54
|
+
console.warn(`Unknown LOG_PRETTY: "${value}"`);
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
24
58
|
export const MP_GRAPHQL_URL = getEnvVariable("MP_GRAPHQL_URL", (value) => {
|
|
25
59
|
if (!value) {
|
|
26
|
-
|
|
60
|
+
console.warn("Missing MP_GRAPHQL_URL env var. Defaulting to http://localhost:3000/graphql");
|
|
27
61
|
return "http://localhost:3000/graphql";
|
|
28
62
|
}
|
|
29
63
|
if (!URL.parse(value)) {
|
|
30
|
-
|
|
64
|
+
console.warn("MP_GRAPHQL_URL is not a valid URL. Defaulting to http://localhost:3000/graphql");
|
|
31
65
|
}
|
|
32
66
|
const url = new URL(value);
|
|
33
67
|
if (url.pathname !== "/graphql") {
|
|
34
|
-
|
|
68
|
+
console.warn("MP_GRAPHQL_URL pathname is not '/graphql'. Are you sure it points to a graphql endpoint?");
|
|
35
69
|
}
|
|
36
70
|
return value;
|
|
37
71
|
});
|
|
@@ -40,11 +74,11 @@ export const DATABASE_URL = getEnvVariable("DATABASE_URL", (value) => {
|
|
|
40
74
|
throw new Error(`Missing DATABASE_URL env var.`);
|
|
41
75
|
}
|
|
42
76
|
if (!URL.parse(value)) {
|
|
43
|
-
|
|
77
|
+
console.warn("DATABASE_URL is not a valid URL.");
|
|
44
78
|
}
|
|
45
79
|
const databaseUrlUsername = pgConnectionString.parse(value).user;
|
|
46
80
|
if (databaseUrlUsername !== "app_postgraphile") {
|
|
47
|
-
|
|
81
|
+
console.warn(`DATABASE_URL username is ${databaseUrlUsername}, expected app_postgraphile`);
|
|
48
82
|
}
|
|
49
83
|
return value;
|
|
50
84
|
});
|
|
@@ -53,21 +87,21 @@ export const SUPERUSER_DATABASE_URL = getEnvVariable("SUPERUSER_DATABASE_URL", (
|
|
|
53
87
|
throw new Error("SUPERUSER_DATABASE_URL env var is required");
|
|
54
88
|
}
|
|
55
89
|
if (!URL.parse(value)) {
|
|
56
|
-
|
|
90
|
+
console.warn("SUPERUSER_DATABASE_URL is not a valid URL.");
|
|
57
91
|
}
|
|
58
92
|
return value;
|
|
59
93
|
});
|
|
60
94
|
export const HASHCHAINSERVER_URL = getEnvVariable("HASHCHAINSERVER_URL", (value) => {
|
|
61
95
|
value = value || "mock-server";
|
|
62
96
|
if (value === "mock-server") {
|
|
63
|
-
|
|
97
|
+
console.warn("Using mock-server for HASHCHAINSERVER_URL. This is only allowed in development.");
|
|
64
98
|
}
|
|
65
99
|
else if (!URL.parse(value)) {
|
|
66
|
-
|
|
100
|
+
console.warn("HASHCHAINSERVER_URL is not a valid URL. It can either be empty, 'mock-server', or URL but it was: " +
|
|
67
101
|
value);
|
|
68
102
|
}
|
|
69
103
|
if (NODE_ENV !== "development" && value === "mock-server") {
|
|
70
|
-
|
|
104
|
+
console.warn("Using mock-server for HASHCHAINSERVER_URL. This is only allowed in development.");
|
|
71
105
|
}
|
|
72
106
|
return value;
|
|
73
107
|
});
|
|
@@ -78,7 +112,7 @@ export const HASHCHAINSERVER_MAX_ITERATIONS = getEnvVariable("HASHCHAINSERVER_MA
|
|
|
78
112
|
});
|
|
79
113
|
export const HASHCHAINSERVER_APPLICATION_SECRET = getEnvVariable("HASHCHAINSERVER_APPLICATION_SECRET", (value) => {
|
|
80
114
|
if (!value && NODE_ENV !== "development") {
|
|
81
|
-
|
|
115
|
+
console.warn("Missing HASHCHAINSERVER_APPLICATION_SECRET and NODE_ENV != 'development': To use the hashchain server you must pick a random (but stable) HASHCHAINSERVER_APPLICATION_SECRET for secure communciation with it. (If you aren't using the hashchain server, you can ignore this.)");
|
|
82
116
|
}
|
|
83
117
|
return value || "";
|
|
84
118
|
});
|
package/dist/src/db/index.js
CHANGED
|
@@ -50,8 +50,8 @@ export async function withPgPoolTransaction(pool, callback, retryCount = 0, maxR
|
|
|
50
50
|
await pgClient.query("rollback");
|
|
51
51
|
}
|
|
52
52
|
catch (rollbackError) {
|
|
53
|
-
logger.error("Original error
|
|
54
|
-
logger.error("Rollback failed
|
|
53
|
+
logger.error(error, "Original error");
|
|
54
|
+
logger.error(rollbackError, "Rollback failed");
|
|
55
55
|
pgClient.release(true);
|
|
56
56
|
pgClient = null;
|
|
57
57
|
throw error;
|
|
@@ -132,7 +132,7 @@ export async function getTransferCursor(pgClient, { casinoId, }) {
|
|
|
132
132
|
return row?.cursor;
|
|
133
133
|
}
|
|
134
134
|
export async function setTransferCursor(pgClient, { cursor, casinoId, }) {
|
|
135
|
-
|
|
135
|
+
logger.debug(cursor, `[setTransferCursor] Setting cursor`);
|
|
136
136
|
await pgClient.query(`
|
|
137
137
|
insert into hub_hidden.transfer_cursor (casino_id, cursor)
|
|
138
138
|
values ($1, $2)
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Express } from "express";
|
|
2
|
-
import { Logger } from "./logger.js";
|
|
3
2
|
import { type PluginIdentity } from "./server/graphile.config.js";
|
|
4
3
|
declare global {
|
|
5
4
|
namespace Grafast {
|
|
@@ -25,7 +24,6 @@ export type ServerOptions = {
|
|
|
25
24
|
extraPgSchemas?: string[];
|
|
26
25
|
exportSchemaSDLPath?: string;
|
|
27
26
|
userDatabaseMigrationsPath?: string;
|
|
28
|
-
logger?: Logger;
|
|
29
27
|
};
|
|
30
28
|
type ListenInfo = {
|
|
31
29
|
port: number;
|
package/dist/src/index.js
CHANGED
|
@@ -4,13 +4,10 @@ import * as config from "./config.js";
|
|
|
4
4
|
import { createHubServer } from "./server/index.js";
|
|
5
5
|
import { initializeTransferProcessors } from "./process-transfers/index.js";
|
|
6
6
|
import { join } from "path";
|
|
7
|
-
import { logger
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
8
|
export { MakeOutcomeBetPlugin, } from "./plugins/hub-make-outcome-bet.js";
|
|
9
9
|
export { defaultPlugins, } from "./server/graphile.config.js";
|
|
10
10
|
async function initialize(options) {
|
|
11
|
-
if (options.logger) {
|
|
12
|
-
setLogger(options.logger);
|
|
13
|
-
}
|
|
14
11
|
if (options.signal.aborted) {
|
|
15
12
|
logger.info("Initialization aborted by graceful shutdown");
|
|
16
13
|
return;
|
|
@@ -27,9 +24,7 @@ async function initialize(options) {
|
|
|
27
24
|
catch (e) {
|
|
28
25
|
logger.error("Error upgrading core schema", e);
|
|
29
26
|
if (e instanceof DatabaseAheadError) {
|
|
30
|
-
logger.error("⚠️".repeat(
|
|
31
|
-
logger.error("@moneypot/hub database was reset to prepare for a production release and you must reset your database to continue. Please see <https://www.npmjs.com/package/@moneypot/hub#change-log> for more info.");
|
|
32
|
-
logger.error("⚠️".repeat(80));
|
|
27
|
+
logger.error(`${"⚠️".repeat(10)}\n@moneypot/hub database was reset to prepare for a production release and you must reset your database to continue. Please see <https://www.npmjs.com/package/@moneypot/hub#change-log> for more info.`);
|
|
33
28
|
process.exit(1);
|
|
34
29
|
}
|
|
35
30
|
throw e;
|
|
@@ -70,7 +65,6 @@ export async function startAndListen(options) {
|
|
|
70
65
|
let isShuttingDown = false;
|
|
71
66
|
await initialize({
|
|
72
67
|
userDatabaseMigrationsPath: options.userDatabaseMigrationsPath,
|
|
73
|
-
logger: options.logger,
|
|
74
68
|
signal: abortController.signal,
|
|
75
69
|
});
|
|
76
70
|
const hubServer = createHubServer({
|
|
@@ -82,14 +76,14 @@ export async function startAndListen(options) {
|
|
|
82
76
|
});
|
|
83
77
|
const gracefulShutdown = async () => {
|
|
84
78
|
if (isShuttingDown) {
|
|
85
|
-
|
|
79
|
+
logger.warn("Already shutting down.");
|
|
86
80
|
return;
|
|
87
81
|
}
|
|
88
82
|
isShuttingDown = true;
|
|
89
|
-
|
|
83
|
+
logger.info("Shutting down gracefully...");
|
|
90
84
|
abortController.abort();
|
|
91
85
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
92
|
-
|
|
86
|
+
logger.info("Closing resources...");
|
|
93
87
|
hubServer.shutdown();
|
|
94
88
|
try {
|
|
95
89
|
await Promise.race([
|
|
@@ -100,10 +94,10 @@ export async function startAndListen(options) {
|
|
|
100
94
|
]),
|
|
101
95
|
new Promise((_, reject) => setTimeout(() => reject(new Error("Database cleanup timeout")), 3000)),
|
|
102
96
|
]);
|
|
103
|
-
|
|
97
|
+
logger.info("Cleanup complete.");
|
|
104
98
|
}
|
|
105
99
|
catch (err) {
|
|
106
|
-
|
|
100
|
+
logger.warn(err, "Cleanup error (proceeding anyway)");
|
|
107
101
|
}
|
|
108
102
|
process.exit(0);
|
|
109
103
|
};
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
info(...args: any[]): void;
|
|
5
|
-
trace(...args: any[]): void;
|
|
6
|
-
warn(...args: any[]): void;
|
|
7
|
-
}
|
|
8
|
-
export declare let logger: Logger;
|
|
9
|
-
export declare function setLogger(instance: Logger): void;
|
|
1
|
+
import { type Logger } from "pino";
|
|
2
|
+
export { type Logger };
|
|
3
|
+
export declare const logger: Logger;
|
package/dist/src/logger.js
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { pino } from "pino";
|
|
2
|
+
import { LOG_LEVEL, LOG_PRETTY, NODE_ENV } from "./config.js";
|
|
3
|
+
function createLogger(options) {
|
|
4
|
+
const prettify = LOG_PRETTY === undefined ? NODE_ENV === "development" : LOG_PRETTY;
|
|
5
|
+
if (prettify) {
|
|
6
|
+
try {
|
|
7
|
+
return pino({
|
|
8
|
+
level: options.level,
|
|
9
|
+
transport: {
|
|
10
|
+
target: "pino-pretty",
|
|
11
|
+
options: {
|
|
12
|
+
colorize: true,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch (_e) {
|
|
18
|
+
console.warn("LOG_PRETTY=true but pino-pretty is not installed, falling back to standard logging");
|
|
19
|
+
return pino({
|
|
20
|
+
level: options.level,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
4
23
|
}
|
|
5
|
-
|
|
6
|
-
|
|
24
|
+
else {
|
|
25
|
+
return pino({
|
|
26
|
+
level: options.level,
|
|
27
|
+
});
|
|
7
28
|
}
|
|
8
|
-
info(...args) {
|
|
9
|
-
logger.info(...args);
|
|
10
|
-
}
|
|
11
|
-
trace(...args) {
|
|
12
|
-
logger.trace(...args);
|
|
13
|
-
}
|
|
14
|
-
warn(...args) {
|
|
15
|
-
logger.warn(...args);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
export let logger = console;
|
|
19
|
-
export function setLogger(instance) {
|
|
20
|
-
logger = instance;
|
|
21
29
|
}
|
|
30
|
+
export const logger = createLogger({ level: LOG_LEVEL });
|
|
@@ -7,7 +7,10 @@ export const DebugPlugin = {
|
|
|
7
7
|
hooks: {
|
|
8
8
|
processGraphQLRequestBody(info, event) {
|
|
9
9
|
const { body } = event;
|
|
10
|
-
logger.debug(
|
|
10
|
+
logger.debug({
|
|
11
|
+
operationName: body.operationName,
|
|
12
|
+
variableValues: body.variableValues,
|
|
13
|
+
}, "GraphQL request");
|
|
11
14
|
},
|
|
12
15
|
},
|
|
13
16
|
},
|
|
@@ -61,7 +61,7 @@ export const HubAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
|
|
|
61
61
|
Authorization: `apikey:${apiKey}`,
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
logger.info(`[hubAddCasino] Making request to ${graphqlUrl}`);
|
|
65
65
|
const result = await graphqlClient
|
|
66
66
|
.request(GET_CURRENT_CONTROLLER)
|
|
67
67
|
.catch((e) => {
|
|
@@ -84,10 +84,6 @@ export const HubAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
|
|
|
84
84
|
returning id
|
|
85
85
|
`,
|
|
86
86
|
values: [name, baseUrl, graphqlUrl],
|
|
87
|
-
})
|
|
88
|
-
.then((res) => {
|
|
89
|
-
console.log("res", res.rows);
|
|
90
|
-
return res;
|
|
91
87
|
})
|
|
92
88
|
.then(exactlyOneRow);
|
|
93
89
|
}
|
|
@@ -105,7 +101,7 @@ export const HubAddCasinoPlugin = makeExtendSchemaPlugin((build) => {
|
|
|
105
101
|
throw new GraphQLError(`Duplicate constraint violation: ${e.constraint}`);
|
|
106
102
|
}
|
|
107
103
|
}
|
|
108
|
-
logger.error("Error adding casino"
|
|
104
|
+
logger.error(e, "Error adding casino");
|
|
109
105
|
throw e;
|
|
110
106
|
}
|
|
111
107
|
await pgClient.query({
|
|
@@ -99,7 +99,7 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
catch (e) {
|
|
102
|
-
logger.error(`[hubAuthenticate] Error when making GET_USER_FROM_USER_TOKEN to casino
|
|
102
|
+
logger.error(e, `[hubAuthenticate] Error when making GET_USER_FROM_USER_TOKEN to casino`);
|
|
103
103
|
if (isGraphQLError(e)) {
|
|
104
104
|
const errorInfo = extractGraphQLErrorInfo(e);
|
|
105
105
|
if (errorInfo.code === "UNAUTHENTICATED") {
|
|
@@ -143,7 +143,11 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
143
143
|
SET name = EXCLUDED.name
|
|
144
144
|
RETURNING id
|
|
145
145
|
`,
|
|
146
|
-
values: [
|
|
146
|
+
values: [
|
|
147
|
+
casino.id,
|
|
148
|
+
mpExperience.id,
|
|
149
|
+
mpExperience.name,
|
|
150
|
+
],
|
|
147
151
|
})
|
|
148
152
|
.then(exactlyOneRow);
|
|
149
153
|
const dbSession = await pgClient
|
|
@@ -153,7 +157,12 @@ export const HubAuthenticatePlugin = makeExtendSchemaPlugin(() => {
|
|
|
153
157
|
VALUES($1, $2, $3, $4)
|
|
154
158
|
RETURNING id, key
|
|
155
159
|
`,
|
|
156
|
-
values: [
|
|
160
|
+
values: [
|
|
161
|
+
casino.id,
|
|
162
|
+
userId,
|
|
163
|
+
dbExperience.id,
|
|
164
|
+
userToken,
|
|
165
|
+
],
|
|
157
166
|
})
|
|
158
167
|
.then(exactlyOneRow);
|
|
159
168
|
const ret = {
|
|
@@ -172,12 +172,12 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
172
172
|
}
|
|
173
173
|
const minProfit = Math.min(...input.outcomes.map((o) => o.profit));
|
|
174
174
|
const maxPlayerLoss = Math.abs(input.wager * minProfit);
|
|
175
|
-
logger.debug(
|
|
175
|
+
logger.debug({
|
|
176
176
|
wager: input.wager,
|
|
177
177
|
minProfit,
|
|
178
178
|
maxPlayerLoss,
|
|
179
179
|
dbPlayerBalance,
|
|
180
|
-
});
|
|
180
|
+
}, "Determining if player can afford bet");
|
|
181
181
|
if (dbPlayerBalance.amount < maxPlayerLoss) {
|
|
182
182
|
if (minProfit === -1) {
|
|
183
183
|
throw new GraphQLError(`You cannot afford wager`);
|
|
@@ -207,7 +207,7 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
207
207
|
finishHashChainInBackground({
|
|
208
208
|
hashChainId: input.hashChainId,
|
|
209
209
|
}).catch((e) => {
|
|
210
|
-
logger.error(
|
|
210
|
+
logger.error({ hashChainId: input.hashChainId, error: e }, "Error finishing hash chain in background");
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
return {
|
|
@@ -393,18 +393,18 @@ export function MakeOutcomeBetPlugin({ betConfigs }) {
|
|
|
393
393
|
}, "HubMakeOutcomeBetPlugin");
|
|
394
394
|
}
|
|
395
395
|
async function finishHashChainInBackground({ hashChainId, }) {
|
|
396
|
-
logger.debug("Finishing hash chain in background"
|
|
396
|
+
logger.debug({ hashChainId }, "Finishing hash chain in background");
|
|
397
397
|
const preimageHashResult = await getPreimageHash({
|
|
398
398
|
hashChainId,
|
|
399
399
|
});
|
|
400
|
-
logger.debug("Preimage hash result"
|
|
400
|
+
logger.debug({ preimageHashResult }, "Preimage hash result");
|
|
401
401
|
if (preimageHashResult.type === "success") {
|
|
402
|
-
logger.debug(
|
|
402
|
+
logger.debug({
|
|
403
403
|
hashChainId,
|
|
404
404
|
kind: DbHashKind.PREIMAGE,
|
|
405
405
|
digest: preimageHashResult.hash,
|
|
406
406
|
iteration: 0,
|
|
407
|
-
});
|
|
407
|
+
}, "Inserting preimage hash");
|
|
408
408
|
await withPgPoolTransaction(superuserPool, async (pgClient) => {
|
|
409
409
|
await dbInsertHubHash(pgClient, {
|
|
410
410
|
hashChainId,
|
|
@@ -424,9 +424,6 @@ async function finishHashChainInBackground({ hashChainId, }) {
|
|
|
424
424
|
});
|
|
425
425
|
}
|
|
426
426
|
else {
|
|
427
|
-
logger.warn("Failed to insert preimage hash in background"
|
|
428
|
-
hashChainId,
|
|
429
|
-
error: preimageHashResult,
|
|
430
|
-
});
|
|
427
|
+
logger.warn({ hashChainId, error: preimageHashResult }, "Failed to insert preimage hash in background");
|
|
431
428
|
}
|
|
432
429
|
}
|
|
@@ -2,6 +2,7 @@ import { context, lambda } from "postgraphile/grafast";
|
|
|
2
2
|
import { gql, makeExtendSchemaPlugin } from "postgraphile/utils";
|
|
3
3
|
import { jsonParse } from "postgraphile/@dataplan/json";
|
|
4
4
|
import { listenWithFilter } from "./listen-with-filter.js";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
5
6
|
export const HubPutAlertPlugin = makeExtendSchemaPlugin(() => {
|
|
6
7
|
return {
|
|
7
8
|
typeDefs: gql `
|
|
@@ -31,7 +32,7 @@ export const HubPutAlertPlugin = makeExtendSchemaPlugin(() => {
|
|
|
31
32
|
});
|
|
32
33
|
return listenWithFilter($pgSubscriber, $channelKey, jsonParse, $identity, (item, identity) => {
|
|
33
34
|
if (typeof item !== "string") {
|
|
34
|
-
|
|
35
|
+
logger.warn(item, `hubPutAlert: item is not a string`);
|
|
35
36
|
return false;
|
|
36
37
|
}
|
|
37
38
|
if (identity?.kind !== "user") {
|
|
@@ -57,7 +57,7 @@ async function listenForNewCasinos({ signal }) {
|
|
|
57
57
|
id: z.string(),
|
|
58
58
|
});
|
|
59
59
|
pgClient.on("notification", async (msg) => {
|
|
60
|
-
logger.debug(`[listenForNewCasinos] received notification
|
|
60
|
+
logger.debug(msg, `[listenForNewCasinos] received notification`);
|
|
61
61
|
switch (msg.channel) {
|
|
62
62
|
case "hub:new_casino": {
|
|
63
63
|
if (!msg.payload) {
|
|
@@ -69,11 +69,11 @@ async function listenForNewCasinos({ signal }) {
|
|
|
69
69
|
json = JSON.parse(msg.payload);
|
|
70
70
|
}
|
|
71
71
|
catch (error) {
|
|
72
|
-
logger.error("Error parsing new casino notification
|
|
72
|
+
logger.error(error, "Error parsing new casino notification");
|
|
73
73
|
}
|
|
74
74
|
const result = NewCasinoPayload.safeParse(json);
|
|
75
75
|
if (!result.success) {
|
|
76
|
-
logger.error("Error parsing new casino notification
|
|
76
|
+
logger.error(result.error, "Error parsing new casino notification");
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
startCasinoTransferProcessor({ casinoId: result.data.id, signal });
|
|
@@ -154,7 +154,7 @@ export function startPollingProcessor({ casinoId, signal, }) {
|
|
|
154
154
|
}
|
|
155
155
|
catch (e) {
|
|
156
156
|
processorState.backoffTime = Math.min(processorState.backoffTime * 2, MAX_BACKOFF_TIME);
|
|
157
|
-
logger.error(`transfer processor failed
|
|
157
|
+
logger.error(e, `transfer processor failed`);
|
|
158
158
|
logger.debug(`Next retry for casino ${casinoId} in ${processorState.backoffTime}ms`);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
@@ -170,7 +170,7 @@ async function processWithdrawals({ abortSignal, casinoId, graphqlClient, }) {
|
|
|
170
170
|
limit: 10,
|
|
171
171
|
});
|
|
172
172
|
if (withdrawals.length > 0) {
|
|
173
|
-
logger.debug(`[sendWithdrawalLoop] withdrawals
|
|
173
|
+
logger.debug(withdrawals, `[sendWithdrawalLoop] withdrawals`);
|
|
174
174
|
}
|
|
175
175
|
for (const withdrawal of withdrawals) {
|
|
176
176
|
if (abortSignal.aborted) {
|
|
@@ -54,7 +54,7 @@ export async function processTransfer({ casinoId, controllerId, transfer, graphq
|
|
|
54
54
|
assert(transfer, "Expected transfer");
|
|
55
55
|
assert(transfer.__typename === "ExperienceTransfer", `Expected ExperienceTransfer but got ${transfer.__typename}`);
|
|
56
56
|
logger.debug(`processing transfer ${transfer.id} for casino ${casinoId}...`);
|
|
57
|
-
logger.debug(
|
|
57
|
+
logger.debug(transfer, "transfer");
|
|
58
58
|
assert(transfer.experienceByExperienceId, "Expected experienceByExperienceId");
|
|
59
59
|
const isIncoming = controllerId === transfer.toHolderId;
|
|
60
60
|
const user = isIncoming
|
|
@@ -103,10 +103,10 @@ export async function processTransfer({ casinoId, controllerId, transfer, graphq
|
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
catch (e) {
|
|
106
|
-
logger.error(`Error sending claimTransfer(${transfer.id}) to ${casinoId}
|
|
106
|
+
logger.error(e, `Error sending claimTransfer(${transfer.id}) to ${casinoId}:`);
|
|
107
107
|
throw e;
|
|
108
108
|
}
|
|
109
|
-
logger.debug("MP_CLAIM_TRANSFER response
|
|
109
|
+
logger.debug(data, "MP_CLAIM_TRANSFER response");
|
|
110
110
|
if (data.claimTransfer?.result.__typename !== "ClaimTransferSuccess") {
|
|
111
111
|
throw new Error(`Failed to claim transfer: ${JSON.stringify(data.claimTransfer)}`);
|
|
112
112
|
}
|
|
@@ -69,13 +69,13 @@ export function startWebsocketProcessor({ casinoId, graphqlUrl, signal, controll
|
|
|
69
69
|
logger.info(`[websocketProcessor] Disconnected from websocket ${graphqlUrl}`);
|
|
70
70
|
});
|
|
71
71
|
client.on("error", (error) => {
|
|
72
|
-
logger.error(`[websocketProcessor] Error on websocket ${graphqlUrl}
|
|
72
|
+
logger.error(error, `[websocketProcessor] Error on websocket ${graphqlUrl}`);
|
|
73
73
|
});
|
|
74
74
|
const graphqlClient = createGraphqlClient({ graphqlUrl, apiKey });
|
|
75
75
|
const dispose1 = createSubscription(client, MP_NEW_EXPERIENCE_TRANSFER, async (result) => {
|
|
76
76
|
const transferId = result.data?.newExperienceTransfer?.id;
|
|
77
77
|
if (!transferId) {
|
|
78
|
-
logger.warn(`Weird, no transfer id in websocket result
|
|
78
|
+
logger.warn(result, `Weird, no transfer id in websocket result`);
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
const mpTransfer = await mpGetExperienceTransfer(graphqlClient, transferId);
|
|
@@ -94,7 +94,7 @@ export function startWebsocketProcessor({ casinoId, graphqlUrl, signal, controll
|
|
|
94
94
|
const dispose2 = createSubscription(client, MP_NEW_TAKE_REQUEST, async (result) => {
|
|
95
95
|
const mpTakeRequestId = result.data?.newTakeRequest?.id;
|
|
96
96
|
if (!mpTakeRequestId) {
|
|
97
|
-
logger.warn(`Weird, no take request id in websocket result
|
|
97
|
+
logger.warn(result, `Weird, no take request id in websocket result`);
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
100
|
const mpTakeRequest = await mpGetTakeRequest(graphqlClient, mpTakeRequestId);
|
|
@@ -118,11 +118,11 @@ function createSubscription(client, query, handler) {
|
|
|
118
118
|
return client.subscribe({ query: print(query) }, {
|
|
119
119
|
next: (result) => {
|
|
120
120
|
handler(result).catch((e) => {
|
|
121
|
-
logger.error(`Error while handling websocket result
|
|
121
|
+
logger.error(e, `Error while handling websocket result`);
|
|
122
122
|
});
|
|
123
123
|
},
|
|
124
124
|
error: (err) => {
|
|
125
|
-
logger.error(`Error during WebSocket subscription
|
|
125
|
+
logger.error(err, `Error during WebSocket subscription`);
|
|
126
126
|
},
|
|
127
127
|
complete: () => logger.info("Subscription closed"),
|
|
128
128
|
});
|
|
@@ -64,7 +64,7 @@ export function createPreset({ plugins, exportSchemaSDLPath, extraPgSchemas, abo
|
|
|
64
64
|
mutablePlugins.unshift(requiredPlugin);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
logger.info(
|
|
67
|
+
logger.info(`Will save generated graphql schema to ${exportSchemaSDLPath}`);
|
|
68
68
|
const preset = {
|
|
69
69
|
extends: [PostGraphileAmberPreset],
|
|
70
70
|
disablePlugins: ["NodePlugin"],
|
|
@@ -233,7 +233,7 @@ export async function processSingleTakeRequest({ mpTakeRequestId, mpTakeRequest,
|
|
|
233
233
|
graphqlClient,
|
|
234
234
|
});
|
|
235
235
|
}
|
|
236
|
-
|
|
236
|
+
logger.info(`[processSingleTakeRequest] Take request ${mpTakeRequestId} not found in MP or our DB for casino ${casinoId}`);
|
|
237
237
|
return null;
|
|
238
238
|
});
|
|
239
239
|
}
|
|
@@ -319,7 +319,7 @@ async function processExistingTakeRequest({ pgClient, takeRequest, casinoId, gra
|
|
|
319
319
|
assert(pgClient._inTransaction, "pgClient must be in a transaction");
|
|
320
320
|
switch (takeRequest.status) {
|
|
321
321
|
case LocalTakeRequestStatus.PENDING:
|
|
322
|
-
|
|
322
|
+
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} in PENDING state`);
|
|
323
323
|
break;
|
|
324
324
|
case LocalTakeRequestStatus.PROCESSING: {
|
|
325
325
|
const { dbUser, dbExperience, dbCurrency } = await loadRequiredEntities(pgClient, {
|
|
@@ -345,16 +345,16 @@ async function processExistingTakeRequest({ pgClient, takeRequest, casinoId, gra
|
|
|
345
345
|
});
|
|
346
346
|
}
|
|
347
347
|
case LocalTakeRequestStatus.COMPLETED:
|
|
348
|
-
|
|
348
|
+
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} already COMPLETED`);
|
|
349
349
|
break;
|
|
350
350
|
case LocalTakeRequestStatus.FAILED:
|
|
351
|
-
|
|
351
|
+
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} in FAILED state`);
|
|
352
352
|
break;
|
|
353
353
|
case LocalTakeRequestStatus.REJECTED:
|
|
354
|
-
|
|
354
|
+
logger.info(`[processExistingTakeRequest] Take request ${takeRequest.id} already REJECTED`);
|
|
355
355
|
break;
|
|
356
356
|
default:
|
|
357
|
-
|
|
357
|
+
logger.error(`[processExistingTakeRequest] Unknown status: ${takeRequest.status}`);
|
|
358
358
|
break;
|
|
359
359
|
}
|
|
360
360
|
return null;
|
|
@@ -422,7 +422,7 @@ async function attemptTransfer({ pgClient, takeRequestId, mpTakeRequestId, mpExp
|
|
|
422
422
|
return transferId;
|
|
423
423
|
}
|
|
424
424
|
catch (error) {
|
|
425
|
-
|
|
425
|
+
logger.error(error, `[attemptTransfer] Error`);
|
|
426
426
|
await pgClient.query({
|
|
427
427
|
text: `
|
|
428
428
|
UPDATE hub.take_request
|
|
@@ -521,7 +521,7 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
521
521
|
MpTakeRequestStatus.Transferred,
|
|
522
522
|
],
|
|
523
523
|
});
|
|
524
|
-
|
|
524
|
+
logger.info(`[completeTransfer] Successfully completed transfer ${mpTransferId}`);
|
|
525
525
|
break;
|
|
526
526
|
case "InvalidTransferStatus": {
|
|
527
527
|
const currentStatus = completionResult.currentStatus;
|
|
@@ -543,7 +543,7 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
543
543
|
MpTakeRequestStatus.Transferred,
|
|
544
544
|
],
|
|
545
545
|
});
|
|
546
|
-
|
|
546
|
+
logger.info(`[completeTransfer] Transfer ${mpTransferId} was already completed`);
|
|
547
547
|
}
|
|
548
548
|
else if (currentStatus === "CANCELED" ||
|
|
549
549
|
currentStatus === "EXPIRED") {
|
|
@@ -572,15 +572,15 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
572
572
|
`MP transfer was ${currentStatus}`,
|
|
573
573
|
],
|
|
574
574
|
});
|
|
575
|
-
|
|
575
|
+
logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}`);
|
|
576
576
|
}
|
|
577
577
|
else {
|
|
578
|
-
|
|
578
|
+
logger.info(`[completeTransfer] Transfer ${mpTransferId} has status ${currentStatus}, will retry later`);
|
|
579
579
|
}
|
|
580
580
|
break;
|
|
581
581
|
}
|
|
582
582
|
case "InsufficientBalance": {
|
|
583
|
-
|
|
583
|
+
logger.info(`[completeTransfer] Insufficient balance to complete transfer ${mpTransferId}, will retry later`);
|
|
584
584
|
await pgClient.query({
|
|
585
585
|
text: `
|
|
586
586
|
UPDATE hub.take_request
|
|
@@ -592,7 +592,7 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
592
592
|
break;
|
|
593
593
|
}
|
|
594
594
|
case undefined: {
|
|
595
|
-
|
|
595
|
+
logger.error(`[completeTransfer] Unexpected completion result of undefined for transfer ${mpTransferId}`);
|
|
596
596
|
await pgClient.query({
|
|
597
597
|
text: `
|
|
598
598
|
UPDATE hub.take_request
|
|
@@ -610,7 +610,7 @@ async function completeTransfer({ mpTakeRequestId, takeRequestId, mpTransferId,
|
|
|
610
610
|
}
|
|
611
611
|
}
|
|
612
612
|
catch (e) {
|
|
613
|
-
|
|
613
|
+
logger.error(e, `[completeTransfer] Error completing transfer ${mpTransferId}`);
|
|
614
614
|
if (e instanceof Error) {
|
|
615
615
|
if (isNetworkError(e)) {
|
|
616
616
|
await pgClient.query({
|
|
@@ -682,7 +682,7 @@ async function loadRequiredEntities(pgClient, params) {
|
|
|
682
682
|
})
|
|
683
683
|
.then(maybeOneRow);
|
|
684
684
|
if (!dbCurrency) {
|
|
685
|
-
|
|
685
|
+
logger.warn(`[loadRequiredEntities] Currency ${currencyKey} not found`);
|
|
686
686
|
return {
|
|
687
687
|
dbCurrency: null,
|
|
688
688
|
dbUser: null,
|
|
@@ -716,7 +716,7 @@ async function loadRequiredEntities(pgClient, params) {
|
|
|
716
716
|
.then(maybeOneRow);
|
|
717
717
|
}
|
|
718
718
|
if (!dbUser) {
|
|
719
|
-
|
|
719
|
+
logger.warn(`[loadRequiredEntities] User not found`);
|
|
720
720
|
return { dbCurrency, dbUser: null, dbExperience: null, dbBalance: null };
|
|
721
721
|
}
|
|
722
722
|
let dbExperience;
|
|
@@ -745,7 +745,7 @@ async function loadRequiredEntities(pgClient, params) {
|
|
|
745
745
|
.then(maybeOneRow);
|
|
746
746
|
}
|
|
747
747
|
if (!dbExperience) {
|
|
748
|
-
|
|
748
|
+
logger.warn(`[loadRequiredEntities] Experience not found`);
|
|
749
749
|
return { dbCurrency, dbUser, dbExperience: null, dbBalance: null };
|
|
750
750
|
}
|
|
751
751
|
let dbBalance = null;
|
|
@@ -771,7 +771,7 @@ async function loadRequiredEntities(pgClient, params) {
|
|
|
771
771
|
async function rejectMpTakeRequest(pgClient, graphqlClient, mpTakeRequestId, takeRequestId) {
|
|
772
772
|
assert(pgClient._inTransaction, "pgClient must be in a transaction");
|
|
773
773
|
try {
|
|
774
|
-
|
|
774
|
+
logger.info(`[rejectMpTakeRequest] Rejecting take request ${mpTakeRequestId}`);
|
|
775
775
|
const rejectResult = await graphqlClient.request(MP_REJECT_TAKE_REQUEST, {
|
|
776
776
|
mpTakeRequestId,
|
|
777
777
|
});
|
|
@@ -841,7 +841,7 @@ async function rejectMpTakeRequest(pgClient, graphqlClient, mpTakeRequestId, tak
|
|
|
841
841
|
return success;
|
|
842
842
|
}
|
|
843
843
|
catch (error) {
|
|
844
|
-
|
|
844
|
+
logger.error(error, `[rejectMpTakeRequest] Error`);
|
|
845
845
|
return false;
|
|
846
846
|
}
|
|
847
847
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moneypot/hub",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0-dev.2",
|
|
4
4
|
"author": "moneypot.com",
|
|
5
5
|
"homepage": "https://moneypot.com/hub",
|
|
6
6
|
"keywords": [
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"jose": "^6.0.11",
|
|
57
57
|
"pg": "^8.12.0",
|
|
58
58
|
"pg-connection-string": "^2.6.4",
|
|
59
|
+
"pino": "^9.7.0",
|
|
59
60
|
"postgraphile": "^5.0.0-beta.42",
|
|
60
61
|
"tsafe": "^1.6.6",
|
|
61
62
|
"yup": "^1.6.1",
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
"@types/supertest": "^6.0.2",
|
|
73
74
|
"eslint": "^9.8.0",
|
|
74
75
|
"globals": "^16.0.0",
|
|
76
|
+
"pino-pretty": "^13.0.0",
|
|
75
77
|
"supertest": "^7.0.0",
|
|
76
78
|
"tsx": "^4.20.3",
|
|
77
79
|
"typescript": "^5.4.5",
|