So the steps of an standalone witty w/ custom resource server:
- create a server
- register a custom resource on a desired path
- start the server, hence its resources
- wait for server shutdown signal
- stop the server
Here is the snippet of the main.cpp, ignore all log-related plumbing:
#include <Wt/WServer>
#include <iostream>
#include "MyResource.h"
#include "log.h"
using namespace std;
using namespace Wt;
int main(int argc, char **argv) {
WLogger logger;
configLogger(logger);
try {
WServer server(argv[0], "");
try {
server.setServerConfiguration(argc, argv);
MyResource dr;
server.addResource(&dr, "/resource");
info(logger, "Starting resource server.");
if (server.start()) {
WServer::waitForShutdown();
server.stop();
} else {
fatal(logger, "Fatal error starting resource server.");
return 1;
}
return 0;
} catch (std::exception& e) {
fatal(logger, "Fatal error starting resource server.", e.what());
return 1;
}
} catch (WServer::Exception& e) {
fatal(logger, "Fatal error creating WServer.", e.what());
return 1;
} catch (exception& e) {
fatal(logger, "Fatal error occurred.", e.what());
return 1;
}
}
You may notice the creation and registration of MyResource, this is place where you provide the service implementation, specifically on the handleRequest() method, take a look at MyResource.h:
#ifndef MYRESOURCE_H_
#define MYRESOURCE_H_
#include <Wt/WResource>
using namespace Wt;
using namespace Wt::Http;
class MyResource: public WResource {
public:
MyResource();
virtual ~MyResource();
protected:
virtual void handleRequest(const Request &request, Response &response);
};
#endif /* MYPRESOURCE_H_ */
The implemantation is very trivial, it's just an echo of the request content also including some extra data like content type, content length and request method: GET, POST, etc. Enjoy MyResource.cpp:
#include <iostream>
#include <Wt/Http/Response>
#include "MyResource.h"
using namespace std;
using namespace Wt::Http;
MyResource::MyResource() {
}
MyResource::~MyResource() {
}
void MyResource::handleRequest(const Request& request, Response& response) {
string method = request.method();
string contentType = request.contentType();
int contentLength = request.contentLength();
char* buffer = new char[contentLength + 1];
request.in().read(buffer, contentLength);
buffer[contentLength] = 0;
response.setMimeType("application/xml");
ostream& out = response.out();
out << "<?xml version='1.0' encoding='utf-8' ?>" << endl;
out << "<reply>" << endl;
out << "<method>" << method << "</method>" << endl;
out << "<contentType>" << contentType << "</contentType>" << endl;
out << "<contentLenght>" << contentLength << "</contentLenght>" << endl;
out << "<body>" << buffer << "</body>" << endl;
out << "</reply>";
delete[] buffer;
}
The reamining stuff is just plumbing as I said before, here you got log.h:
#ifndef LOG_H_ #define LOG_H_ #include <Wt/WLogger> using namespace std; using namespace Wt; void info(WLogger& logger, const string& message); void fatal(WLogger& logger, const string& message, const char* what); void fatal(WLogger& logger, const string& message); void configLogger(WLogger& logger); #endif /* LOG_H_ */
And log.cpp:
#include "log.h"
#include <iostream>
void info(WLogger& logger, const string& message) {
WLogEntry entry = logger.entry("info");
entry << WLogger::timestamp << WLogger::sep << WLogger::sep << '[' << "info"
<< ']' << WLogger::sep << message;
}
void fatal(WLogger& logger, const string& message, const char* what) {
WLogEntry entry = logger.entry("fatal");
entry << WLogger::timestamp << WLogger::sep << WLogger::sep << '['
<< "fatal" << ']' << WLogger::sep << message << what;
}
void fatal(WLogger& logger, const string& message) {
fatal(logger, message, "");
}
void configLogger(WLogger& logger) {
logger.addField("datetime", false);
logger.addField("type", false);
logger.addField("message", true);
logger.setFile("/var/log/resource.log");
}
Now compile an run the server, here in this case using standalone server mode instead of fast cgi mode, but also works w/ fast cgi variant:
$ g++ log.cpp MyResource.cpp main.cpp -lwthttp -oresource
Run the server:
$ ./resource --http-address 0.0.0.0 --http-port 80 --docroot=. INFO: Opened log file (/var/log/resource.log). [2013-May-07 19:52:11.046985] 9658 - [info] "config: reading Wt config file: /etc/wt/wt_config.xml (location = './resource')" [2013-May-07 19:52:11.047757] 9658 - [info] "WServer/wthttp: initializing built-in wthttpd" [2013-May-07 19:52:11.048027] 9658 - [info] "wthttp: started server: http://0.0.0.0:80"
Finally test the service using a simple call:
$ curl -X POST -H "Content-Type: application/xml" -d"<payload>PAYLOAD GOES HERE!</payload>" http://localhost/resource
<?xml version='1.0' encoding='utf-8' ?> <reply> <method>POST</method> <contentType>application/xml</contentType> <contentLenght>37</contentLenght> <body><payload>PAYLOAD GOES HERE!</payload></body> </reply>Very simple as you can see!
Very nice. Thanks!
ReplyDelete-Jim
Very clear article. I like Wt, too.
ReplyDeleteStage Rental Chicago
ReplyDeleteSpeaker Rental Chicago
LED Wall Rental Chicago
Best barber in surrey
ReplyDelete