diff --git a/app/electron/main.js b/app/electron/main.js
index faae062be..1c7ab3851 100644
--- a/app/electron/main.js
+++ b/app/electron/main.js
@@ -606,13 +606,19 @@ const initKernel = (initData) => {
count++
if (64 < count) {
writeLog('get kernel port failed [pid=' + kernelProcessPid + '], try to use 6806')
- return kernelPort
+ return
}
}
}
}
kernelPort = await getKernelPort()
+ if (!kernelPort) {
+ showErrorWindow('⚠️ 获取内核服务端口失败 Failed to get kernel serve port',
+ '
获取内核服务端口失败,请确保程序拥有网络权限并不受防火墙和杀毒软件阻止。
Failed to get kernel serve port, please make sure the program has network permissions and is not blocked by firewalls and antivirus software.
')
+ bootWindow.destroy()
+ resolve(false)
+ }
writeLog("got kernel port [" + kernelPort + "]")
let gotVersion = false
@@ -713,7 +719,7 @@ app.whenReady().then(() => {
// 改进桌面端初始化时使用的外观语言 https://github.com/siyuan-note/siyuan/issues/6803
let languages = app.getPreferredSystemLanguages();
- let language = languages && 0 < languages.length && "zh-Hans-CN" === languages[0] ? "zh_CN": "en_US";
+ let language = languages && 0 < languages.length && "zh-Hans-CN" === languages[0] ? "zh_CN" : "en_US";
firstOpenWindow.loadFile(
initHTMLPath, {
query: {
diff --git a/kernel/go.mod b/kernel/go.mod
index 398d5d75d..09a3604a8 100644
--- a/kernel/go.mod
+++ b/kernel/go.mod
@@ -27,6 +27,7 @@ require (
github.com/gin-contrib/gzip v0.0.6
github.com/gin-contrib/sessions v0.0.5
github.com/gin-gonic/gin v1.8.1
+ github.com/gofrs/flock v0.8.1
github.com/imroc/req/v3 v3.26.4
github.com/jinzhu/copier v0.3.5
github.com/json-iterator/go v1.1.12
diff --git a/kernel/go.sum b/kernel/go.sum
index 0833136d7..dd417aaac 100644
--- a/kernel/go.sum
+++ b/kernel/go.sum
@@ -125,6 +125,8 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
+github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
diff --git a/kernel/model/conf.go b/kernel/model/conf.go
index 6a670fb4b..c951e2866 100644
--- a/kernel/model/conf.go
+++ b/kernel/model/conf.go
@@ -434,6 +434,7 @@ func Close(force bool, execInstallPkg int) (exitCode int) {
treenode.SaveBlockTree()
clearWorkspaceTemp()
clearPortJSON()
+ util.UnlockWorkspace()
go func() {
time.Sleep(500 * time.Millisecond)
diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go
index b30157119..72850d31e 100644
--- a/kernel/util/runtime.go
+++ b/kernel/util/runtime.go
@@ -36,6 +36,7 @@ const (
ExitCodeUnavailablePort = 21 // 端口不可用
ExitCodeCreateConfDirErr = 22 // 创建配置目录失败
ExitCodeBlockTreeErr = 23 // 无法读写 blocktree.msgpack 文件
+ ExitCodeWorkspaceLocked = 24 // 工作区已被锁定
ExitCodeOk = 0 // 正常退出
ExitCodeFatal = 1 // 致命错误
)
diff --git a/kernel/util/working.go b/kernel/util/working.go
index 6073f76bf..0b27d3e57 100644
--- a/kernel/util/working.go
+++ b/kernel/util/working.go
@@ -32,6 +32,7 @@ import (
"github.com/88250/gulu"
figure "github.com/common-nighthawk/go-figure"
+ "github.com/gofrs/flock"
"github.com/siyuan-note/httpclient"
"github.com/siyuan-note/logging"
)
@@ -95,6 +96,10 @@ func Boot() {
SSL = *ssl
LogPath = filepath.Join(TempDir, "siyuan.log")
logging.SetLogPath(LogPath)
+
+ // 工作空间仅允许被一个内核进程伺服
+ tryLockWorkspace()
+
AppearancePath = filepath.Join(ConfDir, "appearance")
if "dev" == Mode {
ThemesPath = filepath.Join(WorkingDir, "appearance", "themes")
@@ -154,6 +159,7 @@ var (
WorkingDir, _ = os.Getwd()
WorkspaceDir string // 工作空间目录路径
+ WorkspaceLock *flock.Flock // 工作空间锁
ConfDir string // 配置目录路径
DataDir string // 数据目录路径
RepoDir string // 仓库目录路径
@@ -437,3 +443,27 @@ func GetDataAssetsAbsPath() (ret string) {
}
return
}
+
+func tryLockWorkspace() {
+ WorkspaceLock = flock.New(filepath.Join(WorkspaceDir, ".lock"))
+ if err := WorkspaceLock.Lock(); nil != err {
+ logging.LogErrorf("lock workspace [%s] failed: %s", WorkspaceDir, err)
+ os.Exit(ExitCodeWorkspaceLocked)
+ }
+}
+
+func UnlockWorkspace() {
+ if nil == WorkspaceLock {
+ return
+ }
+
+ if err := WorkspaceLock.Unlock(); nil != err {
+ logging.LogErrorf("unlock workspace [%s] failed: %s", WorkspaceDir, err)
+ return
+ }
+
+ if err := os.Remove(filepath.Join(WorkspaceDir, ".lock")); nil != err {
+ logging.LogErrorf("remove workspace lock failed: %s", err)
+ return
+ }
+}