Skip to content

Commit

Permalink
feat: make dispatcher truly global (nodejs#1405)
Browse files Browse the repository at this point in the history
* Make the dispatcher truly global

* make sure the global dispatcher is used for Node.js fetch

* Fix test

* added version number
  • Loading branch information
mcollina authored and crysmags committed Feb 27, 2024
1 parent 3f06552 commit ca33e25
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .husky/pre-commit
Expand Up @@ -2,4 +2,4 @@
. "$(dirname "$0")/_/husky.sh"

npm run lint
npm run test
npm run test
8 changes: 3 additions & 5 deletions index-fetch.js
@@ -1,12 +1,10 @@
'use strict'

const Agent = require('./lib/agent')

const globalDispatcher = new Agent()

const { getGlobalDispatcher } = require('./lib/global')
const fetchImpl = require('./lib/fetch')

module.exports.fetch = async function fetch (resource) {
return fetchImpl.apply(globalDispatcher, arguments)
return fetchImpl.apply(getGlobalDispatcher(), arguments)
}
module.exports.FormData = require('./lib/fetch/formdata').FormData
module.exports.Headers = require('./lib/fetch/headers').Headers
Expand Down
14 changes: 1 addition & 13 deletions index.js
Expand Up @@ -15,6 +15,7 @@ const MockAgent = require('./lib/mock/mock-agent')
const MockPool = require('./lib/mock/mock-pool')
const mockErrors = require('./lib/mock/mock-errors')
const ProxyAgent = require('./lib/proxy-agent')
const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')

const nodeVersion = process.versions.node.split('.')
const nodeMajor = Number(nodeVersion[0])
Expand All @@ -32,19 +33,6 @@ module.exports.ProxyAgent = ProxyAgent
module.exports.buildConnector = buildConnector
module.exports.errors = errors

let globalDispatcher = new Agent()

function setGlobalDispatcher (agent) {
if (!agent || typeof agent.dispatch !== 'function') {
throw new InvalidArgumentError('Argument agent must implement Agent')
}
globalDispatcher = agent
}

function getGlobalDispatcher () {
return globalDispatcher
}

function makeDispatcher (fn) {
return (url, opts, handler) => {
if (typeof opts === 'function') {
Expand Down
32 changes: 32 additions & 0 deletions lib/global.js
@@ -0,0 +1,32 @@
'use strict'

// We include a version number for the Dispatcher API. In case of breaking changes,
// this version number must be increased to avoid conflicts.
const globalDispatcher = Symbol.for('undici.globalDispatcher.1')
const { InvalidArgumentError } = require('./core/errors')
const Agent = require('./agent')

if (getGlobalDispatcher() === undefined) {
setGlobalDispatcher(new Agent())
}

function setGlobalDispatcher (agent) {
if (!agent || typeof agent.dispatch !== 'function') {
throw new InvalidArgumentError('Argument agent must implement Agent')
}
Object.defineProperty(globalThis, globalDispatcher, {
value: agent,
writable: true,
enumerable: false,
configurable: false
})
}

function getGlobalDispatcher () {
return globalThis[globalDispatcher]
}

module.exports = {
setGlobalDispatcher,
getGlobalDispatcher
}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -79,6 +79,7 @@
"formdata-node": "^4.3.1",
"https-pem": "^2.0.0",
"husky": "^7.0.2",
"import-fresh": "^3.3.0",
"jest": "^28.0.1",
"jsfuzz": "^1.0.15",
"mocha": "^10.0.0",
Expand Down
39 changes: 10 additions & 29 deletions test/agent.js
Expand Up @@ -10,8 +10,10 @@ const {
request,
stream,
pipeline,
setGlobalDispatcher
setGlobalDispatcher,
getGlobalDispatcher
} = require('../')
const importFresh = require('import-fresh')

test('setGlobalDispatcher', t => {
t.plan(2)
Expand Down Expand Up @@ -645,34 +647,6 @@ test('drain', t => {
})
})

// Port 80 is no accessible on CI.
// test('agent works with port 80', t => {
// t.plan(1)

// const server = http.createServer((req, res) => {
// res.setHeader('Content-Type', 'text/plain')
// res.end()
// })

// t.teardown(server.close.bind(server))

// server.listen(80, async () => {
// const dispatcher = new Agent()

// const origin = `http://localhost:${server.address().port}`

// try {
// const { body } = await dispatcher.request({ origin, method: 'GET', path: '/' })

// body.on('end', () => {
// t.pass()
// }).resume()
// } catch (err) {
// t.error(err)
// }
// })
// })

test('global api', t => {
t.plan(6 * 2)

Expand Down Expand Up @@ -724,3 +698,10 @@ test('connect is not valid', t => {

t.throws(() => new Agent({ connect: false }), errors.InvalidArgumentError, 'connect must be a function or an object')
})

test('the dispatcher is truly global', t => {
const agent = getGlobalDispatcher()
const undiciFresh = importFresh('../index.js')
t.equal(agent, undiciFresh.getGlobalDispatcher())
t.end()
})

0 comments on commit ca33e25

Please sign in to comment.