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