Is it possible to store current session information globally in vibe.d? (dlang)

597 views Asked by At

The example from the site:

import vibe.d;

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["username"] = req.form["username"];
    session["password"] = req.form["password"];
    res.redirect("/home");
}

void logout(HTTPServerRequest req, HTTPServerResponse res)
{
    res.terminateSession();
    res.redirect("/");
}

void checkLogin(HTTPServerRequest req, HTTPServerResponse res)
{
    // force a redirect to / for unauthenticated users
    if( req.session is null )
        res.redirect("/");
}

shared static this()
{
    auto router = new URLRouter;
    router.get("/", staticTemplate!"index.dl");
    router.post("/login", &login);
    router.post("/logout", &logout);
    // restrict all following routes to authenticated users:
    router.any("*", &checkLogin);
    router.get("/home", staticTemplate!"home.dl");

    auto settings = new HTTPServerSettings;
    settings.sessionStore = new MemorySessionStore;
    // ...
}

But lets say I didnt want to pass the ServerResponse throughout my program into every function. For example, what if the res.session was storing the id of the current user. This is used often, so I wouldnt want this passed through each function. How do I store this session info globally? Assuming there's multiple users using the site.

1

There are 1 answers

0
Mihails Strasuns On BEST ANSWER

It is possible, though kind of discouraged.

Solution

You can't simply store it globally because there is not such thing as "global" session - it is always specific to request context. Even having globals thread-local by default in D does not help as multiple fibers share same execution thread.

For such tasks vibe.d provides TaskLocal template which allows to do exactly what you want. I have not tried it but expect TaskLocal!Session session to "just work".

Please pay attention to these two warnings from docs:

Note, however, that each TaskLocal variable will increase the memory footprint of any task that uses task local storage. There is also an overhead to access TaskLocal variables, higher than for thread local variables, but generally still O(1)

and

FiberLocal instances MUST be declared as static/global thread-local variables. Defining them as a temporary/stack variable will cause crashes or data corruption!

Objection

Based on my experience, however, it still better to pass all such context explicitly through despite small typing inconvenience. Using globals is discouraged for a reason - as your program size grows it becomes inevitably hard to track dependencies between modules and test such code. Falling to convenience temptation now may cause lot of headache later. To minimize extra typing and simplify code maintenance I may suggest to instead define struct Context { ...} which will contain request / session pointers and will be routinely passed around instead.