-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
136 lines (103 loc) · 3.68 KB
/
Copy pathmain.py
File metadata and controls
136 lines (103 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import argparse, loguru, threading, time, yaml, sys, os, psutil, signal
from daemoniker import Daemonizer, SignalHandler1, send, SIGTERM
from sender import Sender
from receiver import Receiver
FILE = 'clipboard'
LOG_FILE = f'{FILE}.log'
DAEMON_FILE = f'{FILE}.pid'
def parse_arguments():
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--node", required=True,
help="host node name from config")
parser.add_argument("-c", "--config",
help="path to configuration file")
parser.add_argument("-l", "--log", choices=["DEBUG", "INFO", "WARNING", "ERROR"],
help="enable logging (default: disabled)")
parser.add_argument("-lf", "--log-file", dest="logf", nargs='?', const=f"{LOG_FILE}",
help=f'write logs to file (default: {LOG_FILE})')
parser.add_argument("-d", "--daemon", action="store_true",
help="run as background daemon")
parser.add_argument("-dk", "--daemon-kill", dest="kill", action="store_true",
help="stop running daemon")
return parser.parse_args()
def setup_logger(args):
loguru.logger.remove()
if args.log:
if not args.daemon:
loguru.logger.add(sys.stderr, level=args.log)
if args.logf:
loguru.logger.add(args.logf, level=args.log)
def run(args):
try:
with open(args.config, 'r') as stream:
config = yaml.safe_load(stream)
except Exception as e:
loguru.logger.error(f'Config error: {e}')
sys.exit(1)
setup_logger(args)
host_node = args.node
if host_node not in config['nodes']:
loguru.logger.error(f'Node {host_node} not in config')
sys.exit(1)
key = config['key']
nodes = config['nodes']
node_conf = nodes[host_node]
receiver = Receiver(node_conf['host'], node_conf['port'], key)
threading.Thread(target=receiver.run, daemon=True).start()
peers = {
name: f"ws://{node['host']}:{node['port']}"
for name, node in nodes.items()
if name != host_node
}
loguru.logger.info(f'Starting {host_node} ({len(peers)} peers)')
sender = Sender(peers,key)
threading.Thread(target=sender.run, daemon=True).start()
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit, SIGTERM):
loguru.logger.info('Shutting down')
except Exception as e:
loguru.logger.error(f'Unexpected error: {e}')
sys.exit(1)
finally:
receiver.stop()
if peers:
sender.stop()
if os.path.exists(DAEMON_FILE):
os.remove(DAEMON_FILE)
def stop_previous_daemon():
try:
if os.path.exists(DAEMON_FILE):
with open(DAEMON_FILE, 'rb') as f:
pid = int(f.read())
if psutil.pid_exists(pid):
os.kill(pid, signal.SIGTERM)
timeout = time.time() + 10
while timeout < time.time() or psutil.pid_exists(pid):
time.sleep(1) # wait for process to die
os.remove(DAEMON_FILE)
except:
pass
def run_with_daemon(args):
stop_previous_daemon()
with Daemonizer() as (is_setup, daemonizer):
if is_setup:
pass
is_parent, args = daemonizer(DAEMON_FILE, args)
if is_parent:
pass
setup_logger(args)
SignalHandler1(DAEMON_FILE).start()
run(args)
def main():
arguments = parse_arguments()
if arguments.kill:
send(DAEMON_FILE, SIGTERM)
sys.exit(0)
if arguments.daemon:
run_with_daemon(arguments)
else:
run(arguments)
if __name__ == '__main__':
main()