Beispiel #1
0
 def setupIRCBot(self, ircConnectionData):
         botFunctions = [
                 self.ircPauseRoom,
                 self.getRooms,
                 self.getRoomPosition,
                 self.ircSetRoomPosition,
                 self.getRoomUsernames,
                 self.isRoomPaused,                            
                 ]
         self.ircBot = IRCBot(
                ircConnectionData['server'],
                ircConnectionData['serverPassword'],
                ircConnectionData['port'],
                ircConnectionData['nick'],
                ircConnectionData['nickservPass'],
                ircConnectionData['channel'],
                ircConnectionData['channelPassword'],
                botFunctions,
                )
Beispiel #2
0
 def setupIRCBot(self, ircConnectionData):
     botFunctions = {
         "pause": self.ircPauseRoom,
         "getRooms": self.getRooms,
         "setRoomPosition": self.ircSetRoomPosition,
         "getRoomPosition": self.getRoomPosition,
         "getRoomUsers": self.getRoomUsernames,
         "isRoomPaused": self.isRoomPaused,
     }
     try:
         self.ircBot = IRCBot(
             ircConnectionData['server'],
             ircConnectionData['port'],
             ircConnectionData['nick'],
             ircConnectionData['channel'],
             botFunctions,
         )
         self.ircBot.start()
     except:
         print "IRC Bot could not be started, please check your configuration"
Beispiel #3
0
 def setupIRCBot(self, ircConnectionData):
         botFunctions = {
                 "pause": self.ircPauseRoom,
                 "getRooms": self.getRooms,
                 "setRoomPosition": self.ircSetRoomPosition,
                 "getRoomPosition": self.getRoomPosition,
                 "getRoomUsers": self.getRoomUsernames,
                 "isRoomPaused": self.isRoomPaused,                            
                 }
         try:
             self.ircBot = IRCBot(
                    ircConnectionData['server'],
                    ircConnectionData['port'],
                    ircConnectionData['nick'],
                    ircConnectionData['channel'],
                    botFunctions,
                    )
             self.ircBot.start()
         except:
             print "IRC Bot could not be started, please check your configuration"
Beispiel #4
0
class SyncFactory(Factory):
    def __init__(self, password = '', motdFilePath = None, httpReplyFilePath= None, ircConfig = None, ircVerbose = False):
        print getMessage("en", "welcome-server-notification").format(syncplay.version)
        if(password):
            password = hashlib.md5(password).hexdigest()
        self.password = password
        self._motdFilePath = motdFilePath
        self._httpReplyFilePath = httpReplyFilePath
        self._rooms = {}
        self._roomStates = {}
        self._roomUpdate = threading.RLock()
        self.ircVerbose = ircVerbose,
        ircConnectionData = self.readIrcConfig(ircConfig)
        if(ircConnectionData):
            self.setupIRCBot(ircConnectionData)
    
    def readIrcConfig(self, ircConfig): #TODO:
        if(ircConfig and os.path.isfile(ircConfig)):
            cfg = codecs.open(ircConfig, "r", "utf-8-sig").read()
            cfg = cfg.splitlines()
            if(len(cfg) == 7):
                ircConnectionData = {}
                ircConnectionData['server'] = cfg[0]
                ircConnectionData['serverPassword'] = cfg[1]
                ircConnectionData['port'] = int(cfg[2])
                ircConnectionData['nick'] = cfg[3]
                ircConnectionData['nickservPass'] = cfg[4]
                ircConnectionData['channelPassword'] = cfg[5] 
                ircConnectionData['channel'] = cfg[6]
                return ircConnectionData
        
    def setupIRCBot(self, ircConnectionData):
            botFunctions = [
                    self.ircPauseRoom,
                    self.getRooms,
                    self.getRoomPosition,
                    self.ircSetRoomPosition,
                    self.getRoomUsernames,
                    self.isRoomPaused,                            
                    ]
            self.ircBot = IRCBot(
                   ircConnectionData['server'],
                   ircConnectionData['serverPassword'],
                   ircConnectionData['port'],
                   ircConnectionData['nick'],
                   ircConnectionData['nickservPass'],
                   ircConnectionData['channel'],
                   ircConnectionData['channelPassword'],
                   botFunctions,
                   )

    def buildProtocol(self, addr):
        return SyncServerProtocol(self)        
        
    def _createRoomIfDoesntExist(self, roomName):
        if (not self._rooms.has_key(roomName)):
            with self._roomUpdate:
                self._rooms[roomName] = {}
                self._roomStates[roomName] = {
                                              "position": 0.0,
                                              "paused": True,
                                              "setBy": None,
                                              "lastUpdate": time.time()
                                             }

    def addWatcher(self, watcherProtocol, username, roomName, roomPassword):
        allnames = []
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                allnames.append(watcher.name.lower()) 
        while username.lower() in allnames:
            username += '_'
        self._createRoomIfDoesntExist(roomName)
        watcher = Watcher(self, watcherProtocol, username, roomName)
        with self._roomUpdate:
            self._rooms[roomName][watcherProtocol] = watcher
        print getMessage("en", "client-connected-room-server-notification").format(username, roomName, watcherProtocol.transport.getPeer().host)    
        reactor.callLater(0.1, watcher.scheduleSendState)
        l = lambda w: w.sendUserSetting(username, roomName, None, {"joined": True})
        self.broadcast(watcherProtocol, l)
        if(self.ircVerbose):
            self.ircBot.sp_joined(username, roomName)

    def getWatcher(self, watcherProtocol):
        for room in self._rooms.itervalues():
            if(room.has_key(watcherProtocol)):
                return room[watcherProtocol]

    def getAllWatchers(self, watcherProtocol): #TODO: Optimize me
        watchers = {}
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                watchers[watcher.watcherProtocol] = watcher
        return watchers

    def _removeWatcherFromTheRoom(self, watcherProtocol):
        for room in self._rooms.itervalues():
            with self._roomUpdate:
                watcher = room.pop(watcherProtocol, None)
            if(watcher):
                return watcher

    def _deleteRoomIfEmpty(self, room):
        if (self._rooms[room] == {}):
            with self._roomUpdate:
                self._rooms.pop(room)
                self._roomStates.pop(room)
    
    def getRoomPausedAndPosition(self, room):
        position = self._roomStates[room]["position"]
        paused = self._roomStates[room]["paused"]
        if (not paused):
            timePassedSinceSet = time.time() - self._roomStates[room]["lastUpdate"]
            position += timePassedSinceSet
        return paused, position

    def getMotd(self, userIp, username, room):
        if(self._motdFilePath and os.path.isfile(self._motdFilePath)):
            tmpl = codecs.open(self._motdFilePath, "r", "utf-8-sig").read()
            args = dict(version=syncplay.version, userIp=userIp, username=username, room=room)
            try:
                motd = Template(tmpl).substitute(args)
                return motd if len(motd) < constants.SERVER_MAX_TEMPLATE_LENGTH else getMessage("en", "server-messed-up-motd-too-long").format(constants.SERVER_MAX_TEMPLATE_LENGTH, len(motd))
            except ValueError: 
                return getMessage("en", "server-messed-up-motd-unescaped-placeholders")
        else:
            return ""

    def gethttpRequestReply(self):
        if(self._httpReplyFilePath and os.path.isfile(self._httpReplyFilePath)):
            tmpl = codecs.open(self._httpReplyFilePath, "r", "utf-8-sig").read()
            return tmpl.encode('utf-8')
        else:
            return getMessage("en", "server-default-http-reply")

    def sendState(self, watcherProtocol, doSeek = False, senderLatency = 0, forcedUpdate = False):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        room = watcher.room
        paused, position = self.getRoomPausedAndPosition(room)
        setBy = self._roomStates[room]["setBy"]
        watcher.paused = paused
        watcher.position = position
        watcherProtocol.sendState(position, paused, doSeek, setBy, senderLatency, watcher.latency, forcedUpdate)
        if(time.time() - watcher.lastUpdate > constants.PROTOCOL_TIMEOUT):
            watcherProtocol.drop()
            self.removeWatcher(watcherProtocol)
        
    def __updateWatcherPing(self, latencyCalculation, watcher):
        if (latencyCalculation):
            ping = (time.time() - latencyCalculation) / 2
            if (watcher.latency):
                watcher.latency = watcher.latency * (constants.PING_MOVING_AVERAGE_WEIGHT) + ping * (1-constants.PING_MOVING_AVERAGE_WEIGHT) #Exponential moving average 
            else:
                watcher.latency = ping

    def __shouldServerForceUpdateOnRoom(self, pauseChanged, doSeek):
        return doSeek or pauseChanged
            
    def __updatePausedState(self, paused, watcher):
        watcher.paused = paused
        if(self._roomStates[watcher.room]["paused"] <> paused):
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["paused"] = paused
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
            return True
    
    def __updatePositionState(self, position, doSeek, watcher):
        watcher.position = position
        if (doSeek):
            self._roomStates[watcher.room]["position"] = position
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
        else:
            setter = min(self._rooms[watcher.room].values())
            self._roomStates[watcher.room]["position"] = setter.position
            self._roomStates[watcher.room]["setBy"] = setter.name 
            self._roomStates[watcher.room]["lastUpdate"] = setter.lastUpdate
            
    def updateWatcherState(self, watcherProtocol, position, paused, doSeek, latencyCalculation):
        watcher = self.getWatcher(watcherProtocol)
        self.__updateWatcherPing(latencyCalculation, watcher)
        watcher.lastUpdate = time.time()
        if(watcher.file):
            oldPosition = self._roomStates[watcher.room]["position"]
            if(position is not None):
                self.__updatePositionState(position, doSeek, watcher)
            pauseChanged = False
            if(paused is not None):
                pauseChanged = self.__updatePausedState(paused, watcher)
            forceUpdate = self.__shouldServerForceUpdateOnRoom(pauseChanged, doSeek)
            if(forceUpdate):
                if(self.ircVerbose):
                    if(paused and pauseChanged):
                        self.ircBot.sp_paused(watcher.name, watcher.room)
                    elif(not paused and pauseChanged):
                        self.ircBot.sp_unpaused(watcher.name, watcher.room)
                    if(doSeek and position):
                        self.ircBot.sp_seek(watcher.name, watcher.room, oldPosition, position)
                l = lambda w: self.sendState(w, doSeek, watcher.latency, forceUpdate)
                self.broadcastRoom(watcher.watcherProtocol, l)

    def removeWatcher(self, watcherProtocol):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, None, {"left": True})
        self.broadcast(watcherProtocol, l)
        self._removeWatcherFromTheRoom(watcherProtocol)
        watcher.deactivate()
        self._deleteRoomIfEmpty(watcher.room)
        print getMessage("en", "client-left-server-notification").format(watcher.name) 
        if(self.ircVerbose):
            self.ircBot.sp_left(watcher.name, watcher.room)
            
    def watcherGetUsername(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).name
    
    def watcherGetRoom(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).room
    
    def watcherSetRoom(self, watcherProtocol, room):
        watcher = self._removeWatcherFromTheRoom(watcherProtocol)
        if(not watcher):
            return
        watcher.resetStateTimer()
        oldRoom = watcher.room
        self._createRoomIfDoesntExist(room)
        with self._roomUpdate:
            self._rooms[room][watcherProtocol] = watcher
        self._roomStates[room]["position"] = watcher.position
        self._roomStates[room]["setBy"] = watcher.name
        self._roomStates[room]["lastUpdate"] = time.time()
        self._deleteRoomIfEmpty(oldRoom)
        watcher.room = room
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, watcher.file, None)
        self.broadcast(watcherProtocol, l)
                
    def watcherSetFile(self, watcherProtocol, file_):
        watcher = self.getWatcher(watcherProtocol)
        watcher.file = file_
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, watcher.file, None)
        self.broadcast(watcherProtocol, l)
        if(self.ircVerbose):
            self.ircBot.sp_fileplaying(watcher.name, watcher.file['name'], watcher.room)
    
    def broadcastRoom(self, sender, what):
        room = self._rooms[self.watcherGetRoom(sender)]
        if(room):
            with self._roomUpdate:
                for receiver in room:
                    what(receiver)
                
    def broadcast(self, sender, what):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                    for receiver in room:
                        what(receiver)
    
    def _findUserByUsername(self, username):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                for user in room.itervalues():
                    if user.name == username:
                        return user
    
    def ircPauseRoom(self, setBy, paused):
        user = self._findUserByUsername(setBy)
        if(user):
            with self._roomUpdate:
                self._roomStates[user.room]['paused'] = paused
                self._roomStates[user.room]['setBy'] = "IRC: " + setBy
            l = lambda w: self.sendState(w, False, user.latency, True)
            self.broadcastRoom(user.watcherProtocol, l)
  
    
    def getRooms(self):
        return self._rooms.keys()
    
    def getRoomPosition(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["position"]
            
    def ircSetRoomPosition(self, setBy, time):
        user = self._findUserByUsername(setBy)
        if(user):
            with self._roomUpdate:
                self._roomStates[user.room]['paused'] = time
                self._roomStates[user.room]['setBy'] = "IRC: " + setBy 
            l = lambda w: self.sendState(w, True, user.latency, True)
            self.broadcastRoom(user.watcherProtocol, l)
  
    
    def getRoomUsernames(self, room):
        l = []
        with self._roomUpdate:
            if room in self._rooms:
                for user in self._rooms[room].itervalues():
                    l.append({'nick': user.name, 'file': user.file['name'], "length": user.file['duration']})
        return l
            
    def isRoomPaused(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["paused"]
Beispiel #5
0
class SyncFactory(Factory):
    def __init__(self,
                 password='',
                 motdFilePath=None,
                 httpReplyFilePath=None,
                 ircConfig=None,
                 ircVerbose=False):
        print getMessage("en", "welcome-server-notification").format(
            syncplay.version)
        if (password):
            password = hashlib.md5(password).hexdigest()
        self.password = password
        self._motdFilePath = motdFilePath
        self._httpReplyFilePath = httpReplyFilePath
        self._rooms = {}
        self._roomStates = {}
        self._roomUpdate = threading.RLock()
        self.ircVerbose = ircVerbose
        ircConnectionData = self.readIrcConfig(ircConfig)
        if (ircConnectionData):
            self.setupIRCBot(ircConnectionData)

    def readIrcConfig(self, ircConfig):
        if (ircConfig and os.path.isfile(ircConfig)):
            cfg = codecs.open(ircConfig, "r", "utf-8-sig").read()
            cfg = cfg.splitlines()
            ircConnectionData = {
                "server": "",
                "port": "",
                "nick": "",
                "channel": ""
            }
            for line in cfg:
                if ("irc.server: " in line):
                    ircConnectionData['server'] = line.split(": ")[1]
                elif ("irc.serverPort: " in line):
                    ircConnectionData['port'] = int(line.split(": ")[1])
                elif ("irc.botName: " in line):
                    ircConnectionData['nick'] = line.split(": ")[1]
                elif ("irc.channel: " in line):
                    ircConnectionData['channel'] = line.split(": ")[1]
            return ircConnectionData

    def setupIRCBot(self, ircConnectionData):
        botFunctions = {
            "pause": self.ircPauseRoom,
            "getRooms": self.getRooms,
            "setRoomPosition": self.ircSetRoomPosition,
            "getRoomPosition": self.getRoomPosition,
            "getRoomUsers": self.getRoomUsernames,
            "isRoomPaused": self.isRoomPaused,
        }
        try:
            self.ircBot = IRCBot(
                ircConnectionData['server'],
                ircConnectionData['port'],
                ircConnectionData['nick'],
                ircConnectionData['channel'],
                botFunctions,
            )
            self.ircBot.start()
        except:
            print "IRC Bot could not be started, please check your configuration"

    def buildProtocol(self, addr):
        return SyncServerProtocol(self)

    def _createRoomIfDoesntExist(self, roomName):
        if (not self._rooms.has_key(roomName)):
            with self._roomUpdate:
                self._rooms[roomName] = {}
                self._roomStates[roomName] = {
                    "position": 0.0,
                    "paused": True,
                    "setBy": None,
                    "lastUpdate": time.time()
                }

    def addWatcher(self, watcherProtocol, username, roomName, roomPassword):
        allnames = []
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                allnames.append(watcher.name.lower())
        while username.lower() in allnames:
            username += '_'
        self._createRoomIfDoesntExist(roomName)
        watcher = Watcher(self, watcherProtocol, username, roomName)
        with self._roomUpdate:
            self._rooms[roomName][watcherProtocol] = watcher
        reactor.callLater(0.1, watcher.scheduleSendState)
        l = lambda w: w.sendUserSetting(username, roomName, None,
                                        {"joined": True})
        self.broadcast(watcherProtocol, l)
        if (self.ircVerbose):
            self.ircBot.sp_joined(username, roomName)

    def getWatcher(self, watcherProtocol):
        for room in self._rooms.itervalues():
            if (room.has_key(watcherProtocol)):
                return room[watcherProtocol]

    def getAllWatchers(self, watcherProtocol):  #TODO: Optimize me
        watchers = {}
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                watchers[watcher.watcherProtocol] = watcher
        return watchers

    def _removeWatcherFromTheRoom(self, watcherProtocol):
        for room in self._rooms.itervalues():
            with self._roomUpdate:
                watcher = room.pop(watcherProtocol, None)
            if (watcher):
                return watcher

    def _deleteRoomIfEmpty(self, room):
        if (self._rooms[room] == {}):
            with self._roomUpdate:
                self._rooms.pop(room)
                self._roomStates.pop(room)

    def getRoomPausedAndPosition(self, room):
        position = self._roomStates[room]["position"]
        paused = self._roomStates[room]["paused"]
        if (not paused):
            timePassedSinceSet = time.time(
            ) - self._roomStates[room]["lastUpdate"]
            position += timePassedSinceSet
        return paused, position

    def getMotd(self, userIp, username, room):
        if (self._motdFilePath and os.path.isfile(self._motdFilePath)):
            tmpl = codecs.open(self._motdFilePath, "r", "utf-8-sig").read()
            args = dict(version=syncplay.version,
                        userIp=userIp,
                        username=username,
                        room=room)
            try:
                motd = Template(tmpl).substitute(args)
                return motd if len(
                    motd
                ) < constants.SERVER_MAX_TEMPLATE_LENGTH else getMessage(
                    "en", "server-messed-up-motd-too-long").format(
                        constants.SERVER_MAX_TEMPLATE_LENGTH, len(motd))
            except ValueError:
                return getMessage(
                    "en", "server-messed-up-motd-unescaped-placeholders")
        else:
            return ""

    def gethttpRequestReply(self):
        if (self._httpReplyFilePath
                and os.path.isfile(self._httpReplyFilePath)):
            tmpl = codecs.open(self._httpReplyFilePath, "r",
                               "utf-8-sig").read()
            return tmpl.encode('utf-8')
        else:
            return getMessage("en", "server-default-http-reply")

    def sendState(self, watcherProtocol, doSeek=False, forcedUpdate=False):
        watcher = self.getWatcher(watcherProtocol)
        if (not watcher):
            return
        room = watcher.room
        paused, position = self.getRoomPausedAndPosition(room)
        setBy = self._roomStates[room]["setBy"]
        watcher.paused = paused
        watcher.position = position
        watcherProtocol.sendState(position, paused, doSeek, setBy,
                                  forcedUpdate)
        if (time.time() - watcher.lastUpdate > constants.PROTOCOL_TIMEOUT):
            watcherProtocol.drop()
            self.removeWatcher(watcherProtocol)

    def __shouldServerForceUpdateOnRoom(self, pauseChanged, doSeek):
        return doSeek or pauseChanged

    def __updatePausedState(self, paused, watcher):
        watcher.paused = paused
        if (self._roomStates[watcher.room]["paused"] <> paused):
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["paused"] = paused
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
            return True

    def __updatePositionState(self, position, doSeek, watcher):
        watcher.position = position
        if (doSeek):
            self._roomStates[watcher.room]["position"] = position
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
        else:
            setter = min(self._rooms[watcher.room].values())
            self._roomStates[watcher.room]["position"] = setter.position
            self._roomStates[watcher.room]["setBy"] = setter.name
            self._roomStates[watcher.room]["lastUpdate"] = setter.lastUpdate

    def __notifyIrcBot(self, position, paused, doSeek, watcher, oldPosition,
                       pauseChanged):
        if (self.ircVerbose):
            if (paused and pauseChanged):
                self.ircBot.sp_paused(watcher.name, watcher.room)
            elif (not paused and pauseChanged):
                self.ircBot.sp_unpaused(watcher.name, watcher.room)
            if (doSeek and position):
                self.ircBot.sp_seek(watcher.name, oldPosition, position,
                                    watcher.room)

    def updateWatcherState(self, watcherProtocol, position, paused, doSeek,
                           messageAge):
        watcher = self.getWatcher(watcherProtocol)
        if (not watcher):
            return
        watcher.lastUpdate = time.time()
        if (watcher.file):
            oldPosition = self._roomStates[watcher.room]["position"]
            pauseChanged = False
            if (paused is not None):
                pauseChanged = self.__updatePausedState(paused, watcher)
            if (position is not None):
                if (not paused):
                    position += messageAge
                self.__updatePositionState(position, doSeek or pauseChanged,
                                           watcher)
            forceUpdate = self.__shouldServerForceUpdateOnRoom(
                pauseChanged, doSeek)
            if (forceUpdate):
                self.__notifyIrcBot(position, paused, doSeek, watcher,
                                    oldPosition, pauseChanged)
                l = lambda w: self.sendState(w, doSeek, forceUpdate)
                self.broadcastRoom(watcher.watcherProtocol, l)

    def removeWatcher(self, watcherProtocol):
        watcher = self.getWatcher(watcherProtocol)
        if (not watcher):
            return
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, None,
                                        {"left": True})
        self.broadcast(watcherProtocol, l)
        self._removeWatcherFromTheRoom(watcherProtocol)
        watcher.deactivate()
        self._deleteRoomIfEmpty(watcher.room)
        if (self.ircVerbose):
            self.ircBot.sp_left(watcher.name, watcher.room)

    def watcherGetUsername(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).name

    def watcherGetRoom(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).room

    def watcherSetRoom(self, watcherProtocol, room):
        watcher = self._removeWatcherFromTheRoom(watcherProtocol)
        if (not watcher):
            return
        watcher.resetStateTimer()
        oldRoom = watcher.room
        self._createRoomIfDoesntExist(room)
        with self._roomUpdate:
            self._rooms[room][watcherProtocol] = watcher
        self._deleteRoomIfEmpty(oldRoom)
        watcher.room = room
        self.sendState(watcherProtocol, True)
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, None, None)
        self.broadcast(watcherProtocol, l)

    def watcherSetFile(self, watcherProtocol, file_):
        watcher = self.getWatcher(watcherProtocol)
        if (not watcher):
            return
        watcher.file = file_
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, watcher.
                                        file, None)
        self.broadcast(watcherProtocol, l)
        if (self.ircVerbose):
            self.ircBot.sp_fileplaying(watcher.name, watcher.file['name'],
                                       watcher.room)

    def broadcastRoom(self, sender, what):
        room = self._rooms[self.watcherGetRoom(sender)]
        if (room):
            with self._roomUpdate:
                for receiver in room:
                    what(receiver)

    def broadcast(self, sender, what):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                for receiver in room:
                    what(receiver)

    def _findUserByUsername(self, username):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                for user in room.itervalues():
                    if user.name == username:
                        return user

    def ircPauseRoom(self, setBy, paused):
        user = self._findUserByUsername(setBy)
        if (user):
            with self._roomUpdate:
                if (self._roomStates[user.room]['paused'] != paused):
                    self._roomStates[user.room]['paused'] = paused
                    self._roomStates[user.room]['setBy'] = "IRC: " + setBy
                    if (paused):
                        self.ircBot.sp_paused("IRC: " + user.name, user.room)
                    elif (not paused):
                        self.ircBot.sp_unpaused("IRC: " + user.name, user.room)
                    l = lambda w: self.sendState(w, False, 0, True)
                    self.broadcastRoom(user.watcherProtocol, l)

    def getRooms(self):
        return self._rooms.keys()

    def getRoomPosition(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["position"]

    def ircSetRoomPosition(self, setBy, time):
        user = self._findUserByUsername(setBy)
        if (user):
            with self._roomUpdate:
                oldPosition = self._roomStates[user.room]['paused']
                if (oldPosition - time > 1):
                    self._roomStates[user.room]['paused'] = time
                    self._roomStates[user.room]['setBy'] = "IRC: " + setBy
                    self.ircBot.sp_seek(user.name, oldPosition, time,
                                        user.room)
                    l = lambda w: self.sendState(w, True, 0, True)
                    self.broadcastRoom(user.watcherProtocol, l)

    def getRoomUsernames(self, room):
        l = []
        with self._roomUpdate:
            if room in self._rooms:
                for user in self._rooms[room].itervalues():
                    if (user.file):
                        l.append({
                            'nick': user.name,
                            'file': user.file['name'],
                            "duration": user.file['duration']
                        })
                    else:
                        l.append({
                            'nick': user.name,
                            'file': None,
                            "duration": None
                        })
        return l

    def isRoomPaused(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["paused"]
Beispiel #6
0
class SyncFactory(Factory):
    def __init__(self, password = '', motdFilePath = None, httpReplyFilePath= None, ircConfig = None, ircVerbose = False):
        print getMessage("en", "welcome-server-notification").format(syncplay.version)
        if(password):
            password = hashlib.md5(password).hexdigest()
        self.password = password
        self._motdFilePath = motdFilePath
        self._httpReplyFilePath = httpReplyFilePath
        self._rooms = {}
        self._roomStates = {}
        self._roomUpdate = threading.RLock()
        self.ircVerbose = ircVerbose
        ircConnectionData = self.readIrcConfig(ircConfig)
        if(ircConnectionData):
            self.setupIRCBot(ircConnectionData)
    
    def readIrcConfig(self, ircConfig):
        if(ircConfig and os.path.isfile(ircConfig)):
            cfg = codecs.open(ircConfig, "r", "utf-8-sig").read()
            cfg = cfg.splitlines()
            ircConnectionData = {
                                 "server": "",
                                 "port": "",
                                 "nick": "",
                                 "channel": ""
                                 }
            for line in cfg:
                if("irc.server: " in line):
                    ircConnectionData['server'] = line.split(": ")[1]
                elif("irc.serverPort: " in line):
                    ircConnectionData['port'] = int(line.split(": ")[1])
                elif("irc.botName: " in line):
                    ircConnectionData['nick'] = line.split(": ")[1]
                elif("irc.channel: " in line):
                    ircConnectionData['channel'] = line.split(": ")[1]
            return ircConnectionData
        
    def setupIRCBot(self, ircConnectionData):
            botFunctions = {
                    "pause": self.ircPauseRoom,
                    "getRooms": self.getRooms,
                    "setRoomPosition": self.ircSetRoomPosition,
                    "getRoomPosition": self.getRoomPosition,
                    "getRoomUsers": self.getRoomUsernames,
                    "isRoomPaused": self.isRoomPaused,                            
                    }
            try:
                self.ircBot = IRCBot(
                       ircConnectionData['server'],
                       ircConnectionData['port'],
                       ircConnectionData['nick'],
                       ircConnectionData['channel'],
                       botFunctions,
                       )
                self.ircBot.start()
            except:
                print "IRC Bot could not be started, please check your configuration"

    def buildProtocol(self, addr):
        return SyncServerProtocol(self)        
        
    def _createRoomIfDoesntExist(self, roomName):
        if (not self._rooms.has_key(roomName)):
            with self._roomUpdate:
                self._rooms[roomName] = {}
                self._roomStates[roomName] = {
                                              "position": 0.0,
                                              "paused": True,
                                              "setBy": None,
                                              "lastUpdate": time.time()
                                             }

    def addWatcher(self, watcherProtocol, username, roomName, roomPassword):
        allnames = []
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                allnames.append(watcher.name.lower()) 
        while username.lower() in allnames:
            username += '_'
        self._createRoomIfDoesntExist(roomName)
        watcher = Watcher(self, watcherProtocol, username, roomName)
        with self._roomUpdate:
            self._rooms[roomName][watcherProtocol] = watcher  
        reactor.callLater(0.1, watcher.scheduleSendState)
        l = lambda w: w.sendUserSetting(username, roomName, None, {"joined": True})
        self.broadcast(watcherProtocol, l)
        if(self.ircVerbose):
            self.ircBot.sp_joined(username, roomName)

    def getWatcher(self, watcherProtocol):
        for room in self._rooms.itervalues():
            if(room.has_key(watcherProtocol)):
                return room[watcherProtocol]

    def getAllWatchers(self, watcherProtocol): #TODO: Optimize me
        watchers = {}
        for room in self._rooms.itervalues():
            for watcher in room.itervalues():
                watchers[watcher.watcherProtocol] = watcher
        return watchers

    def _removeWatcherFromTheRoom(self, watcherProtocol):
        for room in self._rooms.itervalues():
            with self._roomUpdate:
                watcher = room.pop(watcherProtocol, None)
            if(watcher):
                return watcher

    def _deleteRoomIfEmpty(self, room):
        if (self._rooms[room] == {}):
            with self._roomUpdate:
                self._rooms.pop(room)
                self._roomStates.pop(room)
    
    def getRoomPausedAndPosition(self, room):
        position = self._roomStates[room]["position"]
        paused = self._roomStates[room]["paused"]
        if (not paused):
            timePassedSinceSet = time.time() - self._roomStates[room]["lastUpdate"]
            position += timePassedSinceSet
        return paused, position

    def getMotd(self, userIp, username, room, clientVersion):
        oldClient = False
        if constants.WARN_OLD_CLIENTS:
            if int(clientVersion.replace(".","")) < int(constants.RECENT_CLIENT_THRESHOLD.replace(".","")):
                oldClient = True
        if(self._motdFilePath and os.path.isfile(self._motdFilePath)):
            tmpl = codecs.open(self._motdFilePath, "r", "utf-8-sig").read()
            args = dict(version=syncplay.version, userIp=userIp, username=username, room=room)
            try:
                motd = Template(tmpl).substitute(args)
                if oldClient:
                    motdwarning = getMessage("en","new-syncplay-available-motd-message").format(clientVersion)
                    motd = "{}\n{}".format(motdwarning, motd)
                return motd if len(motd) < constants.SERVER_MAX_TEMPLATE_LENGTH else getMessage("en", "server-messed-up-motd-too-long").format(constants.SERVER_MAX_TEMPLATE_LENGTH, len(motd))
            except ValueError: 
                return getMessage("en", "server-messed-up-motd-unescaped-placeholders")
        elif oldClient:
            return getMessage("en", "new-syncplay-available-motd-message").format(clientVersion)
        else:
            return ""

    def gethttpRequestReply(self):
        if(self._httpReplyFilePath and os.path.isfile(self._httpReplyFilePath)):
            tmpl = codecs.open(self._httpReplyFilePath, "r", "utf-8-sig").read()
            return tmpl.encode('utf-8')
        else:
            return getMessage("en", "server-default-http-reply")

    def sendState(self, watcherProtocol, doSeek = False, forcedUpdate = False):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        room = watcher.room
        paused, position = self.getRoomPausedAndPosition(room)
        setBy = self._roomStates[room]["setBy"]
        watcher.paused = paused
        watcher.position = position
        watcherProtocol.sendState(position, paused, doSeek, setBy, forcedUpdate)
        if(time.time() - watcher.lastUpdate > constants.PROTOCOL_TIMEOUT):
            watcherProtocol.drop()
            self.removeWatcher(watcherProtocol)

    def __shouldServerForceUpdateOnRoom(self, pauseChanged, doSeek):
        return doSeek or pauseChanged
            
    def __updatePausedState(self, paused, watcher):
        watcher.paused = paused
        if(self._roomStates[watcher.room]["paused"] <> paused):
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["paused"] = paused
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
            return True
    
    def __updatePositionState(self, position, doSeek, watcher):
        watcher.position = position
        if (doSeek):
            self._roomStates[watcher.room]["position"] = position
            self._roomStates[watcher.room]["setBy"] = watcher.name
            self._roomStates[watcher.room]["lastUpdate"] = time.time()
        else:
            setter = min(self._rooms[watcher.room].values())
            self._roomStates[watcher.room]["position"] = setter.position
            self._roomStates[watcher.room]["setBy"] = setter.name 
            self._roomStates[watcher.room]["lastUpdate"] = setter.lastUpdate
            

    def __notifyIrcBot(self, position, paused, doSeek, watcher, oldPosition, pauseChanged):
        if (self.ircVerbose):
            if (paused and pauseChanged):
                self.ircBot.sp_paused(watcher.name, watcher.room)
            elif (not paused and pauseChanged):
                self.ircBot.sp_unpaused(watcher.name, watcher.room)
            if (doSeek and position):
                self.ircBot.sp_seek(watcher.name, oldPosition, position, watcher.room)

    def updateWatcherState(self, watcherProtocol, position, paused, doSeek, messageAge):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        watcher.lastUpdate = time.time()
        if(watcher.file):
            oldPosition = self._roomStates[watcher.room]["position"]
            pauseChanged = False
            if(paused is not None):
                pauseChanged = self.__updatePausedState(paused, watcher)
            if(position is not None):
                if(not paused):
                    position += messageAge
                self.__updatePositionState(position, doSeek or pauseChanged, watcher)
            forceUpdate = self.__shouldServerForceUpdateOnRoom(pauseChanged, doSeek)
            if(forceUpdate):
                self.__notifyIrcBot(position, paused, doSeek, watcher, oldPosition, pauseChanged)
                l = lambda w: self.sendState(w, doSeek, forceUpdate)
                self.broadcastRoom(watcher.watcherProtocol, l)

    def removeWatcher(self, watcherProtocol):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, None, {"left": True})
        self.broadcast(watcherProtocol, l)
        self._removeWatcherFromTheRoom(watcherProtocol)
        watcher.deactivate()
        self._deleteRoomIfEmpty(watcher.room)
        if(self.ircVerbose):
            self.ircBot.sp_left(watcher.name, watcher.room)
            
    def watcherGetUsername(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).name
    
    def watcherGetRoom(self, watcherProtocol):
        return self.getWatcher(watcherProtocol).room
    
    def watcherSetRoom(self, watcherProtocol, room):
        watcher = self._removeWatcherFromTheRoom(watcherProtocol)
        if(not watcher):
            return
        watcher.resetStateTimer()
        oldRoom = watcher.room
        self._createRoomIfDoesntExist(room)
        with self._roomUpdate:
            self._rooms[room][watcherProtocol] = watcher
        self._deleteRoomIfEmpty(oldRoom)
        watcher.room = room
        self.sendState(watcherProtocol, True)
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, None, None)
        self.broadcast(watcherProtocol, l)
                
    def watcherSetFile(self, watcherProtocol, file_):
        watcher = self.getWatcher(watcherProtocol)
        if(not watcher):
            return
        watcher.file = file_
        l = lambda w: w.sendUserSetting(watcher.name, watcher.room, watcher.file, None)
        self.broadcast(watcherProtocol, l)
        if(self.ircVerbose):
            self.ircBot.sp_fileplaying(watcher.name, watcher.file['name'], watcher.room)
    
    def broadcastRoom(self, sender, what):
        room = self._rooms[self.watcherGetRoom(sender)]
        if(room):
            with self._roomUpdate:
                for receiver in room:
                    what(receiver)
                
    def broadcast(self, sender, what):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                    for receiver in room:
                        what(receiver)
    
    def _findUserByUsername(self, username):
        with self._roomUpdate:
            for room in self._rooms.itervalues():
                for user in room.itervalues():
                    if user.name == username:
                        return user
    
    def ircPauseRoom(self, setBy, paused):
        user = self._findUserByUsername(setBy)
        if(user):
            with self._roomUpdate:
                if(self._roomStates[user.room]['paused'] != paused):
                    self._roomStates[user.room]['paused'] = paused
                    self._roomStates[user.room]['setBy'] = "IRC: " + setBy
                    if(paused):
                        self.ircBot.sp_paused("IRC: " + user.name, user.room)
                    elif(not paused):
                        self.ircBot.sp_unpaused("IRC: " + user.name, user.room)
                    l = lambda w: self.sendState(w, False, 0, True)
                    self.broadcastRoom(user.watcherProtocol, l)
      
    
    def getRooms(self):
        return self._rooms.keys()
    
    def getRoomPosition(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["position"]
            
    def ircSetRoomPosition(self, setBy, time):
        user = self._findUserByUsername(setBy)
        if(user):
            with self._roomUpdate:
                oldPosition = self._roomStates[user.room]['paused']
                if(oldPosition - time > 1):
                    self._roomStates[user.room]['paused'] = time
                    self._roomStates[user.room]['setBy'] = "IRC: " + setBy 
                    self.ircBot.sp_seek(user.name, oldPosition, time, user.room)                
                    l = lambda w: self.sendState(w, True, 0, True)
                    self.broadcastRoom(user.watcherProtocol, l)
  
    
    def getRoomUsernames(self, room):
        l = []
        with self._roomUpdate:
            if room in self._rooms:
                for user in self._rooms[room].itervalues():
                    if(user.file):
                        l.append({'nick': user.name, 'file': user.file['name'], "duration": user.file['duration']})
                    else:
                        l.append({'nick': user.name, 'file': None, "duration": None})
        return l
            
    def isRoomPaused(self, room):
        with self._roomUpdate:
            if room in self._roomStates:
                return self._roomStates[room]["paused"]