Monday, 9 December 2013

newlisp accesses MongoDB via C++ dynamic library

I want to let my newlisp app access MongoDB server. There is C driver for MongoDB, but I have no time to learn C driver, just want to finish my job ASAP.
Below is my way, create a dynamic library using C++, also link to MongoDB C++ driver. But export C function using extern "C" statement.

One thing needs to note, MongoDB C++ driver must be compiled using -fPIC option.

First, create db.h file
extern "C" void CheckOnline();
extern "C" void Init(char * mongo_uri);

edit file
#include "db.h"
#include <stdlib.h>
#include <ctype.h>
#include <iostream>
#include "mongo_session_factory.h"
#include "mongo_session.h"
#include <mongo/bson/bsonobj.h>
#include <mongo/bson/bsonobjbuilder.h>
using namespace std;
class Config {
  string mongo_uri;
Config config;
void SetOffline(mongo::DBClientBase& con, mongo::OID const& id) {
  mongo::BSONObjBuilder condition;
  condition.append("_id", id);
  mongo::BSONObjBuilder update_field;
  update_field.append("status", "offline");
  mongo::BSONObjBuilder set_field;
  set_field.append("$set", update_field.obj());
  con.update("kaimei.display", mongo::Query(condition.obj()), set_field.obj());
 * Check every sign status
void CheckOnline() {
  cout << config.mongo_uri << endl;
  std::shared_ptr<MongoSession> session = MongoSessionFactory::GetSession(config.mongo_uri);
  mongo::DBClientBase & con = session->get_db_client_base();
  mongo::BSONObjBuilder condition;
  std::unique_ptr<mongo::DBClientCursor> cursor = con.query("kaimei.display", mongo::Query(condition.obj()));
  while (cursor->more()) {
    mongo::BSONObj record = cursor->next();
    uint64_t t1 = record.getField("last_active_time").numberLong();
    timeval tv;
    if (tv.tv_sec - t1 > 300) {
      SetOffline(con, record.getField("_id").OID());

void Init(char * mongo_uri) {
  config.mongo_uri = mongo_uri;
in include and src folders, there are some helper classes called MongoSessionFactory and MongoSesion. They are useful to connect to MongoDB server(Replicaset or Single server)

Ok, build it, see build.lsp file
(if (file? "")
    (delete-file ""))
(if (directory? "objects")
    (exec "rm -rf objects"))
(make-dir "objects")
(exec "c++ -g -fPIC -std=c++11 -I./include  -Wall -o ./objects/ -c ./src/")
(exec "c++ -g -fPIC -std=c++11 -I./include  -Wall -o ./objects/ -c ./src/")
(exec "c++ -g -fPIC -std=c++11 -I./include  -Wall -o ./objects/ -c ./src/")
(exec "c++ -g -fPIC -std=c++11 ./objects/ ./objects/ ./objects/ -shared -o -rdynamic -lpthread -lmongoclient -lboost_system -lboost_thread -lboost_filesystem")

After building succeeds, write a check.lsp to use the library.

(set 'db-path "/path/to/your/")
(import db-path "Init")
(import db-path "CheckOnline")
(Init "localhost:27017")

That's all. It works now.

No comments: