d87076c51741a0653ea3cbb73d843249a7a59ba6
[cs-p2p-next.git] / ppf / new / storage.py
1 """
2 Storage class for P2P logging information.
3
4 2011, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
5 """
6
7 import os
8 import os.path
9 import re
10 import logging
11 import sqlite3
12
13 #
14 # Logging code heavily inspired by Logging HOWTO documentation:
15 #     http://docs.python.org/dev/howto/logging.html#configuring-logging
16 #
17
18 # Create logger; default logging level is DEBUG.
19 logger = logging.getLogger(__name__)
20 logger.setLevel(logging.DEBUG)
21
22 # Create console handler and set level to ERROR.
23 ch = logging.StreamHandler()
24 ch.setLevel(logging.DEBUG)
25
26 # Create formatter.
27 formatter = logging.Formatter('%(filename)s:%(lineno)s - %(levelname)s: %(message)s')
28
29 # Add formatter to console handler.
30 ch.setFormatter(formatter)
31
32 # Add console handler to logger.
33 logger.addHandler(ch)
34
35
36 message_types = {
37         'CHOKE': {'id': 1, 'parameters': None},
38         'UNCHOKE': {'id': 2, 'parameters': None},
39         'INTERESTED': {'id': 3, 'parameters': None},
40         'NOT_INTERESTED': {'id': 4, 'parameters': None},
41         'HAVE': {'id': 5, 'parameters': None},
42         'BITFIELD': {'id': 6, 'parameters': None},
43         'REQUEST': {'id': 7, 'parameters': None},
44         'PIECE': {'id': 8, 'parameters': None},
45         'CANCEL': {'id': 9, 'parameters': None},
46         'DHT_PORT': {'id': 10, 'parameters': None}
47 }
48
49 bittorrent_clients = {
50         'Tribler': {
51             'id': 1,
52             'language': 'Python',
53             'url': 'http://www.tribler.org/trac',
54             'dht_support': True,
55             'streaming_support': True,
56             'pxe_support': None,
57             'features': None
58         },
59         'NextShare': {
60             'id': 2,
61             'language': 'Python',
62             'url': 'https://trac.p2p-next.org/',
63             'dht_support': True,
64             'streaming_support': True,
65             'pxe_support': None,
66             'features': None
67         },
68         'libtorrent-rasterbar': {
69             'id': 3,
70             'language': 'C++',
71             'url': 'http://www.rasterbar.com/products/libtorrent/',
72             'dht_support': True,
73             'streaming_support': True,
74             'pxe_support': None,
75             'features': None
76         },
77         'Vuze': {
78             'id': 4,
79             'language': 'Java',
80             'url': 'http://www.vuze.com/',
81             'dht_support': True,
82             'streaming_support': True,
83             'pxe_support': None,
84             'features': None
85         },
86         'Transmission': {
87             'id': 5,
88             'language': 'C',
89             'url': 'http://www.transmissionbt.com/',
90             'dht_support': True,
91             'streaming_support': False,
92             'pxe_support': None,
93             'features': None
94         },
95         'Aria': {
96             'id': 6,
97             'language': 'C',
98             'url': 'http://aria2.sourceforge.net/',
99             'dht_support': True,
100             'streaming_support': False,
101             'pxe_support': None,
102             'features': None
103         },
104         'Mainline': {
105             'id': 7,
106             'language': 'Python',
107             'url': 'http://www.bittorrent.com/',
108             'dht_support': True,
109             'streaming_support': False,
110             'pxe_support': None,
111             'features': None
112         }
113 }
114
115 transfer_directions = {
116         'to': 1,
117         'from': 2
118 }
119
120 class Swarm(object):
121     """ Class mimics a C structure. """
122     def __init__(self, torrent_filename=None, data_size=None,
123             description=None):
124         self.torrent_filename = torrent_filename
125         self.data_size = data_size
126         self.description = description
127
128 class ClientSession(object):
129     """ Class mimics a C structure. """
130     def __init__(self, swarm_id=None, btclient=None, system_os=None,
131             system_os_version=None, system_ram=None, system_cpu=None,
132             public_ip=None, public_port=None, ds_limit=None, us_limit=None,
133             start_time=None, dht_enabled=None, pxe_enabled=None,
134             streaming_enabled=None, features=None, description=None):
135         self.swarm_id = swarm_id
136         self.btclient = btclient
137         self.system_os = system_os
138         self.system_os_version = system_os_version
139         self.system_ram = system_ram
140         self.system_cpu = system_cpu
141         self.public_ip = public_ip
142         self.public_port = public_port
143         self.ds_limit = ds_limit
144         self.us_limit = us_limit
145         self.start_time = start_time
146         self.dht_enabled = dht_enabled
147         self.pxe_enabled = pxe_enabled
148         self.streaming_enabled = streaming_enabled
149         self.features = features
150         self.description = description
151
152 class PeerStatusMessage(object):
153     """ Class mimics a C structure. """
154     def __init__(self, swarm_id=None, client_session_id=None, date=None,
155             time=None, peer_ip=None, peer_port=None, download_speed=None,
156             upload_speed=None):
157         self.swarm_id = swarm_id
158         self.client_session_id = client_session_id
159         self.date = date
160         self.time = time
161         self.peer_ip = peer_ip
162         self.peer_port = peer_port
163         self.download_speed = download_speed
164         self.upload_speed = upload_speed
165
166 class StatusMessage(object):
167     """ Class mimics a C structure. """
168     def __init__(self, swarm_id=None, client_session_id=None, date=None,
169             time=None, num_peers=None, num_dht_peers=None,
170             download_speed=None, upload_speed=None, download_size=None,
171             upload_size=None, eta=None):
172         self.swarm_id = swarm_id
173         self.client_session_id = client_session_id
174         self.date = date
175         self.time = time
176         self.num_peers = num_peers
177         self.num_dht_peers = num_dht_peers
178         self.download_speed = download_speed
179         self.upload_speed = upload_speed
180         self.download_size = download_size
181         self.upload_size = upload_size
182         self.eta = eta
183
184 class VerboseMessage(object):
185     """ Class mimics a C structure. """
186     def __init__(self, swarm_id=None, client_session_id=None, date=None,
187             time=None, transfer_direction=None, peer_ip=None, peer_port=None,
188             message_type=None, index=None, begin=None, length=None,
189             listen_port=None):
190         self.swarm_id = swarm_id
191         self.client_session_id = client_session_id
192         self.date = date
193         self.time = time
194         self.transfer_direction = transfer_direction
195         self.peer_ip = peer_ip
196         self.peer_port = peer_port
197         self.message_type = message_type
198         self.index = index
199         self.begin = begin
200         self.length = length
201         self.listen_port = listen_port
202
203 class SwarmDataAccess(object):
204     def __init__(self):
205         pass
206
207     def add_swarm(self, swarm):
208         pass
209
210     def remove_swarm(self):
211         pass
212
213     def get_swarm(self):
214         pass
215
216     def update_swarm(self):
217         pass
218
219     def add_client_session(self, session):
220         pass
221
222     def remove_client_session(self):
223         pass
224
225     def get_client_session(self):
226         pass
227
228     def update_client_session(self):
229         pass
230
231     def add_peer_status_message(self, msg):
232         pass
233
234     def remove_peer_status_message(self):
235         pass
236
237     def get_peer_status_message(self):
238         pass
239
240     def update_peer_status_message(self):
241         pass
242
243     def add_status_message(self, msg):
244         pass
245
246     def remove_status_message(self):
247         pass
248
249     def get_status_message(self):
250         pass
251
252     def update_status_message(self):
253         pass
254
255     def add_verbose_message(self, msg):
256         pass
257
258     def remove_verbose_message(self):
259         pass
260
261     def get_verbose_message(self):
262         pass
263
264     def update_verbose_message(self):
265         pass
266
267 class FileAccess(SwarmDataAccess):
268     def __init__(self, path):
269         self.base_path = path
270
271 def find_last_numeric_subfolder(path):
272     """
273     Find last numeric folder in base_path folder.
274     The last numeric folder is the last swarm_id.
275     """
276     dir_list = []
277     pattern = re.compile("[0-9]+")
278
279     # Browse entries in base_path folder.
280     listing = os.listdir(path)
281     for entry in listing:
282         # If directory name is a number (id) add it to the list.
283         if os.path.isdir(os.path.join(path, entry)):
284             if pattern.match(entry):
285                 dir_list.append(int(entry))
286
287     if not dir_list:
288         return None
289     else:
290         dir_list.sort()
291         return dir_list[len(dir_list)-1]
292
293 class TreeTextFileAccess(FileAccess):
294     def __init__(self, path):
295         super(TreeTextFileAccess, self).__init__(path)
296
297     def add_swarm(self, swarm):
298         """
299         Create a subfolder with an unique id. Add 1 to the last numeric
300         subfolder id. In case none exists, use 1 as id.
301         """
302         id = find_last_numeric_subfolder(self.base_path)
303         if id == None:
304             id = 1
305         else:
306             id = id+1
307
308         swarm_path = os.path.join(self.base_path, str(id))
309         os.mkdir(swarm_path)
310
311         swarm_config = os.path.join(swarm_path, "swarm.conf")
312         f = open(swarm_config, 'w')
313         f.write("""id = %s
314         torrent_filename = %s
315         data_size = %s
316         description = %s
317         """ %(id, swarm.torrent_filename, swarm.data_size, swarm.description))
318         f.close()
319
320     def add_client_session(self, session):
321         """
322         Create session subfolder in swarm subfolder and add config file.
323         TODO: Throw exception in case swarm subfolder doesn't exist.
324         """
325         swarm_path = os.path.join(self.base_path, str(session.swarm_id))
326
327         # Search first available folder in swarm_path.
328         id = find_last_numeric_subfolder(swarm_path)
329         if id == None:
330             id = 1
331         else:
332             id = id+1
333
334         # Create session subfolder.
335         session_path = os.path.join(swarm_path, str(id))
336         os.mkdir(session_path)
337
338         # Create and populate configuration file.
339         session_config = os.path.join(session_path, "client_session.conf")
340         f = open(session_config, 'w')
341         f.write("""id = %s
342         swarm_id = %s
343         btclient = %s
344         system_os = %s
345         system_os_version = %s
346         system_ram = %s
347         system_cpu = %s
348         public_ip = %s
349         public_port = %s
350         ds_limit = %s
351         us_limit = %s
352         start_time = %s
353         dht_enabled = %s
354         pxe_enabled = %s
355         streaming_enabled = %s
356         features = %s
357         description = %s
358         """ %(id, session.swarm_id, session.btclient, session.system_os,
359             session.system_os_version, session.system_ram, session.system_cpu,
360             session.public_ip, session.public_port, session.ds_limit,
361             session.us_limit, session.start_time, session.dht_enabled,
362             session.pxe_enabled, session.streaming_enabled,
363             session.features, session.description))
364         f.close()
365
366     def add_peer_status_message(self, msg):
367         # TODO: id is number of lines in file.
368         swarm_path = os.path.join(self.base_path, str(msg.swarm_id))
369         session_path = os.path.join(swarm_path, str(msg.client_session_id))
370         message_file = os.path.join(session_path, "peer_status.txt")
371
372         f = open(message_file, 'w')
373         f.write("""id = %s
374         swarm_id = %s
375         client_session_id = %s
376         date = %s
377         time = %s
378         peer_ip = %s
379         peer_port = %s
380         download_speed = %s
381         upload_speed = %s
382         """ %(1, msg.swarm_id, msg.client_session_id, msg.date, msg.time,
383             msg.peer_ip, msg.peer_port, msg.download_speed, msg.upload_speed))
384         f.close()
385
386     def add_status_message(self, msg):
387         # TODO: id is number of lines in file.
388         swarm_path = os.path.join(self.base_path, str(msg.swarm_id))
389         session_path = os.path.join(swarm_path, str(msg.client_session_id))
390         message_file = os.path.join(session_path, "status.txt")
391
392         f = open(message_file, 'w')
393         f.write("""id = %s
394         swarm_id = %s
395         client_session_id = %s
396         date = %s
397         time = %s
398         num_peers = %s
399         num_dht_peers = %s
400         download_speed = %s
401         upload_speed = %s
402         download_size = %s
403         upload_size = %s
404         eta = %s
405         """ %(1, msg.swarm_id, msg.client_session_id, msg.date, msg.time,
406             msg.num_peers, msg.num_dht_peers, msg.download_speed,
407             msg.upload_speed, msg.download_size, msg.upload_size, msg.eta))
408         f.close()
409
410     def add_verbose_message(self, msg):
411         # TODO: id is number of lines in file.
412         swarm_path = os.path.join(self.base_path, str(msg.swarm_id))
413         session_path = os.path.join(swarm_path, str(msg.client_session_id))
414         message_file = os.path.join(session_path, "verbose.txt")
415
416         f = open(message_file, 'w')
417         f.write("""id = %s
418         swarm_id = %s
419         client_session_id = %s
420         date = %s
421         time = %s
422         transfer_direction = %s
423         peer_ip = %s
424         peer_port = %s
425         message_type = %s
426         index = %s
427         begin = %s
428         length = %s
429         listen_port = %s
430         """ %(1, msg.swarm_id, msg.client_session_id, msg.date, msg.time,
431             msg.transfer_direction, msg.peer_ip, msg.peer_port,
432             msg.message_type, msg.index, msg.begin, msg.length,
433             msg.listen_port))
434         f.close()
435
436 class DatabaseAccess(SwarmDataAccess):
437     def __init__(self):
438         pass
439
440     def connect(self, database):
441         self.database = database
442         self.conn = None
443         self.cursor = None
444
445     def disconnect(self):
446         self.cursor.close()
447         self.conn.close()
448
449 class SQLiteDatabaseAccess(DatabaseAccess):
450     def __init___(self):
451         pass
452
453     def connect(self, database):
454         self.database = database
455         self.conn = sqlite3.connect(self.database)
456         self.cursor = self.conn.cursor()
457
458     def add_swarm(self, swarm):
459         pass
460
461     def add_client_session(self, session):
462         pass
463
464     def add_peer_status_message(self, msg):
465         pass
466
467     def add_status_message(self, msg):
468         pass
469
470     def add_verbose_message(self, msg):
471         pass
472
473 class MySQLDatabaseAccess(DatabaseAccess):
474     def __init___(self):
475         pass
476
477     def connect(self, database):
478         pass
479
480     def add_swarm(self, swarm):
481         pass
482
483     def add_client_session(self, session):
484         pass
485
486     def add_peer_status_message(self, msg):
487         pass
488
489     def add_status_message(self, msg):
490         pass
491
492     def add_verbose_message(self, msg):
493         pass