Skip to content

Commit bbd66d0

Browse files
authored
chore: use Promise.withResolvers in SOCKS5 proxy agent (#4978)
* chore: use Promise.withResolvers for async helpers - Replace manual promise wrappers across API and dispatcher paths - Keep error and timeout handling intact while simplifying control flow Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> * chore: re-introduce 'new Promise(...)' with 1-2 LoC in body * chore: re-introduce 'new Promise(...)' with single proimse in block --------- Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
1 parent 6a30f74 commit bbd66d0

1 file changed

Lines changed: 68 additions & 62 deletions

File tree

lib/dispatcher/socks5-proxy-agent.js

Lines changed: 68 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,28 @@ class Socks5ProxyAgent extends DispatcherBase {
7979
debug('creating SOCKS5 connection to', proxyHost, proxyPort)
8080

8181
// Connect to the SOCKS5 proxy
82-
const socket = await new Promise((resolve, reject) => {
83-
const onConnect = () => {
84-
socket.removeListener('error', onError)
85-
resolve(socket)
86-
}
82+
const socketReady = Promise.withResolvers()
8783

88-
const onError = (err) => {
89-
socket.removeListener('connect', onConnect)
90-
reject(err)
91-
}
84+
const onSocketConnect = () => {
85+
socket.removeListener('error', onSocketError)
86+
socketReady.resolve(socket)
87+
}
9288

93-
const socket = net.connect({
94-
host: proxyHost,
95-
port: proxyPort
96-
})
89+
const onSocketError = (err) => {
90+
socket.removeListener('connect', onSocketConnect)
91+
socketReady.reject(err)
92+
}
9793

98-
socket.once('connect', onConnect)
99-
socket.once('error', onError)
94+
const socket = net.connect({
95+
host: proxyHost,
96+
port: proxyPort
10097
})
10198

99+
socket.once('connect', onSocketConnect)
100+
socket.once('error', onSocketError)
101+
102+
await socketReady.promise
103+
102104
// Create SOCKS5 client
103105
const socks5Client = new Socks5Client(socket, this[kProxyAuth])
104106

@@ -112,58 +114,62 @@ class Socks5ProxyAgent extends DispatcherBase {
112114
await socks5Client.handshake()
113115

114116
// Wait for authentication (if required)
115-
await new Promise((resolve, reject) => {
116-
const timeout = setTimeout(() => {
117-
reject(new Error('SOCKS5 authentication timeout'))
118-
}, 5000)
119-
120-
const onAuthenticated = () => {
121-
clearTimeout(timeout)
122-
socks5Client.removeListener('error', onError)
123-
resolve()
124-
}
117+
const authenticationReady = Promise.withResolvers()
125118

126-
const onError = (err) => {
127-
clearTimeout(timeout)
128-
socks5Client.removeListener('authenticated', onAuthenticated)
129-
reject(err)
130-
}
119+
const authenticationTimeout = setTimeout(() => {
120+
authenticationReady.reject(new Error('SOCKS5 authentication timeout'))
121+
}, 5000)
131122

132-
// Check if already authenticated (for NO_AUTH method)
133-
if (socks5Client.state === 'authenticated') {
134-
clearTimeout(timeout)
135-
resolve()
136-
} else {
137-
socks5Client.once('authenticated', onAuthenticated)
138-
socks5Client.once('error', onError)
139-
}
140-
})
123+
const onAuthenticated = () => {
124+
clearTimeout(authenticationTimeout)
125+
socks5Client.removeListener('error', onAuthenticationError)
126+
authenticationReady.resolve()
127+
}
128+
129+
const onAuthenticationError = (err) => {
130+
clearTimeout(authenticationTimeout)
131+
socks5Client.removeListener('authenticated', onAuthenticated)
132+
authenticationReady.reject(err)
133+
}
134+
135+
// Check if already authenticated (for NO_AUTH method)
136+
if (socks5Client.state === 'authenticated') {
137+
clearTimeout(authenticationTimeout)
138+
authenticationReady.resolve()
139+
} else {
140+
socks5Client.once('authenticated', onAuthenticated)
141+
socks5Client.once('error', onAuthenticationError)
142+
}
143+
144+
await authenticationReady.promise
141145

142146
// Send CONNECT command
143147
await socks5Client.connect(targetHost, targetPort)
144148

145149
// Wait for connection
146-
await new Promise((resolve, reject) => {
147-
const timeout = setTimeout(() => {
148-
reject(new Error('SOCKS5 connection timeout'))
149-
}, 5000)
150-
151-
const onConnected = (info) => {
152-
debug('SOCKS5 tunnel established to', targetHost, targetPort, 'via', info)
153-
clearTimeout(timeout)
154-
socks5Client.removeListener('error', onError)
155-
resolve()
156-
}
150+
const connectionReady = Promise.withResolvers()
157151

158-
const onError = (err) => {
159-
clearTimeout(timeout)
160-
socks5Client.removeListener('connected', onConnected)
161-
reject(err)
162-
}
152+
const connectionTimeout = setTimeout(() => {
153+
connectionReady.reject(new Error('SOCKS5 connection timeout'))
154+
}, 5000)
163155

164-
socks5Client.once('connected', onConnected)
165-
socks5Client.once('error', onError)
166-
})
156+
const onConnected = (info) => {
157+
debug('SOCKS5 tunnel established to', targetHost, targetPort, 'via', info)
158+
clearTimeout(connectionTimeout)
159+
socks5Client.removeListener('error', onConnectionError)
160+
connectionReady.resolve()
161+
}
162+
163+
const onConnectionError = (err) => {
164+
clearTimeout(connectionTimeout)
165+
socks5Client.removeListener('connected', onConnected)
166+
connectionReady.reject(err)
167+
}
168+
169+
socks5Client.once('connected', onConnected)
170+
socks5Client.once('error', onConnectionError)
171+
172+
await connectionReady.promise
167173

168174
return socket
169175
}
@@ -206,10 +212,10 @@ class Socks5ProxyAgent extends DispatcherBase {
206212
...connectOpts.tls || {}
207213
})
208214

209-
await new Promise((resolve, reject) => {
210-
finalSocket.once('secureConnect', resolve)
211-
finalSocket.once('error', reject)
212-
})
215+
const tlsReady = Promise.withResolvers()
216+
finalSocket.once('secureConnect', tlsReady.resolve)
217+
finalSocket.once('error', tlsReady.reject)
218+
await tlsReady.promise
213219
}
214220

215221
callback(null, finalSocket)

0 commit comments

Comments
 (0)