From 5407ef8c59eb9fa42f1def2d74dbc2e4f72fe60d Mon Sep 17 00:00:00 2001 From: Alexey Kasyanchuk Date: Fri, 13 Apr 2018 00:33:11 +0300 Subject: [PATCH] feat(peerDB): store on peers feature --- package-lock.json | 5 ++ package.json | 1 + src/app/torrent-page.js | 6 -- src/background/api.js | 77 +++++++++--------------- src/background/sphinx.js | 10 ++++ src/background/spider.js | 5 +- src/background/store.js | 126 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 56 deletions(-) create mode 100644 src/background/store.js diff --git a/package-lock.json b/package-lock.json index d891c98..c6d7cc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11897,6 +11897,11 @@ } } }, + "object-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.0.tgz", + "integrity": "sha512-05KzQ70lSeGSrZJQXE5wNDiTkBJDlUT/myi6RX9dVIvz7a7Qh4oH93BQdiPMn27nldYvVQCKMUaM83AfizZlsQ==" + }, "object-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", diff --git a/package.json b/package.json index b37b19e..0d43242 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "moment": "^2.20.1", "mysql": "^2.15.0", "nat-upnp": "^1.1.1", + "object-hash": "^1.3.0", "react": "^16.3.1", "react-dom": "^16.3.1", "react-input-range": "^1.3.0", diff --git a/src/app/torrent-page.js b/src/app/torrent-page.js index ead80f4..7fbf1a0 100644 --- a/src/app/torrent-page.js +++ b/src/app/torrent-page.js @@ -289,12 +289,6 @@ export default class TorrentPage extends Page { if(!this.torrent) return; - if(true) - { - alert('Nice try :)! But this feature will be restored in later. Just keep go in other direction :D.') - return - } - this.setState({ voting: true }); diff --git a/src/background/api.js b/src/background/api.js index d18e6cd..98e2580 100644 --- a/src/background/api.js +++ b/src/background/api.js @@ -14,7 +14,8 @@ module.exports = ({ crypto, insertTorrentToDB, removeTorrentFromDB, - checkTorrent + checkTorrent, + p2pStore }) => { let torrentClientHashMap = {} @@ -629,20 +630,7 @@ module.exports = ({ }, done) }) - let socketIPV4 = () => { - let ip = socket.request.connection.remoteAddress; - if (ipaddr.IPv4.isValid(ip)) { - // all ok - } else if (ipaddr.IPv6.isValid(ip)) { - let ipv6 = ipaddr.IPv6.parse(ip); - if (ipv6.isIPv4MappedAddress()) { - ip = ipv6.toIPv4Address().toString(); - } - } - return ip - }; - - recive('vote', function(hash, isGood, callback) + recive('vote', async (hash, isGood, callback) => { if(hash.length != 40) return; @@ -650,44 +638,35 @@ module.exports = ({ if(typeof callback != 'function') return; - const ip = socketIPV4(); isGood = !!isGood; - sphinx.query('SELECT * FROM `torrents_actions` WHERE `hash` = ? AND (`action` = \'good\' OR `action` = \'bad\') AND ipv4 = ?', [hash, ip], function (error, rows, fields) { - if(!rows) { - console.error(error); - } - if(rows.length > 0) { - callback(false) - return - } + const action = isGood ? 'good' : 'bad'; - sphinx.query('SELECT good, bad FROM `torrents` WHERE `hash` = ?', hash, function (error, rows, fields) { - if(!rows || rows.length == 0) - return; + const votes = await p2pStore.find(`vote:${hash}`) + let good = isGood ? 1 : 0 + let bad = !isGood ? 1 : 0 + if(votes) + { + console.log(votes) + votes.forEach(({vote}) => { + if(vote == 'bad') + bad++ + else + good++ + }) + } + console.log(bad, good) - let {good, bad} = rows[0]; - const action = isGood ? 'good' : 'bad'; - sphinx.query('INSERT INTO `torrents_actions` SET ?', {hash, action, ipv4: ip}, function(err, result) { - if(!result) { - console.error(err); - } - sphinx.query('UPDATE torrents SET ' + action + ' = ' + action + ' + 1 WHERE hash = ?', hash, function(err, result) { - if(!result) { - console.error(err); - } - if(isGood) { - good++; - } else { - bad++; - } - send('vote', { - hash, good, bad - }); - callback(true) - }); - }); - }); + p2pStore.store({ + type: 'vote', + torrentHash: hash, + vote: action, + _index: `vote:${hash}` + }) + send('vote', { + hash, good, bad }); + callback(true) + }); } \ No newline at end of file diff --git a/src/background/sphinx.js b/src/background/sphinx.js index d20e29e..6c248c3 100644 --- a/src/background/sphinx.js +++ b/src/background/sphinx.js @@ -55,6 +55,16 @@ const writeSphinxConfig = (path, dbPath) => { rt_field = versionIndex } + index store + { + type = rt + path = ${dbPath}/database/store + + rt_field = storeIndex + rt_attr_json = data + rt_attr_string = hash + } + searchd { listen = 9312 diff --git a/src/background/spider.js b/src/background/spider.js index c99b781..607b0be 100644 --- a/src/background/spider.js +++ b/src/background/spider.js @@ -6,6 +6,7 @@ const mysql = require('mysql'); const getPeersStatisticUDP = require('./bt/udp-tracker-request') const crypto = require('crypto') const P2PServer = require('./p2p') +const P2PStore = require('./store') const stun = require('stun') const natUpnp = require('nat-upnp'); const http = require('https') @@ -49,6 +50,7 @@ const p2p = new P2PServer(send) p2p.version = version p2p.encryptor = encryptor p2p.listen() +const p2pStore = new P2PStore(p2p, sphinx) const udpTrackers = [ { @@ -744,7 +746,8 @@ API({ crypto, insertTorrentToDB, removeTorrentFromDB, - checkTorrent + checkTorrent, + p2pStore }) if(config.indexer) { diff --git a/src/background/store.js b/src/background/store.js new file mode 100644 index 0000000..a8e9c3f --- /dev/null +++ b/src/background/store.js @@ -0,0 +1,126 @@ +const objectHash = require('object-hash'); + +module.exports = class P2PStore { + constructor(p2p, sphinx) + { + this.id = 1 + + console.log('connect p2p store...') + this.p2p = p2p + this.sphinx = sphinx + + this.sphinx.query("SELECT MAX(`id`) as mx from store", (err, rows) => { + if(err) + return + + if(rows[0] && rows[0].mx >= 1) + this.id = rows[0].mx + 1; + }) + + this.p2p.on('dbStore', (record, callback) => { + if(!record) + return + + if(typeof record !== 'object') + return + + if(!record.id) + return + + if(record.id <= this.id) + return + + // store + this._pushToDb(record) + }) + + this.p2p.on('dbSync', ({id} = {}, callback) => { + if(!id || this.id <= id) + { + callback(false) + return + } + + // back + this.sphinx.query(`select * from store where id >= ${id}`, (err, records) => { + if(err) + { + console.log(err) + return + } + + if(records.length > 0) + callback({records}) + }) + }) + } + + sync() + { + this.p2p.emit('dbSync', {id: this.id}, (data) => { + if(!data || !data.records) + return + + for(const record of data.records) + { + if(!record.id) + return + + if(record.id <= this.id) + return + + // push to db + this._pushToDb(record) + } + }) + } + + _pushToDb(value, callback) + { + const data = this.sphinx.escape(JSON.stringify(value.data)) + this.sphinx.query( + `insert into store(id, hash, data` + (value.index ? ', storeIndex' : '') + `) + values('${value.id}', '${value.hash}', ${data}` + (value.index ? ',' + this.sphinx.escape(value.index) : '') + ')', + (err) => { + if(err) + { + console.log(err) + return + } + + if(callback) + callback() + }) + } + + store(obj) + { + const value = { + id: this.id++, + hash: objectHash(obj), + data: obj, + index: obj._index + } + + this._pushToDb(value, () => { + // store record + this.p2p.emit('dbStore', value) + }) + } + + find(index) + { + return new Promise((resolve) => { + this.sphinx.query(`select * from store where match(${this.sphinx.escape(index)}) LIMIT 50000`, (err, records) => { + if(err) + { + console.log(err) + resolve(false) + return + } + + resolve(records.map(({data}) => JSON.parse(data))) + }) + }) + } +} \ No newline at end of file