Node中通过使用FFI调用外部库文件

2017-08-01  本文已影响0人  环零弦

Node中通过使用FFI调用外部库文件

因为NPM上的Sqlite3版本过于低了(3.1.8),有很多新的特性和性能提升没有及时更新,所以决定使用最新版本发布的dll/so文件作为方案。
代码如下:

var fs = require('fs')
  , ref = require('ref')
  , ffi = require('ffi')
  , ArrayType = require('ref-array')
var dbName = process.argv[2] || 'test.sqlite3'
var sqlite3 = 'void'
  , sqlite3Ptr = ref.refType(sqlite3)
  , sqlite3PtrPtr = ref.refType(sqlite3Ptr)
  , sqlite3_exec_callback = 'pointer'
  , stringPtr = ref.refType('string')
  , string = ref.types.CString
  , stringArray = ArrayType(string)

var SQLite3 = ffi.Library('./wxsqlite3-sqlite3-aes128_x64/aes128/dll/release/sqlite3_x64', {
  'sqlite3_libversion': [ 'string', [ ] ],
  'sqlite3_open': [ 'int', [ 'string', sqlite3PtrPtr ] ],
  'sqlite3_close': [ 'int', [ sqlite3Ptr ] ],
  'sqlite3_changes': [ 'int', [ sqlite3Ptr ]],
  'sqlite3_exec': [ 'int', [ sqlite3Ptr, 'string', sqlite3_exec_callback, 'void *', stringPtr ] ],
  'sqlite3_key': ['int', [sqlite3Ptr, 'string', 'int']],
  'sqlite3_rekey': ['int', [sqlite3Ptr, 'string', 'int']]
})

var db = ref.alloc(sqlite3PtrPtr)
SQLite3.sqlite3_open(dbName, db)
db = db.deref()
var x = process.argv[3];
if(x === 'create'){
    // SQLite3.sqlite3_exec(db, 'CREATE TABLE tb_test (name VARCHAR, password VARCHAR, gender int, email VARCHAR, address VARCHAR);', null, null, null)
    // SQLite3.sqlite3_exec(db, 'INSERT INTO tb_test VALUES(\'randy3\', \'123456\', 0, \'typhoeus@163.com\', \'Changchun Jilin\');', null, null, null)
    SQLite3.sqlite3_exec(db, 'UPDATE tb_test SET name = \'Lily\' WHERE name = \'randy2\';', null, null, null)

    // SQLite3.sqlite3_rekey(db, '456', 3)

} else {
    
    // SQLite3.sqlite3_key(db, '456', 3);
    // SQLite3.sqlite3_rekey(db, null, 0);
    var rowCount = 0

    var callback = ffi.Callback('int', ['void *', 'int', stringPtr, stringPtr], function (tmp, cols, argv, colv) {
        var obj = {}
        var colName = stringArray.untilZeros(colv).toJSON();
        var colData = stringArray.untilZeros(argv).toJSON();
        for (let i = 0; i < cols; i++) {
            obj[colName[i]] = colData[i]
        }
        console.log(obj);
        // console.log('Row: %j', obj)
        rowCount++
        return 0
    })

    var b = new Buffer('test')
    SQLite3.sqlite3_exec.async(db, 'SELECT * FROM tb_test;', callback, b, null, function (err, ret) {
        if (err) throw err
        console.log('Total Rows: %j', rowCount)
        //console.log('Changes: %j', SQLite3.sqlite3_changes(db))
        //console.log('Closing...')
        //SQLite3.sqlite3_close(db)
        //fs.unlinkSync(dbName)
        fin = true
    })
}
//SQLite3.sqlite3_close(db)


/*
module.exports = {
  fooSync : mylibrary.foo,
  foo: mylibrary.foo.async,
  barSync : mylibrary.bar,
  bar: mylibrary.bar.async
};
*/

ref这个很坑,完全看不懂好吧,不过官方有例子,正好又是跟我一样连的Sqlite3,省去无数麻烦,但有个缺点,只能获取第一列的数据,好在又有ref-array,不过也很难理解,最终凭经验猜到方法用toJSON(),成功搞定,获取到了完整结果集。


相关阅读:


拓展阅读:

上一篇下一篇

猜你喜欢

热点阅读