diff --git a/client/client.js b/client/client.js index d30d83bb..904634f1 100644 --- a/client/client.js +++ b/client/client.js @@ -7,6 +7,7 @@ const inherits = require('inherits'); const rendy = require('rendy'); const load = require('load.js'); const tryToCatch = require('try-to-catch'); +const {addSlashToEnd} = require('format-io'); const pascalCase = require('just-pascal-case'); const isDev = process.env.NODE_ENV === 'development'; @@ -114,9 +115,11 @@ function CloudCmdProto(DOM) { imgPosition = 'top'; Images.show.load(imgPosition, panel); + const path = addSlashToEnd(p.path); + console.log(path); /* загружаем содержимое каталога */ - await ajaxLoad(p.path, { + await ajaxLoad(path, { refresh, history, noCurrent, diff --git a/client/dom/current-file.js b/client/dom/current-file.js index 012d68dc..e009bd59 100644 --- a/client/dom/current-file.js +++ b/client/dom/current-file.js @@ -287,9 +287,13 @@ module.exports.setTitle = (name) => { */ module.exports.isCurrentIsDir = (currentFile) => { const current = currentFile || DOM.getCurrentFile(); + const path = DOM.getCurrentPath(current); const fileType = DOM.getCurrentType(current); - return /^directory(-link)?/.test(fileType); + const isZip = /\.zip$/.test(path); + const isDir = /^directory(-link)?/.test(fileType); + + return isDir || isZip; }; module.exports.getCurrentType = (currentFile) => { diff --git a/client/dom/current-file.spec.js b/client/dom/current-file.spec.js index f96271bc..5cc683c3 100644 --- a/client/dom/current-file.spec.js +++ b/client/dom/current-file.spec.js @@ -299,10 +299,12 @@ function getDOM({ getByDataName = stub(), isContainClass = stub(), getCurrentType = stub(), + getCurrentPath = stub(), } = {}) { return { getCurrentDirPath, getCurrentDirName, + getCurrentPath, getByDataName, isContainClass, getCurrentType, diff --git a/client/listeners/index.js b/client/listeners/index.js index 3eac5b59..16bdc4d3 100644 --- a/client/listeners/index.js +++ b/client/listeners/index.js @@ -267,21 +267,18 @@ function changePanel(element) { } async function onDblClick(event) { + event.preventDefault(); + const current = getLIElement(event.target); const isDir = DOM.isCurrentIsDir(current); const path = DOM.getCurrentPath(current); - if (isDir) { - await CloudCmd.loadDir({ - path: path === '/' ? '/' : path + '/', - }); - - event.preventDefault(); - } else { - CloudCmd.View.show(); - - event.preventDefault(); - } + if (!isDir) + return CloudCmd.View.show(); + + await CloudCmd.loadDir({ + path, + }); } async function onTouch(event) { diff --git a/package.json b/package.json index 61bb7d3e..4fc95df7 100644 --- a/package.json +++ b/package.json @@ -157,8 +157,9 @@ "ponse": "^5.0.0", "pullout": "^4.0.0", "putout": "^13.0.0", + "redzip": "^1.0.2", "rendy": "^3.0.0", - "restafary": "^9.0.1", + "restafary": "^9.1.0", "restbox": "^2.0.0", "shortdate": "^2.0.0", "simport": "^1.0.1", diff --git a/server/cloudcmd.js b/server/cloudcmd.js index 6faa6ed0..845f92c7 100644 --- a/server/cloudcmd.js +++ b/server/cloudcmd.js @@ -34,6 +34,7 @@ const dword = require('dword'); const deepword = require('deepword'); const nomine = require('nomine'); const fileop = require('@cloudcmd/fileop'); +//const readzip = require('readzip/lib/middle.js'); const isDev = process.env.NODE_ENV === 'development'; const getDist = (isDev) => isDev ? 'dist-dev' : 'dist'; @@ -238,6 +239,13 @@ function cloudcmd({modules, config}) { token: dropboxToken, }), + /* + readzip({ + prefix: cloudfunc.apiURL + '/fs', + root, + }), + */ + restafary({ prefix: cloudfunc.apiURL + '/fs', root, diff --git a/server/route.js b/server/route.js index 5c48b744..53bfbac4 100644 --- a/server/route.js +++ b/server/route.js @@ -3,15 +3,17 @@ const DIR_SERVER = './'; const DIR_COMMON = '../common/'; -const {realpath} = require('fs').promises; +const {extname} = require('path'); -const {read} = require('flop'); +const {read} = require('redzip'); const ponse = require('ponse'); const rendy = require('rendy'); const format = require('format-io'); const currify = require('currify'); const tryToCatch = require('try-to-catch'); const once = require('once'); +const pipe = require('pipe-io'); +const {contentType} = require('mime-types'); const root = require(DIR_SERVER + 'root'); const prefixer = require(DIR_SERVER + 'prefixer'); @@ -77,25 +79,27 @@ async function route({config, options, request, response}) { const fullPath = root(rootName, config('root')); const read = getReadDir(config); - const [error, dir] = await tryToCatch(read, fullPath); + const [error, stream] = await tryToCatch(read, fullPath); const {html} = options; - if (!error) - return sendIndex(p, buildIndex(config, html, { - ...dir, - path: format.addSlashToEnd(rootName), - })); - - if (error.code !== 'ENOTDIR') + if (error) return ponse.sendError(error, p); - const [realPathError, pathReal] = await tryToCatch(realpath, fullPath); + if (stream.type === 'directory') { + const {files} = stream; + + return sendIndex(p, buildIndex(config, html, { + files, + path: format.addSlashToEnd(rootName), + })); + } - ponse.sendFile({ - ...p, - name: realPathError ? name : pathReal, - gzip: false, - }); + response.setHeader('Content-Type', contentType(extname(fullPath))); + + await pipe([ + stream, + response, + ]); } /** diff --git a/server/route.spec.js b/server/route.spec.js index 4c5b2b22..b381b6d6 100644 --- a/server/route.spec.js +++ b/server/route.spec.js @@ -4,7 +4,7 @@ const path = require('path'); const fs = require('fs'); const tryToCatch = require('try-to-catch'); -const test = require('supertape'); +const {test, stub} = require('supertape'); const mockRequire = require('mock-require'); const {reRequire, stopAll} = mockRequire; @@ -219,39 +219,6 @@ test('cloudcmd: route: not found', async (t) => { t.end(); }); -test('cloudcmd: route: realpath: error', async (t) => { - const error = 'realpath error'; - const {realpath} = fs.promises; - - fs.promises.realpath = async () => { - throw error; - }; - - const config = { - root: fixtureDir, - }; - - const options = { - config, - }; - - reRequire(routePath); - const cloudcmd = reRequire(cloudcmdPath); - - const {request} = serveOnce(cloudcmd, { - config: defaultConfig, - }); - - const {body} = await request.get('/fs/empty-file', { - options, - }); - - fs.promises.realpath = realpath; - - t.ok(/^ENOENT/.test(body), 'should return error'); - t.end(); -}); - test('cloudcmd: route: sendIndex: encode', async (t) => { const name = '">'; const nameEncoded = '"><svg onload=alert(3);>'; @@ -259,12 +226,12 @@ test('cloudcmd: route: sendIndex: encode', async (t) => { name, }]; - const read = async (path) => ({ - path, + const read = stub().returns({ + type: 'directory', files, }); - mockRequire('flop', { + mockRequire('redzip', { read, }); diff --git a/test/server/console.js b/test/server/console.js index d467918d..8eb8bfdc 100644 --- a/test/server/console.js +++ b/test/server/console.js @@ -29,7 +29,6 @@ test('cloudcmd: console: enabled', async (t) => { t.end(); }); -// need options to close socket faster test('cloudcmd: console: disabled', async (t) => { const config = { console: false,