Search code examples
mysqldmariadbvibed

Can't connect to MySQL/MariaDB database from vibed app


All work fine if I use custom main ( void main() instead of shared static this() ).

With default main I am getting "Access Violation" error. It's look like MySQL not allow connecting to it from localhost, but in my.ini I added string:

bind-address = 127.0.0.1

code, if it's help:

import std.stdio;
import std.path;
import std.file;
import std.string;

import dini;
import vibe.d;
import colorize;
import ddbc.all;

shared static this()
{
    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    settings.bindAddresses = ["::1", "127.0.0.1"];
    listenHTTP(settings, &hello);

    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
    res.writeBody("Hello, World!");
}


class ParseConfig
{
    string dbname;
    string dbuser;
    string dbpass;
    string dbhost;
    string dbport;

this()
    {
        try
        {
            //getcwd do not return correct path if run from task shoulder
            string confpath = buildPath((thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]), "config.ini");
            //writefln(thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]); // get path without extention +1 is for getting last slash

            //string confpath = buildPath(thisExePath, "config.ini");
            if (!exists(confpath)) 
                {
                    writeln("ERROR: config.ini do not exists");
                }
            auto config = Ini.Parse(confpath);
            try
            {
                this.dbname = config.getKey("dbname");
                this.dbuser = config.getKey("dbuser");
                this.dbpass = config.getKey("dbpass");
                this.dbhost = config.getKey("dbhost");
                this.dbport = config.getKey("dbport");

            }
            catch (Exception msg)
            {
                cwritefln("ERROR: Can't parse config: %s".color(fg.red), msg.msg);
            }       
        }
        catch(Exception msg)
        {
            cwriteln(msg.msg.color(fg.red));
            core.thread.Thread.sleep( dur!("msecs")(1000));
        }   
    }


}


class DBConnect
{
    Statement stmt;
    ParseConfig parseconfig;

    this(ParseConfig parseconfig)
    {
        try
            {
                this.parseconfig = parseconfig;
                MySQLDriver driver = new MySQLDriver();
                string url = MySQLDriver.generateUrl(parseconfig.dbhost, to!short(parseconfig.dbport), parseconfig.dbname);
                string[string] params = MySQLDriver.setUserAndPassword(parseconfig.dbuser, parseconfig.dbpass);

                DataSource ds = new ConnectionPoolDataSourceImpl(driver, url, params);

                auto conn = ds.getConnection();
                scope(exit) conn.close();

                stmt = conn.createStatement();
                writefln("\n[Database connection OK]");
            }
        catch (Exception ex)
        {
            writefln(ex.msg);
            writeln("Could not connect to DB. Please check settings");
        }

    }   
}

Also I run next command:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES;

also I tried different bind-address like: 0.0.0.0 and localhost but without result. After every new binding I did restart of MySQL service.

I am using this driver http://code.dlang.org/packages/ddbc

What's wrong?


Solution

  • To continue on my comment ( Can't connect to MySQL/MariaDB database from vibed app ).

    I just tested, and it's definitely the event loop ;)

    Instead of:

    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
    

    Just do:

    runTask({
        auto parseconfig = new ParseConfig();
        auto db = new DBConnect(parseconfig);
    });
    

    Worked for me (DMD 2.067.0 / Vibe 0.7.23 / ddbc 0.2.24 / colorize & dini master).

    To answer your comment ( Can't connect to MySQL/MariaDB database from vibed app) : the event loop starts inside the main function. What happens when you launch a D application ? The entry point is a C main inside the runtime, which initialize it (the runtime), including module constructor, run the unittest (if you've compiled with -unittest), then call your main (which name is "_Dmain" - useful to know if you want to set a breakpoint with GDB). When Vibe.d's main is called, it parses command line argument, an optional config file, and finally, starts the event loop. Any code that wish to run once the event loop has started should use runTask and similar, or createTimer. They should not call the code directly from the static constructor (it's actually one of the most common mistake when starting with Vibe.d).