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/AuthorList/AuthorList.vue b/client/components/Search/AuthorList/AuthorList.vue index 07ada45..a3e177f 100644 --- a/client/components/Search/AuthorList/AuthorList.vue +++ b/client/components/Search/AuthorList/AuthorList.vue @@ -238,6 +238,13 @@ class AuthorList extends BaseList { const booksToFilter = await this.loadAuthorBooks(item.key); const filtered = this.filterBooks(booksToFilter); + if (!filtered.length && this.list.totalFound == 1) { + this.list.queryFound = 0; + this.list.totalFound = 0; + this.searchResult.found = []; + return false; + } + const prepareBook = (book) => { return Object.assign( { @@ -345,7 +352,10 @@ class AuthorList extends BaseList { if (authors.length > 1 || item.count > this.maxItemCount) this.getAuthorBooks(item);//no await else - await this.getAuthorBooks(item); + if (await this.getAuthorBooks(item) === false) { + this.tableData = []; + return; + } } result.push(item); 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/client/components/Search/BookInfoDialog/BookInfoDialog.vue b/client/components/Search/BookInfoDialog/BookInfoDialog.vue index 36b5863..a7bca77 100644 --- a/client/components/Search/BookInfoDialog/BookInfoDialog.vue +++ b/client/components/Search/BookInfoDialog/BookInfoDialog.vue @@ -185,7 +185,10 @@ class BookInfoDialog { return utils.sqlDateFormat(value); if (nodePath == 'fileInfo/del') - return (value ? 'Да' : ''); + return (value ? 'Да' : null); + + if (nodePath == 'fileInfo/insno') + return (value ? value : null); if (nodePath == 'titleInfo/author') return value.split(',').join(', '); diff --git a/package-lock.json b/package-lock.json index 9b5a88e..a2fcfeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "inpx-web", - "version": "1.2.2", + "version": "1.2.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "inpx-web", - "version": "1.2.2", + "version": "1.2.3", "hasInstallScript": true, "license": "CC0-1.0", "dependencies": { diff --git a/package.json b/package.json index 334f1fb..f334db7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inpx-web", - "version": "1.2.2", + "version": "1.2.3", "author": "Book Pauk ", "license": "CC0-1.0", "repository": "bookpauk/inpx-web", 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;