Reputation: 2265
I want to realize a client/server architecture (web browser clients <-> backend nodejs server), using a communication protocol to exchange 1-to-1 binary/voice messages between web clients and the backend server (a "voice assistant/bot").
I chose socketio as websocket protocol. This is the basic message exchange flow:
clients requests to the server (pull mode)
server notification to a client (push mode)
+----------------+ +------------------+
| | | |
+--+ | | | |
| | web browser | | | |
user 1 | +--------------> https | | |
| <--------------+ web server | | |
+--+ | for | | |
| static assets | | |
+--+ | | | |
| | web browser | | | cobot <--------+
user 2 | +--------------> +---> dialog +------+ |
| <--------------+ +---+ manager | | |
+--+ | socketio | | server | | |
| server | | logic | | |
| for audio / | | | | |
+--+ | video | | | | |
| | web browser | messages | | | | |
user N | +--------------> | | | | |
| <--------------+ | | | | |
+--+ | | | | | |
| | | | | |
+----------------+ +------------------+ | |
| |
Maybe one could call "unicast" this client-server communication. Server side, that's the usual behavior of a web server that receives a request from a certain client and serve the request replying to this client.
I'm confused about out to use socketio API to realize the scenario described. If I well understood socketio architecture:
// sending to sender-client only
socket.emit('messageType', 'message payload');
Is
room
socketio concept a solution? I think about assigning a room to each client (a user), allowing users to connect from different devices with auser_id
(room_id
=user_id
). In this scenario, I guess each client have to join his "dedicated" room. Right?
UPDATE
reading interesting question /answers: socket.io private message and How synchronise socketIO connection ID's on client and server?, I sketched this pseudocode, following the idea to associate a room to each private bidirectional client/server channel:
The client:
//
// client side
//
const user_id = 'username'
const audioBlob = ... // audioChunks blob from MediaRecorder
// join the room with his user_id as name
socket.join(user_id)
// new user (= room) registration
// notify the server about this new connection
socket.emit('user_id', user_id)
...
// client send a message (request) to the server
// on room with name user_id, excluding sender as recipients
socket.broadcast.to(user_id).emit('audioMessage', audioBlob)
...
// client receive a message
// audio message received from server (the answer to the request)
socket.on('audioMessage', audioBlob =>
playAudio(audioBlob) )
The server:
//
// server side
//
io.on('connection', socket => {
// pair/associate the socket with a room name
socket.on('user_id', user_id => {
socket.join(user_id)
// store somewhere association: {socket.id, user_id}
storeOnDB(socket, user_id)
})
// server receives a message from a client (pull request)
// the server elaborates the message
// and sends back to the user an answer
// (all clients in 'uid' room except sender, the server itself)
socket.on('audioMessage', msg => {
// retrieve the room name to which socket belongs
const user_id = getFromDB(socket)
socket.broadcast.to(user_id).emit('audioMessage', answerTo(msg))
})
}
...
// server sends an unsolicited/push message to a user
// (client socket on a room)
io.to('some uid').emit('some notification', data)
Does the pseudo-code make sense/it's correct?
Upvotes: 0
Views: 980
Reputation: 2265
I found a simple running solution that avoid any user_id <-> room concept.
That's working with just socket.emit()
for the client/server request/replies.
In a way, socket.id
act as session_id
.
Almost satisfying, but to manage unsolicited/push messages from server to client. I need to store/retrieve session_id
(socket.id
):
// just use socket id
// no room / no user id
//
// client side
//
const audioBlob = // some audioChunks blob from MediaRecorder
// ..
// client send a message (request) to the server
socket.emit('audioMessage', audioBlob)
// ...
// client receive a message
// audio message received from server (answering the request)
socket.on('audioMessage', audioBlob =>
playAudio(audioBlob) )
//
// server side
//
io.on('connection', socket => {
// store connected socket (optional, only for unsolicited push)
// server receives a message from a client (pull request)
// the server elaborates the message
// and sends back to the user an answer
socket.on('audioMessage', msg =>
socket.emit('audioMessage', answerTo(msg)) )
})
// ...
// retrieve connected socket
// server sends an unsolicited/push message to a user
someSocket.emit('some notification', data)
This solution seems to work, even if the room=uid based solution proposed in my question maybe is better because allows to have multiple devices connected at the same time (honestly not a business logic requirement in my case).
Upvotes: 1