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 server
18
19import (
20 "fmt"
21 "os"
22 "os/exec"
23 "path/filepath"
24 "strconv"
25 "strings"
26 "time"
27
28 "github.com/88250/gulu"
29 goPS "github.com/mitchellh/go-ps"
30 "github.com/siyuan-note/logging"
31 "github.com/siyuan-note/siyuan/kernel/util"
32)
33
34func killRunningKernel() {
35 defer logging.Recover()
36
37 now := time.Now()
38 defer logging.LogInfof("check running kernel elapsed [%dms]", time.Since(now).Milliseconds())
39
40 processes, err := goPS.Processes()
41 if err != nil {
42 logging.LogErrorf("get processes failed: %s", err)
43 killByPort(util.FixedPort)
44 return
45 }
46
47 currentPid := os.Getpid()
48 killed := false
49 for _, process := range processes {
50 if process.Pid() == currentPid {
51 continue
52 }
53 procName := strings.ToLower(process.Executable())
54 if strings.Contains(procName, "siyuan-kernel") {
55 kill(fmt.Sprintf("%d", process.Pid()))
56 killed = true
57 }
58 }
59
60 if killed {
61 portJSON := filepath.Join(util.HomeDir, ".config", "siyuan", "port.json")
62 os.RemoveAll(portJSON)
63 }
64}
65
66func killByPort(port string) {
67 if !util.IsPortOpen(port) {
68 return
69 }
70
71 portJSON := filepath.Join(util.HomeDir, ".config", "siyuan", "port.json")
72 os.RemoveAll(portJSON)
73
74 pid := pidByPort(port)
75 if "" == pid {
76 return
77 }
78
79 pidInt, _ := strconv.Atoi(pid)
80 proc, _ := goPS.FindProcess(pidInt)
81 var name string
82 if nil != proc {
83 name = proc.Executable()
84 }
85 kill(pid)
86 logging.LogInfof("killed process [name=%s, pid=%s]", name, pid)
87}
88
89func kill(pid string) {
90 var killCmd *exec.Cmd
91 if gulu.OS.IsWindows() {
92 killCmd = exec.Command("cmd", "/c", "TASKKILL /F /PID "+pid)
93 } else {
94 killCmd = exec.Command("kill", "-9", pid)
95 }
96 gulu.CmdAttr(killCmd)
97 killCmd.CombinedOutput()
98}
99
100func pidByPort(port string) (ret string) {
101 if gulu.OS.IsWindows() {
102 cmd := exec.Command("cmd", "/c", "netstat -ano | findstr "+port)
103 gulu.CmdAttr(cmd)
104 data, err := cmd.CombinedOutput()
105 if err != nil {
106 logging.LogErrorf("netstat failed: %s", err)
107 return
108 }
109 output := string(data)
110 lines := strings.Split(output, "\n")
111 for _, l := range lines {
112 if strings.Contains(l, "LISTENING") {
113 l = l[strings.Index(l, "LISTENING")+len("LISTENING"):]
114 l = strings.TrimSpace(l)
115 ret = l
116 return
117 }
118 }
119 return
120 }
121
122 cmd := exec.Command("lsof", "-Fp", "-i", ":"+port)
123 gulu.CmdAttr(cmd)
124 data, err := cmd.CombinedOutput()
125 if err != nil {
126 logging.LogErrorf("lsof failed: %s", err)
127 return
128 }
129 output := string(data)
130 lines := strings.Split(output, "\n")
131 for _, l := range lines {
132 if strings.HasPrefix(l, "p") {
133 l = l[1:]
134 ret = l
135 return
136 }
137 }
138 return
139}