def method(self, method, args=None, force=False, notoken=False): """ This is a duplicate function of self.engine.method Needed to handle errors properly exactly in __main__ Args: method: a VK API method args: method arguments force: whether to force execution (ignore self.online and captcha) notoken: whether to cut the token from the request Returns: The method execution result See library/vkapi.py for more information about exceptions """ args = args or {} result = {} self.methods += 1 Stats["method"] += 1 if not self.engine.captcha and (self.online or force): try: result = self.engine.method(method, args, notoken=notoken) except (api.InternalServerError, api.AccessDenied) as e: if force: raise except api.CaptchaNeeded as e: executeHandlers("evt04", (self.source, self.engine.captcha)) self.online = False except api.NetworkNotFound as e: self.online = False except api.NotAllowed as e: if self.engine.lastMethod[0] == "messages.send": sendMessage( self.source, vk2xmpp(args.get("user_id", TransportID)), _("You're not allowed to perform this action.")) except api.VkApiError as e: # There are several types of VkApiError # But the user definitely must be removed. # The question is: how? # Should we completely exterminate them or just remove? roster = False m = e.message # TODO: Make new exceptions for each of the conditions below if m == "User authorization failed: user revoke access for this token.": roster = True elif m == "User authorization failed: invalid access_token.": sendMessage(self.source, TransportID, m + " Please, register again") utils.runThread(removeUser, (self.source, roster)) logger.error("VK: apiError %s (jid: %s)", m, self.source) self.online = False else: return result logger.error( "VK: error %s occurred while executing" " method(%s) (%s) (jid: %s)", e.__class__.__name__, method, e.message, self.source) return result
def initialize(self, force=False, send=True, resource=None, first=False): """ Initializes user after the connection has been completed Args: force: force sending subscription presence send: whether to send the init presence resource: add resource in self.resources to prevent unneeded stanza sending first: whether to initialize the user for the first time (during registration) """ logger.debug("User: beginning user initialization (jid: %s)", self.source) Users[self.source] = self if not self.friends: self.friends = self.vk.getFriends() if force or not self.rosterSet: logger.debug("User: sending subscription presence with force:%s (jid: %s)", force, self.source) import rostermanager rostermanager.Roster.checkRosterx(self, resource) if send: self.sendInitPresence() if resource: self.resources.add(resource) utils.runThread(self.vk.getUserPreferences) if first: self.sendMessages(True, filter_="unread") else: self.sendMessages(True) Poll.add(self) utils.runThread(executeHandlers, ("evt05", (self,)))
def initialize(self, force=False, send=True, resource=None): """ Initializes user after self.connect() is done: 1. Receives friends list and set 'em to self.friends 2. If #1 is done and roster is not yet set (self.rosterSet) then sends a subscription presence 3. Calls sendInitPresnece() if parameter send is True 4. Adds resource if resource parameter exists Parameters: force: force sending subscription presence send: needed to know if need to send init presence or not resource: add resource in self.resources to prevent unneeded stanza sending """ logger.debug("User: called init for user %s", self.source) Transport[self.source] = self if not self.friends: self.friends = self.vk.getFriends() if self.friends and not self.rosterSet or force: logger.debug("User: sending subscription presence with force:%s (jid: %s)", force, self.source) import rostermanager rostermanager.Roster.checkRosterx(self, resource) if send: self.sendInitPresence() if resource: self.resources.add(resource) utils.runThread(self.vk.getUserID) Poll.add(self) self.sendMessages(True) utils.runThread(executeHandlers, ("evt05", (self,)))
def initialize(self, force=False, send=True, resource=None, first=False): """ Initializes user after the connection has been completed Args: force: force sending subscription presence send: whether to send the init presence resource: add resource in self.resources to prevent unneeded stanza sending first: whether to initialize the user for the first time (during registration) """ logger.debug("User: beginning user initialization (jid: %s)", self.source) Users[self.source] = self if not self.friends: self.friends = self.vk.getFriends() if force or not self.rosterSet: logger.debug( "User: sending subscription presence with force:%s (jid: %s)", force, self.source) import rostermanager rostermanager.Roster.checkRosterx(self, resource) if send: self.sendInitPresence() if resource: self.resources.add(resource) utils.runThread(self.vk.getUserPreferences) if first: self.sendMessages(True, filter_="unread") else: self.sendMessages(True) Poll.add(self) utils.runThread(executeHandlers, ("evt05", (self, )))
def method(self, method, args=None, force=False, notoken=False): """ This is a duplicate function of self.engine.method Needed to handle errors properly exactly in __main__ Args: method: a VK API method args: method arguments force: whether to force execution (ignore self.online and captcha) notoken: whether to cut the token from the request Returns: The method execution result See library/vkapi.py for more information about exceptions """ args = args or {} result = {} self.methods += 1 Stats["method"] += 1 if not self.engine.captcha and (self.online or force): try: result = self.engine.method(method, args, notoken=notoken) except (api.InternalServerError, api.AccessDenied) as e: if force: raise except api.CaptchaNeeded as e: executeHandlers("evt04", (self.source, self.engine.captcha)) self.online = False except api.NetworkNotFound as e: self.online = False except api.NotAllowed as e: if self.engine.lastMethod[0] == "messages.send": sendMessage(self.source, vk2xmpp(args.get("user_id", TransportID)), _("You're not allowed to perform this action.")) except api.VkApiError as e: # There are several types of VkApiError # But the user definitely must be removed. # The question is: how? # Should we completely exterminate them or just remove? roster = False m = e.message # TODO: Make new exceptions for each of the conditions below if m == "User authorization failed: user revoke access for this token.": roster = True elif m == "User authorization failed: invalid access_token.": sendMessage(self.source, TransportID, m + " Please, register again") utils.runThread(removeUser, (self.source, roster)) logger.error("VK: apiError %s (jid: %s)", m, self.source) self.online = False else: return result logger.error("VK: error %s occurred while executing" " method(%s) (%s) (jid: %s)", e.__class__.__name__, method, e.message, self.source) return result
def method(self, method, args=None, force=False): """ This is a duplicate function of self.engine.method Needed to handle errors properly exactly in __main__ Parameters: method: obviously VK API method args: method aruments nodecode: decode flag (make json.loads or not) force: says that method will be executed even the captcha and not online See library/vkapi.py for more information about exceptions Returns method execution result """ args = args or {} result = {} Stats["method"] += 1 if not self.engine.captcha and (self.online or force): try: result = self.engine.method(method, args) except (api.InternalServerError, api.AccessDenied) as e: if force: raise except api.CaptchaNeeded as e: executeHandlers("evt04", (self, self.engine.captcha["img"])) self.online = False except api.NetworkNotFound as e: self.online = False except api.NotAllowed as e: if self.engine.lastMethod[0] == "messages.send": sendMessage(Component, self.source, vk2xmpp(args.get("user_id", TransportID)), _("You're not allowed to perform this action.")) except api.VkApiError as e: # There are several types of VkApiError # But the user defenitely must be removed. # The question is: how? # Are they should be completely exterminated or just removed? roster = False m = e.message # Probably should be done in vkapi.py by status codes if m == "User authorization failed: user revoke access for this token.": roster = True elif m == "User authorization failed: invalid access_token.": sendMessage(Component, self.source, TransportID, m + " Please, register again") utils.runThread(removeUser, (self.source, roster)) logger.error("VK: apiError %s (jid: %s)", m, self.source) self.online = False else: return result logger.error("VK: error %s occurred while executing" " method(%s) (%s) (jid: %s)", e.__class__.__name__, method, e.message, self.source) return result
def __addToBuff(cls, user): """ Adds user to the list of "bad" users The list is mostly contain users whose poll request was failed for some reasons """ cls.__buff.add(user) logger.debug("longpoll: adding user to watcher (jid: %s)" % user.source) utils.runThread(cls.__initPoll, (user,), "__initPoll-%s" % user.source)
def processPollResult(self, opener): """ Processes poll result Retur codes: 0: need to reinit poll (add user to the poll buffer) 1: all is fine (request again) -1: just continue iteration, ignoring this user (user won't be added for the next iteration) """ if DEBUG_POLL: logger.debug("longpoll: processing result (jid: %s)", self.source) if self.vk.engine.captcha: return -1 data = None try: data = opener.read() data = json.loads(data) except (ValueError, httplib.BadStatusLine, socket.error): return 1 if not data: logger.error("longpoll: no data. Gonna request again") return 1 if "failed" in data: logger.debug("longpoll: failed. Searching for a new server (jid: %s)", self.source) return 0 self.vk.pollConfig["ts"] = data["ts"] for evt in data.get("updates", ()): typ = evt.pop(0) if typ == 4: # new message utils.runThread(self.sendMessages, name="sendMessages-%s" % self.source) elif typ == 8: # user has joined if not self.settings.i_am_ghost: uid = abs(evt[0]) key = "name" if self.settings.use_nicknames: key = "screen_name" sendPresence(self.source, vk2xmpp(uid), nick=self.vk.getUserData(uid)[key], caps=True) elif typ == 9: # user has left uid = abs(evt[0]) sendPresence(self.source, vk2xmpp(uid), "unavailable") elif typ == 61: # user is typing if evt[0] not in self.typing: sendMessage(Component, self.source, vk2xmpp(evt[0]), typ="composing") self.typing[evt[0]] = time.time() return 1
def __addToBuffer(cls, user): """ Adds user to the list of "bad" users The list is mostly contain users whose poll request was failed for some reasons Args: user: the user object """ cls.__buff.add(user) logger.debug("longpoll: adding user to the init buffer (jid: %s)", user.source) utils.runThread(cls.handleUser, (user,), "handleBuffer-%s" % user.source)
def process(cls): """ Processes poll sockets by select.select() As soon as socket will be ready to be read will be called user.processPollResult() function Read processPollResult.__doc__ to learn more about status codes """ while ALIVE: socks = cls.__list.keys() if not socks: time.sleep(0.02) continue try: ready, error = select.select(socks, [], socks, 2)[::2] except (select.error, socket.error) as e: logger.error("longpoll: %s" % (e.message)) # debug? for sock in error: with cls.__lock: # We will just re-add the user to poll # in case if anything weird happen to the socket try: cls.__add(cls.__list.pop(sock)[0]) except KeyError: continue for sock in ready: with cls.__lock: try: user, opener = cls.__list.pop(sock) except KeyError: continue # Check if user is still in the memory user = Transport.get(user.source) if not user: continue # Check if the user haven't left yet if not user.vk.online: continue utils.runThread(cls.processResult, (user, opener), "poll.processResult-%s" % user.source) with cls.__lock: for sock, (user, opener) in cls.__list.items(): if not user.vk.online: logger.debug("longpoll: user is not online, so removing their from poll" " (jid: %s)" % user.source) try: del cls.__list[sock] except KeyError: pass
def runMainActions(): """ Running main actions to make transport work """ if allowBePublic: makeMeKnown() for num, event in enumerate(Handlers["evt01"]): utils.runThread(event, (), "extension-%d" % num) utils.runThread(Poll.process, (), "longPoll") utils.runThread(updateCron, (), "updateCron") import modulemanager Manager = modulemanager.ModuleManager Manager.load(Manager.list())
def runMainActions(): """ Running the main actions to make the transport work """ for num, event in enumerate(Handlers["evt01"]): utils.runThread(event, name=("extension-%d" % num)) utils.runThread(Poll.process, name="longPoll") utils.runThread(updateCron) import modulemanager Manager = modulemanager.ModuleManager Manager.load(Manager.list()) global USER_CAPS_HASH, TRANSPORT_CAPS_HASH USER_CAPS_HASH = computeCapsHash(UserFeatures) TRANSPORT_CAPS_HASH = computeCapsHash(TransportFeatures)
def runMainActions(): """ Runs the actions for the gateway to work well Initializes extensions, longpoll and modules Computes required hashes """ for num, event in enumerate(Handlers["evt01"]): utils.runThread(event, name=("extension-%d" % num)) utils.runThread(Poll.process, name="longPoll") utils.runThread(updateCron) import modulemanager Manager = modulemanager.ModuleManager Manager.load(Manager.list()) global USER_CAPS_HASH, TRANSPORT_CAPS_HASH USER_CAPS_HASH = computeCapsHash(UserFeatures) TRANSPORT_CAPS_HASH = computeCapsHash(TransportFeatures)
def processPollResult(user, data): """ Processes a poll result Decides whether to send a chat/groupchat message or presence or just pass the iteration Args: user: the User object data: a valid json with poll result Returns: CODE_SKIP: just skip iteration, not adding the user to poll again CODE_FINE: add user for the next iteration CODE_ERROR: user should be added to the init buffer """ debug("longpoll: processing result (jid: %s)", user.source) retcode = CODE_FINE try: data = json.loads(data) except ValueError: logger.error("longpoll: no data. Gonna request again (jid: %s)", user.source) retcode = CODE_ERROR return retcode if "failed" in data: logger.debug("longpoll: failed. Searching for a new server (jid: %s)", user.source) retcode = CODE_ERROR else: user.vk.pollConfig["ts"] = data["ts"] for evt in data.get("updates", ()): typ = evt.pop(0) debug( "longpoll: got updates, processing event %s with arguments %s (jid: %s)", typ, str(evt), user.source) if typ == TYPE_MSG: # new message message = None mid, flags, uid, date, subject, body, attachments = evt out = flags & FLAG_OUT chat = (uid > MIN_CHAT_UID ) # a groupchat always has uid > 2000000000 # there is no point to request messages if there's only a single emoji attachment # we actually only need to request for new messages if there are complex attachments in it (e.g. photos) if len(attachments) == 1 and "emoji" in attachments: attachments = None if not out: if not attachments and not chat: message = [{ "out": 0, "user_id": uid, "id": mid, "date": date, "body": body }] utils.runThread(user.sendMessages, (False, message, mid - 1, uid), "sendMessages-%s" % user.source) elif typ == TYPE_MSG_READ_OUT: uid, mid = evt cache = user.msgCacheByUser.get(uid) if cache: xmppMID = cache["xmpp"] cache.clear() sendChatMarker(user.source, vk2xmpp(uid), xmppMID) elif typ == TYPE_PRS_IN: # user has joined uid = abs(evt[0]) sendPresence(user.source, vk2xmpp(uid), hash=USER_CAPS_HASH) elif typ == TYPE_PRS_OUT: # user has left uid = abs(evt[0]) sendPresence(user.source, vk2xmpp(uid), "unavailable") elif typ == TYPE_TYPING: # user is typing uid = evt[0] if uid not in user.typing: sendMessage(user.source, vk2xmpp(uid), typ="composing") user.typing[uid] = time.time() retcode = CODE_FINE return retcode
def processPollResult(self, opener): """ Processes poll result Retur codes: 0: need to reinit poll (add user to the poll buffer) 1: all is fine (request again) -1: just continue iteration, ignoring this user (user won't be added for the next iteration) """ if DEBUG_POLL: logger.debug("longpoll: processing result (jid: %s)", self.source) if self.vk.engine.captcha: return -1 data = None try: data = opener.read() except (httplib.BadStatusLine, socket.error, socket.timeout) as e: logger.warning("longpoll: got error `%s` (jid: %s)", e.__class__.__name__, self.source) return 0 try: data = json.loads(data) if not data: raise ValueError() except ValueError: logger.error("longpoll: no data. Gonna request again (jid: %s)", self.source) return 1 if "failed" in data: logger.debug("longpoll: failed. Searching for a new server (jid: %s)", self.source) return 0 self.vk.pollConfig["ts"] = data["ts"] for evt in data.get("updates", ()): typ = evt.pop(0) if DEBUG_POLL: logger.debug("longpoll: got updates, processing event %s with arguments %s (jid: %s)", typ, str(evt), self.source) if typ == 4: # new message if len(evt) == 7: message = None mid, flags, uid, date, subject, body, attachments = evt out = flags & 2 == 2 chat = uid > 2000000000 # a groupchat always has uid > 2000000000 if not out: if not attachments and not chat: message = [{"out": 0, "user_id": uid, "id": mid, "date": date, "body": body}] utils.runThread(self.sendMessages, (None, message), "sendMessages-%s" % self.source) else: logger.warning("longpoll: incorrect events number while trying to process arguments %s (jid: %s)", str(evt), self.source) elif typ == 8: # user has joined uid = abs(evt[0]) sendPresence(self.source, vk2xmpp(uid), hash=USER_CAPS_HASH) elif typ == 9: # user has left uid = abs(evt[0]) sendPresence(self.source, vk2xmpp(uid), "unavailable") elif typ == 61: # user is typing if evt[0] not in self.typing: sendMessage(self.source, vk2xmpp(evt[0]), typ="composing") self.typing[evt[0]] = time.time() return 1
def processPollResult(user, data): """ Processes a poll result Decides whether to send a chat/groupchat message or presence or just pass the iteration Args: user: the User object data: a valid json with poll result Returns: CODE_SKIP: just skip iteration, not adding the user to poll again CODE_FINE: add user for the next iteration CODE_ERROR: user should be added to the init buffer """ debug("longpoll: processing result (jid: %s)", user.source) retcode = CODE_FINE try: data = json.loads(data) except ValueError: logger.error("longpoll: no data. Gonna request again (jid: %s)", user.source) retcode = CODE_ERROR return retcode if "failed" in data: logger.debug("longpoll: failed. Searching for a new server (jid: %s)", user.source) retcode = CODE_ERROR else: user.vk.pollConfig["ts"] = data["ts"] for evt in data.get("updates", ()): typ = evt.pop(0) debug( "longpoll: got updates, processing event %s with arguments %s (jid: %s)", typ, str(evt), user.source) if typ == TYPE_MSG: # new message if len(evt) == 7: message = None mid, flags, uid, date, subject, body, attachments = evt out = flags & FLAG_OUT chat = (uid > MIN_CHAT_UID ) # a groupchat always has uid > 2000000000 if not out: if not attachments and not chat: message = [ 1, { "out": 0, "uid": uid, "mid": mid, "date": date, "body": body } ] utils.runThread(user.sendMessages, (None, message), "sendMessages-%s" % user.source) else: logger.warning( "longpoll: incorrect events number while trying to " "process arguments %s (jid: %s)", str(evt), user.source) elif typ == TYPE_PRS_IN: # user has joined uid = abs(evt[0]) sendPresence(user.source, vk2xmpp(uid), hash=USER_CAPS_HASH) elif typ == TYPE_PRS_OUT: # user has left uid = abs(evt[0]) sendPresence(user.source, vk2xmpp(uid), "unavailable") elif typ == TYPE_TYPING: # user is typing uid = evt[0] if uid not in user.typing: sendMessage(user.source, vk2xmpp(uid), typ="composing") user.typing[uid] = time.time() retcode = CODE_FINE return retcode