|
Post by sarossell on Jan 26, 2020 3:26:33 GMT -5
So, I have this idea that may prove to be overly ambitious, but I'd like to give it a try. We all know Liberty BASIC is amazing. And I think the rest of the world would more easily take notice if we managed to get a few little things in place. I was originally going to try to do this on my own, but it occurred to me that other folks here might be interested as well. This idea started with me simply wanting to have all of my daily driver apps to be open source, written with Liberty BASIC, highly configurable, sharing a common look and feel, and able to run on Linux, Windows, Mac, and Raspberry Pi. So I made a list of the top programs I use on a regular basis, and then added a couple I'd enjoy using. As I was planning the development of all of these programs, I had a few insights. As far as I know, the Liberty BASIC community does not have written standard guidelines that include descriptions and definitions for things like program preference settings file structures, language localization standards, color theme definitions, application toolbar icon images, and pre-approved fonts. This is probably because most, if not all, of the programmers who enjoy using Liberty BASIC are hobbyists. So, I might be on my own here, but I hope not. My ultimate vision is a simple version controlled zip file package with documented guidelines, icon image files, and template files for source code and GUI forms that anyone could download and use to quickly program a professional looking application with matching look and feel to similarly developed projects. Hopefully, over time, the end result would be a professional looking suite of open source applications written with Liberty BASIC that people outside of the Liberty BASIC community can't help but notice. I sorted the list of applications in order of ease and speed to develop. Preliminary research suggests that the first six or so have already seen some efforts in development. Calculator Contacts Database Word Processor Image Viewer/Editor Code Text Editor Web Browser File Compression App File Manager Media Management Database Journaling/Knowledge Base App Email Client Calendar Video Converter Terminal Program FTP Client Messaging App EBook/PDF Reader Spreadsheet Audio File Editor Screen/Image Capture App Torrent Client Remote Desktop Client/Server Network VPN/Tunnel Virus/Malware Software Video Editor Language Transpiler with modules to Liberty BASIC (e.g., PHP to LB, or Python to LB) The last application on the list is a program to translate the source code of other languages to Liberty BASIC in order to encourage people with skills in other languages to learn by example with their own code. As a technical writer, I can put together the written details and provide a public file access location for download. If you're not interested in getting involved, any insights or suggestions would be appreciated - particularly regarding exemplary materials worthy of emulation, sources for original icon designs, preferential standards, best practices, etc. Thanks! -Scott :@)
|
|
|
Post by tsh73 on Jan 26, 2020 5:44:00 GMT -5
|
|
|
Post by meerkat on Jan 26, 2020 8:12:40 GMT -5
Wow! I would really be interested in how to do Client/Server. I'm fairly new to LB, so maybe something I completely missed. I tried to set something up with LB using CGI WEB interface with Apache, but failed.
How is this done?? Thanks for the help..
|
|
|
Post by sarossell on Jan 26, 2020 15:22:06 GMT -5
Whoo Hoo! These are the kind of comments I love to hear. tsh73: Anyone that gets to know me well enough soon learns that the concept of "impossible" just bounces right off me. In my career, I have been directly responsible for eliminating several supposed "impossible" objectives. And if there's one thing I know for sure about pursuing the impossible is that you learn volumes of information you would never have even glanced upon had you just moved on to simpler projects. In fact, to this day, the U.S. Navy at the Grace Hopper Computational Center in Coronado uses a method I devised to get programming groups to think outside of the box, and it has solved countless challenges. I'm currently on a team that has been working on an "impossible" computing task for over 22 years now. During that time, we have developed several new and more efficient encryption systems, improved compression efficiencies, developed an entire pseudo-code interpreter for data analysis, and developed a program that detects steganographic alterations in image data. We haven't quite solved the original challenge yet ('cuz it's a doozy!), but we've learned a lot by trying to "land on the moon", and we have a much clearer picture of the challenge than we did when we started back in '98. As for LB not being up to the challenge, if it has to be able to read JavaScript, then that sounds like a JavaScript interpreter needs to be written. And browser blocking may be overcome by sending out user-agent data for a different browser. I've done that on the Raspberry Pi before. meerkat: I'm diggin' your enthusiasm! I'd like to see a Client/Server solution with LB achieved as well. Perhaps you could share what you've already tried by submitting a message to the Projects section here on the Forum and hopefully, another member might chime in with some insights in that direction. What exactly were you trying to put together? I'm intrigued. As for now, I'm just trying to collect information on how to make programs written with LB share a common professional appearance and functionality. That's actually the easy part. The more challenging work is actually writing the code. I know LB can do it! Back in 1989, a couple of my friends in San Diego decided to "do the impossible" and built a 12-house theater lighting and curtain control system with an Atari 65XE, a boatload of X-11 remote control switches from Radio Shack, and all the control code was written in Atari BASIC. The system took cues from the projectors to activate the lights and curtains (theaters don't even bother with curtains these days). At the time, the factory system for doing this cost well over $100,000 for equipment and installation. They did it for $600. I wonder if they took any pictures or kept the code? I should get in touch with them to see if there's anything they can share. Anyway, if they could do that with an 8-bit computer over thirty years ago, imagine what Liberty BASIC could do today! -Scott :@)
|
|
|
Post by meerkat on Jan 27, 2020 8:49:52 GMT -5
It was a long time ago, and I can't remember what I did or find the LB web interface program. However here the best I can recall: ------------------------------------------------------------------- Liberty Basic CGI on an Apache server Setup Steps: 1 Install Apache 2 Configure Apache 3 Add LB 4 Add Your Script 4 Test 1. Install Apache Install the Apache HTTP Server program on to your computer. Download from: httpd.apache.org/downloadMake note of where you installed it on your computer. For example: C:\Program Files\Apache 2. Configure Apache Configure Apache so that it recognizes CGI. Find and edit "httpd.conf". This is where the entire Apache server is configured, so be careful when editing it. In your editor search for "CGI" until you find the following: <Directory "C:/Program Files/Apache/Apache2.2/CGI-bin " AllowOverride None Options None <-- change this line to 'Options ExecCGI'. Order allow,deny Allow from all </Directory> Next, search for "CGI" until you come across: #AddHandler CGI-script .CGI Simply remove the '#' sign from the line, so it reads: AddHandler CGI-script .CGI Save your new config file, then restart Apache. 3.Add LibertyBasic Add your LB web interface script program into the "CGI-bin" directory, located in the "Apache" folder. This is the program that is executed when your server receives something from the web. Your program decides what to do based on what it receives. Next, put your LB CGI scripts in the "CGI-bin" directory of the Apache server. A sample script may be: #!"C:/Program Files/Apache/Apache2.2/CGI-bin/WebTest.exe" -cs print "Content-type: text/html^/" print "<html><body>LB CGI Works!</body></html>] Notice the first line; #!"C:/Program Files/Apache/Apache2.2/CGI-bin/webTest.exe" -cs This line of code tells Apache where to find your LB interface program , so it can process CGI requests. At the end of the line, the "-cs" simply tells Apache to: c -Allow CGI processing s -Disable security, so we can save files with the data collected. 4. Test Create an HTML page with a simple form in it. The form action will look something like this: <form action="/CGI-bin/CGItest.CGI" method="POST " "CGItest.CGI" is the name of your CGI file, which must be in the CGI-bin folder. Next, put the HTML file into the "htdocs" folder, once again inside the Apache folder. After you put the HTML document in this folder, open your web browser and type the following in the address: http://localhost/*name of your html file here* ------------------------------------------------------------------------ That's the best I can remember.. I'll look around and see if I can anything. Not sure it means much since I could never get LB to work with apache CGI.
|
|
|
Post by sarossell on Jan 27, 2020 11:17:35 GMT -5
Wow. That's incredible. I had no idea that was even possible. How would this configuration compare to Run BASIC? Would it provide more options or greater flexibility?
|
|
|
Post by meerkat on Jan 27, 2020 12:30:22 GMT -5
Wow. That's incredible. I had no idea that was even possible. How would this configuration compare to Run BASIC? Would it provide more options or greater flexibility? I'm running Run Basic behind Apache. It allows me to do client/server with run basic and also stuff that has nothing to do with RB. If RB worked, I wouldn't even be trying to get LB to do client/server. Actually it works fine for some projects. But most of my projects are large. Downtime is not allowed, so I need a real managed database with replication. For me personally, there are only 2 problems with RB. And I really need a real DB. But the problems make it not usable for me. 1. SQLite locks and the only way out is to stop the backend RB server and restart it. 2. It has a memory leak. Again the only way out is to stop and start the RB server.
|
|
|
Post by Chris Iverson on Jan 27, 2020 13:52:17 GMT -5
CGI failed because it relies on being able to pass information through standard input/output, which LB does not normally have access to.
LB CAN access stdin/stdout using the Win32 console API, and now I'm curious if that would be enough to get CGI to work.
As for generic client/server stuff, I've been working quite a while on a DLL I should really get around to releasing, to make it easier to use basic sockets in LB, as well as making it (somewhat) easier to use secure, encrypted sockets in LB(though it's still complicated, because encryption is.)
EDIT: In fact, I was right. You need to compile the program for it to work, and you have to copy the EXE, TKN, and ALL of LB's runtime engine files into the Apache cgi-bin folder, but it works. (After doing so, you navigate to http://<servername>/cgi-bin/<lb app name>.exe)
This is a basic example that does output only; if you need to get the query string from a GET request, that'd be reading an environment variable(QUERY_STRING), and if you needed to read the parameters in a POST request, that would be provided via stdin, which is available using GetStdinHandle() and ReadFile().
EDIT2: And I've modified the example to include retrieving QUERY_STRING and the user-agent.
'Get QUERY_STRING length query$ = "" lenQuery = GetEnvironmentVariable("QUERY_STRING", query$, 0)
'If QUERY_STRING is defined, retrieve it if lenQuery <> 0 then query$ = space$(lenQuery) a = GetEnvironmentVariable("QUERY_STRING", query$, lenQuery) end if
'Same process for the user agent ua$ = "" lenUA = GetEnvironmentVariable("HTTP_USER_AGENT", ua$, 0)
if lenUA <> 0 then ua$ = space$(lenUA) a = GetEnvironmentVariable("HTTP_USER_AGENT", ua$, lenUA) end if
crlf$ = chr$(13) + chr$(10)
'Output can roughly be in any format we like, as long as it parses as what we specify '(in this case, HTML) output$ = "<html><head><title>Success</title></head><body><h1>LB CGI Test Successful!</h1>" + crlf$ if lenQuery > 0 then output$ = output$ + "<p>Query String: " + query$ + "</p>" + crlf$ end if
if lenUA > 0 then output$ = output$ + "<p>User Agent: " + ua$ + "</p>" + crlf$ end if
output$ = output$ + "</body></html>" outputLen = len(output$)
'Headers have a very specific format, one-per-line, with each line ending in a CRLF headers$ = "Content-Type: text/html" + crlf$ headers$ = headers$ + "Content-Length: " + str$(outputLen) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
'The full HTTP response, as per the standard, is headers(one-per-line) + blank line(CRLF) + content. response$ = headers$ + crlf$ + output$
lenResp = len(response$)
hStdOut = GetStdoutHandle() if hStdOut = 0 then end end if
bytesWritten = 0 a = WriteFile(hStdOut, response$, lenResp, bytesWritten) end
Function GetStdinHandle() stdin = -10 GetStdinHandle = GetStdHandle(stdin) End Function
Function GetStdoutHandle() stdout = -11 GetStdoutHandle = GetStdHandle(stdout) End Function
Function GetStdHandle(nStdHandle) CallDLL #kernel32, "GetStdHandle",_ nStdHandle as long,_ GetStdHandle as ulong End Function
Function GetEnvironmentVariable(envVar$, byref lpBuf$, nSize) CallDLL #kernel32, "GetEnvironmentVariableA",_ envVar$ as ptr,_ lpBuf$ as ptr,_ nSize as long,_ GetEnvironmentVariable as long End Function
Function WriteFile(hFile, lpBuf$, lpBufLen, byref bytesWritten) struct a, lpNumberOfBytesWritten as long a.lpNumberOfBytesWritten.struct = 0
CallDLL #kernel32, "WriteFile",_ hFile as ulong,_ lpBuf$ as ptr,_ lpBufLen as long,_ a as struct,_ 0 as ulong,_ WriteFile as long
bytesWritten = a.lpNumberOfBytesWritten.struct End Function
Function ReadFile(hFile, byref lpBuf$, lpBufLen, byref bytesRead) struct a, lpNumberOfBytesRead as long a.lpNumberOfBytesRead.struct = 0
CallDLL #kernel32, "ReadFile",_ hFile as ulong,_ lpBuf$ as ptr,_ lpBufLen as long,_ a as struct,_ 0 as ulong,_ ReadFile as long
bytesRead = a.lpNumberOfBytesRead.struct End Function
EDIT3: And just for completeness, a POST example. Note that you'll have to copy-paste the functions from the above example to this one, as I removed them to avoid duplicated code.
crlf$ = chr$(13) + chr$(10)
'Get request method. reqMethod$ = "" lenReqMethod = GetEnvironmentVariable("REQUEST_METHOD", reqMethod$, 0) if lenReqMethod = 0 then 'Problem. CGI gateway failed to process properly. end end if
reqMethod$ = space$(lenReqMethod) a = GetEnvironmentVariable("REQUEST_METHOD", reqMethod$, lenReqMethod)
'Reject anything that's not a POST request. if upper$(trim$(reqMethod$)) <> "POST" then output$ = "Requests must be submitted using the POST method." lenOutput = len(output$)
'We can submit custom HTTP status codes by specifying it as a Status header 'in the response.
'HTTP Status Code 405 means the requested method is not allowed for the 'requested resource. In this case, we refuse anything that's not a POST request. headers$ = "Status: 405 Method Not Allowed" + crlf$
'According to the standard, if we sent back a 405, we have to specify in another 'header what methods are acceptable. headers$ = headers$ + "Allow: POST" + crlf$ headers$ = headers$ + "Content-Type: text/plain" + crlf$
headers$ = headers$ + "Content-Length: " + str$(lenOutput) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
goto [sendResponse] end if
'Try to get the stdin handle for the POST data, and (try to) send back an 'HTTP 500 Internal Server Error if we can't. hStdIn = GetStdinHandle()
if hStdIn = 0 then output$ = "Internal server error; unable to access input data." lenOutput = len(output$)
headers$ = "Status: 500 Internal Server Error" + crlf$ headers$ = headers$ + "Content-Type: text/plain" + crlf$ headers$ = headers$ + "Content-Length: " + str$(lenOutput) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
goto [sendResponse] end if
postData$ = "" readBufSize = 500 readBuf$ = space$(readBufSize) numBytesRead = 0
[readLoop] 'Keep reading data until we either get nothing back, 'or get less back than a full buffer. ' 'Either one indicates we've reached the end of the available data. if ReadFile(hStdIn, readBuf$, readBufSize, numBytesRead) then if numBytesRead > 0 then postData$ = postData$ + left$(readBuf$, numBytesRead) if numBytesRead = readBufSize then [readLoop] end if end if
param1$ = word$(postData$, 1, "&") param2$ = word$(postData$, 2, "&")
param1Name$ = word$(param1$, 1, "=") param1Value$ = word$(param1$, 2, "=")
param2Name$ = word$(param2$, 1, "=") param2Value$ = word$(param2$, 2, "=")
sum = val(param1Value$) + val(param2Value$)
'Output can roughly be in any format we like, as long as it parses as what we specify '(in this case, HTML) output$ = "<html><head><title>Success</title></head><body><h1>LB CGI Test Successful!</h1>" + crlf$ output$ = output$ + "<p>" + param1Name$ + " - " + param1Value$ + "</p>" + crlf$ output$ = output$ + "<p>" + param2Name$ + " - " + param2Value$ + "</p>" + crlf$ output$ = output$ + "<p>" + param1Value$ + " + " + param2Value$ + " = " + str$(sum) + "</p>" + crlf$
output$ = output$ + "</body></html>" outputLen = len(output$)
'Headers have a very specific format, one-per-line, with each line ending in a CRLF headers$ = "Content-Type: text/html" + crlf$ headers$ = headers$ + "Content-Length: " + str$(outputLen) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
[sendResponse] 'The full HTTP response, as per the standard, is headers(one-per-line) + blank line(CRLF) + content. response$ = headers$ + crlf$ + output$
lenResp = len(response$)
hStdOut = GetStdoutHandle() if hStdOut = 0 then end end if
bytesWritten = 0 a = WriteFile(hStdOut, response$, lenResp, bytesWritten) end
|
|
|
Post by meerkat on Jan 28, 2020 7:08:12 GMT -5
Thanks Chris. I have a system in mind to try. It's about 100 programs; kneware.com/wine/index.htmlThis is one I had in RB but had to move to another language. Would like it in RB, but maybe LB will work. Not sure what will be involved to convert the system. For sure I'll have to store all the variables between sessions. Since Apache now expects CGI, it looks like LB will have to broker the pages??? I have a feeling I can get a simple javascript to handle this. Most of my web pages are interactive and do not use a simple [Submit] button. Some entries are checked on the fly. For example a web page with a country drop down, with ONCHANGE, LB must immediately look up the states and create a state drop down back into the page, and the state entry must automatically create a county drop down.. So not sure how to handle the html <INPUT ONLEAVE or ONCHANGE several times on a web page. And JavaScript is not uncommon. Since this system does not allow downtime, I need replication and system fail-over. I'll see how it goes. It will take some time to test these and other known issues.. Thanks for the help.. Dan
|
|
|
Post by meerkat on Jan 28, 2020 9:01:16 GMT -5
Actually, Probably the best way to handle all web hits to the site, would be to run 2 Apache sessions. One session uses port 80 and handles regular hits to the domain name. The other session is set up for CGI and uses port 8008 for example. So searches to your site will use port 80. Any LB app links would simply have a link that initiates the proper session on port 8008... I think???
|
|
|
Post by Chris Iverson on Jan 28, 2020 12:00:09 GMT -5
That shouldn't be necessary at all, if you don't want it. Apache will still serve all other code(HTML, CSS, Javascript) from /htdocs. It's just the /cgi-bin/ path that gets directed to the cgi-bin folder, and it's configured to do so.
You could serve static HTML from the regular location, and just use calls to the /cgi-bin/*.exe programs to handle dynamic page information, most likely using something like XMLHttpRequest.
EDIT: Here's an example. Here's a modified version of the POST example above, that only returns the sum in plaintext, nothing else. Compile it as cgitest.exe in the cgi-bin folder(or edit the next example to change the .exe name).
crlf$ = chr$(13) + chr$(10)
'Get request method. reqMethod$ = "" lenReqMethod = GetEnvironmentVariable("REQUEST_METHOD", reqMethod$, 0) if lenReqMethod = 0 then 'Problem. CGI gateway failed to process properly. end end if
reqMethod$ = space$(lenReqMethod) a = GetEnvironmentVariable("REQUEST_METHOD", reqMethod$, lenReqMethod)
'Reject anything that's not a POST request. if upper$(trim$(reqMethod$)) <> "POST" then output$ = "Requests must be submitted using the POST method." lenOutput = len(output$)
'We can submit custom HTTP status codes by specifying it as a Status header 'in the response.
'HTTP Status Code 405 means the requested method is not allowed for the 'requested resource. In this case, we refuse anything that's not a POST request. headers$ = "Status: 405 Method Not Allowed" + crlf$
'According to the standard, if we sent back a 405, we have to specify in another 'header what methods are acceptable. headers$ = headers$ + "Allow: POST" + crlf$ headers$ = headers$ + "Content-Type: text/plain" + crlf$
headers$ = headers$ + "Content-Length: " + str$(lenOutput) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
goto [sendResponse] end if
'Try to get the stdin handle for the POST data, and (try to) send back an 'HTTP 500 Internal Server Error if we can't. hStdIn = GetStdinHandle()
if hStdIn = 0 then output$ = "Internal server error; unable to access input data." lenOutput = len(output$)
headers$ = "Status: 500 Internal Server Error" + crlf$ headers$ = headers$ + "Content-Type: text/plain" + crlf$ headers$ = headers$ + "Content-Length: " + str$(lenOutput) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
goto [sendResponse] end if
postData$ = "" readBufSize = 500 readBuf$ = space$(readBufSize) numBytesRead = 0
[readLoop] 'Keep reading data until we either get nothing back, 'or get less back than a full buffer. ' 'Either one indicates we've reached the end of the available data. if ReadFile(hStdIn, readBuf$, readBufSize, numBytesRead) then if numBytesRead > 0 then postData$ = postData$ + left$(readBuf$, numBytesRead) if numBytesRead = readBufSize then [readLoop] end if end if
param1$ = word$(postData$, 1, "&") param2$ = word$(postData$, 2, "&")
param1Value$ = word$(param1$, 2, "=")
param2Value$ = word$(param2$, 2, "=")
sum = val(param1Value$) + val(param2Value$)
output$ = str$(sum) outputLen = len(output$)
'Headers have a very specific format, one-per-line, with each line ending in a CRLF headers$ = "Content-Type: text/plain" + crlf$ headers$ = headers$ + "Content-Length: " + str$(outputLen) + crlf$ headers$ = headers$ + "X-From-LB: true" + crlf$
[sendResponse] 'The full HTTP response, as per the standard, is headers(one-per-line) + blank line(CRLF) + content. response$ = headers$ + crlf$ + output$
lenResp = len(response$)
hStdOut = GetStdoutHandle() if hStdOut = 0 then end end if
bytesWritten = 0 a = WriteFile(hStdOut, response$, lenResp, bytesWritten) end
Now, here's an HTML file you can save as test.html(or something similar) and put it in your Apache install's htdocs folder:
<html> <head><title>Addition Test</title> <script type='text/javascript'> function getSum() { var xhr = new XMLHttpRequest(); xhr.open("POST", "/cgi-bin/cgitest.exe", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { document.getElementById('sum').innerHTML = this.responseText; } };
var num1 = document.getElementById('num1').value; var num2 = document.getElementById('num2').value;
var postData = "num1=" + num1 + "&num2=" + num2; xhr.send(postData); } </script>
</head> <body> <h1>Enter two numbers to add!</h1> <form> First number:<br> <input id="num1" type="number" name="num1" /><br> Second number: <br> <input id="num2" type="number" name="num2" /><br><br>
<input type='button' value='Calculate' onclick='getSum()' /> </form> <br> <p>Sum: <span id='sum'></span></p> </body> </html>
When you put in two numbers, and click "Calculate", your browser will send a request in the background to the LB script, which will add the numbers and return the response. Your browser will put the response next to where it says "Sum:".
|
|
|
Post by meerkat on Jan 28, 2020 12:48:09 GMT -5
Thanks Chris.. I'll give it a try. I don't want to mess up what I have working on client/server. So I'm setting up a PC to do this. Initially I'll run on win/10. If it looks like it works, I may try to move to linux.
Since I have a lot of programs, I'm writing a program to convert RB to LB. I'm trying to come up with a general purpose routine that knows what variables are used in HTML and remembers the data between sessions.
Looks like a few late nights...
Thanks again.. Dan
|
|