]>
Commit | Line | Data |
---|---|---|
1 | import json | |
2 | import socket | |
3 | import urllib2 | |
4 | import xpath | |
5 | from BaseHTTPServer import BaseHTTPRequestHandler | |
6 | from decimal import Decimal | |
7 | from StringIO import StringIO | |
8 | from urlparse import urlparse | |
9 | from xml.dom.minidom import Element | |
10 | from xml.dom.minidom import parse | |
11 | ||
12 | class InputError(Exception): | |
13 | def __init__(self, msg): | |
14 | self.msg = msg | |
15 | ||
16 | def __str__(self): | |
17 | return str(self.msg) | |
18 | ||
19 | class FeedError(Exception): | |
20 | def __init__(self, e): | |
21 | if hasattr(e, 'code'): | |
22 | c = e.code | |
23 | ||
24 | if c == 404: | |
25 | self.msg = 'not found.' | |
26 | elif c == 406: | |
27 | self.msg = 'this eRepublik API feed is unavailable.' | |
28 | elif c == 500: | |
29 | self.msg = 'eRepublik server has encountered an unexpected error.' | |
30 | elif c == 502: | |
31 | self.msg = 'invalid response from eRepublik server. Try again later.' | |
32 | elif c == 503: | |
33 | self.msg = 'eRepublik API feed is temporarily unavailable. Try again later.' | |
34 | else: | |
35 | self.msg = 'something went wrong while connecting to eRepublik API feed (%s)' % BaseHTTPRequestHandler.responses[e.code][0] | |
36 | ||
37 | self.code = c | |
38 | self.url = e.url | |
39 | elif hasattr(e, 'reason'): | |
40 | r = str(e.reason) | |
41 | ||
42 | if r == 'timed out': | |
43 | self.msg = 'connection to eRepublik API feed timed out. Try again later.' | |
44 | else: | |
45 | self.msg = r | |
46 | ||
47 | self.code = None | |
48 | self.url = None | |
49 | else: | |
50 | e = unicode(e) | |
51 | ||
52 | if e == 'an error occured': | |
53 | self.msg = 'this command cannot work because eRepublik admins disabled the API. If you want to complain, send a ticket: http://www.erepublik.com/en/tickets' | |
54 | else: | |
55 | self.msg = e | |
56 | ||
57 | self.code = None | |
58 | self.url = None | |
59 | ||
60 | def __str__(self): | |
61 | return self.msg | |
62 | ||
63 | class HtmlFeed: | |
64 | def __init__(self, value): | |
65 | if value == None: | |
66 | raise InputError('Invalid feed input.') | |
67 | ||
68 | if isinstance(value, str) or isinstance(value, unicode): | |
69 | try: | |
70 | opener = urllib2.build_opener() | |
71 | opener.addheaders = [('User-Agent', 'Rizon eRepublik bot - www.rizon.net')] | |
72 | feed = opener.open(value.replace(' ', '%20'), timeout=20) | |
73 | self._html = feed.read() | |
74 | feed.close() | |
75 | except urllib2.URLError, e: | |
76 | raise FeedError(e) | |
77 | else: | |
78 | raise InputError('Invalid feed input type.') | |
79 | ||
80 | def html(self): | |
81 | return self._html | |
82 | ||
83 | def get_json(value): | |
84 | if value == None: | |
85 | raise InputError('Invalid feed input.') | |
86 | ||
87 | if isinstance(value, basestring): | |
88 | feed = HtmlFeed(value) | |
89 | return json.load(StringIO(feed.html())) | |
90 | else: | |
91 | raise InputError('Invalid feed input type.') | |
92 | ||
93 | class XmlFeed: | |
94 | def __init__(self, value, namespaces = None): | |
95 | if value == None: | |
96 | raise InputError('Invalid feed input.') | |
97 | ||
98 | self.namespaces = {} if namespaces == None else namespaces | |
99 | ||
100 | if isinstance(value, basestring): | |
101 | feed = HtmlFeed(value) | |
102 | self._element = parse(StringIO(feed.html())) | |
103 | elif isinstance(value, Element): | |
104 | self._element = value | |
105 | else: | |
106 | raise InputError('Invalid feed input type.') | |
107 | ||
108 | error = xpath.findvalue('/error/message', self._element) | |
109 | ||
110 | if error != None: | |
111 | raise FeedError(error) | |
112 | ||
113 | def elements(self, query): | |
114 | return [XmlFeed(x, self.namespaces) for x in xpath.find(query, self._element, namespaces=self.namespaces)] | |
115 | ||
116 | def text(self, query, default=None): | |
117 | result = xpath.findvalue(query, self._element, namespaces=self.namespaces) | |
118 | ||
119 | if not result: | |
120 | value = default | |
121 | else: | |
122 | value = result.strip() | |
123 | ||
124 | if isinstance(value, unicode): | |
125 | try: | |
126 | value = value.encode('latin-1').decode('utf-8') | |
127 | except: | |
128 | pass | |
129 | ||
130 | return value | |
131 | ||
132 | def int(self, query, default = None): | |
133 | result = self.text(query, None) | |
134 | ||
135 | if result == None: | |
136 | return default | |
137 | ||
138 | try: | |
139 | return int(result) | |
140 | except: | |
141 | return default | |
142 | ||
143 | def decimal(self, query, default = None): | |
144 | result = self.text(query, None) | |
145 | ||
146 | if result == None: | |
147 | return default | |
148 | ||
149 | try: | |
150 | return Decimal(result) | |
151 | except: | |
152 | return default | |
153 | ||
154 | def bool(self, query, default = None): | |
155 | result = self.text(query, None) | |
156 | ||
157 | if result == None: | |
158 | return default | |
159 | ||
160 | if 'true' in result.lower() or result == '1': | |
161 | return True | |
162 | elif 'false' in result.lower() or result == '0': | |
163 | return False | |
164 | else: | |
165 | try: | |
166 | return int(result) > 0 | |
167 | except: | |
168 | return default |