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
这个提交包含在:
114
packages/lib/net-utils.ts
普通文件
114
packages/lib/net-utils.ts
普通文件
@@ -0,0 +1,114 @@
|
||||
import shim from './shim';
|
||||
|
||||
export async function ip() {
|
||||
const response = await shim.fetch('https://api.ipify.org/?format=json');
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not retrieve IP: ${await response.text()}`);
|
||||
}
|
||||
|
||||
const ip = await response.json();
|
||||
return ip.ip;
|
||||
}
|
||||
|
||||
interface TcpPortUsed {
|
||||
check(port: number): Promise<boolean>;
|
||||
}
|
||||
|
||||
export async function findAvailablePort(tcpPortUsed: TcpPortUsed, possiblePorts: number[], 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++) {
|
||||
const inUse = await tcpPortUsed.check(possiblePorts[i]);
|
||||
if (!inUse) {
|
||||
port = possiblePorts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
export function mimeTypeFromHeaders(headers: Record<string, string>) {
|
||||
if (!headers || !headers['content-type']) return null;
|
||||
|
||||
const splitted = headers['content-type'].split(';');
|
||||
return splitted[0].trim().toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
const httpStatusCodes_: Record<number, string> = {
|
||||
100: 'Continue',
|
||||
101: 'Switching Protocols',
|
||||
102: 'Processing',
|
||||
103: 'Early Hints',
|
||||
200: 'OK',
|
||||
201: 'Created',
|
||||
202: 'Accepted',
|
||||
203: 'Non-Authoritative Information',
|
||||
204: 'No Content',
|
||||
205: 'Reset Content',
|
||||
206: 'Partial Content',
|
||||
207: 'Multi-Status',
|
||||
208: 'Already Reported',
|
||||
226: 'IM Used',
|
||||
300: 'Multiple Choices',
|
||||
301: 'Moved Permanently',
|
||||
302: 'Found',
|
||||
303: 'See Other',
|
||||
304: 'Not Modified',
|
||||
305: 'Use Proxy',
|
||||
307: 'Temporary Redirect',
|
||||
308: 'Permanent Redirect',
|
||||
400: 'Bad Request',
|
||||
401: 'Unauthorized',
|
||||
402: 'Payment Required',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
405: 'Method Not Allowed',
|
||||
406: 'Not Acceptable',
|
||||
407: 'Proxy Authentication Required',
|
||||
408: 'Request Timeout',
|
||||
409: 'Conflict',
|
||||
410: 'Gone',
|
||||
411: 'Length Required',
|
||||
412: 'Precondition Failed',
|
||||
413: 'Payload Too Large',
|
||||
414: 'URI Too Long',
|
||||
415: 'Unsupported Media Type',
|
||||
416: 'Range Not Satisfiable',
|
||||
417: 'Expectation Failed',
|
||||
418: 'I\'m a Teapot',
|
||||
421: 'Misdirected Request',
|
||||
422: 'Unprocessable Entity',
|
||||
423: 'Locked',
|
||||
424: 'Failed Dependency',
|
||||
425: 'Too Early',
|
||||
426: 'Upgrade Required',
|
||||
428: 'Precondition Required',
|
||||
429: 'Too Many Requests',
|
||||
431: 'Request Header Fields Too Large',
|
||||
451: 'Unavailable For Legal Reasons',
|
||||
500: 'Internal Server Error',
|
||||
501: 'Not Implemented',
|
||||
502: 'Bad Gateway',
|
||||
503: 'Service Unavailable',
|
||||
504: 'Gateway Timeout',
|
||||
505: 'HTTP Version Not Supported',
|
||||
506: 'Variant Also Negotiates',
|
||||
507: 'Insufficient Storage',
|
||||
508: 'Loop Detected',
|
||||
509: 'Bandwidth Limit Exceeded',
|
||||
510: 'Not Extended',
|
||||
511: 'Network Authentication Required',
|
||||
};
|
||||
|
||||
export function getHttpStatusMessage(statusCode: number): string {
|
||||
const msg = httpStatusCodes_[statusCode];
|
||||
|
||||
// We don't throw an exception since a server can send any arbitrary error code
|
||||
if (!msg) return 'Unknown status code';
|
||||
|
||||
return msg;
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户