1. Euphoria CGI

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

new topic     » topic index » view message » categorize

2. Re: Euphoria CGI

I forgot to mention I'm running Apache2 on Debian 8 (Jessie) on either PC or Raspberry Pi.

new topic     » goto parent     » topic index » view message » categorize

3. Re: Euphoria CGI

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.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Euphoria CGI

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

new topic     » goto parent     » topic index » view message » categorize

5. Re: Euphoria CGI

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

new topic     » goto parent     » topic index » view message » categorize

6. Re: Euphoria CGI

"whatever else" is mostly JSON data used in the requests.

new topic     » goto parent     » topic index » view message » categorize

7. Re: Euphoria CGI

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

new topic     » goto parent     » topic index » view message » categorize

8. Re: Euphoria CGI

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

new topic     » goto parent     » topic index » view message » categorize

9. Re: Euphoria CGI

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() 
new topic     » goto parent     » topic index » view message » categorize

10. Re: Euphoria CGI

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

new topic     » goto parent     » topic index » view message » categorize

11. Re: Euphoria CGI

What about using HTML5 server-sent events? https://duckduckgo.com/?q=html5+server+events&ia=web

new topic     » goto parent     » topic index » view message » categorize

12. Re: Euphoria CGI

acEduardo said...

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

new topic     » goto parent     » topic index » view message » categorize

13. Re: Euphoria CGI

acEduardo said...

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.

new topic     » goto parent     » topic index » view message » categorize

14. Re: Euphoria CGI

jmduro said...

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

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu