Repository navigation
Expand file tree
/
Copy pathapiServer.py
More file actions
132 lines (108 loc) · 4.07 KB
/
Copy pathapiServer.py
File metadata and controls
132 lines (108 loc) · 4.07 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
from http.server import BaseHTTPRequestHandler
from pprint import pprint
import json
import sys
import os
import time
from tion_btle.tion import tion
from tion_btle.s3 import S3
from tion_btle.lite import Lite
class TionApiServer(BaseHTTPRequestHandler):
allowed_devices = []
cache_valid = 600 # seconds
cache_expire = 0
cache_response = {}
@classmethod
def _is_cache_valid(cls, ts) -> bool:
return not cls.cache_expire < ts
@classmethod
def _invalidate_cache(cls):
cls.cache_expire = 0
@classmethod
def _get_cache(cls) -> dict:
return cls.cache_response
@classmethod
def _set_cache(cls, response, ts):
cls.cache_expire = ts + cls.cache_valid
cls.cache_response = dict(response)
cls.cache_response["code"] = 304
cls.cache_response["last_update"] = ts
def __init__(self, request, client_addr, server):
self.allowed_devices = self._get_allowed_devices()
BaseHTTPRequestHandler.__init__(self, request, client_addr, server)
def _get_allowed_devices(self):
result = []
for c in tion.__subclasses__():
result.append(c.__name__)
return result
def _set_headers(self, code):
self.send_response(code)
self.send_header('Content-type', 'application/json')
self.end_headers()
def _send_response(self, code, message: dict, error=""):
self._set_headers(200)
response = {"code": code, "error": error, }
response = {**response, **message}
response = json.dumps(response)
self.log_message("Response is: " + response)
self.wfile.write((response + "\n").encode())
def _create_device(self, device_name: str, device_mac: str) -> tion:
if device_name in self.allowed_devices:
device = getattr(sys.modules[__name__], device_name)(device_mac)
else:
raise AttributeError
return device
def _send_bad_request(self, message: str):
self._send_response(400, {"message": "request is {}".format(self.path)}, message)
def _get_device_from_request(self, path: str) -> tion:
s = path.split("?")
r = s[0].split("/")
try:
device_name = r[1]
device_mac = r[2]
except IndexError as e:
self._send_bad_request("Use requests like '/model/mac_addres'")
return
if len(s) > 1:
p = s[1].split("&")
try:
device = self._create_device(device_name, device_mac)
except AttributeError as e:
self._send_response(422, {}, "Device {} is not supported".format(device_name))
return
self.log_message(path)
self.log_message("Process device {0} with mac {1}".format(device_name, device_mac))
return device
def do_GET(self):
now = time.time()
if not self._is_cache_valid(now):
try:
device = self._get_device_from_request(self.path)
response = device.get()
except Exception as e:
self._invalidate_cache() # drop cache
self._send_response(400, {}, str(e))
else:
if response["code"] == 200:
self._set_cache(response, now)
self._send_response(response["code"], response)
else:
response = self._get_cache()
self._send_response(response["code"], response)
def do_POST(self):
content_len = int(self.headers.get('content-length', 0))
post_body = self.rfile.read(content_len).decode()
device = self._get_device_from_request(self.path)
i = 0
done = False
exception = None
self.log_message(post_body)
self._invalidate_cache() # drop cache
try:
device.set(json.loads(post_body))
except Exception as e:
self._send_response(400, {}, str(e))
else:
self._send_response(200, {"message": "Data {} were sent to device {}".format(post_body, device.mac)})
def do_PUT(self):
self.do_POST()