Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mrDoctorWho/vk4xmpp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Smith <mrdoctorwho@helldev.net>2020-08-30 06:30:33 +0300
committerJohn Smith <mrdoctorwho@helldev.net>2020-08-30 06:30:33 +0300
commit656fdba28d372d7e37c81042823e9df07f77fa34 (patch)
tree52f7b509ca6298646d5f9340191dfbcc6d2f5bf4
parentd07c9705bd77af2f0f2a09579babf1ec09648550 (diff)
Update to support API v5.120, introduce friends limit
This release is devoted to Alexey, who has supported us through the years. RIP.
-rw-r--r--Config_example.txt3
-rw-r--r--extensions/.example.py19
-rw-r--r--extensions/attachments.py75
-rw-r--r--extensions/forwarded_messages.py16
-rw-r--r--extensions/geo.py4
-rw-r--r--extensions/groupchats.py14
-rw-r--r--gateway.py90
-rw-r--r--library/defaults.py3
-rw-r--r--library/longpoll.py5
-rw-r--r--library/vkapi.py57
10 files changed, 176 insertions, 110 deletions
diff --git a/Config_example.txt b/Config_example.txt
index a74ec99..65b8adc 100644
--- a/Config_example.txt
+++ b/Config_example.txt
@@ -68,6 +68,9 @@ URL_VCARD_NO_IMAGE = "https://raw.githubusercontent.com/mrDoctorWho/vk4xmpp/mast
# Old users will be able to update their registration.
ALLOW_REGISTRATION = True
+# Friends limit per user.
+MAX_FRIENDS = 5000
+
#! Danger zone.
#! Change the settings below ONLY IF YOU KNOW WHAT ARE YOU DOING! DEFAULT VALUES ARE RECOMMENDED!
# You were warned.
diff --git a/extensions/.example.py b/extensions/.example.py
index 81fb522..43b8759 100644
--- a/extensions/.example.py
+++ b/extensions/.example.py
@@ -3,7 +3,7 @@
# © simpleApps, 2014.
# This plugin contain all vk4xmpp plugin's API features
# Rename it to "example.py" if you wanna test it
-# Please notice that plugins are working in globals() so names must be unique
+# Please notice that plugins are working in globals() so variable and function names must be unique
## Events (not finished yet so not sorted):
# 01 - transport's start (threaded), no args
@@ -56,7 +56,7 @@ def evt04_handler(vk):
Parameters:
vk: VK class object
"""
- print "Look at this man, he've got a captcha: %s. This image: %s is not for robots" % (vk.source, vk.engine.captcha["img"])
+ print "Look at this man, he's got a captcha: %s. This image: %s is not for robots" % (vk.source, vk.engine.captcha["img"])
registerHandler("evt04", evt04_handler)
@@ -68,7 +68,7 @@ def evt05_handler(user):
Parameters:
user: User class object
"""
- print "Hey, look who come to see us: %s" % user.source
+ print "Hey, look who came to see us: %s" % user.source
registerHandler("evt05", evt05_handler)
@@ -119,11 +119,14 @@ def msg01_handler(user, message):
Parameters:
user: User class object
message: single message json object
- Return values:
- None: the function itself should send a message
- str type: transport's core will add returned string to existing body
- """
- return "\nmsg01_handler is awesome"
+ Returns:
+ A tuple of (status, body) where status indicates what to do with the body.
+ List of statuses:
+ * MSG_SKIP: message will be skipped and execution of other handlers stopped
+ * MSG_APPEND: message body will be appended with returning body
+ * MSG_APPEND: message body will be prepended with returning body
+ """
+ return (MSG_APPEND, "\nmsg01_handler is awesome")
registerHandler("msg01", msg01_handler)
diff --git a/extensions/attachments.py b/extensions/attachments.py
index 3b65376..2cc6668 100644
--- a/extensions/attachments.py
+++ b/extensions/attachments.py
@@ -4,16 +4,18 @@
import re
import urllib
+import time
from printer import *
VK_AUDIO_SEARCH_LINK = "https://vk.com/search?c[q]=%s&c[section]=audio"
WALL_LINK = "https://vk.com/wall%(to_id)s_%(id)s"
-WALL_COMMENT_LINK = "https://vk.com/wall%(owner_id)s_%(post_id)s?w=wall%(owner_id)s3_%(post_id)s"
+WALL_COMMENT_LINK = "https://vk.com/wall%(owner_id)s_%(post_id)s?w=wall%(owner_id)s_%(post_id)s"
-PHOTO_SIZES = ("photo_2560", "photo_1280", "photo_807", "photo_604", "photo_130", "photo_75")
-STICKER_SIZES = ("photo_256", "photo_128", "photo_64")
+PHOTO_SIZES = ("w", "z", "y", "x", "q", "p", "m", "o", "s")
+STICKER_SIZES = (512, 352, 256, 128, 64)
-ATTACHMENT_REGEX = re.compile(r"^(?P<type>Photo|Document|Sticker)\:\s(?P<name>“.+?”\s—\s)?(?P<url>http[s]?:\/\/[^\s]+)$", re.UNICODE)
+
+ATTACHMENT_REGEX = re.compile(r"^(?P<type>Photo|Document|Sticker|Audio message)\:\s(?P<name>“.+?”\s—\s)?(?P<url>http[s]?:\/\/[^\s]+)$", re.UNICODE)
GLOBAL_USER_SETTINGS["parse_wall"] = {"value": 1, "label": "Parse wall attachments"}
GLOBAL_USER_SETTINGS["make_oob"] = {"value": 1, "label": "Allow OOB for attachments",
@@ -27,20 +29,24 @@ SIMPLE_ATTACHMENTS = {"doc": "Document: “%(title)s” — %(url)s",
"page": "Page: %(title)s — %(view_url)s"}
+timeFormat = lambda seconds: time.strftime('%H:%M:%S', time.gmtime(seconds))
+
+
def parseAttachments(self, msg, spacer=""):
"""
“parses” attachments from the json to a string
"""
- result = ""
+ result = (MSG_APPEND, "")
+ final_body = ""
if "attachments" in msg:
attachments = msg["attachments"]
# Add new line and "Attachments" if there some text added
- if msg.get("body") and len(attachments) > 1:
- result += chr(10) + spacer + _("Attachments:")
+ if msg.get("text") and len(attachments) > 1:
+ final_body += chr(10) + spacer + _("Attachments:")
if spacer:
- result += "\n"
- elif msg.get("body"):
- result += "\n"
+ final_body += "\n"
+ elif msg.get("text"):
+ final_body += "\n"
for num, attachment in enumerate(attachments):
body = spacer
@@ -62,26 +68,42 @@ def parseAttachments(self, msg, spacer=""):
if current.get("text") or current.get("copy_text"):
body += spacer + uhtml(compile_eol.sub("\n" + spacer, current["text"] or current.get("copy_text"))) + "\n"
if current.get("attachments"):
- body += spacer + parseAttachments(self, current, spacer) + "\n" + spacer + "\n"
+ body += spacer + parseAttachments(self, current, spacer)[1] + "\n" + spacer + "\n"
body += spacer + ("Wall: %s" % WALL_LINK % current)
elif type == "photo":
+ sizes = current.get("sizes", [])
+ found = False
for key in PHOTO_SIZES:
- if key in current:
- body += "Photo: %s" % current[key] # No new line needed if we have just one photo and no text
+ for size in sizes:
+ if size.get("type") == key:
+ body += "Photo: %s" % size.get("url") # No new line needed if we have just one photo and no text
+ found = True
+ break
+ if found:
break
elif type == "audio":
current["performer"] = uhtml(current.get("performer", ""))
current["title"] = uhtml(current.get("title", ""))
current["url"] = VK_AUDIO_SEARCH_LINK % urllib.quote(str("%(artist)s %(title)s" % current))
- current["time"] = current["duration"] / 60.0
+ current["time"] = timeFormat(current["duration"])
body += "Audio: %(artist)s — “%(title)s“ (%(time)s min) — %(url)s" % current
+ elif type == "audio_message":
+ link = current.get("link_ogg") or current.get("link_mp3")
+ body += "Audio message: %s (%s)" % (link, timeFormat(current["duration"]))
+
elif type == "sticker":
- for key in STICKER_SIZES:
- if key in current:
- body += "Sticker: %s" % current[key]
+ images = current.get("images", [])
+ found = False
+ for size in STICKER_SIZES:
+ for image in images:
+ if image.get("width") == size or image.get("height") == size:
+ body += "Sticker: %s" % image["url"]
+ found = True
+ break
+ if found:
break
elif type == "wall_reply":
@@ -97,13 +119,12 @@ def parseAttachments(self, msg, spacer=""):
elif type == "video":
current["title"] = current.get("title", "Untitled")
-
current["desc"] = ""
if current.get("description"):
current["desc"] += uhtml(compile_eol.sub(" / ", "%(description)s, " % current))
current["desc"] += "%(views)d views" % current
- current["time"] = "%d:%d" % (current["duration"] // 60, current["duration"] % 60)
+ current["time"] = timeFormat(current["duration"])
body += "Video: %(title)s (%(desc)s, %(time)s min) — https://vk.com/video%(owner_id)s_%(id)s" % current
@@ -112,7 +133,8 @@ def parseAttachments(self, msg, spacer=""):
else:
body += "Unknown attachment: %s\n%s" % (type, str(current))
- result += body
+ final_body += body
+ result = (MSG_APPEND, final_body)
return result
@@ -127,19 +149,6 @@ def attachments_msg03(msg, destination, source):
match = ATTACHMENT_REGEX.match(body.encode("utf-8"))
if match:
link = match.group("url")
- typ = match.group("type")
- name = match.group("name")
- if link and name:
- # shorten links only for audio messages
- # todo: is there a better way to detect them?
- # probably having "psv4." in the domain might
- # be considered as private storage and hence shouldn't be downloaded by us
- if typ == "Document" and ".ogg" in name:
- try:
- link = urllib.urlopen(link).url
- except Exception:
- crashLog("attachments_msg03")
- logger.error("unable to fetch real url for link %s and (jid: %s)", (link, user.source))
oob = msg.setTag("x", namespace=xmpp.NS_OOB)
oob.setTagData("url", link)
msg.setBody(link)
diff --git a/extensions/forwarded_messages.py b/extensions/forwarded_messages.py
index f052ec7..20320fe 100644
--- a/extensions/forwarded_messages.py
+++ b/extensions/forwarded_messages.py
@@ -27,21 +27,23 @@ class TimezoneOffset(tzinfo):
def parseForwardedMessages(self, msg, depth=0):
body = ""
- if "fwd_messages" in msg:
+ result = (MSG_APPEND, "")
+ if msg.get("fwd_messages"):
spacer = BASE_SPACER * depth
body = "\n" + spacer
body += _("Forwarded messages:")
fwd_messages = sorted(msg["fwd_messages"], sortMsg)
for fwd in fwd_messages:
- source = fwd["user_id"]
- fwdBody = escape("", uhtml(compile_eol.sub("\n" + spacer + BASE_SPACER, fwd["body"])))
+ source = fwd["from_id"]
+ fwdBody = escape("", uhtml(compile_eol.sub("\n" + spacer + BASE_SPACER, fwd["text"])))
date = getUserDate(self, fwd["date"])
name = self.vk.getName(source)
body += "\n%s[%s] %s> %s" % (spacer + BASE_SPACER, date, name, fwdBody)
- body += parseAttachments(self, fwd, spacer + (BASE_SPACER * 2))
+ body += parseAttachments(self, fwd, spacer + (BASE_SPACER * 2))[1]
if depth < MAXIMUM_FORWARD_DEPTH:
- body += parseForwardedMessages(self, fwd, (depth + 1))
- return body
+ body += parseForwardedMessages(self, fwd, (depth + 1))[1]
+ result = (MSG_APPEND, body)
+ return result
def getUserDate(user, timestamp):
@@ -62,6 +64,6 @@ def getUserDate(user, timestamp):
if not isdef("MAXIMUM_FORWARD_DEPTH"):
- MAXIMUM_FORWARD_DEPTH = 29
+ MAXIMUM_FORWARD_DEPTH = 33
registerHandler("msg01", parseForwardedMessages)
diff --git a/extensions/geo.py b/extensions/geo.py
index 9a2eb8e..928d2c0 100644
--- a/extensions/geo.py
+++ b/extensions/geo.py
@@ -8,6 +8,7 @@ GoogleMapLink = "https://maps.google.com/maps?q=%s"
def TimeAndRelativeDimensionInSpace(self, machine):
body = ""
+ result = (MSG_APPEND, "")
if machine.has_key("geo"):
t_machine = machine["geo"]
place = t_machine.get("place")
@@ -19,6 +20,7 @@ def TimeAndRelativeDimensionInSpace(self, machine):
body += _("\nCity: %s\n") % place["city"]
body += _("Coordinates: %s") % coordinates
body += "\n%s — Google Maps" % GoogleMapLink % urllib.quote(t_machine["coordinates"])
- return body
+ result = (MSG_APPEND, body)
+ return result
registerHandler("msg01", TimeAndRelativeDimensionInSpace)
diff --git a/extensions/groupchats.py b/extensions/groupchats.py
index ed6632f..9eaef8c 100644
--- a/extensions/groupchats.py
+++ b/extensions/groupchats.py
@@ -145,9 +145,9 @@ def handleOutgoingChatMessage(user, vkChat):
Handles outging VK messages and sends them to XMPP
"""
# peer_id for newer APIs
- chatID = vkChat.get("chat_id", 0)
+ chatID = vkChat.get("peer_id", 0) - MIN_CHAT_ID
- if chatID:
+ if chatID > 0:
# check if the groupchats support enabled in user's settings
if not user.settings.groupchats:
return None
@@ -173,8 +173,8 @@ def handleOutgoingChatMessage(user, vkChat):
if not chat.created:
time.sleep(1.5)
chat.handleMessage(user, vkChat)
- return None
- return ""
+ return (MSG_SKIP, "")
+ return (MSG_APPEND, "")
def createChat(user, source):
@@ -365,9 +365,9 @@ class Chat(object):
"""
if self.created:
self.update(user, vkChat)
- body = escape("", uhtml(vkChat["body"]))
- body += parseAttachments(user, vkChat)
- body += parseForwardedMessages(user, vkChat)
+ body = escape("", uhtml(vkChat["text"]))
+ body += parseAttachments(user, vkChat)[1]
+ body += parseForwardedMessages(user, vkChat)[1]
if body:
chatMessage(self.jid, body, vk2xmpp(vkChat["from_id"]), None)
else:
diff --git a/gateway.py b/gateway.py
index f7e0484..26eb488 100644
--- a/gateway.py
+++ b/gateway.py
@@ -64,8 +64,6 @@ Config = args.config
startTime = int(time.time())
-# not really required to be none, but the debugger requires them to be defined
-# and, come on, this is much better, isn't it?
DatabaseFile = None
TransportID = None
Host = None
@@ -125,6 +123,17 @@ Stats = {"msgin": 0, # from vk
MAX_MESSAGES_PER_REQUEST = 20
+# Status code that indicates what to do with returning body from plugins
+MSG_SKIP = -1
+MSG_PREPEND = 0
+MSG_APPEND = 1
+
+# Timeout after which user is considered paused typing
+TYPING_TIMEOUT = 5
+
+# Timeout for friends updating
+FRIENDS_UPDATE_TIMEOUT = 300
+
def runDatabaseQuery(query, args=(), set=False, many=True):
"""
@@ -194,7 +203,7 @@ def getGatewayRev():
"""
Gets gateway revision using git or custom revision number
"""
- number, hash = 460, 0
+ number, hash = 480, 0
shell = os.popen("git describe --always &"
"& git log --pretty=format:''").readlines()
if shell:
@@ -433,8 +442,7 @@ class VK(object):
del data["last_name"]
return name
-
- def getFriends(self, fields=None):
+ def getFriends(self, fields=None, limit=MAX_FRIENDS):
"""
Executes the friends.get method and formats it in the key-value style
Example:
@@ -444,7 +452,7 @@ class VK(object):
Which will be added in the result values
"""
fields = fields or self.friends_fields
- raw = self.method("friends.get", {"fields": str.join(",", fields)}) or {}
+ raw = self.method("friends.get", {"fields": str.join(",", fields), "count": limit}) or {}
raw = raw.get("items", {})
friends = {}
for friend in raw:
@@ -627,7 +635,7 @@ class VK(object):
The result of sending the message
"""
Stats["msgout"] += 1
- values = {mType: id, "message": body, "type": 0}
+ values = {mType: id, "message": body, "type": 0, "random_id": int(time.time())}
values.update(more)
try:
result = self.method("messages.send", values)
@@ -807,18 +815,16 @@ class User(object):
Sends messages from vk to xmpp and call message01 handlers
Args:
init: needed to know if function called at init (add time or not)
- Plugins notice (msg01):
- If plugin returns None then message will not be sent by transport's core,
- it shall be sent by plugin itself
- Otherwise, if plugin returns string,
- the message will be sent by transport's core
+ messages: a list of pre-defined messages that would be handled and sent (w/o requesting new ones)
+ mid: last message id
+ uid: user id
+ filter_: what filter to use (all/unread)
"""
with self.sync:
date = 0
if not messages:
- messages = self.vk.getMessages(MAX_MESSAGES_PER_REQUEST, mid or self.lastMsgID+1, uid, filter_)
- if not messages:
- return None
+ messages = self.vk.getMessages(MAX_MESSAGES_PER_REQUEST, mid or self.lastMsgID, uid, filter_)
+
messages = sorted(messages, sortMsg)
for message in messages:
# check if message wasn't sent by our user
@@ -826,27 +832,28 @@ class User(object):
if self.lastMsgID >= message["id"]:
continue
Stats["msgin"] += 1
- frm = message["user_id"]
+ frm = message["from_id"]
mid = message["id"]
- if frm in self.typing:
- del self.typing[frm]
+ self.removeTyping(frm)
fromjid = vk2xmpp(frm)
- body = message["body"]
- body = uhtml(body)
- iter = Handlers["msg01"].__iter__()
- for func in iter:
+ body = uhtml(message["text"])
+ iter_ = Handlers["msg01"].__iter__()
+ for func in iter_:
try:
- result = func(self, message)
+ status, data = func(self, message)
except Exception:
- result = ""
+ status, data = MSG_APPEND, ""
crashLog("handle.%s" % func.__name__)
- if result is None:
- for func in iter:
+ # got ignore status, continuing execution
+ if status == MSG_SKIP:
+ for func in iter_:
utils.execute(func, (self, message))
break
- else:
- body += result
+ elif status == MSG_APPEND:
+ body += data
+ elif status == MSG_PREPEND:
+ body = data + body
else:
if self.settings.force_vk_date or init:
date = message["date"]
@@ -854,9 +861,14 @@ class User(object):
sendMessage(self.source, fromjid, escape("", body), date, mid=mid)
if messages:
newLastMsgID = messages[-1]["id"]
- self.lastMsgID = newLastMsgID
- runDatabaseQuery("update users set lastMsgID=? where jid=?",
- (newLastMsgID, self.source), True)
+ if newLastMsgID > self.lastMsgID:
+ self.lastMsgID = newLastMsgID
+ runDatabaseQuery("update users set lastMsgID=? where jid=?",
+ (newLastMsgID, self.source), True)
+
+ def removeTyping(self, frm):
+ if frm in self.typing:
+ del self.typing[frm]
def updateTypingUsers(self, cTime):
"""
@@ -867,7 +879,7 @@ class User(object):
"""
with self.sync:
for user, last in self.typing.items():
- if cTime - last > 7:
+ if cTime - last > TYPING_TIMEOUT:
del self.typing[user]
sendMessage(self.source, vk2xmpp(user), typ="paused")
@@ -877,7 +889,7 @@ class User(object):
Compares the current friends list to the new list
Takes a corresponding action if any difference found
"""
- if (cTime - self.last_udate) > 300 and not self.vk.engine.captcha:
+ if (cTime - self.last_udate) > FRIENDS_UPDATE_TIMEOUT and not self.vk.engine.captcha:
if self.settings.keep_online:
self.vk.setOnline()
else:
@@ -954,6 +966,7 @@ def sendMessage(destination, source, body=None, timestamp=0, typ="active", mtype
timestamp: message timestamp (XEP-0091)
typ: xmpp chatstates type (XEP-0085)
mtype: the message type
+ mid: message id
"""
msg = xmpp.Message(destination, body, mtype, frm=source)
msg.setTag(typ, namespace=xmpp.NS_CHATSTATES)
@@ -967,6 +980,14 @@ def sendMessage(destination, source, body=None, timestamp=0, typ="active", mtype
def sendChatMarker(destination, source, mid, typ="displayed"):
+ """
+ Sends a chat marker as per XEP-0333
+ Args:
+ destination: to whom send the marker
+ source: from who send the marker
+ mid: which message id should be marked as read
+ typ: marker type (displayed by default)
+ """
msg = xmpp.Message(destination, typ="chat",frm=source)
msg.setTag(typ, {"id": mid}, xmpp.NS_CHAT_MARKERS)
sender(Component, msg)
@@ -1026,6 +1047,7 @@ def updateCron():
user.updateFriends(cTime)
time.sleep(2)
+
def calcStats():
"""
Returns count(*) from users database
@@ -1084,9 +1106,9 @@ def checkPID():
if os.path.exists(pidFile):
old = rFile(pidFile)
if old:
- Print("#-# Killing the previous instance: ", False)
old = int(old)
if pid != old:
+ Print("#-# Killing the previous instance: ", False)
try:
os.kill(old, signal.SIGTERM)
time.sleep(3)
diff --git a/library/defaults.py b/library/defaults.py
index 93a3f7f..5f40043 100644
--- a/library/defaults.py
+++ b/library/defaults.py
@@ -49,6 +49,9 @@ DefLang = "ru"
AdditionalAbout = ""
allowBePublic = True
+# Max friends per user
+MAX_FRIENDS = 5000
+
# The features transport will advertise
TransportFeatures = {xmpp.NS_DELAY, xmpp.NS_CHATSTATES, xmpp.NS_LAST, xmpp.NS_CHAT_MARKERS, xmpp.NS_OOB}
diff --git a/library/longpoll.py b/library/longpoll.py
index cd47df5..e62b1e0 100644
--- a/library/longpoll.py
+++ b/library/longpoll.py
@@ -116,8 +116,9 @@ def processPollResult(user, data):
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, uid), "sendMessages-%s" % user.source)
+ message = [{"out": 0, "from_id": uid, "id": mid, "date": date, "text": body}]
+ # we substract 1 from msg id b/c VK now has reverse history so we need to ask what happened before this exact message
+ utils.runThread(user.sendMessages, (False, message, mid - 1, uid), "sendMessages-%s" % user.source)
elif typ == TYPE_MSG_READ_OUT:
uid, mid = evt
diff --git a/library/vkapi.py b/library/vkapi.py
index c32284e..05188e0 100644
--- a/library/vkapi.py
+++ b/library/vkapi.py
@@ -31,7 +31,7 @@ APP_ID = 3789129
# VK APP scope
SCOPE = 69638
# VK API VERSION
-API_VERSION = "5.21"
+API_VERSION = "5.120"
socket.setdefaulttimeout(SOCKET_TIMEOUT)
@@ -48,13 +48,28 @@ ERRORS = (httplib.BadStatusLine,
METHOD_THROUGHPUT = 3.0
-# Trying to use faster library usjon instead of simplejson
+# VK API error codes
+UNKNOWN_ERROR = 1
+TOO_FAST_ERROR = 6
+FLOOD_CONTROL_ERROR = 9
+NOT_ALLOWED_ERROR = 7
+INTERNAL_SERVER_ERROR = 10
+RUNTIME_ERROR = 13
+CAPTCHA_NEEDED_ERROR = 14
+ACCESS_DENIED_ERROR = 15
+VALIDATION_REQUIRED_ERROR = 17
+WRONG_METHOD_OR_PARAM_ERROR = 100
+
+
+ERRNO_NETWORK_IS_UNREACHABLE = 101
+ERRNO_CONNECTION_RESET_BY_PEER = 104
+
+# Try to use faster library usjon instead of simplejson
try:
import ujson as json
- logger.debug("vkapi: using ujson instead of simplejson")
except ImportError:
import json
- logger.warning("vkapi: ujson wasn't loaded, using simplejson instead")
+
def repeat(maxRetries, resultType, *errors):
@@ -82,10 +97,11 @@ def repeat(maxRetries, resultType, *errors):
else:
break
else:
+ logger.critical("network error: ")
errno = getattr(exc, "errno", 0)
- if errno == 101:
+ if errno == ERRNO_NETWORK_IS_UNREACHABLE:
raise NetworkNotFound()
- elif errno == 104:
+ elif errno == ERRNO_CONNECTION_RESET_BY_PEER:
raise NetworkError()
data = resultType()
logger.warning("vkapi: Error %s occurred on executing %s(*%s, **%s)",
@@ -101,6 +117,7 @@ def repeat(maxRetries, resultType, *errors):
return decorator
+
class AsyncHTTPRequest(httplib.HTTPSConnection):
"""
A method to make asynchronous http requests
@@ -294,7 +311,7 @@ class PasswordLogin(RequestProcessor):
class APIBinding(RequestProcessor):
"""
Provides simple VK API binding
- Translates VK errors to python exceptions
+ Converts VK errors to Python exceptions
"""
def __init__(self, token, debug=None, logline=""):
self.token = token
@@ -302,7 +319,7 @@ class APIBinding(RequestProcessor):
self.last = []
self.captcha = {}
self.lastMethod = ()
- self.delay = 1.00
+ self.delay = 1.25
# to use it in logs without showing the token
self.logline = logline
RequestProcessor.__init__(self)
@@ -311,7 +328,7 @@ class APIBinding(RequestProcessor):
def __delay(self):
"""
Delaying method execution to prevent "too fast" errors from happening
- Typically VK allows us execution of 3 methods per second.
+ Typically VK allows execution of 3 methods per second.
"""
self.last.append(time.time())
if len(self.last) > 2:
@@ -321,7 +338,7 @@ class APIBinding(RequestProcessor):
def method(self, method, values=None, notoken=False):
"""
- Issues a VK method
+ Executes a VK method
Args:
method: vk method
values: method parameters
@@ -378,30 +395,34 @@ class APIBinding(RequestProcessor):
logger.error("vkapi: error occured on executing method"
" (%s(%s), code: %s, msg: %s), (for: %s)" % (method, values, eCode, eMsg, self.logline))
- if eCode == 7: # not allowed
+
+ if eCode == NOT_ALLOWED_ERROR: # not allowed
raise NotAllowed(eMsg)
- elif eCode == 10: # internal server error
+ elif eCode == INTERNAL_SERVER_ERROR: # internal server error
raise InternalServerError(eMsg)
- elif eCode == 13: # runtime error
+ elif eCode == RUNTIME_ERROR: # runtime error
raise RuntimeError(eMsg)
- elif eCode == 14: # captcha
+ elif eCode == CAPTCHA_NEEDED_ERROR: # captcha
if "captcha_sid" in error:
self.captcha = {"sid": error["captcha_sid"], "img": error["captcha_img"]}
raise CaptchaNeeded()
- elif eCode == 15:
+ elif eCode == ACCESS_DENIED_ERROR:
raise AccessDenied(eMsg)
- elif eCode == 17:
+ elif eCode == VALIDATION_REQUIRED_ERROR:
raise ValidationRequired(eMsg)
# 1 - unknown error / 100 - wrong method or parameters loss
# todo: where we going we NEED constants
- elif eCode in (1, 6, 9, 100):
- if eCode in (6, 9): # 6 - too fast / 9 - flood control
+ elif eCode in (UNKNOWN_ERROR,
+ TOO_FAST_ERROR,
+ FLOOD_CONTROL_ERROR,
+ WRONG_METHOD_OR_PARAM_ERROR):
+ if eCode in (TOO_FAST_ERROR, FLOOD_CONTROL_ERROR):
self.delay += 0.15
# logger doesn't seem to support %0.2f
logger.warning("vkapi: got code %s, increasing timeout to %0.2f (for: %s)" %