Skip to content

Commit 67cb972

Browse files
committed
reviewer suggestions implemented
1 parent 232c5fc commit 67cb972

File tree

3 files changed

+29
-54
lines changed

3 files changed

+29
-54
lines changed

src/handlers/egress-tracker.js

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,13 @@ import { Accounting } from '../services/accounting.js'
1515
*
1616
* @type {Middleware<EgressTrackerContext, EgressTrackerContext, Environment>}
1717
*/
18-
export function withEgressHandler (handler) {
18+
export function withEgressHandler(handler) {
1919
return async (req, env, ctx) => {
2020
if (env.FF_EGRESS_TRACKER_ENABLED !== 'true') {
2121
return handler(req, env, ctx)
2222
}
2323

24-
let response
25-
try {
26-
response = await handler(req, env, ctx)
27-
} catch (error) {
28-
console.error('Error in egress tracker handler:', error)
29-
throw error
30-
}
31-
24+
const response = await handler(req, env, ctx)
3225
if (!response.ok || !response.body) {
3326
return response
3427
}
@@ -38,17 +31,18 @@ export function withEgressHandler (handler) {
3831
serviceURL: env.ACCOUNTING_SERVICE_URL
3932
})
4033

41-
const { readable, writable } = createEgressPassThroughStream(ctx, accounting, dataCid)
42-
43-
try {
44-
ctx.waitUntil(response.body.pipeTo(writable))
45-
} catch (error) {
46-
console.error('Error in egress tracker handler:', error)
47-
// Original response in case of an error to avoid breaking the chain and serve the content
48-
return response
49-
}
34+
const responseBody = response.body.pipeThrough(
35+
createByteCountStream((totalBytesServed) => {
36+
// Non-blocking call to the accounting service to record egress
37+
if (totalBytesServed > 0) {
38+
ctx.waitUntil(
39+
accounting.record(dataCid, totalBytesServed, new Date().toISOString())
40+
);
41+
}
42+
})
43+
);
5044

51-
return new Response(readable, {
45+
return new Response(responseBody, {
5246
status: response.status,
5347
statusText: response.statusText,
5448
headers: response.headers
@@ -60,58 +54,39 @@ export function withEgressHandler (handler) {
6054
* Creates a TransformStream to count bytes served to the client.
6155
* It records egress when the stream is finalized without an error.
6256
*
63-
* @param {import('@web3-storage/gateway-lib/middleware').Context} ctx - The context object.
64-
* @param {AccountingService} accounting - The accounting service instance to record egress.
65-
* @param {import('@web3-storage/gateway-lib/handlers').CID} dataCid - The CID of the served content.
66-
* @returns {TransformStream} - The created TransformStream.
57+
* @param {(totalBytesServed: number) => void} onClose
58+
* @template {Uint8Array} T
59+
* @returns {TransformStream<T, T>} - The created TransformStream.
6760
*/
68-
function createEgressPassThroughStream (ctx, accounting, dataCid) {
61+
function createByteCountStream(onClose) {
6962
let totalBytesServed = 0
7063

7164
return new TransformStream({
72-
/**
73-
* The start function is called when the stream is being initialized.
74-
* It resets the total bytes served to 0.
75-
*/
76-
start () {
77-
totalBytesServed = 0
78-
},
7965
/**
8066
* The transform function is called for each chunk of the response body.
8167
* It enqueues the chunk and updates the total bytes served.
8268
* If an error occurs, it signals an error to the controller and logs it.
8369
* The bytes are not counted in case of enqueuing an error.
84-
* @param {Uint8Array} chunk
85-
* @param {TransformStreamDefaultController} controller
8670
*/
87-
async transform (chunk, controller) {
71+
async transform(chunk, controller) {
8872
try {
8973
controller.enqueue(chunk)
9074
totalBytesServed += chunk.byteLength
9175
} catch (error) {
92-
console.error('Error while counting egress bytes:', error)
76+
console.error('Error while counting bytes:', error)
9377
controller.error(error)
9478
}
9579
},
9680

9781
/**
9882
* The flush function is called when the stream is being finalized,
9983
* which is when the response is being sent to the client.
100-
* So before the response is sent, we record the egress.
101-
* It is called only once and it triggers a non-blocking call to the accounting service.
84+
* So before the response is sent, we record the egress using the callback.
10285
* If an error occurs, the egress is not recorded.
103-
* NOTE: The flush function is NOT called in case of an stream error.
86+
* NOTE: The flush function is NOT called in case of a stream error.
10487
*/
105-
async flush (controller) {
106-
try {
107-
// Non-blocking call to the accounting service to record egress
108-
if (totalBytesServed > 0) {
109-
ctx.waitUntil(accounting.record(dataCid, totalBytesServed, new Date().toISOString()))
110-
}
111-
} catch (error) {
112-
console.error('Error while recording egress:', error)
113-
controller.error(error)
114-
}
88+
async flush() {
89+
onClose(totalBytesServed)
11590
}
11691
})
11792
}

test/fixtures/worker-fixture.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const __dirname = path.dirname(__filename)
1212
*/
1313
const wranglerEnv = process.env.WRANGLER_ENV || 'integration'
1414

15-
const DEBUG = process.env.DEBUG === 'true' || false
15+
const DEBUG = process.env.DEBUG === 'true'
1616

1717
/**
1818
* Worker information object

test/unit/middlewares/egress-tracker.spec.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ const env =
3535
})
3636

3737
const accountingRecordMethodStub = sinon.stub()
38-
// @ts-expect-error
39-
.returns(async (cid, bytes, servedAt) => {
40-
console.log(`[mock] record called with cid: ${cid}, bytes: ${bytes}, servedAt: ${servedAt}`)
41-
return Promise.resolve()
42-
})
38+
.returns(
39+
/** @type {import('../../../src/bindings.js').AccountingService['record']} */
40+
async (cid, bytes, servedAt) => {
41+
console.log(`[mock] record called with cid: ${cid}, bytes: ${bytes}, servedAt: ${servedAt}`)
42+
})
4343

4444
/**
4545
* Mock implementation of the AccountingService.

0 commit comments

Comments
 (0)