Changed treehug again
This commit is contained in:
parent
5f30b430ff
commit
cc472c0df4
136
src/treehug/frmWrk/.gitignore
vendored
136
src/treehug/frmWrk/.gitignore
vendored
|
@ -1,136 +0,0 @@
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
clearLogs.py
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
test.py
|
|
||||||
test/
|
|
||||||
|
|
||||||
# website/
|
|
||||||
.vscode/
|
|
||||||
log.txt
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
|
@ -1,62 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
[Installation](#installing)
|
|
||||||
|
|
||||||
[Quickstart](#usage)
|
|
||||||
|
|
||||||
[Documentation](#documentation)
|
|
||||||
|
|
||||||
# Installing
|
|
||||||
|
|
||||||
Open terminal in project folder.
|
|
||||||
Run:
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/vanten-s/frmWrk frmWrk
|
|
||||||
```
|
|
||||||
|
|
||||||
Done. Look at usage for quickstart.
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
With a index.html in the working directory this will make host a website at 127.0.0.1
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Example for website
|
|
||||||
|
|
||||||
import frmWrk.website as frw
|
|
||||||
|
|
||||||
# Start the server on 127.0.0.1:80 with parent folder as root directory
|
|
||||||
website = frw.WebServer("127.0.0.1", 80, "./")
|
|
||||||
website.start()
|
|
||||||
|
|
||||||
# Close the server when we get input
|
|
||||||
input()
|
|
||||||
website.close()
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Import everything
|
|
||||||
|
|
||||||
import frmWrk
|
|
||||||
import time
|
|
||||||
|
|
||||||
# Create the webserver. Directory is where the server should look for files
|
|
||||||
website = frmWrk.website.WebServer(ip, port, directory)
|
|
||||||
|
|
||||||
# Run the server
|
|
||||||
website.start()
|
|
||||||
|
|
||||||
# Wait 10 seconds and close the server
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
website.close()
|
|
||||||
```
|
|
||||||
|
|
||||||
frmWrk will replace substrings in the format of {ip:port:prompt} by connecting to (ip, port) and sending "{promt} {path}" where path is the URL that the user is on. Then they replace the whole substring with the response (max 1024 bytes).
|
|
||||||
|
|
||||||
frmWrk.databases should not be used.
|
|
||||||
It Can be used but please dont use it.
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
import frmWrk.website
|
|
||||||
import frmWrk.decorators
|
|
|
@ -1,192 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
import socket
|
|
||||||
import threading
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
enable_logging = True
|
|
||||||
log_file = "log.txt"
|
|
||||||
|
|
||||||
def log(func):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
if not enable_logging: return func(*args, **kwargs)
|
|
||||||
returnVal = func(*args, **kwargs)
|
|
||||||
with open(log_file, "a") as f:
|
|
||||||
try:
|
|
||||||
if len(returnVal) < 100:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')} and returned {returnVal}\n")
|
|
||||||
else:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}\n")
|
|
||||||
except TypeError as e:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}\n")
|
|
||||||
|
|
||||||
return returnVal
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def log_string(string):
|
|
||||||
if not enable_logging: return string
|
|
||||||
with open(log_file, "a") as f:
|
|
||||||
f.write(f"{string}\n")
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
databases = {}
|
|
||||||
__using_remote_access = False
|
|
||||||
|
|
||||||
"""
|
|
||||||
Usage:
|
|
||||||
CREATE <name> # Creates a new database
|
|
||||||
ADDATTRIBUTE <name> <attribute> # Adds an attribute to a database
|
|
||||||
ADD <name> <database> # Adds an entry to a database
|
|
||||||
LIST # Lists all databases
|
|
||||||
GET <entry> <database> <attribute> # Gets an entry from a database
|
|
||||||
SET <entry> <database> <attribute> <value> # Sets an attribute of an entry in a database
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def help():
|
|
||||||
return "Usage: CREATE <name> # Creates a new database\nADDATTRIBUTE <name> <attribute> # Adds an attribute to a database\nADD <name> <database> # Adds an entry to a database\nLIST # Lists all databases\nGET <entry> <database> # Gets an entry from a database\nSET <entry> <database> <attribute> <value> # Sets an attribute of an entry in a database"
|
|
||||||
|
|
||||||
|
|
||||||
class Database:
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
self.attributes = []
|
|
||||||
self.entrys = {}
|
|
||||||
databases[name] = self
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.name == other.name
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def addAttribute(self, attribute):
|
|
||||||
self.attributes.append(attribute)
|
|
||||||
for entry in self.entrys:
|
|
||||||
entry.__setAttribute(attribute)
|
|
||||||
|
|
||||||
def getAttribute(self, attribute):
|
|
||||||
return self.attributes[attribute]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Entry:
|
|
||||||
def __init__(self, name, parent):
|
|
||||||
self.name = name
|
|
||||||
self.parent = parent
|
|
||||||
self.attributes = {attr:None for attr in parent.attributes}
|
|
||||||
self.parent.entrys[name] = self
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.name == other.name
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.attributes.__str__()
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return self.name + " with " + self.attributes.__str__()
|
|
||||||
|
|
||||||
def __setAttribute(self, attribute):
|
|
||||||
self.attributes[attribute] = ""
|
|
||||||
|
|
||||||
def setAttribute(self, attribute, value):
|
|
||||||
if attribute in self.attributes.keys():
|
|
||||||
self.attributes[attribute] = value
|
|
||||||
else:
|
|
||||||
raise Exception("Attribute not found")
|
|
||||||
|
|
||||||
def getAttribute(self, attribute):
|
|
||||||
if attribute in self.attributes.keys():
|
|
||||||
return self.attributes[attribute]
|
|
||||||
else:
|
|
||||||
raise Exception("Attribute not found")
|
|
||||||
|
|
||||||
|
|
||||||
def executeInstruction(instruction):
|
|
||||||
tokens = instruction.split(" ")
|
|
||||||
log_string(f"Executing instruction: {instruction}")
|
|
||||||
if tokens[0] == "CREATE":
|
|
||||||
database = Database(tokens[1])
|
|
||||||
return database
|
|
||||||
|
|
||||||
elif tokens[0] == "ADDATTRIBUTE":
|
|
||||||
databases[tokens[1]].addAttribute(tokens[2])
|
|
||||||
|
|
||||||
elif tokens[0] == "ADD":
|
|
||||||
Entry(tokens[1], databases[tokens[2]])
|
|
||||||
|
|
||||||
elif tokens[0] == "LIST":
|
|
||||||
if len(databases) == 0:
|
|
||||||
return "No databases"
|
|
||||||
|
|
||||||
if len(tokens) == 2:
|
|
||||||
return databases[tokens[1]].entrys
|
|
||||||
|
|
||||||
if len(tokens) == 3:
|
|
||||||
return databases[tokens[1]].entrys[tokens[2]]
|
|
||||||
|
|
||||||
return databases
|
|
||||||
|
|
||||||
elif tokens[0] == "GET":
|
|
||||||
return databases[tokens[1]].entrys[tokens[2]].getAttribute(tokens[3]).__str__()
|
|
||||||
|
|
||||||
elif tokens[0] == "SET":
|
|
||||||
database = databases[tokens[1]].entrys[tokens[2]].setAttribute(tokens[3], tokens[4])
|
|
||||||
|
|
||||||
else:
|
|
||||||
print(instruction)
|
|
||||||
return "Invalid instruction"
|
|
||||||
|
|
||||||
return "Success"
|
|
||||||
|
|
||||||
def __enable_remote_access(ip, port):
|
|
||||||
HOST = ip # The server's hostname or IP address
|
|
||||||
PORT = port # The port used by the server
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.bind((HOST, PORT))
|
|
||||||
s.listen(1)
|
|
||||||
while True and __using_remote_access:
|
|
||||||
conn, addr = s.accept()
|
|
||||||
with conn:
|
|
||||||
print('Connected by', addr)
|
|
||||||
while True:
|
|
||||||
data = conn.recv(1024).decode()
|
|
||||||
|
|
||||||
firstLine = data.split("\n")[0]
|
|
||||||
instruction = " ".join(firstLine.split(" ")[1:-1])
|
|
||||||
|
|
||||||
conn.send(executeInstruction(instruction).encode())
|
|
||||||
if not data: break
|
|
||||||
|
|
||||||
|
|
||||||
print('Connection closed')
|
|
||||||
|
|
||||||
@log
|
|
||||||
def enable_remote_access(ip, port):
|
|
||||||
global __using_remote_access
|
|
||||||
__using_remote_access = True
|
|
||||||
t = threading.Thread(target=__enable_remote_access, args=(ip, port))
|
|
||||||
t.start()
|
|
||||||
return "Enabled remote access"
|
|
||||||
|
|
||||||
def disable_remote_access():
|
|
||||||
global __using_remote_access
|
|
||||||
__using_remote_access = False
|
|
||||||
return "Disabled remote access"
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
import datetime
|
|
||||||
|
|
||||||
enable_logging = True
|
|
||||||
log_file = "log.txt"
|
|
||||||
|
|
||||||
def log(func):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
if not enable_logging: return func(*args, **kwargs)
|
|
||||||
returnVal = func(*args, **kwargs)
|
|
||||||
with open(log_file, "a") as f:
|
|
||||||
try:
|
|
||||||
if len(returnVal) < 100:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')} and returned {returnVal}\n")
|
|
||||||
else:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}\n")
|
|
||||||
except TypeError as e:
|
|
||||||
f.write(f"{func.__name__} was called at {datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}\n")
|
|
||||||
|
|
||||||
return returnVal
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def log_string(string):
|
|
||||||
if not enable_logging: return string
|
|
||||||
with open(log_file, "a") as f:
|
|
||||||
f.write(f"{string}\n")
|
|
||||||
return string
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.7 KiB |
File diff suppressed because one or more lines are too long
|
@ -1,300 +0,0 @@
|
||||||
|
|
||||||
import socket
|
|
||||||
import threading
|
|
||||||
import datetime
|
|
||||||
import os
|
|
||||||
|
|
||||||
def boron (code: str, path: str) -> str:
|
|
||||||
total = []
|
|
||||||
none = []
|
|
||||||
|
|
||||||
while "{" in code and "}" in code:
|
|
||||||
startIndex = code.index("{")
|
|
||||||
endIndex = code.index("}")
|
|
||||||
try:
|
|
||||||
string = code[startIndex+1:endIndex]
|
|
||||||
ip = string.split(":")[0]
|
|
||||||
port = int(string.split(":")[1])
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
addr = (ip, port)
|
|
||||||
print(addr)
|
|
||||||
s.connect(addr)
|
|
||||||
s.send((string.split(":")[2] + " " + path).encode('utf-8'))
|
|
||||||
response = s.recv(1024).decode()
|
|
||||||
s.close()
|
|
||||||
code = code.replace("{" + string + "}", response)
|
|
||||||
print("{" + string + "}")
|
|
||||||
print(code)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
code = code.replace("{" + string + "}", string)
|
|
||||||
none.append(string)
|
|
||||||
print("{" + string + "}")
|
|
||||||
print(code)
|
|
||||||
|
|
||||||
for string in none:
|
|
||||||
code = code.replace(string, "{" + string + "}")
|
|
||||||
|
|
||||||
return code
|
|
||||||
|
|
||||||
|
|
||||||
enable_logging = True
|
|
||||||
log_file = "log.txt"
|
|
||||||
|
|
||||||
def log(func):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
if not enable_logging: return func(*args, **kwargs)
|
|
||||||
returnVal = func(*args, **kwargs)
|
|
||||||
try:
|
|
||||||
if len(returnVal) < 10:
|
|
||||||
log_string(f"[{datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}] {func.__name__} was called and returned {returnVal}\n")
|
|
||||||
else:
|
|
||||||
log_string(f"[{datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}] {func.__name__} was called\n")
|
|
||||||
except TypeError as e:
|
|
||||||
log_string(f"[{datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}] {func.__name__} was called\n")
|
|
||||||
|
|
||||||
return returnVal
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
def log_string(string):
|
|
||||||
global log_file, enable_logging
|
|
||||||
if not enable_logging: return
|
|
||||||
with open(log_file, "a") as f:
|
|
||||||
f.write(f"[{datetime.datetime.now().strftime('%m/%d/%Y, %H:%M:%S')}] {string}\n")
|
|
||||||
|
|
||||||
return string
|
|
||||||
|
|
||||||
AASCI_404_NOT_FOUND = """
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="author" content="">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>404 Not Found</h1>
|
|
||||||
<pre style="font-size: xx-large;">
|
|
||||||
_ _ ___ _ _ _ __ _
|
|
||||||
| || | / _ \| || | | | / _| | |
|
|
||||||
| || |_| | | | || |_ _ __ ___ | |_ | |_ ___ _ _ _ __ __| |
|
|
||||||
|__ _| | | |__ _| | '_ \ / _ \| __| | _/ _ \| | | | '_ \ / _` |
|
|
||||||
| | | |_| | | | | | | | (_) | |_ | || (_) | |_| | | | | (_| |
|
|
||||||
|_| \___/ |_| |_| |_|\___/ \__| |_| \___/ \__,_|_| |_|\__,_|</pre>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
content_type = {
|
|
||||||
'html': 'text/html; charset=\'utf-8\'',
|
|
||||||
'css': 'text/css; charset=\'utf-8\'',
|
|
||||||
'js': 'application/javascript; charset=\'utf-8\'',
|
|
||||||
'xml': 'application/xml; charset=\'utf-8\'',
|
|
||||||
'png': 'image/png',
|
|
||||||
'jpg': 'image/jpeg',
|
|
||||||
'jpeg': 'image/jpeg',
|
|
||||||
'gif': 'image/gif',
|
|
||||||
'ico': 'image/x-icon',
|
|
||||||
'svg': 'image/svg+xml',
|
|
||||||
'json': 'application/json; charset=\'utf-8\'',
|
|
||||||
'txt': 'text/plain; charset=\'utf-8\'',
|
|
||||||
'pdf': 'application/pdf',
|
|
||||||
'zip': 'application/zip',
|
|
||||||
'rar': 'application/x-rar-compressed',
|
|
||||||
'7z': 'application/x-7z-compressed',
|
|
||||||
'doc': 'application/msword',
|
|
||||||
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
||||||
'xls': 'application/vnd.ms-excel',
|
|
||||||
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
||||||
'ppt': 'application/vnd.ms-powerpoint',
|
|
||||||
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
||||||
'mp3': 'audio/mpeg',
|
|
||||||
'wav': 'audio/x-wav',
|
|
||||||
'mp4': 'video/mp4',
|
|
||||||
'm4v': 'video/x-m4v',
|
|
||||||
'mov': 'video/quicktime',
|
|
||||||
'wmv': 'video/x-ms-wmv',
|
|
||||||
'flv': 'video/x-flv',
|
|
||||||
'avi': 'video/x-msvideo',
|
|
||||||
'mkv': 'video/x-matroska',
|
|
||||||
'm3u': 'application/x-mpegURL',
|
|
||||||
'm3u8': 'application/vnd.apple.mpegurl',
|
|
||||||
'ts': 'video/MP2T',
|
|
||||||
'3gp': 'video/3gpp',
|
|
||||||
'3g2': 'video/3gpp2',
|
|
||||||
'mpd': 'video/vnd.mpeg.dash.mpd',
|
|
||||||
'mp4': 'video/mp4',
|
|
||||||
'webm': 'video/webm',
|
|
||||||
'ogv': 'video/ogg',
|
|
||||||
'ogm': 'video/ogg',
|
|
||||||
'ogg': 'video/ogg',
|
|
||||||
'ogx': 'application/ogg',
|
|
||||||
'oga': 'audio/ogg',
|
|
||||||
'spx': 'audio/ogg',
|
|
||||||
'opus': 'audio/ogg',
|
|
||||||
'flac': 'audio/flac'
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebServer:
|
|
||||||
def __init__(self, ip, port, directory, site404="/404.html", event_handler=None, overwrites={}, custom_router=None):
|
|
||||||
self.directory = directory
|
|
||||||
self.ip = ip
|
|
||||||
self.port = port
|
|
||||||
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.s.bind((ip,port))
|
|
||||||
self.threads = []
|
|
||||||
self.running = True
|
|
||||||
self.site404 = directory + "/404.html"
|
|
||||||
self.event_handler = event_handler
|
|
||||||
self.overwrites = overwrites
|
|
||||||
self.custom_router = custom_router
|
|
||||||
|
|
||||||
def __getContentType(self, path):
|
|
||||||
path = path.split(".")[-1]
|
|
||||||
if not path in content_type.keys():
|
|
||||||
return 'application/octet-stream'
|
|
||||||
|
|
||||||
return content_type[path]
|
|
||||||
|
|
||||||
def __getResponse(self, code, content_type, payload, custom_headers={}):
|
|
||||||
|
|
||||||
response = b'HTTP/1.1 ' + code.encode("utf-8") + b'\n'
|
|
||||||
response += b'Content-Type: ' + content_type.encode("utf-8") + b'\n'
|
|
||||||
response += b'Content-Length: ' + str(len(payload)).encode("utf-8") + b'\n'
|
|
||||||
response += b'server: frmWrk\n'
|
|
||||||
|
|
||||||
for header_key in custom_headers.keys():
|
|
||||||
response += header_key.encode("utf-8") + custom_headers[header_key].encode("utf-8") + b'\n'
|
|
||||||
|
|
||||||
response += b'\n'
|
|
||||||
|
|
||||||
response += payload + b'\n\n'
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def __get(self, path):
|
|
||||||
# Remove data after the ?
|
|
||||||
original = path
|
|
||||||
|
|
||||||
if ".." in path:
|
|
||||||
return self.__getResponse("404 Not Found", self.__getContentType("/index.html"), b'')
|
|
||||||
|
|
||||||
if "?" in path:
|
|
||||||
path = path[:path.index("?")]
|
|
||||||
|
|
||||||
if path == "/":
|
|
||||||
path = "/index.html"
|
|
||||||
|
|
||||||
if os.path.isdir(self.directory + path):
|
|
||||||
if path.endswith("/"):
|
|
||||||
path = path + "/index.html"
|
|
||||||
|
|
||||||
else:
|
|
||||||
return self.__getResponse("301 Moved Permanently", self.__getContentType("/index.html"), b'', custom_headers={"location: ": path + "/"})
|
|
||||||
|
|
||||||
if path in self.overwrites.keys():
|
|
||||||
return self.__getResponse("200 OK", self.__getContentType(path), self.overwrites[path](original).encode("utf-8"))
|
|
||||||
|
|
||||||
path = self.directory + path
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(path, "rb") as f:
|
|
||||||
content = f.read()
|
|
||||||
content_type = self.__getContentType(path)
|
|
||||||
# if content_type.startswith("text/html"):
|
|
||||||
# content = boron(content.decode('utf-8'), path).encode('utf-8')
|
|
||||||
|
|
||||||
return self.__getResponse("200 OK", content_type, content)
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
if "favicon.ico" in path:
|
|
||||||
with open(os.path.dirname(os.path.abspath(__file__)) + "/favicon.ico", "rb") as f:
|
|
||||||
content = f.read()
|
|
||||||
return self.__getResponse("200 OK", "image/x-icon", content)
|
|
||||||
|
|
||||||
try:
|
|
||||||
print(log_string("404 Not Found: " + path))
|
|
||||||
with open(self.site404, "rb") as f:
|
|
||||||
content = f.read()
|
|
||||||
content_type = self.__getContentType(self.site404)
|
|
||||||
return self.__getResponse("404 Not Found", content_type, content)
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
return self.__getResponse("404 Not Found", "text/html; charset=\"utf-8\"", AASCI_404_NOT_FOUND.encode("utf-8"))
|
|
||||||
|
|
||||||
|
|
||||||
def __handleRequest(self, request):
|
|
||||||
tokens = request.split(" ")
|
|
||||||
method = tokens[0]
|
|
||||||
path = tokens[1]
|
|
||||||
version = tokens[2]
|
|
||||||
|
|
||||||
if self.event_handler:
|
|
||||||
self.event_handler(method, (path))
|
|
||||||
|
|
||||||
if self.custom_router:
|
|
||||||
return self.custom_router(method, path, {})
|
|
||||||
|
|
||||||
if method == "GET":
|
|
||||||
return self.__get(path)
|
|
||||||
|
|
||||||
return "Only GET Requests Supported Yet Sorry."
|
|
||||||
|
|
||||||
def __handleClient(self, c: socket.socket, addr):
|
|
||||||
global running
|
|
||||||
while True and self.running:
|
|
||||||
data = c.recv(1024)
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
|
|
||||||
request = data.decode("utf-8")
|
|
||||||
response = self.__handleRequest(request)
|
|
||||||
|
|
||||||
log_string(f"{addr} asked for {request.split(' ')[1]}")
|
|
||||||
|
|
||||||
c.send(response)
|
|
||||||
|
|
||||||
c.close()
|
|
||||||
|
|
||||||
def __startServer(self):
|
|
||||||
global running, s
|
|
||||||
|
|
||||||
log_string("Server started on port " + str(self.port))
|
|
||||||
|
|
||||||
while self.running:
|
|
||||||
try:
|
|
||||||
c, addr = self.s.accept()
|
|
||||||
p = threading.Thread(target=self.__handleClient, args=(c, addr))
|
|
||||||
p.start()
|
|
||||||
self.threads.append(p)
|
|
||||||
except Exception as e:
|
|
||||||
log_string(e)
|
|
||||||
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
print("Starting server...")
|
|
||||||
self.s.listen(1)
|
|
||||||
t = threading.Thread(target=self.__startServer)
|
|
||||||
t.start()
|
|
||||||
self.main_process = t
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.running = False
|
|
||||||
print("Closing server...")
|
|
||||||
self.s.close()
|
|
||||||
|
|
||||||
for thread in self.threads:
|
|
||||||
thread.join()
|
|
||||||
|
|
||||||
self.main_process.join()
|
|
||||||
|
|
||||||
print("Server closed")
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
import frmWrk.website
|
|
||||||
|
|
||||||
webserver = frmWrk.website.WebServer("127.0.0.1", 4000, "./")
|
|
||||||
webserver.start()
|
|
|
@ -6,7 +6,7 @@
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
width: 30em;
|
width: 30em;
|
||||||
max-width: 30em;
|
max-width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search_bar {
|
.search_bar {
|
||||||
|
|
Loading…
Reference in a new issue