Mercurial > personal > weather-server
annotate weather_server/logfile.py @ 23:88249e451566
server: show date when last report was >12h ago.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 10 Nov 2019 19:42:04 -0500 |
parents | beb42c835c52 |
children | 20c8ec56e447 |
rev | line source |
---|---|
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
1 """The part which handles writing things out and reading things in from CSV. |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
2 """ |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
3 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
4 import concurrent.futures as futures |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
5 import contextlib |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
6 import fcntl |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
7 import os |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
8 import queue |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
9 import threading |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
10 import typing as t |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
11 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
12 import bson |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
13 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
14 from . import common |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
15 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
16 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
17 class _WriteRequest: |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
18 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
19 def __init__(self, entries: t.Iterable[t.Dict[str, t.Any]]): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
20 """Creates a request to write the given data to the log.""" |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
21 # The data to be written. We take ownership of all the dicts! |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
22 self.entries = entries |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
23 # Once written, a future that will resolve to None if successful. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
24 self.future = futures.Future() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
25 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
26 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
27 class _ReadRequest: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
28 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
29 def __init__(self): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
30 # The future that will be set with the log's contnets. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
31 self.future = futures.Future() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
32 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
33 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
34 # probably handle file-writing with a queue that reports back its progress |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
35 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
36 class Logger: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
37 """Logger which handles reading/writing a temperature log for one process. |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
38 """ |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
39 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
40 instance_lock = threading.Lock() |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
41 instances: t.Dict[str, 'Logger'] = {} |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
42 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
43 @classmethod |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
44 def create( |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
45 cls, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
46 filename: str, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
47 *, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
48 sample_field: str, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
49 ) -> 'Logger': |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
50 """Creates a single shared instance of a logger for the given file.""" |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
51 try: |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
52 instance = cls.instances[filename] |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
53 except KeyError: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
54 with cls.instance_lock: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
55 try: |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
56 instance = cls.instances[filename] |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
57 except KeyError: |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
58 cls.instances[filename] = Logger( |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
59 filename, |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
60 sample_field=sample_field) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
61 instance = cls.instances[filename] |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
62 if instance._sample_field != sample_field: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
63 raise ValueError( |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
64 'Existing instance has different sample field: ' |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
65 '{!r} != {!r}'.format(instance._sample_field, sample_field)) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
66 return instance |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
67 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
68 def __init__(self, filename: str, *, sample_field: str): |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
69 """You should probably call .create() instead.""" |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
70 self._sample_field = sample_field |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
71 self._file = _open_or_create(filename) |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
72 self._data: t.List[t.Dict[str, t.Any], ...] = [] |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
73 self._queue = queue.SimpleQueue() |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
74 self._last_size = 0 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
75 self._lock_status: t.Optional[int] = None |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
76 self._writer_thread = threading.Thread(target=self._writer) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
77 self._writer_thread.start() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
78 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
79 @property |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
80 def data(self) -> t.Tuple[t.Dict[str, t.Any], ...]: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
81 req = _ReadRequest() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
82 self._queue.put(req) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
83 return req.future.result() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
84 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
85 def write_rows(self, entries: t.Iterable[t.Dict[str, t.Any]]): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
86 req = _WriteRequest(entries) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
87 self._queue.put(req) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
88 return req.future.result() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
89 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
90 _POISON = object() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
91 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
92 def close(self): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
93 self._queue.put(self._POISON) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
94 self._writer_thread.join() |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
95 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
96 def _writer(self) -> None: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
97 running = True |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
98 while running: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
99 item = self._queue.get() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
100 if item is self._POISON: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
101 # None is the poison pill that makes us stop. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
102 running = False |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
103 elif isinstance(item, _ReadRequest): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
104 if not item.future.set_running_or_notify_cancel(): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
105 continue |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
106 try: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
107 with self._file_lock(fcntl.LOCK_SH): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
108 self._catch_up() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
109 except BaseException as x: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
110 item.future.set_exception(x) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
111 else: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
112 item.future.set_result(tuple(self._data)) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
113 elif isinstance(item, _WriteRequest): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
114 if not item.future.set_running_or_notify_cancel(): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
115 continue |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
116 try: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
117 with self._file_lock(fcntl.LOCK_EX): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
118 self._catch_up() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
119 # Since we're at the last good point, truncate after. |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
120 self._file.truncate(self._file.tell()) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
121 if not self._data: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
122 last = None |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
123 else: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
124 last = self._data[-1][self._sample_field] |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
125 for entry in item.entries: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
126 entry_key = entry[self._sample_field] |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
127 if last is None or last < entry_key: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
128 self._file.write(common.bson_encode(entry)) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
129 self._data.append(entry) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
130 last = entry_key |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
131 self._file.flush() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
132 self._last_size = self._file.tell() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
133 except BaseException as x: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
134 item.future.set_exception(x) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
135 else: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
136 item.future.set_result(None) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
137 else: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
138 raise AssertionError( |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
139 'Unexpected item {!r} in the queue'.format(item)) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
140 self._file.close() |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
141 |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
142 def _catch_up(self) -> None: |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
143 """Reads data and advances the file pointer to the end of the file.""" |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
144 assert self._lock_status is not None, 'The lock must be held.' |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
145 size = self._size() |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
146 if size == self._last_size: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
147 return |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
148 last_good = self._file.tell() |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
149 try: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
150 items = bson.decode_file_iter( |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
151 self._file, codec_options=common.BSON_OPTIONS) |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
152 for item in items: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
153 last_good = self._file.tell() |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
154 self._data.append(item) |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
155 except bson.InvalidBSON: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
156 pass # We have reached the last valid document. Bail. |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
157 # Seek back to immediately after the end of the last valid doc. |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
158 self._last_size = last_good |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
159 self._file.seek(last_good, os.SEEK_SET) |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
160 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
161 def fileno(self) -> int: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
162 return self._file.fileno() |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
163 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
164 def _size(self) -> int: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
165 return os.stat(self.fileno()).st_size |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
166 |
21
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
167 @contextlib.contextmanager |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
168 def _file_lock(self, operation: int): |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
169 assert operation in (fcntl.LOCK_SH, fcntl.LOCK_EX), 'Invalid operation.' |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
170 fcntl.flock(self, operation) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
171 self._lock_status = operation |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
172 try: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
173 yield |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
174 finally: |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
175 self._lock_status = None |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
176 fcntl.flock(self, fcntl.LOCK_UN) |
beb42c835c52
Make weather server handle arbitrary data:
Paul Fisher <paul@pfish.zone>
parents:
0
diff
changeset
|
177 |
0
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
178 |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
179 def _open_or_create(path: str) -> t.BinaryIO: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
180 while True: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
181 try: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
182 return open(path, 'r+b') |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
183 except FileNotFoundError: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
184 pass |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
185 try: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
186 return open(path, 'x+b') |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
187 except FileExistsError: |
efe7a1eff167
Create initial logger for weather server.
Paul Fisher <paul@pfish.zone>
parents:
diff
changeset
|
188 pass |