flesh out the python stuff a bit more.

This commit is contained in:
Joris Vink 2017-01-30 20:47:24 +01:00
parent 7bc8bb42e2
commit 3d3d705b98
5 changed files with 153 additions and 30 deletions

View File

@ -1,5 +1,9 @@
Kore python module example.
This application requires kore to be built with PYTHON=1.
It mixes native code (dso) with python code.
Run:
```
$ kore run

View File

@ -1,10 +1,11 @@
# python configuration
load ./python.so onload
# import both python modules.
python_import src/index.py onload
python_import src/websockets.py
#bind 127.0.0.1 8888 c_on_connect
bind 127.0.0.1 8888
tls_dhparam dh2048.pem
@ -25,21 +26,30 @@ domain * {
certfile cert/server.crt
certkey cert/server.key
# Mix page handlers between native and python.
static / page
static /c cpage
static /b minimal
static /json json_parse
static /state state_test
static /ws ws_connect
# Use the builtin asset_serve_* to serve frontend HTML.
static /wspage asset_serve_frontend_html
static /auth page auth
params get / {
#
# On the native page handler, use a python validator.
#
params get /c {
validate id v_p_id
}
params get /c {
#
# On the python page handler, use a native validator.
#
params get / {
validate id v_id
}
}

View File

@ -1,16 +1,50 @@
# Simplistic kore example
#
# Copyright (c) 2017 Joris Vink <joris@coders.se>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# This is a simple python module that can be loaded into Kore.
# It demonstrates some basic abilities to deal with HTTP requests.
# Pull in the kore stuff.
import kore
# Pull in python JSON parsing.
import json
#
# A validator that the configuration for this application uses to determine
# if a request fulfills the requirements to pass an authentication block.
#
# See the configuration for more.
#
def python_auth(req, data):
# print("python auth called %s" % data)
kore.log(kore.LOG_NOTICE, "python auth called %s" % data)
return kore.RESULT_OK
#
# Define a validator that kore can use via the configuration to validate
# something before allowing access to it.
#
def python_validator(req, data):
print("python validator called %s" % data)
kore.log(kore.LOG_NOTICE, "python validator called %s" % data)
return kore.RESULT_OK
#
# This function is called when our python module is loaded/unloaded.
# The action param is kore.MODULE_LOAD or kore.MODULE_UNLOAD respectively.
#
def onload(action):
kore.log(kore.LOG_INFO, "FOOBAR python onload called with %d" % action)
return kore.RESULT_OK
@ -21,22 +55,33 @@ def kore_onload():
def kore_preload():
print("kore_preload called")
#
# Test page handler that displays some debug information as well as
# fetches the "xframe" header from the request and logs it if present.
#
# If the request is a POST then we read the body up to 1024 bytes in
# one go and display the result and bytes read in the log.
#
# If it's a GET request attempts to find the "id" argument and presents
# it to the user.
#
def page(req):
print("%s path is %s - host is %s" % (req, req.path, req.host))
print("connection is %s" % req.connection)
kore.log(kore.LOG_INFO,
"%s path is %s - host is %s" % (req, req.path, req.host))
kore.log(kore.LOG_INFO, "connection is %s" % req.connection)
xframe = req.request_header("xframe")
if xframe != None:
print("xframe header present %s" % xframe)
kore.log(kore.LOG_INFO, "xframe header present: '%s'" % xframe)
if req.method == kore.METHOD_POST:
try:
length, body = req.body_read(1024)
print("POST and got %d bytes! (%s)" %
kore.log(kore.LOG_INFO, "POST and got %d bytes! (%s)" %
(length, body.decode("utf-8")))
except RuntimeError as r:
print("oops runtime error %s" % r)
kore.log(kore.LOG_INFO, "oops runtime error %s" % r)
req.response(500, b'')
except:
print("oops other error")
kore.log(kore.LOG_INFO, "oops other error")
req.response(500, b'')
else:
req.response_header("content-type", "text/plain")
@ -45,35 +90,43 @@ def page(req):
req.populate_get()
id = req.argument("id")
if id != None:
print("got id of %s" % id)
kore.log(kore.LOG_INFO, "got id of %s" % id)
req.response_header("content-type", "text/plain")
req.response(200, "hello 1234".encode("utf-8"))
return kore.RESULT_OK
#
# Handler that parses the incoming body as JSON and dumps out some things.
#
def json_parse(req):
if req.method != kore.METHOD_PUT:
req.response(400, b'')
return kore.RESULT_OK
data = json.loads(req.body)
print("loaded json %s" % data)
kore.log(kore.LOG_INFO, "loaded json %s" % data)
if data["hello"] == 123:
print("hello is 123!")
kore.log(kore.LOG_INFO, "hello is 123!")
req.response(200, "ok".encode("utf-8"))
return kore.RESULT_OK
#
# Handler that stores some python state in req.state that it reuses
# once the handler is called again by the event loop (after having
# returned RESULT_RETRY to the event loop).
#
def state_test(req):
# If we don't have a state this is the first time we're called.
if req.state is None:
print("state_test: first time")
kore.log(kore.LOG_INFO, "state_test: first time")
req.state = "hello world"
# Tell Kore to call us again next event loop.
return kore.RESULT_RETRY
# We have been called before.
print("state_test: second time, with %s" % req.state)
kore.log(kore.LOG_INFO, "state_test: second time, with %s" % req.state)
req.response(200, req.state.encode("utf-8"))
# We *MUST* reset state back to None before returning RESULT_OK
@ -81,6 +134,9 @@ def state_test(req):
return kore.RESULT_OK
#
# Small handler, returns 200 OK.
#
def minimal(req):
req.response(200, b'')
return kore.RESULT_OK

View File

@ -1,28 +1,41 @@
/*
* Copyright (c) 2017 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <kore/kore.h>
#include <kore/http.h>
/*
* Just some examples of things that can be mixed with python modules.
*/
int onload(int);
int cpage(struct http_request *);
void c_on_connect(struct connection *);
int c_validator(struct http_request *, void *);
int
c_validator(struct http_request *req, void *data)
{
printf("c_validator called!\n");
kore_log(LOG_NOTICE, "c_validator(): called!");
return (KORE_RESULT_OK);
}
void
c_on_connect(struct connection *c)
{
printf("c_on_connect!\n");
}
int
onload(int action)
{
printf("C onload called!\n");
kore_log(LOG_NOTICE, "onload called from native");
return (KORE_RESULT_OK);
}
@ -30,9 +43,7 @@ int
cpage(struct http_request *req)
{
http_populate_get(req);
//printf("cpage called\n");
http_response(req, 200, NULL, 0);
http_response(req, 200, "native", 6);
return (KORE_RESULT_OK);
}

View File

@ -1,16 +1,58 @@
# using kore websockets via python.
#
# Copyright (c) 2017 Joris Vink <joris@coders.se>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# Using kore websockets via python.
import kore
#
# Our connection callback, gets called for each new websocket connection.
#
def onconnect(c):
kore.log(kore.LOG_INFO, "%s: py connected" % c)
#
# Each websocket arriving on a connection triggers this function.
#
# It receives the connection object, the opcode (TEXT/BINARY) and the
# actual data received.
#
# In this example we use the websocket_broadcast() method from kore to
# simply relay the message to all other connection clients.
#
def onmessage(c, op, data):
kore.websocket_broadcast(c, op, data, kore.WEBSOCKET_BROADCAST_GLOBAL)
#
# Called for every connection that goes byebye.
#
def ondisconnect(c):
kore.log(kore.LOG_INFO, "%s: py disconnecting" % c)
#
# The /ws connection handler. It establishes the websocket connection
# after a request was made for it.
#
# Note that the websocket_handshake() method for the request takes 3
# parameters which are the connection callback, message callback and
# disconnect callback.
#
# These are given as strings to Kore which will then resolve them
# in all modules which means you can give native callbacks here as well.
#
def ws_connect(req):
try:
req.websocket_handshake("onconnect", "onmessage", "ondisconnect")