2 from http.server import BaseHTTPRequestHandler
5 class PlomException(Exception):
11 def __init__(self, db_name):
12 self.db_file = db_name
13 self.lock_file = db_name+ '.lock'
14 if os.path.exists(self.db_file):
15 with open(self.db_file, 'r') as f:
19 if os.path.exists(self.lock_file):
20 raise PlomException('Sorry, lock file!')
21 f = open(self.lock_file, 'w+')
25 os.remove(self.lock_file)
29 from datetime import datetime, timedelta
30 if not os.path.exists(self.db_file):
33 # collect modification times of numbered .bak files
35 bak_prefix = f'{self.db_file}.bak.'
38 for path in [path for path in os.listdir(os.path.dirname(bak_prefix))
39 if path.startswith(os.path.basename(bak_prefix))]:
40 mod_time = os.path.getmtime(path)
41 print(f'DEBUG pre-exists: {path} {mod_time}')
42 mtimes_to_paths[str(datetime.fromtimestamp(mod_time))] = path
43 # backup_dates += [str(datetime.fromtimestamp(mod_time))]
45 for mtime in sorted(mtimes_to_paths.keys()):
46 print(f'DEBUG mtimes_to_paths: {mtime}:{mtimes_to_paths[mtime]}')
48 # collect what numbered .bak files to save: the older, the fewer; for each
49 # timedelta, keep the newest file that's older
50 ages_to_keep = [timedelta(minutes=4**i) for i in range(0, 8)]
51 print(f'DEBUG ages_to_keep: {ages_to_keep}')
54 for age in ages_to_keep:
56 for mtime in reversed(sorted(mtimes_to_paths.keys())):
57 print(f'DEBUG checking if {mtime} < {limit} ({now} - {age})')
58 if datetime.strptime(mtime, '%Y-%m-%d %H:%M:%S.%f') < limit:
59 print('DEBUG it is, adding!')
60 to_save[mtime] = mtimes_to_paths[mtime]
63 for path in [path for path in mtimes_to_paths.values()
64 if path not in to_save.values()]:
65 print(f'DEBUG removing {path} cause not in to_save')
69 for mtime in sorted(to_save.keys()):
70 source = to_save[mtime]
71 target = f'{bak_prefix}{i}'
72 print(f'DEBUG to_save {source} -> {target}')
74 shutil.move(source, target)
77 # put copy of current state at end of bak list
78 print(f'DEBUG saving current state to {bak_prefix}{i}')
79 shutil.copy(self.db_file, f'{bak_prefix}{i}')
81 def write_text_to_db(self, text, mode='w'):
84 with open(self.db_file, mode) as f:
89 class PlomHandler(BaseHTTPRequestHandler):
91 html_head = '<!DOCTYPE html>\n<html>\n<meta charset="UTF-8">'
92 html_foot = '</body>\n</html>'
94 def fail_400(self, e):
95 self.send_HTML(f'ERROR: {e}', 400)
97 def send_HTML(self, html, code=200):
98 self.send_code_and_headers(code, [('Content-type', 'text/html')])
99 self.wfile.write(bytes(f'{self.html_head}\n{html}\n{self.html_foot}', 'utf-8'))
101 def send_code_and_headers(self, code, headers=[]):
102 self.send_response(code)
103 for fieldname, content in headers:
104 self.send_header(fieldname, content)
107 def redirect(self, url='/'):
108 self.send_code_and_headers(302, [('Location', url)])
110 def try_do(self, do_method):
113 except PlomException as e:
118 def run_server(port, handler_class):
119 from http.server import HTTPServer
120 webServer = HTTPServer(('localhost', port), handler_class)
121 print(f"Server started http://localhost:{port}")
123 webServer.serve_forever()
124 except KeyboardInterrupt:
126 webServer.server_close()
127 print("Server stopped.")