[1mdiff --git a/gmcapsule/init.py b/gmcapsule/init.py[m
[1mindex decc1d8..7a98b98 100644[m
[1m--- a/gmcapsule/init.py[m
[1m+++ b/gmcapsule/init.py[m
[36m@@ -508,11 +508,16 @@[m [mclass Config:[m
"""[m
[m
def __init__(self, config_path):[m
[32m+[m[32m self.config_path = config_path[m
[32m+[m[32m self.reload()[m
[32m+[m
[32m+[m[32m def reload(self):[m
self.ini = configparser.ConfigParser()[m
[31m- if os.path.exists(config_path):[m
[31m- self.ini.read(config_path)[m
[32m+[m[32m if os.path.exists(self.config_path):[m
[32m+[m[32m print('Configuration:', self.config_path)[m
[32m+[m[32m self.ini.read(self.config_path)[m
else:[m
[31m- print(config_path, 'not found -- using defaults')[m
[32m+[m[32m print(self.config_path, 'not found -- using defaults')[m
[m
def hostnames(self):[m
"""[m
[1mdiff --git a/gmcapsule/gemini.py b/gmcapsule/gemini.py[m
[1mindex ecddbeb..a7026a0 100644[m
[1m--- a/gmcapsule/gemini.py[m
[1m+++ b/gmcapsule/gemini.py[m
[36m@@ -11,6 +11,7 @@[m [mimport socket[m
import threading[m
import queue[m
import re[m
[32m+[m[32mimport signal[m
import time[m
from pathlib import Path[m
from urllib.parse import urlparse[m
[36m@@ -659,22 +660,25 @@[m [mclass Worker(threading.Thread):[m
return[m
[m
[m
[32m+[m[32m_server_instance = None[m
[32m+[m
[32m+[m[32mdef _restart_workers(signum, frame):[m
[32m+[m[32m if signum == signal.SIGHUP:[m
[32m+[m[32m _server_instance.restart_workers()[m
[32m+[m
[32m+[m
class Server:[m
def __init__(self, cfg):[m
[32m+[m[32m global _server_instance[m
[32m+[m[32m assert _server_instance is None[m
[32m+[m[32m _server_instance = self[m
#mp.set_start_method('spawn')[m
[32m+[m[32m self.cfg = cfg[m
[32m+[m[32m self.address = cfg.address()[m
[32m+[m[32m self.port = cfg.port()[m
[m
[31m- hostname_or_hostnames = cfg.hostnames()[m
cert_path = cfg.certs_dir() / 'cert.pem'[m
key_path = cfg.certs_dir() / 'key.pem'[m
[31m- address = cfg.address()[m
[31m- port = cfg.port()[m
[31m- session_id = f'GmCapsule:{cfg.port()}'.encode('utf-8')[m
[31m- num_threads = cfg.num_threads()[m
[31m-[m
[31m- self.hostnames = [hostname_or_hostnames] \[m
[31m- if type(hostname_or_hostnames) == str else hostname_or_hostnames[m
[31m- self.address = address[m
[31m- self.port = port[m
[m
if not os.path.exists(cert_path):[m
raise Exception("certificate file not found: " + str(cert_path))[m
[36m@@ -685,22 +689,32 @@[m [mclass Server:[m
self.context.use_certificate_file(str(cert_path))[m
self.context.use_privatekey_file(str(key_path))[m
self.context.set_verify(SSL.VERIFY_PEER, verify_callback)[m
[31m- if session_id:[m
[31m- if type(session_id) != bytes:[m
[31m- raise Exception("session_id type must be bytes
")[m
[31m- self.context.set_session_id(session_id)[m
[32m+[m
[32m+[m[32m session_id = f'GmCapsule:{cfg.port()}'.encode('utf-8')[m
[32m+[m[32m #if type(session_id) != bytes:[m
[32m+[m[32m # raise Exception("session_id type must be bytes
")[m
[32m+[m[32m self.context.set_session_id(session_id)[m
[m
# Spawn the worker threads.[m
self.shutdown_event = threading.Event()[m
self.workers = [][m
self.work_queue = queue.Queue()[m
[31m- for worker_id in range(max(num_threads, 1)):[m
[31m- worker = Worker(worker_id, cfg, self.work_queue, self.shutdown_event)[m
[31m- self.workers.append(worker)[m
[32m+[m[32m self.create_workers(cfg)[m
[m
self.sock = None[m
self.sv_conn = None[m
[m
[32m+[m[32m def restart_workers(self):[m
[32m+[m[32m """[m
[32m+[m[32m Restarts workers with an updated configuration. The server socket or[m
[32m+[m[32m TLS configuration are not modified, even if the values have changed[m
[32m+[m[32m in the configuration file.[m
[32m+[m[32m """[m
[32m+[m[32m self.stop_workers()[m
[32m+[m[32m self.cfg.reload()[m
[32m+[m[32m self.create_workers(self.cfg)[m
[32m+[m[32m self.start_workers()[m
[32m+[m
def run(self):[m
attempts = 60[m
print(f'Opening port {self.port}...')[m
[36m@@ -720,14 +734,12 @@[m [mclass Server:[m
print('...')[m
print(f'Server started on port {self.port}')[m
[m
[31m- PARALLELIZE = True[m
[31m-[m
[31m- if PARALLELIZE:[m
[31m- for worker in self.workers:[m
[31m- worker.start()[m
[31m- print(len(self.workers), 'worker(s) started')[m
[32m+[m[32m self.start_workers()[m
[m
[31m- snapshot = None[m
[32m+[m[32m try:[m
[32m+[m[32m signal.signal(signal.SIGHUP, _restart_workers)[m
[32m+[m[32m except ValueError:[m
[32m+[m[32m print('Restarting with SIGHUP not supported')[m
[m
while True:[m
stream = None[m
[36m@@ -735,11 +747,6 @@[m [mclass Server:[m
stream, from_addr = self.sv_conn.accept()[m
stream._socket.settimeout(10)[m
self.work_queue.put((stream, from_addr))[m
[31m-[m
[31m- if not PARALLELIZE:[m
[31m- self.work_queue.put((None, None)) # single iteration only[m
[31m- self.workers[0].run()[m
[31m-[m
del stream[m
del from_addr[m
except KeyboardInterrupt:[m
[36m@@ -756,11 +763,27 @@[m [mclass Server:[m
self.sock = None[m
[m
# Stop all workers.[m
[31m- self.shutdown_event.set()[m
[31m- if PARALLELIZE:[m
[31m- for i in range(len(self.workers)):[m
[31m- self.work_queue.put((None, None))[m
[31m- for worker in self.workers:[m
[31m- worker.join()[m
[32m+[m[32m self.stop_workers()[m
[m
print('Done')[m
[32m+[m
[32m+[m[32m def create_workers(self, cfg):[m
[32m+[m[32m self.shutdown_event.clear()[m
[32m+[m[32m for worker_id in range(max(cfg.num_threads(), 1)):[m
[32m+[m[32m worker = Worker(worker_id, cfg, self.work_queue, self.shutdown_event)[m
[32m+[m[32m self.workers.append(worker)[m
[32m+[m
[32m+[m[32m def start_workers(self):[m
[32m+[m[32m for worker in self.workers:[m
[32m+[m[32m worker.start()[m
[32m+[m[32m print(len(self.workers), 'worker(s) started')[m
[32m+[m
[32m+[m[32m def stop_workers(self):[m
[32m+[m[32m self.shutdown_event.set()[m
[32m+[m[32m n = len(self.workers)[m
[32m+[m[32m for _ in range(n):[m
[32m+[m[32m self.work_queue.put((None, None))[m
[32m+[m[32m for worker in self.workers:[m
[32m+[m[32m worker.join()[m
[32m+[m[32m self.workers = [][m
[32m+[m[32m print(n, 'worker(s) stopped')[m
text/plain
This content has been proxied by September (ba2dc).