<|start_filename|>index.js<|end_filename|>
var ffi = require('ffi');
var ref = require('ref')
var readline = require('readline');

var sqlite3 = 'void' // `sqlite3` is an "opaque" type, so we don't know its layout
  , sqlite3Ptr = ref.refType(sqlite3)
  , sqlite3PtrPtr = ref.refType(sqlite3Ptr)
  , sqlite3_exec_callback = 'pointer' // TODO: use ffi.Callback when #76 is implemented
  , stringPtr = ref.refType('string');

var SQLite3 = ffi.Library('./libsqlite3.dylib', {
  'sqlite3_libversion': [ 'string', [ ] ],
  'sqlite3_open': [ 'int', [ 'string', sqlite3PtrPtr ] ],
  'sqlite3_open_v2': [ 'int', [ 'string', sqlite3PtrPtr, 'int', 'string' ] ],
  'sqlite3_close': [ 'int', [ sqlite3Ptr ] ],
  'sqlite3_changes': [ 'int', [ sqlite3Ptr ]],
  'sqlite3_exec': [ 'int', [ sqlite3Ptr, 'string', sqlite3_exec_callback, 'void *', stringPtr ] ],
  'sqlite3_errmsg': [ 'string' , [ 'pointer' ]]
})

var sqltorrent = ffi.Library('sqltorrent.dylib', {
  'sqltorrent_init': [ 'int', [ 'pointer', 'string', 'int' ] ],
  'new_session': [ 'pointer', [ ] ],
  'new_add_torrent_params': [ 'pointer', [] ],
  'set_url': [ 'void', ['pointer', 'CString'] ],
  'set_save_path': [ 'void', ['pointer', 'CString'] ],
  'add_torrent': [ 'pointer', ['pointer', 'pointer'] ],
  'alert_loop': [ 'void', [ 'pointer', 'pointer'] ],
  'new_db': [ 'pointer', [ ] ],
  'sqltorrent_open': [ 'int', [ 'string', 'pointer', 'string'] ],
  'get_session': [ 'pointer', [ 'pointer'] ],
  'new_context': [ 'pointer', [ 'string'] ],
  'query_torrents': [ 'void', [ 'pointer', 'pointer'] ],
  'alert_error_code': ['int', ['pointer']],
  'state_update_alert_msg': ['string', ['pointer']],
});

if (process.argv.length < 4) {
  return console.log('pleae provide torrent file path, save path and port')
}

var torrent = process.argv[2];
var save_path = process.argv[3];
var port = process.argv[4]

// TORRENT

console.log('Opening torrent...')

var stdout = {
  progress: '',
  alert: '',
}

var ctx = sqltorrent.new_context(save_path);
sqltorrent.sqltorrent_init(ctx, 'torrent', 0); // gonna register a vfs called torrent

var callback = ffi.Callback('void', ['pointer', 'string', 'string'], (alert, msg, type) => {
  if (type === 'read_piece_alert')
    wsSend({
      alert: type + ' - ' + msg
    });
});
sqltorrent.alert_loop.async(ctx, callback, () => {});

// create a storage area for the db pointer SQLite3 gives us
var db = ref.alloc(sqlite3PtrPtr)
var ready = false;
var open = SQLite3.sqlite3_open_v2.async(torrent, db, 1, 'torrent', (err, ret) => {
  ready = true;
  wsSend({
    ready: true,
  })
  if (ret !== 0) return console.error('error:', SQLite3.sqlite3_errmsg(db))
});


function runQuery(db, query, callback) {
  var rowCount = 0
  var callback2 = ffi.Callback('int', ['void *', 'int', stringPtr, stringPtr], function (tmp, cols, argv, colv) {
    var obj = {}

    for (var i = 0; i < cols; i++) {
      var colName = ref.get(colv, ref.sizeof.pointer * i, ref.types.CString);
      var colData = ref.get(argv, ref.sizeof.pointer * i, ref.types.CString);
      obj[colName] = colData
    }

    callback(obj);

    return 0
  })

  var b = new Buffer('test')
  SQLite3.sqlite3_exec.async(db, query, callback2, b, null, function (err, ret) {
    if (err || ret !== 0) {
      return wsSend({
        result: 'error: ' +  SQLite3.sqlite3_errmsg(db)
      })
    } else {
      return wsSend({
        success: query,
      })
    }
  })
}

var torrents_callback = ffi.Callback('void', ['string', 'float', 'int', 'int'], (name, progress, download_rate, upload_rate) => {
  wsSend({
    progress: name + ' - %' + (progress * 100) + ' - down: ' + (download_rate / 1000) + 'kb/s - up: '  + (upload_rate / 1000) + 'kb/s',
    ready: ready,
  })

});
var ses = sqltorrent.get_session(ctx);
sqltorrent.query_torrents(ses, torrents_callback);
setInterval(() => {
  sqltorrent.query_torrents(ses, torrents_callback);
}, 1000);


// WEBSOCKET

var WebSocketServer = require('ws').Server;
var express = require('express');
var path = require('path');
var app = express();
var server = require('http').createServer();

app.use(express.static(path.join(__dirname, '/public')));

var wss = new WebSocketServer({server: server });
var ws = null
wss.on('connection', function (_ws) {
  ws = _ws;
  ws.on('close', function () {
  });

  ws.on('message', function incoming(message) {
    runQuery(db.deref(), message, response => {
      wsSend({
        result: response
      })
    })
  });
});

server.on('request', app);
server.listen(port, function () {
  console.log('Listening on http://localhost:'+ port);
  var spawn = require('child_process').spawn
  spawn('open', ['http://localhost:'+port]);
});

function wsSend(str) {
  if (ws) {
    try {
      ws.send(JSON.stringify(str));
    } catch (e) {
    }
  }
}
