2023-10-23 15:43:36 -04:00
|
|
|
import io
|
|
|
|
import select
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from . import logging
|
|
|
|
from . import wifi
|
|
|
|
from . import http
|
|
|
|
|
|
|
|
|
|
|
|
class Server:
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.wlan = wifi.connect()
|
|
|
|
self.socket = socket.socket()
|
|
|
|
self.poller = select.poll()
|
|
|
|
self.default_path = 'index.html'
|
|
|
|
|
|
|
|
def cleanup(self):
|
|
|
|
self.socket.close()
|
|
|
|
self.wlan.disconnect()
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
try:
|
|
|
|
addr = self.listen()
|
|
|
|
self.poller.register(self.socket, select.POLLIN)
|
|
|
|
|
|
|
|
logging.info(f'listening on {addr}')
|
|
|
|
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
self.serve()
|
|
|
|
self.work()
|
|
|
|
except Exception as e:
|
2023-10-27 17:48:42 -04:00
|
|
|
self.log_exception(e)
|
2023-10-23 15:43:36 -04:00
|
|
|
finally:
|
|
|
|
self.cleanup()
|
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
def log_exception(self, e):
|
2023-10-23 15:43:36 -04:00
|
|
|
buf = io.StringIO()
|
|
|
|
sys.print_exception(e, buf)
|
|
|
|
logging.debug(f'exception:', buf.getvalue())
|
|
|
|
|
|
|
|
def listen(self):
|
|
|
|
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
|
|
|
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
|
|
self.socket.bind(addr)
|
|
|
|
self.socket.listen(1)
|
|
|
|
|
|
|
|
return addr
|
|
|
|
|
|
|
|
def serve(self):
|
2023-10-27 18:07:44 -04:00
|
|
|
evts = self.poller.poll(50)
|
2023-10-23 15:43:36 -04:00
|
|
|
|
|
|
|
for sock, _evt in evts:
|
|
|
|
try:
|
|
|
|
conn, addr = sock.accept()
|
|
|
|
logging.info(f'client connected from {addr}')
|
|
|
|
request = conn.recv(1024).decode('utf-8').strip()
|
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
self.handle_request(conn, request)
|
2023-10-23 15:43:36 -04:00
|
|
|
except:
|
2023-10-27 17:48:42 -04:00
|
|
|
conn.write(http.server_error_response)
|
2023-10-23 15:43:36 -04:00
|
|
|
raise
|
|
|
|
finally:
|
|
|
|
conn.close()
|
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
def handle_request(self, conn, request):
|
2023-10-23 15:43:36 -04:00
|
|
|
[method, path, _protocol] = request.partition('\n')[0].split()
|
|
|
|
|
|
|
|
logging.info(f'{method} {path}')
|
|
|
|
|
|
|
|
try:
|
|
|
|
if method == 'GET':
|
2023-10-27 17:48:42 -04:00
|
|
|
response = self.handle_path(path.strip('/'))
|
2023-10-23 15:43:36 -04:00
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
conn.write(self.get_content_type(path, response))
|
2023-10-23 15:43:36 -04:00
|
|
|
conn.write(response)
|
|
|
|
else:
|
2023-10-27 17:48:42 -04:00
|
|
|
conn.write(http.not_found_response)
|
2023-10-23 15:43:36 -04:00
|
|
|
except OSError:
|
2023-10-27 17:48:42 -04:00
|
|
|
conn.write(http.not_found_response)
|
2023-10-23 15:43:36 -04:00
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
def get_content_type(self, path, response):
|
2023-10-23 15:43:36 -04:00
|
|
|
if path.endswith('.txt'):
|
2023-10-27 17:48:42 -04:00
|
|
|
return http.ok_text_response
|
2023-10-23 15:43:36 -04:00
|
|
|
elif path.endswith('.json'):
|
2023-10-27 17:48:42 -04:00
|
|
|
return http.ok_json_response
|
2023-10-23 15:43:36 -04:00
|
|
|
elif path.endswith('.ico'):
|
2023-10-27 17:48:42 -04:00
|
|
|
return http.ok_icon_response
|
2023-10-27 17:39:58 -04:00
|
|
|
elif response == '':
|
2023-10-27 17:48:42 -04:00
|
|
|
return http.no_content_response
|
2023-10-23 15:43:36 -04:00
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
return http.ok_response
|
2023-10-23 15:43:36 -04:00
|
|
|
|
2023-10-27 17:48:42 -04:00
|
|
|
def handle_path(self, _path):
|
2023-10-23 15:43:36 -04:00
|
|
|
return ''
|
|
|
|
|
|
|
|
def work(self):
|
|
|
|
if not self.wlan.isconnected():
|
|
|
|
self.wlan = wifi.connect()
|