Работа над проектом
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/server/.inpx-web
|
/server/.inpx-web
|
||||||
|
/server/.inpx-web-bak
|
||||||
/dist
|
/dist
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<q-dialog v-model="busyDialogVisible" no-route-dismiss no-esc-dismiss no-backdrop-dismiss>
|
||||||
|
<div class="q-pa-lg bg-white column" style="width: 400px">
|
||||||
|
<div style="font-weight: bold; font-size: 120%;">
|
||||||
|
{{ mainMessage }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="jobMessage" class="q-mt-sm" style="width: 350px; white-space: nowrap; overflow: hidden">
|
||||||
|
{{ jobMessage }}
|
||||||
|
</div>
|
||||||
|
<div v-show="jobMessage">
|
||||||
|
<q-linear-progress stripe rounded size="30px" :value="progress" color="green">
|
||||||
|
<div class="absolute-full flex flex-center">
|
||||||
|
<div class="text-black bg-white" style="font-size: 10px; padding: 1px 4px 1px 4px; border-radius: 4px">
|
||||||
|
{{ (progress*100).toFixed(2) }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-linear-progress>
|
||||||
|
</div>
|
||||||
|
<!--div class="q-ml-sm">
|
||||||
|
{{ jsonMessage }}
|
||||||
|
</div-->
|
||||||
|
</div>
|
||||||
|
</q-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -7,9 +30,27 @@
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
import vueComponent from '../vueComponent.js';
|
import vueComponent from '../vueComponent.js';
|
||||||
|
|
||||||
import wsc from './webSocketConnection';
|
|
||||||
//import _ from 'lodash';
|
//import _ from 'lodash';
|
||||||
|
|
||||||
|
import wsc from './webSocketConnection';
|
||||||
|
import * as utils from '../../share/utils';
|
||||||
|
|
||||||
|
const rotor = '|/-\\';
|
||||||
|
const stepBound = [
|
||||||
|
0,
|
||||||
|
0,//1
|
||||||
|
18,//2
|
||||||
|
20,//3
|
||||||
|
70,//4
|
||||||
|
82,//5
|
||||||
|
84,//6
|
||||||
|
88,//7
|
||||||
|
90,//8
|
||||||
|
98,//9
|
||||||
|
99,//10
|
||||||
|
100,//11
|
||||||
|
];
|
||||||
|
|
||||||
const componentOptions = {
|
const componentOptions = {
|
||||||
components: {
|
components: {
|
||||||
},
|
},
|
||||||
@@ -18,6 +59,11 @@ const componentOptions = {
|
|||||||
};
|
};
|
||||||
class Api {
|
class Api {
|
||||||
_options = componentOptions;
|
_options = componentOptions;
|
||||||
|
busyDialogVisible = false;
|
||||||
|
mainMessage = '';
|
||||||
|
jobMessage = '';
|
||||||
|
//jsonMessage = '';
|
||||||
|
progress = 0;
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.commit = this.$store.commit;
|
this.commit = this.$store.commit;
|
||||||
@@ -40,8 +86,54 @@ class Api {
|
|||||||
return this.$store.state.config;
|
return this.$store.state.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async showBusyDialog() {
|
||||||
|
this.mainMessage = '';
|
||||||
|
this.jobMessage = '';
|
||||||
|
this.busyDialogVisible = true;
|
||||||
|
try {
|
||||||
|
let ri = 0;
|
||||||
|
while (1) {// eslint-disable-line
|
||||||
|
const server = await wsc.message(await wsc.send({action: 'get-worker-state', workerId: 'server_state'}));
|
||||||
|
|
||||||
|
if (server.state != 'normal') {
|
||||||
|
this.mainMessage = `${server.serverMessage} ${rotor[ri]}`;
|
||||||
|
if (server.job == 'load inpx') {
|
||||||
|
this.jobMessage = `${server.jobMessage} (${server.recsLoaded}): ${server.fileName}`;
|
||||||
|
} else {
|
||||||
|
this.jobMessage = server.jobMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.jsonMessage = server;
|
||||||
|
|
||||||
|
const jStep = server.jobStep;
|
||||||
|
|
||||||
|
if (jStep && stepBound[jStep] !== undefined) {
|
||||||
|
const sp = server.progress || 0;
|
||||||
|
const delta = stepBound[jStep + 1] - stepBound[jStep];
|
||||||
|
this.progress = (stepBound[jStep] + sp*delta)/100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await utils.sleep(300);
|
||||||
|
ri = (ri < rotor.length - 1 ? ri + 1 : 0);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.busyDialogVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async request(params) {
|
async request(params) {
|
||||||
return await wsc.message(await wsc.send(params));
|
while (1) {// eslint-disable-line
|
||||||
|
const response = await wsc.message(await wsc.send(params));
|
||||||
|
|
||||||
|
if (response && response.error == 'server_busy') {
|
||||||
|
await this.showBusyDialog();
|
||||||
|
} else {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async search(query) {
|
async search(query) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DivBtn class="q-ml-md text-white bg-secondary" :size="32" :icon-size="24" icon="la la-cog" round @click="settingsDialogVisible = true" />
|
<DivBtn class="q-ml-md text-white bg-secondary" :size="30" :icon-size="24" :imt="1" icon="la la-cog" round @click="settingsDialogVisible = true" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row q-mx-md q-mb-sm items-center">
|
<div class="row q-mx-md q-mb-sm items-center">
|
||||||
<q-input
|
<q-input
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
/>
|
/>
|
||||||
<div class="q-mx-xs" />
|
<div class="q-mx-xs" />
|
||||||
|
|
||||||
<DivBtn class="text-white bg-grey-13" :size="32" :icon-size="24" icon="la la-question" round @click="showSearchHelp" />
|
<DivBtn class="text-white bg-grey-13" :size="30" :icon-size="24" icon="la la-question" round @click="showSearchHelp" />
|
||||||
|
|
||||||
<div class="q-mx-xs" />
|
<div class="q-mx-xs" />
|
||||||
<div class="row items-center q-mt-xs">
|
<div class="row items-center q-mt-xs">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import localForage from 'localforage';
|
|||||||
//import _ from 'lodash';
|
//import _ from 'lodash';
|
||||||
import * as utils from '../../share/utils';
|
import * as utils from '../../share/utils';
|
||||||
|
|
||||||
const maxDataSize = 100*1024*1024;
|
const maxDataSize = 100*1024*1024;//100 Mb
|
||||||
|
|
||||||
const abStore = localForage.createInstance({
|
const abStore = localForage.createInstance({
|
||||||
name: 'authorBooksStorage'
|
name: 'authorBooksStorage'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="btn" class="button clickable row justify-center items-center" @click="clickEffect">
|
<div ref="btn" class="button clickable row justify-center items-center" @click="clickEffect">
|
||||||
<div class="row justify-center items-center no-wrap" :class="{'button-pressed': pressed}">
|
<div class="row justify-center items-center no-wrap" :class="{'button-pressed': pressed}">
|
||||||
<q-icon :name="icon" :size="`${iconSize}px`" />
|
<i :class="icon" :style="`font-size: ${iconSize}px; margin-top: ${imt}px`" />
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -29,6 +29,7 @@ class DivBtn {
|
|||||||
icon: { type: String, default: '' },
|
icon: { type: String, default: '' },
|
||||||
iconSize: { type: Number, default: 14 },
|
iconSize: { type: Number, default: 14 },
|
||||||
round: { type: Boolean },
|
round: { type: Boolean },
|
||||||
|
imt: { type: Number, default: 0 },// icon margin top
|
||||||
};
|
};
|
||||||
|
|
||||||
pressed = false;
|
pressed = false;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const config = {};
|
|||||||
//import {QDrawer} from 'quasar/src/components/drawer';
|
//import {QDrawer} from 'quasar/src/components/drawer';
|
||||||
|
|
||||||
//import {QCircularProgress} from 'quasar/src/components/circular-progress';
|
//import {QCircularProgress} from 'quasar/src/components/circular-progress';
|
||||||
|
import {QLinearProgress} from 'quasar/src/components/linear-progress';
|
||||||
import {QInput} from 'quasar/src/components/input';
|
import {QInput} from 'quasar/src/components/input';
|
||||||
import {QBtn} from 'quasar/src/components/btn';
|
import {QBtn} from 'quasar/src/components/btn';
|
||||||
//import {QBtnGroup} from 'quasar/src/components/btn-group';
|
//import {QBtnGroup} from 'quasar/src/components/btn-group';
|
||||||
@@ -41,6 +42,7 @@ const components = {
|
|||||||
//QDrawer,
|
//QDrawer,
|
||||||
|
|
||||||
//QCircularProgress,
|
//QCircularProgress,
|
||||||
|
QLinearProgress,
|
||||||
QInput,
|
QInput,
|
||||||
QBtn,
|
QBtn,
|
||||||
//QBtnGroup,
|
//QBtnGroup,
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ class DbCreator {
|
|||||||
async run(db, callback) {
|
async run(db, callback) {
|
||||||
const config = this.config;
|
const config = this.config;
|
||||||
|
|
||||||
callback({job: 'load inpx', jobMessage: 'Загрузка INPX'});
|
callback({jobStepCount: 5});
|
||||||
const readFileCallback = async(readState) => {
|
callback({job: 'load inpx', jobMessage: 'Загрузка INPX', jobStep: 1, progress: 0});
|
||||||
callback(readState);
|
|
||||||
};
|
|
||||||
|
|
||||||
//временная таблица
|
//временная таблица
|
||||||
await db.create({
|
await db.create({
|
||||||
@@ -43,6 +41,7 @@ class DbCreator {
|
|||||||
|
|
||||||
//stuff
|
//stuff
|
||||||
let recsLoaded = 0;
|
let recsLoaded = 0;
|
||||||
|
callback({recsLoaded});
|
||||||
let chunkNum = 0;
|
let chunkNum = 0;
|
||||||
|
|
||||||
const splitAuthor = (author) => {
|
const splitAuthor = (author) => {
|
||||||
@@ -57,6 +56,17 @@ class DbCreator {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let totalFiles = 0;
|
||||||
|
const readFileCallback = async(readState) => {
|
||||||
|
callback(readState);
|
||||||
|
|
||||||
|
if (readState.totalFiles)
|
||||||
|
totalFiles = readState.totalFiles;
|
||||||
|
|
||||||
|
if (totalFiles)
|
||||||
|
callback({progress: (readState.current || 0)/totalFiles});
|
||||||
|
};
|
||||||
|
|
||||||
let id = 0;
|
let id = 0;
|
||||||
const parsedCallback = async(chunk) => {
|
const parsedCallback = async(chunk) => {
|
||||||
for (const rec of chunk) {
|
for (const rec of chunk) {
|
||||||
@@ -123,7 +133,8 @@ class DbCreator {
|
|||||||
|
|
||||||
//отсортируем авторов и выдадим им правильные id
|
//отсортируем авторов и выдадим им правильные id
|
||||||
//порядок id соответствует ASC-сортировке по author.toLowerCase
|
//порядок id соответствует ASC-сортировке по author.toLowerCase
|
||||||
callback({job: 'author sort', jobMessage: 'Сортировка'});
|
callback({job: 'author sort', jobMessage: 'Сортировка авторов', jobStep: 2, progress: 0});
|
||||||
|
await utils.sleep(100);
|
||||||
authorArr.sort((a, b) => a.value.localeCompare(b.value));
|
authorArr.sort((a, b) => a.value.localeCompare(b.value));
|
||||||
|
|
||||||
id = 0;
|
id = 0;
|
||||||
@@ -137,7 +148,9 @@ class DbCreator {
|
|||||||
utils.freeMemory();
|
utils.freeMemory();
|
||||||
|
|
||||||
//подготовка к сохранению author_book
|
//подготовка к сохранению author_book
|
||||||
const saveBookChunk = async(authorChunk) => {
|
const saveBookChunk = async(authorChunk, callback) => {
|
||||||
|
callback(0);
|
||||||
|
|
||||||
const ids = [];
|
const ids = [];
|
||||||
for (const a of authorChunk) {
|
for (const a of authorChunk) {
|
||||||
for (const id of a.bookId) {
|
for (const id of a.bookId) {
|
||||||
@@ -147,7 +160,11 @@ class DbCreator {
|
|||||||
|
|
||||||
ids.sort();// обязательно, иначе будет тормозить - особенности JembaDb
|
ids.sort();// обязательно, иначе будет тормозить - особенности JembaDb
|
||||||
|
|
||||||
|
callback(0.1);
|
||||||
const rows = await db.select({table: 'book', where: `@@id(${db.esc(ids)})`});
|
const rows = await db.select({table: 'book', where: `@@id(${db.esc(ids)})`});
|
||||||
|
callback(0.6);
|
||||||
|
await utils.sleep(100);
|
||||||
|
|
||||||
const bookArr = new Map();
|
const bookArr = new Map();
|
||||||
for (const row of rows)
|
for (const row of rows)
|
||||||
bookArr.set(row.id, row);
|
bookArr.set(row.id, row);
|
||||||
@@ -165,13 +182,15 @@ class DbCreator {
|
|||||||
delete a.bookId;//в дальнейшем не понадобится, authorArr сохраняем без него
|
delete a.bookId;//в дальнейшем не понадобится, authorArr сохраняем без него
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback(0.7);
|
||||||
await db.insert({
|
await db.insert({
|
||||||
table: 'author_book',
|
table: 'author_book',
|
||||||
rows: abRows,
|
rows: abRows,
|
||||||
});
|
});
|
||||||
|
callback(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
callback({job: 'search tables create', jobMessage: 'Создание поисковых таблиц'});
|
callback({job: 'book sort', jobMessage: 'Сортировка книг', jobStep: 3, progress: 0});
|
||||||
|
|
||||||
//сохранение author_book
|
//сохранение author_book
|
||||||
await db.create({
|
await db.create({
|
||||||
@@ -180,12 +199,19 @@ class DbCreator {
|
|||||||
|
|
||||||
let idsLen = 0;
|
let idsLen = 0;
|
||||||
let aChunk = [];
|
let aChunk = [];
|
||||||
for (const author of authorArr) {// eslint-disable-line
|
let prevI = 0;
|
||||||
|
for (let i = 0; i < authorArr.length; i++) {// eslint-disable-line
|
||||||
|
const author = authorArr[i];
|
||||||
|
|
||||||
aChunk.push(author);
|
aChunk.push(author);
|
||||||
idsLen += author.bookId.length;
|
idsLen += author.bookId.length;
|
||||||
|
|
||||||
if (idsLen > 50000) {//константа выяснена эмпирическим путем "память/скорость"
|
if (idsLen > 50000) {//константа выяснена эмпирическим путем "память/скорость"
|
||||||
await saveBookChunk(aChunk);
|
await saveBookChunk(aChunk, (p) => {
|
||||||
|
callback({progress: (prevI + (i - prevI)*p)/authorArr.length});
|
||||||
|
});
|
||||||
|
|
||||||
|
prevI = i;
|
||||||
idsLen = 0;
|
idsLen = 0;
|
||||||
aChunk = [];
|
aChunk = [];
|
||||||
await utils.sleep(100);
|
await utils.sleep(100);
|
||||||
@@ -194,10 +220,12 @@ class DbCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (aChunk.length) {
|
if (aChunk.length) {
|
||||||
await saveBookChunk(aChunk);
|
await saveBookChunk(aChunk, () => {});
|
||||||
aChunk = null;
|
aChunk = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback({progress: 1});
|
||||||
|
|
||||||
//чистка памяти, ибо жрет как не в себя
|
//чистка памяти, ибо жрет как не в себя
|
||||||
await db.drop({table: 'book'});
|
await db.drop({table: 'book'});
|
||||||
await db.freeMemory();
|
await db.freeMemory();
|
||||||
@@ -267,7 +295,10 @@ class DbCreator {
|
|||||||
parseField(rec.lang, langMap, langArr, authorIds);
|
parseField(rec.lang, langMap, langArr, authorIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
callback({job: 'search tables create', jobMessage: 'Создание поисковых таблиц', jobStep: 4, progress: 0});
|
||||||
|
|
||||||
//парсинг 2, теперь можно создавать остальные поисковые таблицы
|
//парсинг 2, теперь можно создавать остальные поисковые таблицы
|
||||||
|
let proc = 0;
|
||||||
while (1) {// eslint-disable-line
|
while (1) {// eslint-disable-line
|
||||||
const rows = await db.select({
|
const rows = await db.select({
|
||||||
table: 'author_book',
|
table: 'author_book',
|
||||||
@@ -295,6 +326,9 @@ class DbCreator {
|
|||||||
for (const rec of books)
|
for (const rec of books)
|
||||||
parseBookRec(rec);
|
parseBookRec(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc += rows.length;
|
||||||
|
callback({progress: proc/authorArr.length});
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -312,7 +346,7 @@ class DbCreator {
|
|||||||
utils.freeMemory();
|
utils.freeMemory();
|
||||||
|
|
||||||
//config
|
//config
|
||||||
callback({job: 'config save', jobMessage: 'Сохранение конфигурации'});
|
callback({job: 'config save', jobMessage: 'Сохранение конфигурации', jobStep: 5, progress: 0});
|
||||||
await db.create({
|
await db.create({
|
||||||
table: 'config'
|
table: 'config'
|
||||||
});
|
});
|
||||||
@@ -367,6 +401,8 @@ class DbCreator {
|
|||||||
await db.freeMemory();
|
await db.freeMemory();
|
||||||
await utils.sleep(100);
|
await utils.sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback({progress: i/arr.length});
|
||||||
}
|
}
|
||||||
|
|
||||||
nullArr();
|
nullArr();
|
||||||
@@ -375,23 +411,23 @@ class DbCreator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//author
|
//author
|
||||||
callback({job: 'author save', jobMessage: 'Сохранение индекса авторов'});
|
callback({job: 'author save', jobMessage: 'Сохранение индекса авторов', jobStep: 6, progress: 0});
|
||||||
await saveTable('author', authorArr, () => {authorArr = null}, false);
|
await saveTable('author', authorArr, () => {authorArr = null}, false);
|
||||||
|
|
||||||
//series
|
//series
|
||||||
callback({job: 'series save', jobMessage: 'Сохранение индекса серий'});
|
callback({job: 'series save', jobMessage: 'Сохранение индекса серий', jobStep: 7, progress: 0});
|
||||||
await saveTable('series', seriesArr, () => {seriesArr = null});
|
await saveTable('series', seriesArr, () => {seriesArr = null});
|
||||||
|
|
||||||
//title
|
//title
|
||||||
callback({job: 'title save', jobMessage: 'Сохранение индекса названий'});
|
callback({job: 'title save', jobMessage: 'Сохранение индекса названий', jobStep: 8, progress: 0});
|
||||||
await saveTable('title', titleArr, () => {titleArr = null});
|
await saveTable('title', titleArr, () => {titleArr = null});
|
||||||
|
|
||||||
//genre
|
//genre
|
||||||
callback({job: 'genre save', jobMessage: 'Сохранение индекса жанров'});
|
callback({job: 'genre save', jobMessage: 'Сохранение индекса жанров', jobStep: 9, progress: 0});
|
||||||
await saveTable('genre', genreArr, () => {genreArr = null});
|
await saveTable('genre', genreArr, () => {genreArr = null});
|
||||||
|
|
||||||
//lang
|
//lang
|
||||||
callback({job: 'lang save', jobMessage: 'Сохранение индекса языков'});
|
callback({job: 'lang save', jobMessage: 'Сохранение индекса языков', jobStep: 10, progress: 0});
|
||||||
await saveTable('lang', langArr, () => {langArr = null});
|
await saveTable('lang', langArr, () => {langArr = null});
|
||||||
|
|
||||||
//кэш-таблицы запросов
|
//кэш-таблицы запросов
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class InpxParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//плюс 3 файла .info
|
//плюс 3 файла .info
|
||||||
await readFileCallback({total: inpFiles.length + 3});
|
await readFileCallback({totalFiles: inpFiles.length + 3});
|
||||||
|
|
||||||
let current = 0;
|
let current = 0;
|
||||||
//info
|
//info
|
||||||
|
|||||||
Reference in New Issue
Block a user