31
31
"""
32
32
# pylint: disable=no-name-in-module
33
33
34
+ import os
34
35
from micropython import const
35
36
import adafruit_esp32spi .adafruit_esp32spi_socket as socket
36
37
from adafruit_esp32spi .adafruit_esp32spi_requests import parse_headers
@@ -43,6 +44,7 @@ def set_interface(iface):
43
44
socket .set_interface (iface )
44
45
45
46
NO_SOCK_AVAIL = const (255 )
47
+ INDEX_HTML = "/index.html"
46
48
47
49
48
50
# pylint: disable=unused-argument, redefined-builtin, invalid-name
@@ -54,6 +56,8 @@ def __init__(self, port=80, debug=False):
54
56
self ._client_sock = socket .socket (socknum = NO_SOCK_AVAIL )
55
57
self ._debug = debug
56
58
self ._listeners = {}
59
+ self ._static_dir = None
60
+ self ._static_files = []
57
61
58
62
59
63
def start (self ):
@@ -72,12 +76,43 @@ def on(self, method, path, request_handler):
72
76
73
77
request_handler should accept the following args:
74
78
(Dict headers, bytes body, Socket client)
79
+
75
80
:param str method: the method of the HTTP request
76
81
:param str path: the path of the HTTP request
77
82
:param func request_handler: the function to call
78
83
"""
79
84
self ._listeners [self ._get_listener_key (method , path )] = request_handler
80
85
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
+
81
116
def update_poll (self ):
82
117
"""
83
118
Call this method inside your main event loop to get the server
@@ -91,16 +126,22 @@ def update_poll(self):
91
126
if (client and client .available ()):
92
127
line = client .readline ()
93
128
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" )
96
131
key = self ._get_listener_key (method , path )
97
132
if key in self ._listeners :
98
133
headers = parse_headers (client )
99
134
body = client .read ()
100
135
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 )
101
142
else :
102
143
# 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 " )
104
145
client .close ()
105
146
106
147
@@ -137,4 +178,16 @@ def client_available(self):
137
178
return None
138
179
139
180
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