|
/* eslint-disable no-console */ |
|
// @ts-check |
|
import http from 'node:http' |
|
import { createVerifiedFetch } from '@helia/verified-fetch' |
|
import { dnsJsonOverHttps } from '@multiformats/dns/resolvers' |
|
import { contentTypeParser } from './dist-tsc/src/lib/content-type-parser.js' |
|
|
|
const fetch = await createVerifiedFetch({ |
|
gateways: ['http://127.0.0.1:8081'], |
|
routers: ['http://127.0.0.1:8081'], |
|
dnsResolvers: { |
|
'.': dnsJsonOverHttps('https://delegated-ipfs.dev/dns-query') |
|
} |
|
}, { |
|
contentTypeParser |
|
}) |
|
|
|
/** |
|
* |
|
* @param {http.IncomingMessage} req |
|
* @param {*} reqId |
|
*/ |
|
const addLoggingToRequest = (req, reqId) => { |
|
req.on('close', () => { |
|
log(`request${reqId}`, 'closed') |
|
// console.log(`request${reqId} closed`) |
|
}) |
|
// don't listen to data event |
|
// req.on('data', (chunk) => { |
|
// console.log(`request${reqId} data: `, chunk) |
|
// }) |
|
req.on('end', () => { |
|
log(`request${reqId}`, ' ended') |
|
}) |
|
req.on('error', (err) => { |
|
log(`request${reqId}`, ' error: `, er', err) |
|
}) |
|
req.on('pause', () => { |
|
log(`request${reqId}`, ' paused') |
|
}) |
|
req.on('readable', () => { |
|
log(`request${reqId}`, ' readable') |
|
}) |
|
req.on('resume', () => { |
|
log(`request${reqId}`, ' resumed') |
|
}) |
|
} |
|
/** |
|
* |
|
* @param {http.ServerResponse<http.IncomingMessage>} res |
|
* @param {number} reqId |
|
*/ |
|
const addLoggingToResponse = (res, reqId) => { |
|
res.on('pause', () => { |
|
log(`response${reqId}`, ' paused') |
|
}) |
|
res.on('resume', () => { |
|
log(`response${reqId}`, ' resumed') |
|
}) |
|
res.on('close', () => { |
|
log(`response${reqId}`, ' closed') |
|
}) |
|
res.on('aborted', () => { |
|
log(`response${reqId}`, ' aborted') |
|
}) |
|
res.on('error', (err) => { |
|
log(`response${reqId}`, ' error', err) |
|
}) |
|
res.on('finish', () => { |
|
log(`response${reqId}`, ' finished') |
|
}) |
|
res.on('end', () => { |
|
log(`response${reqId}`, ' ended') |
|
}) |
|
res.on('unpipe', () => { |
|
log(`response${reqId}`, ' unpipe') |
|
}) |
|
res.on('pipe', () => { |
|
log(`response${reqId}`, ' pipe') |
|
}) |
|
} |
|
|
|
const log = (id, ...args) => { |
|
console.log(`${id} ${new Date().toISOString().substring(11, 23)}`, ...args) |
|
} |
|
let lastReqId = 0 |
|
|
|
function logHeaders (reqId, headers) { |
|
console.group(`headers${reqId}: `) |
|
if (headers != null) { |
|
for (const [name, value] of Object.entries(headers)) { |
|
console.log(`${name}: ${value}`) |
|
} |
|
} |
|
console.groupEnd() |
|
} |
|
const server = http.createServer(function (req, res) { |
|
const reqId = lastReqId++ |
|
console.group(`server: request received ${reqId}`) |
|
log(`server${reqId}`, req.url) |
|
log(`server${reqId}`, req.method) |
|
logHeaders(reqId, req.headers) |
|
|
|
console.groupEnd() |
|
addLoggingToRequest(req, reqId) |
|
addLoggingToResponse(res, reqId) |
|
const vFetchUrl = 'https://bafybeid2sc4k5ynx5yo7wg23fzw2ni4xxuxi7kdq5q3lyurkvglh5wrwmi.ipfs.sw.sgtpooki.com' |
|
log(`server${reqId}`, 'vFetchUrl', vFetchUrl) |
|
|
|
const vFetchReqHeaders = new Headers() |
|
for (const [name, value] of Object.entries(req.headersDistinct)) { |
|
if (value == null) { |
|
continue |
|
} |
|
vFetchReqHeaders.set(name, value.join(', ')) |
|
} |
|
|
|
const abortController = new AbortController() |
|
// if the request stops, cancel the fetch |
|
req.on('aborted', () => { |
|
log(`server${reqId}`, 'req aborted') |
|
abortController.abort() |
|
}) |
|
req.on('close', () => { |
|
log(`server${reqId}`, 'req closed') |
|
abortController.abort() |
|
}) |
|
const fetchResp = fetch(vFetchUrl, { |
|
signal: abortController.signal, |
|
headers: vFetchReqHeaders, |
|
method: req.method |
|
}) |
|
|
|
respondWithVfetch({ req, res, fetchResp, reqId }) |
|
}) |
|
|
|
/** |
|
* Respond to a request with a response from `@helia/verified-fetch` |
|
* |
|
* @param {object} param0 |
|
* @param {http.IncomingMessage} param0.req |
|
* @param {Promise<Response>} param0.fetchResp |
|
* @param {number} param0.reqId |
|
* @param {http.ServerResponse<http.IncomingMessage>} param0.res |
|
*/ |
|
async function respondWithVfetch ({ req, res, fetchResp, reqId }) { |
|
console.group(`respondWithVfetch${reqId}`) |
|
log(`respondWithVfetch${reqId}`, 'start') |
|
let fetchRespValue |
|
try { |
|
fetchRespValue = await fetchResp |
|
} catch (e) { |
|
log(`server${reqId}`, 'fetchRespValue error', e) |
|
res.writeHead(500, {}) |
|
res.end(e) |
|
} |
|
if (fetchRespValue == null) { |
|
log(`server${reqId}`, 'fetchRespValue is null') |
|
res.writeHead(500, {}) |
|
res.end('fetchRespValue is null') |
|
return |
|
} |
|
log(`respondWithVfetch${reqId}`, 'got fetchRespValue') |
|
|
|
logHeaders(reqId, fetchRespValue.headers) |
|
if (!fetchRespValue.ok) { |
|
log(`server${reqId}`, 'fetchRespValue not ok') |
|
res.writeHead(fetchRespValue.status, {}) |
|
res.write(fetchRespValue.statusText) |
|
res.write(await fetchRespValue.text()) |
|
res.end() |
|
return |
|
} |
|
/** |
|
* @type {import('node:http').OutgoingHttpHeaders} |
|
*/ |
|
const headers = {} |
|
for (const [name, value] of fetchRespValue.headers) { |
|
headers[name] = value |
|
} |
|
res.writeHead(fetchRespValue.status, headers) |
|
log(`respondWithVfetch${reqId}`, 'wrote headers', fetchRespValue.status, headers) |
|
const body = await fetchRespValue.arrayBuffer() |
|
// now convert arrayBuffer to nodejs Buffer |
|
const nodeBuffer = Buffer.from(body) |
|
res.end(nodeBuffer) |
|
console.groupEnd() |
|
} |
|
|
|
server.listen(8889).on('listening', () => { |
|
console.log('Server is listening on port 8889') |
|
}) |