-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbadserver.py
108 lines (91 loc) · 3.52 KB
/
badserver.py
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
import io
import os
import shutil
import signal
import sys
import json
import collections
import threading
from http import HTTPStatus
from xmlrpc.server import SimpleXMLRPCRequestHandler
import garage
class HTTPAndRPCRequestHandler(SimpleXMLRPCRequestHandler):
''' extends RPC Handler
added HTTP GET feature
'''
rpc_paths = ('/RPC2',)
def do_GET(self):
"""Serve a GET request."""
f = self.simple_get()
try:
self.copyfile(f, self.wfile)
finally:
f.close()
def simple_get(self):
'''backup's api won't be called during lots of operation,
and they are read-only, so don't add any lock/condition
actually I can do this by adding lock/condition into RPC,
but too troublesome
'''
if self.path == '/kvman/shutdown':
try:
f = open('conf/backup.pid')
pid = int(f.readline())
f.close()
os.remove('conf/backup.pid')
os.kill(pid,signal.SIGKILL)
except:
try:
os.kill(os.getpid(),signal.SIGKILL)
except:
pass
if self.path == '/kvman/countkey':
return self.str2file('{"result": "'+str(garage.countkey())+'"}')
if self.path == '/kvman/dump':
return self.dict2file(garage.dump())
if self.path == '/kvman/gooddump':
return self.str2file('{"main_mem": '+json.dumps(garage.main_mem)+', "time_stamp": "'+str(garage.time_stamp[0])+'"}')
if self.path == '/':
return self.str2file('Test<br>This is backup<br>Client address: '+str(self.client_address)+'<br>Thread: '+threading.currentThread().getName())
return self.str2file('{"success":"false"}')
def copyfile(self, source, outputfile):
"""Copy all data between two file objects.
The SOURCE argument is a file object open for reading
(or anything with a read() method) and the DESTINATION
argument is a file object open for writing (or
anything with a write() method).
The only reason for overriding this would be to change
the block size or perhaps to replace newlines by CRLF
-- note however that this the default server uses this
to copy binary data as well.
"""
shutil.copyfileobj(source, outputfile)
def dict2file(self,d):
''' d is dictionary, similar to str2file(). by wgr'''
r = []
enc = sys.getfilesystemencoding()
od = collections.OrderedDict(sorted(d.items()))
for key,value in od.items():
r.append('['+json.dumps(key)+','+json.dumps(value)+']')
the_string = '['+', '.join(r)+']'
encoded = the_string.encode(enc, 'surrogateescape')
f = io.BytesIO()
f.write(encoded)
f.seek(0)
self.send_response(HTTPStatus.OK)
self.send_header("Content-type", "text/html; charset=%s" % enc)
self.send_header("Content-Length", str(len(encoded)))
self.end_headers()
return f
def str2file(self,word):
''' print string to a file by wgr'''
enc = sys.getfilesystemencoding()
encoded = word.encode(enc, 'surrogateescape')
f = io.BytesIO()
f.write(encoded)
f.seek(0)
self.send_response(HTTPStatus.OK)
self.send_header("Content-type", "text/html; charset=%s" % enc)
self.send_header("Content-Length", str(len(encoded)))
self.end_headers()
return f