From b4bca4c6f2f32f5fb8121d837a2dc81b200f33e1 Mon Sep 17 00:00:00 2001 From: Ryan Huber Date: Sat, 17 Jan 2015 23:45:38 -0800 Subject: autopep8'd --- wee_slack.py | 407 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 283 insertions(+), 124 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index b59e084..267ab34 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -10,7 +10,7 @@ import urlparse import HTMLParser from websocket import create_connection -#hack to make tests possible.. better way? +# hack to make tests possible.. better way? try: import weechat as w except: @@ -25,64 +25,74 @@ SCRIPT_DESC = "Extends weechat for typing notification/search/etc on slack.com" BACKLOG_SIZE = 200 SLACK_API_TRANSLATOR = { - "channel": { - "history" : "channels.history", - "join" : "channels.join", - "leave" : "channels.leave", - "mark" : "channels.mark", - "info" : "channels.info" - }, - "im": { - "history" : "im.history", - "leave" : "im.close", - "mark" : "im.mark" - }, - "group": { - "history" : "groups.history", - "join" : "channels.join", - "leave" : "groups.leave", - "mark" : "groups.mark" - } - - } + "channel": { + "history": "channels.history", + "join": "channels.join", + "leave": "channels.leave", + "mark": "channels.mark", + "info": "channels.info" + }, + "im": { + "history": "im.history", + "leave": "im.close", + "mark": "im.mark" + }, + "group": { + "history": "groups.history", + "join": "channels.join", + "leave": "groups.leave", + "mark": "groups.mark" + } + +} + def dbg(message, fout=False, main_buffer=False): message = "DEBUG: " + str(message) message = message.encode('ascii', 'ignore') if fout: - file('/tmp/debug.log', 'a+').writelines(message+'\n') - if slack_debug != None: + file('/tmp/debug.log', 'a+').writelines(message + '\n') + if slack_debug is not None: if not main_buffer: w.prnt(slack_debug, message) else: w.prnt("", message) -#hilarious, i know +# hilarious, i know + + class Meta(list): + def __init__(self, attribute, search_list): self.attribute = attribute self.search_list = search_list + def __str__(self): string = '' for each in self.search_list.get_all(self.attribute): string += str(each) + ' ' return string + def __repr__(self): self.search_list.get_all(self.attribute) + def __getitem__(self, index): channels = self.get_all() return channels[index] + def __iter__(self): channels = self.get_all() for channel in channels: yield channel + def get_all(self): items = [] items += self.search_list.get_all(self.attribute) return items + def find(self, name): items = self.search_list.find_deep(name, self.attribute) - items = [x for x in items if x != None] + items = [x for x in items if x is not None] if len(items) == 1: return items[0] elif len(items) == 0: @@ -91,17 +101,21 @@ class Meta(list): dbg("probably something bad happened with meta items: {}".format(items)) return items raise AmbiguousProblemError + def find_first(self, name): items = self.find(name) if items.__class__ == list: return items[0] else: return False + def find_by_class(self, class_name): items = self.search_list.find_by_class_deep(class_name, self.attribute) return items + class SearchList(list): + def find(self, name): items = [] for child in self: @@ -114,41 +128,47 @@ class SearchList(list): return items[0] elif items != []: return items + def find_deep(self, name, attribute): items = [] for child in self: if child.__class__ == self.__class__: - if items != None: + if items is not None: items += child.find_deep(name, attribute) elif dir(child).count('find') == 1: - if items != None: + if items is not None: items.append(child.find(name, attribute)) if items != []: return items + def get_all(self, attribute): items = [] for child in self: if child.__class__ == self.__class__: items += child.get_all(attribute) else: - items += (eval("child."+attribute)) + items += (eval("child." + attribute)) return items + def find_by_class(self, class_name): items = [] for child in self: if child.__class__ == class_name: items.append(child) return items + def find_by_class_deep(self, class_name, attribute): items = [] for child in self: if child.__class__ == self.__class__: items += child.find_by_class_deep(class_name, attribute) else: - items += (eval('child.'+attribute).find_by_class(class_name)) + items += (eval('child.' + attribute).find_by_class(class_name)) return items + class SlackServer(object): + def __init__(self, token): self.nick = None self.name = None @@ -167,37 +187,45 @@ class SlackServer(object): self.identifier = None self.connect_to_slack() + def __eq__(self, compare_str): if compare_str == self.identifier or compare_str == self.token or compare_str == self.buffer: return True else: return False + def __str__(self): return "{}".format(self.identifier) + def __repr__(self): return "{}".format(self.identifier) + def find(self, name, attribute): - attribute = eval("self."+attribute) + attribute = eval("self." + attribute) return attribute.find(name) + def send_to_websocket(self, data): try: self.ws.send(data) dbg("Sent {}...".format(data[:100])) except: self.connected = False + def ping(self): if self.ping_counter > 999: self.ping_counter = 0 - request = {"type":"ping", "id":self.ping_counter} + request = {"type": "ping", "id": self.ping_counter} self.send_to_websocket(json.dumps(request)) self.ping_counter += 1 + def connect_to_slack(self): t = time.time() if not self.connecting: - async_slack_api_request("slack.com", self.token, "rtm.start", {"ts":t}) + async_slack_api_request("slack.com", self.token, "rtm.start", {"ts": t}) self.connecting = True + def connected_to_slack(self, login_data): - if login_data["ok"] == True: + if login_data["ok"]: self.domain = login_data["team"]["domain"] + ".slack.com" dbg("connected to {}".format(self.domain)) self.identifier = self.domain @@ -219,10 +247,12 @@ class SlackServer(object): else: w.prnt("", "\n!! slack.com login error: " + login_data["error"] + "\n Please check your API token with\n \"/set plugins.var.python.slack_extension.slack_api_token (token)\"\n\n ") self.connected = False + def create_local_buffer(self): if not w.buffer_search("", self.domain): self.buffer = w.buffer_new(self.domain, "buffer_input_cb", "", "", "") w.buffer_set(self.buffer, "nicklist", "1") + def create_slack_websocket(self, data): web_socket_url = data['url'] try: @@ -232,35 +262,37 @@ class SlackServer(object): return True except: return False + def create_slack_mappings(self, data): for item in data["users"]: self.users.append(User(self, item["name"], item["id"], item["presence"])) for item in data["channels"]: - if not item.has_key("last_read"): + if "last_read" not in item: item["last_read"] = 0 - if not item.has_key("members"): + if "members" not in item: item["members"] = [] - if not item.has_key("topic"): + if "topic" not in item: item["topic"] = {} item["topic"]["value"] = "" self.channels.append(Channel(self, item["name"], item["id"], item["is_member"], item["last_read"], "#", item["members"], item["topic"]["value"])) for item in data["groups"]: - if not item.has_key("last_read"): + if "last_read" not in item: item["last_read"] = 0 self.channels.append(GroupChannel(self, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"]["value"])) for item in data["ims"]: - if not item.has_key("last_read"): + if "last_read" not in item: item["last_read"] = 0 name = self.users.find(item["user"]).name self.channels.append(DmChannel(self, name, item["id"], item["is_open"], item["last_read"])) for item in self.channels: item.get_history() + def buffer_prnt(self, message='no message', user="SYSTEM", backlog=False): message = message.encode('ascii', 'ignore') - if backlog == True: + if backlog: tags = "no_highlight,notify_none,logger_backlog_end" else: tags = "" @@ -270,16 +302,21 @@ class SlackServer(object): pass #w.prnt("", "%s\t%s" % (user, message)) + class SlackThing(object): + def __init__(self, name, identifier): self.name = name self.identifier = identifier self.channel_buffer = None + def __str__(self): return self.name + def __repr__(self): return self.name + def buffer_input_cb(b, buffer, data): channel = channels.find(buffer) channel.send_message(data) @@ -287,7 +324,9 @@ def buffer_input_cb(b, buffer, data): channel.mark_read(True) return w.WEECHAT_RC_ERROR + class Channel(SlackThing): + def __init__(self, server, name, identifier, active, last_read=0, prepend_name="", members=[], topic=""): super(Channel, self).__init__(name, identifier) self.type = "channel" @@ -305,11 +344,13 @@ class Channel(SlackThing): self.attach_buffer() self.update_nicklist() self.set_topic(self.topic) + def __eq__(self, compare_str): - if compare_str == self.fullname() or compare_str == self.name or compare_str == self.identifier or compare_str == self.name[1:] or (compare_str == self.channel_buffer and self.channel_buffer != None): + if compare_str == self.fullname() or compare_str == self.name or compare_str == self.identifier or compare_str == self.name[1:] or (compare_str == self.channel_buffer and self.channel_buffer is not None): return True else: return False + def create_buffer(self): channel_buffer = w.buffer_search("", "{}.{}".format(self.server.domain, self.name)) if channel_buffer: @@ -321,6 +362,7 @@ class Channel(SlackThing): else: w.buffer_set(self.channel_buffer, "localvar_set_type", 'channel') w.buffer_set(self.channel_buffer, "short_name", 'loading..') + def attach_buffer(self): channel_buffer = w.buffer_search("", "{}.{}".format(self.server.domain, self.name)) if channel_buffer != main_weechat_buffer: @@ -328,10 +370,12 @@ class Channel(SlackThing): # w.buffer_set(self.channel_buffer, "highlight_words", self.server.nick) else: self.channel_buffer = None + def detach_buffer(self): - if self.channel_buffer != None: + if self.channel_buffer is not None: w.buffer_close(self.channel_buffer) self.channel_buffer = None + def update_nicklist(self): w.buffer_set(self.channel_buffer, "nicklist", "1") w.nicklist_remove_all(self.channel_buffer) @@ -341,28 +385,37 @@ class Channel(SlackThing): w.nicklist_add_nick(self.channel_buffer, "", user.name, user.color(), " ", "", 1) else: w.nicklist_add_nick(self.channel_buffer, "", user.name, user.color(), "+", "", 1) + def fullname(self): return "{}.{}".format(self.server.domain, self.name) + def has_user(self, name): return name in self.members + def user_join(self, name): self.members.add(name) self.update_nicklist() + def user_leave(self, name): if name in self.members: self.members.remove(name) self.update_nicklist() + def set_active(self): self.active = True + def set_inactive(self): self.active = False + def set_typing(self, user): self.typing[user] = time.time() + def send_message(self, message): message = self.linkify_text(message) dbg(message) - request = {"type":"message", "channel":self.identifier, "text": message} + request = {"type": "message", "channel": self.identifier, "text": message} self.server.send_to_websocket(json.dumps(request)) + def linkify_text(self, message): message = message.split(' ') for item in enumerate(message): @@ -376,43 +429,51 @@ class Channel(SlackThing): message[item[0]] = "<#{}>{}".format(self.server.channels.find(named[0]).identifier, named[1]) dbg(message) return " ".join(message) + def set_topic(self, topic): topic = topic.encode('ascii', 'ignore') - w.buffer_set(self.channel_buffer, "title", topic); + w.buffer_set(self.channel_buffer, "title", topic) + def open(self, update_remote=True): self.create_buffer() self.active = True self.get_history() t = time.time() - async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name":self.name.lstrip("#"), "ts":t}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["info"], {"name": self.name.lstrip("#"), "ts": t}) if update_remote: - async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["join"], {"name":self.name.lstrip("#"), "ts":t}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["join"], {"name": self.name.lstrip("#"), "ts": t}) + def close(self, update_remote=True): - if self.active == True: + if self.active: self.active = False self.detach_buffer() if update_remote: t = time.time() - async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["leave"], {"channel":self.identifier, "ts":t}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["leave"], {"channel": self.identifier, "ts": t}) + def closed(self): self.channel_buffer = None self.close() + def unset_typing(self, user): try: del self.typing[user] except: pass + def is_someone_typing(self): for user in self.typing.keys(): if self.typing[user] + 4 > time.time(): return True return False + def get_typing_list(self): typing = [] for user in self.typing.keys(): if self.typing[user] + 4 > time.time(): typing.append(user) return typing + def mark_read(self, update_remote=True): t = time.time() @@ -421,20 +482,23 @@ class Channel(SlackThing): if update_remote: self.last_read = time.time() self.set_read_marker(self.last_read) + def set_read_marker(self, time): - async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["mark"], {"channel":self.identifier, "ts":time}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["mark"], {"channel": self.identifier, "ts": time}) + def rename(self): if current_domain_name() != self.server.domain and channels_not_on_current_server_color: color = channels_not_on_current_server_color else: color = "default" color = w.color(color) - if self.is_someone_typing() == True: + if self.is_someone_typing(): new_name = ">{}".format(self.name[1:]) else: new_name = self.name if self.channel_buffer: w.buffer_set(self.channel_buffer, "short_name", color + new_name) + def buffer_prnt(self, user='unknown user', message='no message', time=0, backlog=False): set_read_marker = False time = float(time) @@ -459,31 +523,37 @@ class Channel(SlackThing): message = message[len(self.previous_prnt_message):] message = HTMLParser.HTMLParser().unescape(message) w.prnt_date_tags(self.channel_buffer, time, tags, "{}\t{}".format(name, message)) - #eventually maybe - doesn't reprint name if next message is same user - #if name != self.previous_prnt_name: + # eventually maybe - doesn't reprint name if next message is same user + # if name != self.previous_prnt_name: # w.prnt_date_tags(self.channel_buffer, time, tags, "%s\t%s" % (name, message)) # self.previous_prnt_name = name - #else: + # else: # w.prnt_date_tags(self.channel_buffer, time, tags, "%s\t%s" % ("", message)) self.previous_prnt_message = message if set_read_marker: self.mark_read(False) else: self.open(False) + def get_history(self): if self.active: t = time.time() - async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["history"], {"channel":self.identifier, "ts":t, "count":BACKLOG_SIZE}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["history"], {"channel": self.identifier, "ts": t, "count": BACKLOG_SIZE}) + class GroupChannel(Channel): + def __init__(self, server, name, identifier, active, last_read=0, prepend_name="", members=[], topic=""): super(GroupChannel, self).__init__(server, name, identifier, active, last_read, prepend_name, members, topic) self.type = "group" + class DmChannel(Channel): + def __init__(self, server, name, identifier, active, last_read=0, prepend_name=""): super(DmChannel, self).__init__(server, name, identifier, active, last_read, prepend_name) self.type = "im" + def rename(self): if current_domain_name() != self.server.domain and channels_not_on_current_server_color: color = channels_not_on_current_server_color @@ -497,7 +567,9 @@ class DmChannel(Channel): if self.channel_buffer: w.buffer_set(self.channel_buffer, "short_name", color + new_name) + class User(SlackThing): + def __init__(self, server, name, identifier, presence="away"): super(User, self).__init__(name, identifier) self.channel_buffer = w.info_get("irc_buffer", "{}.{}".format(domain, self.name)) @@ -508,11 +580,13 @@ class User(SlackThing): else: self.nicklist_pointer = w.nicklist_add_nick(server.buffer, "", self.name, self.color(), "+", "", 1) # w.nicklist_add_nick(server.buffer, "", self.colorized_name(), "", "", "", 1) + def __eq__(self, compare_str): - if compare_str == self.name or compare_str == "@" + self.name or compare_str == self.identifier: + if compare_str == self.name or compare_str == "@" + self.name or compare_str == self.identifier: return True else: return False + def set_active(self): self.presence = "active" for channel in self.server.channels: @@ -520,6 +594,7 @@ class User(SlackThing): channel.update_nicklist() w.nicklist_nick_set(self.server.buffer, self.nicklist_pointer, "prefix", "+") w.nicklist_nick_set(self.server.buffer, self.nicklist_pointer, "visible", "1") + def set_inactive(self): self.presence = "away" for channel in self.server.channels: @@ -527,22 +602,26 @@ class User(SlackThing): channel.update_nicklist() w.nicklist_nick_set(self.server.buffer, self.nicklist_pointer, "prefix", " ") w.nicklist_nick_set(self.server.buffer, self.nicklist_pointer, "visible", "0") + def color(self): if colorize_nicks: return w.info_get('irc_nick_color_name', self.name) else: return "default" + def colorized_name(self): if colorize_nicks: color = w.info_get('irc_nick_color', self.name) def_color = w.color('default') - return color+self.name+def_color + return color + self.name + def_color else: return self.name + def open(self): t = time.time() + 1 #reply = async_slack_api_request("im.open", {"channel":self.identifier,"ts":t}) - async_slack_api_request(self.server.domain, self.server.token, "im.open", {"user":self.identifier, "ts":t}) + async_slack_api_request(self.server.domain, self.server.token, "im.open", {"user": self.identifier, "ts": t}) + def slack_command_cb(data, current_buffer, args): a = args.split(' ', 1) @@ -556,6 +635,7 @@ def slack_command_cb(data, current_buffer, args): # w.prnt("", "Command not found or exception: "+function_name) return w.WEECHAT_RC_OK + def me_command_cb(data, current_buffer, args): if channels.find(current_buffer): channel = channels.find(current_buffer) @@ -564,6 +644,7 @@ def me_command_cb(data, current_buffer, args): buffer_input_cb("", current_buffer, message) return w.WEECHAT_RC_OK + def join_command_cb(data, current_buffer, args): if channels.find(current_buffer) or servers.find(current_buffer): channel = args.split()[1] @@ -572,6 +653,7 @@ def join_command_cb(data, current_buffer, args): else: return w.WEECHAT_RC_OK + def part_command_cb(data, current_buffer, args): if channels.find(current_buffer) or servers.find(current_buffer): args = args.split() @@ -584,69 +666,84 @@ def part_command_cb(data, current_buffer, args): else: return w.WEECHAT_RC_OK + def command_talk(current_buffer, args): servers.find(current_domain_name()).users.find(args).open() + def command_join(current_buffer, args): servers.find(current_domain_name()).channels.find(args).open() + def command_channels(current_buffer, args): server = servers.find(current_domain_name()) for channel in server.channels: line = "{:<25} {} {}".format(channel.name, channel.identifier, channel.active) server.buffer_prnt(line) + def command_users(current_buffer, args): server = servers.find(current_domain_name()) for user in server.users: line = "{:<40} {} {}".format(user.colorized_name(), user.identifier, user.presence) server.buffer_prnt(line) + def command_setallreadmarkers(current_buffer, args): if args: for channel in channels: channel.set_read_marker(args) + def command_changetoken(current_buffer, args): w.config_set_plugin('slack_api_token', args) + def command_test(current_buffer, args): if slack_buffer: w.prnt(slack_buffer, "worked!") + def command_away(current_buffer, args): server = servers.find(current_domain_name()) - async_slack_api_request(server.domain, server.token, 'presence.set', {"presence":"away"}) + async_slack_api_request(server.domain, server.token, 'presence.set', {"presence": "away"}) + def command_back(current_buffer, args): server = servers.find(current_domain_name()) - async_slack_api_request(server.domain, server.token, 'presence.set', {"presence":"active"}) + async_slack_api_request(server.domain, server.token, 'presence.set', {"presence": "active"}) + def command_markread(current_buffer, args): - #refactor this - one liner i think + # refactor this - one liner i think channel = current_buffer_name(short=True) domain = current_domain_name() if servers.find(domain).channels.find(channel): servers.find(domain).channels.find(channel).mark_read() + def command_neveraway(current_buffer, args): global never_away - if never_away == True: + if never_away: never_away = False dbg("unset never_away") else: never_away = True dbg("set never_away") + def command_printvar(current_buffer, args): w.prnt("", str(eval(args))) + def command_p(current_buffer, args): w.prnt("", str(eval(args))) + def command_debug(current_buffer, args): create_slack_debug_buffer() + def command_debugstring(current_buffer, args): global debug_string if args == '': @@ -654,6 +751,7 @@ def command_debugstring(current_buffer, args): else: debug_string = args + def command_search(current_buffer, args): pass # if not slack_buffer: @@ -668,6 +766,7 @@ def command_search(current_buffer, args): # formatted_message = "%s / %s:\t%s" % (message["channel"]["name"], message['username'], message['text']) # w.prnt(slack_buffer,str(formatted_message)) + def command_nick(current_buffer, args): pass # urllib.urlopen("https://%s/account/settings" % (domain)) @@ -675,25 +774,26 @@ def command_nick(current_buffer, args): # browser.form['username'] = args # reply = browser.submit() -### Websocket handling methods +# Websocket handling methods + def slack_websocket_cb(data, fd): server = data try: data = servers.find(server).ws.recv() message_json = json.loads(data) - #this magic attaches json that helps find the right dest + # this magic attaches json that helps find the right dest message_json['myserver'] = server except: return w.WEECHAT_RC_OK - #dispatch here - if message_json.has_key("type"): + # dispatch here + if "type" in message_json: function_name = message_json["type"] else: function_name = "unknown" try: proc[function_name](message_json) - #dbg(function_name) + # dbg(function_name) except KeyError: pass if function_name: @@ -703,15 +803,18 @@ def slack_websocket_cb(data, fd): w.bar_item_update("slack_typing_notice") return w.WEECHAT_RC_OK + def process_pong(message_json): pass + def process_team_join(message_json): server = servers.find(message_json["myserver"]) item = message_json["user"] server.users.append(User(server, item["name"], item["id"], item["presence"])) w.prnt(server.buffer, "New user joined: {}".format(item["name"])) + def process_presence_change(message_json): buffer_name = "{}.{}".format(domain, message_json["user"]) buf_ptr = w.buffer_search("", buffer_name) @@ -720,18 +823,21 @@ def process_presence_change(message_json): else: users.find(message_json["user"]).set_inactive() + def process_channel_marked(message_json): channel = channels.find(message_json["channel"]) channel.mark_read(False) if not legacy_mode: w.buffer_set(channel.channel_buffer, "hotlist", "-1") + def process_group_marked(message_json): channel = channels.find(message_json["channel"]) channel.mark_read(False) if not legacy_mode: w.buffer_set(channel.channel_buffer, "hotlist", "-1") + def process_channel_created(message_json): server = servers.find(message_json["myserver"]) item = message_json["channel"] @@ -742,20 +848,24 @@ def process_channel_created(message_json): server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) w.prnt(server.buffer, "New channel created: {}".format(item["name"])) + def process_channel_left(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).close(False) + def process_channel_join(message_json): server = servers.find(message_json["myserver"]) channel = server.channels.find(message_json["channel"]) channel.user_join(message_json["user"]) + def process_channel_topic(message_json): server = servers.find(message_json["myserver"]) channel = server.channels.find(message_json["channel"]) channel.set_topic(message_json["topic"]) + def process_channel_joined(message_json): server = servers.find(message_json["myserver"]) if server.channels.find(message_json["channel"]["name"]): @@ -764,15 +874,18 @@ def process_channel_joined(message_json): item = message_json["channel"] server.channels.append(Channel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) + def process_channel_leave(message_json): server = servers.find(message_json["myserver"]) channel = server.channels.find(message_json["channel"]) channel.user_leave(message_json["user"]) + def process_group_left(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).close(False) + def process_group_joined(message_json): server = servers.find(message_json["myserver"]) if server.channels.find(message_json["channel"]["name"]): @@ -781,20 +894,24 @@ def process_group_joined(message_json): item = message_json["channel"] server.channels.append(GroupChannel(server, item["name"], item["id"], item["is_open"], item["last_read"], "#", item["members"], item["topic"])) + def process_im_close(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).close(False) + def process_im_open(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).open(False) + def process_im_marked(message_json): channel = channels.find(message_json["channel"]) channel.mark_read(False) if not legacy_mode: w.buffer_set(channel.channel_buffer, "hotlist", "-1") + def process_im_created(message_json): server = servers.find(message_json["myserver"]) item = message_json["channel"] @@ -806,42 +923,46 @@ def process_im_created(message_json): server.channels.append(DmChannel(server, channel_name, item["id"], item["is_open"], item["last_read"])) w.prnt(server.buffer, "New channel created: {}".format(item["name"])) + def process_user_typing(message_json): server = servers.find(message_json["myserver"]) server.channels.find(message_json["channel"]).set_typing(server.users.find(message_json["user"]).name) -#todo: does this work? +# todo: does this work? + + def process_error(message_json): pass #connected = False -#def process_message_changed(message_json): +# def process_message_changed(message_json): # process_message(message_json) + def process_message(message_json): mark_silly_channels_read(message_json["channel"]) - #send these messages elsewhere + # send these messages elsewhere known_subtypes = ['channel_join', 'channel_leave', 'channel_topic'] - if message_json.has_key("subtype") and message_json["subtype"] in known_subtypes: + if "subtype" in message_json and message_json["subtype"] in known_subtypes: proc[message_json["subtype"]](message_json) else: - #move message properties down to root of json object + # move message properties down to root of json object message_json = unwrap_message(message_json) server = servers.find(message_json["myserver"]) channel = channels.find(message_json["channel"]) time = message_json['ts'] - if message_json.has_key("fallback"): + if "fallback" in message_json: text = message_json["fallback"] - elif message_json.has_key("text"): + elif "text" in message_json: text = message_json["text"] else: text = "" text = unfurl_refs(text) - if message_json.has_key("attachments"): + if "attachments" in message_json: text += "--- {}".format(unwrap_attachments(message_json)) text = text.lstrip() text = text.replace("\t", " ") @@ -851,41 +972,44 @@ def process_message(message_json): server.channels.find(channel).buffer_prnt(name, text, time) + def unwrap_message(message_json): - if message_json.has_key("message"): - if message_json["message"].has_key("attachments"): + if "message" in message_json: + if "attachments" in message_json["message"]: message_json["attachments"] = message_json["message"]["attachments"] - if message_json["message"].has_key("text"): - if message_json.has_key("text"): + if "text" in message_json["message"]: + if "text" in message_json: message_json["text"] += message_json["message"]["text"] dbg("added text!") else: message_json["text"] = message_json["message"]["text"] - if message_json["message"].has_key("fallback"): - if message_json.has_key("fallback"): + if "fallback" in message_json["message"]: + if "fallback" in message_json: message_json["fallback"] += message_json["message"]["fallback"] else: message_json["fallback"] = message_json["message"]["fallback"] return message_json + def unwrap_attachments(message_json): attachment_text = '' for attachment in message_json["attachments"]: - if attachment.has_key("fallback"): + if "fallback" in attachment: attachment_text += attachment["fallback"] attachment_text = attachment_text.encode('ascii', 'ignore') return attachment_text + def unfurl_refs(text): if text.find('<') > -1: newtext = [] text = text.split(" ") for item in text: - #dbg(item) + # dbg(item) start = item.find('<') end = item.find('>') if start > -1 and end > -1: - item = item[start+1:end] + item = item[start + 1:end] if item.find('|') > -1: item = item.split('|')[0] if item.startswith('@U'): @@ -903,23 +1027,25 @@ def unfurl_refs(text): else: return text + def get_user(message_json, server): - if message_json.has_key('user'): + if 'user' in message_json: name = server.users.find(message_json['user']).name - elif message_json.has_key('username'): + elif 'username' in message_json: name = "-{}-".format(message_json["username"]) - elif message_json.has_key('service_name'): + elif 'service_name' in message_json: name = "-{}-".format(message_json["service_name"]) - elif message_json.has_key('bot_id'): + elif 'bot_id' in message_json: name = "-{}-".format(message_json["bot_id"]) else: name = "" return name -### END Websocket handling methods +# END Websocket handling methods + def typing_bar_item_cb(data, buffer, args): - typers = [x for x in channels.get_all() if x.is_someone_typing() == True] + typers = [x for x in channels.get_all() if x.is_someone_typing()] if len(typers) > 0: direct_typers = [] channel_typers = [] @@ -939,36 +1065,41 @@ def typing_bar_item_cb(data, buffer, args): return color + "typing: " + typing_here return "" + def typing_update_cb(data, remaining_calls): w.bar_item_update("slack_typing_notice") return w.WEECHAT_RC_OK + def buffer_list_update_cb(data, remaining_calls): gray_check = False if len(servers) > 1: gray_check = True - #for channel in channels.find_by_class(Channel) + channels.find_by_class(GroupChannel): + # for channel in channels.find_by_class(Channel) + channels.find_by_class(GroupChannel): for channel in channels: channel.rename() return w.WEECHAT_RC_OK + def hotlist_cache_update_cb(data, remaining_calls): - #this keeps the hotlist dupe up to date for the buffer switch, but is prob technically a race condition. (meh) + # this keeps the hotlist dupe up to date for the buffer switch, but is prob technically a race condition. (meh) global hotlist prev_hotlist = hotlist hotlist = w.infolist_get("hotlist", "", "") w.infolist_free(prev_hotlist) return w.WEECHAT_RC_OK + def buffer_closing_cb(signal, sig_type, data): if channels.find(data): channels.find(data).closed() return w.WEECHAT_RC_OK + def buffer_switch_cb(signal, sig_type, data): global previous_buffer, hotlist - #this is to see if we need to gray out things in the buffer list - buffer_list_update_cb('','') + # this is to see if we need to gray out things in the buffer list + buffer_list_update_cb('', '') if channels.find(previous_buffer): channels.find(previous_buffer).mark_read() @@ -976,6 +1107,7 @@ def buffer_switch_cb(signal, sig_type, data): previous_buffer = data return w.WEECHAT_RC_OK + def typing_notification_cb(signal, sig_type, data): if len(w.buffer_get_string(data, "input")) > 8: global typing_timer @@ -984,38 +1116,44 @@ def typing_notification_cb(signal, sig_type, data): channel = channels.find(current_buffer_name()) if channel: identifier = channel.identifier - request = {"type":"typing", "channel":identifier} + request = {"type": "typing", "channel": identifier} channel.server.send_to_websocket(json.dumps(request)) typing_timer = now return w.WEECHAT_RC_OK -#NOTE: figured i'd do this because they do +# NOTE: figured i'd do this because they do + + def slack_ping_cb(data, remaining): servers.find(data).ping() return w.WEECHAT_RC_OK + def slack_connection_persistence_cb(data, remaining_calls): for server in servers: if not server.connected: server.buffer_prnt("Disconnected from slack, trying to reconnect..") - if server.ws_hook != None: + if server.ws_hook is not None: w.unhook(server.ws_hook) server.connect_to_slack() return w.WEECHAT_RC_OK + def slack_never_away_cb(data, remaining): global never_away - if never_away == True: + if never_away: for server in servers: identifier = server.channels.find("slackbot").identifier - request = {"type":"typing", "channel":identifier} + request = {"type": "typing", "channel": identifier} #request = {"type":"typing","channel":"slackbot"} server.send_to_websocket(json.dumps(request)) return w.WEECHAT_RC_OK -### Slack specific requests +# Slack specific requests + +# NOTE: switched to async/curl because sync slowed down the UI + -#NOTE: switched to async/curl because sync slowed down the UI def async_slack_api_request(domain, token, request, post_data, priority=False): #t = time.time() post_elements = pickle.dumps([domain, token, request, post_data]) @@ -1025,42 +1163,54 @@ def async_slack_api_request(domain, token, request, post_data, priority=False): post = {"post": "1", "postfields": post_data} url = 'https://{}/api/{}'.format(domain, request) queue_item = ['url:{}'.format(url), post, 20000, 'url_processor_cb', post_elements] - if priority != True: + if not priority: queue.append(QueueItem(queue_item, 'do_url', 'url_processor_cb')) else: queue.insert(0, QueueItem(queue_item, 'do_url', 'url_processor_cb')) + class QueueLock(object): + def __init__(self): self.max_active = 3 self.active_count = 0 self.counter = 0 self.timer = time.time() pass + def lock(self): self.active_count += 1 + def unlock(self): self.active_count -= 1 + def check(self): if time.time() > (self.counter + self.timer) and self.active_count < self.max_active: return True else: return False + def bad(self): self.counter += 1 self.timer = time.time() + def good(self): self.counter = 0 + class QueueItem(object): + def __init__(self, data, method, callback_method=None): self.method = method self.callback_method = callback_method self.data = data + def __getitem__(self, index): return self.data[index] + def __str__(self): return str(self.data) + def __repr__(self): return str(self.data) @@ -1068,11 +1218,12 @@ queue = [] async_queue_lock = QueueLock() captain_of_hooks = [] + def do_url(item): global captain_of_hooks try: query = urlparse.parse_qs(item[1]["postfields"]) - if query.has_key("channel") and item[0].find('history') > -1: + if "channel" in query and item[0].find('history') > -1: channel = query["channel"][0] channel = channels.find(channel) channel.server.buffer_prnt("downloading channel history for {}".format(channel.name), backlog=True) @@ -1082,6 +1233,7 @@ def do_url(item): # w.hook_process_hashtable(*item) captain_of_hooks.append(w.hook_process(command, 20000, item[3], item[4])) + def async_queue_cb(data, remaining_calls): global async_queue_lock if async_queue_lock.check(): @@ -1092,14 +1244,16 @@ def async_queue_cb(data, remaining_calls): method(item) return w.WEECHAT_RC_OK -#funny, right? +# funny, right? big_data = {} + + def url_processor_cb(data, command, return_code, out, err): global async_queue_lock, big_data, captain_of_hooks # if return_code == 0 or -1: data = pickle.loads(data) identifier = sha.sha(str(data) + command).hexdigest() - if not big_data.has_key(identifier): + if identifier not in big_data: big_data[identifier] = '' big_data[identifier] += out if return_code == 0: @@ -1108,7 +1262,7 @@ def url_processor_cb(data, command, return_code, out, err): my_json = json.loads(big_data[identifier]) async_queue_lock.good() except: -# if big_data[identifier] != '': + # if big_data[identifier] != '': dbg("curl failed, doing again...") dbg("curl length: {} identifier {}\n{}".format(len(big_data[identifier]), identifier, data)) @@ -1124,18 +1278,18 @@ def url_processor_cb(data, command, return_code, out, err): else: query = data[3] - if query.has_key("channel"): + if "channel" in query: channel = query["channel"] token = data[1] - if my_json.has_key("messages"): + if "messages" in my_json: messages = my_json["messages"].reverse() for message in my_json["messages"]: message["myserver"] = servers.find(token).domain message["channel"] = servers.find(token).channels.find(channel).identifier process_message(message) - if my_json.has_key("channel"): - if my_json["channel"].has_key("members"): - channels.find(my_json["channel"]["id"]).members = set(my_json["channel"]["members"]) + if "channel" in my_json: + if "members" in my_json["channel"]: + channels.find(my_json["channel"]["id"]).members = set(my_json["channel"]["members"]) elif return_code != -1: big_data.pop(identifier, None) async_queue_lock.unlock() @@ -1143,15 +1297,17 @@ def url_processor_cb(data, command, return_code, out, err): return w.WEECHAT_RC_OK + def mark_silly_channels_read(channel): name = channels.find(channel).name if name in channels_always_marked_read: if channels.find(channel): channels.find(channel).mark_read() -### END Slack specific requests +# END Slack specific requests + +# Utility Methods -### Utility Methods def current_domain_name(): buffer = w.current_buffer() @@ -1163,6 +1319,7 @@ def current_domain_name(): name = ".".join(name.split(".")[:-1]) return name + def current_buffer_name(short=False): buffer = w.current_buffer() #number = w.buffer_get_integer(buffer, "number") @@ -1174,11 +1331,13 @@ def current_buffer_name(short=False): pass return name + def closed_slack_buffer_cb(data, buffer): global slack_buffer slack_buffer = None return w.WEECHAT_RC_OK + def create_slack_buffer(): global slack_buffer slack_buffer = w.buffer_new("slack", "", "", "closed_slack_buffer_cb", "") @@ -1186,20 +1345,23 @@ def create_slack_buffer(): #w.buffer_set(slack_buffer, "display", "1") return w.WEECHAT_RC_OK + def closed_slack_debug_buffer_cb(data, buffer): global slack_debug slack_debug = None return w.WEECHAT_RC_OK + def create_slack_debug_buffer(): global slack_debug, debug_string - if slack_debug != None: + if slack_debug is not None: w.buffer_set(slack_debug, "display", "1") else: debug_string = None slack_debug = w.buffer_new("slack-debug", "", "", "closed_slack_debug_buffer_cb", "") w.buffer_set(slack_debug, "notify", "0") + def config_changed_cb(data, option, value): global slack_api_token, channels_always_marked_read, channels_not_on_current_server_color, colorize_nicks, slack_debug, debug_mode slack_api_token = w.config_get_plugin("slack_api_token") @@ -1218,12 +1380,12 @@ def config_changed_cb(data, option, value): create_slack_debug_buffer() return w.WEECHAT_RC_OK -### END Utility Methods +# END Utility Methods # Main if __name__ == "__main__": if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, - SCRIPT_DESC, "", ""): + SCRIPT_DESC, "", ""): if not w.config_get_plugin('slack_api_token'): w.config_set_plugin('slack_api_token', "INSERT VALID KEY HERE!") @@ -1236,17 +1398,15 @@ if __name__ == "__main__": if not w.config_get_plugin('colorize_nicks'): w.config_set_plugin('colorize_nicks', "1") - version = w.info_get("version_number", "") or 0 if int(version) >= 0x00040400: legacy_mode = False else: legacy_mode = True - ### Global var section + # Global var section config_changed_cb("", "", "") - cmds = {k[8:]: v for k, v in globals().items() if k.startswith("command_")} proc = {k[8:]: v for k, v in globals().items() if k.startswith("process_")} @@ -1259,7 +1419,7 @@ if __name__ == "__main__": hotlist = w.infolist_get("hotlist", "", "") main_weechat_buffer = w.info_get("irc_buffer", "{}.{}".format(domain, "DOESNOTEXIST!@#$")) - ### End global var section + # End global var section #channels = SearchList() servers = SearchList() @@ -1272,21 +1432,20 @@ if __name__ == "__main__": w.hook_timer(100, 0, 0, "async_queue_cb", "") w.hook_timer(3000, 0, 0, "slack_connection_persistence_cb", "") - ### attach to the weechat hooks we need + # attach to the weechat hooks we need w.hook_timer(1000, 0, 0, "typing_update_cb", "") w.hook_timer(1000, 0, 0, "buffer_list_update_cb", "") w.hook_timer(1000, 0, 0, "hotlist_cache_update_cb", "") - w.hook_timer(1000 * 60* 29, 0, 0, "slack_never_away_cb", "") + w.hook_timer(1000 * 60 * 29, 0, 0, "slack_never_away_cb", "") w.hook_signal('buffer_closing', "buffer_closing_cb", "") w.hook_signal('buffer_switch', "buffer_switch_cb", "") w.hook_signal('window_switch', "buffer_switch_cb", "") w.hook_signal('input_text_changed', "typing_notification_cb", "") - w.hook_command('slack','Plugin to allow typing notification and sync of read markers for slack.com', 'stuff', 'stuff2', '|'.join(cmds.keys()), 'slack_command_cb', '') - w.hook_command('me','', 'stuff', 'stuff2', '', 'me_command_cb', '') + w.hook_command('slack', 'Plugin to allow typing notification and sync of read markers for slack.com', 'stuff', 'stuff2', '|'.join(cmds.keys()), 'slack_command_cb', '') + w.hook_command('me', '', 'stuff', 'stuff2', '', 'me_command_cb', '') # w.hook_command('me', 'me_command_cb', '') w.hook_command_run('/join', 'join_command_cb', '') w.hook_command_run('/part', 'part_command_cb', '') w.hook_command_run('/leave', 'part_command_cb', '') w.bar_item_new('slack_typing_notice', 'typing_bar_item_cb', '') - ### END attach to the weechat hooks we need - + # END attach to the weechat hooks we need -- cgit