commit 3d3d705b985eda8499146e1533e0ea7862438961
parent 7bc8bb42e21391a7da15f65bed8bcdd5249d5a36
Author: Joris Vink <joris@coders.se>
Date: Mon, 30 Jan 2017 20:47:24 +0100
flesh out the python stuff a bit more.
Diffstat:
5 files changed, 154 insertions(+), 31 deletions(-)
diff --git a/examples/python/README.md b/examples/python/README.md
@@ -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
diff --git a/examples/python/conf/python.conf b/examples/python/conf/python.conf
@@ -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
}
}
diff --git a/examples/python/src/index.py b/examples/python/src/index.py
@@ -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
diff --git a/examples/python/src/python.c b/examples/python/src/python.c
@@ -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);
}
diff --git a/examples/python/src/websockets.py b/examples/python/src/websockets.py
@@ -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")