Added comment
[ais.git] / bin / inputs / common.py
1 # -*- coding: utf-8 -*-
2 '''
3 AIS input basic functions
4 '''
5
6 from __future__ import division
7 import os.path
8 import logging
9 from datetime import datetime, timedelta
10
11 from ais.inputs.stats import InStats
12 from ais.inputs.config import peers_get_config
13 from ais.inputs.outpeer import outpeers_from_config
14
15 __all__ = [
16     'NMEA_DIR',
17     'DEFAULT_MTU',
18     'SourceLogger',
19     'Source', 
20     'get_source_by_id4', 'is_id4_active', 'refresh_all_stats',
21     ]
22
23
24 NMEA_DIR = '/var/lib/ais/nmea'
25 DEFAULT_MTU = 1500
26
27 def _get_log_filename(id4, date):
28     localfilename = '%s-%s.dump' \
29                     % (date.strftime('%Y%m%d'), id4)
30     return os.path.join(NMEA_DIR, localfilename)
31
32 class SourceLogger:
33     def __init__(self, id4):
34         self.id4 = id4
35         self.dumpfile = None
36         self.last_timestamp = None
37         self.last_dumpdate = None
38         self.last_from = None
39
40     def log_line(self, timestamp, from_, line):
41         '''
42         Log line in file NMEA_DIR/YYYYMMDD-4444.log.
43         Add a line "Timestamp:" if different than previous call.
44         Add a line "From:" if different than previous call.
45         '''
46
47         timestamp = int(timestamp) # we don't want to log second fragments
48         if timestamp != self.last_timestamp:
49             dumpdate = datetime.utcfromtimestamp(timestamp).date()
50             if dumpdate != self.last_dumpdate:
51                 if self.dumpfile:
52                     self.dumpfile.close()
53                 filename = _get_log_filename(self.id4, dumpdate)
54                 logging.info('Opening %s', filename)
55                 self.dumpfile = file(filename, 'a', 1)
56                 self.last_dumpdate = dumpdate
57                 self.last_from = None # make sure From: is present in new files
58             
59             self.dumpfile.write('Timestamp: %d\n' % timestamp)
60             self.last_timestamp = timestamp
61
62         if from_ != self.last_from:
63             self.dumpfile.write('From: %s\n' % from_)
64             self.last_from = from_
65
66         self.dumpfile.write(line+'\n')
67
68
69 __all_sources__ = {}
70
71 class Source:
72     def __init__(self, id4):
73         self.id4 = id4
74         assert id4 not in __all_sources__, \
75             '%s is allready a registered source.' % id4
76         __all_sources__[id4] = self
77         self.stats = InStats(id4)
78         self.logger = SourceLogger(id4)
79         sources_config = peers_get_config()
80         logging.debug('sources: %s', sources_config)
81         config_outpeers = sources_config[id4].get('out', ())
82         self.outpeers = outpeers_from_config(config_outpeers)
83         logging.info('Outpeers for %s: %s', id4, self.outpeers)
84         self.name = sources_config[id4].get('name', id4)
85
86 def get_source_by_id4(id4):
87     '''
88     Returns a Source object with that id4.
89     Create one if not found.
90     '''
91     return __all_sources__.get(id4, None) or Source(id4)
92
93 def is_id4_active(id4, seconds):
94     """
95     Returns True if the given source send data within the last X seconds
96     X cannot be more than 4 hours (see compression of archive in cron)
97     """
98     reference_time =  datetime.utcnow() - timedelta(seconds=seconds)
99     #logging.error('reference_time=%s', reference_time)
100     logfilename = _get_log_filename(id4, reference_time.date())
101     #logging.error('logfilename=%s', logfilename)
102     if not os.path.exists(logfilename):
103         return False
104     mod_timestamp = os.path.getmtime(logfilename)
105     #logging.error('file_time=%s', datetime.utcfromtimestamp(mod_timestamp))
106     return datetime.utcfromtimestamp(mod_timestamp) > reference_time
107
108
109 def refresh_all_stats():
110     '''
111     Calls stats.refresh() for all sources.
112     '''
113     for source in __all_sources__.itervalues():
114         source.stats.refresh()