Go Down

Topic: Web Server Gateway Interface (WSGI) daemon for serial (Read 1 time) previous topic - next topic

ron_sutherland

Oct 01, 2018, 11:19 pm Last Edit: Oct 02, 2018, 09:07 am by ron_sutherland
This is early work so it is not really usable, but it may help show the idea. To be extra clear I have not used WSGI so this is new to me.

The Python code old code see GitHub

Code: [Select]
#!/usr/bin/env python3
# Web Server Gateway Interface (WSGI) daemon  
# use to serve request on a TCP/IP PORT for serial devices that use simple commands
# at CLI run with
# python3 WSGIdaemon.py
# killing it is a PITA, I just close the terminal, yep that needs some work.
# to try it open a brower with url: http://localhost:8000/?addr=0&cmd=id&q=true

# For info on WSGI see https://docs.python.org/3.7/library/wsgiref.html
# For info on CGI see https://docs.python.org/3.7/library/cgi.html

# The goal is to hold a seril link open while a web server runs pages, e.g. use the WSGI daemon to access the serial link.
# it takes commands from the CGI query string and turns them into the format I am using e.g. "/0/id?" or "/0/adc 3,4,5"

# I am using python3 so make sure the serial package is installed.
# sudo apt-get install python3-serial

import json
import serial
from time import sleep
from wsgiref.simple_server import make_server
from cgi import parse_qs, escape

# claim the serial link (e.g. it is a resourse that I will provide use of)
# hardwar serial on R-Pi is/dev/ttyAMA0
# FTDI and some other usb serial is /dev/ttyUSB0
# Arduino's ATmega16u2 is a modem... what? /dev/ttyACM0
device = "/dev/ttyUSB0"
sio = serial.Serial(device,38400, timeout=3)
print("claim serial link " + device + "\n")
# TBD only run one WSGI server with one thread

# A relatively simple WSGI application.
def simple_app(environ, start_response):
    
    # Returns a dictionary from CGI in which the values are lists, it is the easy way
    query_string = parse_qs(environ['QUERY_STRING'])
    #given URL: http://localhost:8000/?addr=0&cmd=id&q=true
    #the QUERY_STRING is: addr=0&cmd=id&q=true
    addr = query_string.get('addr', [''])[0] # Returns the first addr value
    cmd_base = query_string.get('cmd', [''])[0] # Returns the first cmd value
    q = query_string.get('q', [''])[0] # Returns the first q value
    # TBD thre are arguments to add, but this is a start

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]

    start_response(status, headers)

    #check for correctness of command
    if (addr == ''):
        addr = '0' # for default of /0/id?
    if ( (addr < '0') or (addr > '9') ):
        ret = [ ("ERR: addr must be in the range 0..9\n").encode('utf-8') +
                (b"ERR: bad query_string \"addr=" + addr.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret
    if (cmd_base == ''):
        cmd_base = "id" # default
    if ( not (cmd_base.isalpha()) ):
        ret = [ ("ERR: cmd must be a string that isalpha\n").encode('utf-8') +
                (b"ERR: bad query_string \"cmd=" + cmd_base.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret
    if (q == ''):
        q = 'true' # default needs a ? after the cmd_base
    if ( not ( (q == 'true') or (q == 'false')) ):
        ret = [ ("ERR: q must be true or false\n").encode('utf-8') +
                (b"ERR: bad query_string \"q=" + q.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret

    # note: if the command will not encode with ascii then use bytes e.g.
    # command = b"/"+bytes([192])+b"/id?"
    if (q == "true"):
        command =  "/"+addr+"/"+cmd_base+"?\n"
    else:
        command =  "/"+addr+"/"+cmd_base+"\n"
    sio.write(command.encode('utf-8')) # "/0/id?" is like the command I want to send on the serial link
    sio_echo_cmd = sio.readline().strip() # my serial device echo's the command
    sio_echo = sio.readline().strip() # and then outpus the JSON
    
    # format as bytestring suitable for transmission as HTTP response headers
    ret = [ (sio_echo_cmd + b"\n").decode().encode('utf-8') +
            (sio_echo + b"\n").decode().encode('utf-8') ]
    return ret


with make_server('', 8000, simple_app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()


The idea is to have the daemon make a command for the serial link, the commands I use resemble "/0/id?". The second character is an address on the serial bus (it is a multi-drop), the command is "id", and the "?" means it is a query (but everything has an echo and returns JSON so it's just adding overhead)

If I do end up using this I will likely keep the updates at

https://github.com/epccs/RPUpi/tree/master/WSGIdaemon
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

ron_sutherland

#1
Oct 02, 2018, 04:15 am Last Edit: Oct 10, 2018, 09:11 am by ron_sutherland Reason: old code
My serial commands can have up to five arguments so I wanted to add that. Also deal with a bad request a little better.

Python (old code see GitHub)

Code: [Select]
#!/usr/bin/env python3
# Web Server Gateway Interface (WSGI) daemon  
# use to serve request on a TCP/IP PORT for serial devices that use simple commands
# at CLI run with
# python3 WSGIdaemon.py
# killing it is a PITA, I just close the terminal, yep that needs some work.
# to try it open a brower with url: http://localhost:8000/?addr=0&cmd=id&q=true

# For info on WSGI see https://docs.python.org/3.7/library/wsgiref.html
# For info on CGI see https://docs.python.org/3.7/library/cgi.html

# The goal is to hold a seril link open while a web server runs pages, e.g. use the WSGI daemon to access the serial link.
# it takes commands from the CGI query string and turns them into the format I am using e.g. "/0/id?" or "/0/adc 3,4,5"

# I am using python3 so make sure the serial package is installed.
# sudo apt-get install python3-serial

import json
import serial
from time import sleep
from wsgiref.simple_server import make_server
from cgi import parse_qs, escape

# claim the serial link (e.g. it is a resourse that I will provide use of)
# hardwar serial on R-Pi is/dev/ttyAMA0
# FTDI and some other usb serial is /dev/ttyUSB0
# Arduino's ATmega16u2 is a modem... what? /dev/ttyACM0
device = "/dev/ttyUSB0"
sio = serial.Serial(device,38400, timeout=3)
print("claim serial link " + device)
# TBD only run one WSGI server with one thread

# A relatively simple WSGI application.
def simple_app(environ, start_response):
    
    # Returns a dictionary from CGI in which the values are lists, it is the easy way
    query_string = parse_qs(environ['QUERY_STRING'])
    #given URL: http://localhost:8000/?addr=0&cmd=id&q=true&arg1=1&arg2=2&arg3=3&arg4=4&arg5=5
    #the QUERY_STRING is: addr=0&cmd=id&q=true&arg1=1&arg2=2&arg3=3&arg4=4&arg5=5
    addr = query_string.get('addr', [''])[0] # Returns the first addr value
    cmd_base = query_string.get('cmd', [''])[0] # Returns the first cmd value
    q = query_string.get('q', [''])[0] # Returns the first q value
    arg1 = query_string.get('arg1', [''])[0] # Returns the first argument value
    arg2 = query_string.get('arg2', [''])[0] # Returns the first argument value
    arg3 = query_string.get('arg3', [''])[0] # Returns the first argument value
    arg4 = query_string.get('arg4', [''])[0] # Returns the first argument value
    arg5 = query_string.get('arg5', [''])[0] # Returns the first argument value

    #check for correctness of command
    if (addr == ''):
        addr = '0' # for default of /0/id?
    if ( not (addr.isalnum() and (len(addr) == 1) ) ):
        status = '400 Bad Request'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        ret = [ ("ERR: addr must be a string of len == 1 that isalnum\n").encode('utf-8') +
                (b"ERR: bad query_string \"addr=" + addr.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret
    if (cmd_base == ''):
        cmd_base = "id" # default
    if ( not (cmd_base.isalpha()) ):
        status = '400 Bad Request'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        ret = [ ("ERR: cmd must be a string that isalpha\n").encode('utf-8') +
                (b"ERR: bad query_string \"cmd=" + cmd_base.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret

    # start putting the command togather
    command =  "/"+addr+"/"+cmd_base

    if (q == ''):
        q = 'true' # default needs a ? after the cmd_base
    if ( not ( (q == 'true') or (q == 'false')) ):
        status = '400 Bad Request'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        ret = [ ("ERR: q must be true or false\n").encode('utf-8') +
                (b"ERR: bad query_string \"q=" + q.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret

    # baggage from looking at GPIB commands for too many years
    if (q == "true"):
        command =  command+"?"

    if (len(arg1) >= 1):
        if ( not (arg1.isalnum() ) ):
            status = '400 Bad Request'
            headers = [('Content-type', 'text/plain; charset=utf-8')]
            start_response(status, headers)
            ret = [ ("ERR: arg1 must be a string that isalnum\n").encode('utf-8') +
                    (b"ERR: bad query_string \"arg1=" + arg1.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
            return ret
        command =  command+" "+arg1
        
        #ignore arg2 if arg1 not given
        if (len(arg2) >= 1):
            if ( not (arg2.isalnum() ) ):
                status = '400 Bad Request'
                headers = [('Content-type', 'text/plain; charset=utf-8')]
                start_response(status, headers)
                ret = [ ("ERR: arg2 must be a string that isalnum\n").encode('utf-8') +
                        (b"ERR: bad query_string \"arg2=" + arg2.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
                return ret
            command =  command+","+arg2

            #ignore arg3 if arg2 not given
            if (len(arg3) >= 1):
                if ( not (arg3.isalnum() ) ):
                    status = '400 Bad Request'
                    headers = [('Content-type', 'text/plain; charset=utf-8')]
                    start_response(status, headers)
                    ret = [ ("ERR: arg3 must be a string that isalnum\n").encode('utf-8') +
                            (b"ERR: bad query_string \"arg3=" + arg3.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
                    return ret
                command =  command+","+arg3

                #ignore arg4 if arg3 not given
                if (len(arg4) >= 1):
                    if ( not (arg4.isalnum() ) ):
                        status = '400 Bad Request'
                        headers = [('Content-type', 'text/plain; charset=utf-8')]
                        start_response(status, headers)
                        ret = [ ("ERR: arg4 must be a string that isalnum\n").encode('utf-8') +
                                (b"ERR: bad query_string \"arg4=" + arg4.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
                        return ret
                    command =  command+","+arg4

                    #ignore arg5 if arg4 not given
                    if (len(arg5) >= 1):
                        if ( not (arg5.isalnum() ) ):
                            status = '400 Bad Request'
                            headers = [('Content-type', 'text/plain; charset=utf-8')]
                            start_response(status, headers)
                            ret = [ ("ERR: arg5 must be a string that isalnum\n").encode('utf-8') +
                                    (b"ERR: bad query_string \"arg5=" + arg5.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
                            return ret
                        command =  command+","+arg5

    sio.write((command+"\n").encode('utf-8')) # "/0/id?" is like the command I want to send on the serial link
    sio_echo_cmd = b""
    sio_echo_cmd = sio.readline().strip() # my serial device echo's the command
    if ( not (len(sio_echo_cmd) >= 1) ):
        status = '503 Service Unavailable'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        ret = [ ("ERR: device did not echo command\n").encode('utf-8') +
                (b"ERR: \command=\"" + command.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret
    sio_echo = sio.readline().strip() # and then outpus the JSON
    sio.write("\n".encode('utf-8')) # some commands keep outputing at timed intervals (e.g. /0/adc 1) this should stop them
    if ( not (len(sio_echo) >= 1) ):
        status = '503 Service Unavailable'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        ret = [ ("ERR: device found but ouput not returned\n").encode('utf-8') +
                (b"ERR: \"command=" + command.encode('utf-8') + b"\"\n").decode().encode('utf-8') ]
        return ret

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]

    start_response(status, headers)
    
    # format as bytestring suitable for transmission as HTTP response headers
    ret = [ (sio_echo_cmd + b"\n").decode().encode('utf-8') +
            (sio_echo + b"\n").decode().encode('utf-8') ]
    return ret


with make_server('', 8000, simple_app) as httpd:
    print("Serving on port 8000...")
    httpd.serve_forever()
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

ron_sutherland

#2
Oct 02, 2018, 08:51 am Last Edit: Oct 02, 2018, 08:54 am by ron_sutherland
Now for the mind-bending stuff... JS

Every time I have tried to make sense of JS, I have had to walk away.

When I spin up the WSGI daemon and look at it with a browser it works fine (it has crashed when the browser runs my client.html page since its JS is making the daemon into an angry little beast).

Anyway, the callback does not get called when this client.html page runs its "onTest" JS function but the daemon receives the request (port 8000), sends it to serial (/dev/ttyUSB0),  gets back the serial reply, and forwards that to the web browser (I have no clue what the callback port is on) where it is lost (Ubuntu 1804, Firefox). I wonder if the callback function itself goes out of scope?

html with JS

Code: [Select]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript">
    <!--
        var xhr=new XMLHttpRequest();
        // Use XMLHttpRequest (XHR) objects to interact with servers
        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
        // The Document Object Model (DOM) connects web pages to scripts or programming languages
        // https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
        
        xhr.responseType = 'text'
        
        function onTest( url )
        {
           // set the callback to use when the wsgi daemon finishes.
            xhr.onreadystatechange=function()
            {
                if (xhr.readyState==4 && xhr.status==200)
                {
                    document.getElementById( "wsgi_daemon" ).innerHTML = xhr.responseText;
                    document.getElementById( "wsgi_daemon" ).style.color = 'green'
                }
            }

            document.getElementById( "wsgi_daemon" ).style.color = 'red'
            xhr.open("GET", url, true);
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send( );
        }


    -->
    </script>
</head>

<body>

    <p id="wsgi_daemon"> abcdef </p>
    <a href="javascript:onTest('http://localhost:8000')">/0/id?</a> Click it to run the JS

</body>

</html>
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

Now for the mind-bending stuff... JS
When I do JS I always put the code into a separate .js file and for me that reduces it to an ordinary programming language.

Using a JS library such as jQuery also makes things a great deal easier. Your code can link to a copy of JQuery that is already hosted somewhere so your server does not have to serve it.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

I guess what I am trying to do is have the javascript running on the browser (e.g. the DOM) interact with the gateway daemon, so there is no web server or AJAX stuff going on.

This is the latest static HTML page with JS

Code: [Select]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript">
    <!--
var xhr = new XMLHttpRequest();
// Use XMLHttpRequest (XHR) objects to interact with servers
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
// The Document Object Model (DOM) connects web pages to scripts or programming languages
// https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
// what is this callback maddness
// http://recurial.com/programming/understanding-callback-functions-in-javascript/
xhr.responseType = 'text';

function onTest(url, callback) {
    "use strict";
    // set the callback to use when the wsgi daemon finishes.
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
            callback.call(xhr.responseText);
        }
    }

    xhr.open("GET", url, true);
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xhr.send();
}
    -->
    </script>
</head>

<body>

    <p id="wsgi_daemon"> abcdef </p>
     <button onclick="clickID()">/0/id?</button>
   
<script>
function clickID() {
    "use strict";
    // if it turns red that is DOM based evidance that call was done
    document.getElementById("wsgi_daemon").style.color = 'yellow';
    onTest('http://localhost:8000', function () {
        // pressent unamed callback gets this when it is called
        document.getElementById("wsgi_daemon").innerHTML = this;
        document.getElementById("wsgi_daemon").style.color = 'green';
    });
    document.getElementById("wsgi_daemon").style.color = 'red';
}
</script>
</body>

</html>


Turns out I wasted most of the day with formatting issues, javascript is way pickier than what I thought.

Links to the gateway daemon work, but that is Jurassic.

I thought the daemon was dead when it produced this on the terminal

Code: [Select]
127.0.0.1 - - [02/Oct/2018 20:05:26] "GET / HTTP/1.1" 200 99
127.0.0.1 - - [02/Oct/2018 20:05:26] "GET / HTTP/1.1" 200 99
127.0.0.1 - - [02/Oct/2018 20:05:27] "GET / HTTP/1.1" 200 99
127.0.0.1 - - [02/Oct/2018 20:05:58] "GET / HTTP/1.1" 200 99
127.0.0.1 - - [02/Oct/2018 20:05:59] "GET /favicon.ico HTTP/1.1" 200 99
127.0.0.1 - - [02/Oct/2018 20:05:59] "GET /favicon.ico HTTP/1.1" 200 99
Traceback (most recent call last):
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 138, in run
    self.finish_response()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 180, in finish_response
    self.write(data)
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 274, in write
    self.send_headers()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 332, in send_headers
    self.send_preamble()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 255, in send_preamble
    ('Date: %s\r\n' % format_date_time(time.time())).encode('iso-8859-1')
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 453, in _write
    result = self.stdout.write(data)
  File "/usr/lib/python3.6/socketserver.py", line 800, in write
    self._sock.sendall(b)
BrokenPipeError: [Errno 32] Broken pipe
127.0.0.1 - - [02/Oct/2018 20:05:59] "GET /favicon.ico HTTP/1.1" 500 59
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 59038)
Traceback (most recent call last):
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 138, in run
    self.finish_response()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 180, in finish_response
    self.write(data)
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 274, in write
    self.send_headers()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 332, in send_headers
    self.send_preamble()
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 255, in send_preamble
    ('Date: %s\r\n' % format_date_time(time.time())).encode('iso-8859-1')
  File "/usr/lib/python3.6/wsgiref/handlers.py", line 453, in _write
    result = self.stdout.write(data)
  File "/usr/lib/python3.6/socketserver.py", line 800, in write
    self._sock.sendall(b)
BrokenPipeError: [Errno 32] Broken pipe


but it turns out that it is complaining about the callback not receiving on the socket that was negotiated (e.g. the Broken Pipe). The daemon keeps on working with new connections, which was not what I expected.
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

Turns out I wasted most of the day with formatting issues, javascript is way pickier than what I thought.
It's no worse than C/C++. However unlike (say) Python JS fails silently.

Do you use the Firefox Inspector? It shows the JS errors.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

#6
Oct 03, 2018, 09:30 am Last Edit: Oct 03, 2018, 09:57 am by ron_sutherland
I think I see what the problem is now

Code: [Select]
Failed to load http://127.0.0.1:8000/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

Basically, the browser does not want to accept the connection because it does not know if it is safe, yet it will open it directly.

I ended up using Chrome to find the error, I did not know where to look on FireFox but I think it is probably the same sort of error. I can see where this needs some sort of authorization but...


Update: ouch

WSGI Access-Control Middleware

https://github.com/ianb/wsgi-access-control
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

I ended up using Chrome to find the error, I did not know where to look on FireFox but I think it is probably the same sort of error. I can see where this needs some sort of authorization but...
I presume Chrome has the same sort of developer tools as Firefox. In the Firefox menu click Web Developer / Inspector


I have had a quick look at your HTML file but I can't figure what you are trying to do.

I won't claim to be an expert of JS (I can just get my own stuff to work). I think this style
Code: [Select]
onTest('http://localhost:8000', function () {
is creating an anonymous function inside another function - which seems very advanced / complicated.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

I don't really understand callback's with C but I manage to do them somehow. I was looking at this

http://recurial.com/programming/understanding-callback-functions-in-javascript/

to try to get some insight into what made a JS callback work. I am betting that under the hood it is all done in C, and that article I linked was the only thing I found that seemed to line up with my C based hunches.

So that anonymous function in the clickID function is what gets called back when the onreaddystatechange anonymous function runs... yep it is a callback hell.  This is how all my JS adventures have gone, but I think I finally got the callback right this time.
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

When I find JS code with anonymous functions I like to re-write it as a regular named function to make it easier for my small brain.

If you can explain what you are trying to achieve I am sufficiently interested (to refresh my JS skills) to have a go at doing it myself.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

I was trying to: click on web element -> send to wsgi -> have wsgi convert to a serial command -> run Arduino/avr stuff -> reply to wsgi via serial -> forward that back to the browser via a previously agreed on port that the callback has been set up to receive and finally pass the reply to a DOM element. It's a contraption that seems to have run into a firewall.

I'm going to be out for a few days ... so will catch up when I can.
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

I was trying to: click on web element -> send to wsgi -> have wsgi convert to a serial command -> run Arduino/avr stuff -> reply to wsgi via serial -> forward that back to the browser
I have a couple of projects that do that using the Python Bottle web framework. And I am rather half-heartedly trying to write a minimal demo that I will post if I get it finished.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

#12
Oct 10, 2018, 09:17 am Last Edit: Oct 10, 2018, 09:17 am by ron_sutherland Reason: link image
Proof of Concept

CORS can be turned off in Firefox with the [cors-everywhere-firefox-addon] extension (which is for developer use)

[cors-everywhere-firefox-addon]: https://github.com/spenibus/cors-everywhere-firefox-addon



The code I was using is on Github

https://github.com/epccs/RPUpi/tree/77a96df1e246e182f3deb96309c4c75bef1883c2/WSGIdaemon
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Robin2

CORS can be turned off in Firefox with the [cors-everywhere-firefox-addon] extension (which is for developer use)
I am reminded of a line from the BBC "Yes Minister" TV series

"That is a brave decision, Minister"


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

ron_sutherland

haha, I lost the voters, but now I know my JS callback is working. I think I will try to add the WSGI Access-Control Middleware into the daemon next (that should make the little monster rabid), and then I won't have to turn off CORS.

https://github.com/ianb/wsgi-access-control
I use an R-Pi Zero on an RPUpi shield to have a tool-chain at the network edge.

Go Up