Initial Client Features support
This commit is contained in:
parent
06f6eb183b
commit
7307fb4eb5
@ -552,6 +552,7 @@ class SyncplayClient(object):
|
|||||||
self.ui.showErrorMessage(getMessage("shared-playlists-not-supported-by-server-error").format(constants.SHARED_PLAYLIST_MIN_VERSION, self.serverVersion))
|
self.ui.showErrorMessage(getMessage("shared-playlists-not-supported-by-server-error").format(constants.SHARED_PLAYLIST_MIN_VERSION, self.serverVersion))
|
||||||
elif not self.serverFeatures["sharedPlaylists"]:
|
elif not self.serverFeatures["sharedPlaylists"]:
|
||||||
self.ui.showErrorMessage(getMessage("shared-playlists-disabled-by-server-error"))
|
self.ui.showErrorMessage(getMessage("shared-playlists-disabled-by-server-error"))
|
||||||
|
# TODO: Have messages for all unsupported & disabled features
|
||||||
self.ui.setFeatures(self.serverFeatures)
|
self.ui.setFeatures(self.serverFeatures)
|
||||||
|
|
||||||
def getSanitizedCurrentUserFile(self):
|
def getSanitizedCurrentUserFile(self):
|
||||||
@ -581,6 +582,24 @@ class SyncplayClient(object):
|
|||||||
def getUsername(self):
|
def getUsername(self):
|
||||||
return self.userlist.currentUser.username
|
return self.userlist.currentUser.username
|
||||||
|
|
||||||
|
def chatIsEnabled(self):
|
||||||
|
return True
|
||||||
|
# TODO: Allow chat to be disabled
|
||||||
|
|
||||||
|
def getFeatures(self):
|
||||||
|
features = dict()
|
||||||
|
|
||||||
|
# Can change during runtime:
|
||||||
|
features["sharedPlaylists"] = self.sharedPlaylistIsEnabled() # Can change during runtime
|
||||||
|
features["chat"] = self.chatIsEnabled() # Can change during runtime
|
||||||
|
|
||||||
|
# Static for this version/release of Syncplay:
|
||||||
|
features["featureList"] = True
|
||||||
|
features["readiness"] = True
|
||||||
|
features["managedRooms"] = True
|
||||||
|
|
||||||
|
return features
|
||||||
|
|
||||||
def setRoom(self, roomName, resetAutoplay=False):
|
def setRoom(self, roomName, resetAutoplay=False):
|
||||||
self.userlist.currentUser.room = roomName
|
self.userlist.currentUser.room = roomName
|
||||||
if resetAutoplay:
|
if resetAutoplay:
|
||||||
@ -702,6 +721,9 @@ class SyncplayClient(object):
|
|||||||
message = utils.truncateText(message,constants.MAX_CHAT_MESSAGE_LENGTH)
|
message = utils.truncateText(message,constants.MAX_CHAT_MESSAGE_LENGTH)
|
||||||
self._protocol.sendChatMessage(message)
|
self._protocol.sendChatMessage(message)
|
||||||
|
|
||||||
|
def sendFeaturesUpdate(self, features):
|
||||||
|
self._protocol.sendFeaturesUpdate(features)
|
||||||
|
|
||||||
def changePlaylistEnabledState(self, newState):
|
def changePlaylistEnabledState(self, newState):
|
||||||
oldState = self.sharedPlaylistIsEnabled()
|
oldState = self.sharedPlaylistIsEnabled()
|
||||||
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
|
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
|
||||||
@ -799,6 +821,11 @@ class SyncplayClient(object):
|
|||||||
if oldReadyState != isReady:
|
if oldReadyState != isReady:
|
||||||
self._warnings.checkReadyStates()
|
self._warnings.checkReadyStates()
|
||||||
|
|
||||||
|
@requireServerFeature("managedRooms")
|
||||||
|
def setUserFeatures(self, username, features):
|
||||||
|
self.userlist.setFeatures(username, features)
|
||||||
|
self.ui.userListChange()
|
||||||
|
|
||||||
@requireServerFeature("managedRooms")
|
@requireServerFeature("managedRooms")
|
||||||
def createControlledRoom(self, roomName):
|
def createControlledRoom(self, roomName):
|
||||||
controlPassword = utils.RandomStringGenerator.generate_room_password()
|
controlPassword = utils.RandomStringGenerator.generate_room_password()
|
||||||
@ -989,6 +1016,7 @@ class SyncplayUser(object):
|
|||||||
self.room = room
|
self.room = room
|
||||||
self.file = file_
|
self.file = file_
|
||||||
self._controller = False
|
self._controller = False
|
||||||
|
self._features = {}
|
||||||
|
|
||||||
def setFile(self, filename, duration, size, path=None):
|
def setFile(self, filename, duration, size, path=None):
|
||||||
file_ = {
|
file_ = {
|
||||||
@ -1042,6 +1070,9 @@ class SyncplayUser(object):
|
|||||||
def setReady(self, ready):
|
def setReady(self, ready):
|
||||||
self.ready = ready
|
self.ready = ready
|
||||||
|
|
||||||
|
def setFeatures(self, features):
|
||||||
|
self._features = features
|
||||||
|
|
||||||
class SyncplayUserlist(object):
|
class SyncplayUserlist(object):
|
||||||
def __init__(self, ui, client):
|
def __init__(self, ui, client):
|
||||||
self.currentUser = SyncplayUser()
|
self.currentUser = SyncplayUser()
|
||||||
@ -1120,7 +1151,7 @@ class SyncplayUserlist(object):
|
|||||||
if differentDuration: differences.append(getMessage("file-difference-duration"))
|
if differentDuration: differences.append(getMessage("file-difference-duration"))
|
||||||
return ", ".join(differences)
|
return ", ".join(differences)
|
||||||
|
|
||||||
def addUser(self, username, room, file_, noMessage=False, isController=None, isReady=None):
|
def addUser(self, username, room, file_, noMessage=False, isController=None, isReady=None, features={}):
|
||||||
if username == self.currentUser.username:
|
if username == self.currentUser.username:
|
||||||
if isController is not None:
|
if isController is not None:
|
||||||
self.currentUser.setControllerStatus(isController)
|
self.currentUser.setControllerStatus(isController)
|
||||||
@ -1131,7 +1162,7 @@ class SyncplayUserlist(object):
|
|||||||
user.setControllerStatus(isController)
|
user.setControllerStatus(isController)
|
||||||
self._users[username] = user
|
self._users[username] = user
|
||||||
user.setReady(isReady)
|
user.setReady(isReady)
|
||||||
|
user.setFeatures(features)
|
||||||
if not noMessage:
|
if not noMessage:
|
||||||
self.__showUserChangeMessage(username, room, file_)
|
self.__showUserChangeMessage(username, room, file_)
|
||||||
self.userListChange(room)
|
self.userListChange(room)
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import syncplay
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
import time
|
import time
|
||||||
from syncplay.messages import getMessage
|
from syncplay.messages import getMessage
|
||||||
from syncplay.constants import PING_MOVING_AVERAGE_WEIGHT
|
from syncplay.constants import PING_MOVING_AVERAGE_WEIGHT, CONTROLLED_ROOMS_MIN_VERSION, USER_READY_MIN_VERSION, SHARED_PLAYLIST_MIN_VERSION, CHAT_MIN_VERSION
|
||||||
|
|
||||||
|
|
||||||
class JSONCommandProtocol(LineReceiver):
|
class JSONCommandProtocol(LineReceiver):
|
||||||
def handleMessages(self, messages):
|
def handleMessages(self, messages):
|
||||||
@ -107,6 +106,7 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
if room: hello["room"] = {"name" :room}
|
if room: hello["room"] = {"name" :room}
|
||||||
hello["version"] = "1.2.255" # Used so newer clients work on 1.2.X server
|
hello["version"] = "1.2.255" # Used so newer clients work on 1.2.X server
|
||||||
hello["realversion"] = syncplay.version
|
hello["realversion"] = syncplay.version
|
||||||
|
hello["features"] = self._client.getFeatures()
|
||||||
self.sendMessage({"Hello": hello})
|
self.sendMessage({"Hello": hello})
|
||||||
|
|
||||||
def _SetUser(self, users):
|
def _SetUser(self, users):
|
||||||
@ -147,6 +147,11 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
self._client.playlist.changeToPlaylistIndex(values['index'], values['user'])
|
self._client.playlist.changeToPlaylistIndex(values['index'], values['user'])
|
||||||
elif command == "playlistChange":
|
elif command == "playlistChange":
|
||||||
self._client.playlist.changePlaylist(values['files'], values['user'])
|
self._client.playlist.changePlaylist(values['files'], values['user'])
|
||||||
|
elif command == "features":
|
||||||
|
self._client.setUserFeatures(values["username"],values['features'])
|
||||||
|
|
||||||
|
def sendFeaturesUpdate(self, features):
|
||||||
|
self.sendSet({"features": features})
|
||||||
|
|
||||||
def sendSet(self, setting):
|
def sendSet(self, setting):
|
||||||
self.sendMessage({"Set": setting})
|
self.sendMessage({"Set": setting})
|
||||||
@ -173,7 +178,8 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
file_ = user[1]['file'] if user[1]['file'] <> {} else None
|
file_ = user[1]['file'] if user[1]['file'] <> {} else None
|
||||||
isController = user[1]['controller'] if 'controller' in user[1] else False
|
isController = user[1]['controller'] if 'controller' in user[1] else False
|
||||||
isReady = user[1]['isReady'] if 'isReady' in user[1] else None
|
isReady = user[1]['isReady'] if 'isReady' in user[1] else None
|
||||||
self._client.userlist.addUser(userName, roomName, file_, noMessage=True, isController=isController, isReady=isReady)
|
features = user[1]['features'] if 'features' in user[1] else None
|
||||||
|
self._client.userlist.addUser(userName, roomName, file_, noMessage=True, isController=isController, isReady=isReady, features=features)
|
||||||
self._client.userlist.showUserList()
|
self._client.userlist.showUserList()
|
||||||
|
|
||||||
def sendList(self):
|
def sendList(self):
|
||||||
@ -286,6 +292,7 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
def __init__(self, factory):
|
def __init__(self, factory):
|
||||||
self._factory = factory
|
self._factory = factory
|
||||||
self._version = None
|
self._version = None
|
||||||
|
self._features = None
|
||||||
self._logged = False
|
self._logged = False
|
||||||
self.clientIgnoringOnTheFly = 0
|
self.clientIgnoringOnTheFly = 0
|
||||||
self.serverIgnoringOnTheFly = 0
|
self.serverIgnoringOnTheFly = 0
|
||||||
@ -319,6 +326,16 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
self._factory.removeWatcher(self._watcher)
|
self._factory.removeWatcher(self._watcher)
|
||||||
|
|
||||||
|
def getFeatures(self):
|
||||||
|
if not self._features:
|
||||||
|
self._features = {}
|
||||||
|
self._features["sharedPlaylists"] = self._version >= SHARED_PLAYLIST_MIN_VERSION
|
||||||
|
self._features["chat"] = self._version >= CHAT_MIN_VERSION
|
||||||
|
self._features["featureList"] = False
|
||||||
|
self._features["readiness"] = self._version >= USER_READY_MIN_VERSION
|
||||||
|
self._features["managedRooms"] = self._version >= CONTROLLED_ROOMS_MIN_VERSION
|
||||||
|
return self._features
|
||||||
|
|
||||||
def isLogged(self):
|
def isLogged(self):
|
||||||
return self._logged
|
return self._logged
|
||||||
|
|
||||||
@ -339,7 +356,8 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
roomName = roomName.strip()
|
roomName = roomName.strip()
|
||||||
version = hello["version"] if hello.has_key("version") else None
|
version = hello["version"] if hello.has_key("version") else None
|
||||||
version = hello["realversion"] if hello.has_key("realversion") else version
|
version = hello["realversion"] if hello.has_key("realversion") else version
|
||||||
return username, serverPassword, roomName, version
|
features = hello["features"] if hello.has_key("features") else None
|
||||||
|
return username, serverPassword, roomName, version, features
|
||||||
|
|
||||||
def _checkPassword(self, serverPassword):
|
def _checkPassword(self, serverPassword):
|
||||||
if self._factory.password:
|
if self._factory.password:
|
||||||
@ -352,7 +370,7 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def handleHello(self, hello):
|
def handleHello(self, hello):
|
||||||
username, serverPassword, roomName, version = self._extractHelloArguments(hello)
|
username, serverPassword, roomName, version, features = self._extractHelloArguments(hello)
|
||||||
if not username or not roomName or not version:
|
if not username or not roomName or not version:
|
||||||
self.dropWithError(getMessage("hello-server-error"))
|
self.dropWithError(getMessage("hello-server-error"))
|
||||||
return
|
return
|
||||||
@ -360,14 +378,22 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
if not self._checkPassword(serverPassword):
|
if not self._checkPassword(serverPassword):
|
||||||
return
|
return
|
||||||
self._version = version
|
self._version = version
|
||||||
|
self.setFeatures(features)
|
||||||
self._factory.addWatcher(self, username, roomName)
|
self._factory.addWatcher(self, username, roomName)
|
||||||
self._logged = True
|
self._logged = True
|
||||||
self.sendHello(version)
|
self.sendHello(version)
|
||||||
|
|
||||||
|
@requireLogged
|
||||||
def handleChat(self,chatMessage):
|
def handleChat(self,chatMessage):
|
||||||
if not self._factory.disableChat:
|
if not self._factory.disableChat:
|
||||||
self._factory.sendChat(self._watcher,chatMessage)
|
self._factory.sendChat(self._watcher,chatMessage)
|
||||||
|
|
||||||
|
def setFeatures(self, features):
|
||||||
|
self._features = features
|
||||||
|
|
||||||
|
def sendFeaturesUpdate(self):
|
||||||
|
self.sendSet({"features": self.getFeatures()})
|
||||||
|
|
||||||
def setWatcher(self, watcher):
|
def setWatcher(self, watcher):
|
||||||
self._watcher = watcher
|
self._watcher = watcher
|
||||||
|
|
||||||
@ -404,6 +430,9 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
self._factory.setPlaylist(self._watcher, set_[1]['files'])
|
self._factory.setPlaylist(self._watcher, set_[1]['files'])
|
||||||
elif command == "playlistIndex":
|
elif command == "playlistIndex":
|
||||||
self._factory.setPlaylistIndex(self._watcher, set_[1]['index'])
|
self._factory.setPlaylistIndex(self._watcher, set_[1]['index'])
|
||||||
|
elif command == "features":
|
||||||
|
#TODO: Check
|
||||||
|
self._watcher.setFeatures(set_[1])
|
||||||
|
|
||||||
def sendSet(self, setting):
|
def sendSet(self, setting):
|
||||||
self.sendMessage({"Set": setting})
|
self.sendMessage({"Set": setting})
|
||||||
@ -470,7 +499,8 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
"position": 0,
|
"position": 0,
|
||||||
"file": watcher.getFile() if watcher.getFile() else {},
|
"file": watcher.getFile() if watcher.getFile() else {},
|
||||||
"controller": watcher.isController(),
|
"controller": watcher.isController(),
|
||||||
"isReady": watcher.isReady()
|
"isReady": watcher.isReady(),
|
||||||
|
"features": watcher.getFeatures()
|
||||||
}
|
}
|
||||||
userlist[room.getName()][watcher.getName()] = userFile
|
userlist[room.getName()][watcher.getName()] = userFile
|
||||||
|
|
||||||
|
|||||||
@ -108,7 +108,7 @@ class SyncFactory(Factory):
|
|||||||
self._roomManager.broadcast(watcher, l)
|
self._roomManager.broadcast(watcher, l)
|
||||||
|
|
||||||
def sendJoinMessage(self, watcher):
|
def sendJoinMessage(self, watcher):
|
||||||
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, {"joined": True, "version": watcher.getVersion()}) if w != watcher else None
|
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, {"joined": True, "version": watcher.getVersion(), "features": watcher.getFeatures()}) if w != watcher else None
|
||||||
self._roomManager.broadcast(watcher, l)
|
self._roomManager.broadcast(watcher, l)
|
||||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
||||||
|
|
||||||
@ -414,6 +414,10 @@ class Watcher(object):
|
|||||||
def setReady(self, ready):
|
def setReady(self, ready):
|
||||||
self._ready = ready
|
self._ready = ready
|
||||||
|
|
||||||
|
def getFeatures(self):
|
||||||
|
features = self._connector.getFeatures()
|
||||||
|
return features
|
||||||
|
|
||||||
def isReady(self):
|
def isReady(self):
|
||||||
if self._server.disableReady:
|
if self._server.disableReady:
|
||||||
return None
|
return None
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user