3131"""
3232# pylint: disable=no-name-in-module
3333
34+ import os
3435from micropython import const
3536import adafruit_esp32spi .adafruit_esp32spi_socket as socket
3637from adafruit_esp32spi .adafruit_esp32spi_requests import parse_headers
@@ -43,6 +44,7 @@ def set_interface(iface):
4344 socket .set_interface (iface )
4445
4546NO_SOCK_AVAIL = const (255 )
47+ INDEX_HTML = "/index.html"
4648
4749
4850# pylint: disable=unused-argument, redefined-builtin, invalid-name
@@ -54,6 +56,8 @@ def __init__(self, port=80, debug=False):
5456 self ._client_sock = socket .socket (socknum = NO_SOCK_AVAIL )
5557 self ._debug = debug
5658 self ._listeners = {}
59+ self ._static_dir = None
60+ self ._static_files = []
5761
5862
5963 def start (self ):
@@ -72,12 +76,43 @@ def on(self, method, path, request_handler):
7276
7377 request_handler should accept the following args:
7478 (Dict headers, bytes body, Socket client)
79+
7580 :param str method: the method of the HTTP request
7681 :param str path: the path of the HTTP request
7782 :param func request_handler: the function to call
7883 """
7984 self ._listeners [self ._get_listener_key (method , path )] = request_handler
8085
86+ def set_static_dir (self , directory_path ):
87+ """
88+ allows for setting a directory of static files that will be auto-served
89+ when that file is GET requested at'/<fileName.extension>'
90+ index.html will also be made available at root path '/'
91+
92+ Note: does not support serving files in child folders at this time
93+ """
94+ self ._static_dir = directory_path
95+ self ._static_files = ["/" + file for file in os .listdir (self ._static_dir )]
96+ print (self ._static_files )
97+
98+ def serve_file (self , file_path , dir = None ):
99+ """
100+ writes a file from the file system as a response to the client.
101+
102+ :param string file_path: path to the image to write to client.
103+ if dir is not present, it is treated as an absolute path
104+ :param string dir: path to directory that file is located in (optional)
105+ """
106+ self ._client_sock .write (b"HTTP/1.1 200 OK\r \n " )
107+ self ._client_sock .write (b"Content-Type:" + self ._get_content_type (file_path ) + b"\r \n " )
108+ self ._client_sock .write (b"\r \n " )
109+ full_path = file_path if not dir else dir + file_path
110+ with open (full_path , 'rb' ) as fp :
111+ for line in fp :
112+ self ._client_sock .write (line )
113+ self ._client_sock .write (b"\r \n " )
114+ self ._client_sock .close ()
115+
81116 def update_poll (self ):
82117 """
83118 Call this method inside your main event loop to get the server
@@ -91,16 +126,22 @@ def update_poll(self):
91126 if (client and client .available ()):
92127 line = client .readline ()
93128 line = line .split (None , 2 )
94- method = line [0 ]
95- path = line [1 ]
129+ method = str ( line [0 ], "utf-8" )
130+ path = str ( line [1 ], "utf-8" )
96131 key = self ._get_listener_key (method , path )
97132 if key in self ._listeners :
98133 headers = parse_headers (client )
99134 body = client .read ()
100135 self ._listeners [key ](headers , body , client )
136+ elif method .lower () == "get" :
137+ client .read ()
138+ if path in self ._static_files :
139+ self .serve_file (path , dir = self ._static_dir )
140+ elif path == "/" and INDEX_HTML in self ._static_files :
141+ self .serve_file (INDEX_HTML , dir = self ._static_dir )
101142 else :
102143 # TODO: support optional custom 404 handler?
103- client .write (b"HTTP/1.1 404 NotFound\r \n " )
144+ self . _client_sock .write (b"HTTP/1.1 404 NotFound\r \n " )
104145 client .close ()
105146
106147
@@ -137,4 +178,16 @@ def client_available(self):
137178 return None
138179
139180 def _get_listener_key (self , method , path ): # pylint: disable=no-self-use
140- return "{0}|{1}" .format (str (method .lower (), 'utf-8' ), str (path , 'utf-8' ))
181+ return "{0}|{1}" .format (method .lower (), path )
182+
183+
184+ def _get_content_type (self , file ): # pylint: disable=no-self-use
185+ ext = file .split ('.' )[- 1 ]
186+ if ext in ("html" , "htm" ):
187+ return b"text/html"
188+ if ext == "js" :
189+ return b"application/javascript"
190+ if ext == "css" :
191+ return b"text/css"
192+ # TODO: test adding in support for image types as well
193+ return b"text/plain"
0 commit comments