feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,100 @@
|
||||
import Logger, { LoggerWrapper } from '@joplin/utils/Logger';
|
||||
import { findAvailablePort } from '@joplin/lib/net-utils';
|
||||
import * as http from 'http';
|
||||
import * as urlParser from 'url';
|
||||
const enableServerDestroy = require('server-destroy');
|
||||
|
||||
type LinkHandler = (resourceId: string, response: http.ServerResponse)=> Promise<boolean>;
|
||||
|
||||
class ResourceServer {
|
||||
private server_: http.Server | null;
|
||||
private logger_: LoggerWrapper;
|
||||
private port_: number | null;
|
||||
private linkHandler_: LinkHandler | null;
|
||||
private started_: boolean;
|
||||
|
||||
public constructor() {
|
||||
this.server_ = null;
|
||||
this.logger_ = new Logger();
|
||||
this.port_ = null;
|
||||
this.linkHandler_ = null;
|
||||
this.started_ = false;
|
||||
}
|
||||
|
||||
public setLogger(logger: LoggerWrapper) {
|
||||
this.logger_ = logger;
|
||||
}
|
||||
|
||||
public logger() {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
public started() {
|
||||
return this.started_;
|
||||
}
|
||||
|
||||
public baseUrl() {
|
||||
if (!this.port_) return '';
|
||||
return `http://127.0.0.1:${this.port_}`;
|
||||
}
|
||||
|
||||
public setLinkHandler(handler: LinkHandler) {
|
||||
this.linkHandler_ = handler;
|
||||
}
|
||||
|
||||
public async start() {
|
||||
this.port_ = await findAvailablePort(require('tcp-port-used'), [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: string) => {
|
||||
response.write(message);
|
||||
response.end();
|
||||
};
|
||||
|
||||
const url = urlParser.parse(request.url, true);
|
||||
const pathParts = url.pathname.split('/');
|
||||
if (pathParts.length < 2) {
|
||||
writeResponse(`Error: could not get resource ID from path name: ${url.pathname}`);
|
||||
return;
|
||||
}
|
||||
const resourceId = pathParts[1];
|
||||
|
||||
if (!this.linkHandler_) throw new Error('No link handler is defined');
|
||||
|
||||
try {
|
||||
const done = await this.linkHandler_(resourceId, response);
|
||||
if (!done) throw new Error(`Unhandled resource: ${resourceId}`);
|
||||
} catch (error) {
|
||||
response.setHeader('Content-Type', 'text/plain');
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
response.statusCode = 400;
|
||||
response.write(error.message);
|
||||
}
|
||||
|
||||
response.end();
|
||||
});
|
||||
|
||||
this.server_.on('error', error => {
|
||||
this.logger().error('Resource server:', error);
|
||||
});
|
||||
|
||||
this.server_.listen(this.port_, '127.0.0.1');
|
||||
|
||||
enableServerDestroy(this.server_);
|
||||
|
||||
this.started_ = true;
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.server_) (this.server_ as http.Server & { destroy: ()=> void }).destroy();
|
||||
this.server_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default ResourceServer;
|
||||
在新工单中引用
屏蔽一个用户