Работа над загрузкой файла на сервер
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios';
|
||||
import {sleep} from '../share/utils';
|
||||
|
||||
const maxFileUploadSize = 10*1024*1024;
|
||||
const api = axios.create({
|
||||
baseURL: '/api/reader'
|
||||
});
|
||||
@@ -65,6 +66,36 @@ class Reader {
|
||||
//загрузка
|
||||
return await axios.get(url, options);
|
||||
}
|
||||
|
||||
async uploadFile(file, callback) {
|
||||
if (file.size > maxFileUploadSize)
|
||||
throw new Error(`Размер файла превышает ${maxFileUploadSize} байт`);
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: progress => {
|
||||
const total = (progress.total ? progress.total : progress.loaded + 200000);
|
||||
if (callback)
|
||||
callback({state: 'upload', progress: Math.round((progress.loaded*100)/total)});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let response = await api.post('/upload-file', formData, options);
|
||||
if (response.data.state == 'error')
|
||||
throw new Error(response.data.error);
|
||||
|
||||
const url = response.data.url;
|
||||
if (!url)
|
||||
throw new Error('Неверный ответ api');
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Reader();
|
||||
@@ -10,7 +10,8 @@
|
||||
<el-button slot="append" icon="el-icon-check" @click="submitUrl"></el-button>
|
||||
</el-input>
|
||||
<div class="space"></div>
|
||||
<el-button size="mini" @click="loadFle">
|
||||
<input type="file" id="file" ref="file" @change="loadFile" style='display: none;'/>
|
||||
<el-button size="mini" @click="loadFileClick">
|
||||
Загрузить файл с диска
|
||||
</el-button>
|
||||
<div class="space"></div>
|
||||
@@ -66,7 +67,13 @@ class LoaderPage extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
loadFle() {
|
||||
loadFileClick() {
|
||||
this.$refs.file.click();
|
||||
}
|
||||
|
||||
loadFile() {
|
||||
const file = this.$refs.file.files[0];
|
||||
this.$emit('load-file', {file});
|
||||
}
|
||||
|
||||
openHelp() {
|
||||
|
||||
@@ -21,6 +21,7 @@ const ruMessage = {
|
||||
'convert': 'конвертирование',
|
||||
'loading': 'загрузка',
|
||||
'parse': 'обработка',
|
||||
'upload': 'отправка',
|
||||
};
|
||||
|
||||
export default @Component({
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
<keep-alive>
|
||||
<component ref="page" :is="activePage"
|
||||
@load-book="loadBook"
|
||||
@load-file="loadFile"
|
||||
@book-pos-changed="bookPosChanged"
|
||||
@tool-bar-toggle="toolBarToggle"
|
||||
@full-screen-toogle="fullScreenToggle"
|
||||
@@ -647,6 +648,29 @@ class Reader extends Vue {
|
||||
});
|
||||
}
|
||||
|
||||
loadFile(opts) {
|
||||
this.progressActive = true;
|
||||
this.$nextTick(async() => {
|
||||
const progress = this.$refs.page;
|
||||
try {
|
||||
progress.show();
|
||||
progress.setState({state: 'upload'});
|
||||
|
||||
const url = await readerApi.uploadFile(opts.file, (state) => {
|
||||
progress.setState(state);
|
||||
});
|
||||
|
||||
this.loadBook(url);
|
||||
|
||||
progress.hide(); this.progressActive = false;
|
||||
} catch (e) {
|
||||
progress.hide(); this.progressActive = false;
|
||||
this.loaderActive = true;
|
||||
this.$alert(e.message, 'Ошибка', {type: 'error'});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
blinkCachedLoadMessage() {
|
||||
this.blinkCount = 30;
|
||||
if (!this.inBlink) {
|
||||
|
||||
96
package-lock.json
generated
96
package-lock.json
generated
@@ -619,6 +619,11 @@
|
||||
"normalize-path": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY="
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
@@ -1840,8 +1845,7 @@
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
@@ -1855,6 +1859,38 @@
|
||||
"integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
|
||||
"dev": true
|
||||
},
|
||||
"busboy": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
||||
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
|
||||
"requires": {
|
||||
"dicer": "0.2.5",
|
||||
"readable-stream": "1.1.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"byline": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
|
||||
@@ -2379,7 +2415,6 @@
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
@@ -3251,6 +3286,38 @@
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||
},
|
||||
"dicer": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
||||
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
|
||||
"requires": {
|
||||
"readable-stream": "1.1.x",
|
||||
"streamsearch": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
}
|
||||
}
|
||||
},
|
||||
"diffie-hellman": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
@@ -6521,6 +6588,21 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"multer": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.1.tgz",
|
||||
"integrity": "sha512-zzOLNRxzszwd+61JFuAo0fxdQfvku12aNJgnla0AQ+hHxFmfc/B7jBVuPr5Rmvu46Jze/iJrFpSOsD7afO8SDw==",
|
||||
"requires": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^0.2.11",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"on-finished": "^2.3.0",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"multistream": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz",
|
||||
@@ -10405,6 +10487,11 @@
|
||||
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
|
||||
"dev": true
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
@@ -11036,8 +11123,7 @@
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.4.9",
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"iconv-lite": "^0.4.24",
|
||||
"localforage": "^1.7.3",
|
||||
"lodash": "^4.17.11",
|
||||
"multer": "^1.4.1",
|
||||
"path-browserify": "^1.0.0",
|
||||
"sql-template-strings": "^2.2.2",
|
||||
"sqlite": "^3.0.0",
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = {
|
||||
tempDir: `${dataDir}/tmp`,
|
||||
logDir: `${dataDir}/log`,
|
||||
publicDir: `${execDir}/public`,
|
||||
uploadDir: `${execDir}/public/upload`,
|
||||
dbFileName: 'db.sqlite',
|
||||
loggingEnabled: true,
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ module.exports = Object.assign({}, base, {
|
||||
tempDir: `${dataDir}/tmp`,
|
||||
logDir: `${dataDir}/log`,
|
||||
publicDir: `${execDir}/public`,
|
||||
uploadDir: `${execDir}/public/upload`,
|
||||
|
||||
servers: [
|
||||
{
|
||||
|
||||
@@ -14,19 +14,25 @@ class ReaderController extends BaseController {
|
||||
const request = req.body;
|
||||
let error = '';
|
||||
try {
|
||||
if (!request.type || !(request.type == 'url' || request.type == 'file'))
|
||||
throw new Error(`key 'type' is wrong`);
|
||||
|
||||
if (request.type == 'file')
|
||||
throw new Error(`file loading is not supported yet`);
|
||||
|
||||
if (request.type == 'url') {
|
||||
if (!request.url)
|
||||
throw new Error(`key 'url' is empty`);
|
||||
const workerId = this.readerWorker.loadBookUrl(request.url);
|
||||
const state = workerState.getState(workerId);
|
||||
return (state ? state : {});
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
}
|
||||
//bad request
|
||||
res.status(400).send({error});
|
||||
return false;
|
||||
}
|
||||
|
||||
async uploadFile(req, res) {
|
||||
const file = req.file;
|
||||
let error = '';
|
||||
try {
|
||||
const url = await this.readerWorker.saveFile(file);
|
||||
return ({url});
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ class ReaderWorker {
|
||||
|
||||
return workerId;
|
||||
}
|
||||
|
||||
async saveFile(file) {
|
||||
return `file://${file.filename}`;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReaderWorker;
|
||||
@@ -13,6 +13,7 @@ const SqliteConnectionPool = require('./core/SqliteConnectionPool');
|
||||
|
||||
async function init() {
|
||||
await fs.ensureDir(config.dataDir);
|
||||
await fs.ensureDir(config.uploadDir);
|
||||
await fs.ensureDir(config.tempDir);
|
||||
await fs.emptyDir(config.tempDir);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const c = require('./controllers');
|
||||
const utils = require('./core/utils');
|
||||
const multer = require('multer');
|
||||
|
||||
function initRoutes(app, connPool, config) {
|
||||
const misc = new c.MiscController(connPool, config);
|
||||
@@ -9,16 +11,35 @@ function initRoutes(app, connPool, config) {
|
||||
const [aAll, aNormal, aSite, aReader, aOmnireader] = // eslint-disable-line no-unused-vars
|
||||
[config.mode, 'normal', 'site', 'reader', 'omnireader'];
|
||||
|
||||
//multer
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, config.uploadDir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
cb(null, utils.randomHexString(30));
|
||||
}
|
||||
});
|
||||
const upload = multer({ storage, limits: {fileSize: 10*1024*1024} });
|
||||
|
||||
//routes
|
||||
const routes = [
|
||||
['POST', '/api/config', misc.getConfig.bind(misc), [aAll], {}],
|
||||
['POST', '/api/reader/load-book', reader.loadBook.bind(reader), [aAll], {}],
|
||||
['POST', '/api/reader/upload-file', [upload.single('file'), reader.uploadFile.bind(reader)], [aAll], {}],
|
||||
['POST', '/api/worker/get-state', worker.getState.bind(worker), [aAll], {}],
|
||||
];
|
||||
|
||||
//to app
|
||||
for (let route of routes) {
|
||||
let [httpMethod, path, controller, access, options] = route;
|
||||
let callbacks = [];
|
||||
let [httpMethod, path, controllers, access, options] = route;
|
||||
let controller = controllers;
|
||||
if (Array.isArray(controllers)) {
|
||||
controller = controllers[controllers.length - 1];
|
||||
callbacks = controllers.slice(0, -1);
|
||||
}
|
||||
|
||||
access = new Set(access);
|
||||
|
||||
let callback = () => {};
|
||||
@@ -38,13 +59,14 @@ function initRoutes(app, connPool, config) {
|
||||
res.status(403);
|
||||
};
|
||||
}
|
||||
callbacks.push(callback);
|
||||
|
||||
switch (httpMethod) {
|
||||
case 'GET' :
|
||||
app.get(path, callback);
|
||||
app.get(path, ...callbacks);
|
||||
break;
|
||||
case 'POST':
|
||||
app.post(path, callback);
|
||||
app.post(path, ...callbacks);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`initRoutes error: unknown httpMethod: ${httpMethod}`);
|
||||
|
||||
Reference in New Issue
Block a user