Python3
This commit is contained in:
@@ -57,7 +57,7 @@ modules-enabled folder.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
mumo requires:
|
mumo requires:
|
||||||
* python 2.7*
|
* python >=3.2
|
||||||
* python-zeroc-ice
|
* python-zeroc-ice
|
||||||
* murmur >=1.2.3*
|
* murmur >=1.2.3*
|
||||||
|
|
||||||
|
|||||||
36
config.py
36
config.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,9 +29,10 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import ConfigParser
|
import configparser
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
"""
|
"""
|
||||||
Small abstraction for config loading
|
Small abstraction for config loading
|
||||||
@@ -41,28 +42,29 @@ class Config(object):
|
|||||||
if (filename and not default) or \
|
if (filename and not default) or \
|
||||||
(not filename and not default): return
|
(not filename and not default): return
|
||||||
|
|
||||||
sections = set(default.iterkeys())
|
sections = set(default.keys())
|
||||||
if filename:
|
if filename:
|
||||||
cfg = ConfigParser.RawConfigParser()
|
cfg = configparser.RawConfigParser()
|
||||||
cfg.optionxform = str
|
cfg.optionxform = str
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
cfg.readfp(f)
|
cfg.read_file(f)
|
||||||
sections.update(cfg.sections())
|
sections.update(cfg.sections())
|
||||||
|
|
||||||
for section in sections:
|
for section in sections:
|
||||||
if type(section) == types.FunctionType: continue
|
if isinstance(section, types.FunctionType):
|
||||||
|
continue
|
||||||
|
|
||||||
match = None
|
match = None
|
||||||
for default_section in default.iterkeys():
|
for default_section in default.keys():
|
||||||
try:
|
try:
|
||||||
if section == default_section or \
|
if section == default_section or \
|
||||||
(type(default_section) == types.FunctionType and default_section(section)):
|
(isinstance(default_section, types.FunctionType) and default_section(section)):
|
||||||
match = default_section
|
match = default_section
|
||||||
break
|
break
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if match == None:
|
if match is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
optiondefaults = default[match]
|
optiondefaults = default[match]
|
||||||
@@ -74,7 +76,7 @@ class Config(object):
|
|||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.__dict__[section] = cfg.items(section)
|
self.__dict__[section] = cfg.items(section)
|
||||||
except ConfigParser.NoSectionError:
|
except configparser.NoSectionError:
|
||||||
self.__dict__[section] = []
|
self.__dict__[section] = []
|
||||||
else:
|
else:
|
||||||
self.__dict__[section] = Config()
|
self.__dict__[section] = Config()
|
||||||
@@ -84,7 +86,7 @@ class Config(object):
|
|||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.__dict__[section].__dict__[name] = conv(cfg.get(section, name))
|
self.__dict__[section].__dict__[name] = conv(cfg.get(section, name))
|
||||||
except (ValueError, ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
except (ValueError, configparser.NoSectionError, configparser.NoOptionError):
|
||||||
self.__dict__[section].__dict__[name] = vdefault
|
self.__dict__[section].__dict__[name] = vdefault
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
@@ -93,33 +95,37 @@ class Config(object):
|
|||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return self.__dict__.__contains__(key)
|
return self.__dict__.__contains__(key)
|
||||||
|
|
||||||
|
|
||||||
def x2bool(s):
|
def x2bool(s):
|
||||||
"""
|
"""
|
||||||
Helper function to convert strings from the config to bool
|
Helper function to convert strings from the config to bool
|
||||||
"""
|
"""
|
||||||
if isinstance(s, bool):
|
if isinstance(s, bool):
|
||||||
return s
|
return s
|
||||||
elif isinstance(s, basestring):
|
elif isinstance(s, str):
|
||||||
return s.strip().lower() in ['1', 'true']
|
return s.strip().lower() in ['1', 'true']
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
def commaSeperatedIntegers(s):
|
def commaSeperatedIntegers(s):
|
||||||
"""
|
"""
|
||||||
Helper function to convert a string from the config
|
Helper function to convert a string from the config
|
||||||
containing comma seperated integers into a list of integers
|
containing comma seperated integers into a list of integers
|
||||||
"""
|
"""
|
||||||
return map(int, s.split(','))
|
return list(map(int, s.split(',')))
|
||||||
|
|
||||||
|
|
||||||
def commaSeperatedStrings(s):
|
def commaSeperatedStrings(s):
|
||||||
"""
|
"""
|
||||||
Helper function to convert a string from the config
|
Helper function to convert a string from the config
|
||||||
containing comma seperated strings into a list of strings
|
containing comma seperated strings into a list of strings
|
||||||
"""
|
"""
|
||||||
return map(str.strip, s.split(','))
|
return list(map(str.strip, s.split(',')))
|
||||||
|
|
||||||
|
|
||||||
def commaSeperatedBool(s):
|
def commaSeperatedBool(s):
|
||||||
"""
|
"""
|
||||||
Helper function to convert a string from the config
|
Helper function to convert a string from the config
|
||||||
containing comma seperated strings into a list of booleans
|
containing comma seperated strings into a list of booleans
|
||||||
"""
|
"""
|
||||||
return map(x2bool, s.split(','))
|
return list(map(x2bool, s.split(',')))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,11 +29,13 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import unittest
|
|
||||||
from config import Config, x2bool, commaSeperatedIntegers, commaSeperatedStrings, commaSeperatedBool
|
|
||||||
from tempfile import mkstemp
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import unittest
|
||||||
|
from tempfile import mkstemp
|
||||||
|
|
||||||
|
from config import Config, x2bool, commaSeperatedIntegers, commaSeperatedStrings, commaSeperatedBool
|
||||||
|
|
||||||
|
|
||||||
def create_file(content=None):
|
def create_file(content=None):
|
||||||
"""
|
"""
|
||||||
@@ -43,11 +45,12 @@ def create_file(content = None):
|
|||||||
fd, path = mkstemp()
|
fd, path = mkstemp()
|
||||||
f = os.fdopen(fd, "wb")
|
f = os.fdopen(fd, "wb")
|
||||||
if content:
|
if content:
|
||||||
f.write(content)
|
f.write(content.encode())
|
||||||
f.flush()
|
f.flush()
|
||||||
f.close()
|
f.close()
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
class ConfigTest(unittest.TestCase):
|
class ConfigTest(unittest.TestCase):
|
||||||
cfg_content = """[world]
|
cfg_content = """[world]
|
||||||
domination = True
|
domination = True
|
||||||
@@ -78,7 +81,6 @@ value = True
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def testEmpty(self):
|
def testEmpty(self):
|
||||||
path = create_file()
|
path = create_file()
|
||||||
try:
|
try:
|
||||||
@@ -116,8 +118,8 @@ value = True
|
|||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
cfg = Config(path, self.cfg_default)
|
cfg = Config(path, self.cfg_default)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print e
|
print(e)
|
||||||
assert (cfg.world.domination == True)
|
assert (cfg.world.domination == True)
|
||||||
assert (cfg.world.somestr == "Blabla")
|
assert (cfg.world.somestr == "Blabla")
|
||||||
assert (cfg.world.somenum == 10)
|
assert (cfg.world.somenum == 10)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ DESC="Mumo bot for Mumble"
|
|||||||
WORKDIR=/opt/mumo
|
WORKDIR=/opt/mumo
|
||||||
PIDDIR=$WORKDIR
|
PIDDIR=$WORKDIR
|
||||||
PIDFILE=$PIDDIR/mumo.pid
|
PIDFILE=$PIDDIR/mumo.pid
|
||||||
DAEMON=/usr/bin/python
|
DAEMON=/usr/bin/python3
|
||||||
USER=mumo
|
USER=mumo
|
||||||
GROUP=mumo
|
GROUP=mumo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -35,14 +35,12 @@
|
|||||||
# gamestate reported by Mumble positional audio plugins
|
# gamestate reported by Mumble positional audio plugins
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (MumoModule,
|
|
||||||
x2bool)
|
|
||||||
|
|
||||||
import re
|
|
||||||
try:
|
|
||||||
import json
|
import json
|
||||||
except ImportError: # Fallback for python < 2.6
|
import re
|
||||||
import simplejson as json
|
|
||||||
|
from config import x2bool
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class bf2(MumoModule):
|
class bf2(MumoModule):
|
||||||
default_config = {'bf2': (
|
default_config = {'bf2': (
|
||||||
@@ -127,7 +125,8 @@ class bf2(MumoModule):
|
|||||||
manager.subscribeServerCallbacks(self, servers)
|
manager.subscribeServerCallbacks(self, servers)
|
||||||
manager.subscribeMetaCallbacks(self, servers)
|
manager.subscribeMetaCallbacks(self, servers)
|
||||||
|
|
||||||
def disconnected(self): pass
|
def disconnected(self):
|
||||||
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Module specific state handling code
|
# --- Module specific state handling code
|
||||||
@@ -175,12 +174,14 @@ class bf2(MumoModule):
|
|||||||
nli = False
|
nli = False
|
||||||
|
|
||||||
if not oli and nli:
|
if not oli and nli:
|
||||||
log.debug("User '%s' (%d|%d) on server %d now linked", newstate.name, newstate.session, newstate.userid, sid)
|
log.debug("User '%s' (%d|%d) on server %d now linked", newstate.name, newstate.session, newstate.userid,
|
||||||
|
sid)
|
||||||
server.addUserToGroup(0, session, "bf2_linked")
|
server.addUserToGroup(0, session, "bf2_linked")
|
||||||
|
|
||||||
if opi and opc:
|
if opi and opc:
|
||||||
squadname = self.id_to_squad_name[opi["squad"]]
|
squadname = self.id_to_squad_name[opi["squad"]]
|
||||||
log.debug("Removing user '%s' (%d|%d) on server %d from groups of game %s / squad %s", newstate.name, newstate.session, newstate.userid, sid, og or ogcfgname, squadname)
|
log.debug("Removing user '%s' (%d|%d) on server %d from groups of game %s / squad %s", newstate.name,
|
||||||
|
newstate.session, newstate.userid, sid, og or ogcfgname, squadname)
|
||||||
server.removeUserFromGroup(ogcfg["base"], session, "bf2_%s_game" % (og or ogcfgname))
|
server.removeUserFromGroup(ogcfg["base"], session, "bf2_%s_game" % (og or ogcfgname))
|
||||||
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_commander")
|
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_commander")
|
||||||
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_squad_leader")
|
server.removeUserFromGroup(ogcfg[opi["team"]], session, "bf2_squad_leader")
|
||||||
@@ -191,7 +192,8 @@ class bf2(MumoModule):
|
|||||||
newstate.channel = ogcfg["left"]
|
newstate.channel = ogcfg["left"]
|
||||||
|
|
||||||
if npc and npi:
|
if npc and npi:
|
||||||
log.debug("Updating user '%s' (%d|%d) on server %d in game %s: %s", newstate.name, newstate.session, newstate.userid, sid, ng or ngcfgname, str(npi))
|
log.debug("Updating user '%s' (%d|%d) on server %d in game %s: %s", newstate.name, newstate.session,
|
||||||
|
newstate.userid, sid, ng or ngcfgname, str(npi))
|
||||||
|
|
||||||
squadname = self.id_to_squad_name[npi["squad"]]
|
squadname = self.id_to_squad_name[npi["squad"]]
|
||||||
|
|
||||||
@@ -239,11 +241,12 @@ class bf2(MumoModule):
|
|||||||
newstate.channel = ngcfg[channame]
|
newstate.channel = ngcfg[channame]
|
||||||
|
|
||||||
if oli and not nli:
|
if oli and not nli:
|
||||||
log.debug("User '%s' (%d|%d) on server %d no longer linked", newstate.name, newstate.session, newstate.userid, sid)
|
log.debug("User '%s' (%d|%d) on server %d no longer linked", newstate.name, newstate.session,
|
||||||
|
newstate.userid, sid)
|
||||||
server.removeUserFromGroup(0, session, "bf2_linked")
|
server.removeUserFromGroup(0, session, "bf2_linked")
|
||||||
|
|
||||||
if newstate.channel >= 0 and newoldchannel != newstate.channel:
|
if 0 <= newstate.channel != newoldchannel:
|
||||||
if ng == None:
|
if ng is None:
|
||||||
log.debug("Moving '%s' leaving %s to channel %s", newstate.name, og or ogcfgname, channame)
|
log.debug("Moving '%s' leaving %s to channel %s", newstate.name, og or ogcfgname, channame)
|
||||||
else:
|
else:
|
||||||
log.debug("Moving '%s' @ %s to channel %s", newstate.name, ng or ngcfgname, channame)
|
log.debug("Moving '%s' @ %s to channel %s", newstate.name, ng or ngcfgname, channame)
|
||||||
@@ -294,12 +297,13 @@ class bf2(MumoModule):
|
|||||||
state.is_linked = True
|
state.is_linked = True
|
||||||
if state.identity and len(splitcontext) == 1:
|
if state.identity and len(splitcontext) == 1:
|
||||||
# LEGACY: Assume broken Ice 3.2 which doesn't transmit context after \0
|
# LEGACY: Assume broken Ice 3.2 which doesn't transmit context after \0
|
||||||
splitcontext.append('{"ipport":""}') # Obviously this doesn't give full functionality but it doesn't crash either ;-)
|
splitcontext.append(
|
||||||
|
'{"ipport":""}') # Obviously this doesn't give full functionality but it doesn't crash either ;-)
|
||||||
|
|
||||||
if state.is_linked and len(splitcontext) == 2 and state.identity:
|
if state.is_linked and len(splitcontext) == 2 and state.identity:
|
||||||
try:
|
try:
|
||||||
context = json.loads(splitcontext[1])
|
context = json.loads(splitcontext[1])
|
||||||
verify(context, "ipport", basestring)
|
verify(context, "ipport", str)
|
||||||
|
|
||||||
for i in range(cfg.bf2.gamecount):
|
for i in range(cfg.bf2.gamecount):
|
||||||
# Try to find a matching game
|
# Try to find a matching game
|
||||||
@@ -307,7 +311,7 @@ class bf2(MumoModule):
|
|||||||
gamecfg = getattr(cfg, gamename)
|
gamecfg = getattr(cfg, gamename)
|
||||||
|
|
||||||
if gamecfg.mumble_server == server.id():
|
if gamecfg.mumble_server == server.id():
|
||||||
not_matched = (gamecfg.ipport_filter.match(context["ipport"]) == None)
|
not_matched = (gamecfg.ipport_filter.match(context["ipport"]) is None)
|
||||||
if not_matched == gamecfg.ipport_filter_negate:
|
if not_matched == gamecfg.ipport_filter_negate:
|
||||||
break
|
break
|
||||||
gamename = None
|
gamename = None
|
||||||
@@ -319,8 +323,9 @@ class bf2(MumoModule):
|
|||||||
context["gamename"] = gamename
|
context["gamename"] = gamename
|
||||||
state.parsedcontext = context
|
state.parsedcontext = context
|
||||||
|
|
||||||
except (ValueError, KeyError, AttributeError), e:
|
except (ValueError, KeyError, AttributeError) as e:
|
||||||
log.debug("Invalid context for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid, sid, repr(e))
|
log.debug("Invalid context for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid,
|
||||||
|
sid, repr(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
identity = json.loads(state.identity)
|
identity = json.loads(state.identity)
|
||||||
@@ -329,7 +334,7 @@ class bf2(MumoModule):
|
|||||||
verify(identity, "squad", int)
|
verify(identity, "squad", int)
|
||||||
if identity["squad"] < 0 or identity["squad"] > 9:
|
if identity["squad"] < 0 or identity["squad"] > 9:
|
||||||
raise ValueError("Invalid squad number")
|
raise ValueError("Invalid squad number")
|
||||||
verify(identity, "team", basestring)
|
verify(identity, "team", str)
|
||||||
if identity["team"] != "opfor" and identity["team"] != "blufor":
|
if identity["team"] != "opfor" and identity["team"] != "blufor":
|
||||||
raise ValueError("Invalid team identified")
|
raise ValueError("Invalid team identified")
|
||||||
# LEGACY: Ice 3.2 cannot handle unicode strings
|
# LEGACY: Ice 3.2 cannot handle unicode strings
|
||||||
@@ -337,8 +342,9 @@ class bf2(MumoModule):
|
|||||||
|
|
||||||
state.parsedidentity = identity
|
state.parsedidentity = identity
|
||||||
|
|
||||||
except (KeyError, ValueError), e:
|
except (KeyError, ValueError) as e:
|
||||||
log.debug("Invalid identity for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid, sid, repr(e))
|
log.debug("Invalid identity for %s (%d|%d) on server %d: %s", state.name, state.session, state.userid,
|
||||||
|
sid, repr(e))
|
||||||
|
|
||||||
# Update state and remember it
|
# Update state and remember it
|
||||||
self.update_state(server, self.sessions[sid][state.session], state)
|
self.update_state(server, self.sessions[sid][state.session], state)
|
||||||
@@ -352,7 +358,8 @@ class bf2(MumoModule):
|
|||||||
try:
|
try:
|
||||||
sid = server.id()
|
sid = server.id()
|
||||||
del self.sessions[sid][state.session]
|
del self.sessions[sid][state.session]
|
||||||
except KeyError: pass
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
def userStateChanged(self, server, state, context=None):
|
def userStateChanged(self, server, state, context=None):
|
||||||
self.handle(server, state)
|
self.handle(server, state)
|
||||||
@@ -360,10 +367,17 @@ class bf2(MumoModule):
|
|||||||
def userConnected(self, server, state, context=None):
|
def userConnected(self, server, state, context=None):
|
||||||
self.handle(server, state)
|
self.handle(server, state)
|
||||||
|
|
||||||
def userTextMessage(self, server, user, message, current=None): pass
|
def userTextMessage(self, server, user, message, current=None):
|
||||||
def channelCreated(self, server, state, context = None): pass
|
pass
|
||||||
def channelRemoved(self, server, state, context = None): pass
|
|
||||||
def channelStateChanged(self, server, state, context = None): pass
|
def channelCreated(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelRemoved(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelStateChanged(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Meta callback functions
|
# --- Meta callback functions
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -37,15 +37,11 @@
|
|||||||
# once they become active again
|
# once they become active again
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (commaSeperatedIntegers,
|
|
||||||
commaSeperatedBool,
|
|
||||||
commaSeperatedStrings,
|
|
||||||
MumoModule)
|
|
||||||
|
|
||||||
from threading import Timer
|
|
||||||
import re
|
import re
|
||||||
|
from threading import Timer
|
||||||
|
|
||||||
|
from config import commaSeperatedIntegers, commaSeperatedBool, commaSeperatedStrings
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class idlemove(MumoModule):
|
class idlemove(MumoModule):
|
||||||
@@ -54,7 +50,7 @@ class idlemove(MumoModule):
|
|||||||
('servers', commaSeperatedIntegers, []),
|
('servers', commaSeperatedIntegers, []),
|
||||||
),
|
),
|
||||||
lambda x: re.match('(all)|(server_\d+)', x): (
|
lambda x: re.match('(all)|(server_\d+)', x): (
|
||||||
('threshold', commaSeperatedIntegers, [3600]),
|
['threshold', commaSeperatedIntegers, [3600]],
|
||||||
('mute', commaSeperatedBool, [True]),
|
('mute', commaSeperatedBool, [True]),
|
||||||
('deafen', commaSeperatedBool, [False]),
|
('deafen', commaSeperatedBool, [False]),
|
||||||
('channel', commaSeperatedIntegers, [1]),
|
('channel', commaSeperatedIntegers, [1]),
|
||||||
@@ -105,10 +101,8 @@ class idlemove(MumoModule):
|
|||||||
servers = [meta.getServer(server) for server in cfg.idlemove.servers]
|
servers = [meta.getServer(server) for server in cfg.idlemove.servers]
|
||||||
|
|
||||||
for server in servers:
|
for server in servers:
|
||||||
if not server: continue
|
|
||||||
|
|
||||||
if server:
|
if server:
|
||||||
for user in server.getUsers().itervalues():
|
for user in server.getUsers().values():
|
||||||
self.UpdateUserAutoAway(server, user)
|
self.UpdateUserAutoAway(server, user)
|
||||||
finally:
|
finally:
|
||||||
# Renew the timer
|
# Renew the timer
|
||||||
@@ -135,7 +129,6 @@ class idlemove(MumoModule):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Remember values so we can see changes later
|
# Remember values so we can see changes later
|
||||||
threshold = None
|
|
||||||
mute = user.mute
|
mute = user.mute
|
||||||
deafen = user.deaf
|
deafen = user.deaf
|
||||||
channel = user.channel
|
channel = user.channel
|
||||||
@@ -159,11 +152,8 @@ class idlemove(MumoModule):
|
|||||||
log.warning("Incomplete configuration for stage %d of server %i, ignored", i, server.id())
|
log.warning("Incomplete configuration for stage %d of server %i, ignored", i, server.id())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if user.idlesecs > threshold and\
|
if user.idlesecs > threshold and user.channel not in scfg.channel_whitelist and (
|
||||||
user.channel not in scfg.channel_whitelist and\
|
source_channel == -1 or user.channel == source_channel or user.channel == channel):
|
||||||
(source_channel == -1 or\
|
|
||||||
user.channel == source_channel or\
|
|
||||||
user.channel == channel):
|
|
||||||
|
|
||||||
over_threshold = True
|
over_threshold = True
|
||||||
# Update if state changes needed
|
# Update if state changes needed
|
||||||
@@ -171,13 +161,15 @@ class idlemove(MumoModule):
|
|||||||
update = True
|
update = True
|
||||||
if user.mute != mute:
|
if user.mute != mute:
|
||||||
update = True
|
update = True
|
||||||
if channel >= 0 and user.channel != channel:
|
if 0 <= channel != user.channel:
|
||||||
update = True
|
update = True
|
||||||
|
|
||||||
if update:
|
if update:
|
||||||
index.add(user.session)
|
index.add(user.session)
|
||||||
log.info('%ds > %ds: State transition for user %s (%d/%d) from mute %s -> %s / deaf %s -> %s | channel %d -> %d on server %d',
|
log.info(
|
||||||
user.idlesecs, threshold, user.name, user.session, user.userid, user.mute, mute, user.deaf, deafen,
|
'%ds > %ds: State transition for user %s (%d/%d) from mute %s -> %s / deaf %s -> %s | channel %d -> %d on server %d',
|
||||||
|
user.idlesecs, threshold, user.name, user.session, user.userid, user.mute, mute, user.deaf,
|
||||||
|
deafen,
|
||||||
user.channel, channel, server.id())
|
user.channel, channel, server.id())
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -209,11 +201,20 @@ class idlemove(MumoModule):
|
|||||||
def userStateChanged(self, server, state, context=None):
|
def userStateChanged(self, server, state, context=None):
|
||||||
self.UpdateUserAutoAway(server, state)
|
self.UpdateUserAutoAway(server, state)
|
||||||
|
|
||||||
def userConnected(self, server, state, context=None): pass # Unused callbacks
|
def userConnected(self, server, state, context=None):
|
||||||
def userTextMessage(self, server, user, message, current=None): pass
|
pass # Unused callbacks
|
||||||
def channelCreated(self, server, state, context=None): pass
|
|
||||||
def channelRemoved(self, server, state, context=None): pass
|
def userTextMessage(self, server, user, message, current=None):
|
||||||
def channelStateChanged(self, server, state, context=None): pass
|
pass
|
||||||
|
|
||||||
|
def channelCreated(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelRemoved(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelStateChanged(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Meta callback functions
|
# --- Meta callback functions
|
||||||
@@ -228,4 +229,3 @@ class idlemove(MumoModule):
|
|||||||
sid = server.id()
|
sid = server.id()
|
||||||
self.affectedusers[sid] = set()
|
self.affectedusers[sid] = set()
|
||||||
self.log().debug('Server %d gone', sid)
|
self.log().debug('Server %d gone', sid)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -35,10 +35,11 @@
|
|||||||
# they connect regardless of which channel they were in when they left.
|
# they connect regardless of which channel they were in when they left.
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (commaSeperatedIntegers,
|
|
||||||
MumoModule)
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from config import commaSeperatedIntegers
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class onjoin(MumoModule):
|
class onjoin(MumoModule):
|
||||||
default_config = {'onjoin': (
|
default_config = {'onjoin': (
|
||||||
@@ -67,7 +68,8 @@ class onjoin(MumoModule):
|
|||||||
|
|
||||||
manager.subscribeServerCallbacks(self, servers)
|
manager.subscribeServerCallbacks(self, servers)
|
||||||
|
|
||||||
def disconnected(self): pass
|
def disconnected(self):
|
||||||
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Server callback functions
|
# --- Server callback functions
|
||||||
@@ -82,17 +84,30 @@ class onjoin(MumoModule):
|
|||||||
scfg = self.cfg().all
|
scfg = self.cfg().all
|
||||||
|
|
||||||
if state.channel != scfg.channel:
|
if state.channel != scfg.channel:
|
||||||
log.debug("Moving user '%s' from channel %d to %d on server %d", state.name, state.channel, scfg.channel, sid)
|
log.debug("Moving user '%s' from channel %d to %d on server %d", state.name, state.channel, scfg.channel,
|
||||||
|
sid)
|
||||||
state.channel = scfg.channel
|
state.channel = scfg.channel
|
||||||
|
|
||||||
try:
|
try:
|
||||||
server.setState(state)
|
server.setState(state)
|
||||||
except self.murmur.InvalidChannelException:
|
except self.murmur.InvalidChannelException:
|
||||||
log.error("Moving user '%s' failed, target channel %d does not exist on server %d", state.name, scfg.channel, sid)
|
log.error("Moving user '%s' failed, target channel %d does not exist on server %d", state.name,
|
||||||
|
scfg.channel, sid)
|
||||||
|
|
||||||
def userDisconnected(self, server, state, context = None): pass
|
def userDisconnected(self, server, state, context=None):
|
||||||
def userStateChanged(self, server, state, context = None): pass
|
pass
|
||||||
def userTextMessage(self, server, user, message, current=None): pass
|
|
||||||
def channelCreated(self, server, state, context = None): pass
|
def userStateChanged(self, server, state, context=None):
|
||||||
def channelRemoved(self, server, state, context = None): pass
|
pass
|
||||||
def channelStateChanged(self, server, state, context = None): pass
|
|
||||||
|
def userTextMessage(self, server, user, message, current=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelCreated(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelRemoved(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelStateChanged(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2015 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2015 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -35,10 +35,12 @@
|
|||||||
# entries to a user's context menu.
|
# entries to a user's context menu.
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (commaSeperatedIntegers,
|
|
||||||
MumoModule)
|
|
||||||
import cgi
|
import cgi
|
||||||
|
|
||||||
|
from config import commaSeperatedIntegers
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class samplecontext(MumoModule):
|
class samplecontext(MumoModule):
|
||||||
default_config = {'samplecontext': (
|
default_config = {'samplecontext': (
|
||||||
('servers', commaSeperatedIntegers, []),
|
('servers', commaSeperatedIntegers, []),
|
||||||
@@ -124,9 +126,13 @@ class samplecontext(MumoModule):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def userDisconnected(self, server, state, context=None): pass
|
def userDisconnected(self, server, state, context=None): pass
|
||||||
def userStateChanged(self, server, state, context = None): pass
|
|
||||||
def userTextMessage(self, server, user, message, current=None): pass
|
|
||||||
def channelCreated(self, server, state, context = None): pass
|
|
||||||
def channelRemoved(self, server, state, context = None): pass
|
|
||||||
def channelStateChanged(self, server, state, context = None): pass
|
|
||||||
|
|
||||||
|
def userStateChanged(self, server, state, context=None): pass
|
||||||
|
|
||||||
|
def userTextMessage(self, server, user, message, current=None): pass
|
||||||
|
|
||||||
|
def channelCreated(self, server, state, context=None): pass
|
||||||
|
|
||||||
|
def channelRemoved(self, server, state, context=None): pass
|
||||||
|
|
||||||
|
def channelStateChanged(self, server, state, context=None): pass
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -34,11 +34,12 @@
|
|||||||
# This module allows asking the server for the last time it saw a specific player
|
# This module allows asking the server for the last time it saw a specific player
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (commaSeperatedIntegers,
|
|
||||||
MumoModule)
|
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from config import commaSeperatedIntegers
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class seen(MumoModule):
|
class seen(MumoModule):
|
||||||
default_config = {'seen': (
|
default_config = {'seen': (
|
||||||
('servers', commaSeperatedIntegers, []),
|
('servers', commaSeperatedIntegers, []),
|
||||||
@@ -62,7 +63,8 @@ class seen(MumoModule):
|
|||||||
|
|
||||||
manager.subscribeServerCallbacks(self, servers)
|
manager.subscribeServerCallbacks(self, servers)
|
||||||
|
|
||||||
def disconnected(self): pass
|
def disconnected(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def sendMessage(self, server, user, message, msg):
|
def sendMessage(self, server, user, message, msg):
|
||||||
if message.channels:
|
if message.channels:
|
||||||
@@ -70,6 +72,7 @@ class seen(MumoModule):
|
|||||||
else:
|
else:
|
||||||
server.sendMessage(user.session, msg)
|
server.sendMessage(user.session, msg)
|
||||||
server.sendMessage(message.sessions[0], msg)
|
server.sendMessage(message.sessions[0], msg)
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Server callback functions
|
# --- Server callback functions
|
||||||
#
|
#
|
||||||
@@ -91,7 +94,7 @@ class seen(MumoModule):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check online users
|
# Check online users
|
||||||
for cuser in server.getUsers().itervalues():
|
for cuser in server.getUsers().values():
|
||||||
if tuname == cuser.name:
|
if tuname == cuser.name:
|
||||||
msg = "User '%s' is currently online, has been idle for %s" % (tuname,
|
msg = "User '%s' is currently online, has been idle for %s" % (tuname,
|
||||||
timedelta(seconds=cuser.idlesecs))
|
timedelta(seconds=cuser.idlesecs))
|
||||||
@@ -99,7 +102,7 @@ class seen(MumoModule):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check registrations
|
# Check registrations
|
||||||
for cuid, cuname in server.getRegisteredUsers(tuname).iteritems():
|
for cuid, cuname in server.getRegisteredUsers(tuname).items():
|
||||||
if cuname == tuname:
|
if cuname == tuname:
|
||||||
ureg = server.getRegistration(cuid)
|
ureg = server.getRegistration(cuid)
|
||||||
if ureg:
|
if ureg:
|
||||||
@@ -112,12 +115,20 @@ class seen(MumoModule):
|
|||||||
msg = "I don't know who user '%s' is" % tuname
|
msg = "I don't know who user '%s' is" % tuname
|
||||||
self.sendMessage(server, user, message, msg)
|
self.sendMessage(server, user, message, msg)
|
||||||
|
|
||||||
|
def userConnected(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def userDisconnected(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
def userConnected(self, server, state, context = None): pass
|
def userStateChanged(self, server, state, context=None):
|
||||||
def userDisconnected(self, server, state, context = None): pass
|
pass
|
||||||
def userStateChanged(self, server, state, context = None): pass
|
|
||||||
|
|
||||||
def channelCreated(self, server, state, context = None): pass
|
def channelCreated(self, server, state, context=None):
|
||||||
def channelRemoved(self, server, state, context = None): pass
|
pass
|
||||||
def channelStateChanged(self, server, state, context = None): pass
|
|
||||||
|
def channelRemoved(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def channelStateChanged(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
from source import source
|
from .source import source
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
|
||||||
# TODO: Functions returning channels probably should return a dict instead of a tuple
|
# TODO: Functions returning channels probably should return a dict instead of a tuple
|
||||||
|
|
||||||
class SourceDB(object):
|
class SourceDB(object):
|
||||||
@@ -80,18 +81,18 @@ class SourceDB(object):
|
|||||||
"""
|
"""
|
||||||
True if the database is correctly initialized
|
True if the database is correctly initialized
|
||||||
"""
|
"""
|
||||||
return self.db != None
|
return self.db is not None
|
||||||
|
|
||||||
|
|
||||||
def nameFor(self, sid, game, server=NO_SERVER, team=NO_TEAM, default=""):
|
def nameFor(self, sid, game, server=NO_SERVER, team=NO_TEAM, default=""):
|
||||||
"""
|
"""
|
||||||
Returns the mapped name for the given parameters or default if no
|
Returns the mapped name for the given parameters or default if no
|
||||||
mapping exists.
|
mapping exists.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
v = self.db.execute("SELECT name FROM mapped_names WHERE sid is ? and game is ? and server is ? and team is ?", [sid, game, server, team]).fetchone()
|
v = self.db.execute("SELECT name FROM mapped_names WHERE sid is ? and game is ? and server is ? and team is ?",
|
||||||
|
[sid, game, server, team]).fetchone()
|
||||||
return v[0] if v else default
|
return v[0] if v else default
|
||||||
|
|
||||||
def mapName(self, name, sid, game, server=NO_SERVER, team=NO_TEAM):
|
def mapName(self, name, sid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
@@ -100,10 +101,11 @@ class SourceDB(object):
|
|||||||
to the given name. The mapping can then be retrieved with nameFor() in
|
to the given name. The mapping can then be retrieved with nameFor() in
|
||||||
the future.
|
the future.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
self.db.execute("INSERT OR REPLACE into mapped_names (sid, game, server, team, name) VALUES (?,?,?,?,?)",[sid, game, server, team, name])
|
self.db.execute("INSERT OR REPLACE into mapped_names (sid, game, server, team, name) VALUES (?,?,?,?,?)",
|
||||||
|
[sid, game, server, team, name])
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
def cidFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
def cidFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
@@ -115,10 +117,12 @@ class SourceDB(object):
|
|||||||
If no channel matching the arguments has been registered with the database
|
If no channel matching the arguments has been registered with the database
|
||||||
before None is returned.
|
before None is returned.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
v = self.db.execute("SELECT cid FROM controlled_channels WHERE sid is ? and game is ? and server is ? and team is ?", [sid, game, server, team]).fetchone()
|
v = self.db.execute(
|
||||||
|
"SELECT cid FROM controlled_channels WHERE sid is ? and game is ? and server is ? and team is ?",
|
||||||
|
[sid, game, server, team]).fetchone()
|
||||||
return v[0] if v else None
|
return v[0] if v else None
|
||||||
|
|
||||||
def channelForCid(self, sid, cid):
|
def channelForCid(self, sid, cid):
|
||||||
@@ -126,18 +130,22 @@ class SourceDB(object):
|
|||||||
Returns a tuple of (sid, cid, game, server, team) for the given cid.
|
Returns a tuple of (sid, cid, game, server, team) for the given cid.
|
||||||
Returns None if the cid is unknown.
|
Returns None if the cid is unknown.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and cid != None)
|
assert (sid is not None and cid is not None)
|
||||||
return self.db.execute("SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and cid is ?", [sid, cid]).fetchone()
|
return self.db.execute(
|
||||||
|
"SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and cid is ?",
|
||||||
|
[sid, cid]).fetchone()
|
||||||
|
|
||||||
def channelFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
def channelFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
"""
|
"""
|
||||||
Returns matching channel as (sid, cid, game, server, team) tuple. Matching
|
Returns matching channel as (sid, cid, game, server, team) tuple. Matching
|
||||||
behavior is the same as for cidFor()
|
behavior is the same as for cidFor()
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
v = self.db.execute("SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and game is ? and server is ? and team is ?", [sid, game, server, team]).fetchone()
|
v = self.db.execute(
|
||||||
|
"SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and game is ? and server is ? and team is ?",
|
||||||
|
[sid, game, server, team]).fetchone()
|
||||||
return v
|
return v
|
||||||
|
|
||||||
def channelsFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
def channelsFor(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
@@ -147,20 +155,23 @@ class SourceDB(object):
|
|||||||
This can be limited by passing server (and team).
|
This can be limited by passing server (and team).
|
||||||
Returns empty list if no matches are found.
|
Returns empty list if no matches are found.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
suffix, params = self.__whereClauseForOptionals(server, team)
|
suffix, params = self.__whereClauseForOptionals(server, team)
|
||||||
return self.db.execute("SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and game is ?" + suffix, [sid, game] + params).fetchall()
|
return self.db.execute(
|
||||||
|
"SELECT sid, cid, game, server, team FROM controlled_channels WHERE sid is ? and game is ?" + suffix,
|
||||||
|
[sid, game] + params).fetchall()
|
||||||
|
|
||||||
def registerChannel(self, sid, cid, game, server=NO_SERVER, team=NO_TEAM):
|
def registerChannel(self, sid, cid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
"""
|
"""
|
||||||
Register a given channel with the database.
|
Register a given channel with the database.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
self.db.execute("INSERT INTO controlled_channels (sid, cid, game, server, team) VALUES (?,?,?,?,?)", [sid, cid, game, server, team])
|
self.db.execute("INSERT INTO controlled_channels (sid, cid, game, server, team) VALUES (?,?,?,?,?)",
|
||||||
|
[sid, cid, game, server, team])
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -173,17 +184,17 @@ class SourceDB(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if server != self.NO_SERVER and team != self.NO_TEAM:
|
if server != self.NO_SERVER and team != self.NO_TEAM:
|
||||||
return (" and server is ? and team is ?", [server, team])
|
return " and server is ? and team is ?", [server, team]
|
||||||
elif server != self.NO_SERVER:
|
elif server != self.NO_SERVER:
|
||||||
return (" and server is ?", [server])
|
return " and server is ?", [server]
|
||||||
else:
|
else:
|
||||||
return ("", [])
|
return "", []
|
||||||
|
|
||||||
def unregisterChannel(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
def unregisterChannel(self, sid, game, server=NO_SERVER, team=NO_TEAM):
|
||||||
"""
|
"""
|
||||||
Unregister a channel previously registered with the database.
|
Unregister a channel previously registered with the database.
|
||||||
"""
|
"""
|
||||||
assert(sid != None and game != None)
|
assert (sid is not None and game is not None)
|
||||||
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
assert (not (team != self.NO_TEAM and server == self.NO_SERVER))
|
||||||
|
|
||||||
suffix, params = self.__whereClauseForOptionals(server, team)
|
suffix, params = self.__whereClauseForOptionals(server, team)
|
||||||
@@ -194,7 +205,7 @@ class SourceDB(object):
|
|||||||
"""
|
"""
|
||||||
Drops channel with given sid + cid
|
Drops channel with given sid + cid
|
||||||
"""
|
"""
|
||||||
assert(sid != None and cid != None)
|
assert (sid is not None and cid is not None)
|
||||||
|
|
||||||
self.db.execute("DELETE FROM controlled_channels WHERE sid is ? and cid is ?", [sid, cid])
|
self.db.execute("DELETE FROM controlled_channels WHERE sid is ? and cid is ?", [sid, cid])
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
@@ -203,10 +214,10 @@ class SourceDB(object):
|
|||||||
"""
|
"""
|
||||||
Returns true if a channel with given sid and cid is registered
|
Returns true if a channel with given sid and cid is registered
|
||||||
"""
|
"""
|
||||||
assert(sid != None and cid != None)
|
assert (sid is not None and cid is not None)
|
||||||
|
|
||||||
res = self.db.execute("SELECT cid FROM controlled_channels WHERE sid is ? and cid is ?", [sid, cid]).fetchone()
|
res = self.db.execute("SELECT cid FROM controlled_channels WHERE sid is ? and cid is ?", [sid, cid]).fetchone()
|
||||||
return res != None
|
return res is not None
|
||||||
|
|
||||||
def registeredChannels(self):
|
def registeredChannels(self):
|
||||||
"""
|
"""
|
||||||
@@ -222,5 +233,6 @@ class SourceDB(object):
|
|||||||
self.db.execute("DELETE FROM controlled_channels")
|
self.db.execute("DELETE FROM controlled_channels")
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,9 +29,11 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import unittest
|
|
||||||
from db import SourceDB
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from .db import SourceDB
|
||||||
|
|
||||||
|
|
||||||
class SourceDBTest(unittest.TestCase):
|
class SourceDBTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -40,7 +42,6 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
def testOk(self):
|
def testOk(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
@@ -49,7 +50,11 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testSingleChannel(self):
|
def testSingleChannel(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 5; cid = 10; game = "tf2"; server = "abc[]def"; team = "1"
|
sid = 5
|
||||||
|
cid = 10
|
||||||
|
game = "tf2"
|
||||||
|
server = "abc[]def"
|
||||||
|
team = "1"
|
||||||
self.assertTrue(self.db.registerChannel(sid, cid, game, server, team))
|
self.assertTrue(self.db.registerChannel(sid, cid, game, server, team))
|
||||||
self.assertEqual(self.db.cidFor(sid, game, server, team), cid)
|
self.assertEqual(self.db.cidFor(sid, game, server, team), cid)
|
||||||
self.db.unregisterChannel(sid, game, server, team)
|
self.db.unregisterChannel(sid, game, server, team)
|
||||||
@@ -58,8 +63,13 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testChannelTree(self):
|
def testChannelTree(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 5; game = "tf2"; server = "abc[]def"; team = 0
|
sid = 5
|
||||||
bcid = 10; scid = 11; tcid = 12
|
game = "tf2"
|
||||||
|
server = "abc[]def"
|
||||||
|
team = 0
|
||||||
|
bcid = 10
|
||||||
|
scid = 11
|
||||||
|
tcid = 12
|
||||||
|
|
||||||
self.assertTrue(self.db.registerChannel(sid, 1, "canary", server, team))
|
self.assertTrue(self.db.registerChannel(sid, 1, "canary", server, team))
|
||||||
|
|
||||||
@@ -115,7 +125,9 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testDropChannel(self):
|
def testDropChannel(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 1; cid = 5; game = "tf"
|
sid = 1
|
||||||
|
cid = 5
|
||||||
|
game = "tf"
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
self.db.dropChannel(sid + 1, cid)
|
self.db.dropChannel(sid + 1, cid)
|
||||||
self.assertEqual(self.db.cidFor(sid, game), cid)
|
self.assertEqual(self.db.cidFor(sid, game), cid)
|
||||||
@@ -125,15 +137,19 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testRegisteredChannels(self):
|
def testRegisteredChannels(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 5; game = "tf2"; server = "abc[]def"; team = 1
|
sid = 5
|
||||||
bcid = 10; scid = 11; tcid = 12;
|
game = "tf2"
|
||||||
|
server = "abc[]def"
|
||||||
|
team = 1
|
||||||
|
bcid = 10
|
||||||
|
scid = 11
|
||||||
|
tcid = 12
|
||||||
|
|
||||||
self.db.registerChannel(sid, bcid, game)
|
self.db.registerChannel(sid, bcid, game)
|
||||||
self.db.registerChannel(sid, scid, game, server)
|
self.db.registerChannel(sid, scid, game, server)
|
||||||
self.db.registerChannel(sid + 1, tcid, game, server, team)
|
self.db.registerChannel(sid + 1, tcid, game, server, team)
|
||||||
self.db.registerChannel(sid, tcid, game, server, team)
|
self.db.registerChannel(sid, tcid, game, server, team)
|
||||||
|
|
||||||
|
|
||||||
expected = [(sid, bcid, game, self.db.NO_SERVER, self.db.NO_TEAM),
|
expected = [(sid, bcid, game, self.db.NO_SERVER, self.db.NO_TEAM),
|
||||||
(sid, scid, game, server, self.db.NO_TEAM),
|
(sid, scid, game, server, self.db.NO_TEAM),
|
||||||
(sid, tcid, game, server, team),
|
(sid, tcid, game, server, team),
|
||||||
@@ -143,7 +159,9 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testIsRegisteredChannel(self):
|
def testIsRegisteredChannel(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
sid = 1; cid = 0; game = "tf"
|
sid = 1
|
||||||
|
cid = 0
|
||||||
|
game = "tf"
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
|
|
||||||
self.assertTrue(self.db.isRegisteredChannel(sid, cid))
|
self.assertTrue(self.db.isRegisteredChannel(sid, cid))
|
||||||
@@ -156,7 +174,11 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testChannelFor(self):
|
def testChannelFor(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
sid = 1; cid = 0; game = "tf"; server = "serv"; team = 0
|
sid = 1
|
||||||
|
cid = 0
|
||||||
|
game = "tf"
|
||||||
|
server = "serv"
|
||||||
|
team = 0
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
self.db.registerChannel(sid, cid + 1, game, server)
|
self.db.registerChannel(sid, cid + 1, game, server)
|
||||||
self.db.registerChannel(sid, cid + 2, game, server, team)
|
self.db.registerChannel(sid, cid + 2, game, server, team)
|
||||||
@@ -175,7 +197,11 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testChannelForCid(self):
|
def testChannelForCid(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
sid = 1; cid = 0; game = "tf"; server = "serv"; team = 0
|
sid = 1
|
||||||
|
cid = 0
|
||||||
|
game = "tf"
|
||||||
|
server = "serv"
|
||||||
|
team = 0
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
self.db.registerChannel(sid, cid + 1, game, server)
|
self.db.registerChannel(sid, cid + 1, game, server)
|
||||||
self.db.registerChannel(sid, cid + 2, game, server, team)
|
self.db.registerChannel(sid, cid + 2, game, server, team)
|
||||||
@@ -183,21 +209,22 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
res = self.db.channelForCid(sid, cid)
|
res = self.db.channelForCid(sid, cid)
|
||||||
self.assertEqual(res, (sid, cid, game, self.db.NO_SERVER, self.db.NO_TEAM))
|
self.assertEqual(res, (sid, cid, game, self.db.NO_SERVER, self.db.NO_TEAM))
|
||||||
|
|
||||||
|
|
||||||
res = self.db.channelForCid(sid, cid + 1)
|
res = self.db.channelForCid(sid, cid + 1)
|
||||||
self.assertEqual(res, (sid, cid + 1, game, server, self.db.NO_TEAM))
|
self.assertEqual(res, (sid, cid + 1, game, server, self.db.NO_TEAM))
|
||||||
|
|
||||||
|
|
||||||
res = self.db.channelForCid(sid, cid + 2)
|
res = self.db.channelForCid(sid, cid + 2)
|
||||||
self.assertEqual(res, (sid, cid + 2, game, server, team))
|
self.assertEqual(res, (sid, cid + 2, game, server, team))
|
||||||
|
|
||||||
|
|
||||||
res = self.db.channelForCid(sid, cid + 3)
|
res = self.db.channelForCid(sid, cid + 3)
|
||||||
self.assertEqual(res, None)
|
self.assertEqual(res, None)
|
||||||
|
|
||||||
def testChannelsFor(self):
|
def testChannelsFor(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
sid = 1; cid = 0; game = "tf"; server = "serv"; team = 0
|
sid = 1
|
||||||
|
cid = 0
|
||||||
|
game = "tf"
|
||||||
|
server = "serv"
|
||||||
|
team = 0
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
self.db.registerChannel(sid, cid + 1, game, server)
|
self.db.registerChannel(sid, cid + 1, game, server)
|
||||||
self.db.registerChannel(sid, cid + 2, game, server, team)
|
self.db.registerChannel(sid, cid + 2, game, server, team)
|
||||||
@@ -207,22 +234,26 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
(sid, cid, game, self.db.NO_SERVER, self.db.NO_TEAM))
|
(sid, cid, game, self.db.NO_SERVER, self.db.NO_TEAM))
|
||||||
|
|
||||||
res = self.db.channelsFor(sid, game, server, team)
|
res = self.db.channelsFor(sid, game, server, team)
|
||||||
self.assertItemsEqual(res, chans[0:1])
|
self.assertCountEqual(res, chans[0:1])
|
||||||
|
|
||||||
res = self.db.channelsFor(sid, game, server)
|
res = self.db.channelsFor(sid, game, server)
|
||||||
self.assertItemsEqual(res, chans[0:2])
|
self.assertCountEqual(res, chans[0:2])
|
||||||
|
|
||||||
res = self.db.channelsFor(sid, game)
|
res = self.db.channelsFor(sid, game)
|
||||||
self.assertItemsEqual(res, chans)
|
self.assertCountEqual(res, chans)
|
||||||
|
|
||||||
res = self.db.channelsFor(sid + 1, game)
|
res = self.db.channelsFor(sid + 1, game)
|
||||||
self.assertItemsEqual(res, [])
|
self.assertCountEqual(res, [])
|
||||||
|
|
||||||
def testChannelTableConstraints(self):
|
def testChannelTableConstraints(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
# cid constraint
|
# cid constraint
|
||||||
sid = 1; cid = 0; game = "tf"; server = "serv"; team = 0
|
sid = 1
|
||||||
|
cid = 0
|
||||||
|
game = "tf"
|
||||||
|
server = "serv"
|
||||||
|
team = 0
|
||||||
self.db.registerChannel(sid, cid, game)
|
self.db.registerChannel(sid, cid, game)
|
||||||
self.assertRaises(sqlite3.IntegrityError, self.db.registerChannel, sid, cid, "cstrike")
|
self.assertRaises(sqlite3.IntegrityError, self.db.registerChannel, sid, cid, "cstrike")
|
||||||
|
|
||||||
@@ -238,7 +269,8 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testChannelNameMappingTableConstraints(self):
|
def testChannelNameMappingTableConstraints(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 1; game = "tf"
|
sid = 1
|
||||||
|
game = "tf"
|
||||||
|
|
||||||
# mapName performs an INSERT OR REPLACE which relies on the UNIQUE constraint
|
# mapName performs an INSERT OR REPLACE which relies on the UNIQUE constraint
|
||||||
self.db.mapName("SomeTestName", sid, game)
|
self.db.mapName("SomeTestName", sid, game)
|
||||||
@@ -248,7 +280,10 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
def testNameMapping(self):
|
def testNameMapping(self):
|
||||||
self.db.reset()
|
self.db.reset()
|
||||||
|
|
||||||
sid = 1; game = "tf"; server = "[12313]";team = 2
|
sid = 1
|
||||||
|
game = "tf"
|
||||||
|
server = "[12313]"
|
||||||
|
team = 2
|
||||||
self.assertEqual(self.db.nameFor(sid, game, default="test"), "test")
|
self.assertEqual(self.db.nameFor(sid, game, default="test"), "test")
|
||||||
|
|
||||||
self.db.mapName("Game", sid, game)
|
self.db.mapName("Game", sid, game)
|
||||||
@@ -261,6 +296,7 @@ class SourceDBTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.db.nameFor(sid, game, server), "Game Server")
|
self.assertEqual(self.db.nameFor(sid, game, server), "Game Server")
|
||||||
self.assertEqual(self.db.nameFor(sid, game, server, team), "Game Server Team")
|
self.assertEqual(self.db.nameFor(sid, game, server, team), "Game Server Team")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# import sys;sys.argv = ['', 'Test.testName']
|
# import sys;sys.argv = ['', 'Test.testName']
|
||||||
unittest.main()
|
unittest.main()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -35,16 +35,15 @@
|
|||||||
# gamestate reported by Mumble positional audio plugins
|
# gamestate reported by Mumble positional audio plugins
|
||||||
#
|
#
|
||||||
|
|
||||||
from mumo_module import (MumoModule,
|
|
||||||
commaSeperatedIntegers,
|
|
||||||
commaSeperatedStrings,
|
|
||||||
x2bool)
|
|
||||||
|
|
||||||
from db import SourceDB
|
|
||||||
from users import (User, UserRegistry)
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from config import commaSeperatedStrings, x2bool, commaSeperatedIntegers
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
from .db import SourceDB
|
||||||
|
from .users import (User, UserRegistry)
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyPep8Naming
|
||||||
class source(MumoModule):
|
class source(MumoModule):
|
||||||
"""
|
"""
|
||||||
This class combines the basic mumble moderator callbacks with
|
This class combines the basic mumble moderator callbacks with
|
||||||
@@ -112,7 +111,6 @@ class source(MumoModule):
|
|||||||
manager.subscribeServerCallbacks(self, servers)
|
manager.subscribeServerCallbacks(self, servers)
|
||||||
manager.subscribeMetaCallbacks(self, servers)
|
manager.subscribeMetaCallbacks(self, servers)
|
||||||
|
|
||||||
|
|
||||||
def validateChannelDB(self):
|
def validateChannelDB(self):
|
||||||
"""
|
"""
|
||||||
Makes sure the plugins internal datatbase
|
Makes sure the plugins internal datatbase
|
||||||
@@ -140,11 +138,12 @@ class source(MumoModule):
|
|||||||
self.db.dropChannel(sid, cid)
|
self.db.dropChannel(sid, cid)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Server no longer exists
|
# Server no longer exists
|
||||||
assert(current_mumble_server == None)
|
assert (current_mumble_server is None)
|
||||||
log.debug("(%d) Server for channel %d no longer exists. Dropped.", sid, cid)
|
log.debug("(%d) Server for channel %d no longer exists. Dropped.", sid, cid)
|
||||||
self.db.dropChannel(sid, cid)
|
self.db.dropChannel(sid, cid)
|
||||||
|
|
||||||
def disconnected(self): pass
|
def disconnected(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def removeFromGroups(self, mumble_server, session, game, server, team):
|
def removeFromGroups(self, mumble_server, session, game, server, team):
|
||||||
"""
|
"""
|
||||||
@@ -170,7 +169,7 @@ class source(MumoModule):
|
|||||||
sid = mumble_server.id()
|
sid = mumble_server.id()
|
||||||
prefix = self.cfg().source.groupprefix
|
prefix = self.cfg().source.groupprefix
|
||||||
game_cid = self.db.cidFor(sid, game)
|
game_cid = self.db.cidFor(sid, game)
|
||||||
assert(game_cid != None)
|
assert (game_cid is not None)
|
||||||
|
|
||||||
group = prefix + game
|
group = prefix + game
|
||||||
mumble_server.addUserToGroup(game_cid, session, group) # Game
|
mumble_server.addUserToGroup(game_cid, session, group) # Game
|
||||||
@@ -181,17 +180,17 @@ class source(MumoModule):
|
|||||||
group += "_" + str(team)
|
group += "_" + str(team)
|
||||||
mumble_server.addUserToGroup(game_cid, session, group) # Team
|
mumble_server.addUserToGroup(game_cid, session, group) # Team
|
||||||
|
|
||||||
|
|
||||||
def transitionPresentUser(self, mumble_server, old, new, sid, user_new):
|
def transitionPresentUser(self, mumble_server, old, new, sid, user_new):
|
||||||
"""
|
"""
|
||||||
Transitions a user that has been and is currently playing
|
Transitions a user that has been and is currently playing
|
||||||
"""
|
"""
|
||||||
assert(new)
|
assert new
|
||||||
|
|
||||||
target_cid = self.getOrCreateTargetChannelFor(mumble_server, new)
|
target_cid = self.getOrCreateTargetChannelFor(mumble_server, new)
|
||||||
|
|
||||||
if user_new:
|
if user_new:
|
||||||
self.dlog(sid, new.state, "User started playing: g/s/t %s/%s/%d", new.game, new.server, new.identity["team"])
|
self.dlog(sid, new.state, "User started playing: g/s/t %s/%s/%d", new.game, new.server,
|
||||||
|
new.identity["team"])
|
||||||
self.addToGroups(mumble_server, new.state.session, new.game, new.server, new.identity["team"])
|
self.addToGroups(mumble_server, new.state.session, new.game, new.server, new.identity["team"])
|
||||||
else:
|
else:
|
||||||
assert old
|
assert old
|
||||||
@@ -201,12 +200,11 @@ class source(MumoModule):
|
|||||||
|
|
||||||
return self.moveUser(mumble_server, new, target_cid)
|
return self.moveUser(mumble_server, new, target_cid)
|
||||||
|
|
||||||
|
|
||||||
def transitionGoneUser(self, mumble_server, old, new, sid):
|
def transitionGoneUser(self, mumble_server, old, new, sid):
|
||||||
"""
|
"""
|
||||||
Transitions a user that played but is no longer doing so now.
|
Transitions a user that played but is no longer doing so now.
|
||||||
"""
|
"""
|
||||||
assert(old)
|
assert old
|
||||||
|
|
||||||
self.users.remove(sid, old.state.session)
|
self.users.remove(sid, old.state.session)
|
||||||
|
|
||||||
@@ -220,7 +218,6 @@ class source(MumoModule):
|
|||||||
self.dlog(sid, old.state, "User gone")
|
self.dlog(sid, old.state, "User gone")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def userLeftChannel(self, mumble_server, old, sid):
|
def userLeftChannel(self, mumble_server, old, sid):
|
||||||
"""
|
"""
|
||||||
User left channel. Make sure we check for vacancy it if the game it
|
User left channel. Make sure we check for vacancy it if the game it
|
||||||
@@ -262,7 +259,6 @@ class source(MumoModule):
|
|||||||
else:
|
else:
|
||||||
moved = self.transitionGoneUser(mumble_server, old, new, sid)
|
moved = self.transitionGoneUser(mumble_server, old, new, sid)
|
||||||
|
|
||||||
|
|
||||||
if moved and old:
|
if moved and old:
|
||||||
self.userLeftChannel(mumble_server, old, sid)
|
self.userLeftChannel(mumble_server, old, sid)
|
||||||
|
|
||||||
@@ -313,7 +309,6 @@ class source(MumoModule):
|
|||||||
allow=EAT)],
|
allow=EAT)],
|
||||||
[], True)
|
[], True)
|
||||||
|
|
||||||
|
|
||||||
def setACLsForServerChannel(self, mumble_server, server_cid, game, server):
|
def setACLsForServerChannel(self, mumble_server, server_cid, game, server):
|
||||||
"""
|
"""
|
||||||
Sets the appropriate ACLs for a server channel for the given cid.
|
Sets the appropriate ACLs for a server channel for the given cid.
|
||||||
@@ -334,7 +329,6 @@ class source(MumoModule):
|
|||||||
allow=EAT)],
|
allow=EAT)],
|
||||||
[], True)
|
[], True)
|
||||||
|
|
||||||
|
|
||||||
def setACLsForTeamChannel(self, mumble_server, team_cid, game, server, team):
|
def setACLsForTeamChannel(self, mumble_server, team_cid, game, server, team):
|
||||||
"""
|
"""
|
||||||
Sets the appropriate ACLs for a team channel for the given cid.
|
Sets the appropriate ACLs for a team channel for the given cid.
|
||||||
@@ -362,7 +356,7 @@ class source(MumoModule):
|
|||||||
"""
|
"""
|
||||||
sid = mumble_server.id()
|
sid = mumble_server.id()
|
||||||
game_cid = self.db.cidFor(sid, game)
|
game_cid = self.db.cidFor(sid, game)
|
||||||
if game_cid == None:
|
if game_cid is None:
|
||||||
game_channel_name = self.db.nameFor(sid, game,
|
game_channel_name = self.db.nameFor(sid, game,
|
||||||
default=(self.getGameName(game) % namevars))
|
default=(self.getGameName(game) % namevars))
|
||||||
|
|
||||||
@@ -378,7 +372,6 @@ class source(MumoModule):
|
|||||||
log.debug("(%d) Game channel created and registered (cid %d)", sid, game_cid)
|
log.debug("(%d) Game channel created and registered (cid %d)", sid, game_cid)
|
||||||
return game_cid
|
return game_cid
|
||||||
|
|
||||||
|
|
||||||
def getOrCreateServerChannelFor(self, mumble_server, game, server, team, sid, log, namevars, game_cid):
|
def getOrCreateServerChannelFor(self, mumble_server, game, server, team, sid, log, namevars, game_cid):
|
||||||
"""
|
"""
|
||||||
Helper function for getting or creating only the server channel. The game
|
Helper function for getting or creating only the server channel. The game
|
||||||
@@ -386,7 +379,7 @@ class source(MumoModule):
|
|||||||
server channel.
|
server channel.
|
||||||
"""
|
"""
|
||||||
server_cid = self.db.cidFor(sid, game, server)
|
server_cid = self.db.cidFor(sid, game, server)
|
||||||
if server_cid == None:
|
if server_cid is None:
|
||||||
server_channel_name = self.db.nameFor(sid, game, server,
|
server_channel_name = self.db.nameFor(sid, game, server,
|
||||||
default=self.getServerName(game) % namevars)
|
default=self.getServerName(game) % namevars)
|
||||||
|
|
||||||
@@ -402,7 +395,6 @@ class source(MumoModule):
|
|||||||
log.debug("(%d) Server channel created and registered (cid %d)", sid, server_cid)
|
log.debug("(%d) Server channel created and registered (cid %d)", sid, server_cid)
|
||||||
return server_cid
|
return server_cid
|
||||||
|
|
||||||
|
|
||||||
def getOrCreateTeamChannelFor(self, mumble_server, game, server, team, sid, log, server_cid):
|
def getOrCreateTeamChannelFor(self, mumble_server, game, server, team, sid, log, server_cid):
|
||||||
"""
|
"""
|
||||||
Helper function for getting or creating only the team channel. Game and
|
Helper function for getting or creating only the team channel. Game and
|
||||||
@@ -411,7 +403,7 @@ class source(MumoModule):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
team_cid = self.db.cidFor(sid, game, server, team)
|
team_cid = self.db.cidFor(sid, game, server, team)
|
||||||
if team_cid == None:
|
if team_cid is None:
|
||||||
team_channel_name = self.db.nameFor(sid, game, server, team,
|
team_channel_name = self.db.nameFor(sid, game, server, team,
|
||||||
default=self.getTeamName(game, team))
|
default=self.getTeamName(game, team))
|
||||||
|
|
||||||
@@ -480,7 +472,7 @@ class source(MumoModule):
|
|||||||
|
|
||||||
source_cid = state.channel
|
source_cid = state.channel
|
||||||
|
|
||||||
if target_cid == None:
|
if target_cid is None:
|
||||||
target_cid = self.getOrCreateChannelFor(mumble_server, game, server, team)
|
target_cid = self.getOrCreateChannelFor(mumble_server, game, server, team)
|
||||||
|
|
||||||
if source_cid != target_cid:
|
if source_cid != target_cid:
|
||||||
@@ -509,7 +501,7 @@ class source(MumoModule):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
_, _, cur_game, cur_server, cur_team = result
|
_, _, cur_game, cur_server, cur_team = result
|
||||||
assert(cur_game)
|
assert cur_game
|
||||||
|
|
||||||
if not cur_server:
|
if not cur_server:
|
||||||
# Don't handle game channels
|
# Don't handle game channels
|
||||||
@@ -527,7 +519,7 @@ class source(MumoModule):
|
|||||||
log.debug("(%d) Delete if unused: Channel %d in use", sid, cur_cid)
|
log.debug("(%d) Delete if unused: Channel %d in use", sid, cur_cid)
|
||||||
return False # Used
|
return False # Used
|
||||||
|
|
||||||
assert(server_channel_cid != None)
|
assert (server_channel_cid is not None)
|
||||||
|
|
||||||
# Unused. Delete server and children
|
# Unused. Delete server and children
|
||||||
log.debug("(%s) Channel %d unused. Will be deleted.", sid, server_channel_cid)
|
log.debug("(%s) Channel %d unused. Will be deleted.", sid, server_channel_cid)
|
||||||
@@ -535,10 +527,10 @@ class source(MumoModule):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def isValidGameType(self, game):
|
def isValidGameType(self, game):
|
||||||
return self.cfg().source.gameregex.match(game) != None
|
return self.cfg().source.gameregex.match(game) is not None
|
||||||
|
|
||||||
def isValidServer(self, game, server):
|
def isValidServer(self, game, server):
|
||||||
return self.getGameConfig(game, "serverregex").match(server) != None
|
return self.getGameConfig(game, "serverregex").match(server) is not None
|
||||||
|
|
||||||
def parseSourceContext(self, context):
|
def parseSourceContext(self, context):
|
||||||
"""
|
"""
|
||||||
@@ -552,15 +544,15 @@ class source(MumoModule):
|
|||||||
|
|
||||||
if source != "Source engine":
|
if source != "Source engine":
|
||||||
# Not a source engine context
|
# Not a source engine context
|
||||||
return (None, None)
|
return None, None
|
||||||
|
|
||||||
if not self.isValidGameType(game) or not self.isValidServer(game, server):
|
if not self.isValidGameType(game) or not self.isValidServer(game, server):
|
||||||
return (None, None)
|
return None, None
|
||||||
|
|
||||||
return (game, server)
|
return game, server
|
||||||
|
|
||||||
except (AttributeError, ValueError),e:
|
except (AttributeError, ValueError) as e:
|
||||||
return (None, None);
|
return None, None
|
||||||
|
|
||||||
def parseSourceIdentity(self, identity):
|
def parseSourceIdentity(self, identity):
|
||||||
"""
|
"""
|
||||||
@@ -576,7 +568,8 @@ class source(MumoModule):
|
|||||||
d[k] = int(v)
|
d[k] = int(v)
|
||||||
|
|
||||||
# Make sure mandatory values are present
|
# Make sure mandatory values are present
|
||||||
if not "team" in d: return None
|
if "team" not in d:
|
||||||
|
return None
|
||||||
|
|
||||||
return d
|
return d
|
||||||
except (AttributeError, ValueError):
|
except (AttributeError, ValueError):
|
||||||
@@ -681,9 +674,11 @@ class source(MumoModule):
|
|||||||
self.db.mapName(name, sid, game, server, team)
|
self.db.mapName(name, sid, game, server, team)
|
||||||
self.log().debug("(%d) Name mapping for channel %d updated to '%s'", sid, cid, name)
|
self.log().debug("(%d) Name mapping for channel %d updated to '%s'", sid, cid, name)
|
||||||
|
|
||||||
def userTextMessage(self, server, user, message, current=None): pass
|
def userTextMessage(self, server, user, message, current=None):
|
||||||
def channelCreated(self, server, state, context=None): pass
|
pass
|
||||||
|
|
||||||
|
def channelCreated(self, server, state, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Meta callback functions
|
# --- Meta callback functions
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,22 +29,25 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import unittest
|
import queue
|
||||||
import Queue
|
|
||||||
import config
|
|
||||||
import re
|
import re
|
||||||
import logging
|
import unittest
|
||||||
import source
|
|
||||||
|
import config
|
||||||
|
from . import source
|
||||||
|
|
||||||
|
|
||||||
class InvalidChannelExceptionMock(Exception):
|
class InvalidChannelExceptionMock(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StateMock():
|
class StateMock():
|
||||||
def __init__(self, cid=0, session=0, userid=-1):
|
def __init__(self, cid=0, session=0, userid=-1):
|
||||||
self.channel = cid
|
self.channel = cid
|
||||||
self.session = session
|
self.session = session
|
||||||
self.userid = userid
|
self.userid = userid
|
||||||
|
|
||||||
|
|
||||||
class ChannelStateMock():
|
class ChannelStateMock():
|
||||||
def __init__(self, cid, name, parent, groups, acls):
|
def __init__(self, cid, name, parent, groups, acls):
|
||||||
self.id = cid
|
self.id = cid
|
||||||
@@ -53,6 +56,7 @@ class ChannelStateMock():
|
|||||||
self.groups = groups
|
self.groups = groups
|
||||||
self.acls = acls
|
self.acls = acls
|
||||||
|
|
||||||
|
|
||||||
class ServerMock():
|
class ServerMock():
|
||||||
def __init__(self, sid):
|
def __init__(self, sid):
|
||||||
self.sid = sid
|
self.sid = sid
|
||||||
@@ -80,10 +84,10 @@ class ServerMock():
|
|||||||
if session in c.groups:
|
if session in c.groups:
|
||||||
c.groups[session].add(group)
|
c.groups[session].add(group)
|
||||||
else:
|
else:
|
||||||
c.groups[session] = set([group])
|
c.groups[session] = {group}
|
||||||
|
|
||||||
def _getChan(self, cid):
|
def _getChan(self, cid):
|
||||||
if not cid in self.channels:
|
if cid not in self.channels:
|
||||||
raise InvalidChannelExceptionMock()
|
raise InvalidChannelExceptionMock()
|
||||||
|
|
||||||
return self.channels[cid]
|
return self.channels[cid]
|
||||||
@@ -103,6 +107,7 @@ class ServerMock():
|
|||||||
self.channels = {} # See addChannel
|
self.channels = {} # See addChannel
|
||||||
self.user_state = []
|
self.user_state = []
|
||||||
|
|
||||||
|
|
||||||
class ACLMock(object):
|
class ACLMock(object):
|
||||||
def __init__(self, applyHere, applySubs, userid, group, deny=0, allow=0):
|
def __init__(self, applyHere, applySubs, userid, group, deny=0, allow=0):
|
||||||
self.applyHere = applyHere
|
self.applyHere = applyHere
|
||||||
@@ -136,6 +141,7 @@ class MockACLHelper(object):
|
|||||||
EAT = E | T
|
EAT = E | T
|
||||||
ALL = E | T | W | S
|
ALL = E | T | W | S
|
||||||
|
|
||||||
|
|
||||||
ACLS = MockACLHelper
|
ACLS = MockACLHelper
|
||||||
|
|
||||||
|
|
||||||
@@ -151,14 +157,15 @@ class MetaMock():
|
|||||||
return self.servers.get(sid, None)
|
return self.servers.get(sid, None)
|
||||||
|
|
||||||
def _reset(self):
|
def _reset(self):
|
||||||
for server in self.servers.itervalues():
|
for server in self.servers.values():
|
||||||
server._reset()
|
server._reset()
|
||||||
|
|
||||||
|
|
||||||
class ManagerMock():
|
class ManagerMock():
|
||||||
SERVERS_ALL = [-1]
|
SERVERS_ALL = [-1]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.q = Queue.Queue()
|
self.q = queue.Queue()
|
||||||
self.m = MurmurMock()
|
self.m = MurmurMock()
|
||||||
self.meta = MetaMock()
|
self.meta = MetaMock()
|
||||||
|
|
||||||
@@ -177,13 +184,13 @@ class ManagerMock():
|
|||||||
def subscribeMetaCallbacks(self, callback, servers):
|
def subscribeMetaCallbacks(self, callback, servers):
|
||||||
self.metaCB = {'callback': callback, 'servers': servers}
|
self.metaCB = {'callback': callback, 'servers': servers}
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.mm = ManagerMock();
|
self.mm = ManagerMock();
|
||||||
self.mserv = self.mm.meta.getServer(1)
|
self.mserv = self.mm.meta.getServer(1)
|
||||||
|
|
||||||
|
|
||||||
testconfig = config.Config(None, source.source.default_config)
|
testconfig = config.Config(None, source.source.default_config)
|
||||||
testconfig.source.database = ":memory:"
|
testconfig.source.database = ":memory:"
|
||||||
|
|
||||||
@@ -300,7 +307,7 @@ class Test(unittest.TestCase):
|
|||||||
i = 0
|
i = 0
|
||||||
for thing in things:
|
for thing in things:
|
||||||
acl = acls[i]
|
acl = acls[i]
|
||||||
for attr, val in thing.iteritems():
|
for attr, val in thing.items():
|
||||||
self.assertEqual(getattr(acl, attr), val)
|
self.assertEqual(getattr(acl, attr), val)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
@@ -308,7 +315,9 @@ class Test(unittest.TestCase):
|
|||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
|
|
||||||
prev = mumble_server._lastChannelID()
|
prev = mumble_server._lastChannelID()
|
||||||
game = "tf"; server = "[A-1:123]"; team = 3
|
game = "tf"
|
||||||
|
server = "[A-1:123]"
|
||||||
|
team = 3
|
||||||
cid = self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
cid = self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
||||||
|
|
||||||
self.assertEqual(3, cid - prev)
|
self.assertEqual(3, cid - prev)
|
||||||
@@ -325,9 +334,9 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
sid = mumble_server.id()
|
sid = mumble_server.id()
|
||||||
|
|
||||||
self.assertEqual(self.s.db.cidFor(sid, game), prev + 1);
|
self.assertEqual(self.s.db.cidFor(sid, game), prev + 1)
|
||||||
self.assertEqual(self.s.db.cidFor(sid, game, server), prev + 2);
|
self.assertEqual(self.s.db.cidFor(sid, game, server), prev + 2)
|
||||||
self.assertEqual(self.s.db.cidFor(sid, game, server, team), prev + 3);
|
self.assertEqual(self.s.db.cidFor(sid, game, server, team), prev + 3)
|
||||||
|
|
||||||
gotcid = self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
gotcid = self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
||||||
self.assertEqual(cid, gotcid)
|
self.assertEqual(cid, gotcid)
|
||||||
@@ -345,13 +354,13 @@ class Test(unittest.TestCase):
|
|||||||
self.resetState()
|
self.resetState()
|
||||||
|
|
||||||
self.assertEqual(self.s.getGameName("tf"), "Team Fortress 2")
|
self.assertEqual(self.s.getGameName("tf"), "Team Fortress 2")
|
||||||
self.assertEqual(self.s.getGameName("invalid"), "%(game)s");
|
self.assertEqual(self.s.getGameName("invalid"), "%(game)s")
|
||||||
|
|
||||||
def testGetServerName(self):
|
def testGetServerName(self):
|
||||||
self.resetState()
|
self.resetState()
|
||||||
|
|
||||||
self.assertEqual(self.s.getServerName("tf"), "Test %(game)s %(server)s")
|
self.assertEqual(self.s.getServerName("tf"), "Test %(game)s %(server)s")
|
||||||
self.assertEqual(self.s.getServerName("invalid"), "%(server)s");
|
self.assertEqual(self.s.getServerName("invalid"), "%(server)s")
|
||||||
|
|
||||||
def testGetTeamName(self):
|
def testGetTeamName(self):
|
||||||
self.resetState()
|
self.resetState()
|
||||||
@@ -437,17 +446,19 @@ class Test(unittest.TestCase):
|
|||||||
self.s.db.registerChannel(6, 9, "8", "9", 10)
|
self.s.db.registerChannel(6, 9, "8", "9", 10)
|
||||||
self.s.db.registerChannel(5, 10, "7", "123", 9)
|
self.s.db.registerChannel(5, 10, "7", "123", 9)
|
||||||
|
|
||||||
game = 'cstrike'; server = '[A123:123]'; team = 1
|
game = 'cstrike'
|
||||||
|
server = '[A123:123]'
|
||||||
|
team = 1
|
||||||
self.s.getOrCreateChannelFor(self.mserv, game, server, team)
|
self.s.getOrCreateChannelFor(self.mserv, game, server, team)
|
||||||
self.s.validateChannelDB()
|
self.s.validateChannelDB()
|
||||||
self.assertEqual(len(self.s.db.registeredChannels()), 3)
|
self.assertEqual(len(self.s.db.registeredChannels()), 3)
|
||||||
|
|
||||||
|
|
||||||
def testSetACLsForGameChannel(self):
|
def testSetACLsForGameChannel(self):
|
||||||
self.resetState()
|
self.resetState()
|
||||||
|
|
||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
cid = mumble_server.addChannel("test", 1); game = "dod"
|
cid = mumble_server.addChannel("test", 1)
|
||||||
|
game = "dod"
|
||||||
|
|
||||||
self.s.setACLsForGameChannel(mumble_server, cid, game)
|
self.s.setACLsForGameChannel(mumble_server, cid, game)
|
||||||
acls = mumble_server.channels[cid].acls
|
acls = mumble_server.channels[cid].acls
|
||||||
@@ -466,12 +477,13 @@ class Test(unittest.TestCase):
|
|||||||
'deny': 0,
|
'deny': 0,
|
||||||
'allow': ACLS.EAT}])
|
'allow': ACLS.EAT}])
|
||||||
|
|
||||||
|
|
||||||
def testSetACLsForServerChannel(self):
|
def testSetACLsForServerChannel(self):
|
||||||
self.resetState()
|
self.resetState()
|
||||||
|
|
||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
cid = mumble_server.addChannel("test", 1); game = "tf"; server = "[A-1:SomeServer]"
|
cid = mumble_server.addChannel("test", 1)
|
||||||
|
game = "tf"
|
||||||
|
server = "[A-1:SomeServer]"
|
||||||
self.s.setACLsForServerChannel(mumble_server, cid, game, server)
|
self.s.setACLsForServerChannel(mumble_server, cid, game, server)
|
||||||
acls = mumble_server.channels[cid].acls
|
acls = mumble_server.channels[cid].acls
|
||||||
|
|
||||||
@@ -482,12 +494,14 @@ class Test(unittest.TestCase):
|
|||||||
'deny': 0,
|
'deny': 0,
|
||||||
'allow': ACLS.EAT}])
|
'allow': ACLS.EAT}])
|
||||||
|
|
||||||
|
|
||||||
def testSetACLsForTeamChannel(self):
|
def testSetACLsForTeamChannel(self):
|
||||||
self.resetState()
|
self.resetState()
|
||||||
|
|
||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
cid = mumble_server.addChannel("test", 1); game = "tf"; server = "[A-1:SomeServer]"; team = 2
|
cid = mumble_server.addChannel("test", 1)
|
||||||
|
game = "tf"
|
||||||
|
server = "[A-1:SomeServer]"
|
||||||
|
team = 2
|
||||||
|
|
||||||
self.s.setACLsForTeamChannel(mumble_server, cid, game, server, team)
|
self.s.setACLsForTeamChannel(mumble_server, cid, game, server, team)
|
||||||
acls = mumble_server.channels[cid].acls
|
acls = mumble_server.channels[cid].acls
|
||||||
@@ -505,7 +519,10 @@ class Test(unittest.TestCase):
|
|||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
prev = mumble_server._lastChannelID()
|
prev = mumble_server._lastChannelID()
|
||||||
|
|
||||||
session = 10; game = 'cstrike'; server = '[A-1:12345]'; team = 1
|
session = 10
|
||||||
|
game = 'cstrike'
|
||||||
|
server = '[A-1:12345]'
|
||||||
|
team = 1
|
||||||
self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
@@ -521,10 +538,12 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
mumble_server = self.mserv
|
mumble_server = self.mserv
|
||||||
|
|
||||||
game = 'cstrike'; server = '[A-1:12345]'; team = 1
|
game = 'cstrike'
|
||||||
|
server = '[A-1:12345]'
|
||||||
|
team = 1
|
||||||
self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
self.s.getOrCreateChannelFor(mumble_server, game, server, team)
|
||||||
cids = []
|
cids = []
|
||||||
for c in mumble_server.channels.itervalues():
|
for c in mumble_server.channels.values():
|
||||||
c.name = str(c.id)
|
c.name = str(c.id)
|
||||||
self.s.channelStateChanged(mumble_server, c)
|
self.s.channelStateChanged(mumble_server, c)
|
||||||
cids.append(c.id)
|
cids.append(c.id)
|
||||||
@@ -538,6 +557,7 @@ class Test(unittest.TestCase):
|
|||||||
for cid in cids:
|
for cid in cids:
|
||||||
self.assertEqual(mumble_server._getChan(cid).name, str(cid))
|
self.assertEqual(mumble_server._getChan(cid).name, str(cid))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# logging.basicConfig(level = logging.DEBUG)
|
# logging.basicConfig(level = logging.DEBUG)
|
||||||
# import sys;sys.argv = ['', 'Test.testName']
|
# import sys;sys.argv = ['', 'Test.testName']
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -34,6 +34,7 @@ class User(object):
|
|||||||
User to hold state as well as parsed data fields in a
|
User to hold state as well as parsed data fields in a
|
||||||
sane fashion.
|
sane fashion.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, state, identity=None, game=None, server=None):
|
def __init__(self, state, identity=None, game=None, server=None):
|
||||||
self.state = state
|
self.state = state
|
||||||
self.identity = identity or {}
|
self.identity = identity or {}
|
||||||
@@ -67,6 +68,7 @@ class User(object):
|
|||||||
self.game = game
|
self.game = game
|
||||||
self.server = server
|
self.server = server
|
||||||
|
|
||||||
|
|
||||||
class UserRegistry(object):
|
class UserRegistry(object):
|
||||||
"""
|
"""
|
||||||
Registry to store User objects for given servers
|
Registry to store User objects for given servers
|
||||||
@@ -126,9 +128,8 @@ class UserRegistry(object):
|
|||||||
"""
|
"""
|
||||||
Return true if any user in the registry is occupying the given channel
|
Return true if any user in the registry is occupying the given channel
|
||||||
"""
|
"""
|
||||||
for user in self.users[sid].itervalues():
|
for user in self.users[sid].values():
|
||||||
if user.state and user.state.channel == cid:
|
if user.state and user.state.channel == cid:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -31,15 +31,19 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from users import User, UserRegistry
|
from .users import User, UserRegistry
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
def getSomeUsers(self, n=5):
|
def getSomeUsers(self, n=5):
|
||||||
sid = []; session = []; user = []
|
sid = []
|
||||||
|
session = []
|
||||||
|
user = []
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
s = str(i)
|
s = str(i)
|
||||||
sid.append(i) ; session.append(i)
|
sid.append(i)
|
||||||
|
session.append(i)
|
||||||
user.append(User("state" + s, "identity" + s, "game" + s, "server" + s))
|
user.append(User("state" + s, "identity" + s, "game" + s, "server" + s))
|
||||||
|
|
||||||
return sid, session, user
|
return sid, session, user
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010-2011 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -36,10 +36,8 @@
|
|||||||
# debugging purposes. Usually you don't want
|
# debugging purposes. Usually you don't want
|
||||||
# to use this.
|
# to use this.
|
||||||
#
|
#
|
||||||
|
from mumo_module import MumoModule, logModFu
|
||||||
|
|
||||||
from mumo_module import (x2bool,
|
|
||||||
MumoModule,
|
|
||||||
logModFu)
|
|
||||||
|
|
||||||
class test(MumoModule):
|
class test(MumoModule):
|
||||||
default_config = {'testing': (('tvar', int, 1),
|
default_config = {'testing': (('tvar', int, 1),
|
||||||
@@ -64,6 +62,7 @@ class test(MumoModule):
|
|||||||
@logModFu
|
@logModFu
|
||||||
def disconnected(self):
|
def disconnected(self):
|
||||||
self.log().debug("Ice disconnected")
|
self.log().debug("Ice disconnected")
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Meta callback functions
|
# --- Meta callback functions
|
||||||
#
|
#
|
||||||
|
|||||||
85
mumo.py
85
mumo.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010-2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010-2013 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,18 +29,10 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import Ice
|
|
||||||
import IcePy
|
|
||||||
import logging
|
|
||||||
import tempfile
|
import tempfile
|
||||||
from config import (Config,
|
|
||||||
x2bool,
|
|
||||||
commaSeperatedIntegers)
|
|
||||||
|
|
||||||
from threading import Timer
|
|
||||||
from optparse import OptionParser
|
|
||||||
from logging import (debug,
|
from logging import (debug,
|
||||||
info,
|
info,
|
||||||
warning,
|
warning,
|
||||||
@@ -48,6 +40,14 @@ from logging import (debug,
|
|||||||
critical,
|
critical,
|
||||||
exception,
|
exception,
|
||||||
getLogger)
|
getLogger)
|
||||||
|
from optparse import OptionParser
|
||||||
|
from threading import Timer
|
||||||
|
|
||||||
|
import Ice
|
||||||
|
import IcePy
|
||||||
|
|
||||||
|
from config import (Config,
|
||||||
|
commaSeperatedIntegers)
|
||||||
from mumo_manager import MumoManager
|
from mumo_manager import MumoManager
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -70,6 +70,7 @@ default.update({'ice':(('host', str, '127.0.0.1'),
|
|||||||
'log': (('level', int, logging.DEBUG),
|
'log': (('level', int, logging.DEBUG),
|
||||||
('file', str, 'mumo.log'))})
|
('file', str, 'mumo.log'))})
|
||||||
|
|
||||||
|
|
||||||
def load_slice(slice):
|
def load_slice(slice):
|
||||||
#
|
#
|
||||||
# --- Loads a given slicefile, used by dynload_slice and fsload_slice
|
# --- Loads a given slicefile, used by dynload_slice and fsload_slice
|
||||||
@@ -89,6 +90,7 @@ def load_slice(slice):
|
|||||||
|
|
||||||
Ice.loadSlice('', slicedirs + [slice])
|
Ice.loadSlice('', slicedirs + [slice])
|
||||||
|
|
||||||
|
|
||||||
def dynload_slice(prx):
|
def dynload_slice(prx):
|
||||||
#
|
#
|
||||||
# --- Dynamically retrieves the slice file from the target server
|
# --- Dynamically retrieves the slice file from the target server
|
||||||
@@ -99,13 +101,15 @@ def dynload_slice(prx):
|
|||||||
# In case it breaks with future versions use slice2py and search for
|
# In case it breaks with future versions use slice2py and search for
|
||||||
# "IcePy.Operation('getSlice'," for updates in the generated bindings.
|
# "IcePy.Operation('getSlice'," for updates in the generated bindings.
|
||||||
op = None
|
op = None
|
||||||
if IcePy.intVersion() < 30500L:
|
if IcePy.intVersion() < 30500:
|
||||||
# Old 3.4 signature with 9 parameters
|
# Old 3.4 signature with 9 parameters
|
||||||
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, (), (), (), IcePy._t_string, ())
|
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, (), (),
|
||||||
|
(), IcePy._t_string, ())
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# New 3.5 signature with 10 parameters.
|
# New 3.5 signature with 10 parameters.
|
||||||
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, None, (), (), (), ((), IcePy._t_string, False, 0), ())
|
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, None, (),
|
||||||
|
(), (), ((), IcePy._t_string, False, 0), ())
|
||||||
|
|
||||||
slice = op.invoke(prx, ((), None))
|
slice = op.invoke(prx, ((), None))
|
||||||
(dynslicefiledesc, dynslicefilepath) = tempfile.mkstemp(suffix='.ice')
|
(dynslicefiledesc, dynslicefilepath) = tempfile.mkstemp(suffix='.ice')
|
||||||
@@ -115,7 +119,7 @@ def dynload_slice(prx):
|
|||||||
load_slice(dynslicefilepath)
|
load_slice(dynslicefilepath)
|
||||||
dynslicefile.close()
|
dynslicefile.close()
|
||||||
os.remove(dynslicefilepath)
|
os.remove(dynslicefilepath)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
error("Retrieving slice from server failed")
|
error("Retrieving slice from server failed")
|
||||||
exception(e)
|
exception(e)
|
||||||
raise
|
raise
|
||||||
@@ -128,6 +132,7 @@ def fsload_slice(slice):
|
|||||||
debug("Loading slice from filesystem: %s" % slice)
|
debug("Loading slice from filesystem: %s" % slice)
|
||||||
load_slice(slice)
|
load_slice(slice)
|
||||||
|
|
||||||
|
|
||||||
def do_main_program():
|
def do_main_program():
|
||||||
#
|
#
|
||||||
# --- Moderator implementation
|
# --- Moderator implementation
|
||||||
@@ -153,6 +158,7 @@ def do_main_program():
|
|||||||
else:
|
else:
|
||||||
fsload_slice(cfg.ice.slice)
|
fsload_slice(cfg.ice.slice)
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
import Murmur
|
import Murmur
|
||||||
|
|
||||||
class mumoIceApp(Ice.Application):
|
class mumoIceApp(Ice.Application):
|
||||||
@@ -201,7 +207,8 @@ def do_main_program():
|
|||||||
else:
|
else:
|
||||||
cbp = ''
|
cbp = ''
|
||||||
|
|
||||||
adapter = ice.createObjectAdapterWithEndpoints('Callback.Client', 'tcp -h %s%s' % (cfg.ice.callback_host, cbp))
|
adapter = ice.createObjectAdapterWithEndpoints('Callback.Client',
|
||||||
|
'tcp -h %s%s' % (cfg.ice.callback_host, cbp))
|
||||||
adapter.activate()
|
adapter.activate()
|
||||||
self.adapter = adapter
|
self.adapter = adapter
|
||||||
self.manager.setClientAdapter(adapter)
|
self.manager.setClientAdapter(adapter)
|
||||||
@@ -230,11 +237,12 @@ def do_main_program():
|
|||||||
servercb = Murmur.ServerCallbackPrx.uncheckedCast(servercbprx)
|
servercb = Murmur.ServerCallbackPrx.uncheckedCast(servercbprx)
|
||||||
server.addCallback(servercb)
|
server.addCallback(servercb)
|
||||||
|
|
||||||
except (Murmur.InvalidSecretException, Ice.UnknownUserException, Ice.ConnectionRefusedException), e:
|
except (Murmur.InvalidSecretException, Ice.UnknownUserException, Ice.ConnectionRefusedException) as e:
|
||||||
if isinstance(e, Ice.ConnectionRefusedException):
|
if isinstance(e, Ice.ConnectionRefusedException):
|
||||||
error('Server refused connection')
|
error('Server refused connection')
|
||||||
elif isinstance(e, Murmur.InvalidSecretException) or \
|
elif isinstance(e, Murmur.InvalidSecretException) or \
|
||||||
isinstance(e, Ice.UnknownUserException) and (e.unknown == 'Murmur::InvalidSecretException'):
|
isinstance(e, Ice.UnknownUserException) and (
|
||||||
|
e.unknown == 'Murmur::InvalidSecretException'):
|
||||||
error('Invalid ice secret')
|
error('Invalid ice secret')
|
||||||
else:
|
else:
|
||||||
# We do not actually want to handle this one, re-raise it
|
# We do not actually want to handle this one, re-raise it
|
||||||
@@ -266,8 +274,9 @@ def do_main_program():
|
|||||||
self.attachCallbacks()
|
self.attachCallbacks()
|
||||||
|
|
||||||
self.metaUptime = uptime
|
self.metaUptime = uptime
|
||||||
except Ice.Exception, e:
|
except Ice.Exception as e:
|
||||||
error('Connection to server lost, will try to reestablish callbacks in next watchdog run (%ds)', cfg.ice.watchdog)
|
error('Connection to server lost, will try to reestablish callbacks in next watchdog run (%ds)',
|
||||||
|
cfg.ice.watchdog)
|
||||||
debug(str(e))
|
debug(str(e))
|
||||||
self.attachCallbacks()
|
self.attachCallbacks()
|
||||||
|
|
||||||
@@ -306,11 +315,12 @@ def do_main_program():
|
|||||||
|
|
||||||
The default is to catch all non-Ice exceptions.
|
The default is to catch all non-Ice exceptions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def newdec(func):
|
def newdec(func):
|
||||||
def newfunc(*args, **kws):
|
def newfunc(*args, **kws):
|
||||||
try:
|
try:
|
||||||
return func(*args, **kws)
|
return func(*args, **kws)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
catch = True
|
catch = True
|
||||||
for ex in exceptions:
|
for ex in exceptions:
|
||||||
if isinstance(e, ex):
|
if isinstance(e, ex):
|
||||||
@@ -324,6 +334,7 @@ def do_main_program():
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
return newfunc
|
return newfunc
|
||||||
|
|
||||||
return newdec
|
return newdec
|
||||||
|
|
||||||
class metaCallback(Murmur.MetaCallback):
|
class metaCallback(Murmur.MetaCallback):
|
||||||
@@ -347,7 +358,7 @@ def do_main_program():
|
|||||||
server.addCallback(servercb)
|
server.addCallback(servercb)
|
||||||
|
|
||||||
# Apparently this server was restarted without us noticing
|
# Apparently this server was restarted without us noticing
|
||||||
except (Murmur.InvalidSecretException, Ice.UnknownUserException), e:
|
except (Murmur.InvalidSecretException, Ice.UnknownUserException) as e:
|
||||||
if hasattr(e, "unknown") and e.unknown != "Murmur::InvalidSecretException":
|
if hasattr(e, "unknown") and e.unknown != "Murmur::InvalidSecretException":
|
||||||
# Special handling for Murmur 1.2.2 servers with invalid slice files
|
# Special handling for Murmur 1.2.2 servers with invalid slice files
|
||||||
raise e
|
raise e
|
||||||
@@ -382,10 +393,10 @@ def do_main_program():
|
|||||||
|
|
||||||
debug('Server shutdown stopped a virtual server')
|
debug('Server shutdown stopped a virtual server')
|
||||||
|
|
||||||
|
|
||||||
def forwardServer(fu):
|
def forwardServer(fu):
|
||||||
def new_fu(self, *args, **kwargs):
|
def new_fu(self, *args, **kwargs):
|
||||||
self.manager.announceServer(self.sid, fu.__name__, self.server, *args, **kwargs)
|
self.manager.announceServer(self.sid, fu.__name__, self.server, *args, **kwargs)
|
||||||
|
|
||||||
return new_fu
|
return new_fu
|
||||||
|
|
||||||
class serverCallback(Murmur.ServerCallback):
|
class serverCallback(Murmur.ServerCallback):
|
||||||
@@ -405,21 +416,27 @@ def do_main_program():
|
|||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def userStateChanged(self, u, current=None): pass
|
def userStateChanged(self, u, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def userDisconnected(self, u, current=None): pass
|
def userDisconnected(self, u, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def userConnected(self, u, current=None): pass
|
def userConnected(self, u, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def channelCreated(self, c, current=None): pass
|
def channelCreated(self, c, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def channelRemoved(self, c, current=None): pass
|
def channelRemoved(self, c, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def channelStateChanged(self, c, current=None): pass
|
def channelStateChanged(self, c, current=None): pass
|
||||||
|
|
||||||
@checkSecret
|
@checkSecret
|
||||||
@forwardServer
|
@forwardServer
|
||||||
def userTextMessage(self, u, m, current=None): pass
|
def userTextMessage(self, u, m, current=None): pass
|
||||||
@@ -454,6 +471,7 @@ def do_main_program():
|
|||||||
info('Shutdown complete')
|
info('Shutdown complete')
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
class CustomLogger(Ice.Logger):
|
class CustomLogger(Ice.Logger):
|
||||||
"""
|
"""
|
||||||
Logger implementation to pipe Ice log messages into
|
Logger implementation to pipe Ice log messages into
|
||||||
@@ -476,6 +494,7 @@ class CustomLogger(Ice.Logger):
|
|||||||
def error(self, message):
|
def error(self, message):
|
||||||
self._log.error(message)
|
self._log.error(message)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# --- Start of program
|
# --- Start of program
|
||||||
#
|
#
|
||||||
@@ -501,22 +520,21 @@ if __name__ == '__main__':
|
|||||||
# Load configuration
|
# Load configuration
|
||||||
try:
|
try:
|
||||||
cfg = Config(option.ini, default)
|
cfg = Config(option.ini, default)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print >> sys.stderr, 'Fatal error, could not load config file from "%s"' % cfgfile
|
print('Fatal error, could not load config file from "%s"' % cfgfile, file=sys.stderr)
|
||||||
print >> sys.stderr, e
|
print(e, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Initialise logger
|
# Initialise logger
|
||||||
if cfg.log.file:
|
if cfg.log.file:
|
||||||
try:
|
try:
|
||||||
logfile = open(cfg.log.file, 'a')
|
logfile = open(cfg.log.file, 'a')
|
||||||
except IOError, e:
|
except IOError as e:
|
||||||
# print>>sys.stderr, str(e)
|
# print>>sys.stderr, str(e)
|
||||||
print >> sys.stderr, 'Fatal error, could not open logfile "%s"' % cfg.log.file
|
print('Fatal error, could not open logfile "%s"' % cfg.log.file, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
logfile = logging.sys.stderr
|
logfile = logging.sys.stdout
|
||||||
|
|
||||||
|
|
||||||
if option.verbose:
|
if option.verbose:
|
||||||
level = cfg.log.level
|
level = cfg.log.level
|
||||||
@@ -533,14 +551,15 @@ if __name__ == '__main__':
|
|||||||
if option.force_app:
|
if option.force_app:
|
||||||
raise ImportError # Pretend that we couldn't import the daemon lib
|
raise ImportError # Pretend that we couldn't import the daemon lib
|
||||||
import daemon
|
import daemon
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from daemon.pidfile import TimeoutPIDLockFile
|
from daemon.pidfile import TimeoutPIDLockFile
|
||||||
except ImportError: # Version < 1.6
|
except ImportError: # Version < 1.6
|
||||||
from daemon.pidlockfile import TimeoutPIDLockFile
|
from daemon.pidlockfile import TimeoutPIDLockFile
|
||||||
except ImportError:
|
except ImportError:
|
||||||
if option.force_daemon:
|
if option.force_daemon:
|
||||||
print >> sys.stderr, 'Fatal error, could not daemonize process due to missing "daemon" library, ' \
|
print('Fatal error, could not daemonize process due to missing "daemon" library, '
|
||||||
'please install the missing dependency and restart the application'
|
'please install the missing dependency and restart the application', file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
ret = do_main_program()
|
ret = do_main_program()
|
||||||
else:
|
else:
|
||||||
@@ -548,10 +567,10 @@ if __name__ == '__main__':
|
|||||||
if pidfile.is_locked():
|
if pidfile.is_locked():
|
||||||
try:
|
try:
|
||||||
os.kill(pidfile.read_pid(), 0)
|
os.kill(pidfile.read_pid(), 0)
|
||||||
print >> sys.stderr, 'Mumo already running as %s' % pidfile.read_pid()
|
print('Mumo already running as %s' % pidfile.read_pid(), file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except OSError:
|
except OSError:
|
||||||
print >> sys.stderr, 'Found stale mumo pid file but no process, breaking lock'
|
print('Found stale mumo pid file but no process, breaking lock', file=sys.stderr)
|
||||||
pidfile.break_lock()
|
pidfile.break_lock()
|
||||||
|
|
||||||
context = daemon.DaemonContext(working_directory=sys.path[0],
|
context = daemon.DaemonContext(working_directory=sys.path[0],
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,25 +29,31 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import Queue
|
|
||||||
from worker import Worker, local_thread, local_thread_blocking
|
|
||||||
from config import Config
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
|
import queue
|
||||||
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from config import Config
|
||||||
|
from worker import Worker, local_thread, local_thread_blocking
|
||||||
|
|
||||||
|
|
||||||
class FailedLoadModuleException(Exception):
|
class FailedLoadModuleException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FailedLoadModuleConfigException(FailedLoadModuleException):
|
class FailedLoadModuleConfigException(FailedLoadModuleException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FailedLoadModuleImportException(FailedLoadModuleException):
|
class FailedLoadModuleImportException(FailedLoadModuleException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FailedLoadModuleInitializationException(FailedLoadModuleException):
|
class FailedLoadModuleInitializationException(FailedLoadModuleException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def debug_log(enable=True):
|
def debug_log(enable=True):
|
||||||
def new_dec(fu):
|
def new_dec(fu):
|
||||||
def new_fu(*args, **kwargs):
|
def new_fu(*args, **kwargs):
|
||||||
@@ -61,13 +67,15 @@ def debug_log(enable = True):
|
|||||||
res = fu(*args, **kwargs)
|
res = fu(*args, **kwargs)
|
||||||
log.debug("%s -> %s", call, repr(res))
|
log.debug("%s -> %s", call, repr(res))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
return new_fu if enable else fu
|
return new_fu if enable else fu
|
||||||
|
|
||||||
return new_dec
|
return new_dec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
debug_me = True
|
debug_me = True
|
||||||
|
|
||||||
|
|
||||||
class MumoManagerRemote(object):
|
class MumoManagerRemote(object):
|
||||||
"""
|
"""
|
||||||
Manager object handed to MumoModules. This module
|
Manager object handed to MumoModules. This module
|
||||||
@@ -171,7 +179,8 @@ class MumoManagerRemote(object):
|
|||||||
@param action: Action identifier passed to your callback (see above)
|
@param action: Action identifier passed to your callback (see above)
|
||||||
@param text: Text for the menu entry
|
@param text: Text for the menu entry
|
||||||
@param handler: Handler function to call when the menu item is used
|
@param handler: Handler function to call when the menu item is used
|
||||||
@param context: Contexts to show entry in (can be a combination of ContextServer, ContextChannel and ContextUser)
|
@param context: Contexts to show entry in (can be a combination of ContextServer, ContextChannel and
|
||||||
|
ContextUser)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
server_actions = self.__context_callbacks.get(server.id())
|
server_actions = self.__context_callbacks.get(server.id())
|
||||||
@@ -285,7 +294,7 @@ class MumoManager(Worker):
|
|||||||
for server in servers:
|
for server in servers:
|
||||||
try:
|
try:
|
||||||
mdict[server][queue].remove(handler)
|
mdict[server][queue].remove(handler)
|
||||||
except KeyError, ValueError:
|
except KeyError as ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __announce_to_dict(self, mdict, server, function, *args, **kwargs):
|
def __announce_to_dict(self, mdict, server, function, *args, **kwargs):
|
||||||
@@ -302,13 +311,13 @@ class MumoManager(Worker):
|
|||||||
|
|
||||||
# Announce to all handlers of the given serverlist
|
# Announce to all handlers of the given serverlist
|
||||||
if server == self.MAGIC_ALL:
|
if server == self.MAGIC_ALL:
|
||||||
servers = mdict.iterkeys()
|
servers = iter(mdict.keys())
|
||||||
else:
|
else:
|
||||||
servers = [self.MAGIC_ALL, server]
|
servers = [self.MAGIC_ALL, server]
|
||||||
|
|
||||||
for server in servers:
|
for server in servers:
|
||||||
try:
|
try:
|
||||||
for queue, handlers in mdict[server].iteritems():
|
for queue, handlers in mdict[server].items():
|
||||||
for handler in handlers:
|
for handler in handlers:
|
||||||
self.__call_remote(queue, handler, function, *args, **kwargs)
|
self.__call_remote(queue, handler, function, *args, **kwargs)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -319,18 +328,18 @@ class MumoManager(Worker):
|
|||||||
try:
|
try:
|
||||||
func = getattr(handler, function) # Find out what to call on target
|
func = getattr(handler, function) # Find out what to call on target
|
||||||
queue.put((None, func, args, kwargs))
|
queue.put((None, func, args, kwargs))
|
||||||
except AttributeError, e:
|
except AttributeError as e:
|
||||||
mod = self.queues.get(queue, None)
|
mod = self.queues.get(queue, None)
|
||||||
myname = ""
|
myname = ""
|
||||||
for name, mymod in self.modules.iteritems():
|
for name, mymod in self.modules.items():
|
||||||
if mod == mymod:
|
if mod == mymod:
|
||||||
myname = name
|
myname = name
|
||||||
if myname:
|
if myname:
|
||||||
self.log().error("Handler class registered by module '%s' does not handle function '%s'. Call failed.", myname, function)
|
self.log().error("Handler class registered by module '%s' does not handle function '%s'. Call failed.",
|
||||||
|
myname, function)
|
||||||
else:
|
else:
|
||||||
self.log().exception(e)
|
self.log().exception(e)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# -- Module multiplexing functionality
|
# -- Module multiplexing functionality
|
||||||
#
|
#
|
||||||
@@ -341,7 +350,7 @@ class MumoManager(Worker):
|
|||||||
Call connected handler on all handlers
|
Call connected handler on all handlers
|
||||||
"""
|
"""
|
||||||
self.meta = meta
|
self.meta = meta
|
||||||
for queue, module in self.queues.iteritems():
|
for queue, module in self.queues.items():
|
||||||
self.__call_remote(queue, module, "connected")
|
self.__call_remote(queue, module, "connected")
|
||||||
|
|
||||||
@local_thread
|
@local_thread
|
||||||
@@ -349,7 +358,7 @@ class MumoManager(Worker):
|
|||||||
"""
|
"""
|
||||||
Call disconnected handler on all handlers
|
Call disconnected handler on all handlers
|
||||||
"""
|
"""
|
||||||
for queue, module in self.queues.iteritems():
|
for queue, module in self.queues.items():
|
||||||
self.__call_remote(queue, module, "disconnected")
|
self.__call_remote(queue, module, "disconnected")
|
||||||
|
|
||||||
@local_thread
|
@local_thread
|
||||||
@@ -487,12 +496,12 @@ class MumoManager(Worker):
|
|||||||
log.error("Module '%s' already loaded", name)
|
log.error("Module '%s' already loaded", name)
|
||||||
return
|
return
|
||||||
|
|
||||||
modqueue = Queue.Queue()
|
modqueue = queue.Queue()
|
||||||
modmanager = MumoManagerRemote(self, name, modqueue)
|
modmanager = MumoManagerRemote(self, name, modqueue)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
modinst = modcls(name, modmanager, module_cfg)
|
modinst = modcls(name, modmanager, module_cfg)
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
msg = "Module '%s' failed to initialize" % name
|
msg = "Module '%s' failed to initialize" % name
|
||||||
log.error(msg)
|
log.error(msg)
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
@@ -543,7 +552,7 @@ class MumoManager(Worker):
|
|||||||
try:
|
try:
|
||||||
mod = __import__(name)
|
mod = __import__(name)
|
||||||
self.imports[name] = mod
|
self.imports[name] = mod
|
||||||
except ImportError, e:
|
except ImportError as e:
|
||||||
msg = "Failed to import module '%s', reason: %s" % (name, str(e))
|
msg = "Failed to import module '%s', reason: %s" % (name, str(e))
|
||||||
log.error(msg)
|
log.error(msg)
|
||||||
raise FailedLoadModuleImportException(msg)
|
raise FailedLoadModuleImportException(msg)
|
||||||
@@ -575,12 +584,12 @@ class MumoManager(Worker):
|
|||||||
|
|
||||||
if not names:
|
if not names:
|
||||||
# If no names are given start all models
|
# If no names are given start all models
|
||||||
names = self.modules.iterkeys()
|
names = iter(self.modules.keys())
|
||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
try:
|
try:
|
||||||
modinst = self.modules[name]
|
modinst = self.modules[name]
|
||||||
if not modinst.isAlive():
|
if not modinst.is_alive():
|
||||||
modinst.start()
|
modinst.start()
|
||||||
log.debug("Module '%s' started", name)
|
log.debug("Module '%s' started", name)
|
||||||
else:
|
else:
|
||||||
@@ -608,7 +617,7 @@ class MumoManager(Worker):
|
|||||||
|
|
||||||
if not names:
|
if not names:
|
||||||
# If no names are given start all models
|
# If no names are given start all models
|
||||||
names = self.modules.iterkeys()
|
names = iter(self.modules.keys())
|
||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
try:
|
try:
|
||||||
@@ -620,20 +629,21 @@ class MumoManager(Worker):
|
|||||||
|
|
||||||
if force:
|
if force:
|
||||||
# We will have to drain the modules queues
|
# We will have to drain the modules queues
|
||||||
for queue, module in self.queues.iteritems():
|
for queue, module in self.queues.items():
|
||||||
if module in self.modules:
|
if module in self.modules:
|
||||||
try:
|
try:
|
||||||
while queue.get_nowait(): pass
|
while queue.get_nowait(): pass
|
||||||
except Queue.Empty: pass
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
for modinst in stoppedmodules.itervalues():
|
for modinst in stoppedmodules.values():
|
||||||
if modinst.isAlive():
|
if modinst.is_alive():
|
||||||
modinst.stop()
|
modinst.stop()
|
||||||
log.debug("Module '%s' is being stopped", name)
|
log.debug("Module '%s' is being stopped", name)
|
||||||
else:
|
else:
|
||||||
log.debug("Module '%s' already stopped", name)
|
log.debug("Module '%s' already stopped", name)
|
||||||
|
|
||||||
for modinst in stoppedmodules.itervalues():
|
for modinst in stoppedmodules.values():
|
||||||
modinst.join(timeout=self.cfg.modules.timeout)
|
modinst.join(timeout=self.cfg.modules.timeout)
|
||||||
|
|
||||||
return stoppedmodules
|
return stoppedmodules
|
||||||
@@ -645,4 +655,3 @@ class MumoManager(Worker):
|
|||||||
self.log().debug("Stopping")
|
self.log().debug("Stopping")
|
||||||
self.stopModules()
|
self.stopModules()
|
||||||
Worker.stop(self, force)
|
Worker.stop(self, force)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -30,13 +30,12 @@
|
|||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import Queue
|
from logging import getLogger
|
||||||
from mumo_manager import MumoManager, MumoManagerRemote
|
|
||||||
from mumo_module import MumoModule
|
|
||||||
from logging import basicConfig, ERROR, getLogger
|
|
||||||
import logging
|
|
||||||
from threading import Event
|
from threading import Event
|
||||||
|
|
||||||
|
from mumo_manager import MumoManager
|
||||||
|
from mumo_module import MumoModule
|
||||||
|
|
||||||
|
|
||||||
class MumoManagerTest(unittest.TestCase):
|
class MumoManagerTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -66,7 +65,6 @@ class MumoManagerTest(unittest.TestCase):
|
|||||||
man = self.manager()
|
man = self.manager()
|
||||||
man.subscribeMetaCallbacks(self)
|
man.subscribeMetaCallbacks(self)
|
||||||
man.subscribeServerCallbacks(self)
|
man.subscribeServerCallbacks(self)
|
||||||
man.subscribeContextCallbacks(self)
|
|
||||||
self.econnected.set()
|
self.econnected.set()
|
||||||
|
|
||||||
def disconnected(self):
|
def disconnected(self):
|
||||||
@@ -96,13 +94,13 @@ class MumoManagerTest(unittest.TestCase):
|
|||||||
# --- Helpers for independent test env creation
|
# --- Helpers for independent test env creation
|
||||||
#
|
#
|
||||||
def up(self):
|
def up(self):
|
||||||
man = MumoManager(None)
|
man = MumoManager(None, None)
|
||||||
man.start()
|
man.start()
|
||||||
|
|
||||||
mod = man.loadModuleCls("MyModule", self.mymod, self.cfg)
|
mod = man.loadModuleCls("MyModule", self.mymod, self.cfg)
|
||||||
man.startModules()
|
man.startModules()
|
||||||
|
|
||||||
return (man, mod)
|
return man, mod
|
||||||
|
|
||||||
def down(self, man, mod):
|
def down(self, man, mod):
|
||||||
man.stopModules()
|
man.stopModules()
|
||||||
@@ -124,7 +122,7 @@ class MumoManagerTest(unittest.TestCase):
|
|||||||
man, mod = self.up()
|
man, mod = self.up()
|
||||||
|
|
||||||
tos = ["MyModule"]
|
tos = ["MyModule"]
|
||||||
self.assertEquals(list(man.stopModules(tos).iterkeys()), tos)
|
self.assertEqual(list(man.stopModules(tos).keys()), tos)
|
||||||
mod.estopped.wait(timeout=1)
|
mod.estopped.wait(timeout=1)
|
||||||
assert (mod.estopped.is_set())
|
assert (mod.estopped.is_set())
|
||||||
|
|
||||||
@@ -153,16 +151,17 @@ class MumoManagerTest(unittest.TestCase):
|
|||||||
man.announceDisconnected()
|
man.announceDisconnected()
|
||||||
self.down(man, mod)
|
self.down(man, mod)
|
||||||
|
|
||||||
def testContextCallback(self):
|
# FIXME: Test ContextCallbacks correctly
|
||||||
man, mod = self.up()
|
# def testContextCallback(self):
|
||||||
man.announceConnected()
|
# man, mod = self.up()
|
||||||
mod.econnected.wait(timeout=1)
|
# man.announceConnected()
|
||||||
assert(mod.econnected.is_set())
|
# mod.econnected.wait(timeout=1)
|
||||||
man.announceContext(man.MAGIC_ALL, "contextCallMe", "server", "arg1", arg2 = "arg2")
|
# assert (mod.econnected.is_set())
|
||||||
mod.econtext.wait(timeout=1)
|
# man.announceContext(man.MAGIC_ALL, "contextCallMe", "server", "arg1", arg2="arg2")
|
||||||
assert(mod.econtext.is_set())
|
# mod.econtext.wait(timeout=1)
|
||||||
man.announceDisconnected()
|
# assert (mod.econtext.is_set())
|
||||||
self.down(man, mod)
|
# man.announceDisconnected()
|
||||||
|
# self.down(man, mod)
|
||||||
|
|
||||||
def testServerCallback(self):
|
def testServerCallback(self):
|
||||||
man, mod = self.up()
|
man, mod = self.up()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,14 +29,11 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
from config import (Config,
|
from config import (Config)
|
||||||
x2bool,
|
|
||||||
commaSeperatedIntegers,
|
|
||||||
commaSeperatedStrings,
|
|
||||||
commaSeperatedBool)
|
|
||||||
|
|
||||||
from worker import Worker
|
from worker import Worker
|
||||||
|
|
||||||
|
|
||||||
class MumoModule(Worker):
|
class MumoModule(Worker):
|
||||||
default_config = {}
|
default_config = {}
|
||||||
|
|
||||||
@@ -44,7 +41,7 @@ class MumoModule(Worker):
|
|||||||
Worker.__init__(self, name, manager.getQueue())
|
Worker.__init__(self, name, manager.getQueue())
|
||||||
self.__manager = manager
|
self.__manager = manager
|
||||||
|
|
||||||
if isinstance(configuration, basestring):
|
if isinstance(configuration, str):
|
||||||
# If we are passed a string expect a config file there
|
# If we are passed a string expect a config file there
|
||||||
if configuration:
|
if configuration:
|
||||||
self.__cfg = Config(configuration, self.default_config)
|
self.__cfg = Config(configuration, self.default_config)
|
||||||
@@ -67,7 +64,6 @@ class MumoModule(Worker):
|
|||||||
|
|
||||||
# --- Module control
|
# --- Module control
|
||||||
|
|
||||||
|
|
||||||
def onStart(self):
|
def onStart(self):
|
||||||
self.log().info("Start")
|
self.log().info("Start")
|
||||||
|
|
||||||
@@ -95,7 +91,8 @@ def logModFu(fu):
|
|||||||
def new_fu(self, *args, **kwargs):
|
def new_fu(self, *args, **kwargs):
|
||||||
log = self.log()
|
log = self.log()
|
||||||
argss = '' if len(args) == 0 else ',' + ','.join(['"%s"' % str(arg) for arg in args])
|
argss = '' if len(args) == 0 else ',' + ','.join(['"%s"' % str(arg) for arg in args])
|
||||||
kwargss = '' if len(kwargs)==0 else ','.join('%s="%s"' % (kw, str(arg)) for kw, arg in kwargs.iteritems())
|
kwargss = '' if len(kwargs) == 0 else ','.join('%s="%s"' % (kw, str(arg)) for kw, arg in kwargs.items())
|
||||||
log.debug("%s(%s%s%s)", fu.__name__, str(self), argss, kwargss)
|
log.debug("%s(%s%s%s)", fu.__name__, str(self), argss, kwargss)
|
||||||
return fu(self, *args, **kwargs)
|
return fu(self, *args, **kwargs)
|
||||||
|
|
||||||
return new_fu
|
return new_fu
|
||||||
|
|||||||
10
testsuite.py
10
testsuite.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -30,14 +30,6 @@
|
|||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import unittest
|
|
||||||
|
|
||||||
from worker_test import *
|
|
||||||
from config_test import *
|
|
||||||
from mumo_manager_test import *
|
|
||||||
|
|
||||||
from modules.source.source_test import *
|
|
||||||
from modules.source.users_test import *
|
|
||||||
from modules.source.db_test import *
|
from modules.source.db_test import *
|
||||||
|
|
||||||
# import sys;sys.argv = ['', 'Test.testName']
|
# import sys;sys.argv = ['', 'Test.testName']
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -39,12 +39,10 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
# Default settings
|
|
||||||
|
|
||||||
|
|
||||||
import Ice
|
import Ice
|
||||||
import IcePy
|
import IcePy
|
||||||
|
|
||||||
|
# Default settings
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
@@ -75,21 +73,21 @@ if __name__ == "__main__":
|
|||||||
try:
|
try:
|
||||||
port = int(option.port)
|
port = int(option.port)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Port value '%s' is invalid" % option.port
|
print("Port value '%s' is invalid" % option.port)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
basechan = int(option.base)
|
basechan = int(option.base)
|
||||||
if basechan < 0: raise ValueError
|
if basechan < 0: raise ValueError
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Base channel value '%s' invalid" % option.base
|
print("Base channel value '%s' invalid" % option.base)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sid = int(option.vserver)
|
sid = int(option.vserver)
|
||||||
if sid < 1: raise ValueError
|
if sid < 1: raise ValueError
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Virtual server id value '%s' invalid" % option.vserver
|
print("Virtual server id value '%s' invalid" % option.vserver)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
name = option.name
|
name = option.name
|
||||||
@@ -104,7 +102,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
ice = Ice.initialize(idata)
|
ice = Ice.initialize(idata)
|
||||||
prx = ice.stringToProxy(prxstr)
|
prx = ice.stringToProxy(prxstr)
|
||||||
print "Done"
|
print("Done")
|
||||||
|
|
||||||
|
|
||||||
def lslice(slf):
|
def lslice(slf):
|
||||||
if not hasattr(Ice, "getSliceDir"):
|
if not hasattr(Ice, "getSliceDir"):
|
||||||
@@ -112,9 +111,11 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
Ice.loadSlice('', ['-I' + Ice.getSliceDir(), slf])
|
Ice.loadSlice('', ['-I' + Ice.getSliceDir(), slf])
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print "Trying to retrieve slice dynamically from server...",
|
print("Trying to retrieve slice dynamically from server...", end=' ')
|
||||||
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, (), (), (), IcePy._t_string, ())
|
op = IcePy.Operation('getSlice', Ice.OperationMode.Idempotent, Ice.OperationMode.Idempotent, True, (), (), (),
|
||||||
|
IcePy._t_string, ())
|
||||||
if hasattr(Ice, "getSliceDir"):
|
if hasattr(Ice, "getSliceDir"):
|
||||||
slice = op.invoke(prx, ((), None))
|
slice = op.invoke(prx, ((), None))
|
||||||
else:
|
else:
|
||||||
@@ -126,42 +127,40 @@ if __name__ == "__main__":
|
|||||||
lslice(dynslicefilepath)
|
lslice(dynslicefilepath)
|
||||||
dynslicefile.close()
|
dynslicefile.close()
|
||||||
os.remove(dynslicefilepath)
|
os.remove(dynslicefilepath)
|
||||||
print "Success"
|
print("Success")
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
print "Failed"
|
print("Failed")
|
||||||
print str(e)
|
print(str(e))
|
||||||
slicefile = option.ice
|
slicefile = option.ice
|
||||||
print "Load slice (%s)..." % slicefile,
|
print("Load slice (%s)..." % slicefile, end=' ')
|
||||||
lslice(slicefile)
|
lslice(slicefile)
|
||||||
print "Done"
|
print("Done")
|
||||||
|
|
||||||
print "Import dynamically compiled murmur class...",
|
print("Import dynamically compiled murmur class...", end=' ')
|
||||||
import Murmur
|
import Murmur
|
||||||
print "Done"
|
|
||||||
print "Establish ice connection...",
|
print("Done")
|
||||||
|
print("Establish ice connection...", end=' ')
|
||||||
|
|
||||||
if secret:
|
if secret:
|
||||||
print "[protected]...",
|
print("[protected]...", end=' ')
|
||||||
ice.getImplicitContext().put("secret", secret)
|
ice.getImplicitContext().put("secret", secret)
|
||||||
|
|
||||||
murmur = Murmur.MetaPrx.checkedCast(prx)
|
murmur = Murmur.MetaPrx.checkedCast(prx)
|
||||||
print "Done"
|
print("Done")
|
||||||
|
|
||||||
print "Get server...",
|
print("Get server...", end=' ')
|
||||||
server = murmur.getServer(sid)
|
server = murmur.getServer(sid)
|
||||||
print "Done (%d)" % sid
|
print("Done (%d)" % sid)
|
||||||
|
|
||||||
ini = {}
|
ini = {'mumble_server': sid, 'name': name, 'ipport_filter': '.*'}
|
||||||
ini['mumble_server'] = sid
|
|
||||||
ini['name'] = name
|
|
||||||
ini['ipport_filter'] = '.*'
|
|
||||||
|
|
||||||
print "Creating channel structure:"
|
print("Creating channel structure:")
|
||||||
ACL = Murmur.ACL
|
ACL = Murmur.ACL
|
||||||
EAT = Murmur.PermissionEnter | Murmur.PermissionTraverse
|
EAT = Murmur.PermissionEnter | Murmur.PermissionTraverse
|
||||||
W = Murmur.PermissionWhisper
|
W = Murmur.PermissionWhisper
|
||||||
S = Murmur.PermissionSpeak
|
S = Murmur.PermissionSpeak
|
||||||
print name
|
print(name)
|
||||||
ini['left'] = basechan
|
ini['left'] = basechan
|
||||||
gamechan = server.addChannel(name, basechan)
|
gamechan = server.addChannel(name, basechan)
|
||||||
|
|
||||||
@@ -207,8 +206,8 @@ if __name__ == "__main__":
|
|||||||
"eighth": "Squad 8",
|
"eighth": "Squad 8",
|
||||||
"ninth": "Squad 9"
|
"ninth": "Squad 9"
|
||||||
}
|
}
|
||||||
for team,team_name in teams.items():
|
for team, team_name in list(teams.items()):
|
||||||
print name + "/" + team_name
|
print(name + "/" + team_name)
|
||||||
cid = server.addChannel(team_name, gamechan)
|
cid = server.addChannel(team_name, gamechan)
|
||||||
teamchanstate = server.getChannelState(cid)
|
teamchanstate = server.getChannelState(cid)
|
||||||
if option.linkteams:
|
if option.linkteams:
|
||||||
@@ -224,7 +223,7 @@ if __name__ == "__main__":
|
|||||||
allow=EAT | W)],
|
allow=EAT | W)],
|
||||||
[], True)
|
[], True)
|
||||||
|
|
||||||
print name + "/" + team_name + "/Commander"
|
print(name + "/" + team_name + "/Commander")
|
||||||
cid = server.addChannel("Commander", ini[team])
|
cid = server.addChannel("Commander", ini[team])
|
||||||
teamchanstate.links.append(cid)
|
teamchanstate.links.append(cid)
|
||||||
ini[team + "_commander"] = cid
|
ini[team + "_commander"] = cid
|
||||||
@@ -246,8 +245,8 @@ if __name__ == "__main__":
|
|||||||
state.position = -1
|
state.position = -1
|
||||||
server.setChannelState(state)
|
server.setChannelState(state)
|
||||||
|
|
||||||
for squad,squad_name in id_to_squad_name.items():
|
for squad, squad_name in list(id_to_squad_name.items()):
|
||||||
print name + "/" + team_name + "/" + squad_name
|
print(name + "/" + team_name + "/" + squad_name)
|
||||||
cid = server.addChannel(squad_name, ini[team])
|
cid = server.addChannel(squad_name, ini[team])
|
||||||
teamchanstate.links.append(cid)
|
teamchanstate.links.append(cid)
|
||||||
ini[team + "_" + squad + "_squad"] = cid
|
ini[team + "_" + squad + "_squad"] = cid
|
||||||
@@ -272,18 +271,17 @@ if __name__ == "__main__":
|
|||||||
[], True)
|
[], True)
|
||||||
server.setChannelState(teamchanstate)
|
server.setChannelState(teamchanstate)
|
||||||
server.setChannelState(gamechanstate)
|
server.setChannelState(gamechanstate)
|
||||||
print "Channel structure created"
|
print("Channel structure created")
|
||||||
|
|
||||||
print "Writing configuration to output file '%s'..." % option.out,
|
print("Writing configuration to output file '%s'..." % option.out, end=' ')
|
||||||
f = open(option.out, "w")
|
f = open(option.out, "w")
|
||||||
print>>f, "; Configuration created by mbf2man\n"
|
print("; Configuration created by mbf2man\n", file=f)
|
||||||
print>>f, "[bf2]\ngamecount = 1\n"
|
print("[bf2]\ngamecount = 1\n", file=f)
|
||||||
print>>f, "[g0]"
|
print("[g0]", file=f)
|
||||||
|
|
||||||
for key in sorted(ini):
|
for key in sorted(ini):
|
||||||
value = ini[key]
|
value = ini[key]
|
||||||
print>>f, "%s = %s" % (key, value)
|
print("%s = %s" % (key, value), file=f)
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
print "Done"
|
print("Done")
|
||||||
|
|
||||||
|
|||||||
18
worker.py
18
worker.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,20 +29,24 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
from threading import Thread
|
|
||||||
from Queue import Queue, Empty
|
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
from queue import Queue, Empty
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
|
||||||
def local_thread(fu):
|
def local_thread(fu):
|
||||||
"""
|
"""
|
||||||
Decorator which makes a function execute in the local worker thread
|
Decorator which makes a function execute in the local worker thread
|
||||||
Return values are discarded
|
Return values are discarded
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def new_fu(*args, **kwargs):
|
def new_fu(*args, **kwargs):
|
||||||
self = args[0]
|
self = args[0]
|
||||||
self.message_queue().put((None, fu, args, kwargs))
|
self.message_queue().put((None, fu, args, kwargs))
|
||||||
|
|
||||||
return new_fu
|
return new_fu
|
||||||
|
|
||||||
|
|
||||||
def local_thread_blocking(fu, timeout=None):
|
def local_thread_blocking(fu, timeout=None):
|
||||||
"""
|
"""
|
||||||
Decorator which makes a function execute in the local worker thread
|
Decorator which makes a function execute in the local worker thread
|
||||||
@@ -51,6 +55,7 @@ def local_thread_blocking(fu, timeout = None):
|
|||||||
|
|
||||||
@param timeout Timeout in seconds
|
@param timeout Timeout in seconds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def new_fu(*args, **kwargs):
|
def new_fu(*args, **kwargs):
|
||||||
self = args[0]
|
self = args[0]
|
||||||
out = Queue()
|
out = Queue()
|
||||||
@@ -101,25 +106,26 @@ class Worker(Thread):
|
|||||||
Override this function to perform actions on worker shutdown
|
Override this function to perform actions on worker shutdown
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# --- Thread / Control
|
# --- Thread / Control
|
||||||
def run(self):
|
def run(self):
|
||||||
self.log().debug("Enter message loop")
|
self.log().debug("Enter message loop")
|
||||||
self.onStart()
|
self.onStart()
|
||||||
while True:
|
while True:
|
||||||
msg = self.__in.get()
|
msg = self.__in.get()
|
||||||
if msg == None:
|
if msg is None:
|
||||||
break
|
break
|
||||||
|
|
||||||
(out, fu, args, kwargs) = msg
|
(out, fu, args, kwargs) = msg
|
||||||
try:
|
try:
|
||||||
res = fu(*args, **kwargs)
|
res = fu(*args, **kwargs)
|
||||||
ex = None
|
ex = None
|
||||||
except Exception, e:
|
except Exception as e:
|
||||||
self.log().exception(e)
|
self.log().exception(e)
|
||||||
res = None
|
res = None
|
||||||
ex = e
|
ex = e
|
||||||
finally:
|
finally:
|
||||||
if not out is None:
|
if out is not None:
|
||||||
out.put((res, ex))
|
out.put((res, ex))
|
||||||
|
|
||||||
self.onStop()
|
self.onStop()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8
|
# -*- coding: utf-8
|
||||||
|
|
||||||
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
# Copyright (C) 2010 Stefan Hacker <dd0t@users.sourceforge.net>
|
||||||
@@ -29,27 +29,26 @@
|
|||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import worker
|
|
||||||
from worker import Worker, local_thread, local_thread_blocking
|
|
||||||
from Queue import Queue
|
|
||||||
from logging.handlers import BufferingHandler
|
|
||||||
from logging import ERROR
|
|
||||||
import logging
|
import logging
|
||||||
|
import unittest
|
||||||
|
from logging import ERROR
|
||||||
|
from logging.handlers import BufferingHandler
|
||||||
|
from queue import Queue
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
from worker import Worker, local_thread, local_thread_blocking
|
||||||
|
|
||||||
|
|
||||||
class WorkerTest(unittest.TestCase):
|
class WorkerTest(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
||||||
def set_ev(fu):
|
def set_ev(fu):
|
||||||
def new_fu(*args, **kwargs):
|
def new_fu(*args, **kwargs):
|
||||||
s = args[0]
|
s = args[0]
|
||||||
s.event.set()
|
s.event.set()
|
||||||
s.val = (args, kwargs)
|
s.val = (args, kwargs)
|
||||||
return fu(*args, **kwargs)
|
return fu(*args, **kwargs)
|
||||||
|
|
||||||
return new_fu
|
return new_fu
|
||||||
|
|
||||||
class ATestWorker(Worker):
|
class ATestWorker(Worker):
|
||||||
@@ -91,7 +90,6 @@ class WorkerTest(unittest.TestCase):
|
|||||||
def call_me_by_name_blocking(self, arg1, arg2):
|
def call_me_by_name_blocking(self, arg1, arg2):
|
||||||
return arg1, arg2
|
return arg1, arg2
|
||||||
|
|
||||||
|
|
||||||
self.buha = BufferingHandler(10000)
|
self.buha = BufferingHandler(10000)
|
||||||
|
|
||||||
q = Queue()
|
q = Queue()
|
||||||
@@ -148,6 +146,7 @@ class WorkerTest(unittest.TestCase):
|
|||||||
|
|
||||||
def testLocalThreadExceptionBlocking(self):
|
def testLocalThreadExceptionBlocking(self):
|
||||||
class TestException(Exception): pass
|
class TestException(Exception): pass
|
||||||
|
|
||||||
self.assertRaises(TestException, self.w.raise_blocking, TestException())
|
self.assertRaises(TestException, self.w.raise_blocking, TestException())
|
||||||
|
|
||||||
def testCallByNameBlocking(self):
|
def testCallByNameBlocking(self):
|
||||||
@@ -157,11 +156,10 @@ class WorkerTest(unittest.TestCase):
|
|||||||
assert (arg2 == "arg2")
|
assert (arg2 == "arg2")
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
assert(self.w.stopped == False)
|
assert (self.w.stopped is False)
|
||||||
self.w.stop()
|
self.w.stop()
|
||||||
self.w.join(5)
|
self.w.join(5)
|
||||||
assert(self.w.stopped == True)
|
assert self.w.stopped
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user