Server¶
Server provide HTTP technologies integrations under a common interface. They inherit from GLib.Application, providing an optimal integration with the host environment.
General¶
Basically, you have access to a DBusConnection to communicate with other process and a GLib.MainLoop to process events and asynchronous work.
- an application id to identify primary instance
startup
signal emmited right after the registrationshutdown
signal just before the server exits- a resource base path
- ability to handle CLI arguments
The server can be gracefully terminated by sending a SIGTERM signal to the process.
Load an implementation¶
Server implementations are dynamically loaded using GLib.Module. It makes it possible to define its own implementation if necessary.
The shared library name must conform to libvsgi-<name>
with the appropriate
extension. For instance, on GNU/Linux, the CGI module is stored in
${LIBDIR}/vsgi/servers/libvsgi-cgi.so
.
To load an implementation, use the Server.new
factory, which can receive
GObject-style arguments as well.
var cgi_server = Server.new ("cgi", "application-id", "org.valum.example.CGI");
if (cgi_server == null) {
assert_not_reached ();
}
cgi_server.set_application_callback ((req, res) => {
return res.expand_utf8 ("Hello world!");
});
For typical case, use Server.new_with_application
to initialize the
instance with an application identifier and callback:
var cgi_server = Server.new_with_application ("cgi", "org.example.CGI", (req, res) => {
return true;
});
For more flexibility, the ServerModule
class allow a more fine-grained
control for loading a server implementation. If non-null, the directory
property will be used to retrieve the implementation from the given path
instead of standard locations.
The computed path of the shared library is available from path
property,
which can be used for debugging purposes.
var directory = "/usr/lib64/vsgi/servers";
var cgi_module = new ServerModule (directory, "cgi");
if (!cgi_module.load ()) {
error ("could not load 'cgi' from '%s'", cgi_module.path);
}
var server = Object.new (cgi_module.server_type);
Unloading a module is not necessary: once initially loaded, a use count is kept so that it can be loaded on need or unloaded if not used.
Warning
Since a ServerModule
cannot be disposed (see GLib.TypeModule), one
must be careful of how its reference is being handled. For instance,
Server.new
keeps track of requested implementations and persist them
forever.
Mixing direct usages of ServerModule
and Server.@new
(and the likes) is
not recommended and will result in undefined behaviours if an implementation is
loaded more than once.
DBus connection¶
GLib.Application will automatically register to the session DBus bus, making IPC (Inter-Process Communication) an easy thing.
It can be used to expose runtime information such as a database connection details or the amount of processing requests. See this example of DBus server for code examples.
This can be used to request services, communicate between your workers and interact with the runtime.
var connection = server.get_dbus_connection ()
connection.call ()
Options¶
Each server implementation can optionally take arguments that parametrize its runtime.
If you build your application in a main block, it will not be possible to
obtain the CLI arguments to parametrize the runtime. Instead, the code can be
written in a usual main
function.
public static int main (string[] args) {
Server.new ("http", "org.vsgi.App", (req, res) => {
res.status = Soup.Status.OK;
return res.body.write_all ("Hello world!".data, null);
}).run (args);
}
If you specify the --help
flag, you can get more information on the
available options which vary from an implementation to another.
build/examples/fastcgi --help
Usage:
fastcgi [OPTION...]
Help Options:
-h, --help Show help options
--help-all Show all help options
--help-gapplication Show GApplication options
Application Options:
--forks=0 Number of fork to create
-s, --socket Listen to the provided UNIX domain socket (or named pipe for WinNT)
-p, --port Listen to the provided TCP port
-f, --file-descriptor=0 Listen to the provided file descriptor
-b, --backlog=10 Listen queue depth used in the listen() call
Forking¶
To achieve optimal performances on a multi-core architecture, VSGI support forking at the server level.
Warning
Keep in mind that the fork
system call will actually copy the whole
process: no resources (e.g. lock, memory) can be shared unless
inter-process communication is used.
The --forks
option will spawn the requested amount of workers, which should
optimally default to the number of available CPUs.
server.run ("app", {"--forks=4"});
It’s also possible to fork manually via the fork
call.
using VSGI.HTTP;
var server = new Server ();
server.listen (options);
server.fork ();
new MainLoop ().run ();
It is recommended to fork only through that call since implementations such as CGI are not guaranteed to support it.
Listen on distinct interfaces¶
Typically, fork
is called after listen
so that all processes share the
same file descriptors and interfaces. However, it might be useful to listen
to multiple ports (e.g. HTTP and HTTPS).
using VSGI.HTTP;
var server = new Server ();
var parent_options = new VariantDict ();
var child_options = new VariantDict ();
// parent serve HTTP
parent_options.insert_value ("port", new Variant.int32 (80));
// child serve HTTPS
child_options.insert_value ("https");
child_options.insert_value ("port", new Variant.int32 (443));
if (server.fork () > 0) {
server.listen (parent_options);
} else {
server.listen (child_options);
}
new MainLoop ().run ();