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