diff options
Diffstat (limited to 'wee_slack.py')
-rw-r--r-- | wee_slack.py | 333 |
1 files changed, 196 insertions, 137 deletions
diff --git a/wee_slack.py b/wee_slack.py index 57b8637..15bc09c 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -45,19 +45,74 @@ SLACK_API_TRANSLATOR = { } def dbg(message): - w.prnt("", str(message)) + w.prnt("", "DEBUG: " + str(message)) + +#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 find(self, name): + items = self.search_list.find_deep(name, self.attribute) + if len(items) == 1: + return items[0] + else: + raise AmbiguousProblemError + def find_by_class(self, class_name): + items = [] + #for each in self.search_list.find_by_class(class_name): + items += self.search_list.find_by_class_deep(class_name, self.attribute) + return items class SearchList(list): - def find(self, item): - try: - return self[self.index(item)] - except ValueError: - return None + def find(self, name): + items = [] + for child in self: + if child.__class__ == self.__class__: + items += child.find(name) + else: + if child == name: + items.append(child) + if len(items) == 1: + return items[0] + else: + return items + def find_deep(self, name, attribute): + items = [] + for child in self: + if child.__class__ == self.__class__: + items += child.find_deep(name, attribute) + elif dir(child).count('find') == 1: + items.append(child.find(name, attribute)) + 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)) + return items def find_by_class(self, class_name): items = [] - for item in self: - if item.__class__ == class_name: - items.append(item) + 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)) return items class SlackServer(object): @@ -76,7 +131,7 @@ class SlackServer(object): self.connect_to_slack() w.hook_timer(6000, 0, 0, "slack_connection_persistence_cb", self.identifier) def __eq__(self, compare_str): - if compare_str == self.identifier: + if compare_str == self.identifier or compare_str == self.token: return True else: return False @@ -84,6 +139,9 @@ class SlackServer(object): return "%s" % (self.identifier) def __repr__(self): return "%s" % (self.identifier) + def find(self, name, attribute): + attribute = eval("self."+attribute) + return attribute.find(name) def connect_to_slack(self): data = {} t = time.time() @@ -102,9 +160,10 @@ class SlackServer(object): self.create_slack_websocket(login_data) self.create_slack_mappings(login_data) - general_buffer_ptr = w.buffer_search("",self.domain+".#general") - nick_ptr = w.nicklist_search_nick(general_buffer_ptr,'',self.nick) - name = w.nicklist_nick_get_string(general_buffer_ptr,self.nick,'name') + self.buffer = w.buffer_new(self.domain, "input", "", "", "") + self.general_buffer_ptr = w.buffer_search("",self.domain+".#general") + nick_ptr = w.nicklist_search_nick(self.general_buffer_ptr,'',self.nick) + name = w.nicklist_nick_get_string(self.general_buffer_ptr,self.nick,'name') self.connected = True return True @@ -126,47 +185,38 @@ class SlackServer(object): def create_slack_mappings(self, data): for item in data["users"]: - self.users.append(User(item["name"], item["id"], item["presence"])) + self.users.append(User(self, item["name"], item["id"], item["presence"])) for item in data["channels"]: if not item.has_key("last_read"): item["last_read"] = 0 - self.channels.append(Channel(self.domain, item["name"], item["id"], item["is_member"], item["last_read"], "#")) + self.channels.append(Channel(self, item["name"], item["id"], item["is_member"], item["last_read"], "#")) for item in data["groups"]: if not item.has_key("last_read"): item["last_read"] = 0 - self.channels.append(GroupChannel(self.domain, item["name"], item["id"], item["is_open"], item["last_read"], "#")) + self.channels.append(GroupChannel(self, item["name"], item["id"], item["is_open"], item["last_read"], "#")) for item in data["ims"]: if not item.has_key("last_read"): item["last_read"] = 0 name = self.users.find(item["user"]).name - self.channels.append(DmChannel(self.domain, name, item["id"], item["is_open"], item["last_read"])) + self.channels.append(DmChannel(self, name, item["id"], item["is_open"], item["last_read"])) for item in self.channels: item.get_history() - - - class SlackThing(object): def __init__(self, name, identifier): self.name = name self.identifier = identifier self.channel_buffer = None - def __eq__(self, compare_str): - if 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): - return True - else: - return False def __str__(self): return "Name: %s Id: %s CB: %s" % (self.name, self.identifier, self.channel_buffer) def __repr__(self): return "Name: %s Id: %s CB: %s" % (self.name, self.identifier, self.channel_buffer) def input(b,c,data): - for server in servers: - server.channels.find(b).send_message(data) - server.channels.find(b).prnt(nick, data) + channels.find(b).send_message(data) + channels.find(b).prnt(data) return w.WEECHAT_RC_ERROR class Channel(SlackThing): @@ -181,18 +231,23 @@ class Channel(SlackThing): if active: self.create_buffer() self.attach_buffer() + 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): + return True + else: + return False def __str__(self): return "Name: %s Id: %s CB: %s Active: %s" % (self.name, self.identifier, self.channel_buffer, self.active) def __repr__(self): return "Name: %s Id: %s CB: %s Active: %s" % (self.name, self.identifier, self.channel_buffer, self.active) def create_buffer(self): - channel_buffer = w.buffer_search("", "%s.%s" % (self.server, self.name)) + channel_buffer = w.buffer_search("", "%s.%s" % (self.server.domain, self.name)) if channel_buffer: self.channel_buffer = channel_buffer else: - self.channel_buffer = w.buffer_new("%s.%s" % (self.server, self.name), "input", self.name, "", "") + self.channel_buffer = w.buffer_new("%s.%s" % (self.server.domain, self.name), "input", self.name, "", "") def attach_buffer(self): - channel_buffer = w.buffer_search("", "%s.%s" % (self.server, self.name)) + channel_buffer = w.buffer_search("", "%s.%s" % (self.server.domain, self.name)) if channel_buffer != main_weechat_buffer: self.channel_buffer = channel_buffer else: @@ -200,6 +255,8 @@ class Channel(SlackThing): def detach_buffer(self): self.channel_buffer = None #self.weechat_buffer = None + def fullname(self): + return "%s.%s" % (self.server.domain, self.name) def set_active(self): self.active = True def set_inactive(self): @@ -208,15 +265,15 @@ class Channel(SlackThing): self.typing[user] = time.time() def send_message(self, message): request = {"type":"message","channel":self.identifier, "text": message} - servers.find(self.server).ws.send(json.dumps(request)) + self.server.ws.send(json.dumps(request)) def open(self): t = time.time() + 1 - reply = async_slack_api_request(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}) self.create_buffer() self.active = True def close(self): t = time.time() + 1 - reply = async_slack_api_request(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}) self.active = False def unset_typing(self, user): try: @@ -241,7 +298,7 @@ class Channel(SlackThing): if self.channel_buffer: w.buffer_set(self.channel_buffer, "unread", "") if update_remote: - async_slack_api_request(SLACK_API_TRANSLATOR[self.type]["mark"], {"channel":self.identifier,"ts":t}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["mark"], {"channel":self.identifier,"ts":t}) def rename(self, name=None, fmt=None): if self.channel_buffer: if name: @@ -271,9 +328,9 @@ class Channel(SlackThing): def get_history(self): if self.active: t = time.time() - async_slack_api_request(SLACK_API_TRANSLATOR[self.type]["history"], {"channel":self.identifier,"ts":t, "oldest":self.last_read}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["history"], {"channel":self.identifier,"ts":t, "oldest":self.last_read}) queue.append(self) - async_slack_api_request(SLACK_API_TRANSLATOR[self.type]["history"], {"channel":self.identifier,"ts":t, "count":BACKLOG_SIZE, "latest":self.last_read}) + async_slack_api_request(self.server.domain, self.server.token, SLACK_API_TRANSLATOR[self.type]["history"], {"channel":self.identifier,"ts":t, "count":BACKLOG_SIZE, "latest":self.last_read}) class GroupChannel(Channel): def __init__(self, server, name, identifier, active, last_read=0, prepend_name=""): @@ -296,10 +353,16 @@ class DmChannel(Channel): w.buffer_set(self.channel_buffer, "short_name", color + new_name) class User(SlackThing): - def __init__(self, name, identifier, presence="away"): + def __init__(self, server, name, identifier, presence="away"): super(User, self).__init__(name, identifier) self.channel_buffer = w.info_get("irc_buffer", "%s.%s" % (domain, self.name)) self.presence = presence + self.server = server + def __eq__(self, compare_str): + if compare_str == self.name or compare_str == self.identifier: + return True + else: + return False def set_active(self): self.presence = "active" def set_inactive(self): @@ -310,45 +373,46 @@ class User(SlackThing): def open(self): t = time.time() + 1 #reply = async_slack_api_request("im.open", {"channel":self.identifier,"ts":t}) - reply = async_slack_api_request("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) if len(a) > 1: - function_name, args = a[0], a[1] + function_name, args = a[0], " ".join(a[1:]) else: function_name, args = a[0], None # try: - cmds[function_name](args) + cmds[function_name](current_buffer, args) # except KeyError: # w.prnt("", "Command not found or exception: "+function_name) return w.WEECHAT_RC_OK -def command_talk(args): - users.find(args).open() +def command_talk(current_buffer, args): + channels.find(current_buffer).server.users.find(args).open() -def command_join(args): - channels.find(args).open() +def command_join(current_buffer, args): + servers.find(current_domain_name()).channels.find(args).open() -def command_changetoken(args): +def command_changetoken(current_buffer, args): w.config_set_plugin('slack_api_token', args) -def command_test(args): +def command_test(current_buffer, args): if slack_buffer: w.prnt(slack_buffer,"worked!") -def command_away(args): +def command_away(current_buffer, args): async_slack_api_request('presence.set', {"presence":"away"}) -def command_back(args): +def command_back(current_buffer, args): async_slack_api_request('presence.set', {"presence":"active"}) -def command_markread(args): +def command_markread(current_buffer, args): channel = current_buffer_name(short=True) - if channels.find(channel): - channels.find(channel).mark_read() + domain = current_domain_name() + if servers.find(domain).channels.find(channel): + servers.find(domain).channels.find(channel).mark_read() -def command_neveraway(args): +def command_neveraway(current_buffer, args): global never_away if never_away == True: never_away = False @@ -357,20 +421,23 @@ def command_neveraway(args): never_away = True w.prnt("", "set as never_away") -def command_printvar(args): +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(args): +def command_debug(current_buffer, args): create_slack_debug_buffer() -def command_debugstring(args): +def command_debugstring(current_buffer, args): global debug_string if args == '': debug_string = None else: debug_string = args -def command_search(args): +def command_search(current_buffer, args): if not slack_buffer: create_slack_buffer() w.buffer_set(slack_buffer, "display", "1") @@ -383,14 +450,7 @@ def command_search(args): formatted_message = "%s / %s:\t%s" % (message["channel"]["name"], message['username'], message['text']) w.prnt(slack_buffer,str(formatted_message)) -def command_awaybomb(args): - for i in range(1,10): - async_slack_api_request('presence.set', {"presence":"away"}) - time.sleep(.2) - async_slack_api_request('presence.set', {"presence":"active"}) - time.sleep(.2) - -def command_nick(args): +def command_nick(current_buffer, args): urllib.urlopen("https://%s/account/settings" % (domain)) browser.select_form(nr=0) browser.form['username'] = args @@ -403,6 +463,7 @@ def slack_websocket_cb(data, fd): try: data = servers.find(server).ws.recv() message_json = json.loads(data) + #this magic attaches json that helps find the right dest message_json['myserver'] = server except: return w.WEECHAT_RC_OK @@ -435,29 +496,23 @@ def write_debug(message_json): return w.prnt(slack_debug,output) -#def modify_buffer_name(name, new_name_fmt="%s"): -# buffer_name = "%s.%s" % (server, name) -# buf_ptr = w.buffer_search("",buffer_name) -# new_buffer_name = new_name_fmt % (name) -# w.buffer_set(buf_ptr, "short_name", new_buffer_name) - def process_presence_change(message_json): - server = servers.find(message_json["myserver"]) - global nick_ptr - if message_json["user"] == nick: - nick_ptr = w.nicklist_search_nick(general_buffer_ptr,'',nick) - if message_json["presence"] == 'active': - w.nicklist_nick_set(general_buffer_ptr, nick_ptr, "prefix", "+") - else: - w.nicklist_nick_set(general_buffer_ptr, nick_ptr, "prefix", " ") - else: + #server = servers.find(message_json["myserver"]) +# global nick_ptr +# if message_json["user"] == nick: +# nick_ptr = w.nicklist_search_nick(general_buffer_ptr,'',nick) +# if message_json["presence"] == 'active': +# w.nicklist_nick_set(general_buffer_ptr, nick_ptr, "prefix", "+") +# else: +# w.nicklist_nick_set(general_buffer_ptr, nick_ptr, "prefix", " ") +# else: #this puts +/- in front of usernames in the buffer list. (req buffers.pl) buffer_name = "%s.%s" % (domain, message_json["user"]) buf_ptr = w.buffer_search("",buffer_name) if message_json["presence"] == 'active': - server.users.find(message_json["user"]).set_active() + users.find(message_json["user"]).set_active() else: - server.users.find(message_json["user"]).set_inactive() + users.find(message_json["user"]).set_inactive() def process_channel_marked(message_json): server = servers.find(message_json["myserver"]) @@ -538,8 +593,9 @@ def process_im_open(message_json): def process_user_typing(message_json): server = servers.find(message_json["myserver"]) - server.server.channels.find(message_json["channel"]).set_typing(server.users.find(message_json["user"]).name) + server.channels.find(message_json["channel"]).set_typing(server.users.find(message_json["user"]).name) +#todo: does this work? def process_error(message_json): connected = False @@ -601,24 +657,23 @@ def typing_update_cb(data, remaining_calls): return w.WEECHAT_RC_OK def buffer_list_update_cb(data, remaining_calls): - for server in servers: - for channel in server.channels.find_by_class(Channel): - if channel.is_someone_typing() == True: - channel.rename(fmt=">%s") - else: - channel.rename() - for channel in server.channels.find_by_class(GroupChannel): - if channel.is_someone_typing() == True: - channel.rename(fmt=">%s") - else: - channel.rename() - for channel in server.channels.find_by_class(DmChannel): -# if server.users.find(channel.name).presence == "active": -# channel.rename(fmt="+%s") -# else: -# channel.rename(fmt=" %s") - pass - return w.WEECHAT_RC_OK + for channel in channels.find_by_class(Channel): + if channel.is_someone_typing() == True: + channel.rename(fmt=">%s") + else: + channel.rename() + for channel in channels.find_by_class(GroupChannel): + if channel.is_someone_typing() == True: + channel.rename(fmt=">%s") + else: + channel.rename() + for channel in channels.find_by_class(DmChannel): + if users.find(channel.name).presence == "active": + channel.rename(fmt="+%s") + else: + channel.rename(fmt=" %s") + pass + 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) @@ -628,26 +683,20 @@ def hotlist_cache_update_cb(data, remaining_calls): w.infolist_free(prev_hotlist) return w.WEECHAT_RC_OK -def incoming_irc_message_cb(data, modifier, modifier_data, line): -# currently blocks incoming irc messages. lets do this on websockets! -# irc_privmsg -# w.prnt("", str(data)) -# w.prnt("", str(modifier)) -# w.prnt("", str(modifier_data)) - if modifier_data.count('irc_privmsg') > 0: - return "" - else: - return line - def buffer_opened_cb(signal, sig_type, data): name = w.buffer_get_string(data, "name") - if name.startswith(domain): - name = name.split(".")[-1] - if users.find(name): - users.find(name).open() - if channels.find(name): - channels.find(name).attach_buffer() - channels.find(name).get_history() + channel = channels.find(name) + channel.set_active() +# domain = ".".join(name.split('.')[:-1]) +# if domain in servers: + channel.attach_buffer() + channel.get_history() +# name = name.split(".")[-1] +# if server.find(domain).users.find(name): +# server.find(domain).users.find(name).open() +# if server.find(domain).channels.find(name): +# server.find(domain).channels.find(name).attach_buffer() +# server.find(domain).channels.find(name).get_history() return w.WEECHAT_RC_OK def buffer_closing_cb(signal, sig_type, data): @@ -659,12 +708,11 @@ def buffer_closing_cb(signal, sig_type, data): def buffer_switch_cb(signal, sig_type, data): #NOTE: we flush both the next and previous buffer so that all read pointer id up to date global previous_buffer, hotlist - for server in servers: - if server.channels.find(previous_buffer): - server.channels.find(previous_buffer).mark_read() + if channels.find(previous_buffer): + channels.find(previous_buffer).mark_read() channel_name = current_buffer_name() - previous_buffer = channel_name + previous_buffer = data # if current_buffer_name().startswith(domain): # channel_name = current_buffer_name(short=True) @@ -732,14 +780,14 @@ def slack_mark_channel_read(channel_id): channel.find(channel_id).mark_read() #NOTE: switched to async/curl because sync slowed down the UI -def async_slack_api_request(request, data): - t = time.time() + random.random() - request += "?t=%s" % t - data["token"] = slack_api_token - data = urllib.urlencode(data) - post = {"maxconnects": "1", "post": "1", "postfields": data} - url = 'https://%s/api/%s' % (domain, request) - queue.append(['url:%s' % (url), post, 20000, 'url_processor_cb', str(data)]) +def async_slack_api_request(domain, token, request, data): + t = time.time() + request += "?t=%s" % t + data["token"] = token + data = urllib.urlencode(data) + post = {"post": "1", "postfields": data} + url = 'https://%s/api/%s' % (domain, request) + queue.append(['url:%s' % (url), post, 20000, 'url_processor_cb', str(data)]) queue = [] @@ -757,7 +805,7 @@ def async_queue_cb(data, remaining_calls): query = urlparse.parse_qs(item[-1]) if query.has_key("channel") and item[0].find('history') > -1: channel = query["channel"][0] - dbg("downloading channel history for %s" % (channels.find(channel).name)) + dbg("downloading channel history for %s" % (channel)) except: pass if item.__class__ == list: @@ -770,6 +818,7 @@ def async_queue_cb(data, remaining_calls): return w.WEECHAT_RC_OK def url_processor_cb(data, command, return_code, out, err): + url_processor_lock=False global url_processor_lock, big_data if return_code == 0: url_processor_lock=False @@ -785,12 +834,15 @@ def url_processor_cb(data, command, return_code, out, err): query = urlparse.parse_qs(data) if query.has_key("channel"): channel = query["channel"][0] + if query.has_key("token"): + token = query["token"][0] message_json = json.loads(big_data[identifier]) del big_data[identifier] if message_json.has_key("messages"): messages = message_json["messages"].reverse() for message in message_json["messages"]: - message["channel"] = channels.find(channel) + message["myserver"] = servers.find(token).domain + message["channel"] = servers.find(token).channels.find(channel) process_message(message) return w.WEECHAT_RC_OK @@ -811,6 +863,13 @@ def mark_silly_channels_read(channel): ### Utility Methods +def current_domain_name(): + buffer = w.current_buffer() + #number = w.buffer_get_integer(buffer, "number") + name = w.buffer_get_string(buffer, "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") @@ -880,7 +939,7 @@ if __name__ == "__main__": ### Global var section slack_api_token = w.config_get_plugin("slack_api_token") - server = w.config_get_plugin("server") + #server = w.config_get_plugin("server") timeout = w.config_get_plugin("timeout") channels_always_marked_read = [x.strip() for x in w.config_get_plugin("channels_always_marked_read").split(',')] @@ -896,7 +955,6 @@ if __name__ == "__main__": login_data = None nick = None nick_ptr = None - general_buffer_ptr = None name = None connected = False never_away = False @@ -905,10 +963,11 @@ if __name__ == "__main__": ### End global var section - channels = SearchList() - users = SearchList() + #channels = SearchList() servers = SearchList() servers.append(SlackServer(slack_api_token)) + channels = Meta('channels', servers) + users = Meta('users', servers) # w.hook_timer(60000, 0, 0, "slack_connection_persistence_cb", "") |