forked from nat/sludge
add logging, update readme
This commit is contained in:
parent
6175fafd20
commit
bdc96b5700
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
config.yaml
|
||||
log
|
||||
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
|
62
README.md
62
README.md
@ -1,3 +1,63 @@
|
||||
# Sludge: webthing for natalieee.net
|
||||
# sludge: webthing for natalieee.net
|
||||
it rhymes with kludge.
|
||||
|
||||
## config
|
||||
```yaml
|
||||
ssl-key: ./key.pem
|
||||
ssl-cert: ./cert.pem
|
||||
http-port: 5000
|
||||
https-port: # 5001
|
||||
file-dir: 'site'
|
||||
```
|
||||
ssl-{cert,key} are self explanatory.
|
||||
if the value of https? port is commented or not present, it will not run the https? server on that port.
|
||||
file-dir is where the files for the site can be found.
|
||||
the above config is the config for the local version of my website, which is used for testing.
|
||||
it runs an http server on 5000, but no https server.
|
||||
|
||||
## serving files
|
||||
- src/lib/router.py has the routing config for my website in it. it is easy to modify to your usecase.
|
||||
- src/lib/patchers.py has the patching config for my website in it. it is also easy to modify.
|
||||
|
||||
## dynamic content
|
||||
### embedded bash scripting
|
||||
sludge has support for inline bash inside of html documents.<br>
|
||||
ex:
|
||||
```html
|
||||
<p>lorem ipsum $[echo foo]</p>
|
||||
```
|
||||
would resolve to
|
||||
```html
|
||||
<p>lorem ipsum foo</p>
|
||||
```
|
||||
|
||||
### variables in html
|
||||
in addition to the above, you can have variables embedded in html.
|
||||
```html
|
||||
<p>lorem ipsum {aoeu}</p>
|
||||
```
|
||||
would normally resolve to
|
||||
```html
|
||||
<p>lorem ipsum {aoeu}</p>
|
||||
```
|
||||
however, if we assume that this text is in a file `foo.html`, then we can serve that file such that
|
||||
```py
|
||||
parse_file('./foo.html', dict(aoeu='foo'))
|
||||
```
|
||||
in which case it would resolve to
|
||||
```html
|
||||
<p>lorem ipsum foo</p>
|
||||
```
|
||||
<br>
|
||||
in practice, this may be seen here:
|
||||
```py
|
||||
Route(
|
||||
lambda path: os.path.isdir('.' + path.path),
|
||||
[Method.GET],
|
||||
lambda request, *_: Response(
|
||||
ResponseCode.OK,
|
||||
{'Content-Type': 'text/html'},
|
||||
parse_file('./dir_index.html', dict(path='.' + request.path.path)).encode('utf-8')
|
||||
)
|
||||
)
|
||||
```
|
||||
|
@ -45,8 +45,7 @@ def remove_html_tags(input_string: str) -> str:
|
||||
|
||||
def error_page(code: int) -> Response:
|
||||
type = ResponseCode(code)
|
||||
print('error page called')
|
||||
aoeu= Response(
|
||||
return Response(
|
||||
type,
|
||||
{'Content-Type': 'text/html'},
|
||||
parse(f'''
|
||||
@ -61,8 +60,6 @@ def error_page(code: int) -> Response:
|
||||
</html>
|
||||
''').encode('utf-8')
|
||||
)
|
||||
print(aoeu)
|
||||
return aoeu
|
||||
|
||||
def page(title, body):
|
||||
return parse("""
|
||||
|
22
src/lib/logger.py
Normal file
22
src/lib/logger.py
Normal file
@ -0,0 +1,22 @@
|
||||
import logging
|
||||
|
||||
log = logging.getLogger()
|
||||
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s | %(name)s | %(threadName)s | %(levelname)s: %(message)s')
|
||||
|
||||
file_logger = logging.FileHandler('log')
|
||||
stream_logger = logging.StreamHandler()
|
||||
|
||||
file_logger.setLevel(logging.DEBUG)
|
||||
stream_logger.setLevel(logging.INFO)
|
||||
|
||||
file_logger.setFormatter(formatter)
|
||||
stream_logger.setFormatter(formatter)
|
||||
|
||||
log.addHandler(file_logger)
|
||||
log.addHandler(stream_logger)
|
||||
|
||||
log.info('log initialized')
|
||||
|
@ -86,5 +86,10 @@ patchers: List[Patcher] = [
|
||||
response.code,
|
||||
response.headers,
|
||||
uwuify(response.body).encode('utf-8')
|
||||
) if 'text/html' in response.headers.values() and is_subdict({'uwu': 'true'}, request.path.params) else response
|
||||
) if 'text/html' in response.headers.values() and is_subdict({'uwu': 'true'}, request.path.params) else response,
|
||||
lambda response, request: Response(
|
||||
response.code,
|
||||
response.headers,
|
||||
re.sub(r'sludge', lambda match: 'sludge' + ' (/slʌd͡ʒ/)' if random.randint(0, 5) < 1 else 'sludge', response.body.decode('utf-8')).encode('utf-8')
|
||||
) if 'text/html' in response.headers.values() else response
|
||||
]
|
||||
|
@ -5,6 +5,7 @@ from .path import Path
|
||||
from .headers import Headers
|
||||
from .body import Body
|
||||
from .router import routes
|
||||
from .logger import log
|
||||
|
||||
@dataclass
|
||||
class Request:
|
||||
@ -43,12 +44,13 @@ class Request:
|
||||
body_start = request_str.find('\r\n\r\n') + 4
|
||||
body = Body(request_bytes[body_start:], headers.get('Content-Type') or 'text/plain')
|
||||
|
||||
log.info(f'received request for {path.path} from {headers.get('X-Real-IP')}')
|
||||
return cls(method, path, version, headers, body)
|
||||
|
||||
def match(self):
|
||||
for route in routes:
|
||||
if route.matches(self):
|
||||
print(route)
|
||||
if route.matches(self):
|
||||
log.debug(f'matched {self} with {route}')
|
||||
return route
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -1,6 +1,7 @@
|
||||
from socket import socket
|
||||
from typing import Dict
|
||||
from .responsecodes import ResponseCode
|
||||
from .logger import log
|
||||
|
||||
class Response:
|
||||
def __init__(self, code: ResponseCode, headers: Dict[str, str], body: bytes):
|
||||
@ -16,6 +17,9 @@ class Response:
|
||||
)
|
||||
|
||||
def send(self, client: socket) -> None:
|
||||
print(self)
|
||||
log.debug(f'sending {self} to {client}')
|
||||
client.sendall(self.build_response())
|
||||
client.close()
|
||||
|
||||
def __repr__(self):
|
||||
return f'Response(code={self.code}, headers={self.headers}, body={self.body[:256]})'
|
||||
|
@ -8,7 +8,9 @@ from .response import Response
|
||||
from .responsecodes import ResponseCode
|
||||
from .content import *
|
||||
from .patchers import patchers
|
||||
from .logger import log
|
||||
import os
|
||||
import traceback
|
||||
|
||||
@dataclass
|
||||
class Route:
|
||||
@ -28,7 +30,7 @@ class Route:
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
log.error(tracebark.format_exc)
|
||||
return error_page(500)
|
||||
|
||||
def matches(self, request: 'Request') -> bool:
|
||||
@ -46,7 +48,6 @@ routes = [
|
||||
[
|
||||
(lambda form_data: (
|
||||
(lambda time: (
|
||||
print('\n\nFORM DATA!!!!',form_data,request, '\n\n'),
|
||||
f:=open(f'./files/posts-to-homepage/post_{time}.txt', 'w'),
|
||||
f.write(f"<i style='font-family: MapleMonoItalic'>{form_data['name']}</i>@{time}<br>{form_data['text']}<br><br>"),
|
||||
f.close()
|
||||
@ -60,7 +61,7 @@ routes = [
|
||||
parse_file('./home.html').encode('utf-8')
|
||||
][1]
|
||||
))
|
||||
) if len(request.body.data) > 0 or request.method != Method.POST else error_page(ResponseCode.BAD_REQUEST)
|
||||
) if len(request.body.data) > 0 or request.method != Method.POST else error_page(400)
|
||||
),
|
||||
Route(
|
||||
lambda path: os.path.isdir('.' + path.path),
|
||||
|
@ -1,21 +1,30 @@
|
||||
import socket
|
||||
import threading
|
||||
import traceback
|
||||
from typing import Callable
|
||||
|
||||
from .logger import log
|
||||
|
||||
def serve(address: str, port: int, callback: Callable, wrapper: Callable[[socket.socket], socket.socket] = lambda s: s) -> None:
|
||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
while True:
|
||||
try:
|
||||
server_socket.bind((address, port))
|
||||
server_socket.listen(1)
|
||||
server_socket = wrapper(server_socket)
|
||||
log.info(f'server started on {port}')
|
||||
try:
|
||||
server_socket.bind((address, port))
|
||||
server_socket.listen(1)
|
||||
server_socket = wrapper(server_socket)
|
||||
|
||||
while True:
|
||||
while True:
|
||||
try:
|
||||
conn, addr = server_socket.accept()
|
||||
client_connection = threading.Thread(target=callback, args=(conn, addr))
|
||||
client_connection.start()
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
finally: server_socket.close()
|
||||
except Exception:
|
||||
log.warn(traceback.format_exc())
|
||||
|
||||
except:
|
||||
log.critical(traceback.format_exc())
|
||||
|
||||
finally:
|
||||
server_socket.close()
|
||||
log.info(f'server on {port} shut down')
|
||||
|
@ -1,4 +1,5 @@
|
||||
from lib import Request, serve
|
||||
from lib.logger import log
|
||||
from typing import Tuple
|
||||
import threading
|
||||
import socket
|
||||
@ -16,7 +17,6 @@ def handle_client(client: socket.socket, addr: Tuple[str, int]) -> None:
|
||||
|
||||
while (data := client.recv(1024)):
|
||||
request += data
|
||||
print(len(data), data)
|
||||
|
||||
if len(data) < 1024: break
|
||||
|
||||
@ -25,6 +25,8 @@ def handle_client(client: socket.socket, addr: Tuple[str, int]) -> None:
|
||||
.execute(request, client, addr) \
|
||||
.send(client)
|
||||
|
||||
log.info('destroy thread')
|
||||
|
||||
def main() -> None:
|
||||
http_thread = threading.Thread(name='http', target=serve, args=('0.0.0.0', config['http-port'], handle_client))
|
||||
https_thread = threading.Thread(name='https', target=serve, args=('0.0.0.0', config['https-port'], handle_client), kwargs=dict(wrapper=lambda socket: [
|
||||
|
Loading…
Reference in New Issue
Block a user