mirror of
https://github.com/eliasrenman/gardentron.git
synced 2026-03-16 20:46:07 +01:00
feat: created decorator powered http server
This commit is contained in:
3
pico-w/.gitignore
vendored
3
pico-w/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.env
|
||||
env.json
|
||||
config.py
|
||||
config.py
|
||||
__pycache__
|
||||
6
pico-w/src/codes.py
Normal file
6
pico-w/src/codes.py
Normal file
@@ -0,0 +1,6 @@
|
||||
codes = {
|
||||
200: 'OK',
|
||||
400: 'Bad Request',
|
||||
404: 'Not Found',
|
||||
405: 'Method Not Allowed',
|
||||
}
|
||||
114
pico-w/src/decorators.py
Normal file
114
pico-w/src/decorators.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import socket
|
||||
import json
|
||||
from codes import codes
|
||||
|
||||
|
||||
def respond(cl: socket.socket, status: int, response: dict | list):
|
||||
|
||||
stringified = json.dumps(response, separators=(',', ':'))
|
||||
cl.send(
|
||||
f'HTTP/1.0 {status} {codes.get(status)}\r\nContent-type: text/json\r\n\r\n')
|
||||
cl.send(stringified)
|
||||
cl.close()
|
||||
|
||||
|
||||
class HttpError(Exception):
|
||||
def __init__(self, status: int, message: dict | list):
|
||||
|
||||
super().__init__(message)
|
||||
|
||||
self.status = status
|
||||
self.message = message
|
||||
|
||||
|
||||
class Endpoint:
|
||||
def __init__(self, path: str, method='GET'):
|
||||
if method not in ('GET', 'POST', 'PATCH', 'PUT', 'DELETE'):
|
||||
raise ValueError(
|
||||
'Valid values are GET, POST, PATCH, PUT', 'DELETE')
|
||||
self.method = method
|
||||
self.path = path
|
||||
|
||||
def __call__(self, function):
|
||||
def wrapper(instance, *args, **kwargs):
|
||||
|
||||
request: str = instance.__request # type: ignore
|
||||
cl: socket.socket = instance.__cl # type: ignore
|
||||
# TODO: Improve find checker here to be more precise when dealing with requests.
|
||||
if request.find(self.path) == -1 and self.path != '*' or request.find(self.method) == -1:
|
||||
return
|
||||
try:
|
||||
val = function(instance, *args, **kwargs)
|
||||
respond(cl, 200, val)
|
||||
return val
|
||||
except HttpError as e:
|
||||
respond(cl, e.status,
|
||||
e.message)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class ServerHandler(object):
|
||||
def __init__(self, s: socket.socket):
|
||||
not_found_endpoints = (self.__post_not_found,
|
||||
self.__get_not_found, self.__patch_not_found, self.__put_not_found, self.__delete_not_found)
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
||||
cl, addr = s.accept()
|
||||
print('client connected from', addr)
|
||||
request: bytes = cl.recv(1024)
|
||||
print(f"{request} \n")
|
||||
|
||||
self.__request = request.decode('utf-8')
|
||||
self.__cl = cl
|
||||
method_list = dir(self.__class__)
|
||||
alreadyReturned = False
|
||||
for endpoint in method_list:
|
||||
|
||||
if endpoint.startswith('_') is True:
|
||||
continue
|
||||
|
||||
func = getattr(self.__class__, endpoint)
|
||||
|
||||
if not callable(func):
|
||||
continue
|
||||
|
||||
result = func(self)
|
||||
if result:
|
||||
alreadyReturned = True
|
||||
break
|
||||
if (not alreadyReturned):
|
||||
for endpoint in not_found_endpoints:
|
||||
result = endpoint()
|
||||
if result:
|
||||
break
|
||||
|
||||
except OSError as e:
|
||||
print(e)
|
||||
self.__cl.close()
|
||||
s.close()
|
||||
|
||||
print('connection closed')
|
||||
break
|
||||
|
||||
@Endpoint('*', 'POST')
|
||||
def __post_not_found(self):
|
||||
raise HttpError(404, {'status': 'Not Found'})
|
||||
|
||||
@Endpoint('*', 'GET')
|
||||
def __get_not_found(self):
|
||||
raise HttpError(404, {'status': 'Not Found'})
|
||||
|
||||
@Endpoint('*', 'PATCH')
|
||||
def __patch_not_found(self):
|
||||
raise HttpError(404, {'status': 'Not Found'})
|
||||
|
||||
@Endpoint('*', 'PUT')
|
||||
def __put_not_found(self):
|
||||
raise HttpError(404, {'status': 'Not Found'})
|
||||
|
||||
@Endpoint('*', 'DELETE')
|
||||
def __delete_not_found(self):
|
||||
raise HttpError(404, {'status': 'Not Found'})
|
||||
@@ -1,9 +1,7 @@
|
||||
import socket
|
||||
from utime import sleep_ms
|
||||
from machine import Pin
|
||||
from config import ssid, password
|
||||
from server import initalize_app
|
||||
from config import led
|
||||
|
||||
led = Pin("LED", Pin.OUT)
|
||||
|
||||
led.value(1)
|
||||
sleep_ms(200)
|
||||
@@ -11,47 +9,4 @@ led.value(0)
|
||||
|
||||
print("Successfully started pico...")
|
||||
|
||||
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
|
||||
|
||||
s = socket.socket()
|
||||
s.bind(addr)
|
||||
s.listen(1)
|
||||
|
||||
print('listening on', addr)
|
||||
|
||||
|
||||
def respond(cl, status, response):
|
||||
cl.send(f'HTTP/1.0 {status} OK\r\nContent-type: text/html\r\n\r\n')
|
||||
cl.send(response)
|
||||
cl.close()
|
||||
|
||||
|
||||
# Listen for connections
|
||||
while True:
|
||||
try:
|
||||
cl, addr = s.accept()
|
||||
print('client connected from', addr)
|
||||
request = cl.recv(1024)
|
||||
print(request)
|
||||
|
||||
request = str(request)
|
||||
led_on = request.find('/light/on')
|
||||
led_off = request.find('/light/off')
|
||||
print('led on = ' + str(led_on))
|
||||
print('led off = ' + str(led_off))
|
||||
|
||||
if led_on == 6:
|
||||
print("led on")
|
||||
led.value(1)
|
||||
respond(cl, 200, '{"led": "on"}')
|
||||
|
||||
if led_off == 6:
|
||||
print("led off")
|
||||
led.value(0)
|
||||
respond(cl, 200, '{"led": "off"}')
|
||||
|
||||
except OSError as e:
|
||||
cl.close()
|
||||
s.close()
|
||||
|
||||
print('connection closed')
|
||||
initalize_app()
|
||||
|
||||
31
pico-w/src/server.py
Normal file
31
pico-w/src/server.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import socket
|
||||
from config import led
|
||||
from decorators import Endpoint, ServerHandler
|
||||
|
||||
|
||||
def initalize_app():
|
||||
|
||||
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
|
||||
|
||||
s = socket.socket()
|
||||
s.bind(addr)
|
||||
s.listen(1)
|
||||
print('listening on', addr)
|
||||
|
||||
# Listen for connections
|
||||
Handler(s)
|
||||
|
||||
|
||||
class Handler(ServerHandler):
|
||||
|
||||
@Endpoint('light/on', 'POST')
|
||||
def light_on(self):
|
||||
print("led on")
|
||||
led.value(1)
|
||||
return {"led": "on"}
|
||||
|
||||
@Endpoint('light/off', 'POST')
|
||||
def light_off(self):
|
||||
print("led off")
|
||||
led.value(0)
|
||||
return {"led": "off"}
|
||||
Reference in New Issue
Block a user