-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
connect.js
91 lines (83 loc) · 2.3 KB
/
connect.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import createDebug from 'debug'
import {connect as connectTls} from 'node:tls'
import {
DEFAULT_PORT,
ALPN_ID,
MIN_TLS_VERSION,
} from './lib/util.js'
const debug = createDebug('gemini:connect')
const connectToGeminiServer = (opt, cb) => {
if (typeof opt === 'function') {
cb = opt
opt = {}
}
debug('connectToGeminiServer', opt)
const {
hostname,
port,
cert, key, passphrase,
connectTimeout,
tlsOpt,
} = {
hostname: '127.0.0.1',
port: DEFAULT_PORT,
cert: null, key: null, passphrase: null,
// todo [breaking]: reduce to e.g. 20s
connectTimeout: 60 * 1000, // 60s
tlsOpt: {},
...opt,
}
const socket = connectTls({
ALPNProtocols: [ALPN_ID],
minVersion: MIN_TLS_VERSION,
host: hostname,
servername: hostname,
port,
cert, key, passphrase,
...tlsOpt,
})
// Sets the socket to timeout after timeout milliseconds of inactivity on
// the socket. By default net.Socket do not have a timeout.
// When an idle timeout is triggered the socket will receive a 'timeout'
// event but the connection will not be severed. The user must manually
// call socket.end() or socket.destroy() to end the connection.
// https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay
let timeoutTimer = null
const onTimeout = () => {
clearTimeout(timeoutTimer)
const err = new Error('connect timeout')
err.timeout = connectTimeout
err.code = 'ETIMEDOUT' // is it okay to mimic syscall errors?
err.errno = -60
socket.destroy(err)
}
socket.once('timeout', onTimeout)
if (connectTimeout !== null) {
// This sets the timeout for inactivity on the *socket* layer. But the
// TLS handshake might also stall. This is why we also set one manually.
// see also https://github.com/nodejs/node/issues/5757
socket.setTimeout(connectTimeout)
timeoutTimer = setTimeout(onTimeout, connectTimeout)
timeoutTimer.unref()
}
let cbCalled = false
socket.once('error', (err) => {
debug('socket error', err)
if (cbCalled) return;
cbCalled = true
cb(err)
})
socket.once('secureConnect', () => {
if (cbCalled) return;
// If timeout is 0, then the existing idle timeout is disabled.
// https://nodejs.org/api/net.html#net_socket_setnodelay_nodelay
socket.setTimeout(0)
clearTimeout(timeoutTimer)
cbCalled = true
cb(null, socket)
})
return socket
}
export {
connectToGeminiServer,
}