Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2026-03-02 18:18:25 +08:00
commit 119f78a952
24 changed files with 1995 additions and 347 deletions

File diff suppressed because it is too large Load diff

View file

@ -281,6 +281,7 @@
<option value="pl_PL">Polski</option>
<option value="pt_BR">Português (Brasil)</option>
<option value="ru_RU">Русский</option>
<option value="sk_SK">Slovenčina</option>
<option value="tr_TR">Türkçe</option>
<option value="zh_CHT">繁體中文</option>
<option value="zh_CN">简体中文</option>
@ -332,6 +333,7 @@
<option value="pl_PL">Polski</option>
<option value="pt_BR">Português (Brasil)</option>
<option value="ru_RU">Русский</option>
<option value="sk_SK">Slovenčina</option>
<option value="tr_TR">Türkçe</option>
<option value="zh_CHT">繁體中文</option>
<option value="zh_CN">简体中文</option>

View file

@ -62,20 +62,20 @@ if (!app.requestSingleInstanceLock()) {
return;
}
if (process.platform === 'linux') {
const desktop = (process.env.XDG_CURRENT_DESKTOP || '').toUpperCase();
if (process.platform === "linux") {
const desktop = (process.env.XDG_CURRENT_DESKTOP || "").toUpperCase();
const isChineseOS = [
'DDE', // 统信
'DEEPIN', // 统信
'UKUI', // 银河麒麟
'KYLIN', // 麒麟备用标识
'NEWSTART' // 中兴新支点
"DDE", // 统信
"DEEPIN", // 统信
"UKUI", // 银河麒麟
"KYLIN", // 麒麟备用标识
"NEWSTART" // 中兴新支点
].some(key => desktop.includes(key));
const isKylinFile = fs.existsSync('/etc/kylin-release');
const isUosFile = fs.existsSync('/etc/uos-version');
const isDeepinFile = fs.existsSync('/etc/deepin-release');
const isKylinFile = fs.existsSync("/etc/kylin-release");
const isUosFile = fs.existsSync("/etc/uos-version");
const isDeepinFile = fs.existsSync("/etc/deepin-release");
if (isChineseOS || isKylinFile || isUosFile || isDeepinFile) {
app.commandLine.appendSwitch('ozone-platform', 'x11');
app.commandLine.appendSwitch("ozone-platform", "x11");
}
}
@ -191,6 +191,7 @@ const resolveAppLanguage = (languageTags) => {
"pl": "pl_PL",
"pt": "pt_BR",
"ru": "ru_RU",
"sk": "sk_SK",
"tr": "tr_TR"
};

View file

@ -6,7 +6,7 @@
"id": "20200924100717-yzwzn64",
"title": "Kernel parameter",
"type": "doc",
"updated": "20221025095725"
"updated": "20260302173748"
},
"Children": [
{
@ -212,7 +212,7 @@
"HeadingLevel": 3,
"Properties": {
"id": "20220517144139-qeoe1f3",
"updated": "20220517144139"
"updated": "20260302173748"
},
"Children": [
{
@ -227,7 +227,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220517144139-7q5hnts",
"updated": "20220517144139"
"updated": "20260302173748"
},
"Children": [
{
@ -241,7 +241,7 @@
},
{
"Type": "NodeText",
"Data": " will use Simplified Chinese to initialize the appearance language, the default is "
"Data": " will use Simplified Chinese to initialize the appearance language, the default is "
},
{
"Type": "NodeTextMark",
@ -250,7 +250,7 @@
},
{
"Type": "NodeText",
"Data": ". Currently available values: "
"Data": ". Currently available values: "
},
{
"Type": "NodeTextMark",
@ -259,7 +259,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -268,7 +268,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -277,7 +277,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -286,7 +286,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -295,7 +295,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -304,7 +304,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -313,7 +313,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -322,7 +322,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -331,7 +331,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -340,7 +340,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -349,7 +349,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -358,7 +358,16 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "sk_SK"
},
{
"Type": "NodeText",
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -367,7 +376,7 @@
},
{
"Type": "NodeText",
"Data": ", "
"Data": ", "
},
{
"Type": "NodeTextMark",
@ -376,7 +385,7 @@
},
{
"Type": "NodeText",
"Data": " and "
"Data": " and "
},
{
"Type": "NodeTextMark",
@ -385,7 +394,7 @@
},
{
"Type": "NodeText",
"Data": "."
"Data": "."
}
]
},

View file

@ -6,7 +6,7 @@
"id": "20200828105441-r76vmu5",
"title": "内核参数",
"type": "doc",
"updated": "20221025095729"
"updated": "20260302173621"
},
"Children": [
{
@ -292,7 +292,7 @@
"HeadingLevel": 3,
"Properties": {
"id": "20220517143906-h2p1a5m",
"updated": "20220517143913"
"updated": "20260302173621"
},
"Children": [
{
@ -317,270 +317,174 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220517143906-cd8h1g8",
"updated": "20220517144043"
"updated": "20260302173621"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用 ",
"Properties": {
"id": ""
}
"Data": "使用 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "--lang=zh_CN"
},
{
"Type": "NodeText",
"Data": " 后将使用简体中文初始化外观语言,默认 ",
"Properties": {
"id": ""
}
"Data": " 后将使用简体中文初始化外观语言,默认 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "en_US"
},
{
"Type": "NodeText",
"Data": "。目前可选值:",
"Properties": {
"id": ""
}
"Data": "​。目前可选值:"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ar_SA"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "de_DE"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "en_US"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "es_ES"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "fr_FR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "he_IL"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "it_IT"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ja_JP"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ko_KR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "pl_PL"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "pt_BR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ru_RU"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "sk_SK"
},
{
"Type": "NodeText",
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "tr_TR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "zh_CHT"
},
{
"Type": "NodeText",
"Data": " 和 ",
"Properties": {
"id": ""
}
"Data": " 和 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "zh_CN"
},
{
"Type": "NodeText",
"Data": "。",
"Properties": {
"id": ""
}
"Data": "​。"
}
]
},

View file

@ -6,7 +6,7 @@
"id": "20211226122358-hctqcn5",
"title": "Kernel 參數",
"type": "doc",
"updated": "20221025095721"
"updated": "20260302173650"
},
"Children": [
{
@ -292,7 +292,7 @@
"HeadingLevel": 3,
"Properties": {
"id": "20220517144220-400hbxb",
"updated": "20220517144220"
"updated": "20260302173650"
},
"Children": [
{
@ -317,270 +317,174 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220517144220-5dryt3i",
"updated": "20220517144233"
"updated": "20260302173650"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用 ",
"Properties": {
"id": ""
}
"Data": "使用 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "--lang=zh_CN"
},
{
"Type": "NodeText",
"Data": " 後將使用簡體中文初始化外觀語言,預設 ",
"Properties": {
"id": ""
}
"Data": " 後將使用簡體中文初始化外觀語言,預設 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "en_US"
},
{
"Type": "NodeText",
"Data": "。目前可選值:",
"Properties": {
"id": ""
}
"Data": "​。目前可選值:"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ar_SA"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "de_DE"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "en_US"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "es_ES"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "fr_FR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "he_IL"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "it_IT"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ja_JP"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ko_KR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "pl_PL"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "pt_BR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "ru_RU"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "sk_SK"
},
{
"Type": "NodeText",
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "tr_TR"
},
{
"Type": "NodeText",
"Data": "、",
"Properties": {
"id": ""
}
"Data": "​、"
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "zh_CHT"
},
{
"Type": "NodeText",
"Data": " 和 ",
"Properties": {
"id": ""
}
"Data": " 和 "
},
{
"Type": "NodeTextMark",
"Properties": {
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "zh_CN"
},
{
"Type": "NodeText",
"Data": "。",
"Properties": {
"id": ""
}
"Data": "​。"
}
]
},

View file

@ -7,7 +7,7 @@
"id": "20240530101000-xq26o73",
"title": "カーネルパラメータ",
"type": "doc",
"updated": "20240530101000"
"updated": "20260302173724"
},
"Children": [
{
@ -249,7 +249,7 @@
"Properties": {
"ID": "20240530101000-rje9q9t",
"id": "20240530101000-pzmi4gj",
"updated": "20240530101000"
"updated": "20260302173724"
},
"Children": [
{
@ -263,9 +263,8 @@
"ID": "20240530101000-bqisa84",
"Type": "NodeParagraph",
"Properties": {
"ID": "20240530101000-f48ihvt",
"id": "20240530101000-bqisa84",
"updated": "20240530101000"
"updated": "20260302173724"
},
"Children": [
{
@ -380,6 +379,15 @@
"Type": "NodeText",
"Data": "​、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "sk_SK"
},
{
"Type": "NodeText",
"Data": "​、"
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",

View file

@ -8,7 +8,7 @@ module.exports = async function afterPack(context) {
async function removeLanguagePacks(appOutDir, packager, platform) {
// 支持的语言都要保留,否则影响开发者工具字体显示
const wantedLanguages = ["ar_SA", "de_DE", "en_US", "es_ES", "fr_FR", "he_IL", "it_IT", "ja_JP", "ko_KR", "pl_PL", "pt_BR", "ru_RU", "tr_TR", "zh_CHT", "zh_CN"];
const wantedLanguages = ["ar_SA", "de_DE", "en_US", "es_ES", "fr_FR", "he_IL", "it_IT", "ja_JP", "ko_KR", "pl_PL", "pt_BR", "ru_RU", "sk_SK", "tr_TR", "zh_CHT", "zh_CN"];
const keepPrefixes = new Set(wantedLanguages.map(lang => lang.substring(0, 2)));
let resourcePath;

View file

@ -7,13 +7,7 @@ import {fetchPost} from "../util/fetch";
import {setAccessAuthCode} from "./util/about";
import {exportLayout} from "../layout/util";
import {exitSiYuan, processSync} from "../dialog/processSystem";
import {
isInMobileApp,
isIPad,
isMac,
openByMobile,
writeText
} from "../protyle/util/compatibility";
import {isInMobileApp, isIPad, isMac, openByMobile, writeText} from "../protyle/util/compatibility";
import {showMessage} from "../dialog/message";
import {Dialog} from "../dialog";
import {confirmDialog} from "../dialog/confirmDialog";
@ -63,7 +57,7 @@ export const about = {
<div class="fn__space"></div>
<input class="b3-switch fn__flex-center" id="downloadInstallPkg" type="checkbox"${window.siyuan.config.system.downloadInstallPkg ? " checked" : ""}>
</label>
<div class="b3-label">
<div class="b3-label${isBrowser() ? " fn__none" : ""}">
<label class="fn__flex config__item">
<div class="fn__flex-1">
${window.siyuan.languages.about11}

View file

@ -317,6 +317,7 @@ export abstract class Constants {
pl_PL: "20210808180117-6v0mkxr",
pt_BR: "20210808180117-6v0mkxr",
ru_RU: "20210808180117-6v0mkxr",
sk_SK: "20210808180117-6v0mkxr",
tr_TR: "20210808180117-6v0mkxr",
zh_CHT: "20211226090932-5lcq56f",
zh_CN: "20210808180117-czj9bvb",

View file

@ -26,7 +26,7 @@ import {
import {initMessage, showMessage} from "./dialog/message";
import {getAllTabs} from "./layout/getAll";
import {getLocalStorage, isChromeBrowser, isInMobileApp} from "./protyle/util/compatibility";
import {getSearch} from "./util/functions";
import {getSearch, isBrowser} from "./util/functions";
import {checkPublishServiceClosed} from "./util/processMessage";
import {hideAllElements} from "./protyle/ui/hideElements";
import {loadPlugins, reloadPlugin} from "./plugin/loader";
@ -191,6 +191,10 @@ export class App {
case "openFileById":
openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]});
break;
case "exit":
if (isBrowser()) {
window.location.href = "about:blank";
}
}
}
}

View file

@ -15,12 +15,7 @@ import {bootSync} from "../dialog/processSystem";
import {initMessage, showMessage} from "../dialog/message";
import {goBack} from "./util/MobileBackFoward";
import {activeBlur, hideKeyboardToolbar, showKeyboardToolbar} from "./util/keyboardToolbar";
import {
getLocalStorage,
isChromeBrowser,
isInMobileApp,
writeText
} from "../protyle/util/compatibility";
import {getLocalStorage, isChromeBrowser, isInMobileApp, writeText} from "../protyle/util/compatibility";
import {getCurrentEditor, openMobileFileById} from "./editor";
import {getSearch} from "../util/functions";
import {checkPublishServiceClosed} from "../util/processMessage";

View file

@ -2,7 +2,9 @@ import {openMobileFileById} from "../editor";
import {
processSync,
progressLoading,
reloadSync, setDefRefCount, setRefDynamicText,
reloadSync,
setDefRefCount,
setRefDynamicText,
transactionError
} from "../../dialog/processSystem";
import {App} from "../../index";
@ -24,7 +26,7 @@ export const onMessage = (app: App, data: IWebSocketData) => {
break;
case "sendDeviceNotification":
if (window.JSAndroid.sendNotification) {
window.JSAndroid.sendNotification(data.data.title, data.data.body);
window.JSAndroid.sendNotification(data.data.title, data.data.body, data.data.delayInSeconds);
}
break;
case "backgroundtask":

View file

@ -10,7 +10,6 @@ import {openGlobalSearch} from "../../search/util";
/// #else
import {popSearch} from "../../mobile/menu/search";
/// #endif
import {getEventName} from "../util/compatibility";
import {Dialog} from "../../dialog";
import {Constants} from "../../constants";
import {assetMenu} from "../../menus/protyle";

View file

@ -289,6 +289,7 @@ declare namespace Config {
| "pl_PL"
| "pt_BR"
| "ru_RU"
| "sk_SK"
| "tr_TR"
| "zh_CN"
| "zh_CHT";

View file

@ -255,7 +255,7 @@ interface Window {
getScreenWidthPx(): number
exit(): void
setWebViewFocusable(enable: boolean): void
sendNotification(title: string, body: string): void
sendNotification(title: string, body: string, delayInSeconds: number): void
};
JSHarmony: {
showKeyboard(): void

View file

@ -40,14 +40,36 @@ func sendDeviceNotification(c *gin.Context) {
return
}
title := arg["title"].(string)
body := arg["body"].(string)
evt := util.NewCmdResult("sendDeviceNotification", 0, util.PushModeSingleSelf)
evt.Data = map[string]interface{}{
"title": title,
"body": body,
var title string
if nil != arg["title"] {
title = strings.TrimSpace(arg["title"].(string))
} else {
ret.Code = -1
ret.Msg = "title can't be empty"
return
}
util.PushEvent(evt)
var body string
if nil != arg["body"] {
body = strings.TrimSpace(arg["body"].(string))
} else {
ret.Code = -1
ret.Msg = "body can't be empty"
return
}
var delayInSeconds int
if nil != arg["delayInSeconds"] {
delayInSeconds = int(arg["delayInSeconds"].(float64))
} else {
delayInSeconds = 1
}
util.BroadcastByType("main", "sendDeviceNotification", 0, "", map[string]interface{}{
"title": title,
"body": body,
"delayInSeconds": delayInSeconds,
})
}
func pushMsg(c *gin.Context) {

View file

@ -509,6 +509,7 @@ const (
NumberFormatSGD NumberFormat = "SGD" // 新加坡元
NumberFormatNZD NumberFormat = "NZD" // 新西兰元
NumberFormatILS NumberFormat = "ILS" // 以色列新谢克尔
NumberFormatSKK NumberFormat = "SKK" // 斯洛伐克克朗
)
func NewFormattedValueNumber(content float64, format NumberFormat) (ret *ValueNumber) {
@ -605,6 +606,9 @@ func formatNumber(content float64, format NumberFormat) string {
case NumberFormatILS:
p := message.NewPrinter(language.Hebrew)
return p.Sprintf("ILS₪%.2f", content)
case NumberFormatSKK:
p := message.NewPrinter(language.Slovak)
return p.Sprintf("SKK%.2f", content)
default:
return strconv.FormatFloat(content, 'f', -1, 64)
}

View file

@ -790,6 +790,7 @@ func Close(force, setCurrentWorkspace bool, execInstallPkg int) (exitCode int) {
}
}
util.BroadcastByType("main", "exit", 0, "", nil)
util.UnlockWorkspace()
time.Sleep(500 * time.Millisecond)

View file

@ -58,6 +58,8 @@ func LogoutAuth(c *gin.Context) {
ret.Code = -1
ret.Msg = "save session failed"
}
util.BroadcastByType("main", "logoutAuth", 0, "", nil)
}
func LoginAuth(c *gin.Context) {

View file

@ -18,6 +18,7 @@ package proxy
import (
"crypto/tls"
"errors"
"net"
"net/http"
"net/http/httputil"
@ -51,39 +52,10 @@ func InitFixedPortService(host string, useTLS bool, certPath, keyPath string) {
return
}
m := cmux.New(ln)
// Match TLS connections (first byte 0x16 indicates TLS handshake)
tlsL := m.Match(cmux.TLS())
// Match HTTP (anything else)
httpL := m.Match(cmux.Any())
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
logging.LogWarnf("failed to load TLS cert for fixed port service: %s", err)
ln.Close()
return
}
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}
tlsListener := tls.NewListener(tlsL, tlsConfig)
go func() {
httpServer := &http.Server{Handler: proxy}
if err := httpServer.Serve(httpL); err != nil && err != cmux.ErrListenerClosed {
logging.LogWarnf("fixed port HTTP server error: %s", err)
if serveErr := util.ServeMultiplexed(ln, proxy, certPath, keyPath, nil); serveErr != nil {
if serveErr != cmux.ErrListenerClosed && !errors.Is(serveErr, http.ErrServerClosed) {
logging.LogWarnf("fixed port cmux serve error: %s", serveErr)
}
}()
go func() {
httpsServer := &http.Server{Handler: proxy}
if err := httpsServer.Serve(tlsListener); err != nil && err != cmux.ErrListenerClosed {
logging.LogWarnf("fixed port HTTPS server error: %s", err)
}
}()
if err := m.Serve(); err != nil && err != cmux.ErrListenerClosed {
logging.LogWarnf("fixed port cmux serve error: %s", err)
}
} else {
logging.LogInfof("fixed port service [%s] is running", addr)

View file

@ -47,6 +47,7 @@ import (
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/server/proxy"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/soheilhy/cmux"
"golang.org/x/net/webdav"
)
@ -244,6 +245,20 @@ func Serve(fastMode bool, cookieKey string) {
Handler: ginServer,
}
if useTLS && (util.FixedPort == util.ServerPort || util.IsPortOpen(util.FixedPort)) {
if err = util.ServeMultiplexed(ln, ginServer, certPath, keyPath, util.HttpServer); err != nil {
if errors.Is(err, http.ErrServerClosed) || err == cmux.ErrListenerClosed {
return
}
if !fastMode {
logging.LogErrorf("boot kernel failed: %s", err)
os.Exit(logging.ExitCodeUnavailablePort)
}
}
return
}
if err = util.HttpServer.Serve(ln); err != nil {
if errors.Is(err, http.ErrServerClosed) {
return

52
kernel/util/cmux.go Normal file
View file

@ -0,0 +1,52 @@
package util
import (
"crypto/tls"
"errors"
"net"
"net/http"
"github.com/siyuan-note/logging"
"github.com/soheilhy/cmux"
)
func ServeMultiplexed(ln net.Listener, handler http.Handler, certPath, keyPath string, httpServer *http.Server) error {
m := cmux.New(ln)
tlsL := m.Match(cmux.TLS())
httpL := m.Match(cmux.Any())
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
logging.LogErrorf("failed to load TLS cert for multiplexing: %s", err)
return err
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
tlsListener := tls.NewListener(tlsL, tlsConfig)
if httpServer == nil {
httpServer = &http.Server{Handler: handler}
} else {
httpServer.Handler = handler
}
httpsServer := &http.Server{Handler: handler}
go func() {
if serveErr := httpServer.Serve(httpL); serveErr != nil && serveErr != cmux.ErrListenerClosed && !errors.Is(serveErr, http.ErrServerClosed) {
logging.LogErrorf("multiplexed HTTP server error: %s", serveErr)
}
}()
go func() {
if serveErr := httpsServer.Serve(tlsListener); serveErr != nil && serveErr != cmux.ErrListenerClosed && !errors.Is(serveErr, http.ErrServerClosed) {
logging.LogErrorf("multiplexed HTTPS server error: %s", serveErr)
}
}()
return m.Serve()
}

View file

@ -96,7 +96,7 @@ func Boot() {
readOnly := flag.String("readonly", "false", "read-only mode")
accessAuthCode := flag.String("accessAuthCode", "", "access auth code")
ssl := flag.Bool("ssl", false, "for https and wss")
lang := flag.String("lang", "", "ar_SA/de_DE/en_US/es_ES/fr_FR/he_IL/it_IT/ja_JP/ko_KR/pl_PL/pt_BR/ru_RU/tr_TR/zh_CHT/zh_CN")
lang := flag.String("lang", "", "ar_SA/de_DE/en_US/es_ES/fr_FR/he_IL/it_IT/ja_JP/ko_KR/pl_PL/pt_BR/ru_RU/sk_SK/tr_TR/zh_CHT/zh_CN")
mode := flag.String("mode", "prod", "dev/prod")
flag.Parse()