]> git.ipfire.org Git - people/jschlag/pbs.git/blame - backend/mirrors.py
Second import.
[people/jschlag/pbs.git] / backend / mirrors.py
CommitLineData
f6e6ff79
MT
1#!/usr/bin/python
2
3import logging
4import math
5import socket
6import tornado.database
7
8import base
9import logs
10
11class GeoIP(object):
12 db = None
13
14 def __init__(self, pakfire, server, name, user):
15 self.pakfire = pakfire
16
17 if self.db is None:
18 self.db = tornado.database.Connection(
19 server, name, user=user
20 )
21
22 logging.info("Creating database connection to GeoIP database.")
23
24 @property
25 def cache(self):
26 return self.pakfire.cache
27
28 def __encode_ip(self, addr):
29 # We get a tuple if there were proxy headers.
30 addr = addr.split(", ")
31 if addr:
32 addr = addr[-1]
33
34 # ip is calculated as described in http://ipinfodb.com/ip_database.php
35 a1, a2, a3, a4 = addr.split(".")
36
37 return int(((int(a1) * 256 + int(a2)) * 256 + int(a3)) * 256 + int(a4) + 100)
38
39 def get_all(self, addr):
40 addr = self.__encode_ip(addr)
41
42 mem_id = "geoip-all-%s" % addr
43 ret = self.cache.get(mem_id)
44
45 if not ret:
46 ret = self.db.get("SELECT * FROM locations \
47 JOIN ip_group_city ON ip_group_city.location = locations.id \
48 WHERE ip_group_city.ip_start <= %s \
49 ORDER BY ip_group_city.ip_start DESC LIMIT 1", addr)
50
51 self.cache.set(mem_id, ret, 3600)
52
53 # If location was not determinable
54 if ret.latitude == 0 and ret.longitude == 0:
55 return None
56
57 return ret
58
59
60class Mirrors(base.Object):
61 def get_all(self):
62 mirrors = []
63
64 for mirror in self.db.query("SELECT id FROM mirrors \
65 WHERE NOT status = 'deleted' ORDER BY hostname"):
66 mirror = Mirror(self.pakfire, mirror.id)
67 mirrors.append(mirror)
68
69 return mirrors
70
71 def count(self, status=None):
72 query = "SELECT COUNT(*) AS count FROM mirrors"
73 args = []
74
75 if status:
76 query += " WHERE status = %s"
77 args.append(status)
78
79 query = self.db.get(query, *args)
80
81 return query.count
82
83 def get_random(self, limit=None):
84 query = "SELECT id FROM mirrors WHERE status = 'enabled' ORDER BY RAND()"
85 args = []
86
87 if limit:
88 query += " LIMIT %s"
89 args.append(limit)
90
91 mirrors = []
92 for mirror in self.db.query(query, *args):
93 mirror = Mirror(self.pakfire, mirror.id)
94 mirrors.append(mirror)
95
96 return mirrors
97
98 def get_by_id(self, id):
99 mirror = self.db.get("SELECT id FROM mirrors WHERE id = %s", id)
100 if not mirror:
101 return
102
103 return Mirror(self.pakfire, mirror.id)
104
105 def get_by_hostname(self, hostname):
106 mirror = self.db.get("SELECT id FROM mirrors WHERE NOT status = 'deleted' \
107 AND hostname = %s", hostname)
108
109 if not mirror:
110 return
111
112 return Mirror(self.pakfire, mirror.id)
113
114 def get_for_location(self, addr):
115 distance = 10
116
117 # Get all mirrors in here.
118 _mirrors = self.get_all()
119
120 mirrors = []
121 while len(mirrors) <= 2 and distance <= 270:
122 for mirror in _mirrors:
123 if not mirror.enabled:
124 continue
125
126 if mirror in mirrors:
127 continue
128
129 # Cannot calc the distance for mirrors when their location is unknown.
130 if mirror.location is None:
131 continue
132
133 if mirror.distance_to(addr) <= distance:
134 mirrors.append(mirror)
135
136 distance *= 1.2
137
138 return mirrors
139
140 def get_history(self, limit=None, offset=None, mirror=None, user=None):
141 query = "SELECT * FROM mirrors_history"
142 args = []
143
144 conditions = []
145
146 if mirror:
147 conditions.append("mirror_id = %s")
148 args.append(mirror.id)
149
150 if user:
151 conditions.append("user_id = %s")
152 args.append(user.id)
153
154 if conditions:
155 query += " WHERE %s" % " AND ".join(conditions)
156
157 query += " ORDER BY time DESC"
158
159 if limit:
160 if offset:
161 query += " LIMIT %s,%s"
162 args += [offset, limit,]
163 else:
164 query += " LIMIT %s"
165 args += [limit,]
166
167 entries = []
168 for entry in self.db.query(query, *args):
169 entry = logs.MirrorLogEntry(self.pakfire, entry)
170 entries.append(entry)
171
172 return entries
173
174
175class Mirror(base.Object):
176 def __init__(self, pakfire, id):
177 base.Object.__init__(self, pakfire)
178
179 self.id = id
180
181 # Cache.
182 self._data = None
183 self._location = None
184
185 def __cmp__(self, other):
186 return cmp(self.id, other.id)
187
188 @classmethod
189 def create(cls, pakfire, hostname, path="", owner=None, contact=None, user=None):
190 id = pakfire.db.execute("INSERT INTO mirrors(hostname, path, owner, contact) \
191 VALUES(%s, %s, %s, %s)", hostname, path, owner, contact)
192
193 mirror = cls(pakfire, id)
194 mirror.log("created", user=user)
195
196 return mirror
197
198 def log(self, action, user=None):
199 user_id = None
200 if user:
201 user_id = user.id
202
203 self.db.execute("INSERT INTO mirrors_history(mirror_id, action, user_id, time) \
204 VALUES(%s, %s, %s, NOW())", self.id, action, user_id)
205
206 @property
207 def data(self):
208 if self._data is None:
209 self._data = \
210 self.db.get("SELECT * FROM mirrors WHERE id = %s", self.id)
211
212 return self._data
213
214 def set_status(self, status, user=None):
215 assert status in ("enabled", "disabled", "deleted")
216
217 if self.status == status:
218 return
219
220 self.db.execute("UPDATE mirrors SET status = %s WHERE id = %s",
221 status, self.id)
222
223 if self._data:
224 self._data["status"] = status
225
226 # Log the status change.
227 self.log(status, user=user)
228
229 def set_hostname(self, hostname):
230 if self.hostname == hostname:
231 return
232
233 self.db.execute("UPDATE mirrors SET hostname = %s WHERE id = %s",
234 hostname, self.id)
235
236 if self._data:
237 self._data["hostname"] = hostname
238
239 hostname = property(lambda self: self.data.hostname, set_hostname)
240
241 @property
242 def path(self):
243 return self.data.path
244
245 def set_path(self, path):
246 if self.path == path:
247 return
248
249 self.db.execute("UPDATE mirrors SET path = %s WHERE id = %s",
250 path, self.id)
251
252 if self._data:
253 self._data["path"] = path
254
255 path = property(lambda self: self.data.path, set_path)
256
257 @property
258 def url(self):
259 ret = "http://%s" % self.hostname
260
261 if self.path:
262 path = self.path
263
264 if not self.path.startswith("/"):
265 path = "/%s" % path
266
267 if self.path.endswith("/"):
268 path = path[:-1]
269
270 ret += path
271
272 return ret
273
274 def set_owner(self, owner):
275 if self.owner == owner:
276 return
277
278 self.db.execute("UPDATE mirrors SET owner = %s WHERE id = %s",
279 owner, self.id)
280
281 if self._data:
282 self._data["owner"] = owner
283
284 owner = property(lambda self: self.data.owner or "", set_owner)
285
286 def set_contact(self, contact):
287 if self.contact == contact:
288 return
289
290 self.db.execute("UPDATE mirrors SET contact = %s WHERE id = %s",
291 contact, self.id)
292
293 if self._data:
294 self._data["contact"] = contact
295
296 contact = property(lambda self: self.data.contact or "", set_contact)
297
298 @property
299 def status(self):
300 return self.data.status
301
302 @property
303 def enabled(self):
304 return self.status == "enabled"
305
306 @property
307 def check_status(self):
308 return self.data.check_status
309
310 @property
311 def last_check(self):
312 return self.data.last_check
313
314 @property
315 def address(self):
316 return socket.gethostbyname(self.hostname)
317
318 @property
319 def location(self):
320 if self._location is None:
321 self._location = self.geoip.get_all(self.address)
322
323 return self._location
324
325 @property
326 def country_code(self):
327 if self.location:
328 return self.location.country_code
329
330 return "UNKNOWN"
331
332 @property
333 def latitude(self):
334 if self.location:
335 return self.location.latitude
336
337 return 0
338
339 @property
340 def longitude(self):
341 if self.location:
342 return self.location.longitude
343
344 return 0
345
346 def distance_to(self, addr):
347 location = self.geoip.get_all(addr)
348 if not location:
349 return 0
350
351 #if location.country_code.lower() in self.prefer_for_countries:
352 # return 0
353
354 distance_vector = (
355 self.latitude - location.latitude,
356 self.longitude - location.longitude
357 )
358
359 distance = 0
360 for i in distance_vector:
361 distance += i**2
362
363 return math.sqrt(distance)
364
365 def get_history(self, *args, **kwargs):
366 kwargs["mirror"] = self
367
368 return self.pakfire.mirrors.get_history(*args, **kwargs)