mirror of
https://github.com/laurent22/joplin.git
synced 2026-06-18 20:16:34 +02:00
Display link to resources and display them via server.
This commit is contained in:
@@ -0,0 +1,85 @@
|
|||||||
|
import { _ } from 'lib/locale.js'
|
||||||
|
import { Logger } from 'lib/logger.js';
|
||||||
|
import { Resource } from 'lib/models/resource.js';
|
||||||
|
import { netUtils } from 'lib/net-utils.js'
|
||||||
|
|
||||||
|
const http = require("http");
|
||||||
|
const urlParser = require("url");
|
||||||
|
const enableServerDestroy = require('server-destroy');
|
||||||
|
|
||||||
|
class ResourceServer {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.server_ = null;
|
||||||
|
this.logger_ = new Logger();
|
||||||
|
this.port_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogger(logger) {
|
||||||
|
this.logger_ = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger() {
|
||||||
|
return this.logger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
baseUrl() {
|
||||||
|
if (!this.port_) return '';
|
||||||
|
return 'http://127.0.0.1:' + this.port_;
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
this.port_ = await netUtils.findAvailablePort([9167, 9267, 8167, 8267]);
|
||||||
|
if (!this.port_) {
|
||||||
|
this.logger().error('Could not find available port to start resource server. Please report the error at https://github.com/laurent22/joplin');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.server_ = http.createServer();
|
||||||
|
|
||||||
|
this.server_.on('request', async (request, response) => {
|
||||||
|
|
||||||
|
const writeResponse = (message) => {
|
||||||
|
response.write(message);
|
||||||
|
response.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = urlParser.parse(request.url, true);
|
||||||
|
let resourceId = url.pathname.split('/');
|
||||||
|
if (resourceId.length < 2) {
|
||||||
|
writeResponse('Error: could not get resource ID from path name: ' + url.pathname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resourceId = resourceId[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
let resource = await Resource.loadByPartialId(resourceId);
|
||||||
|
if (!resource.length) throw new Error('No resource with ID ' + resourceId);
|
||||||
|
if (resource.length > 2) throw new Error('More than one resource match ID ' + resourceId); // That's very unlikely
|
||||||
|
resource = resource[0];
|
||||||
|
if (resource.mime) response.setHeader('Content-Type', resource.mime);
|
||||||
|
writeResponse(await Resource.content(resource));
|
||||||
|
} catch (error) {
|
||||||
|
response.setHeader('Content-Type', 'text/plain');
|
||||||
|
response.statusCode = 400;
|
||||||
|
writeResponse('Error: could not retrieve resource: ' + error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.server_.on('error', (error) => {
|
||||||
|
this.logger().error('Resource server:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.server_.listen(this.port_);
|
||||||
|
|
||||||
|
enableServerDestroy(this.server_);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if (this.server_) this.server_.destroy();
|
||||||
|
this.server_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ResourceServer;
|
||||||
@@ -23,6 +23,7 @@ const RootWidget = require('tkwidgets/RootWidget.js');
|
|||||||
const WindowWidget = require('tkwidgets/WindowWidget.js');
|
const WindowWidget = require('tkwidgets/WindowWidget.js');
|
||||||
|
|
||||||
const NoteWidget = require('./gui/NoteWidget.js');
|
const NoteWidget = require('./gui/NoteWidget.js');
|
||||||
|
const ResourceServer = require('./ResourceServer.js');
|
||||||
const NoteMetadataWidget = require('./gui/NoteMetadataWidget.js');
|
const NoteMetadataWidget = require('./gui/NoteMetadataWidget.js');
|
||||||
const FolderListWidget = require('./gui/FolderListWidget.js');
|
const FolderListWidget = require('./gui/FolderListWidget.js');
|
||||||
const NoteListWidget = require('./gui/NoteListWidget.js');
|
const NoteListWidget = require('./gui/NoteListWidget.js');
|
||||||
@@ -229,6 +230,10 @@ class AppGui {
|
|||||||
this.rootWidget_.addChild(win1);
|
this.rootWidget_.addChild(win1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addCommandToConsole(cmd) {
|
||||||
|
this.stdout(chalk.cyan.bold('> ' + cmd));
|
||||||
|
}
|
||||||
|
|
||||||
setupShortcuts() {
|
setupShortcuts() {
|
||||||
const shortcuts = {};
|
const shortcuts = {};
|
||||||
|
|
||||||
@@ -291,7 +296,7 @@ class AppGui {
|
|||||||
action: async () => {
|
action: async () => {
|
||||||
const cmd = await this.widget('statusBar').prompt();
|
const cmd = await this.widget('statusBar').prompt();
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
this.stdout(chalk.cyan.bold('> ' + cmd));
|
this.addCommandToConsole(cmd);
|
||||||
await this.processCommand(cmd);
|
await this.processCommand(cmd);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -327,17 +332,17 @@ class AppGui {
|
|||||||
|
|
||||||
shortcuts['nn'] = {
|
shortcuts['nn'] = {
|
||||||
description: _('Create a new note'),
|
description: _('Create a new note'),
|
||||||
action: { type: 'prompt', initialText: 'mknote ' },
|
action: { type: 'prompt', initialText: 'mknote ""', cursorPosition: -2 },
|
||||||
}
|
}
|
||||||
|
|
||||||
shortcuts['nt'] = {
|
shortcuts['nt'] = {
|
||||||
description: _('Create a new todo'),
|
description: _('Create a new todo'),
|
||||||
action: { type: 'prompt', initialText: 'mktodo ' },
|
action: { type: 'prompt', initialText: 'mktodo ""', cursorPosition: -2 },
|
||||||
}
|
}
|
||||||
|
|
||||||
shortcuts['nb'] = {
|
shortcuts['nb'] = {
|
||||||
description: _('Create a new notebook'),
|
description: _('Create a new notebook'),
|
||||||
action: { type: 'prompt', initialText: 'mkbook ' },
|
action: { type: 'prompt', initialText: 'mkbook ""', cursorPosition: -2 },
|
||||||
}
|
}
|
||||||
|
|
||||||
return shortcuts;
|
return shortcuts;
|
||||||
@@ -526,6 +531,11 @@ class AppGui {
|
|||||||
this.updateStatusBarMessage();
|
this.updateStatusBarMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit() {
|
||||||
|
this.fullScreen(false);
|
||||||
|
this.resourceServer_.stop();
|
||||||
|
}
|
||||||
|
|
||||||
updateStatusBarMessage() {
|
updateStatusBarMessage() {
|
||||||
const consoleWidget = this.widget('console');
|
const consoleWidget = this.widget('console');
|
||||||
|
|
||||||
@@ -547,12 +557,58 @@ class AppGui {
|
|||||||
if (msg !== '') this.widget('statusBar').setItemAt(0, msg);
|
if (msg !== '') this.widget('statusBar').setItemAt(0, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupResourceServer() {
|
||||||
|
const linkStyle = chalk.blue.underline;
|
||||||
|
const noteTextWidget = this.widget('noteText');
|
||||||
|
const resourceIdRegex = /^:\/[a-f0-9]+$/i
|
||||||
|
|
||||||
|
const regularUrlRenderer = (url) => {
|
||||||
|
if (!url) return url;
|
||||||
|
const l = url.toLowerCase();
|
||||||
|
if (l.indexOf('http://') === 0 || l.indexOf('https://') === 0 || l.indexOf('www.') === 0) {
|
||||||
|
return linkStyle(url);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default, before the server is started, only the regular
|
||||||
|
// URLs appear in blue.
|
||||||
|
noteTextWidget.markdownRendererOptions = {
|
||||||
|
linkUrlRenderer: (url) => {
|
||||||
|
if (resourceIdRegex.test(url)) {
|
||||||
|
return url;
|
||||||
|
} else {
|
||||||
|
return regularUrlRenderer(url);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.resourceServer_ = new ResourceServer();
|
||||||
|
this.resourceServer_.setLogger(this.app().logger());
|
||||||
|
this.resourceServer_.start().then(() => {
|
||||||
|
if (this.resourceServer_.baseUrl()) {
|
||||||
|
noteTextWidget.markdownRendererOptions = {
|
||||||
|
linkUrlRenderer: (url) => {
|
||||||
|
if (resourceIdRegex.test(url)) {
|
||||||
|
const resourceId = url.substr(2);
|
||||||
|
return linkStyle(this.resourceServer_.baseUrl() + '/' + resourceId.substr(0, 7));
|
||||||
|
} else {
|
||||||
|
return regularUrlRenderer(url);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
const term = this.term();
|
const term = this.term();
|
||||||
|
|
||||||
this.fullScreen();
|
this.fullScreen();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.setupResourceServer();
|
||||||
|
|
||||||
this.renderer_.start();
|
this.renderer_.start();
|
||||||
|
|
||||||
const statusBar = this.widget('statusBar');
|
const statusBar = this.widget('statusBar');
|
||||||
@@ -630,8 +686,10 @@ class AppGui {
|
|||||||
await cmd.action();
|
await cmd.action();
|
||||||
} else if (typeof cmd.action === 'object') {
|
} else if (typeof cmd.action === 'object') {
|
||||||
if (cmd.action.type === 'prompt') {
|
if (cmd.action.type === 'prompt') {
|
||||||
const commandString = await statusBar.prompt(cmd.action.initialText ? cmd.action.initialText : '');
|
let promptOptions = {};
|
||||||
this.stdout(commandString);
|
if ('cursorPosition' in cmd.action) promptOptions.cursorPosition = cmd.action.cursorPosition;
|
||||||
|
const commandString = await statusBar.prompt(cmd.action.initialText ? cmd.action.initialText : '', null, promptOptions);
|
||||||
|
this.addCommandToConsole(commandString);
|
||||||
await this.processCommand(commandString);
|
await this.processCommand(commandString);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown command: ' + JSON.stringify(cmd.action));
|
throw new Error('Unknown command: ' + JSON.stringify(cmd.action));
|
||||||
|
|||||||
+19
-3
@@ -315,9 +315,24 @@ class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async exit(code = 0) {
|
async exit(code = 0) {
|
||||||
await Setting.saveAll();
|
const doExit = async () => {
|
||||||
this.gui().fullScreen(false);
|
await Setting.saveAll();
|
||||||
process.exit(code);
|
this.gui().exit();
|
||||||
|
process.exit(code);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Give it a few seconds to cancel otherwise exit anyway
|
||||||
|
setTimeout(async () => {
|
||||||
|
await doExit();
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
if (await reg.syncStarted()) {
|
||||||
|
this.stdout(_('Cancelling background synchronisation... Please wait.'));
|
||||||
|
const sync = await reg.synchronizer(Setting.value('sync.target'));
|
||||||
|
await sync.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
await doExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
commands() {
|
commands() {
|
||||||
@@ -403,6 +418,7 @@ class Application {
|
|||||||
maximizeConsole: () => {},
|
maximizeConsole: () => {},
|
||||||
stdout: (text) => { console.info(text); },
|
stdout: (text) => { console.info(text); },
|
||||||
fullScreen: (b=true) => {},
|
fullScreen: (b=true) => {},
|
||||||
|
exit: () => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
await Resource.save(resource, { isNew: true });
|
await Resource.save(resource, { isNew: true });
|
||||||
|
|
||||||
note.body += "\n" + Resource.markdownTag(resource);
|
note.body += "\n\n" + Resource.markdownTag(resource);
|
||||||
await Note.save(note);
|
await Note.save(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
output.push(item.title);
|
output.push(item.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item && item.id) output.push(item.id.substr(0, 5));
|
// if (item && item.id) output.push(item.id.substr(0, 5));
|
||||||
|
|
||||||
return output.join(' ');
|
return output.join(' ');
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
async prompt(initialText = '', promptString = ':') {
|
async prompt(initialText = '', promptString = null, options = null) {
|
||||||
if (this.promptState_) throw new Error('Another prompt already active');
|
if (this.promptState_) throw new Error('Another prompt already active');
|
||||||
|
if (promptString === null) promptString = ':';
|
||||||
|
if (options === null) options = {};
|
||||||
|
|
||||||
this.root.globalDisableKeyboard(this);
|
this.root.globalDisableKeyboard(this);
|
||||||
|
|
||||||
@@ -38,6 +40,8 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
promptString: stripAnsi(promptString),
|
promptString: stripAnsi(promptString),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ('cursorPosition' in options) this.promptState_.cursorPosition = options.cursorPosition;
|
||||||
|
|
||||||
this.promptState_.promise = new Promise((resolve, reject) => {
|
this.promptState_.promise = new Promise((resolve, reject) => {
|
||||||
this.promptState_.resolve = resolve;
|
this.promptState_.resolve = resolve;
|
||||||
this.promptState_.reject = reject;
|
this.promptState_.reject = reject;
|
||||||
@@ -100,6 +104,8 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
style: this.term.innerStyle.bgBrightBlue.white, // NOTE: Need to use TK style for this as inputField is not compatible with chalk
|
style: this.term.innerStyle.bgBrightBlue.white, // NOTE: Need to use TK style for this as inputField is not compatible with chalk
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
|
||||||
|
|
||||||
this.inputEventEmitter_ = this.term.inputField(options, (error, input) => {
|
this.inputEventEmitter_ = this.term.inputField(options, (error, input) => {
|
||||||
let resolveResult = null;
|
let resolveResult = null;
|
||||||
const resolveFn = this.promptState_.resolve;
|
const resolveFn = this.promptState_.resolve;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { _ } from 'lib/locale.js'
|
import { _ } from 'lib/locale.js'
|
||||||
|
import { netUtils } from 'lib/net-utils.js'
|
||||||
|
|
||||||
const tcpPortUsed = require('tcp-port-used');
|
|
||||||
const http = require("http");
|
const http = require("http");
|
||||||
const urlParser = require("url");
|
const urlParser = require("url");
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
@@ -43,16 +43,7 @@ class OneDriveApiNodeUtils {
|
|||||||
|
|
||||||
this.api().setAuth(null);
|
this.api().setAuth(null);
|
||||||
|
|
||||||
let ports = this.possibleOAuthDancePorts();
|
const port = netUtils.findAvailablePort(this.possibleOAuthDancePorts());
|
||||||
let port = null;
|
|
||||||
for (let i = 0; i < ports.length; i++) {
|
|
||||||
let inUse = await tcpPortUsed.check(ports[i]);
|
|
||||||
if (!inUse) {
|
|
||||||
port = ports[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!port) throw new Error(_('All potential ports are in use - please report the issue at %s', 'https://github.com/laurent22/joplin'));
|
if (!port) throw new Error(_('All potential ports are in use - please report the issue at %s', 'https://github.com/laurent22/joplin'));
|
||||||
|
|
||||||
let authCodeUrl = this.api().authCodeUrl('http://localhost:' + port);
|
let authCodeUrl = this.api().authCodeUrl('http://localhost:' + port);
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ msgstr ""
|
|||||||
msgid "Exits the application."
|
msgid "Exits the application."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Cancelling background synchronisation... Please wait."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Only Bash is currently supported for autocompletion."
|
msgid "Only Bash is currently supported for autocompletion."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ msgstr "Affiche l'aide pour la commande donnée."
|
|||||||
msgid "Exits the application."
|
msgid "Exits the application."
|
||||||
msgstr "Quitter le logiciel."
|
msgstr "Quitter le logiciel."
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Cancelling background synchronisation... Please wait."
|
||||||
|
msgstr "Annulation..."
|
||||||
|
|
||||||
msgid "Only Bash is currently supported for autocompletion."
|
msgid "Only Bash is currently supported for autocompletion."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ msgstr ""
|
|||||||
msgid "Exits the application."
|
msgid "Exits the application."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Cancelling background synchronisation... Please wait."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Only Bash is currently supported for autocompletion."
|
msgid "Only Bash is currently supported for autocompletion."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -14,8 +14,8 @@ ajv@^4.9.1:
|
|||||||
json-stable-stringify "^1.0.1"
|
json-stable-stringify "^1.0.1"
|
||||||
|
|
||||||
ajv@^5.1.0:
|
ajv@^5.1.0:
|
||||||
version "5.2.4"
|
version "5.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.4.tgz#3daf9a8b67221299fdae8d82d117ed8e6c80244b"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.5.tgz#b637234d3e2675eb5f79fc652242a853a48cb49f"
|
||||||
dependencies:
|
dependencies:
|
||||||
co "^4.6.0"
|
co "^4.6.0"
|
||||||
fast-deep-equal "^1.0.0"
|
fast-deep-equal "^1.0.0"
|
||||||
@@ -832,8 +832,8 @@ chalk@^1.1.3:
|
|||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
chalk@^2.1.0:
|
chalk@^2.1.0:
|
||||||
version "2.2.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.2.0.tgz#477b3bf2f9b8fd5ca9e429747e37f724ee7af240"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles "^3.1.0"
|
ansi-styles "^3.1.0"
|
||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
@@ -1815,9 +1815,9 @@ node-bitmap@0.0.1:
|
|||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091"
|
resolved "https://registry.yarnpkg.com/node-bitmap/-/node-bitmap-0.0.1.tgz#180eac7003e0c707618ef31368f62f84b2a69091"
|
||||||
|
|
||||||
"node-emoji@https://github.com/laurent22/node-emoji":
|
"node-emoji@git+https://github.com/laurent22/node-emoji.git":
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
resolved "https://github.com/laurent22/node-emoji#9fa01eac463e94dde1316ef8c53089eeef4973b5"
|
resolved "git+https://github.com/laurent22/node-emoji.git#9fa01eac463e94dde1316ef8c53089eeef4973b5"
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash.toarray "^4.4.0"
|
lodash.toarray "^4.4.0"
|
||||||
|
|
||||||
@@ -2455,8 +2455,8 @@ tcp-port-used@^0.1.2:
|
|||||||
q "0.9.7"
|
q "0.9.7"
|
||||||
|
|
||||||
terminal-kit@^1.13.11:
|
terminal-kit@^1.13.11:
|
||||||
version "1.13.13"
|
version "1.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/terminal-kit/-/terminal-kit-1.13.13.tgz#fa53dbc17f5fb7e1630784274a7e57a10b1c0201"
|
resolved "https://registry.yarnpkg.com/terminal-kit/-/terminal-kit-1.14.0.tgz#1cb89c22bf697152a3f8e54569c61d5084ed690a"
|
||||||
dependencies:
|
dependencies:
|
||||||
async-kit "^2.2.3"
|
async-kit "^2.2.3"
|
||||||
get-pixels "^3.3.0"
|
get-pixels "^3.3.0"
|
||||||
|
|||||||
@@ -109,6 +109,15 @@ class BaseModel {
|
|||||||
return id.substr(0, 5);
|
return id.substr(0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static minimalPartialId(id) {
|
||||||
|
// let length = 2;
|
||||||
|
// while (true) {
|
||||||
|
// const partialId = id.substr(0, length);
|
||||||
|
// const r = await this.db().selectOne('SELECT count(*) as total FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
||||||
|
// if (r['total'] <= 1) return partialId;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
static loadByPartialId(partialId) {
|
static loadByPartialId(partialId) {
|
||||||
return this.modelSelectAll('SELECT * FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
return this.modelSelectAll('SELECT * FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { mime } from 'lib/mime-utils.js';
|
|||||||
import { filename } from 'lib/path-utils.js';
|
import { filename } from 'lib/path-utils.js';
|
||||||
import { FsDriverDummy } from 'lib/fs-driver-dummy.js';
|
import { FsDriverDummy } from 'lib/fs-driver-dummy.js';
|
||||||
import { markdownUtils } from 'lib/markdown-utils.js';
|
import { markdownUtils } from 'lib/markdown-utils.js';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
|
|
||||||
class Resource extends BaseItem {
|
class Resource extends BaseItem {
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class Resource extends BaseItem {
|
|||||||
return filename(path);
|
return filename(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static content(resource) {
|
static async content(resource) {
|
||||||
return this.fsDriver().readFile(this.fullPath(resource));
|
return this.fsDriver().readFile(this.fullPath(resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { shim } from 'lib/shim.js'
|
import { shim } from 'lib/shim.js'
|
||||||
|
|
||||||
|
const tcpPortUsed = require('tcp-port-used');
|
||||||
|
|
||||||
const netUtils = {};
|
const netUtils = {};
|
||||||
|
|
||||||
netUtils.ip = async () => {
|
netUtils.ip = async () => {
|
||||||
@@ -12,4 +14,20 @@ netUtils.ip = async () => {
|
|||||||
return ip.ip;
|
return ip.ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netUtils.findAvailablePort = async (possiblePorts, extraRandomPortsToTry = 20) => {
|
||||||
|
for (let i = 0; i < extraRandomPortsToTry; i++) {
|
||||||
|
possiblePorts.push(Math.floor(8000 + Math.random() * 2000));
|
||||||
|
}
|
||||||
|
|
||||||
|
let port = null;
|
||||||
|
for (let i = 0; i < possiblePorts.length; i++) {
|
||||||
|
let inUse = await tcpPortUsed.check(possiblePorts[i]);
|
||||||
|
if (!inUse) {
|
||||||
|
port = possiblePorts[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
export { netUtils };
|
export { netUtils };
|
||||||
@@ -14,6 +14,7 @@ import { _ } from 'lib/locale.js';
|
|||||||
const reg = {};
|
const reg = {};
|
||||||
|
|
||||||
reg.initSynchronizerStates_ = {};
|
reg.initSynchronizerStates_ = {};
|
||||||
|
reg.synchronizers_ = {};
|
||||||
|
|
||||||
reg.logger = () => {
|
reg.logger = () => {
|
||||||
if (!reg.logger_) {
|
if (!reg.logger_) {
|
||||||
@@ -96,7 +97,6 @@ reg.initSynchronizer_ = async (syncTargetId) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reg.synchronizer = async (syncTargetId) => {
|
reg.synchronizer = async (syncTargetId) => {
|
||||||
if (!reg.synchronizers_) reg.synchronizers_ = [];
|
|
||||||
if (reg.synchronizers_[syncTargetId]) return reg.synchronizers_[syncTargetId];
|
if (reg.synchronizers_[syncTargetId]) return reg.synchronizers_[syncTargetId];
|
||||||
if (!reg.db()) throw new Error('Cannot initialize synchronizer: db not initialized');
|
if (!reg.db()) throw new Error('Cannot initialize synchronizer: db not initialized');
|
||||||
|
|
||||||
@@ -191,6 +191,7 @@ reg.scheduleSync = async (delay = null) => {
|
|||||||
|
|
||||||
reg.syncStarted = async () => {
|
reg.syncStarted = async () => {
|
||||||
const syncTarget = Setting.value('sync.target');
|
const syncTarget = Setting.value('sync.target');
|
||||||
|
if (!reg.synchronizers_[syncTarget]) return false;
|
||||||
if (!reg.syncHasAuth(syncTarget)) return false;
|
if (!reg.syncHasAuth(syncTarget)) return false;
|
||||||
const sync = await reg.synchronizer(syncTarget);
|
const sync = await reg.synchronizer(syncTarget);
|
||||||
return sync.state() != 'idle';
|
return sync.state() != 'idle';
|
||||||
|
|||||||
Reference in New Issue
Block a user