mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-06-24 19:51:30 +02:00
Keep original socket.io server for non-subdir clients
This commit is contained in:
parent
ef82e8b0d0
commit
843dd0b1b2
@ -84,7 +84,6 @@ class Server {
|
|||||||
Logger.logManager = new LogManager()
|
Logger.logManager = new LogManager()
|
||||||
|
|
||||||
this.server = null
|
this.server = null
|
||||||
this.io = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,18 +440,11 @@ class Server {
|
|||||||
async stop() {
|
async stop() {
|
||||||
Logger.info('=== Stopping Server ===')
|
Logger.info('=== Stopping Server ===')
|
||||||
Watcher.close()
|
Watcher.close()
|
||||||
Logger.info('Watcher Closed')
|
Logger.info('[Server] Watcher Closed')
|
||||||
|
await SocketAuthority.close()
|
||||||
return new Promise((resolve) => {
|
Logger.info('[Server] Closing HTTP Server')
|
||||||
SocketAuthority.close((err) => {
|
await new Promise((resolve) => this.server.close(resolve))
|
||||||
if (err) {
|
Logger.info('[Server] HTTP Server Closed')
|
||||||
Logger.error('Failed to close server', err)
|
|
||||||
} else {
|
|
||||||
Logger.info('Server successfully closed')
|
|
||||||
}
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = Server
|
module.exports = Server
|
||||||
|
@ -14,7 +14,7 @@ const Auth = require('./Auth')
|
|||||||
class SocketAuthority {
|
class SocketAuthority {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.Server = null
|
this.Server = null
|
||||||
this.io = null
|
this.socketIoServers = []
|
||||||
|
|
||||||
/** @type {Object.<string, SocketClient>} */
|
/** @type {Object.<string, SocketClient>} */
|
||||||
this.clients = {}
|
this.clients = {}
|
||||||
@ -89,82 +89,104 @@ class SocketAuthority {
|
|||||||
*
|
*
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
*/
|
*/
|
||||||
close(callback) {
|
async close() {
|
||||||
Logger.info('[SocketAuthority] Shutting down')
|
Logger.info('[SocketAuthority] closing...')
|
||||||
// This will close all open socket connections, and also close the underlying http server
|
const closePromises = this.socketIoServers.map((io) => {
|
||||||
if (this.io) this.io.close(callback)
|
return new Promise((resolve) => {
|
||||||
else callback()
|
Logger.info(`[SocketAuthority] Closing Socket.IO server: ${io.path}`)
|
||||||
|
io.close(() => {
|
||||||
|
Logger.info(`[SocketAuthority] Socket.IO server closed: ${io.path}`)
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await Promise.all(closePromises)
|
||||||
|
Logger.info('[SocketAuthority] closed')
|
||||||
|
this.socketIoServers = []
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(Server) {
|
initialize(Server) {
|
||||||
this.Server = Server
|
this.Server = Server
|
||||||
|
|
||||||
this.io = new SocketIO.Server(this.Server.server, {
|
const socketIoOptions = {
|
||||||
cors: {
|
cors: {
|
||||||
origin: '*',
|
origin: '*',
|
||||||
methods: ['GET', 'POST']
|
methods: ['GET', 'POST']
|
||||||
},
|
|
||||||
path: `${global.RouterBasePath}/socket.io`
|
|
||||||
})
|
|
||||||
|
|
||||||
this.io.on('connection', (socket) => {
|
|
||||||
this.clients[socket.id] = {
|
|
||||||
id: socket.id,
|
|
||||||
socket,
|
|
||||||
connected_at: Date.now()
|
|
||||||
}
|
}
|
||||||
socket.sheepClient = this.clients[socket.id]
|
}
|
||||||
|
|
||||||
Logger.info('[SocketAuthority] Socket Connected', socket.id)
|
const ioServer = new SocketIO.Server(Server.server, socketIoOptions)
|
||||||
|
ioServer.path = '/socket.io'
|
||||||
|
this.socketIoServers.push(ioServer)
|
||||||
|
|
||||||
// Required for associating a User with a socket
|
if (global.RouterBasePath) {
|
||||||
socket.on('auth', (token) => this.authenticateSocket(socket, token))
|
// open a separate socket.io server for the router base path, keeping the original server open for legacy clients
|
||||||
|
const ioBasePath = `${global.RouterBasePath}/socket.io`
|
||||||
|
const ioBasePathServer = new SocketIO.Server(Server.server, { ...socketIoOptions, path: ioBasePath })
|
||||||
|
ioBasePathServer.path = ioBasePath
|
||||||
|
this.socketIoServers.push(ioBasePathServer)
|
||||||
|
}
|
||||||
|
|
||||||
// Scanning
|
this.socketIoServers.forEach((io) => {
|
||||||
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
io.on('connection', (socket) => {
|
||||||
|
this.clients[socket.id] = {
|
||||||
// Logs
|
id: socket.id,
|
||||||
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
socket,
|
||||||
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
connected_at: Date.now()
|
||||||
|
|
||||||
// Sent automatically from socket.io clients
|
|
||||||
socket.on('disconnect', (reason) => {
|
|
||||||
Logger.removeSocketListener(socket.id)
|
|
||||||
|
|
||||||
const _client = this.clients[socket.id]
|
|
||||||
if (!_client) {
|
|
||||||
Logger.warn(`[SocketAuthority] Socket ${socket.id} disconnect, no client (Reason: ${reason})`)
|
|
||||||
} else if (!_client.user) {
|
|
||||||
Logger.info(`[SocketAuthority] Unauth socket ${socket.id} disconnected (Reason: ${reason})`)
|
|
||||||
delete this.clients[socket.id]
|
|
||||||
} else {
|
|
||||||
Logger.debug('[SocketAuthority] User Offline ' + _client.user.username)
|
|
||||||
this.adminEmitter('user_offline', _client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
|
|
||||||
|
|
||||||
const disconnectTime = Date.now() - _client.connected_at
|
|
||||||
Logger.info(`[SocketAuthority] Socket ${socket.id} disconnected from client "${_client.user.username}" after ${disconnectTime}ms (Reason: ${reason})`)
|
|
||||||
delete this.clients[socket.id]
|
|
||||||
}
|
}
|
||||||
})
|
socket.sheepClient = this.clients[socket.id]
|
||||||
|
|
||||||
//
|
Logger.info(`[SocketAuthority] Socket Connected to ${io.path}`, socket.id)
|
||||||
// Events for testing
|
|
||||||
//
|
// Required for associating a User with a socket
|
||||||
socket.on('message_all_users', (payload) => {
|
socket.on('auth', (token) => this.authenticateSocket(socket, token))
|
||||||
// admin user can send a message to all authenticated users
|
|
||||||
// displays on the web app as a toast
|
// Scanning
|
||||||
const client = this.clients[socket.id] || {}
|
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
||||||
if (client.user?.isAdminOrUp) {
|
|
||||||
this.emitter('admin_message', payload.message || '')
|
// Logs
|
||||||
} else {
|
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
||||||
Logger.error(`[SocketAuthority] Non-admin user sent the message_all_users event`)
|
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
||||||
}
|
|
||||||
})
|
// Sent automatically from socket.io clients
|
||||||
socket.on('ping', () => {
|
socket.on('disconnect', (reason) => {
|
||||||
const client = this.clients[socket.id] || {}
|
Logger.removeSocketListener(socket.id)
|
||||||
const user = client.user || {}
|
|
||||||
Logger.debug(`[SocketAuthority] Received ping from socket ${user.username || 'No User'}`)
|
const _client = this.clients[socket.id]
|
||||||
socket.emit('pong')
|
if (!_client) {
|
||||||
|
Logger.warn(`[SocketAuthority] Socket ${socket.id} disconnect, no client (Reason: ${reason})`)
|
||||||
|
} else if (!_client.user) {
|
||||||
|
Logger.info(`[SocketAuthority] Unauth socket ${socket.id} disconnected (Reason: ${reason})`)
|
||||||
|
delete this.clients[socket.id]
|
||||||
|
} else {
|
||||||
|
Logger.debug('[SocketAuthority] User Offline ' + _client.user.username)
|
||||||
|
this.adminEmitter('user_offline', _client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
|
||||||
|
|
||||||
|
const disconnectTime = Date.now() - _client.connected_at
|
||||||
|
Logger.info(`[SocketAuthority] Socket ${socket.id} disconnected from client "${_client.user.username}" after ${disconnectTime}ms (Reason: ${reason})`)
|
||||||
|
delete this.clients[socket.id]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//
|
||||||
|
// Events for testing
|
||||||
|
//
|
||||||
|
socket.on('message_all_users', (payload) => {
|
||||||
|
// admin user can send a message to all authenticated users
|
||||||
|
// displays on the web app as a toast
|
||||||
|
const client = this.clients[socket.id] || {}
|
||||||
|
if (client.user?.isAdminOrUp) {
|
||||||
|
this.emitter('admin_message', payload.message || '')
|
||||||
|
} else {
|
||||||
|
Logger.error(`[SocketAuthority] Non-admin user sent the message_all_users event`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
socket.on('ping', () => {
|
||||||
|
const client = this.clients[socket.id] || {}
|
||||||
|
const user = client.user || {}
|
||||||
|
Logger.debug(`[SocketAuthority] Received ping from socket ${user.username || 'No User'}`)
|
||||||
|
socket.emit('pong')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user