diff --git a/client/components/Api/Api.vue b/client/components/Api/Api.vue index a4703c0..c2fb977 100644 --- a/client/components/Api/Api.vue +++ b/client/components/Api/Api.vue @@ -231,12 +231,12 @@ class Api { return await this.request({action: 'get-genre-tree'}); } - async getBookLink(bookId) { - return await this.request({action: 'get-book-link', bookId}, 120); + async getBookLink(bookUid) { + return await this.request({action: 'get-book-link', bookUid}, 120); } - async getBookInfo(bookId) { - return await this.request({action: 'get-book-info', bookId}, 120); + async getBookInfo(bookUid) { + return await this.request({action: 'get-book-info', bookUid}, 120); } async getConfig() { diff --git a/client/components/Search/BaseList.js b/client/components/Search/BaseList.js index ad259bb..8db041d 100644 --- a/client/components/Search/BaseList.js +++ b/client/components/Search/BaseList.js @@ -130,7 +130,7 @@ export default class BaseList { try { //подготовка - const response = await this.api.getBookLink(book.id); + const response = await this.api.getBookLink(book._uid); const link = response.link; const href = `${window.location.origin}${link}`; @@ -164,7 +164,7 @@ export default class BaseList { } } else if (action == 'bookInfo') { //информация о книге - const response = await this.api.getBookInfo(book.id); + const response = await this.api.getBookInfo(book._uid); this.$emit('listEvent', {action: 'bookInfo', data: response.bookInfo}); } } catch(e) { diff --git a/server/config/base.js b/server/config/base.js index ced76b7..923a53a 100644 --- a/server/config/base.js +++ b/server/config/base.js @@ -16,7 +16,7 @@ module.exports = { //поправить в случае, если были критические изменения в DbCreator или InpxParser //иначе будет рассинхронизация между сервером и клиентом на уровне БД - dbVersion: '6', + dbVersion: '7', dbCacheSize: 5, maxPayloadSize: 500,//in MB diff --git a/server/controllers/WebSocketController.js b/server/controllers/WebSocketController.js index 8f9ed44..566348b 100644 --- a/server/controllers/WebSocketController.js +++ b/server/controllers/WebSocketController.js @@ -165,19 +165,19 @@ class WebSocketController { } async getBookLink(req, ws) { - if (!utils.hasProp(req, 'bookId')) - throw new Error(`bookId is empty`); + if (!utils.hasProp(req, 'bookUid')) + throw new Error(`bookUid is empty`); - const result = await this.webWorker.getBookLink(req.bookId); + const result = await this.webWorker.getBookLink(req.bookUid); this.send(result, req, ws); } async getBookInfo(req, ws) { - if (!utils.hasProp(req, 'bookId')) - throw new Error(`bookId is empty`); + if (!utils.hasProp(req, 'bookUid')) + throw new Error(`bookUid is empty`); - const result = await this.webWorker.getBookInfo(req.bookId); + const result = await this.webWorker.getBookInfo(req.bookUid); this.send(result, req, ws); } diff --git a/server/core/DbCreator.js b/server/core/DbCreator.js index f5a9c6a..3cfc00e 100644 --- a/server/core/DbCreator.js +++ b/server/core/DbCreator.js @@ -65,6 +65,8 @@ class DbCreator { let librateMap = new Map();//оценка let librateArr = []; + let uidSet = new Set();//уникальные идентификаторы + //stats let authorCount = 0; let bookCount = 0; @@ -221,13 +223,14 @@ class DbCreator { let filtered = false; for (const rec of chunk) { //сначала фильтр - if (!filter(rec)) { + if (!filter(rec) || uidSet.has(rec._uid)) { rec.id = 0; filtered = true; continue; } rec.id = ++id; + uidSet.add(rec._uid); if (!rec.del) { bookCount++; @@ -269,6 +272,7 @@ class DbCreator { delMap = null; dateMap = null; librateMap = null; + uidSet = null; await db.close({table: 'book'}); await db.freeMemory(); @@ -624,6 +628,12 @@ class DbCreator { stats.filesDelCount = res.filesDelCount; } + //заодно добавим нужный индекс + await db.create({ + in: 'book', + hash: {field: '_uid', type: 'string', depth: 100, unique: true}, + }); + countDone = true; } } diff --git a/server/core/InpxParser.js b/server/core/InpxParser.js index 919e6c3..6e2d864 100644 --- a/server/core/InpxParser.js +++ b/server/core/InpxParser.js @@ -1,4 +1,5 @@ const path = require('path'); +const crypto = require('crypto'); const ZipReader = require('./ZipReader'); const collectionInfo = 'collection.info'; @@ -98,9 +99,13 @@ class InpxParser { if (line[line.length - 1] == '\x0D') line = line.substring(0, line.length - 1); + const rec = {}; + //уникальный идентификатор записи + const sha256 = crypto.createHash('sha256'); + rec._uid = sha256.update(line).digest('base64'); + //парсим запись const parts = line.split('\x04'); - const rec = {}; const len = (parts.length > structLen ? structLen : parts.length); for (let i = 0; i < len; i++) { diff --git a/server/core/RemoteLib.js b/server/core/RemoteLib.js index 8681931..0ab0c8e 100644 --- a/server/core/RemoteLib.js +++ b/server/core/RemoteLib.js @@ -58,9 +58,9 @@ class RemoteLib { } } - async downloadBook(bookId) { + async downloadBook(bookUid) { try { - const response = await await this.wsRequest({action: 'get-book-link', bookId}); + const response = await await this.wsRequest({action: 'get-book-link', bookUid}); const link = response.link; const buf = await this.down.load(`${this.remoteHost}${link}`, {decompress: false}); diff --git a/server/core/WebWorker.js b/server/core/WebWorker.js index a73deb5..547f55d 100644 --- a/server/core/WebWorker.js +++ b/server/core/WebWorker.js @@ -354,7 +354,7 @@ class WebWorker { } } - async restoreBook(bookId, bookPath, downFileName) { + async restoreBook(bookUid, bookPath, downFileName) { const db = this.db; let extractedFile = ''; @@ -364,7 +364,7 @@ class WebWorker { extractedFile = await this.extractBook(bookPath); hash = await utils.getFileHash(extractedFile, 'sha256', 'hex'); } else { - hash = await this.remoteLib.downloadBook(bookId); + hash = await this.remoteLib.downloadBook(bookUid); } const link = `${this.config.filesPathStatic}/${hash}`; @@ -402,7 +402,7 @@ class WebWorker { return link; } - async getBookLink(bookId) { + async getBookLink(bookUid) { this.checkMyState(); try { @@ -410,11 +410,11 @@ class WebWorker { let link = ''; //найдем bookPath и downFileName - let rows = await db.select({table: 'book', where: `@@id(${db.esc(bookId)})`}); + let rows = await db.select({table: 'book', where: `@@hash('_uid', ${db.esc(bookUid)})`}); if (!rows.length) throw new Error('404 Файл не найден'); - const book = rows[0]; + const book = rows[0]; let downFileName = book.file; const author = book.author.split(','); const at = [author[0], book.title]; @@ -443,7 +443,7 @@ class WebWorker { } if (!link) { - link = await this.restoreBook(bookId, bookPath, downFileName) + link = await this.restoreBook(bookUid, bookPath, downFileName) } if (!link) @@ -458,13 +458,13 @@ class WebWorker { } } - async getBookInfo(bookId) { + async getBookInfo(bookUid) { this.checkMyState(); try { const db = this.db; - let bookInfo = await this.getBookLink(bookId); + let bookInfo = await this.getBookLink(bookUid); const hash = path.basename(bookInfo.link); const bookFile = `${this.config.filesDir}/${hash}`; const bookFileInfo = `${bookFile}.i.json`; @@ -472,7 +472,9 @@ class WebWorker { const restoreBookInfo = async(info) => { const result = {}; - const rows = await db.select({table: 'book', where: `@@id(${db.esc(bookId)})`}); + let rows = await db.select({table: 'book', where: `@@hash('_uid', ${db.esc(bookUid)})`}); + if (!rows.length) + throw new Error('404 Файл не найден'); const book = rows[0]; result.book = book;