@uppy/companion-client: revert breaking change (#4801)

Revert breaking change

This reverts parts of commit 17826da517.
This commit is contained in:
Antoine du Hamel 2023-11-20 15:50:44 +01:00 committed by GitHub
parent c60ece4dc7
commit a67f0ffdf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 266 additions and 0 deletions

View file

@ -0,0 +1,87 @@
import ee from 'namespace-emitter'
export default class UppySocket {
#queued = []
#emitter = ee()
#isOpen = false
#socket
constructor (opts) {
this.opts = opts
if (!opts || opts.autoOpen !== false) {
this.open()
}
}
get isOpen () { return this.#isOpen }
[Symbol.for('uppy test: getSocket')] () { return this.#socket }
[Symbol.for('uppy test: getQueued')] () { return this.#queued }
open () {
if (this.#socket != null) return
this.#socket = new WebSocket(this.opts.target)
this.#socket.onopen = () => {
this.#isOpen = true
while (this.#queued.length > 0 && this.#isOpen) {
const first = this.#queued.shift()
this.send(first.action, first.payload)
}
}
this.#socket.onclose = () => {
this.#isOpen = false
this.#socket = null
}
this.#socket.onmessage = this.#handleMessage
}
close () {
this.#socket?.close()
}
send (action, payload) {
// attach uuid
if (!this.#isOpen) {
this.#queued.push({ action, payload })
return
}
this.#socket.send(JSON.stringify({
action,
payload,
}))
}
on (action, handler) {
this.#emitter.on(action, handler)
}
emit (action, payload) {
this.#emitter.emit(action, payload)
}
once (action, handler) {
this.#emitter.once(action, handler)
}
#handleMessage = (e) => {
try {
const message = JSON.parse(e.data)
this.emit(message.action, message.payload)
} catch (err) {
// TODO: use a more robust error handler.
console.log(err) // eslint-disable-line no-console
}
}
}

View file

@ -0,0 +1,176 @@
import { afterEach, beforeEach, vi, describe, it, expect } from 'vitest'
import UppySocket from './Socket.js'
describe('Socket', () => {
let webSocketConstructorSpy
let webSocketCloseSpy
let webSocketSendSpy
beforeEach(() => {
webSocketConstructorSpy = vi.fn()
webSocketCloseSpy = vi.fn()
webSocketSendSpy = vi.fn()
globalThis.WebSocket = class WebSocket {
constructor (target) {
webSocketConstructorSpy(target)
}
// eslint-disable-next-line class-methods-use-this
close (args) {
webSocketCloseSpy(args)
}
// eslint-disable-next-line class-methods-use-this
send (json) {
webSocketSendSpy(json)
}
triggerOpen () {
this.onopen()
}
triggerClose () {
this.onclose()
}
}
})
afterEach(() => {
globalThis.WebSocket = undefined
})
it('should expose a class', () => {
expect(UppySocket.name).toEqual('UppySocket')
expect(
new UppySocket({
target: 'foo',
}) instanceof UppySocket,
)
})
it('should setup a new WebSocket', () => {
new UppySocket({ target: 'foo' }) // eslint-disable-line no-new
expect(webSocketConstructorSpy.mock.calls[0][0]).toEqual('foo')
})
it('should send a message via the websocket if the connection is open', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.send('bar', 'boo')
expect(webSocketSendSpy.mock.calls.length).toEqual(1)
expect(webSocketSendSpy.mock.calls[0]).toEqual([
JSON.stringify({ action: 'bar', payload: 'boo' }),
])
})
it('should queue the message for the websocket if the connection is not open', () => {
const uppySocket = new UppySocket({ target: 'foo' })
uppySocket.send('bar', 'boo')
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([{ action: 'bar', payload: 'boo' }])
expect(webSocketSendSpy.mock.calls.length).toEqual(0)
})
it('should queue any messages for the websocket if the connection is not open, then send them when the connection is open', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
uppySocket.send('bar', 'boo')
uppySocket.send('moo', 'baa')
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([
{ action: 'bar', payload: 'boo' },
{ action: 'moo', payload: 'baa' },
])
expect(webSocketSendSpy.mock.calls.length).toEqual(0)
webSocketInstance.triggerOpen()
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([])
expect(webSocketSendSpy.mock.calls.length).toEqual(2)
expect(webSocketSendSpy.mock.calls[0]).toEqual([
JSON.stringify({ action: 'bar', payload: 'boo' }),
])
expect(webSocketSendSpy.mock.calls[1]).toEqual([
JSON.stringify({ action: 'moo', payload: 'baa' }),
])
})
it('should start queuing any messages when the websocket connection is closed', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.send('bar', 'boo')
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([])
webSocketInstance.triggerClose()
uppySocket.send('bar', 'boo')
expect(uppySocket[Symbol.for('uppy test: getQueued')]()).toEqual([{ action: 'bar', payload: 'boo' }])
})
it('should close the websocket when it is force closed', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
webSocketInstance.triggerOpen()
uppySocket.close()
expect(webSocketCloseSpy.mock.calls.length).toEqual(1)
})
it('should be able to subscribe to messages received on the websocket', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const webSocketInstance = uppySocket[Symbol.for('uppy test: getSocket')]()
const emitterListenerMock = vi.fn()
uppySocket.on('hi', emitterListenerMock)
webSocketInstance.triggerOpen()
webSocketInstance.onmessage({
data: JSON.stringify({ action: 'hi', payload: 'ho' }),
})
expect(emitterListenerMock.mock.calls).toEqual([
['ho', undefined, undefined, undefined, undefined, undefined],
])
})
it('should be able to emit messages and subscribe to them', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const emitterListenerMock = vi.fn()
uppySocket.on('hi', emitterListenerMock)
uppySocket.emit('hi', 'ho')
uppySocket.emit('hi', 'ho')
uppySocket.emit('hi', 'off to work we go')
expect(emitterListenerMock.mock.calls).toEqual([
['ho', undefined, undefined, undefined, undefined, undefined],
['ho', undefined, undefined, undefined, undefined, undefined],
[
'off to work we go',
undefined,
undefined,
undefined,
undefined,
undefined,
],
])
})
it('should be able to subscribe to the first event for a particular action', () => {
const uppySocket = new UppySocket({ target: 'foo' })
const emitterListenerMock = vi.fn()
uppySocket.once('hi', emitterListenerMock)
uppySocket.emit('hi', 'ho')
uppySocket.emit('hi', 'ho')
uppySocket.emit('hi', 'off to work we go')
expect(emitterListenerMock.mock.calls.length).toEqual(1)
expect(emitterListenerMock.mock.calls).toEqual([
['ho', undefined, undefined, undefined, undefined, undefined],
])
})
})

View file

@ -7,3 +7,6 @@
export { default as RequestClient } from './RequestClient.js'
export { default as Provider } from './Provider.js'
export { default as SearchProvider } from './SearchProvider.js'
// TODO: remove in the next major
export { default as Socket } from './Socket.js'