Guide Framework basic WSGI web application framework that uses Middleware.
Features
auto description to status code
send data as soon as possible
send strings, bytes, lists(even bytes and strings mixed) or files directly
error catcher and error logger
works with many WSGI compatible servers
you should use HTTP version 1.1
Server with your WSGI framework for some clients like Firefox browser
Copy from wsocket import WSocketApp, WebSocketError, logger, run
from time import sleep
logger.setLevel(10) # for debugging
app = WSocketApp()
# app = WSocketApp(protocol="WAMP")
@app.route("/")
def handle_websocket(environ, start_response):
wsock = environ.get("wsgi.websocket")
if not wsock:
start_response()
return "Hello World!"
while True:
try:
message = wsock.receive()
if message != None:
print("participator : " + message)
wsock.send("you : "+message)
sleep(2)
wsock.send("you : "+message)
except WebSocketError:
break
run(app)
see Websocket for more info on wsgi.websocket
variable in WSGI environment dictionary.
WSocketApp
class WSocketApp(app=None, protocol=None)
Class variables
GUID
- unique ID to generate websocket accept key
SUPPORTED_VERSIONS
- 13, 8 or 7
routes
- dictionary for route handlers
websocket_class
- "wsgi.websocket"
in WSGI Environ
Methods
not_found(self, environ, start_response)
- handle 404 NOT FOUND
error
route(self, r)
- register routes
Routes
WSocket uses simple routes engine. How it works?
URL - http://localhost:8080/hello/world?user=Ksengine&pass=1234
divided into parts(by Server)
only path is used to find routes
walk through routes dictionary
if "/hello/world"
path found, trigger route handler
Copy @app.route("/hello/world")
else, if some route string ends with "*" and path starts with that string trigger route handler
Copy @app.route("/hello/world")
Status and Headers
call start_response
to send status code and headers. if you returns without calling it. It will send 200 OK
status and some basic headers to client. if start_response
is called without argsuments, it will send 200 OK
status and some basic headers to client.
start_response
has two arguments
status - status code as int(eg:-200) or str(eg:- "200 OK" or "200"). If status description(eg:-"OK") not supplied, it will find it.
headers - HTTP headers. can passed as,
list of tuples
Copy [("header1 name", "header1 value"),
("header2 name", "header2 value") ]
dictionary
Copy {"header1 name": "header1 value",
"header2 name": "header2 value"}
status code examples:-
Copy start_response() # start_response("200 OK",[])
Copy start_response(200) # start_response("200 OK",[])
Copy start_response("200") # start_response("200 OK",[])
Copy start_response("200 OK") # start_response("200 OK",[])
send headers examples:-
list of tuples
Copy start_response("200 OK",[
("header1 name", "header1 value"),
("header2 name", "header2 value")
])
dictionary
Copy start_response("200 OK",{
"header1 name": "header1 value",
"header2 name": "header2 value"
})
Send data
You can send following data types
str
- string, text
Copy def sender(environ, start_response)
start_response()
# ...some code here
return "Hello World!"
bytes
- binary
Copy def sender(environ, start_response)
start_response()
# ...some code here
return b"Hello World!" # b"" is binary string
Copy def sender(environ, start_response)
start_response()
# ...some code here
return "Hello World!".encode() # str.encode converts str to bytes
Copy def sender(environ, start_response)
start_response()
# ...some code here
return b"Hello World!" # open file as text file
files
- opened files
Copy def sender(environ, start_response)
start_response()
# ...some code here
return open("hello.txt")
Copy def sender(environ, start_response)
start_response()
# ...some code here
return open("hello.txt", "b") # "b" - open as binary file
file-like object
- streams(text, binary) like StringIO
or BytesIO
Copy try:
from io import StringIO
except ImportError:
from StringIO import StringIO
def sender(environ, start_response)
start_response()
# ...some code here
file_like = StringIO()
return file_like
Copy try:
from io import BytesIO
except ImportError:
from StringIO import BytesIO
def sender(environ, start_response)
start_response()
# ...some code here
file_like = BytesIO()
return file_like
iterables
- list
, tuple
, set
dict
generators
etc.
Copy def sender(environ, start_response)
start_response()
# ...some code here
return ["Hello ", b"World", "!".encode(), 2020] # list
Copy def sender(environ, start_response)
start_response()
# ...some code here
return ("Hello ", b"World", "!".encode(), 2020) # tuple
Copy def sender(environ, start_response)
start_response()
# ...some code here
return {"Hello ", b"World", "!".encode(), 2020} # set
Copy def sender(environ, start_response)
start_response()
# ...some code here
return {"Hello ":None, "World!":None} # dict
Copy import time
def sender(environ, start_response)
start_response()
# ...some code here
yield "Hello "
time.sleep(2)
yield b"World"
time.sleep(5)
yield "!".encode()
yield 2020 # generators
generators can send data one by one with time intervals. so it's like async Server
other -
Copy def sender(environ, start_response)
start_response()
# ...some code here
return 3.3 # float
Errors
example :-
Internal Server Error(500)
ZeroDivisionError :division by zero
Copy Traceback (most recent call last):
File "wsocket.py", line 881, in process_response
results = self.app(self.environ, self.start_response)
File "wsocket.py", line 1068, in wsgi
1/0
ZeroDivisionError: division by zero
report
report button starts reporting issue and logger will print error to python console