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