Documentation
First steps
First, install the DUB package manager to let it handle downloading and building of vibe.d and derived applications. On non-Windows systems, a number of additional dependencies needs to be installed. See the project description on GitHub for details.
Manual building (e.g. using RDMD) is a possible alternative, but you have to make sure that external libraries are linked in (such as OpenSSL) and that the import directories for all sub projects of vibe.d (such as vibe-core and vibe-http) are properly set. You can run DUB with the -v
switch to see the actual compiler command line if in doubt.
The easiest way to get started is to run the following command from your projects directory:
cd /path/to/my/projects dub init <project-name> -t vibe.d
This will create a new directory with the given name and creates the basic directory structure that is recommended for vibe.d projects. Running it will start up an HTTP server on port 8080, serving a simple plain-text page. As the next step, you can go ahead and edit the source/app.d
file. If you want to publish your project, you should also edit the dub.json
/dub.sdl
file and properly fill in all fields, including a "license" field.
Once you have the project in place, simply run DUB from the project's root directory and it will get all dependencies, compile the application, and run it:
cd path/to/project
dub
Starting Performing "debug" build using ldc2 for x86_64.
Up-to-date diet-ng 1.8.1: building configuration [library]
Up-to-date taggedalgebraic 0.11.22: building configuration [library]
Up-to-date eventcore 0.9.28: building configuration [winapi]
Up-to-date vibe-container 1.3.0: building configuration [library]
Up-to-date vibe-core 2.8.2: building configuration [winapi]
Up-to-date vibe-inet:textfilter 1.0.0: building configuration [library]
Up-to-date vibe-serialization 1.0.1: building configuration [library]
Up-to-date vibe-stream 1.1.0: building configuration [library]
Up-to-date vibe-inet 1.0.0: building configuration [library]
Up-to-date mir-linux-kernel 1.0.1: building configuration [library]
Up-to-date vibe-inet:crypto 1.0.0: building configuration [library]
Up-to-date vibe-stream:tls 1.1.0: target for configuration [openssl-3.0] is up to date.
Up-to-date vibe-http 1.0.0: building configuration [library]
Up-to-date vibe-d:mail 0.10.0: building configuration [library]
Up-to-date vibe-d:mongodb 0.10.0: building configuration [library]
Up-to-date vibe-d:redis 0.10.0: building configuration [library]
Up-to-date vibe-d:utils 0.10.0: building configuration [library]
Up-to-date vibe-d:web 0.10.0: building configuration [library]
Up-to-date vibe-d 0.10.0: building configuration [library]
Building vibe-test ~master: building configuration [application]
Linking vibe-test
Finished To force a rebuild of up-to-date targets, run again with --force
Copying files for vibe-stream:tls...
Running vibe-test.exe
[main(----) INF] Listening for requests on http://[::1]:8080/
[main(----) INF] Listening for requests on http://127.0.0.1:8080/
[main(----) INF] Please open http://127.0.0.1:8080/ in your browser.
Recommended project structure
The recommended directory structure for a project, which the "dub init" command establishes, is separated into three base folders:
appname/ source/ app.d public/ images/ styles/ style.css views/ layout.dt index.dt dub.sdl
For a simple web application, the 'app.d' file could look similar to this one:
import vibe.vibe; void index(HTTPServerRequest req, HTTPServerResponse res) { res.render!("index.dt", req); } void main() { auto router = new URLRouter; router.get("/", &index); auto settings = new HTTPServerSettings; settings.port = 8080; listenHTTP(settings, router); runApplication(); }
The 'views' sub folder is automatically searched for templates instantiated with render
. The two templates in the example structure might look like this:
doctype html html head title Example page body block body
extends layout block body h1 Example page - Home p Hello, World!
This structure makes use of the blocks/extensions feature of the Diet template compiler. For more advanced template features see the Diet template documentation.
Finally, the "dub.sdl" (SDLang) lets the vibe.d package manager automatically download and compile dependency libraries. This file will also provide the description that is needed to later put your own library into the public extension registry.
name "appname" description "My fabulous new app" copyright "Copyright (C) 2000 Me. All rights reserved." license "AGPL-3.0" homepage "http://appname.org" authors "Hans Wurst" dependency "vibe-d" version="~>0.10.0"
DUB also provides support for the original JSON based syntax. The filename to use is "dub.json" in this case:
{ "name": "appname", "description": "My fabulous new app", "copyright": "Copyright (C) 2000 Me. All rights reserved.", "license": "AGPL-3.0", "homepage": "http://appname.org", "authors": ["Hans Wurst"], "dependencies": { "vibe-d": "~>0.10.0" } }
Example projects
A library of example projects is maintained in the Git repository. Most things not covered in this document can be found there in the form of code: Example projects
To run the examples locally, you can either download the repository as a zip file, or use GIT to get the examples:
git clone https://github.com/vibe-d/vibe.d.git
To run the "http_server" example, type:
dub run --root=vibe.d/examples/http_server
HTTP
Server configuration
The HTTP server supports a number of configuration options to customize its behavior. By default, the server will listen on all local network adapters on port 80 and will perform complete request parsing. The following list gives an overview of the most common settings:
-
port
- The port on which the HTTP server shall listen
-
bindAddresses
- A list of all interfaces on which the server shall listen. IPv4 and IPv6 addresses, as well as domain names are supported.
-
options
- Controls optional features of the web server. Certain options can be disabled to increase speed or to decrease memory usage. By default, the following options are enabled: parseURL, parseQueryString, parseFormBody, parseJsonBody, parseMultiPartBody, parseCookies. Enabled options are ORed together.
-
errorPageHandler
-
Provides a way to customize error pages. For example:
void errorPage(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error) { res.render!("error.dt", req, error); } void main() { auto settings = new HTTPServerSettings; settings.errorPageHandler = toDelegate(&errorPage); // ... }
Inside of the error.dt template, the variables req, code and msg are available in this example. -
tlsContext
- Lets the server operate as an HTTPS server. You should probably also set the port to 443 in case this field is set.
HTTPS
To serve HTTPS connections, the configuration simply needs to have a TLS context that has the appropriate certificate and private key files set:
auto settings = new HTTPServerSettings; settings.port = 443; settings.bindAddresses = ["127.0.0.1"]; settings.tlsContext = createTLSContext(TLSContextKind.server); settings.tlsContext.useCertificateChainFile("server-cert.pem"); settings.tlsContext.usePrivateKeyFile("server-key.pem");
Selecting the TLS provider
Two TLS providers are currently supported, OpenSSL and the D port of Botan. By default, OpenSSL 3.x is used to provide TLS/HTTPS functionality. To select a different provider, or to avoid compiling with TLS support enabled, the appropriate build configuration of the vibe-d:tls sub package needs to be selected:
dependency "vibe-stream:tls" version="~>1.0" subConfiguration "vibe-stream:tls" "botan"
When using a JSON based package recipe, the two lines have to be inserted as follows (the "…" are just placeholders for other possible directives):
{ … "dependencies": { … "vibe-stream:tls": "~>1.0" }, "subConfigurations": { … "vibe-stream:tls": "botan" } }
Available configurations:
-
"notls"
- Don't compile with TLS support
-
"openssl"
- OpenSSL, auto-detect version (default)
-
"openssl-3.0"
- OpenSSL 3.0.x (default in Windows)
-
"openssl-1.1"
- OpenSSL 1.1.x
-
"openssl-1.0"
- OpenSSL 1.0.x
-
"openssl-static"
- Uses the openssl-static package to provide static OpenSSL 3.x binaries on various platforms
-
"botan"
- D port of Botan
Routing
The
URLRouter
class provides a convenient way to let different functions handle different URLs. It supports static path matching, variable placeholders and wild-cards. Any matched variable will be available as an entry in the params
dictionary.
In addition to the path, the HTTP method is also used for matching requests. Each HTTP method has a corresponding method in the code.prettyprint URLRouter class (e.g. get
or post
). The following example will route all GET requests matching the path scheme "/users/*"
to the userInfo
handler and serve all other GET requests using the files in the public folder, see serveStaticFiles
.
import vibe.vibe; void userInfo(HTTPServerRequest req, HTTPServerResponse res) { auto username = req.params["user"]; render!("userinfo.dt", username)(res); } void addUser(HTTPServerRequest req, HTTPServerResponse res) { enforceHTTP("user" in req.form, HTTPStatus.badRequest, "Missing user field."); res.redirect("/users/"~req.form["user"]); } void main() { auto router = new URLRouter; router.get("/users/:user", &userInfo); router.post("/adduser", &addUser); router.get("*", serveStaticFiles("./public/")); // To reduce code redundancy, you can also // use method chaining: router .get("/users/:user", &userInfo) .post("/adduser", &addUser) .get("*", serveStaticFiles("./public/")); listenHTTP(new HTTPServerSettings, router); runApplication(); }
Diet templates
Vibe.d supports HTML templates with a syntax mostly compatible to Pug templates. They provide a concise way to dynamically generate the HTML code of the final web pages. D expressions and statements can be embedded and the full vibe.d API is available within templates.
Templates should reside somewhere inside the 'views' folder of a project. They are then rendered using the
render
function, which takes the template file name as the first template argument, followed by a list of variables that should be available to the template. Finally, it takes a
HTTPServerResponse
to render into.
The following example shows a number of features of the Diet template compiler. A full reference of the template syntax is found on the Diet templates page.
doctype html html head title My page: #{pageTitle} body h1= pageTitle p This is the content of this page. The | title "#{pageTitle}" is inserted dynamically. | We can also use loops and other D statements: block placeholder p - foreach(i, ch; pageTitle) | #{i+1}. character: #{ch} p.special.small This paragraph has the 'special' | and 'small' CSS classes p#footer This paragraph has the id 'footer'. #somediv. I'm a multiline text inside the div #somediv
Error pages
There are three ways in which an error page is sent back to the client:
-
An exception is thrown from the request handler or while parsing the request. By default, a 500 "Internal Server Error" is returned. By throwing a
HTTPStatusException
, the status code can be customized. - The request handler does not write a response. In this case the server automatically returns a 404 "Not Found" error.
- The request handler manually sets an error status to HTTPServerResponse.statusCode and writes a body. In this case, the error page will be written exactly as specified.
The
HTTPServerSettings
can be used to provide a custom error page handler. If one is provided, it is called for any of the first two conditions and must render an error page to the response object. If no handler is given, a simple plain-text error page is generated. See the HTTP server configuration section for an example.
Authentication
Currently, HTTP-Basic-Auth and HTTP-Digest-Auth authentication methods are implemented. Higher level mechanisms such as OAuth will be provided using extension libraries.
A simple way to plug authentication into a web application is to use the fall-through feature of the URLRouter
. If the user is properly authenticated, the
performBasicAuth
function will not do anything and the URLRouter will continue to match the request to all following routes. If, however, there is no authentication or if the username/password pair is not valid, it will throw a
HTTPStatusException
exception which generates a 403 error page so that the user is prompted with a password dialog on the browser side. The routing stops in this case.
Note that it is generally recommended to make use of the high level web framework when developing web application front ends. See the "web" example project for a way to implement session based authentication in such a setting.
import vibe.vibe; bool checkPassword(string user, string password) { return user == "admin" && password == "secret"; } void main() { auto router = new URLRouter; // the following two routes are accessible without authentication: router.get("/", staticTemplate!"index.dt"); router.get("/about", staticTemplate!"about.dt"); // now any request is matched and checked for authentication: router.any("*", performBasicAuth("Site Realm", toDelegate(&checkPassword))); // the following routes can only be reached if authenticated: router.get("/profile", staticTemplate!"profile.dt"); router.get("/internal", staticTemplate!"internal.dt"); // ... }
Sessions
Cookie based HTTP sessions are supported directly by the HTTP server. To be able to use them, you first have to set a
SessionStore
in the
HTTPServerSettings
. Sessions are then established by calling code.prettyprint.lang-d HTTPServerResponse.startSession and stopped using code.prettyprint.lang-d HTTPServerResponse.terminateSession. The returned
Session
object behaves as a key value store taking strings as keys and values.
import vibe.vibe; void login(HTTPServerRequest req, HTTPServerResponse res) { enforceHTTP("username" in req.form && "password" in req.form, HTTPStatus.badRequest, "Missing username/password field."); // todo: verify user/password here auto session = res.startSession(); session.set("username", req.form["username"]); session.set("password", req.form["password"]); res.redirect("/home"); } void logout(HTTPServerRequest req, HTTPServerResponse res) { if (res.session) res.terminateSession(); res.redirect("/"); } void checkLogin(HTTPServerRequest req, HTTPServerResponse res) { // force a redirect to / for unauthenticated users if (!req.session) res.redirect("/"); } void main() { auto router = new URLRouter; router.get("/", staticTemplate!"index.dt"); router.post("/login", &login); router.post("/logout", &logout); // restrict all following routes to authenticated users: router.any("*", &checkLogin); router.get("/home", staticTemplate!"home.dt"); auto settings = new HTTPServerSettings; settings.sessionStore = new MemorySessionStore; // ... }
Client requests
Client request are done using the requestHTTP
function.
import vibe.vibe; void main() { requestHTTP("http://google.com", (scope HTTPClientRequest req) { // could add headers here before sending, // write a POST body, or do similar things. }, (scope HTTPClientResponse res) { logInfo("Response: %s", res.bodyReader.readAllUTF8()); } ); }
Note that you can leave off the explicit `HTTPClientRequest` and `HTTPClientResponse` parameter types. They will be inferred automatically by the compiler.
A connection pool is used internally in conjunction with persistent HTTP connections (keep-alive) for maximum thoughput.
Web framework
Based on the low-level HTTP/HTML foundation, the high-level web application framework allows for faster and more solid web application development. It uses a class based declarative approach to avoid the boilerplate code that would otherwise usually be needed. Static typing is exploited as much as possible to avoid conversion errors, or errors accessing wrong runtime keys (such as a non-existent or mistyped form field).
The framework comes in two flavors, one for front end development, targeted at generating HTML pages and processing form requests, and one for REST based back end development, providing a transparent JSON/REST based RPC mechanism (client and server). Both of these components share the same basis and use the same approach to map class methods to routes of the URLRouter
.
For the usual case, both, the HTTP method and the matching path are inferred from the class method's name. In particular, the name is mapped to a certain HTTP method according to its prefix and the rest of the name is converted to a path name in a configurable style. On top of that, it is possible to use the @path
and @method
attributes to override these defaults.
HTTP method | Corresponding prefixes |
---|---|
GET | get , query , getter @property methods, methods named index |
POST | post , create , add , no prefix |
PUT | put , set , setter @property methods |
PATCH | patch , update |
DELETE | delete , erase , remove |
Web interface generator
The front end web interface generator automatically maps incoming query or POST form fields to method parameters, performing the necessary conversion and validation automatically. On top of that, it offers several convenience functions for rendering Diet templates, handling sessions and performing redirects - without directly accessing the underlying HTTPServerRequest
or HTTPServerResponse
object. This enables a completely statically checked and clean code style in most cases.
For those situations where more control is required, it is possible to simply declare parameters of type HTTPServerRequest
or HTTPServerResponse
to give a method full access. Note that this is in contrast to the REST interface generator covered below, which cannot give access to the request/response without losing the ability to generate the client side of the REST protocol. It does, however, provide a way to get around this, using the @before
attribute.
import vibe.http.router; import vibe.http.server; import vibe.web.web; void main() { auto router = new URLRouter; router.registerWebInterface(new WebInterface); auto settings = new HTTPServerSettings; settings.port = 8080; settings.sessionStore = new MemorySessionStore; listenHTTP(settings, router); } class WebInterface { private { // stored in the session store SessionVar!(bool, "authenticated") ms_authenticated; } // GET / void index() { bool authenticated = ms_authenticated; render!("index.dt", authenticated); } // POST /login (username and password are automatically read as form fields) void postLogin(string username, string password) { enforceHTTP(username == "user" && password == "secret", HTTPStatus.forbidden, "Invalid user name or password."); ms_authenticated = true; redirect("/"); } // POST /logout @method(HTTPMethod.POST) @path("logout") void postLogout() { ms_authenticated = false; terminateSession(); redirect("/"); } }
doctype 5 html head title Welcome body h1 Welcome - if (authenticated) form(action="logout", method="POST") button(type="submit") Log out - else h2 Log in form(action="login", method="POST") p User name: input(type="text", name="username") p Password: input(type="password", name="password") button(type="submit")
Localization
Using GNU gettext compatible .po translation files, it's possible to localize Diet templates at compile time. This just requires putting the translation files with the naming scheme <name>.<language>.po
into a path that is registered in the "stringImportPaths"
field of the dub.json. <language>
must be a language identifier of the form en_US
.
import vibe.web.web; struct TranslationContext { alias languages = TypeTuple!("en_US", "de_DE"); mixin translationModule!"example"; } @translationContext!TranslationContext class WebInterface { void index() { render!("index.dt"); } }
doctype 5 html head title& Welcome body h1& Welcome p& home.welcome.text
msgid "Welcome" msgstr "Welcome" msgid "home.welcome-text" msgstr "Hello, this is a translation example."
msgid "Welcome" msgstr "Willkommen" msgid "home.welcome-text" msgstr "Hallo, dies ist ein Übersetzungs-Beispiel."
REST interface generator
Similar to the browser oriented web interface generator, there is a machine communication oriented JSON/REST based interface generator. Method parameters are mapped to JSON fields and get serialized according to the usual serialization rules. In addition to the interface generator, there is also a client generator, which automatically implements a class that emits the proper REST calls to access the REST interface.
import vibe.core.core; import vibe.core.log; import vibe.http.router; import vibe.http.server; import vibe.web.rest; struct Weather { string text; double temperature; // °C } interface MyAPI { // GET /weather -> responds {"text": "...", "temperature": ...} Weather getWeather(); // PUT /location -> accepts {"location": "..."} @property void location(string location); // GET /location -> responds "..." @property string location(); } class MyAPIImplementation : MyAPI { private { string m_location; } Weather getWeather() { return Weather("sunny", 25); } @property void location(string location) { m_location = location; } @property string location() { return m_location; } } void main() { auto router = new URLRouter; router.registerRestInterface(new MyAPIImplementation); auto settings = new HTTPServerSettings; settings.port = 8080; listenHTTP(settings, router); // create a client to talk to the API implementation over the REST interface runTask({ auto client = new RestInterfaceClient!MyAPI("http://127.0.0.1:8080/"); auto weather = client.getWeather(); logInfo("Weather: %s, %s °C", weather.text, weather.temperature); client.location = "Paris"; logInfo("Location: %s", client.location); }); runApplication(); }
Database support
MongoDB
A native MongoDB driver is part of the distribution supporting the standard set of database operations. Data is exchanged using the
Bson
struct.
For an comprehensive documentation of MongoDB's operations see the MongoDB manual. The API reference contains the documentation for the driver.
import vibe.vibe; void main() { MongoClient client = connectMongoDB("127.0.0.1"); auto coll = client.getCollection("test.collection"); foreach (doc; coll.find(["name": "Peter"])) logInfo("Found entry: %s", doc.toJson()); }
Redis
A client for the structured storage server Redis is included in vibe.d. Commands and operations on Redis data types are implemented as instance methods of the client and of the RedisDatabase
class. The methods are named after their corresponding Redis command documented in the command reference.
On top of the low level interface, two high level modules, types
and idioms
are available to solve common tasks in a more convenient and type safe way. In addition to that, a Redis based HTTP session store is also included.
Raw TCP
Low level TCP connections are handled using the
TCPConnection
class, which implements the
ConnectionStream
interface. Connections can be established by either listening on a specific port for incoming connections or by actively connecting to a remote server.
Server
Listening for TCP connections is done using the
listenTCP
function. An implementation of a very simple echo server could look like this:
import vibe.vibe; void main() { listenTCP(7, (conn) { conn.write(conn) }); runApplication(); }
Calling
listenTCP
like this will listen on all local network devices. To listen only on a specific device, the bind address can be given as an additional parameter:
import vibe.vibe; void main() { listenTCP(7, conn => conn.write(conn), "127.0.0.1"); runApplication(); }
The address can be given as either an IPv4 or an IPv6 address string.
Client
Connecting to a TCP server is done with the
connectTCP
function. The following example gets the current time using the Daytime Protocol.
import vibe.vibe; void main() { auto conn = connectTCP("time-c.nist.gov", 13); logInfo("The time is: %s", conn.readAllUTF8()); }
Raw UDP
In addition to stream based TCP connections, packet based UDP communication is also supported. To open a UDP socket, use the
listenUDP
function with the appropriate port. It will return a
UDPConnection
instance, which can then be used to send and receive individual packets.
import vibe.appmain; import vibe.core.core; import vibe.core.log; import vibe.core.net; import core.time; void main() { runTask({ auto udp_listener = listenUDP(1234); while (true) { auto pack = udp_listener.recv(); logInfo("Got packet: %s", cast(string)pack); } }); runTask({ auto udp_sender = listenUDP(0); udp_sender.connect("127.0.0.1", 1234); while (true) { sleep(dur!"msecs"(500)); logInfo("Sending packet..."); udp_sender.send(cast(ubyte[])"Hello, World!"); } }); runApplication(); }
Advanced topics
Publishing on the DUB registry
The DUB registry contains packages that use the same package management as vibe.d. Many of them extend and supplement vibe.d's functionality. The packages are automatically downloaded if the corresponding entry in the "dependencies" section of the project's dub.json file is present.
If you have written an extension library yourself, you can register it in the DUB registry so others can easily make use of it. For this to work, you will first have to write a proper dub.json, which has to reside in the root directory of your project (the project should adhere to the structure mentioned in the first steps). The project currently also has to be hosted either on GitHub or on BitBucket. See https://code.dlang.org/publish for more information.
{ "name": "vibelog", "description": "A light-weight embeddable blog implementation", "homepage": "https://github.com/rejectedsoftware/vibelog", "license": "AGPL-3.0", "authors": [ "Sönke Ludwig" ], "dependencies": { "vibe-d": "~>0.10.0" } }
You can then register your project on code.dlang.org and as soon as you then add a new git tag with the name matching the current version prefixed with "v" ("v0.0.1" for the example here), it should appear there. Note that the update can take up to 30 minutes. Anyone can then add an entry similar to the following to their project to make use of the library:
{ ... "dependencies": { "vibelog": ">=0.0.1" } }
The main function
To simplify development of server-like applications that are command line based and run an event loop, vibe.d includes a default application entry point (main()
). To use it, define the version VibeDefaultMain
when building the project. This can be done by simply adding the following entry to your package description file: "versions": ["VibeDefaultMain"]
. However, note that for new applications it is recommended to define a regular `main` function instead and call runApplication
to initialize and run the vibe.d event loop.
When writing a pure command line client application, maybe something like wget, it may not be desirable to start an explicit event loop, but instead exit right after the work is done. In this case, vibe.d will automatically run a temporary event loop as long as any blocking operation is in progress, so that no explicit runApplication
or runEventLoop
calls are necessary.
import vibe.vibe; void main() { // ... perform setup here ... runApplication(); }
import vibe.vibe; void main() { auto f = openFile("test.html", FileMode.CreateTrunc); f.write(download("http://google.com/")); }
Privilege lowering
For server applications it may be desirable to start the application as root so that it can listen on privileged ports or open system log files for writing. After these setup tasks, such applications impose a security risk because a hole in the application that allows to somehow execute malicious commands on the server will give the attacker full access to the system. For this reason vibe.d supports privilege lowering, where the user id and group id of the process are changed to an unprivileged user after the startup process, right before the event loop is started.
Privilege lowering can be configured in the configuration file /etc/vibe/vibe.conf (on Windows vibe.conf must be in the application's root directory instead). The two fields "user" and "group" have to be set to the the name or numeric ID of the unprivileged user/group.
{ "user": "www-data", "group": "www-data" }
Selecting the event loop driver
By default, the native API for each platform is selected as the default for providing the asynchronous I/O and concurrency primitive support. However, you may select a particular implementation if there are more than one available for the target platform. In order to override the default, add a sub configuration directive to your dub.sdl (choosing the "select" driver in this case):
dependency "eventcore" version="*" subConfiguration "eventcore" "select"
When using a JSON based package recipe, the two lines have to be inserted as follows (the "…" are just placeholders for other possible directives):
{ … "dependencies": { … "eventcore": "*" }, "subConfigurations": { … "eventcore": "select" } }
The following implementations are available:
-
"epoll"
- Uses the Linux
epoll
interface, default when building for Linux, including Android -
"epoll-gaia"
- Uses the Linux
epoll
interface andgetaddrinfo_a
for asynchronous DNS lookups -
"cfrunloop"
- On Darwin based systems (macOS/iOS), uses
CFRunLoop
in order to be compatible with GUI applications, default on macOS and iOS -
"kqueue"
- Uses the BSD
kqueue
interface, default on FreeBSD, also available on Darwin based systems -
"winapi"
- Windows API based implementation using
MsgWaitForMultipleObjectsEx
in order to be compatible with GUI applications, default on Windows -
"select"
- Available for all Posix compliant systems, as well as Windows, uses
select()
for non-blocking I/O, only recommended for otherwise unsupported platforms -
"libasync"
- Uses the libasync library to choose and wrap the operating system specific API
-
"generic"
- Does not provide a driver, but instead requires calling
setupEventDriver
to set a custom driver implementation
Compile time configuration
There is a number of features that can be controlled via "versions". To defined a certain version, add the corresponding entry to the "versions"
in your dub.json:
{ ... "versions": ["VibeManualMemoryManagement", "VibeDefaultMain"], ... }
Version constant | Meaning |
---|---|
VibeDefaultMain
|
Tells vibe.d to use its own predefined main function. This is mutually exclusive to VibeCustomMain . |
VibeDisableCommandLineParsing
|
Disables automatic parsing of command line options passed to the application, such as "--help" or "--verbose". |
VibeNoDefaultArgs
|
Disables all default command line options, but keeps the command line argument module functional. |
VibeManualMemoryManagement
|
Performs a number of operations using manual memory management instead of the garbage collector, most notably in the HTTP server. This can lead to considerable performance improvements, but also makes certain operations unsafe and thus may open up the possibility for certain attacks. Especially any code needs to make sure to not escape any data (including string data) from HTTPServerRequest . |
VibeIdleCollect
|
Perform manual garbage collection runs when the application is idle for more than two seconds. |
VibePartialAutoExit
|
Partial workaround for issue #212 - exits the event loop after no mode file and socket based events exist. Note that this will exit the event loop, even if other kinds of events, such as timers, are still active. It is currently recommended to explicitly use exitEventLoop instead. |
VibeJsonFieldNames
|
Stores field names for JSON values for better error messages. This will use a few bytes of additional memory per Json value. |
JsonLineNumbers
|
Stores line numbers for each JSON value parsed from a JSON string for improved error messages. This will store an additional int for each Json value. |
VibeOutputCompactHTML
|
Instructs Diet-NG to output compact HTML (no extraneous white space) by default |
VibeDebugCatchAll
|
Enables catching of exceptions that derive from Error . This can be useful during application development to get useful error information while keeping the application running, but can generally be dangerous, because the application may be left in a bad state after an Error has been thrown. |
VibePragmaLib
|
Uses a pragma(lib) to link against OpenSSL. This is only useful for building without DUB. |
|
main function. This is mutually exclusive to VibeDefaultMain .
|
|
vibe.stream.tls module will be dysfunctional.
|
|
|
|
|
Handling segmentation-faults on Linux
While access violations on Windows usually trigger an exception with a convenient stack trace, on other operating systems D applications just terminate and possibly cause a core dump file to be written. However, there is a module hidden in the D runtime that enables such a stack trace also on Linux. Simply run the following code at program initialization:
import etc.linux.memoryerror; static if (is(typeof(registerMemoryErrorHandler))) registerMemoryErrorHandler();
This currently works only on Linux x86 and x86-64.