Added room permanence option to server

This commit is contained in:
Assistant 2021-06-26 16:39:21 +02:00
parent 9d1deebd85
commit 50b810a75f
11 changed files with 60 additions and 6 deletions

View File

@ -77,6 +77,10 @@ Random string used to generate managed room passwords.
.B \-\-motd\-file [file] .B \-\-motd\-file [file]
Path to a file from which motd (Message Of The Day) will be read. Path to a file from which motd (Message Of The Day) will be read.
.TP
.B \-\-rooms\-dir [directory]
Path to a directory from where room data will be written to and read from. This will enable rooms to persist without watchers and through restarts. Will not work if using \fB--isolate-rooms\fP.
.TP .TP
.B \-\-max\-chat\-message\-length [maxChatMessageLength] .B \-\-max\-chat\-message\-length [maxChatMessageLength]
Maximum number of characters in one chat message (default is 150). Maximum number of characters in one chat message (default is 150).

View File

@ -34,6 +34,7 @@ def main():
args.port, args.port,
args.password, args.password,
args.motd_file, args.motd_file,
args.rooms_dir,
args.isolate_rooms, args.isolate_rooms,
args.salt, args.salt,
args.disable_ready, args.disable_ready,

View File

@ -472,6 +472,7 @@ de = {
"server-salt-argument": "zufällige Zeichenkette, die zur Erstellung von Passwörtern verwendet wird", "server-salt-argument": "zufällige Zeichenkette, die zur Erstellung von Passwörtern verwendet wird",
"server-disable-ready-argument": "Bereitschaftsfeature deaktivieren", "server-disable-ready-argument": "Bereitschaftsfeature deaktivieren",
"server-motd-argument": "Pfad zur Datei, von der die Nachricht des Tages geladen wird", "server-motd-argument": "Pfad zur Datei, von der die Nachricht des Tages geladen wird",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "Soll Chat deaktiviert werden?", "server-chat-argument": "Soll Chat deaktiviert werden?",
"server-chat-maxchars-argument": "Maximale Zeichenzahl in einer Chatnachricht (Standard ist {})", "server-chat-maxchars-argument": "Maximale Zeichenzahl in einer Chatnachricht (Standard ist {})",
"server-maxusernamelength-argument": "Maximale Zeichenzahl in einem Benutzernamen (Standard ist {})", "server-maxusernamelength-argument": "Maximale Zeichenzahl in einem Benutzernamen (Standard ist {})",

View File

@ -473,6 +473,7 @@ en = {
"server-salt-argument": "random string used to generate managed room passwords", "server-salt-argument": "random string used to generate managed room passwords",
"server-disable-ready-argument": "disable readiness feature", "server-disable-ready-argument": "disable readiness feature",
"server-motd-argument": "path to file from which motd will be fetched", "server-motd-argument": "path to file from which motd will be fetched",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts",
"server-chat-argument": "Should chat be disabled?", "server-chat-argument": "Should chat be disabled?",
"server-chat-maxchars-argument": "Maximum number of characters in a chat message (default is {})", # Default number of characters "server-chat-maxchars-argument": "Maximum number of characters in a chat message (default is {})", # Default number of characters
"server-maxusernamelength-argument": "Maximum number of characters in a username (default is {})", "server-maxusernamelength-argument": "Maximum number of characters in a username (default is {})",

View File

@ -472,6 +472,7 @@ es = {
"server-salt-argument": "cadena aleatoria utilizada para generar contraseñas de salas administradas", "server-salt-argument": "cadena aleatoria utilizada para generar contraseñas de salas administradas",
"server-disable-ready-argument": "deshabilitar la función de preparación", "server-disable-ready-argument": "deshabilitar la función de preparación",
"server-motd-argument": "ruta al archivo del cual se obtendrá el texto motd", "server-motd-argument": "ruta al archivo del cual se obtendrá el texto motd",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "¿Debería deshabilitarse el chat?", "server-chat-argument": "¿Debería deshabilitarse el chat?",
"server-chat-maxchars-argument": "Número máximo de caracteres en un mensaje de chat (el valor predeterminado es {})", # Default number of characters "server-chat-maxchars-argument": "Número máximo de caracteres en un mensaje de chat (el valor predeterminado es {})", # Default number of characters
"server-maxusernamelength-argument": "Número máximo de caracteres para el nombre de usuario (el valor predeterminado es {})", "server-maxusernamelength-argument": "Número máximo de caracteres para el nombre de usuario (el valor predeterminado es {})",

View File

@ -472,6 +472,7 @@ it = {
"server-salt-argument": "usare stringhe casuali per generare le password delle stanze gestite", "server-salt-argument": "usare stringhe casuali per generare le password delle stanze gestite",
"server-disable-ready-argument": "disabilita la funzionalità \"pronto\"", "server-disable-ready-argument": "disabilita la funzionalità \"pronto\"",
"server-motd-argument": "percorso del file da cui verrà letto il messaggio del giorno", "server-motd-argument": "percorso del file da cui verrà letto il messaggio del giorno",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "abilita o disabilita la chat", "server-chat-argument": "abilita o disabilita la chat",
"server-chat-maxchars-argument": "Numero massimo di caratteri in un messaggio di chat (default è {})", # Default number of characters "server-chat-maxchars-argument": "Numero massimo di caratteri in un messaggio di chat (default è {})", # Default number of characters
"server-maxusernamelength-argument": "Numero massimo di caratteri in un nome utente (default è {})", "server-maxusernamelength-argument": "Numero massimo di caratteri in un nome utente (default è {})",

View File

@ -473,6 +473,7 @@ pt_BR = {
"server-salt-argument": "string aleatória utilizada para gerar senhas de salas gerenciadas", "server-salt-argument": "string aleatória utilizada para gerar senhas de salas gerenciadas",
"server-disable-ready-argument": "desativar recurso de prontidão", "server-disable-ready-argument": "desativar recurso de prontidão",
"server-motd-argument": "caminho para o arquivo o qual o motd será obtido", "server-motd-argument": "caminho para o arquivo o qual o motd será obtido",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "O chat deve ser desativado?", "server-chat-argument": "O chat deve ser desativado?",
"server-chat-maxchars-argument": "Número máximo de caracteres numa mensagem do chat (o padrão é {})", # Default number of characters "server-chat-maxchars-argument": "Número máximo de caracteres numa mensagem do chat (o padrão é {})", # Default number of characters
"server-maxusernamelength-argument": "Número máximos de caracteres num nome de usuário (o padrão é {})", "server-maxusernamelength-argument": "Número máximos de caracteres num nome de usuário (o padrão é {})",

View File

@ -472,6 +472,7 @@ pt_PT = {
"server-salt-argument": "string aleatória utilizada para gerar senhas de salas gerenciadas", "server-salt-argument": "string aleatória utilizada para gerar senhas de salas gerenciadas",
"server-disable-ready-argument": "desativar recurso de prontidão", "server-disable-ready-argument": "desativar recurso de prontidão",
"server-motd-argument": "caminho para o arquivo o qual o motd será obtido", "server-motd-argument": "caminho para o arquivo o qual o motd será obtido",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "O chat deve ser desativado?", "server-chat-argument": "O chat deve ser desativado?",
"server-chat-maxchars-argument": "Número máximo de caracteres numa mensagem do chat (o padrão é {})", # Default number of characters "server-chat-maxchars-argument": "Número máximo de caracteres numa mensagem do chat (o padrão é {})", # Default number of characters
"server-maxusernamelength-argument": "Número máximos de caracteres num nome de utilizador (o padrão é {})", "server-maxusernamelength-argument": "Número máximos de caracteres num nome de utilizador (o padrão é {})",

View File

@ -469,6 +469,7 @@ ru = {
"server-salt-argument": "генерировать пароли к управляемым комнатам на основании указанной строки (соли)", "server-salt-argument": "генерировать пароли к управляемым комнатам на основании указанной строки (соли)",
"server-disable-ready-argument": "отключить статусы готов/не готов", "server-disable-ready-argument": "отключить статусы готов/не готов",
"server-motd-argument": "путь к файлу, из которого будет извлекаться MOTD-сообщение", "server-motd-argument": "путь к файлу, из которого будет извлекаться MOTD-сообщение",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "Должен ли чат быть отключён?", "server-chat-argument": "Должен ли чат быть отключён?",
"server-chat-maxchars-argument": "Максимальное число символов в сообщениях в чате (по умолчанию {})", "server-chat-maxchars-argument": "Максимальное число символов в сообщениях в чате (по умолчанию {})",
"server-maxusernamelength-argument": "Максимальное число символов в именах пользователей (по умолчанию {})", "server-maxusernamelength-argument": "Максимальное число символов в именах пользователей (по умолчанию {})",

View File

@ -473,6 +473,7 @@ tr = {
"server-salt-argument": "yönetilen oda şifreleri oluşturmak için kullanılan rastgele dize", "server-salt-argument": "yönetilen oda şifreleri oluşturmak için kullanılan rastgele dize",
"server-disable-ready-argument": "hazır olma özelliğini devre dışı bırak", "server-disable-ready-argument": "hazır olma özelliğini devre dışı bırak",
"server-motd-argument": "motd alınacak dosyanın yolu", "server-motd-argument": "motd alınacak dosyanın yolu",
"server-rooms-argument": "path to directory to store/fetch room data. Enables rooms to persist without watchers and through restarts", # TODO: Translate
"server-chat-argument": "Sohbet devre dışı bırakılmalı mı?", "server-chat-argument": "Sohbet devre dışı bırakılmalı mı?",
"server-chat-maxchars-argument": "Bir sohbet mesajındaki maksimum karakter sayısı (varsayılan: {})", # Default number of characters "server-chat-maxchars-argument": "Bir sohbet mesajındaki maksimum karakter sayısı (varsayılan: {})", # Default number of characters
"server-maxusernamelength-argument": "Bir kullanıcı adındaki maksimum karakter sayısı (varsayılan {})", "server-maxusernamelength-argument": "Bir kullanıcı adındaki maksimum karakter sayısı (varsayılan {})",

View File

@ -4,6 +4,7 @@ import hashlib
import os import os
import random import random
import time import time
import json
from string import Template from string import Template
from twisted.enterprise import adbapi from twisted.enterprise import adbapi
@ -25,7 +26,7 @@ from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomString
class SyncFactory(Factory): class SyncFactory(Factory):
def __init__(self, port='', password='', motdFilePath=None, isolateRooms=False, salt=None, def __init__(self, port='', password='', motdFilePath=None, roomsDirPath=None, isolateRooms=False, salt=None,
disableReady=False, disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH, disableReady=False, disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH,
maxUsernameLength=constants.MAX_USERNAME_LENGTH, statsDbFile=None, tlsCertPath=None): maxUsernameLength=constants.MAX_USERNAME_LENGTH, statsDbFile=None, tlsCertPath=None):
self.isolateRooms = isolateRooms self.isolateRooms = isolateRooms
@ -40,12 +41,13 @@ class SyncFactory(Factory):
print(getMessage("no-salt-notification").format(salt)) print(getMessage("no-salt-notification").format(salt))
self._salt = salt self._salt = salt
self._motdFilePath = motdFilePath self._motdFilePath = motdFilePath
self._roomsDirPath = roomsDirPath if os.path.isdir(roomsDirPath) else None
self.disableReady = disableReady self.disableReady = disableReady
self.disableChat = disableChat self.disableChat = disableChat
self.maxChatMessageLength = maxChatMessageLength if maxChatMessageLength is not None else constants.MAX_CHAT_MESSAGE_LENGTH self.maxChatMessageLength = maxChatMessageLength if maxChatMessageLength is not None else constants.MAX_CHAT_MESSAGE_LENGTH
self.maxUsernameLength = maxUsernameLength if maxUsernameLength is not None else constants.MAX_USERNAME_LENGTH self.maxUsernameLength = maxUsernameLength if maxUsernameLength is not None else constants.MAX_USERNAME_LENGTH
if not isolateRooms: if not isolateRooms:
self._roomManager = RoomManager() self._roomManager = RoomManager(self._roomsDirPath)
else: else:
self._roomManager = PublicRoomManager() self._roomManager = PublicRoomManager()
if statsDbFile is not None: if statsDbFile is not None:
@ -311,8 +313,20 @@ class DBManager(object):
class RoomManager(object): class RoomManager(object):
def __init__(self): def __init__(self, roomsDir=None):
self._roomsDir = roomsDir
self._rooms = {} self._rooms = {}
if self._roomsDir is not None:
for root, dirs, files in os.walk(self._roomsDir):
for file in files:
if file.endswith(".room"):
room = Room('', self._roomsDir)
room.loadFromFile(os.path.join(root, file))
roomName = truncateText(room.getName(), constants.MAX_ROOM_NAME_LENGTH)
if len(room.getPlaylist()) == 0:
os.remove(os.path.join(root, file))
else:
self._rooms[roomName] = room
def broadcastRoom(self, sender, whatLambda): def broadcastRoom(self, sender, whatLambda):
room = sender.getRoom() room = sender.getRoom()
@ -342,7 +356,8 @@ class RoomManager(object):
oldRoom = watcher.getRoom() oldRoom = watcher.getRoom()
if oldRoom: if oldRoom:
oldRoom.removeWatcher(watcher) oldRoom.removeWatcher(watcher)
self._deleteRoomIfEmpty(oldRoom) if self._roomsDir is None:
self._deleteRoomIfEmpty(oldRoom)
def _getRoom(self, roomName): def _getRoom(self, roomName):
if roomName in self._rooms: if roomName in self._rooms:
@ -351,7 +366,7 @@ class RoomManager(object):
if RoomPasswordProvider.isControlledRoom(roomName): if RoomPasswordProvider.isControlledRoom(roomName):
room = ControlledRoom(roomName) room = ControlledRoom(roomName)
else: else:
room = Room(roomName) room = Room(roomName, self._roomsDir)
self._rooms[roomName] = room self._rooms[roomName] = room
return room return room
@ -392,8 +407,9 @@ class Room(object):
STATE_PAUSED = 0 STATE_PAUSED = 0
STATE_PLAYING = 1 STATE_PLAYING = 1
def __init__(self, name): def __init__(self, name, _roomsDir=None):
self._name = name self._name = name
self._roomsDir = _roomsDir
self._watchers = {} self._watchers = {}
self._playState = self.STATE_PAUSED self._playState = self.STATE_PAUSED
self._setBy = None self._setBy = None
@ -405,6 +421,27 @@ class Room(object):
def __str__(self, *args, **kwargs): def __str__(self, *args, **kwargs):
return self.getName() return self.getName()
def writeToFile(self):
if self._roomsDir is None:
return
if len(self._playlist) == 0:
return
data = {}
data['name'] = self._name
data['playlist'] = self._playlist
data['playlistIndex'] = self._playlistIndex
data['position'] = self._position
with open(os.path.join(self._roomsDir, self._name+'.room'), "w") as outfile:
json.dump(data, outfile)
def loadFromFile(self, filename):
with open(filename) as json_file:
data = json.load(json_file)
self._name = truncateText(data['name'], constants.MAX_ROOM_NAME_LENGTH)
self._playlist = data['playlist']
self._playlistIndex = data['playlistIndex']
self._position = data['position']
def getName(self): def getName(self):
return self._name return self._name
@ -424,6 +461,7 @@ class Room(object):
def setPaused(self, paused=STATE_PAUSED, setBy=None): def setPaused(self, paused=STATE_PAUSED, setBy=None):
self._playState = paused self._playState = paused
self._setBy = setBy self._setBy = setBy
self.writeToFile()
def setPosition(self, position, setBy=None): def setPosition(self, position, setBy=None):
self._position = position self._position = position
@ -465,9 +503,11 @@ class Room(object):
def setPlaylist(self, files, setBy=None): def setPlaylist(self, files, setBy=None):
self._playlist = files self._playlist = files
self.writeToFile()
def setPlaylistIndex(self, index, setBy=None): def setPlaylistIndex(self, index, setBy=None):
self._playlistIndex = index self._playlistIndex = index
self.writeToFile()
def getPlaylist(self): def getPlaylist(self):
return self._playlist return self._playlist
@ -687,6 +727,7 @@ class ConfigurationGetter(object):
self._argparser.add_argument('--disable-chat', action='store_true', help=getMessage("server-chat-argument")) self._argparser.add_argument('--disable-chat', action='store_true', help=getMessage("server-chat-argument"))
self._argparser.add_argument('--salt', metavar='salt', type=str, nargs='?', help=getMessage("server-salt-argument"), default=os.environ.get('SYNCPLAY_SALT')) self._argparser.add_argument('--salt', metavar='salt', type=str, nargs='?', help=getMessage("server-salt-argument"), default=os.environ.get('SYNCPLAY_SALT'))
self._argparser.add_argument('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument")) self._argparser.add_argument('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument"))
self._argparser.add_argument('--rooms-dir', metavar='rooms', type=str, nargs='?', help=getMessage("server-rooms-argument"))
self._argparser.add_argument('--max-chat-message-length', metavar='maxChatMessageLength', type=int, nargs='?', help=getMessage("server-chat-maxchars-argument").format(constants.MAX_CHAT_MESSAGE_LENGTH)) self._argparser.add_argument('--max-chat-message-length', metavar='maxChatMessageLength', type=int, nargs='?', help=getMessage("server-chat-maxchars-argument").format(constants.MAX_CHAT_MESSAGE_LENGTH))
self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH)) self._argparser.add_argument('--max-username-length', metavar='maxUsernameLength', type=int, nargs='?', help=getMessage("server-maxusernamelength-argument").format(constants.MAX_USERNAME_LENGTH))
self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument")) self._argparser.add_argument('--stats-db-file', metavar='file', type=str, nargs='?', help=getMessage("server-stats-db-file-argument"))