From d00b26b23d9b3fc1e54a4d117366f0f22e664135 Mon Sep 17 00:00:00 2001 From: Florrie Date: Fri, 10 Jul 2020 20:52:13 -0300 Subject: basic command relay across socket clients --- socket.js | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 17 deletions(-) (limited to 'socket.js') diff --git a/socket.js b/socket.js index 5bfe80a..ae8ef87 100644 --- a/socket.js +++ b/socket.js @@ -48,8 +48,23 @@ function validateCommand(command) { case 'initialize-backend': return typeof command.backend === 'object' } - break + // No break here; servers can send commands which typically come from + // clients too. case 'client': + switch (command.code) { + case 'seek-to': + return ( + typeof command.queuePlayer === 'string' && + typeof command.time === 'number' + ) + case 'set-pause': + return ( + typeof command.queuePlayer === 'string' && + typeof command.paused === 'boolean' + ) + case 'status': + return typeof command.status === 'string' + } break } @@ -70,7 +85,7 @@ function makeSocketServer() { server.canonicalBackend = null - function receivedData(data) { + function receivedData(socket, data) { // Parse data as a command and validate it. If invalid, drop this data. let command @@ -80,14 +95,45 @@ function makeSocketServer() { return } + command.sender = 'client' + if (!validateCommand(command)) { return } + // If it's a status command, respond appropriately, and return so that it + // is not relayed. + + if (command.code === 'status') { + switch (command.status) { + case 'sync-playback': + for (const QP of server.canonicalBackend.queuePlayers) { + if (QP.timeData) { + socket.write(JSON.stringify({ + sender: 'server', + code: 'seek-to', + queuePlayer: QP.id, + time: QP.timeData.curSecTotal + }) + '\n') + socket.write(JSON.stringify({ + sender: 'server', + code: 'set-pause', + queuePlayer: QP.id, + paused: false + })) + } + } + + break + } + + return + } + // Relay the data to client sockets. for (const socket of sockets) { - socket.write(command) + socket.write(JSON.stringify(command)) } } @@ -100,12 +146,20 @@ function makeSocketServer() { } }) - socket.on('data', receivedData) + socket.on('data', data => receivedData(socket, data)) + + const savedBackend = saveBackend(server.canonicalBackend) + + for (const qpData of savedBackend.queuePlayers) { + if (qpData.playerInfo) { + qpData.playerInfo.isPaused = true + } + } socket.write(JSON.stringify({ sender: 'server', code: 'initialize-backend', - backend: saveBackend(server.canonicalBackend) + backend: savedBackend })) }) @@ -129,18 +183,20 @@ function makeSocketClient() { // Same sort of "guarding" deserialization/validation as in the server // code, because it's possible the client and server backends mismatch. - let command - try { - command = deserializeDataToCommand(data) - } catch (error) { - return - } + for (const line of data.toString().split('\n')) { + let command + try { + command = deserializeDataToCommand(line) + } catch (error) { + return + } - if (!validateCommand(command)) { - return - } + if (!validateCommand(command)) { + return + } - client.emit('command', command) + client.emit('command', command) + } }) return client @@ -160,11 +216,51 @@ function attachBackendToSocketClient(backend, client, { await restoreBackend(backend, command.backend) // TODO: does this need to be called here? updateRestoredTracksUsingPlaylists(backend, getPlaylistSources()) - break + backend.on('playing', QP => { + QP.once('received time data', () => { + client.sendCommand({code: 'status', status: 'sync-playback'}) + }) + }) + return + } + // Again, no pause. Client commands can come from the server. + case 'client': { + let QP = ( + command.queuePlayer && + backend.queuePlayers.find(QP => QP.id === command.queuePlayer) + ) + + switch (command.code) { + case 'seek-to': + if (QP) QP.seekTo(command.time) + return + case 'set-pause': + if (QP) QP.setPause(command.paused) + return } - break + } } }) + + backend.on('toggle-pause', queuePlayer => { + client.sendCommand({ + code: 'set-pause', + queuePlayer: queuePlayer.id, + paused: queuePlayer.player.isPaused + }) + }) + + function handleSeek(queuePlayer) { + client.sendCommand({ + code: 'seek-to', + queuePlayer: queuePlayer.id, + time: queuePlayer.time + }) + } + + backend.on('seek-ahead', handleSeek) + backend.on('seek-back', handleSeek) + backend.on('seek-to', handleSeek) } function attachSocketServerToBackend(server, backend) { -- cgit 1.3.0-6-gf8a5