1. Euphoria CGI
- Posted by jmduro Apr 18, 2017
- 3944 views
Maybe this is a stupid question but as it is that easy to run Euphoria CGI programs is there any good reason not to build an HTML-based cross-platform IDE?
Here is the way I configured CGI on my Apache 2 server as I had difficulties to get CGI scripts to be run with official documentation.
cd /etc/apache2/ sudo vi conf-available/serve-cgi-bin.conf below folowing line: ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ add following lines: AddHandler exu-file .exu .ex Action exu-file /cgi-bin/runexu.cgi cd mods-enabled/ sudo ln -s ../mods-available/cgi.load sudo vi /usr/lib/cgi-bin/runexu.cgi #!/bin/sh #runexu.cgi - wrapper to run a euphoria program without the need for #! # Naturally, use the path to YOUR exu on your system /usr/local/euphoria-4.1.0-Linux-x86/bin/eui $PATH_TRANSLATED # END of runexu.cgi sudo chmod +x /usr/lib/cgi-bin/runexu.cgi sudo /etc/init.d/apache2 restart sudo ln -s myCgiFolder/myCgiSubfolder /var/www/html/myCgiSubfolder
Of course myCgiFolder, myCgiSubfolder and /usr/local/euphoria-4.1.0-Linux-x86/bin/eui have to be replaced by your own locations. Any Euphoria CGI script under myCgiFolder/myCgiSubfolder can be performed by accessing http://localhost/myCgiSubfolder/scriptName
Jean-Marc
2. Re: Euphoria CGI
- Posted by jmduro Apr 18, 2017
- 3942 views
I forgot to mention I'm running Apache2 on Debian 8 (Jessie) on either PC or Raspberry Pi.
3. Re: Euphoria CGI
- Posted by irv Apr 21, 2017
- 3852 views
Since with HTML5 you can do most things that you can do with a native GUI, it seems that a wrapper would be possible. Can you write a small demo as proof of concept? That would provide a starting point.
4. Re: Euphoria CGI
- Posted by jmduro Apr 22, 2017
- 3817 views
I will try. In the mean time, I think I discovered many reasons that make it difficult to build:
- widgets layout
- events
- one script per Web page
- parameters
Jean-Marc
5. Re: Euphoria CGI
- Posted by jmduro Apr 22, 2017
- 3988 views
Here is the basic principle of the web display server:
- The OpenEuphoria program acts as a client to send orders to the display server and as a server to listen for events.
- Each command (for example Create Button) is sent as a POST request to the Web display server on a dedicated port, let's say 10000.
- The server updates the page and sets the Refresh field in the header.
When the user submits a form, the client program does not know anything happened, so the server has to send a frame to inform the client program.
The problem is that a browser is needed to display pages. Either we need to write a browser in Euphoria or we need to drive a browser with Euphoria.
Second option needs:
- either a wrapper on the selenium2 library (www.seleniumhq.org)
- or to drive Firefox through MozREPL (addons.mozilla.org/fr/firefox/addon/mozrepl)
- or to drive geckodriver (github.com/mozilla/geckodriver) or chromedriver (sites.google.com/a/chromium.org/chromedriver) via WebDriver's wire protocol
I already tried different ways to drive a webbrowser via Euphoria but I have never been able to get it work as I needed. WebDriver's wire protocol seems to be the way to go but I was not able to communicate correctly with either chromedriver or geckodriver because of missing information in headers or whatever else.
Jean-Marc
6. Re: Euphoria CGI
- Posted by jmduro Apr 22, 2017
- 3796 views
"whatever else" is mostly JSON data used in the requests.
7. Re: Euphoria CGI
- Posted by jmduro Apr 23, 2017
- 3748 views
I have been able to communicate with chromedriver via libcurl and following code (needs Eu3 Standard Library or Eu4 Standard Library or my libcurl wrapper):
include std/filesys.e include std/error.e include lib/_curl_constants_.e include lib/_curl_.e include std/console.e object res atom curl crash_file(InitialDir & SLASH & "ex.err") res = curl_global_init(CURL_GLOBAL_DEFAULT) curl = curl_easy_init() if curl then curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP) curl_easy_setopt(curl, CURLOPT_PROXY, "") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEJAR, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9515/status") curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Connection: keep-alive") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Accept: application/json") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Content-Type: application/json; charset=UTF-8") res = curl_easy_perform_ex(curl) printf(1, "Status: %d\n", {res[1]}) printf(1, "Effective URL: %s\n", {res[2]}) analyze_object(res[3], "Headers", 1) analyze_object(res[4], "Content", 1) curl_easy_cleanup(curl) end if curl_global_cleanup() maybe_any_key()
Jean-Marc
8. Re: Euphoria CGI
- Posted by jmduro Apr 23, 2017
- 3779 views
I have been able to communicate with chromedriver via libcurl and following code (needs Eu3 Standard Library or Eu4 Standard Library or my libcurl wrapper):
include std/filesys.e include std/error.e include lib/_debug_.e include lib/_curl_constants_.e include lib/_curl_.e include std/console.e object res atom curl crash_file(InitialDir & SLASH & "ex.err") res = curl_global_init(CURL_GLOBAL_DEFAULT) curl = curl_easy_init() if curl then curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP) curl_easy_setopt(curl, CURLOPT_PROXY, "") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEJAR, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9515/status") curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Connection: keep-alive") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Accept: application/json") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Content-Type: application/json; charset=UTF-8") res = curl_easy_perform_ex(curl) printf(1, "Status: %d\n", {res[1]}) printf(1, "Effective URL: %s\n", {res[2]}) analyze_object(res[3], "Headers", 1) analyze_object(res[4], "Content", 1) curl_easy_cleanup(curl) end if curl_global_cleanup() maybe_any_key()
Jean-Marc
9. Re: Euphoria CGI
- Posted by jmduro Apr 23, 2017
- 3752 views
I got it work with WinHTTP also
include std/dll.e include std/machine.e include std/math.e include std/filesys.e include std/console.e include lib/_conv_.e include lib/_debug_.e include lib/_w32errors_.e include lib/_winhttp_constants_.e include lib/_winhttp_.e atom hSession, hConnect, hRequest hSession = NULL hConnect = NULL hRequest = NULL procedure free_pointers() integer bResults if hRequest != NULL then bResults = WinHttpCloseHandle(hRequest) end if if hConnect != NULL then bResults = WinHttpCloseHandle(hConnect) end if if hSession != NULL then bResults = WinHttpCloseHandle(hSession) end if end procedure object Buffer integer bResults, dwSize, status sequence UserAgent, cookies, url, headers, content atom addr f_debug = open(InitialDir & SLASH & "debug.log", "w") Buffer = "" bResults = FALSE UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0" -- Use WinHttpOpen to obtain a session handle. hSession = WinHttpOpen( UserAgent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0) if hSession = NULL then printf(1, "Error %d: %s\n", {error_code, error_msg}) abort(1) end if printf(1, "hSession = %d\n", {hSession}) -- Specify an HTTP server. -- WinHTTP is Unicode only hConnect = WinHttpConnect( hSession, "127.0.0.1", 9515) if hConnect = NULL then printf(1, "Error %d: %s\n", {error_code, error_msg}) abort(1) end if printf(1, "hConnect = %d\n", {hConnect}) -- Create an HTTP request handle. hRequest = WinHttpOpenRequest( hConnect, "GET", "/status", NULL, WINHTTP_NO_REFERER, {WINHTTP_DEFAULT_ACCEPT_TYPES}, NULL) if hRequest = NULL then printf(1, "Error %d: %s\n", {error_code, error_msg}) abort(1) end if printf(1, "hRequest = %d\n", {hRequest}) -- Send a request. bResults = WinHttpSendRequest( hRequest, "Accept: application/json\r\nContent-Type: application/json; charset=UTF-8\r\n", NULL, 0) if bResults = NULL then printf(1, "Error %d: %s\n", {error_code, error_msg}) abort(1) end if printf(1, "bResults = %d\n", {bResults}) -- End the request. bResults = WinHttpReceiveResponse( hRequest, NULL) if bResults = NULL then printf(1, "Error %d: %s\n", {error_code, error_msg}) abort(1) end if printf(1, "bResults = %d\n", {bResults}) -- Retrieve the header. Buffer = WinHttpQueryHeaders( hRequest ) -- Print the header contents. if sequence(Buffer) then printf(1, "Header contents: \n%s", {Buffer}) cookies = WinHttpExtractCookies(Buffer, 1) analyze_object(cookies, "cookies") cookies = WinHttpExtractCookies(Buffer) analyze_object(cookies, "cookies") end if -- Retrieve page content. Buffer = "" dwSize = WinHttpQueryDataAvailable(hRequest) while dwSize do Buffer &= WinHttpReadData(hRequest, dwSize) dwSize = WinHttpQueryDataAvailable(hRequest) end while puts(1, Buffer & "\n") -- Close any open handles. free_pointers() close(f_debug) maybe_any_key()
10. Re: Euphoria CGI
- Posted by jmduro Apr 24, 2017
- 3789 views
I am now able to drive Chrome through chromedriver via libcurl (not via WinHTTP, I don't know why). Here is an example of code:
include std/filesys.e include std/error.e include lib/_debug_.e include lib/_curl_constants_.e include lib/_curl_.e include lib/_json_.e include std/console.e object res atom curl f_debug = open(InitialDir & SLASH & "debug.log", "w") crash_file(InitialDir & SLASH & "ex.err") res = curl_global_init(CURL_GLOBAL_DEFAULT) curl = curl_easy_init() if curl then curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP) curl_easy_setopt(curl, CURLOPT_PROXY, "") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEJAR, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:9515/session") curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Connection: keep-alive") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Accept: application/json") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Content-Type: application/json; charset=UTF-8") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"desiredCapabilities\": {}}") -- curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, length(postthis)) res = curl_easy_perform_ex(curl) printf(1, "Status: %d\n", {res[1]}) printf(1, "Effective URL: %s\n", {res[2]}) analyze_object(res[3], "Headers", 1) analyze_object(res[4], "Content", 1) sequence sessionId = get_json_value("sessionId", json_to_sequence(res[4]), 0) printf(1, "Session ID: %s\n", {sessionId}) curl_easy_reset(curl) curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP) curl_easy_setopt(curl, CURLOPT_PROXY, "") curl_easy_setopt(curl, CURLOPT_COOKIEFILE, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_COOKIEJAR, InitialDir & SLASH & "cookies.txt") curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:9515/session/" & sessionId & "/url") curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Connection: keep-alive") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Accept: application/json") curl_easy_setopt(curl, CURLOPT_HTTPHEADER, "Content-Type: application/json; charset=UTF-8") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"url\": \"http://192.168.1.251:5000\"}") res = curl_easy_perform_ex(curl) printf(1, "Status: %d\n", {res[1]}) printf(1, "Effective URL: %s\n", {res[2]}) analyze_object(res[3], "Headers", 1) analyze_object(res[4], "Content", 1) curl_easy_cleanup(curl) end if curl_global_cleanup() close(f_debug) maybe_any_key()
Next step is to improve the libcurl wrapper and to get a first demo working.
Jean-Marc
11. Re: Euphoria CGI
- Posted by acEduardo Apr 24, 2017
- 3762 views
What about using HTML5 server-sent events? https://duckduckgo.com/?q=html5+server+events&ia=web
12. Re: Euphoria CGI
- Posted by jmduro Apr 24, 2017
- 3744 views
What about using HTML5 server-sent events? https://duckduckgo.com/?q=html5+server+events&ia=web
Maybe it's what you're thinking of: I intended to use Javascript to fire events (sending home-made UDP event frames to client side) as described here: https://www.w3schools.com/tags/ev_onmouseup.asp
It looks to me that HTML5 events are equivalent but I don't know how to handle them on client side. I need events to be catched by the OEU client that drives the browser, not by the browser itself.
Jean-Marc
13. Re: Euphoria CGI
- Posted by CraigWelch May 08, 2017
- 3558 views
What about using HTML5 server-sent events? https://duckduckgo.com/?q=html5+server+events&ia=web
I've done some work with Server-Side Events, and written up my results.
14. Re: Euphoria CGI
- Posted by jmduro Jan 23, 2018
- 2984 views
Maybe it's what you're thinking of: I intended to use Javascript to fire events (sending home-made UDP event frames to client side) as described here: https://www.w3schools.com/tags/ev_onmouseup.asp
It looks to me that HTML5 events are equivalent but I don't know how to handle them on client side. I need events to be catched by the OEU client that drives the browser, not by the browser itself.
Here is what I'm experimenting:
- a standard web server with a CGI module (I use lighttpd)
- a small notifier in OE run via CGI
- main OE program acting as a server to get notifications via the CGI module
Create an HTML file with this javascript function
function sendNotification(url, params) { var http = new XMLHttpRequest(); http.open("POST", url, true); //Send the proper header information along with the request http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.send(params); }
For each widget requiring action, as a button, call the method as in this example
<button onclick="sendNotification('notify.ex', 'action=delete&id=myButton')" class="btn btn-danger"> <span class="glyphicon glyphicon-trash" title="Delete" aria-hidden="true"></span> </button>
When button is clicked, there is an XMLHttpRequest towards the CGI module which relays notification to the main programs listening socket, so the main program can modify the HTML web page.
The CGI program relaying notifications is very short
include std/convert.e include std/io.e include std/socket.e as sock sequence cmd, query object nBytes cmd = command_line() nBytes = getenv("CONTENT_LENGTH") query = get_bytes(0, to_number(nBytes)) sock:socket sock = sock:create(sock:AF_INET, sock:SOCK_STREAM, 0) if sock:connect(sock, "127.0.0.1:5000") != sock:OK then printf(1, "Could not connect to server, is it running?\nError = %d\n", { sock:error_code() }) abort(1) end if sock:send(sock, query & "\n", 0) sock:close(sock)
Main program listens on port 5000 in this example and gets notified when the button is clicked on the HTML page so it can update the file.
Regards
Jean-Marc