velocious 1.0.516 → 1.0.518
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/README.md +2 -0
- package/build/background-jobs/job.js +27 -2
- package/build/background-jobs/store.js +356 -39
- package/build/background-jobs/types.js +6 -0
- package/build/configuration-types.js +12 -1
- package/build/configuration.js +2 -1
- package/build/database/drivers/base.js +26 -0
- package/build/database/drivers/mssql/index.js +13 -0
- package/build/database/drivers/mysql/index.js +18 -0
- package/build/database/drivers/pgsql/index.js +12 -0
- package/build/database/drivers/sqlite/connection-sql-js.js +11 -0
- package/build/database/drivers/sqlite/index.js +14 -4
- package/build/database/drivers/sqlite/index.native.js +13 -0
- package/build/database/drivers/sqlite/index.web.js +11 -1
- package/build/database/drivers/sqlite/query.js +1 -2
- package/build/http-server/client/request-buffer/index.js +151 -89
- package/build/src/background-jobs/job.d.ts +15 -0
- package/build/src/background-jobs/job.d.ts.map +1 -1
- package/build/src/background-jobs/job.js +24 -3
- package/build/src/background-jobs/store.d.ts +111 -9
- package/build/src/background-jobs/store.d.ts.map +1 -1
- package/build/src/background-jobs/store.js +339 -40
- package/build/src/background-jobs/types.d.ts +30 -0
- package/build/src/background-jobs/types.d.ts.map +1 -1
- package/build/src/background-jobs/types.js +7 -1
- package/build/src/configuration-types.d.ts +29 -2
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +13 -2
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +3 -2
- package/build/src/database/drivers/base.d.ts +13 -0
- package/build/src/database/drivers/base.d.ts.map +1 -1
- package/build/src/database/drivers/base.js +25 -1
- package/build/src/database/drivers/mssql/index.d.ts.map +1 -1
- package/build/src/database/drivers/mssql/index.js +13 -1
- package/build/src/database/drivers/mysql/index.d.ts.map +1 -1
- package/build/src/database/drivers/mysql/index.js +21 -1
- package/build/src/database/drivers/pgsql/index.d.ts.map +1 -1
- package/build/src/database/drivers/pgsql/index.js +14 -1
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts +6 -0
- package/build/src/database/drivers/sqlite/connection-sql-js.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/connection-sql-js.js +11 -1
- package/build/src/database/drivers/sqlite/index.d.ts +2 -2
- package/build/src/database/drivers/sqlite/index.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.js +15 -5
- package/build/src/database/drivers/sqlite/index.native.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.native.js +14 -1
- package/build/src/database/drivers/sqlite/index.web.d.ts +2 -1
- package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/index.web.js +11 -2
- package/build/src/database/drivers/sqlite/query.d.ts +2 -2
- package/build/src/database/drivers/sqlite/query.d.ts.map +1 -1
- package/build/src/database/drivers/sqlite/query.js +2 -3
- package/build/src/http-server/client/request-buffer/index.d.ts +23 -2
- package/build/src/http-server/client/request-buffer/index.d.ts.map +1 -1
- package/build/src/http-server/client/request-buffer/index.js +141 -86
- package/package.json +2 -2
- package/src/background-jobs/job.js +27 -2
- package/src/background-jobs/store.js +356 -39
- package/src/background-jobs/types.js +6 -0
- package/src/configuration-types.js +12 -1
- package/src/configuration.js +2 -1
- package/src/database/drivers/base.js +26 -0
- package/src/database/drivers/mssql/index.js +13 -0
- package/src/database/drivers/mysql/index.js +18 -0
- package/src/database/drivers/pgsql/index.js +12 -0
- package/src/database/drivers/sqlite/connection-sql-js.js +11 -0
- package/src/database/drivers/sqlite/index.js +14 -4
- package/src/database/drivers/sqlite/index.native.js +13 -0
- package/src/database/drivers/sqlite/index.web.js +11 -1
- package/src/database/drivers/sqlite/query.js +1 -2
- package/src/http-server/client/request-buffer/index.js +151 -89
|
@@ -161,7 +161,18 @@
|
|
|
161
161
|
* long-running jobs and for using more cores. Default: `4`.
|
|
162
162
|
* @property {number} [maxConcurrentForkedJobs] - How many out-of-process
|
|
163
163
|
* `"forked"` or `"spawned"` jobs a single `background-jobs-worker` is
|
|
164
|
-
* allowed to keep in flight. Default: `4`.
|
|
164
|
+
* allowed to keep in flight. Default: `4`. This is a per-worker safety cap;
|
|
165
|
+
* for workload-shaped limits use per-queue caps (`queues`) instead, which are
|
|
166
|
+
* enforced cluster-wide and are immune to duplicate worker processes.
|
|
167
|
+
* @property {Record<string, {maxConcurrent?: number}>} [queues] - Per-queue
|
|
168
|
+
* concurrency caps, Sidekiq-style. A job declares its queue (static `queue` on
|
|
169
|
+
* the job class, or the `queue` enqueue option; defaults to `"default"`), and
|
|
170
|
+
* `queues[name].maxConcurrent` bounds how many jobs from that queue may be
|
|
171
|
+
* in flight across the whole cluster (enforced via durable per-key
|
|
172
|
+
* concurrency, so it holds regardless of how many worker processes run).
|
|
173
|
+
* Size each queue to its workload: I/O-bound queues (e.g. build runners
|
|
174
|
+
* waiting on remote Docker servers) can run far above the core count, while
|
|
175
|
+
* CPU-bound queues should stay near it. Default: `{}` (no queue caps).
|
|
165
176
|
* @property {BackgroundJobsDispatchStrategy} [dispatchStrategy] - How the main process
|
|
166
177
|
* detects new work. Defaults to `"beacon"` (event-driven). Set to `"polling"`
|
|
167
178
|
* to restore the legacy fixed-interval poll.
|
package/build/configuration.js
CHANGED
|
@@ -1291,8 +1291,9 @@ export default class VelociousConfiguration {
|
|
|
1291
1291
|
const pollIntervalMs = typeof configured.pollIntervalMs === "number" && configured.pollIntervalMs >= 1
|
|
1292
1292
|
? configured.pollIntervalMs
|
|
1293
1293
|
: (typeof envPollInterval === "number" && Number.isFinite(envPollInterval) && envPollInterval >= 1 ? envPollInterval : 1000)
|
|
1294
|
+
const queues = configured.queues && typeof configured.queues === "object" ? configured.queues : {}
|
|
1294
1295
|
|
|
1295
|
-
return {host, port, databaseIdentifier, maxConcurrentForkedJobs, maxConcurrentInlineJobs, dispatchStrategy, pollIntervalMs}
|
|
1296
|
+
return {host, port, databaseIdentifier, maxConcurrentForkedJobs, maxConcurrentInlineJobs, dispatchStrategy, pollIntervalMs, queues}
|
|
1296
1297
|
}
|
|
1297
1298
|
|
|
1298
1299
|
/**
|
|
@@ -1050,6 +1050,22 @@ export default class VelociousDatabaseDriversBase {
|
|
|
1050
1050
|
throw new Error("'query' unexpected came here")
|
|
1051
1051
|
}
|
|
1052
1052
|
|
|
1053
|
+
/**
|
|
1054
|
+
* Executes a mutation and returns the number of rows changed by that statement.
|
|
1055
|
+
* @param {string} sql - Mutation SQL string.
|
|
1056
|
+
* @returns {Promise<number>} - Affected row count.
|
|
1057
|
+
*/
|
|
1058
|
+
async affectedRows(sql) {
|
|
1059
|
+
this._assertWritableQuery(sql)
|
|
1060
|
+
await this.beforeQuery(sql, {})
|
|
1061
|
+
|
|
1062
|
+
try {
|
|
1063
|
+
return await this._affectedRowsActual(sql)
|
|
1064
|
+
} finally {
|
|
1065
|
+
await this.afterQuery(sql, {})
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1053
1069
|
/**
|
|
1054
1070
|
* Runs query actual with logging.
|
|
1055
1071
|
* @param {object} args - Options object.
|
|
@@ -1308,6 +1324,16 @@ export default class VelociousDatabaseDriversBase {
|
|
|
1308
1324
|
throw new Error(`queryActual not implemented`)
|
|
1309
1325
|
}
|
|
1310
1326
|
|
|
1327
|
+
/**
|
|
1328
|
+
* Executes a mutation and returns its affected row count.
|
|
1329
|
+
* @abstract
|
|
1330
|
+
* @param {string} sql - Mutation SQL string.
|
|
1331
|
+
* @returns {Promise<number>} - Affected row count.
|
|
1332
|
+
*/
|
|
1333
|
+
_affectedRowsActual(sql) { // eslint-disable-line no-unused-vars
|
|
1334
|
+
throw new Error(`affectedRowsActual not implemented`)
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1311
1337
|
/**
|
|
1312
1338
|
* Runs query to sql.
|
|
1313
1339
|
* @abstract
|
|
@@ -328,6 +328,19 @@ export default class VelociousDatabaseDriversMssql extends Base{
|
|
|
328
328
|
return Array.isArray(result.recordsets) ? result.recordsets[0] || [] : []
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Executes a mutation with affected-row metadata.
|
|
333
|
+
* @param {string} sql - Mutation SQL.
|
|
334
|
+
* @returns {Promise<number>} - Affected row count.
|
|
335
|
+
*/
|
|
336
|
+
async _affectedRowsActual(sql) {
|
|
337
|
+
const request = this._currentTransaction
|
|
338
|
+
? new mssql.Request(this._currentTransaction)
|
|
339
|
+
: new mssql.Request(this.connection)
|
|
340
|
+
const result = await request.query(sql)
|
|
341
|
+
return result.rowsAffected.reduce((total, count) => total + count, 0)
|
|
342
|
+
}
|
|
343
|
+
|
|
331
344
|
/**
|
|
332
345
|
* Runs query to sql.
|
|
333
346
|
* @param {import("../../query/index.js").default} query - Query instance.
|
|
@@ -344,6 +344,24 @@ export default class VelociousDatabaseDriversMysql extends Base{
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Executes a mutation with affected-row metadata.
|
|
349
|
+
* @param {string} sql - Mutation SQL.
|
|
350
|
+
* @returns {Promise<number>} - Affected row count.
|
|
351
|
+
*/
|
|
352
|
+
async _affectedRowsActual(sql) {
|
|
353
|
+
if (!this.pool) await this.connect()
|
|
354
|
+
if (!this.pool) throw new Error("MySQL pool failed to initialize")
|
|
355
|
+
const pool = this.pool
|
|
356
|
+
|
|
357
|
+
return await new Promise((resolve, reject) => {
|
|
358
|
+
pool.query(sql, (error, result) => {
|
|
359
|
+
if (error) reject(error)
|
|
360
|
+
else resolve("affectedRows" in result ? result.affectedRows : 0)
|
|
361
|
+
})
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
347
365
|
/**
|
|
348
366
|
* Runs query to sql.
|
|
349
367
|
* @param {import("../../query/index.js").default} query - Query instance.
|
|
@@ -227,6 +227,18 @@ export default class VelociousDatabaseDriversPgsql extends Base{
|
|
|
227
227
|
return response.rows
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Executes a mutation with affected-row metadata.
|
|
232
|
+
* @param {string} sql - Mutation SQL.
|
|
233
|
+
* @returns {Promise<number>} - Affected row count.
|
|
234
|
+
*/
|
|
235
|
+
async _affectedRowsActual(sql) {
|
|
236
|
+
if (!this.connection) await this.connect()
|
|
237
|
+
if (!this.connection) throw new Error("PostgreSQL connection failed to initialize")
|
|
238
|
+
const response = await this.connection.query(sql)
|
|
239
|
+
return response.rowCount || 0
|
|
240
|
+
}
|
|
241
|
+
|
|
230
242
|
/**
|
|
231
243
|
* Runs query to sql.
|
|
232
244
|
* @param {import("../../query/index.js").default} query - Query instance.
|
|
@@ -47,6 +47,17 @@ export default class VelociousDatabaseDriversSqliteConnectionSqlJs {
|
|
|
47
47
|
return result
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Executes a mutation with affected-row metadata.
|
|
52
|
+
* @param {string} sql - Mutation SQL.
|
|
53
|
+
* @returns {Promise<number>} - Affected row count.
|
|
54
|
+
*/
|
|
55
|
+
async affectedRows(sql) {
|
|
56
|
+
await this.query(sql)
|
|
57
|
+
const connection = /** @type {import("sql.js").Database & {getRowsModified: () => number}} */ (this.connection)
|
|
58
|
+
return connection.getRowsModified()
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
saveDatabase = async () => {
|
|
51
62
|
const databaseContent = this.connection.export()
|
|
52
63
|
|
|
@@ -15,7 +15,7 @@ import fileExists from "../../../utils/file-exists.js"
|
|
|
15
15
|
export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
16
16
|
/**
|
|
17
17
|
* Connection.
|
|
18
|
-
* @type {import("
|
|
18
|
+
* @type {import("sqlite").Database | undefined} */
|
|
19
19
|
connection = undefined
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -39,11 +39,10 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
|
39
39
|
this._advisoryLockDirectory = path.join(databaseDir, `${this.localStorageName()}.velocious-advisory-locks`)
|
|
40
40
|
|
|
41
41
|
try {
|
|
42
|
-
|
|
43
|
-
this.connection = /** @type {import("sqlite3").Database} */ (await open({
|
|
42
|
+
this.connection = await open({
|
|
44
43
|
filename: databasePath,
|
|
45
44
|
driver: sqlite3.Database
|
|
46
|
-
})
|
|
45
|
+
})
|
|
47
46
|
} catch (error) {
|
|
48
47
|
if (error instanceof Error) {
|
|
49
48
|
throw new Error(`Couldn't open database ${databasePath} because of ${error.constructor.name}: ${error.message}`, {cause: error})
|
|
@@ -79,6 +78,17 @@ export default class VelociousDatabaseDriversSqliteNode extends Base {
|
|
|
79
78
|
return await query(this.connection, sql)
|
|
80
79
|
}
|
|
81
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Executes a mutation with affected-row metadata.
|
|
83
|
+
* @param {string} sql - Mutation SQL.
|
|
84
|
+
* @returns {Promise<number>} - Affected row count.
|
|
85
|
+
*/
|
|
86
|
+
async _affectedRowsActual(sql) {
|
|
87
|
+
if (!this.connection) throw new Error("No connection")
|
|
88
|
+
const result = await this.connection.run(sql)
|
|
89
|
+
return result.changes || 0
|
|
90
|
+
}
|
|
91
|
+
|
|
82
92
|
/**
|
|
83
93
|
* Layers a filesystem lock directory on top of the in-process waiter
|
|
84
94
|
* queue so SQLite deployments with multiple Node processes writing to
|
|
@@ -81,4 +81,17 @@ export default class VelociousDatabaseDriversSqliteNative extends Base {
|
|
|
81
81
|
return query(this.connection, sql)
|
|
82
82
|
})
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Executes a mutation with affected-row metadata.
|
|
87
|
+
* @param {string} sql - Mutation SQL.
|
|
88
|
+
* @returns {Promise<number>} - Affected row count.
|
|
89
|
+
*/
|
|
90
|
+
async _affectedRowsActual(sql) {
|
|
91
|
+
return await this._queryMutex.sync(async () => {
|
|
92
|
+
if (!this.connection) throw new Error("Not connected yet")
|
|
93
|
+
const result = await this.connection.runAsync(sql)
|
|
94
|
+
return result.changes
|
|
95
|
+
})
|
|
96
|
+
}
|
|
84
97
|
}
|
|
@@ -8,7 +8,7 @@ import Base from "./base.js"
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* VelociousDatabaseDriversSqliteWeb class.
|
|
11
|
-
* @typedef {{query: (sql: string) => Promise<Record<string, ?>[]>, close: () => Promise<void>}} SqliteWebConnection
|
|
11
|
+
* @typedef {{query: (sql: string) => Promise<Record<string, ?>[]>, affectedRows: (sql: string) => Promise<number>, close: () => Promise<void>}} SqliteWebConnection
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
@@ -110,4 +110,14 @@ export default class VelociousDatabaseDriversSqliteWeb extends Base {
|
|
|
110
110
|
|
|
111
111
|
return result
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Executes a mutation with affected-row metadata.
|
|
116
|
+
* @param {string} sql - Mutation SQL.
|
|
117
|
+
* @returns {Promise<number>} - Affected row count.
|
|
118
|
+
*/
|
|
119
|
+
async _affectedRowsActual(sql) {
|
|
120
|
+
const connection = this.getConnection()
|
|
121
|
+
return await connection.affectedRows(sql)
|
|
122
|
+
}
|
|
113
123
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Runs query.
|
|
5
|
-
* @param {import("
|
|
5
|
+
* @param {import("sqlite").Database} connection - Connection.
|
|
6
6
|
* @param {string} sql - SQL string.
|
|
7
7
|
* @returns {Promise<Record<string, ?>[]>} - Resolves with string value.
|
|
8
8
|
*/
|
|
@@ -13,7 +13,6 @@ export default async function query(connection, sql) {
|
|
|
13
13
|
* @type {Record<string, ?>[]} */
|
|
14
14
|
let result
|
|
15
15
|
|
|
16
|
-
// @ts-expect-error
|
|
17
16
|
result = await connection.all(sql)
|
|
18
17
|
|
|
19
18
|
return result
|
|
@@ -67,11 +67,9 @@ export default class RequestBuffer {
|
|
|
67
67
|
* @returns {Buffer | undefined} - Remaining data, if any.
|
|
68
68
|
*/
|
|
69
69
|
feed(data) {
|
|
70
|
-
|
|
71
|
-
const char = data[index]
|
|
72
|
-
|
|
73
|
-
if (this.readingBody) this.bodyLength += 1
|
|
70
|
+
let index = 0
|
|
74
71
|
|
|
72
|
+
while (index < data.length) {
|
|
75
73
|
switch(this.state) {
|
|
76
74
|
case "status":
|
|
77
75
|
case "headers":
|
|
@@ -79,101 +77,169 @@ export default class RequestBuffer {
|
|
|
79
77
|
case "multi-part-form-data-header":
|
|
80
78
|
case "chunked-size":
|
|
81
79
|
case "chunked-trailer":
|
|
82
|
-
this.data
|
|
80
|
+
index = this.feedLine(data, index)
|
|
81
|
+
break
|
|
82
|
+
case "post-body":
|
|
83
|
+
index = this.feedPostBody(data, index)
|
|
84
|
+
break
|
|
85
|
+
default:
|
|
86
|
+
index = this.feedByte(data, index)
|
|
87
|
+
}
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
if (this.completed) {
|
|
90
|
+
return data.subarray(index)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
94
|
+
return undefined
|
|
95
|
+
}
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Consumes bytes for the line-based states up to and including the next newline.
|
|
99
|
+
* @param {Buffer} data - Data payload.
|
|
100
|
+
* @param {number} index - Read position.
|
|
101
|
+
* @returns {number} - New read position.
|
|
102
|
+
*/
|
|
103
|
+
feedLine(data, index) {
|
|
104
|
+
const newlineIndex = data.indexOf(10, index)
|
|
94
105
|
|
|
95
|
-
|
|
96
|
-
|
|
106
|
+
if (newlineIndex === -1) {
|
|
107
|
+
if (this.readingBody) this.bodyLength += data.length - index
|
|
97
108
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @type {number} */
|
|
102
|
-
const currentChunkBytesRead = (this.currentChunkBytesRead || 0) + 1
|
|
109
|
+
for (let dataIndex = index; dataIndex < data.length; dataIndex += 1) {
|
|
110
|
+
this.data.push(data[dataIndex])
|
|
111
|
+
}
|
|
103
112
|
|
|
104
|
-
|
|
113
|
+
return data.length
|
|
114
|
+
}
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
this.currentChunkCrlfRead = 0
|
|
108
|
-
this.setState("chunked-data-crlf")
|
|
109
|
-
}
|
|
116
|
+
if (this.readingBody) this.bodyLength += newlineIndex + 1 - index
|
|
110
117
|
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
case "chunked-data-crlf":
|
|
114
|
-
this.currentChunkCrlfRead = (this.currentChunkCrlfRead || 0) + 1
|
|
118
|
+
let line
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
if (this.data.length == 0) {
|
|
121
|
+
line = data.toString("latin1", index, newlineIndex + 1)
|
|
122
|
+
} else {
|
|
123
|
+
// The rest of a line that started in a previous chunk.
|
|
124
|
+
for (let dataIndex = index; dataIndex <= newlineIndex; dataIndex += 1) {
|
|
125
|
+
this.data.push(data[dataIndex])
|
|
126
|
+
}
|
|
120
127
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (!this.boundaryLineEnd) throw new Error("Boundary line end not initialized")
|
|
125
|
-
if (!this.boundaryLineNext) throw new Error("Boundary line next not initialized")
|
|
126
|
-
|
|
127
|
-
const body = this.formDataPart.body // eslint-disable-line no-case-declarations
|
|
128
|
-
|
|
129
|
-
body.push(char)
|
|
130
|
-
|
|
131
|
-
const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length // eslint-disable-line no-case-declarations
|
|
132
|
-
const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length) // eslint-disable-line no-case-declarations
|
|
133
|
-
const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars) // eslint-disable-line no-case-declarations
|
|
134
|
-
|
|
135
|
-
const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length // eslint-disable-line no-case-declarations
|
|
136
|
-
const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length) // eslint-disable-line no-case-declarations
|
|
137
|
-
const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars) // eslint-disable-line no-case-declarations
|
|
138
|
-
|
|
139
|
-
if (possibleBoundaryEnd == this.boundaryLineEnd) {
|
|
140
|
-
this.formDataPart.removeFromBody(possibleBoundaryEnd)
|
|
141
|
-
this.formDataPartDone()
|
|
142
|
-
this.completeRequest()
|
|
143
|
-
} else if (possibleBoundaryNext == this.boundaryLineNext) {
|
|
144
|
-
this.formDataPart.removeFromBody(possibleBoundaryNext)
|
|
145
|
-
this.formDataPartDone()
|
|
146
|
-
this.newFormDataPart()
|
|
147
|
-
} else if (this.contentLength && this.bodyLength >= this.contentLength) {
|
|
148
|
-
this.formDataPartDone()
|
|
149
|
-
this.completeRequest()
|
|
150
|
-
} else if (this.formDataPart.contentLength && this.bodyLength >= this.formDataPart.contentLength) {
|
|
151
|
-
this.formDataPartDone()
|
|
152
|
-
|
|
153
|
-
throw new Error("stub")
|
|
154
|
-
}
|
|
128
|
+
line = String.fromCharCode.apply(null, this.data)
|
|
129
|
+
this.data = []
|
|
130
|
+
}
|
|
155
131
|
|
|
156
|
-
|
|
157
|
-
case "post-body":
|
|
158
|
-
if (!this.postBodyChars) throw new Error("postBodyChars not initialized")
|
|
132
|
+
this.parse(line)
|
|
159
133
|
|
|
160
|
-
|
|
134
|
+
return newlineIndex + 1
|
|
135
|
+
}
|
|
161
136
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Consumes fixed-length request body bytes in bulk.
|
|
139
|
+
* @param {Buffer} data - Data payload.
|
|
140
|
+
* @param {number} index - Read position.
|
|
141
|
+
* @returns {number} - New read position.
|
|
142
|
+
*/
|
|
143
|
+
feedPostBody(data, index) {
|
|
144
|
+
if (!this.postBodyBuffers) throw new Error("postBodyBuffers not initialized")
|
|
145
|
+
if (this.contentLength === undefined) throw new Error("Content length not set")
|
|
165
146
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
147
|
+
const remainingBodyBytes = Math.max(1, this.contentLength - this.bodyLength)
|
|
148
|
+
const endIndex = Math.min(data.length, index + remainingBodyBytes)
|
|
149
|
+
|
|
150
|
+
this.postBodyBuffers.push(data.subarray(index, endIndex))
|
|
151
|
+
this.bodyLength += endIndex - index
|
|
152
|
+
|
|
153
|
+
if (this.contentLength && this.bodyLength >= this.contentLength) {
|
|
154
|
+
this.postRequestDone()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return endIndex
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Consumes a single byte for the byte-based parser states.
|
|
162
|
+
* @param {Buffer} data - Data payload.
|
|
163
|
+
* @param {number} index - Read position.
|
|
164
|
+
* @returns {number} - New read position.
|
|
165
|
+
*/
|
|
166
|
+
feedByte(data, index) {
|
|
167
|
+
const char = data[index]
|
|
168
|
+
|
|
169
|
+
if (this.readingBody) this.bodyLength += 1
|
|
170
|
+
|
|
171
|
+
switch(this.state) {
|
|
172
|
+
case "chunked-data": {
|
|
173
|
+
const chunkedBodyChars = this.chunkedBodyChars
|
|
174
|
+
|
|
175
|
+
if (this.currentChunkSize === undefined) throw new Error("Chunk size not initialized")
|
|
176
|
+
if (!chunkedBodyChars) throw new Error("Chunked body not initialized")
|
|
177
|
+
|
|
178
|
+
chunkedBodyChars.push(char)
|
|
179
|
+
/**
|
|
180
|
+
* Current chunk bytes read.
|
|
181
|
+
* @type {number} */
|
|
182
|
+
const currentChunkBytesRead = (this.currentChunkBytesRead || 0) + 1
|
|
183
|
+
|
|
184
|
+
this.currentChunkBytesRead = currentChunkBytesRead
|
|
185
|
+
|
|
186
|
+
if (currentChunkBytesRead >= this.currentChunkSize) {
|
|
187
|
+
this.currentChunkCrlfRead = 0
|
|
188
|
+
this.setState("chunked-data-crlf")
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
break
|
|
169
192
|
}
|
|
193
|
+
case "chunked-data-crlf":
|
|
194
|
+
this.currentChunkCrlfRead = (this.currentChunkCrlfRead || 0) + 1
|
|
170
195
|
|
|
171
|
-
|
|
172
|
-
|
|
196
|
+
if (this.currentChunkCrlfRead >= 2) {
|
|
197
|
+
this.currentChunkBytesRead = 0
|
|
198
|
+
this.setState("chunked-size")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
break
|
|
202
|
+
case "multi-part-form-data-body": {
|
|
203
|
+
if (!this.formDataPart) throw new Error("FormData part not initialized")
|
|
204
|
+
if (!this.boundaryLineEnd) throw new Error("Boundary line end not initialized")
|
|
205
|
+
if (!this.boundaryLineNext) throw new Error("Boundary line next not initialized")
|
|
206
|
+
|
|
207
|
+
const body = this.formDataPart.body
|
|
208
|
+
|
|
209
|
+
body.push(char)
|
|
210
|
+
|
|
211
|
+
const possibleBoundaryEndPosition = body.length - this.boundaryLineEnd.length
|
|
212
|
+
const possibleBoundaryEndChars = body.slice(possibleBoundaryEndPosition, body.length)
|
|
213
|
+
const possibleBoundaryEnd = String.fromCharCode.apply(null, possibleBoundaryEndChars)
|
|
214
|
+
|
|
215
|
+
const possibleBoundaryNextPosition = body.length - this.boundaryLineNext.length
|
|
216
|
+
const possibleBoundaryNextChars = body.slice(possibleBoundaryNextPosition, body.length)
|
|
217
|
+
const possibleBoundaryNext = String.fromCharCode.apply(null, possibleBoundaryNextChars)
|
|
218
|
+
|
|
219
|
+
if (possibleBoundaryEnd == this.boundaryLineEnd) {
|
|
220
|
+
this.formDataPart.removeFromBody(possibleBoundaryEnd)
|
|
221
|
+
this.formDataPartDone()
|
|
222
|
+
this.completeRequest()
|
|
223
|
+
} else if (possibleBoundaryNext == this.boundaryLineNext) {
|
|
224
|
+
this.formDataPart.removeFromBody(possibleBoundaryNext)
|
|
225
|
+
this.formDataPartDone()
|
|
226
|
+
this.newFormDataPart()
|
|
227
|
+
} else if (this.contentLength && this.bodyLength >= this.contentLength) {
|
|
228
|
+
this.formDataPartDone()
|
|
229
|
+
this.completeRequest()
|
|
230
|
+
} else if (this.formDataPart.contentLength && this.bodyLength >= this.formDataPart.contentLength) {
|
|
231
|
+
this.formDataPartDone()
|
|
232
|
+
|
|
233
|
+
throw new Error("stub")
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
break
|
|
173
237
|
}
|
|
238
|
+
default:
|
|
239
|
+
this.logger.error(() => [`Unknown state for request buffer`, {state: this.state}])
|
|
174
240
|
}
|
|
175
241
|
|
|
176
|
-
return
|
|
242
|
+
return index + 1
|
|
177
243
|
}
|
|
178
244
|
|
|
179
245
|
/**
|
|
@@ -347,11 +413,8 @@ export default class RequestBuffer {
|
|
|
347
413
|
} else {
|
|
348
414
|
/**
|
|
349
415
|
* Narrows the runtime value to the documented type.
|
|
350
|
-
* @type {
|
|
351
|
-
this.
|
|
352
|
-
|
|
353
|
-
// this.postBodyBuffer = new ArrayBuffer(this.contentLength)
|
|
354
|
-
// this.postBodyChars = new Uint8Array(this.postBodyBuffer)
|
|
416
|
+
* @type {Buffer[]} */
|
|
417
|
+
this.postBodyBuffers = []
|
|
355
418
|
|
|
356
419
|
this.setState("post-body")
|
|
357
420
|
}
|
|
@@ -379,12 +442,11 @@ export default class RequestBuffer {
|
|
|
379
442
|
}
|
|
380
443
|
|
|
381
444
|
postRequestDone() {
|
|
382
|
-
if (this.
|
|
383
|
-
this.postBody = Buffer.
|
|
445
|
+
if (this.postBodyBuffers) {
|
|
446
|
+
this.postBody = Buffer.concat(this.postBodyBuffers).toString("utf8")
|
|
384
447
|
}
|
|
385
448
|
|
|
386
|
-
delete this.
|
|
387
|
-
// delete this.postBodyBuffer
|
|
449
|
+
delete this.postBodyBuffers
|
|
388
450
|
|
|
389
451
|
this.completeRequest()
|
|
390
452
|
}
|
|
@@ -9,11 +9,26 @@
|
|
|
9
9
|
* @template {Array<?>} [TArgs=[]]
|
|
10
10
|
*/
|
|
11
11
|
export default class VelociousJob<TArgs extends Array<unknown> = []> {
|
|
12
|
+
/**
|
|
13
|
+
* Queue this job class runs on. Subclasses set e.g. `static queue = "builds"`
|
|
14
|
+
* to route onto a queue with its own cluster-wide concurrency cap (configured
|
|
15
|
+
* via `backgroundJobs.queues`). The `{queue}` enqueue option overrides it.
|
|
16
|
+
* Left undefined, jobs run on the `"default"` queue.
|
|
17
|
+
* @type {string | undefined}
|
|
18
|
+
*/
|
|
19
|
+
static queue: string | undefined;
|
|
12
20
|
/**
|
|
13
21
|
* Runs job name.
|
|
14
22
|
* @returns {string} - Job name.
|
|
15
23
|
*/
|
|
16
24
|
static jobName(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Folds this job class's static `queue` into the enqueue options unless the
|
|
27
|
+
* caller already specified one.
|
|
28
|
+
* @param {import("./types.js").BackgroundJobOptions | undefined} options - Job options.
|
|
29
|
+
* @returns {import("./types.js").BackgroundJobOptions} - Options including the resolved queue.
|
|
30
|
+
*/
|
|
31
|
+
static _withQueue(options: import("./types.js").BackgroundJobOptions | undefined): import("./types.js").BackgroundJobOptions;
|
|
17
32
|
/**
|
|
18
33
|
* Runs perform later.
|
|
19
34
|
* @param {...?} args - Job args.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,kCAFyB,KAAK,SAAhB,KAAK,CAAC,OAAC,CAAE;IAGrB;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,6BAHc,OAAC,EAAA,GACF,OAAO,CAAC,MAAM,CAAC,CAW3B;IAED;;;;;;OAMG;IACH,kDAJG;QAAuB,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CAU3B;IAED;;;;OAIG;IACH,kCAHW,KAAK,CAAC,OAAC,CAAC,GACN;QAAC,OAAO,EAAE,KAAK,CAAC,OAAC,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,YAAY,EAAE,oBAAoB,CAAA;KAAC,CAgBtF;IAED;;;;OAIG;IACH,kBAHW,KAAK,GACH,OAAO,CAAC,IAAI,CAAC,CAIzB;CACF"}
|
|
1
|
+
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/job.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,kCAFyB,KAAK,SAAhB,KAAK,CAAC,OAAC,CAAE;IAGrB;;;;;;OAMG;IACH,cAFU,MAAM,GAAG,SAAS,CAEJ;IAExB;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;;OAKG;IACH,2BAHW,OAAO,YAAY,EAAE,oBAAoB,GAAG,SAAS,GACnD,OAAO,YAAY,EAAE,oBAAoB,CAUrD;IAED;;;;OAIG;IACH,6BAHc,OAAC,EAAA,GACF,OAAO,CAAC,MAAM,CAAC,CAW3B;IAED;;;;;;OAMG;IACH,kDAJG;QAAuB,IAAI,EAAnB,KAAK,CAAC,OAAC,CAAC;QACyC,OAAO;KAChE,GAAU,OAAO,CAAC,MAAM,CAAC,CAU3B;IAED;;;;OAIG;IACH,kCAHW,KAAK,CAAC,OAAC,CAAC,GACN;QAAC,OAAO,EAAE,KAAK,CAAC,OAAC,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,YAAY,EAAE,oBAAoB,CAAA;KAAC,CAgBtF;IAED;;;;OAIG;IACH,kBAHW,KAAK,GACH,OAAO,CAAC,IAAI,CAAC,CAIzB;CACF"}
|