import datetime, socket, struct from src import ModuleManager, utils DEFAULT_PORT = 64738 def _parse(s): host, _, port = s.partition(":") if port: if not port.isdigit(): return None else: port = str(DEFAULT_PORT) return "%s:%s" % (host, port) SETTING = utils.FunctionSetting(_parse, "mumble-server", "Set the mumble server for this channel", example="example.com:%s" % DEFAULT_PORT) @utils.export("channelset", SETTING) @utils.export("serverset", SETTING) class Module(ModuleManager.BaseModule): @utils.hook("received.command.mumble") @utils.kwarg("help", "Get user and bandwidth stats for a mumble server") @utils.kwarg("usage", "[server[:]]") def mumble(self, event): server = None if not event["args"]: server = event["target"].get_setting("mumble-server", event["server"].get_setting("mumble-server", None)) elif event["args"]: server = event["args_split"][0] if not server: raise utils.EventError("Please provide a server") server, _, port = server.partition(":") if port: if not port.isdigit(): raise utils.EventError("Port must be numeric") port = int(port) else: port = DEFAULT_PORT timestamp = datetime.datetime.utcnow().microsecond ping_packet = struct.pack(">iQ", 0, timestamp) s = socket.socket(type=socket.SOCK_DGRAM) s.settimeout(5) with utils.deadline(): try: s.sendto(ping_packet, (server, port)) except socket.gaierror as e: raise utils.EventError(str(e)) try: pong_packet = s.recv(24) except socket.timeout: raise utils.EventError( "Timed out waiting for response from %s:%d" % (server, port)) pong = struct.unpack(">bbbbQiii", pong_packet) version = ".".join(str(v) for v in pong[1:4]) ping = (datetime.datetime.utcnow().microsecond-timestamp)/1000 users = pong[5] max_users = pong[6] bandwidth = pong[7]/1000 # kbit/s event["stdout"].write( "%s:%d (v%s): %d/%d users, %.1fms ping, %dkbit/s bandwidth" % (server, port, version, users, max_users, ping, bandwidth))