美文网首页
Node-Sqlite3 的修改详解

Node-Sqlite3 的修改详解

作者: l蓝色梦幻 | 来源:发表于2018-11-19 16:13 被阅读70次

    由于我们需要使用静态库连接, 尽可能少的使用 dll .因此我们需要对 Node-Sqlite3 的源代码做出对应的修改. 代码相对于 4.0.3
    做出的修改

    关于 Gyp 的修改.

    由于 Node-Sqlite3 使用 Gyp 作为配置, 因此我们从本地编译代码, 就需要添加, 修改对应的代码块才可能. 如下:

    原来的 bingding.gyp.

    下面是我们修改的 gyp 文件. 注意, 修改部分我会加上注释表明是为什么修改, 但是该注释在使用的时候需要删除.

    {
      "includes": [ "deps/common-sqlite.gypi" ],
      "variables": {
          "sqlite%":"sqlcipher_lib",
          "sqlite_libname%":"sqlcipher",
          "openssl_libname%":"crypto" // 添加新的配置项, 支持 openssl 静态库编译
      },
      "targets": [
        {
          "target_name": "<(module_name)",
          "include_dirs": ["<!(node -e \"require('nan')\")"],
          "conditions": [
            ["sqlite != 'internal'", {
                "include_dirs": [ "<(module_root_dir)/<(sqlite)/include", "<(module_root_dir)/<(sqlite)/include/sqlcipher", "<(module_root_dir)/<(sqlite)/include/openssl" ], // 添加 openssl 静态库支持
                "libraries": [
                   "-l<(sqlite_libname)",
               "-l<(openssl_libname)" // 添加 openssl 静态库支持
                ],
                "conditions": [ [ "OS=='linux'", {"libraries+":["-Wl,-rpath=<(module_root_dir)/<@(sqlite)/lib"]} ] ],
                "conditions": [ [ "OS!='win'", {"libraries+":["-l<(openssl_libname)", "-L<(module_root_dir)/<@(sqlite)/lib"]} ] ], // 添加 openssl 静态库支持
            "conditions": [ [ "OS=='win'", {"libraries+":[ "-lmsvcrt", "crypt32.lib", "ws2_32.lib" ] } ] ], // windows 上, 我们需要添加 openssl 静态库支持, 同时需要加入openssl 的依赖
                'msvs_settings': {
                  'VCLinkerTool': {
                    'AdditionalLibraryDirectories': [
                      '<(module_root_dir)/<(sqlite)/lib'
                    ],
            'IgnoreDefaultLibraryNames': [ // 由于在 Windows 上, Node.lib 中本身有 openssl 的代码, 因此我们如果要用 SQLCipher ,就需要智能忽略 openssl 库.
                      '<(openssl_libname).lib',
                      'crypt32.lib',
                      'ws2_32.lib'
            ],
                  },
                }
            },
            {
                "dependencies": [
                  "deps/sqlite3.gyp:sqlite3"
                ]
            }
            ]
          ],
          "sources": [
            "src/database.cc",
            "src/node_sqlite3.cc",
            "src/statement.cc"
          ]
        },
        {
          "target_name": "action_after_build",
          "type": "none",
          "dependencies": [ "<(module_name)" ],
          "copies": [
              {
                "files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
                "destination": "<(module_path)"
              }
          ]
        }
      ]
    }
    

    添加 lib 库到 sqlcipher_lib 目录下. 这样, 我们就不需要再指定代码库了.

    package.json 的修改

    将 binary 中的 host 修改成一个无法访问的地址, 这样就无法从这里下载预编译好的 dll .这时候就只能从本地编译了.

    添加 Backup 方法.

    SQLite 支持 backup 方法. 但是在 Node-Sqlite3 中并不支持. 因此我们需要自己加入该方法. 在 database.cc 中加入如下代码:

    NAN_METHOD(Database::Backup) {
        Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
        REQUIRE_ARGUMENT_STRING(0, filename);
        REQUIRE_ARGUMENT_STRING(1, passcode);
        OPTIONAL_ARGUMENT_FUNCTION(2, callback);
        
        Local<Function> completed;
        int last = info.Length();
    
        if (last >= 3 && info[last - 1]->IsFunction() && info[last - 2]->IsFunction()) {
            completed = Local<Function>::Cast(info[--last]);
        }
        
        info.GetReturnValue().Set(info.This());
        
        Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), info[0].As<String>(), ReadOnly);
        Nan::ForceSet(info.This(), Nan::New("passcode").ToLocalChecked(), info[0].As<String>(), ReadOnly);
    //    Nan::ForceSet(info.This(), Nan::New("mode").ToLocalChecked(), Nan::New(mode), ReadOnly);
        
        // Start opening the database.
        BackupBaton* baton = new BackupBaton(db, callback, *filename, *passcode);
        baton->progress.Reset(completed);
        db->Schedule(Work_Backup, baton, true);
    
        info.GetReturnValue().Set(info.This());
    }
    
    /*
     https://www.sqlite.org/backup.html
     */
    void Database::Work_Backup(Baton* b) {
        Nan::HandleScope scope;
        BackupBaton* baton = static_cast<BackupBaton*>(b);
        Database* db = baton->db;
        
        int rc;
        sqlite3 *pFile;
        sqlite3_backup *pBackup;
    
        assert(baton->db->locked);
        assert(baton->db->open);
        assert(baton->db->_handle);
        assert(baton->db->pending == 0);
    
        rc = sqlite3_open(baton->filename.c_str(), &pFile);
        // pKey 是密钥,nKey 是密钥长度
        sqlite3_key(pFile, baton->passcode.c_str(), strlen(baton->passcode.c_str()));
        if(rc==SQLITE_OK) {
            pBackup = sqlite3_backup_init(pFile, "main", baton->db->_handle, "main");
            if( pBackup ) {
                do {
                    rc = sqlite3_backup_step(pBackup, 5);
    
                    int remaining = sqlite3_backup_remaining(pBackup);
                    int pagecount = sqlite3_backup_pagecount(pBackup);
    
                    if (remaining > 0 && pagecount > 0) {
                        // Completion = 100% * (pagecount() - remaining()) / pagecount()
                        Local<Value> argv[] = {
                            Nan::Null(),
                            Nan::New((int)remaining),
                            Nan::New((int)pagecount)
                        };
    
                        Local<Function> cb = Nan::New(baton->progress);
    
                        if (!cb.IsEmpty() && cb->IsFunction()) {
                            TRY_CATCH_CALL(db->handle(), cb, 3, argv);
                        }
                    }
    
                    if( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
                        sqlite3_sleep(250);
                    }
                } while( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED );
                (void)sqlite3_backup_finish(pBackup);
            }
            rc = sqlite3_errcode(pFile);
        }
    
        (void)sqlite3_close(pFile);
        
        // 2. 返回参数
        Local<Value> argv[1];
        if (baton->status != SQLITE_OK) {
            EXCEPTION(Nan::New(baton->message.c_str()).ToLocalChecked(), baton->status, exception);
            argv[0] = exception;
        } else {
            argv[0] = Nan::Null();
        }
        
        Local<Function> cb = Nan::New(baton->callback);
        
        if (!cb.IsEmpty() && cb->IsFunction()) {
            TRY_CATCH_CALL(db->handle(), cb, 1, argv);
        }
        
        delete baton;
    }
    

    其他的地方仿照其他部分修改一下即可. 这时候我们就加入了 backup 功能.

    参考

    Node-Sqlite3

    SQLite Backup

    GYP Setting 参数

    相关文章

      网友评论

          本文标题:Node-Sqlite3 的修改详解

          本文链接:https://www.haomeiwen.com/subject/dtdafqtx.html