Reputation: 1
I have multiple IOT devices with socket.io clients connecting to a socket.io server. I would like a client to be able to emit a file to be backed up to another client and receive a response that it was done. Since the message is from client to client, it has to be relayed through the server and since socket.IO does not support callbacks on broadcasts and the only way I know how to send an emit message to a specific socket.id is io.to(socket.id).emit(), which is handled as a broadcast, I'm not sure how to proceed. Here is my code:
socket.io Server:
let connections = []
io.on("connection", (socket) => {
socket.on("disconnect", () => {
connections = connections.filter(item => item.socketId !== socket.id)
})
socket.on('setConnectionStatus', (device) => {
connections.push({device: device, socketId: socket.id})
})
//relay backup messages
socket.on('Backup', (file, callback) => {
console.log(file)
let systemController = connections.findIndex(x => x.device == 'system_controller' )
systemController = connections[systemController].socketId
io.to(systemController).emit('Backup', file, (status) => {
console.log(status)
callback(status)
})
})
})
sending socket.io client:
const socketServer = "http://10.10.10.1:3001"
const deviceName = 'liveNet'
const socket = io(socketServer)
socket.on("connect", () => {
socket.emit("setConnectionStatus", deviceName)
})
function backupToSystemController() {
return new Promise(function(resolve, _) {
const file = fs.readFileSync(__dirname + '/public/config/config.json')
socket.emit('Backup', file, (status) => {
resolve(status)
})
})
}
//this is called in an api
backupToSystemController()
receiving socket.io client:
const socketServer = "http://10.10.10.1:3001"
const deviceName = 'system_controller'
const socket = io(socketServer)
socket.on("connect", () => {
socket.emit("setConnectionStatus", deviceName)
})
socket.on('Backup', (file, callback) => {
let response
fs.writeFile(__dirname + '/backups/config.json', file, (err) => {
if (err) {
response = {message: 'Failure' + err}
}
else {
response = {message: 'success'}
}
callback(response)
})
})
Everything works except the callback listener on the server never gets a response because it and I get a timeOut error:
Error: operation has timed out
at Timeout._onTimeout (/home/pi/aeiProject/socketIO/server/node_modules/socket.io/dist/broadcast-operator.js:182:17)
at listOnTimeout (node:internal/timers:569:17)
at process.processTimers (node:internal/timers:512:7)
Upvotes: 0
Views: 199
Reputation: 1
I was able to fix the issue by pushing the actual socket into the object I added to the connections array, and then referencing that socket when sending the emit. See updated socket.io Server code below.
let connections = []
io.on("connection", (socket) => {
socket.on("disconnect", () => {
connections = connections.filter(item => item.socketId !== socket.id)
})
socket.on('setConnectionStatus', (device) => {
connections.push({device: device, socketId: socket.id, socket: socket})
})
//relay backup messages
socket.on('aeinetBackup', (file, callback) => {
let system_controller = connections.findIndex(x => x.device == 'system_controller' )
let systemControllerSocket = connections[system_controller].socket
systemControllerSocket.emit('aeinetBackup', file, (status) => { // in order to get a callback we have to use the specific socket for the system controller. Otherwise if we didn't need a callback we could use io.to(socket.id).emit()
callback(status)
})
})
})
Upvotes: 0