Wtx ~ Wt Extension Library
WtxLib
Part 2 ~ Creating an "active" web server with Wt

This document is a continuation of Part 1 ~ Creating a Simple (linux) Wt4 "static file" Server from Scratch tutorial. In that previous tutorial, we downloaded and built the Wt-4 library set, and then built a simple web server capable of serving up simple static web files.

But now we want to develop a 'live' website, and release that phenominal cosmic powa of Wt that reporters are talking about! This is actually (relatively) fairly simple as well. Yes, a little more code than before, it not too bad, eh? Let's get to it!

Back to our main.cpp program file, we're going to add a few lines:

mark@lsus1:~/projects/demoapp $ cd src
mark@lsus1:~/projects/demoapp/src $ cat main.cpp
#include <Wt/WServer.h>
#include <Wt/WApplication.h>
#include <Wt/WEnvironment.h>
#include <Wt/WContainerWidget.h>
#include <Wt/WText.h>
class DemoApp
: public Wt::WApplication
{
public:
DemoApp(const Wt::WEnvironment &env)
: Wt::WApplication( env )
{
root()-> addNew<Wt::WText>("Hello World!");
root()-> addNew<Wt::WBreak>();
root()-> addNew<Wt::WText>("It's great to be alive!");
}
};
int main(int argc, char** argv)
{
try
{
Wt::WServer server( argc, argv );
server.addEntryPoint
(
Wt::EntryPointType::Application,
[](const Wt::WEnvironment &env)
{
return std::make_unique<DemoApp>(env);
},
"/site"
);
server.run();
}
catch( Wt::WServer::Exception & e )
{
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
}

Let's go through this bit by bit.

The first thing to do is sub-class the WApplication object like this:

class DemoApp
: public Wt::WApplication
{
public:
DemoApp( const Wt::WEnvironment & env )
: Wt::WApplication( env )
{
root()-> addNew<Wt::WText>("Hello World!");
root()-> addNew<Wt::WBreak>();
root()-> addNew<Wt::WText>("It's great to be alive!");
}
};

In the constructor of the class we access something called the root() container. The root() container is actually a WContainerWidget at the root of the browser window. It is the base 'div' element in the browser. So, anything that gets 'added' to the browser window gets added inside that base (root) 'div' element. In this case we added a WText object to the root() container, and the result should place the text "Hello World!" in the browser window.

Next, in the main() function, where the WServer is being initialized we added an 'entry point' to the WServer so that when a browser hits the server and makes a request, the server knows how to respond. In this case, if the browser makes the request http://localhost:8910/site then the WServer will instantiate a new DemoApp Application class and kick it off.

server.addEntryPoint
(
Wt::EntryPointType::Application,
[]( const Wt::WEnvironment &env )
{
return std::make_unique<DemoApp>(env);
},
"/site" <------------- URL designation for this app
);

Notice that when we create an 'entry point' to the server, we have to give the entry point a 'path'. In this case I designated the entry point to be "/site" so when that site URL is hit, this specific application class will be brought to life. There is an issue with this 'path' variable as it pertains to the WFileResouce service that being employed in the previous tutorial, but I'll address that shortly.

Note
There is one server 'instance' running at this time, but for every browser 'session' that requests an app there is a newly constructed WApplication object, so therefore, each browser 'session' is running in its own application and is therefore separated from any other running application. These 'sessions' are available from the WServer object.

When I hit the site from the browser with http://localhost:8910/site I can observe the following in the server console:

mark@lsus1:~/projects/wt/demoapp/build$ ./demoapp --http-port 8910 --http-address 0.0.0.0 --docroot=docroot
[2018-May-24 07:17:32.522] 641 - [info] "config: reading Wt config file: /opt/Wt4/etc/wt/wt_config.xml (location = './demoapp')"
[2018-May-24 07:17:32.523] 641 - [info] "WServer/wthttp: initializing built-in wthttpd"
[2018-May-24 07:17:32.523] 641 - [info] "wthttp: started server: http://0.0.0.0:8910"
[2018-May-24 07:17:38.306] 641 - [info] "Wt: session created (#sessions = 1)" <-------------------------------------- BROWSER REQUEST HAPPENED RIGHT HERE
[2018-May-24 07:17:38.306] 641 [/site Vsg6zSGQEQtYXNAV] [info] "WEnvironment: UserAgent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0"
192.168.1.33 - - [2018-May-24 07:17:38.308] "GET /site HTTP/1.1" 200 2221
[2018-May-24 07:17:38.308] 641 - [info] "WebRequest: took 2.198 ms"
192.168.1.33 - - [2018-May-24 07:17:38.392] "GET /site?wtd=Vsg6zSGQEQtYXNAV&request=style&page=1 HTTP/1.1" 200 88
[2018-May-24 07:17:38.392] 641 - [info] "WebRequest: took 42.774 ms"
192.168.1.33 - - [2018-May-24 07:17:38.398] "GET /resources/themes/default/wt.css HTTP/1.1" 404 85 <------------------ NOTE THE 404 FAILURE
192.168.1.33 - - [2018-May-24 07:17:38.399] "GET /resources/moz-transitions.css HTTP/1.1" 404 85
192.168.1.33 - - [2018-May-24 07:17:38.400] "GET /site?wtd=Vsg6zSGQEQtYXNAV&sid=721053147&webGL=true&scrW=1920&scrH=1080&tz=-300&htmlHistory=true&deployPath=%2Fsite&request=script&rand=17044273 HTTP/1.1" 200 37702
[2018-May-24 07:17:38.400] 641 - [info] "WebRequest: took 10.169 ms"
192.168.1.33 - - [2018-May-24 07:17:38.504] "POST /site?wtd=Vsg6zSGQEQtYXNAV HTTP/1.1" 200 49
[2018-May-24 07:17:38.504] 641 - [info] "WebRequest: took 0.56 ms"

Hey, now we're cooking with cheese!

The browser should have some text in it, with the words "Hello World! It's great to be alive!". If you inspect the page, you should see something like this:

<div id="o27pxbl" class="Wt-domRoot" style="height: 100%;">
<div id="Wt-timers" style="position:absolute;height:0.0px;"></div>
<div id="o27pxbn" style="height:100.0%;"> <---- THIS IS THE ROOT WCONTAINERWIDGET
<span id="o27pxcb"> <------------------------ THIS IS THE WTEXT WIDGET
Hello World!
</span>
<br id="o27pxcc"> <-------------------------- THIS IS THE WBREAK WIDGET
<span id="o27pxcd"> <------------------------ THIS IS THE OTHER WTEXT WIDGET
It's great to be alive!
</span>
</div>
<div id="o27pxc8" class="Wt-loading" style="display: none;">
Loading...
</div>
</div>

Very cool. Everything appears to be working. There's quite a bit going on here, so let's look at a few things.

First off, what's happening is the WServer object was given an 'entry point' associated with a URL "/site" such that when that URL was hit, the WServer would create a new WApplication object for it, and allow that WApplication object to serve up the content. The content that is being served up is just a couple of text messages.

What Wt does is it opens a little conversation with the browser to try to discover what the browser's capabilities are. If it detects that the browser supports java, then it sends to the browser a little wrapper script to 'contain' the website and turn it in to an AJAX-esque web page, that is live and actively connected back to the server. The actual web page is then loaded with all the necessary html tags, with ID values embedded such that the browser scripts can access those html tags and update them... dynamically. This means you can place a WWidget on a web page, and change it's values/contents in C++ and the Wt will automatically propagate those changes right in to the browser, and only update those browser DOM elements that actually need to be updated. This keeps the interactions between Wt and the browser very short, compact and fast, as the only data moving back and forth is the data required to keep the web page up to date. That's different than most web sites that require a total page refresh to get any updates applied. This makes Wt able to generate websites that run extremely fast.

Another thing that happens on first session start, that if Wt queries the browser and determines that the browser has limited abilities, or doesn't have the ability to run java or something, then the Wt session will incrementally dumb-down the link between the browser and Wt to the point where if the only thing the browser can handle is straight-basic-html with no scripting and no fancy formatting, then that's what Wt will use... and the web page will still look the same in the dumbed-down browser as it does in the high-tech advanced browser.

Now let's take a look at that 404 failure we saw on the server console.

[2018-May-24 07:17:38.392] 641 - [info] "WebRequest: took 42.774 ms"
192.168.1.33 - - [2018-May-24 07:17:38.398] "GET /resources/themes/default/wt.css HTTP/1.1" 404 85 <-- 404 ERROR
192.168.1.33 - - [2018-May-24 07:17:38.399] "GET /resources/moz-transitions.css HTTP/1.1" 404 85 <---- 404 ERROR

This 404 error indicates that the files that were requested by the browser were not able to be located by the server. In this case, these files are from the 'resources' folder. The 'resources' folder is the css folder provided by the Wt installation. To fix this all we need to do is link that resources folder in to our 'docroot' folder.

mark@lsus1:~/projects/wt/demoapp/build$ ln -s /opt/Wt4/share/Wt/resources ../src/docroot/resources
mark@lsus1:~/projects/wt/demoapp/build$ ./demoapp --http-port 8910 --http-address 0.0.0.0 --docroot=docroot
[2018-May-25 05:51:39.087] 7255 - [info] "config: reading Wt config file: /opt/Wt4/etc/wt/wt_config.xml (location = './demoapp')"
[2018-May-25 05:51:39.088] 7255 - [info] "WServer/wthttp: initializing built-in wthttpd"
[2018-May-25 05:51:39.088] 7255 - [info] "wthttp: started server: http://0.0.0.0:8910"
[2018-May-25 05:52:23.487] 7255 - [info] "Wt: session created (#sessions = 1)"
[2018-May-25 05:52:23.488] 7255 [/site eFtk2P4NooA8sNV9] [info] "WEnvironment: UserAgent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0"
192.168.1.33 - - [2018-May-25 05:52:23.489] "GET /site HTTP/1.1" 200 2221
[2018-May-25 05:52:23.489] 7255 - [info] "WebRequest: took 2.216 ms"
192.168.1.33 - - [2018-May-25 05:52:23.533] "GET /site?wtd=eFtk2P4NooA8sNV9&request=style&page=1 HTTP/1.1" 200 88
[2018-May-25 05:52:23.533] 7255 - [info] "WebRequest: took 28.405 ms"
192.168.1.33 - - [2018-May-25 05:52:23.535] "GET /resources/themes/default/wt.css HTTP/1.1" 200 20924 <-------------------- NO MORE ERROR
192.168.1.33 - - [2018-May-25 05:52:23.537] "GET /resources/moz-transitions.css HTTP/1.1" 200 6277
192.168.1.33 - - [2018-May-25 05:52:23.545] "GET /site?wtd=eFtk2P4NooA8sNV9&sid=309821055&webGL=true&scrW=1920&scrH=1080&tz=-300&htmlHistory=true&deployPath=%2Fsite&request=script&rand=903332185 HTTP/1.1" 200 37734
[2018-May-25 05:52:23.545] 7255 - [info] "WebRequest: took 14.317 ms"
192.168.1.33 - - [2018-May-25 05:52:23.634] "POST /site?wtd=eFtk2P4NooA8sNV9 HTTP/1.1" 200 49
[2018-May-25 05:52:23.634] 7255 - [info] "WebRequest: took 0.434 ms"

That's it! That's all that's needed to run a live AJAX-esque Wt active website!

For questions, comments, suggestions send email to mark@.nosp@m.lori.nosp@m.marks.nosp@m.olut.nosp@m.ions..nosp@m.com