source: node_modules/pg-cloudflare/src/index.ts@ 2d1ec46

main
Last change on this file since 2d1ec46 was 62b2964, checked in by Klimentina Efremova <klimentina08642@…>, 2 weeks ago

Project Handcraft Marketplace

  • Property mode set to 100644
File size: 4.4 KB
Line 
1import { SocketOptions, Socket, TlsOptions } from 'cloudflare:sockets'
2import { EventEmitter } from 'events'
3
4/**
5 * Wrapper around the Cloudflare built-in socket that can be used by the `Connection`.
6 */
7export class CloudflareSocket extends EventEmitter {
8 writable = false
9 destroyed = false
10
11 private _upgrading = false
12 private _upgraded = false
13 private _cfSocket: Socket | null = null
14 private _cfWriter: WritableStreamDefaultWriter | null = null
15 private _cfReader: ReadableStreamDefaultReader | null = null
16
17 constructor(readonly ssl: boolean) {
18 super()
19 }
20
21 setNoDelay() {
22 return this
23 }
24 setKeepAlive() {
25 return this
26 }
27 ref() {
28 return this
29 }
30 unref() {
31 return this
32 }
33
34 async connect(port: number, host: string, connectListener?: (...args: unknown[]) => void) {
35 try {
36 log('connecting')
37 if (connectListener) this.once('connect', connectListener)
38
39 const options: SocketOptions = this.ssl ? { secureTransport: 'starttls' } : {}
40 const mod = await import('cloudflare:sockets')
41 const connect = mod.connect
42 this._cfSocket = connect(`${host}:${port}`, options)
43 this._cfWriter = this._cfSocket.writable.getWriter()
44 this._addClosedHandler()
45
46 this._cfReader = this._cfSocket.readable.getReader()
47 if (this.ssl) {
48 this._listenOnce().catch((e) => this.emit('error', e))
49 } else {
50 this._listen().catch((e) => this.emit('error', e))
51 }
52
53 await this._cfWriter!.ready
54 log('socket ready')
55 this.writable = true
56 this.emit('connect')
57
58 return this
59 } catch (e) {
60 this.emit('error', e)
61 }
62 }
63
64 async _listen() {
65 // eslint-disable-next-line no-constant-condition
66 while (true) {
67 log('awaiting receive from CF socket')
68 const { done, value } = await this._cfReader!.read()
69 log('CF socket received:', done, value)
70 if (done) {
71 log('done')
72 break
73 }
74 this.emit('data', Buffer.from(value))
75 }
76 }
77
78 async _listenOnce() {
79 log('awaiting first receive from CF socket')
80 const { done, value } = await this._cfReader!.read()
81 log('First CF socket received:', done, value)
82 this.emit('data', Buffer.from(value))
83 }
84
85 write(
86 data: Uint8Array | string,
87 encoding: BufferEncoding = 'utf8',
88 callback: (...args: unknown[]) => void = () => {}
89 ) {
90 if (data.length === 0) return callback()
91 if (typeof data === 'string') data = Buffer.from(data, encoding)
92
93 log('sending data direct:', data)
94 this._cfWriter!.write(data).then(
95 () => {
96 log('data sent')
97 callback()
98 },
99 (err) => {
100 log('send error', err)
101 callback(err)
102 }
103 )
104 return true
105 }
106
107 end(data = Buffer.alloc(0), encoding: BufferEncoding = 'utf8', callback: (...args: unknown[]) => void = () => {}) {
108 log('ending CF socket')
109 this.write(data, encoding, (err) => {
110 this._cfSocket!.close()
111 if (callback) callback(err)
112 })
113 return this
114 }
115
116 destroy(reason: string) {
117 log('destroying CF socket', reason)
118 this.destroyed = true
119 return this.end()
120 }
121
122 startTls(options: TlsOptions) {
123 if (this._upgraded) {
124 // Don't try to upgrade again.
125 this.emit('error', 'Cannot call `startTls()` more than once on a socket')
126 return
127 }
128 this._cfWriter!.releaseLock()
129 this._cfReader!.releaseLock()
130 this._upgrading = true
131 this._cfSocket = this._cfSocket!.startTls(options)
132 this._cfWriter = this._cfSocket.writable.getWriter()
133 this._cfReader = this._cfSocket.readable.getReader()
134 this._addClosedHandler()
135 this._listen().catch((e) => this.emit('error', e))
136 }
137
138 _addClosedHandler() {
139 this._cfSocket!.closed.then(() => {
140 if (!this._upgrading) {
141 log('CF socket closed')
142 this._cfSocket = null
143 this.emit('close')
144 } else {
145 this._upgrading = false
146 this._upgraded = true
147 }
148 }).catch((e) => this.emit('error', e))
149 }
150}
151
152const debug = false
153
154function dump(data: unknown) {
155 if (data instanceof Uint8Array || data instanceof ArrayBuffer) {
156 // workaround https://github.com/microsoft/TypeScript/issues/63447
157 const buf = data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(data)
158
159 const hex = buf.toString('hex')
160 const str = new TextDecoder().decode(data)
161 return `\n>>> STR: "${str.replace(/\n/g, '\\n')}"\n>>> HEX: ${hex}\n`
162 } else {
163 return data
164 }
165}
166
167function log(...args: unknown[]) {
168 debug && console.log(...args.map(dump))
169}
Note: See TracBrowser for help on using the repository browser.