-
2 Attachment(s)
VB6 Web Site/App Server
This project helps you serve web sites/apps with VB6. It is a work in progress. It will eventually become a DLL, but for now it is an EXE project while under development.
It includes a number of nice features to make it easier to deliver websites such as:
- Auto-serves static files (this can be disabled if you want to perform your own file serving).
- Automatically handle If-None-Match headers to return 304 Not Modified when appropriate to save bandwidth.
- Easily handle cookies with the CHttpCookies class.
- Easily handle requests via the CHttpRequest class.
- Easily respond to requests using the CHttpResponse class.
- Include "helper" classes for things like handling dates, encoding HTML entities, "Safe" DB creation, regular expressions, and HTML templates (I call these VBML files, and they have a ".vbml" extension.
- MIME type detection (file extension based).
VBML files are just HTML files with special comments. The app server will detect the comments and raise an event to your app, which can then respond with HTML that will replace the VBML comment. VBML comments are formatted like this:
Code:
<!-- vbml: my_vbml_command -->
Your app will receive "my_vbml_command" in the ConvertVbmlToHtml event, where it can set the p_Html property to whatever you'd like to replace the comment with. VBML commands can also include parameters:
Code:
<!-- vbml: my_vbmlcommand(2, "Param") -->
The parameters will be passed in the po_VbmlParameters arraylist in the ConvertVbmlToHtml event, and you can use them however you like. Take a look at the Web/index.vbml file for examples of some VBML comments/commands, then look at the CApp class' mo_VbmlHelper_ConvertVbmlToHtml event sub to see how the VBML commands are processed.
To Try It Out Yourself:
IMPORTANT NOTE FOR LINUX/WINE USERS: Make sure to use an early Wine 5.x release or a Wine 7.x release. The late 5.x and 6.x series appears to have broken something related to networking, and the RC6 cWebServer class never receives data to respond to. This is discussed in more detail here.
- Make sure that all the RC6 DLLs are installed on your computer.
- Open VBWebAppServer.vbp and run it.
- In your browser, visit http://127.0.0.1:8080
You should see the following page:
Attachment 182810
Note that when running in the IDE, the server will be running as a single thread so performance won't be spectacular as each request will have to wait for the previous request to complete. You can however compile the EXE and use the /spawn switch to spawn as many app server listeners as you like. You can then put Nginx in front of the app server and configure it to be a reverse proxy to all your app server listeners.
Here's the code that produces the dynamic portions of the demo page:
Code:
Option Explicit
Private WithEvents mo_VbmlHelper As CAppHelperVbml
Public Sub RespondToRequest(po_Req As CHttpRequest, po_Response As CHttpResponse, po_Helpers As CAppHelpers)
Dim l_VisitCount As Long
With po_Req.Cookies
l_VisitCount = .CookieValueByKeyOrDefaultValue("visitcount", 0)
l_VisitCount = l_VisitCount + 1
.AddOrReplaceCookie "visitcount", l_VisitCount, , , Now + 10000
End With
With po_Response
If po_Helpers.Regex.Test(po_Req.Url(urlsection_Path), "^showcase/[0-9]+$", False) Then
' Get requested showcase image from database by numeric id
With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
With .CreateSelectCommand("SELECT image, etag, extension FROM showcase WHERE id=?")
.SetInt32 1, Split(po_Req.Url(urlsection_Path), "/")(1) ' Get image ID from request and use it for SELECT query
With .Execute(True)
If .RecordCount = 0 Then
' No image found!
po_Response.Send404NotFound
Else
' Found an image. Check to see if requester has a cached copy
If po_Req.Headers.HeaderValue("If-None-Match") = .Fields("etag").Value Then
' Requester has a cached copy, send 304 Not Modified to save bandwidth
po_Response.Send304NotModified
Else
' Requester does not have a cached copy of the image, so send it (along with the ETag so future cache hits can be tested).
po_Response.AddHttpHeader "ETag", .Fields("etag").Value
po_Response.SendSimpleByteArrayResponse .Fields("image").Value, , , mimeTypeFromFilePath(.Fields("extension").Value)
End If
End If
End With
End With
End With
Else
If Not New_C.FSO.FileExists(po_Req.LocalPath) Then
' File Not found!
.Send404NotFound
Else
If LCase$(Right$(po_Req.Url(urlsection_Path), 5)) = ".vbml" Then
' Request for a dynamic .vbml page
Set mo_VbmlHelper = po_Helpers.Vbml ' Pass VBML helper to module level variable to receive events.
.SendSimpleHtmlResponse mo_VbmlHelper.ParseVbmlString(New_C.FSO.ReadTextContent(po_Req.LocalPath)), po_Req.Cookies
Else
' Since we have auto serve enabled, we should never get here
' as the auto-serve feature should have found and served the requested file.
Debug.Assert False
.Send400BadRequest
End If
End If
End If
End With
End Sub
Private Sub mo_VbmlHelper_ConvertVbmlToHtml(ByVal p_VbmlCommand As String, ByVal po_VbmlParameters As RC6.cArrayList, p_Html As String, p_ShouldEscapeHtml As e_HtmlEscapeType)
Dim l_Date As Date
Dim l_ShowcaseCount As Long
Select Case p_VbmlCommand
Case "get_rc6_version"
' Get the file version of RC6.dll for reporting the most recent version
p_Html = New_C.Version
Case "get_rc6_date"
' Get the file creation date of RC6 DLL for reporting the most date of the most recent release
New_C.FSO.GetFileAttributesEx pathSystem & "RC6.dll", , , , l_Date
p_Html = Format$(l_Date, "YYYY-MM-DD")
Case "get_copyright"
' Get the copyright text for the page
p_Html = "Copyright " & Year(Now) & " — Olaf Schmidt."
p_ShouldEscapeHtml = htmlescape_No
Case "get_random_showcase_items"
' Get random RC6 showcase items and build the product showcase card.
' You can pass a count parameter with this command to determine the number of random showcase items to retrieve
l_ShowcaseCount = 2 ' Default to 2 showcase items
If po_VbmlParameters.Count > 0 Then l_ShowcaseCount = po_VbmlParameters.Item(0) ' Get the desired # of showcase items if defined.
With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
With .OpenRecordset("SELECT rowid, product_name, developer, description_html, website FROM showcase ORDER BY random() LIMIT " & l_ShowcaseCount)
Do Until .EOF
p_Html = p_Html & "<div class='card p-4'>" & _
"<h2 class='text-center'>" & htmlEscape(.Fields("product_name")) & "<br>by " & htmlEscape(.Fields("developer")) & "</h2>" & _
"<img alt='" & htmlEscape(.Fields("product_name")) & " Screenshot' style='max-height: 150px;' class='img-fluid mt-4 mb-4 mx-auto' src='showcase/" & htmlEscape(.Fields("id")) & "' />" & _
.Fields("description_html") & _
"<p><a href='" & htmlEscape(.Fields("website")) & "'>Learn more about " & htmlEscape(.Fields("product_name")) & "...</a></p>" & _
"</div>"
.MoveNext
Loop
End With
End With
p_ShouldEscapeHtml = htmlescape_No
Case Else
p_Html = "Unhandled VBML Command: " & p_VbmlCommand
Debug.Print p_Html
'Debug.Assert False
End Select
End Sub
You can see it's pretty standard VB6 code, reasonably readable/understandable and concise (62 lines not including comments).
Command Line Parameters
If you compile the EXE you'll have access to some command line parameters:
/spawn <number>
Start the app server in "spawner" mode which will cause it to launch <number> processes in "listener" mode.
/stop
Stop all listener and spawner processes.
/ip <IPv4 address>
Tells the app server what IP to listen on
/port <Port>
Tells the app server what Port to listen on. When used with /spawn, this will be the first port of the first spawned listener. Additonal spawned listeners will listen on <port+spawnindex>. For example, spawning 3 listeners at base port 8080 with the command /spawn 3 /ip 127.0.0.1 /port 8080 will result in listeners on ports 8080, 8081, and 8082.
/rootpath <folder path>
Tells the server where the root folder is for serving static files. This defaults to the App.Path & "\web" folder. All of your static files should be placed in this folder (or subfolders thereof).
It's recommended to start in spawner mode like this:
Code:
VbWebApp.exe /spawn 10 /ip 127.0.0.1 /port 8080
The above command spawns 10 app listeners on ports 8080-8089.
Note that the compiled EXE expects the RC6 DLLs to be in the App.Path & "\System" folder for reg-free use.
Anyway, I hope some of you find this useful, and I'll be happy to answer any questions you might have.
SOURCE CODE HERE: Attachment 183610
-
Re: VB6 Web Site/App Server
-
Re: VB6 Web Site/App Server
Also reserved for future use.
-
Re: VB6 Web Site/App Server
G'Day JPBro
Thanks for this post, very interesting and like all of your posts real quality.
But, I'm having what I fear is going to be a very simple mistake.
I cannot compile the project and I think it is to do with my RC6 environment.
I have
- Copied the dlls to System folder under App folder
- Registered RC6.dll & added to project refs.
- Registered RC6Widgets.dll & added to project refs.
As you probably remember I tried to get VB6 going as a Web Dev. 'Engine' a few years back and this is another example of just not being able to get started !!!
H E L P -:)
Attachment 182814
-
Re: VB6 Web Site/App Server
Hi jg.sa,
In the App\System folder, you should have the following files:
cairo_sqlite.dll
DirectCOM.dll
RC6.dll
(You don't need RC6Widgets.dll for this project).
RC6.dll should be registered on your development machine only (you won't need to register when deploying the app to other machines).
The VBWebAppServer.vbp should already have a reference to RC6.dll, and you should then be able to compile the software to the App folder at this point.
It sounds like you've done the right stuff, so I'm not really sure what's wrong. Unfortunately your attachment didn't work for me (it just says "Attachment 182814") so I can't see what error message you a re getting. Can you try posting the image again?
-
Re: VB6 Web Site/App Server
@jg.sa - I've made a few changes to the source that might help. Also be sure that you have downloaded and registered the latest version of RC6 (6.0.8). If there are still any problems, please re-post the screenshot or the full error message so I can have a better chance to figure out what's going wrong.
-
Re: VB6 Web Site/App Server
very good work.
I will try it more calmly.
a greeting
-
Re: VB6 Web Site/App Server
I've just updated the source code in Post #1 with a small improvement when loading hundreds of app server listeners. Before the self-healing feature would chew up way too much CPU when checking hundreds of listeners. Now I'm break up the checks into chunks so that CPU usage is reasonable.
@yokesee - thanks, I hope you find the project useful.
-
Re: VB6 Web Site/App Server
Not sure if any one is bother to play around with this, but if you are please don't try it under Linux/Wine yet. I've bumped into an issue with the RC6 cWebServer under Linux/Wine and there's no sense with any of you wasting your time in that environment until it is resolved. Everything works fine on Windows (tested on 10 only so far, but should be good on any of the OSes that RC6 works with, which I believe is Win7+).
I'll be working on a small login/session handling example soon that I will post as soon as it is done.
-
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jpbro
Not sure if any one is bother to play around with this, but if you are please don't try it under Linux/Wine yet. I've bumped into an issue with the RC6 cWebServer under Linux/Wine and there's no sense with any of you wasting your time in that environment until it is resolved. Everything works fine on Windows (tested on 10 only so far, but should be good on any of the OSes that RC6 works with, which I believe is Win7+).
You should update your OP with this new information. Remember a lot of lurkers come here too, many times led directly by Google's search engines. For example this thread I made back 2012 has something like 12000+ views. All of that can't be from members only. We members will tend to read all of the posts in a thread but some random wanderer from the wider internet may not read past the OP. Just a small tip ;)
-
Re: VB6 Web Site/App Server
Sure, makes sense & will do, done.
-
Re: VB6 Web Site/App Server
G'Day Bro :)
Now I can compile
A N D
Run in IDE
Hugh round of applause !!!
You are the guru
-
Re: VB6 Web Site/App Server
@jg.sa - Great, glad you are up and running, and I hope you find the app useful. If you encounter any bugs or issues, please feel free to post here.
-
Re: VB6 Web Site/App Server
Quick and important update for Linux/Wine users: Make sure to use a Wine 5.x release. The 6.x series appears to have broken something related to networking, and the RC6 cWebServer class never receives data to respond to.
I'm looking for a way to get up and running on 6.x, we'll see if I get lucky.
-
Re: VB6 Web Site/App Server
Perhaps there is something wrong on the Wine side of things. Perhaps there is a forum somewhere where you can alert the developers of Wine that it has a problem. You may also want to alert Olaf just in case the problem is in RC6. I doubt it but it's possible.
-
Re: VB6 Web Site/App Server
I believe that's the case. There is a Wine forum so I will start a thread there when I have a chance. The Wine devs require a mountain of evidence, so it will take some time to gather it.
-
Re: VB6 Web Site/App Server
Alright, after much deeper testing I'm fairly confident that the bug is with Wine 6.x. I've submitted the bug report here: https://bugs.winehq.org/show_bug.cgi?id=52024, so hopefully I'm right and haven't wasted the Wine dev's time!
-
Re: VB6 Web Site/App Server
G'Day Bro
I will 1stly mention what I'm trying to achieve. I want to be able to create smart 'Contact Us' forms, which will include fields like "Employee / Contractor / Contact' email address, so the form can route to a particular inside enterprise person, without having the 'Web Master' forward the email that resulted from this web page.
So I'm hoping to eventually parameterize these types of forms.
I see you mention - "Safe" DB creation
Is this something that you designed into your code, when I read thru. the code it seems to be a part of RC.
If that is the case, what would be the best way to handle forms like 'Contact Us'.
As VB is so good with strings I was hoping to us split to pull apart or assemble the field values and eventually dev. generic fields processing routines for web forms.
TIA
-
1 Attachment(s)
Re: VB6 Web Site/App Server
@jg.sa
I just uploaded the ZIP in the first post with a small demonstration of how you might implement a dynamic contact form. What it does:
1) Converts a VBML tag (get_contact_form) into an HTML <form> block.
2) Queries a DB for available types of issues (e.g. Bug Report, Feature Request).
3) Accepts submission from the user, and determines what email addresses should receive the user's comments depending on the issue type. E.g. bug reports go to certain contacts, feature requests go to different contacts.
4) Fixes a bug in form query data handling.
What it doesn't do:
1) It doesn't actually send the email. That is outside the scope of the demo.
So if you go ahead and grab the latest sources and run it, you can go to http://127.0.0.1:8080 and scroll down to the bottom of the page to see this:
Attachment 182983
Fill in the email address & comments, then click submit. You see a plain text page confirming who the email was "sent" to. If you go back and change the issue type and re-submit, you will see different recipients have been "sent" an email.
Here's the code added to the ConvertVbmlToHtml event of the CApp class:
Code:
Case "get_contact_form"
' Build a dynamic contact form based on records in the "contact_issues" table of our web DB.
' When the user submits this form, the RespondToRequest event will be fired.
' The form query data will be held in the po_Req.Query object
' The value keys will be:
' issue_id - The row ID of the selected contact_issues record
' email - The submitter's email address
' comments - The submitter's comments
With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
With .OpenRecordset("SELECT id, issue_name FROM contact_issues")
p_Html = "<h1>Contact Form</h1>" & _
"<form action='contact' method='post'>" & _
"<select name='issue_id'>"
' Build issue types drop-down list
Do Until .EOF
p_Html = p_Html & _
"<option value='" & .Fields("id").Value & "'>" & htmlEscape(.Fields("issue_name").Value) & "</option>"
.MoveNext
Loop
p_Html = p_Html & "</select>"
' Add fields for submitter's email address and comments.
p_Html = p_Html & "<p><label>Your Email</label></p><p><input type='email' name='email'></p>" & _
"<p><label>Your Comments</label></p><textarea name='comments'></textarea></p>" & _
"<button type='submit'>Submit</button>"
p_Html = p_Html & "</form>"
End With
End With
And here's the code added to the RespondToRequest event:
Code:
Select Case LCase$(po_Req.Url(urlsection_Path))
Case "contact"
' The contact form has been submitted.
' Get the comma-separated email list from our web DB and send the email to all contacts in the list.
' NOTE: We aren't actually going to send the emails in this demo as it is outside the scope of this project.
With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
With .OpenRecordset("SELECT emails FROM contact_people WHERE issue_id=" & po_Req.Query("issue_id"))
Dim l_Emails As String
l_Emails = .Fields("emails").Value
End With
End With
' In a real app we'd redirect to a nice HTML page (or show a popup) to tell the user the email was sent.
' For demo purposes, we'll just send back some boring plain text.
.SendSimplePlainTextResponse "Thank you, your message has been sent to: " & vbNewLine & vbNewLine & Replace$(l_Emails, ",", vbNewLine)
Case Else
' Code below this point is unchanged from the previos demo
Hope that helps :)
-
Re: VB6 Web Site/App Server
Also re: the CSafeDB class - it's not needed for your scenario if you are creating the Contact Form DB/tables offline (that is, not creating them live in a running app server instance).
The "Safe" part comes from the fact that it puts the opening of a DB connection behind a mutex, ensuring that you can create a DB & add tables etc... in one process, and if another process tries to open it while the first process is busy, the second process will wait until the DB has been completely setup before it will be allowed to grab a connection. Since the CAppServer is designed to run as multiple processes for serving requests, we want to make sure they aren't stepping on each other when creating a DB (only one process will be allowed to create a specific DB even if multiple processes are racing to do it).
-
Re: VB6 Web Site/App Server
Very good work, keep it up.
the examples work fine.
I get the following errors on the console, but it seems to work all fine.
I run the cmd VBWebAppServer.exe / spawn 5
Code:
***ERROR: -2147221504 An instance is already running at 0.0.0.0:8084
***ERROR: -2147221504 An instance is already running at 0.0.0.0:8081
a greeting
-
Re: VB6 Web Site/App Server
Hi yokesee,
Thanks for reporting the issue with the already running instance message. So far I have been unable to reproduce the problem, so I'm not sure why you are seeing that message. If you look at the Task Manager, do you have 6 VbWebAppServer.exe instances running (1 for the spawner/monitor process, and 5 for the spawned listener processes)?
-
Re: VB6 Web Site/App Server
Forgot to mention that the latest version has a small improvement to the CHttpCookies and CHttpQueryParams classes.
In the older version you had to use this fairly long code to access a query param value:
Code:
MsgBox po_Req.Query.ValuesByKey("paramname").ValueByIndex(0)
That was getting tiring, so there's a new hidden default .Values(KeyOrIndex) method in the CHttpQueryParams class, and a new hidden default .FirstValue method in the CHttpQueryParam class. Since you will only have 1 query parameter value per query parameter key 99.999% of the time, this means we can now shorten access to a particular query param value as follows:
Code:
MsgBox po_Req.Query("paramname")
Similarly for Cookies, you can use the new shorthand:
Code:
Msgbox po_Req.Cookies("cookiename")
-
Re: VB6 Web Site/App Server
@yokesee - I have now been able to reproduce the problem you reported with error messages in the console. It seems to happen after a period of time with the monitor incorrectly trying to respawn instances it thinks are dead but are actually still alive. Clearly a bug in my code somewhere, so I will get it fixed ASAP. Thanks for reporting the problem!
-
Re: VB6 Web Site/App Server
:) thank you very much great job as always
-
Re: VB6 Web Site/App Server
G'Day Bro :)
Thank you , Thank you , Thank you !!!
This example is so much more than I had hope for and as I'm in the middle of a family BBQ I should not be looking at code.
But I have this on the bottom of the updated example
"Unhandled VBML Command: get_contact_form"
Don't rush to fix this as I can see why, just can't provide a fix as I'm under 'Pressure' not to turn Kebabs into charcoal
Case Else
p_Html = "Unhandled VBML Command: " & p_VbmlCommand
Debug.Print p_Html
'Debug.Assert False
End Select
-
Re: VB6 Web Site/App Server
If you're running the EXE, please make sure you've recompiled it so that the new "get_contact_form" handling code is compiled.
If you're running from the IDE, can you confirm that there is code that looks like this in the mo_VbmlHelper_ConvertVbmlToHtml method of the CApp class?
Code:
Case "get_contact_form"
' Build a dynamic contact form based on records in the "contact_issues" table of our web DB.
' When the user submits this form, the RespondToRequest event will be fired.
' The form query data will be held in the po_Req.Query object
' The value keys will be:
' issue_id - The row ID of the selected contact_issues record
' email - The submitter's email address
' comments - The submitter's comments
With New_C.Connection(pathApp & "web.sqlite", DBOpenFromFile)
With .OpenRecordset("SELECT id, issue_name FROM contact_issues")
p_Html = "<h1>Contact Form</h1>" & _
"<form action='contact' method='post'>" & _
"<select name='issue_id'>"
' Build issue types drop-down list
Do Until .EOF
p_Html = p_Html & _
"<option value='" & .Fields("id").Value & "'>" & htmlEscape(.Fields("issue_name").Value) & "</option>"
.MoveNext
Loop
p_Html = p_Html & "</select>"
' Add fields for submitter's email address and comments.
p_Html = p_Html & "<p><label>Your Email</label></p><p><input type='email' name='email'></p>" & _
"<p><label>Your Comments</label></p><textarea name='comments'></textarea></p>" & _
"<button type='submit'>Submit</button>"
p_Html = p_Html & "</form>"
End With
End With
Enjoy the BBQ :)
-
Re: VB6 Web Site/App Server
@yokesee, I've figured out why you are seeing the error message in the console.
When you don't specify an IP address to listen to, the software defaults to meta-address 0.0.0.0. This is OK for the "listener" mode since 0.0.0.0 means "listen on any/all interfaces", but it is bad for the monitor code since it can't connect to 0.0.0.0 to confirm the server is still listening. It subsequently thinks the server is broken and tries to restart it, but the restart fails because the server is actually OK.
I've changed the code to pick a valid local IP address using a RC6 cTcpClient.GetIP("") call when the listen address is 0.0.0.0 so that the monitor can connect and confirm that the listener is responding to requests. The latest version is available in the first post.
Thanks again for reporting the problem!
-
Re: VB6 Web Site/App Server
G'Day Bro
I have just 'escaped' to get a couple of brewsky from the fridge.
I should have thought about rebuilding the image !!!
We are going to have to agree a data structure for handling forms in the future, nothing complicated possibly using .ini files and compiler directives, I can do this and submit for 'approval' !!!
-
Re: VB6 Web Site/App Server
In the demo app, I use a database for configuring the dynamic aspects of the form. I've only done the bare minimum just to demonstrate it is possible to create custom forms/back-end routing. The EXE rebuild shouldn't generally be necessary, only if you add new features that the old compiled EXE won't understand. So yeah, decide on a structure/set of rules that will accommodate all of your business needs first, then work that into the compiled part. Once that's done you should be able to add forms, changes contacts, etc... without needing to recompile.
Anyway, I'm off to bed, so have a good night and a brewsky for me :)
-
Re: VB6 Web Site/App Server
Very good work now it works perfectly.
take a little time to test, it has a lot of potential.
a greeting
-
Re: VB6 Web Site/App Server
Great, glad it's working better now and thanks for letting me know.
-
Re: VB6 Web Site/App Server
it seems vbml is just html file, why not just use html file?
-
Re: VB6 Web Site/App Server
G'Day Loquat
Bro is taking a break, so I'm southern hemisphere support :)
The official line is "Working as designed" - so 'Yes' not .html, but .vbml, which I really like, it is Bro's version of .php ( Pre-Processing )
Just my 2cs worth
-
1 Attachment(s)
Re: VB6 Web Site/App Server
Thanks for the support @jg.sa! You're 99% correct, but I'd like to clarify that VBML has a *much* smaller scope that PHP. I've never used PHP but AFAIK it is a Turing-complete language that is embedded into comments in HTML files.
VBML's scope is much more limited. While it is also embedded into comments in HTML files, it is only a "hook" into your VB6 code via this VBWebAppServer project. VBML is essentially a keyword and some optional parameters that can be sent to a VBWebAppServer hosted class for dynamic conversion to HTML "snippets" that will replace the HTML/VBML comment. The combined document will be served back to the requesting browser as HTML. The idea is to spend as much time as possible coding the dynamic parts of a web page in VB6, and as much time as possible coding the static parts in HTML.
For the visually minded:
Attachment 182997
-
Re: VB6 Web Site/App Server
Some good news on the Wine front - Zebediah Figura has fixed the problem with 6.x, so I suspect an update will be coming soon. More info here: https://bugs.winehq.org/show_bug.cgi?id=52024
-
1 Attachment(s)
Re: VB6 Web Site/App Server
A little Christmas present for you all!
I've added a very simple LogIn/LogOut process to the page/app:
Attachment 183420
Logging in doesn't really do anything, it's just an example showing the use of Cookies and the new CAppHelperUsers class.
There's one user included with the demo, email: [email protected], password: password
There are also a few bug fixes in the latest version (link is in the first post).
Enjoy!
-
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jpbro
Wow, thanks to the both of you...
(you really hung in there, compiling wine, making bisections + nice communication, BTW) :)
Olaf
-
Re: VB6 Web Site/App Server
Thanks Olaf, it was definitely a learning experience. Good thing Zebediah had a clue as to where the bug was though, I think it would have taken me a few more months to get there bisecting!
-
Re: VB6 Web Site/App Server
Some notes on the new CAppHelperUsers class. It has the following methods (which should all be fairly self-explanatory):
Code:
Public Function CreateUser(ByVal p_EmailAddress As String, ByVal p_DisplayName As String, ByVal p_Password As String) As String
Call this method to create a new user account. The account will be given a permission level of "unauthenticated" to start. Returns a unique user ID. You should probably keep this on the server side.
Code:
Public Function IsUserKnown(ByVal p_EmailAddress As String) As Boolean
Returns True if a user exists in the users.sqlite database users table. Otherwise returns False.
Code:
Public Function IsUserAuthenticated(ByVal p_EmailAddress As String) As Boolean
Returns True if the user has been authenticated (for example, by clicking a link in an email or copy & pasting a code that you send them. You will have to implement this part yourself).
Code:
Public Function IsUserLoggedIn(ByVal p_UserIdOrEmailAddress As String, ByVal p_SessionToken As String) As Boolean
Returns True if the user is logged into an active session. Otherwise returns False.
Code:
Public Function LoginUser(ByVal p_EmailAddress As String, ByVal p_Password As String) As String
Call to login a user by their email address & password. Returns a unique session token that should be sent to the client in a Cookie.
Code:
Public Function LogoutUser(ByVal p_EmailAddress As String) As Boolean
Call the log a user out of all their sessions.
Code:
Public Function LogoutSession(ByVal p_SessionToken As String) As Boolean
Call to log a user out of a single session (the session token will usually be stored in a Cookie).
Code:
Public Function IsSessionActive(ByVal p_SessionToken As String) As Boolean
Returns True if a particular session is active/not expired. Otherwise returns False.
Code:
Public Property Get UserPermissionLevel(ByVal p_EmailAddress As String) As e_UserPermissionLevel
Returns a user's account permission level. Possible values are:
Code:
userpermissionlevel_Banned = -1
userpermissionlevel_Unknown = 0
userpermissionlevel_Unauthenticated = 1
userpermissionlevel_Normal = 2
userpermissionlevel_SuperAdmin = &H7FFFFFFF
Code:
Public Property Let UserPermissionLevel(ByVal p_EmailAddress As String, ByVal p_PermissionLevel As e_UserPermissionLevel)
Sets a user's permission level. Use one of the enum values shown above.
Code:
Public Property Get UserInfoFromSessionToken(ByVal p_SessionToken As String, Optional ByVal p_GetIfExpired As Boolean) As CUserInfo
Get a CUserInfo class (by unique session token) with all of a user's account info.
Code:
Public Sub ActionPerformed(ByVal p_SessionToken As String)
Call whenever the user requests something from the server to keep their session alive. Sessions will expire after 1800 seconds currently, but I will likely make this configurable.
-
Re: VB6 Web Site/App Server
I tried to test it on my machine but got the following error
Public Function dateVbLocalToVbUtc(ByVal p_LocalDate As Date) As Date
''dateVbLocalToVbUtc = p_LocalDate - New_C.UTC.LocalOffs
End Function
When I tried removing it, it worked fine... the code in that project was too difficult for me to edit...
-
Re: VB6 Web Site/App Server
What was the exact error message?
-
1 Attachment(s)
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jpbro
What was the exact error message?
Thank you, I don't understand why... when I run the code for the first time, it gives me an error... after I run it again, it doesn't give an error anymore... the code in that project involved many problems, so I do not know too
Attachment 183422
-
Re: VB6 Web Site/App Server
I'm not sure when the UTC class was added to RC6 (I only noticed myself a few days ago or so). I would try updating RC6 to the latest version available at vbrichclient.com. It should be version 6.0.9 to be compatible with this project.
-
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jpbro
I'm not sure when the UTC class was added to RC6 (I only noticed myself a few days ago or so). I would try updating RC6 to the latest version available at vbrichclient.com. It should be version 6.0.9 to be compatible with this project.
I use the old version so I report that error ( RC6.dll Version 6.0.0.4 )
I just downloaded the new version and it's good to use
-
Re: VB6 Web Site/App Server
Great, glad it's working now :)
-
Re: VB6 Web Site/App Server
-
Re: VB6 Web Site/App Server
G'Day Bro
I missed this 'upgrade' as I have been very busy with the summer of cricket ( SOC ) and the Aussies thrashing the poms at their own game :)
This code change is exactly what I have been wanting to do, it is a bit scary how you are able to read my mind !!!
Keep up the gr8 work.
I will be ready in a couple of weeks to create the contacts system I have been designing as a web version of outlook, internal name saseCon.
The SOC allows me to cut code in front of the TV, so are you pausing dev. on this system in the near future, I will probably need 10 days, funny that being 2 x cricket test matches.
Then I can hand it back with a very poor UI for you or someone else to tart up.
I was thinking of using TABS so it is similar looking to Outlook forms, do you have any ideas / prefs ?
-
5 Attachment(s)
Re: VB6 Web Site/App Server
I thought I would share my experience migrating VBWebAppServer to TwinBasic:
I used the new Import from Visual Basic feature of TwinBasic, and overall it has worked surprisingly well:
Attachment 183444
Off the bat though, I had a few issues appear in the Problems pane. One is currently unresolvable, One required a code change, and the rest were warnings that were my fault. I forgot to declare a return variable type, so the compiler warned that it would default to a Variant. In all of those cases, I didn't want a Variant type so this was a very nice warning to get!
The unresolvable issue is that tB's App object doesn't have a ProductName property (yet), so I will have to open an issue for this. In the meantime, I've just cleared out that code and use App.ExeName instead (which is supported).
The issue that required a code change was that I was using App.LogMode for InIDE testing. tB's App object doesn't support LogMode, so I had to switch that code to the new App.IsInIde property. No big deal.
One note about errors in tB. Right now you get a squiggly underline on an error in tB. It would be nice to have an option to also highlight or outline the whole line of code. I'm used to seeing a red highlighted code line in VB6, and it really jumps out more.
Anyway, after getting rid of a handful of errors and warnings, I want to try to compile the EXE. It took a minute to find out where to compile the EXE as I am used to going to the File menu > Make. I couldn't find a build option in any menu, but I did eventually find the Build icon down in the TWINBASIC tool pane:
Attachment 183445
Just a thought, but it might be better to have the Build button beside the Active Build combo, so that all the build related stuff is together and more easily discoverable:
Attachment 183446
Back to the matter at hand, I finally tried compiling to a Win32 target EXE. At first I was confused because clicking the Build button didn't seem to do anything other than flash the cursor. I tried it a few times, and nothing. Assuming the compiler had crashed, I tried the "Restart Compiler" and then tried rebuilding, but no dice.
I then thought to check the other tabs (output, terminal, and debug console) and finally I saw that the Debug Console window was showing that the linker was successfully creating the output file. It would be nice if tB would do something like popup a toast window, or automatically switch you to the debug console when Build is clicked, so you know it has actually done some work.
Attachment 183442
Another thing related to compiling that would be nice: In the debug console window, it shows a SUCCESS message upon compile with a link to the compiled EXE. Ctrl+Clicking the link attempts to open the EXE in VS Code, which isn't very useful. Right-click options to Open Target Folder, Launch EXE, and Open Target Folder in Command Prompt (for command line only builds) would be very handy.
Once compiled, the first difference I notice is the file size. 220kb for VB6 vs. 847kb for tB. That's to be expected though as tB executables run without needing a separate runtime. It's also early days for the tB compiler/linker so perhaps it will produce somewhat smaller binaries in the future (perhaps not though as more features get added!). Might be interesting to have an option to have tB split out a separate tb.dll to the Build and let the EXEs share it. This would be especially useful for use-cases like VBWebAppServer, where I may be running hundreds of instances.
It was now the moment of truth, let's run this thing! The command-line run produced no errors, and visiting http://127.0.0.1:8080 produced this:
Attachment 183443
Successful!
Or was it? I decided to check the memory situation again to see how tB binaries compared to VB6. When running a VB6 compiled instance of VBWebAppServer, memory seems to stabilize at 13-14MB no matter how many times I refresh the page in my browser. The tB compiled instance seems to have a memory leak, after continually refreshing the page in the browser, memory use slowly climbed (occasionally falling back a bit, but then continuing to climb never to be fully released). I'm not yet sure if this is a bug in my code that the VB6 compiler is smarter about handling without chewing up memory, or if it's a bug in the tB compiler. I'll have to run some more tests.
Lastly, I would like to have tested a 64-bit build to, but VBWebAppServer references a 32-bit DLL (RC6), so this is currently impossible. I'd be interested to know from Olaf if there is any possibility to compile a 64-bit version of RC6, or if there it relies too much relying on a 32-bit environment for this to be possible. Also, I'd be curious to know if some kind of 32-bit AXDLL <->64-bit tB EXE "bridge" could be created, or if this is technically impossible or just plain too difficult? My use-case would be to create Office Add-ins that use some RC6 objects (CRpcConnection, CCollection, CConnection, & CRecordset - none of the visual Cairo stuff though). Again, I have no idea if such a thing is possible, but if so, then it would be awesome.
In the end, I'm very impressed with tB so far. It was relatively painless to take a non-trivial VB6 application and get it to compilie with tB. I'm looking forward to seeing tB continue to develop!
-
Re: VB6 Web Site/App Server
Thanks jpbro, great to see a real world experience of porting to twinBASIC. Note that AppObject support is still in progress - see https://github.com/WaynePhillipsEA/twinbasic/issues/143. Also, multi-threading support is planned, so in future you might not need to use multiple processes to scale.
-
Re: VB6 Web Site/App Server
Hi @mansellan, yes you are right I shouldn't have opened a new issues for the App object...I thought for sure I searched for it, but maybe I just searched for the missing "Screen" object because I was trying to compile some other code that uses Screen.MousePointer and it was failing. Sorry for the noise over there!
Re: multi-threading, it will be interesting the see how this gets implemented in tB. Right now I use Olaf's RC6 mutli-threading classes with success when I need that, but for app servers I've recently started using a separate process per connection approach for a few reasons:
1) Sometimes it can be nice to have access to 2GB of RAM per connection (rare, admittedly).
2) A crash only takes down one request, not X requests.
3) A deadlocked or infinitely looping process only costs you one responder, while threaded may cost you X responders.
4) A watchdog can terminate a busted process relatively cleanly, but not so much for terminating a thread.
Granted that 2 & 3 shouldn't happen in a perfect world, but sometimes my code has bugs (please don't tell anyone)!
-
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jg.sa
I missed this 'upgrade' as I have been very busy with the summer of cricket ( SOC ) and the Aussies thrashing the poms at their own game :)
Sounds good to me, it's winter here on this side of the globe, albeit a bit of a mild one so far.
Quote:
Originally Posted by
jg.sa
This code change is exactly what I have been wanting to do, it is a bit scary how you are able to read my mind !!!
Keep up the gr8 work.
I'm gifted that way ;) Keep in mind that this is very much a work in progress, so bugs are likely, and everything is still subject to change.
Quote:
Originally Posted by
jg.sa
I will be ready in a couple of weeks to create the contacts system I have been designing as a web version of outlook, internal name saseCon.
The SOC allows me to cut code in front of the TV, so are you pausing dev. on this system in the near future, I will probably need 10 days, funny that being 2 x cricket test matches.
When you get a chance to give it a try, let me know if you run in to any problems/bugs and I will do my best to help.
Quote:
Originally Posted by
jg.sa
Then I can hand it back with a very poor UI for you or someone else to tart up.
I was thinking of using TABS so it is similar looking to Outlook forms, do you have any ideas / prefs ?
Well, UI stuff isn't my strongest area, but tabs are generally understood. They seem to be rare on the web though, with slide-out hamburger menus being more popular these days. Might be something to consider.
-
Re: VB6 Web Site/App Server
I just changed the attachment in the first post to the latest version. No major changes, I just made some modifications so that the project can be imported into TwinBasic without getting any errors/warnings.
-
Re: VB6 Web Site/App Server
Looks like TwinBasic did have a memory leak after all, but Wayne has fixed it in version 0.13.60. I can confirm that VBWebAppServer no longer appears to be leaking memory when compiled with the latest version TwinBasic. Thanks Wayne!
-
Re: VB6 Web Site/App Server
Just updated the source in post #1 with a small change. I stupidly forgot to set the "AsHex" parameter in some RC6 SHA method calls, so it was returning byte arrays that were being concatenated with strings. There's no new functionality.
-
1 Attachment(s)
Re: VB6 Web Site/App Server
Dear Sir!
I can't run this interesting project at my machine (Win10 64)
1) I'm placed files into /App/System (cairo_sqllite.dll,DirectCOM.dll,RC6.dll(version: 6.0.0.9))
2) Compile VBWebAppServer.exe to the folder /App
3) Then start the server
VBWebAppServer.exe /spawn 10/ip 127.0.0.1 /port 5000
4) In browser go to the 127.0.0.1:5000
nothing happens
p.s. also, if i'm type port 8080, then i getting error like yokesee above:
***ERROR: -2147221504 An instance is already running at 127.0.0.1:8080
Attachment 183542
-
Re: VB6 Web Site/App Server
It sounds like everything is setup properly and the command line looks good, so I'm not sure what's going wrong. Are you sure you've compiled the latest version (available in the first post)?
-
Re: VB6 Web Site/App Server
A couple of others things to consider:
Some browsers now assume https:// if you don't supply a protocol. Does going to http://127.0.0.1:5000 work?
It's possible that your firewall is blocking VBWebAppServer.exe, so make sure you've allowed it to have network access.
-
Re: VB6 Web Site/App Server
That error looks pretty clear. It looks like he is running multiple instances and your project is checking for that.
-
Re: VB6 Web Site/App Server
Quote:
Originally Posted by
jpbro
A couple of others things to consider:
Some browsers now assume https:// if you don't supply a protocol. Does going to
http://127.0.0.1:5000 work?
It's possible that your firewall is blocking VBWebAppServer.exe, so make sure you've allowed it to have network access.
Yes, http is work!
but only on 5000 port.
8080 don't work.
After command /stop also don't work.