A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1// SiYuan - Refactor your thinking
2// Copyright (c) 2020-present, b3log.org
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17package model
18
19import (
20 "os"
21 "os/signal"
22 "strconv"
23 "strings"
24 "syscall"
25 "time"
26
27 goPS "github.com/mitchellh/go-ps"
28 "github.com/siyuan-note/logging"
29 "github.com/siyuan-note/siyuan/kernel/util"
30)
31
32func HandleSignal() {
33 c := make(chan os.Signal)
34 signal.Notify(c, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
35 s := <-c
36 logging.LogInfof("received os signal [%s], exit kernel process now", s)
37 Close(false, true, 1)
38}
39
40var (
41 firstRunHookDesktopUIProcJob = true
42)
43
44func HookDesktopUIProcJob() {
45 if util.ContainerStd != util.Container || "dev" == util.Mode {
46 return
47 }
48
49 if firstRunHookDesktopUIProcJob {
50 // 等待启动结束再监控
51 time.Sleep(30 * time.Second)
52 firstRunHookDesktopUIProcJob = false
53 return
54 }
55
56 if 0 < util.CountSessions() {
57 // 如果存在活动的会话则说明 UI 进程还在运行
58 return
59 }
60
61 uiProcCount := getAttachedUIProcCount()
62 if 0 < uiProcCount {
63 return
64 }
65
66 logging.LogWarnf("no active UI proc, continue to check from attached ui processes after 15s")
67 time.Sleep(15 * time.Second)
68 uiProcCount = getAttachedUIProcCount()
69 if 0 < uiProcCount {
70 return
71 }
72 logging.LogWarnf("no active UI proc, continue to check from all processes after 15s")
73 time.Sleep(15 * time.Second)
74 uiProcCount = getUIProcCount()
75 if 0 < uiProcCount {
76 logging.LogInfof("active UI proc count [%d]", uiProcCount)
77 return
78 }
79
80 logging.LogWarnf("confirmed no active UI proc, exit kernel process now")
81 Close(false, true, 1)
82}
83
84var uiProcNames = []string{"siyuan", "electron"}
85
86// getAttachedUIProcCount 获取已经附加的 UI 进程数。
87func getAttachedUIProcCount() (ret int) {
88 util.UIProcessIDs.Range(func(uiProcIDArg, _ interface{}) bool {
89 uiProcID, err := strconv.Atoi(uiProcIDArg.(string))
90 if err != nil {
91 logging.LogErrorf("invalid UI proc ID [%s]: %s", uiProcIDArg, err)
92 return true
93 }
94
95 proc, err := goPS.FindProcess(uiProcID)
96 if err != nil {
97 logging.LogErrorf("find UI proc [%d] failed: %s", uiProcID, err)
98 return true
99 }
100
101 if nil == proc {
102 return true
103 }
104
105 procName := strings.ToLower(proc.Executable())
106 uiProcOk := false
107 for _, name := range uiProcNames {
108 if uiProcOk = strings.Contains(procName, name); uiProcOk {
109 break
110 }
111 }
112 if uiProcOk {
113 ret++
114 }
115 return true
116 })
117 return
118}
119
120// getUIProcCount 获取 UI 进程数。
121func getUIProcCount() (ret int) {
122 pid := os.Getpid()
123 procs, _ := goPS.Processes()
124 for _, proc := range procs {
125 if proc.Pid() == pid {
126 continue
127 }
128
129 procName := strings.ToLower(proc.Executable())
130 uiProcOk := false
131 for _, name := range uiProcNames {
132 if uiProcOk = strings.Contains(procName, name); uiProcOk {
133 break
134 }
135 }
136 if uiProcOk {
137 ret++
138 }
139 }
140 return
141}