This repository has been archived by the owner on Dec 13, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
yuhaiin.go
302 lines (282 loc) · 6.79 KB
/
yuhaiin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
package main
import (
"bufio"
"context"
"errors"
"flag"
"fmt"
"io"
"log"
"net"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"syscall"
"time"
"github.com/therecipe/qt/widgets"
"github.com/Asutorufa/yuhaiinqt/gui/sysproxy"
//_ "net/http/pprof"
"github.com/Asutorufa/yuhaiinqt/api"
"github.com/Asutorufa/yuhaiinqt/gui"
"github.com/golang/protobuf/ptypes/empty"
"google.golang.org/grpc"
)
var (
extKernel bool
clientHost string
kernel string
cmd *exec.Cmd
signChannel chan os.Signal
exitFuncCalled bool
qtApp *widgets.QApplication
apiClient api.ProcessInitClient
clientConn *grpc.ClientConn
exitCall []func()
conn2c bool
conn2S = errors.New("connect Exists Client Successful")
conn2Re = errors.New("retry Connect Kernel")
)
func getFreePort() (string, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return "", err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return "", err
}
defer func() {
if err := l.Close(); err != nil {
log.Println(err)
}
}()
return strconv.Itoa(l.Addr().(*net.TCPAddr).Port), nil
}
func startGrpc() {
if extKernel {
return
}
fmt.Println("Try start kernel.")
port, err := getFreePort()
if err != nil {
gui.MessageBox(err.Error())
return
}
clientHost = net.JoinHostPort("127.0.0.1", port)
fmt.Println("gRPC Host:", clientHost)
cmd = exec.Command(kernel, "-host", clientHost, "-kwdc")
fmt.Println("Start kernel command:", cmd.String())
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Println("Get standard output failed:", err)
gui.MessageBox(err.Error())
}
stderr, err := cmd.StderrPipe()
if err != nil {
log.Println("Get standard error failed:", err)
gui.MessageBox(err.Error())
}
fmt.Println("Try to running kernel command.")
err = cmd.Start()
if err != nil {
log.Println("Running kernel command failed:", err)
gui.MessageBox(err.Error())
panic(err)
}
exitCall = append(exitCall, func() {
fmt.Println("Stop kernel")
if cmd != nil && cmd.Process != nil {
err := cmd.Process.Kill()
if err != nil {
log.Println(err)
}
}
})
fmt.Println("Running kernel command successful.")
stdoutReader := bufio.NewReader(stdout)
stderrReader := bufio.NewReader(stderr)
go func() {
for {
line, err := stdoutReader.ReadString('\n')
if err != nil || err == io.EOF {
break
}
fmt.Printf("kernel -> %s", line)
}
}()
go func() {
for {
line, err := stderrReader.ReadString('\n')
if err != nil || err == io.EOF {
break
}
fmt.Printf("kernel -> %s", line)
}
}()
go func() {
err := cmd.Wait()
if err != nil {
log.Println("kernel -> ", err)
}
if conn2c {
conn2c = false
return
}
log.Println("kernel stop running")
exitFunc()
}()
}
func sigh() {
//https://colobu.com/2015/10/09/Linux-Signals/
signChannel = make(chan os.Signal)
signal.Notify(signChannel, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
for s := range signChannel {
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
exitFunc()
default:
fmt.Println("OTHERS SIGN:", s)
}
}
}()
}
func exitFunc() {
if exitFuncCalled {
return
}
fmt.Println("Start Cleaning Process")
exitFuncCalled = true
for index := range exitCall {
exitCall[index]()
}
fmt.Println("Unset System Proxy")
sysproxy.UnsetSysProxy()
os.Exit(0)
}
func execPath() string {
file, err := exec.LookPath(os.Args[0])
if err != nil {
panic(err)
}
path, err := filepath.Abs(file)
if err != nil {
panic(err)
}
return filepath.Dir(path)
}
func main() {
sigh()
log.SetFlags(log.Llongfile)
flag.BoolVar(&extKernel, "nokernel", false, "not run kernel")
flag.StringVar(&clientHost, "host", "127.0.0.1:50051", "kernel rpc host")
if runtime.GOOS == "windows" {
flag.StringVar(&kernel, "kernel", execPath()+"\\yuhaiin_kernel.exe", "kernel file")
} else {
flag.StringVar(&kernel, "kernel", execPath()+"/yuhaiin_kernel", "kernel file")
}
flag.Parse()
_reConnectGrpc:
fmt.Println("Use external:", extKernel)
fmt.Println("Kernel Path:", kernel)
startGrpc()
var err error
ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
fmt.Println("Try to Create gRPC Dial.")
clientConn, err = grpc.DialContext(ctx, clientHost, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Println("Create gRPC Dial failed:", err)
gui.MessageBox(err.Error())
return
}
fmt.Println("Create gRPC Dial successful.")
defer func() {
_ = clientConn.Close()
}()
fmt.Println("Create API Client.")
apiClient = api.NewProcessInitClient(clientConn)
err = checkLockFile()
if err == conn2Re {
goto _reConnectGrpc
}
if err == conn2S {
return
}
if err != nil {
panic(err)
}
fmt.Println("Open GUI.")
qtApp = gui.NewGui(clientConn).App
qtApp.Exec()
defer exitFunc()
}
func checkLockFile() (err error) {
fmt.Println("Try to Get lock file state.")
_, err = apiClient.CreateLockFile(context.Background(), &empty.Empty{})
if err != nil {
log.Println(err)
fmt.Println("Try to Get Already Running kernel gRPC Host.")
s, err := apiClient.GetRunningHost(context.Background(), &empty.Empty{})
if err != nil {
fmt.Println("Get Already Running kernel gRPC Host failed.")
return err
}
err = clientConn.Close()
if err != nil {
return err
}
fmt.Println("Get Running Host Successful, Host:", s.Value)
ctx, _ := context.WithTimeout(context.Background(), time.Second*3)
fmt.Println("Try to Create gRPC Dial.")
clientConn, err = grpc.DialContext(ctx, s.Value, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
fmt.Println("Create gRPC Dial failed:", err)
return err
}
fmt.Println("Create gRPC Dial successful.")
apiClient = api.NewProcessInitClient(clientConn)
fmt.Println("Try to Open GUI.")
_, err = apiClient.ClientOn(context.Background(), &empty.Empty{})
if err != nil {
fmt.Println("Call exists GUI failed:", err)
fmt.Println("Try to Stop exists kernel")
_, err := apiClient.StopKernel(context.Background(), &empty.Empty{})
if err != nil {
kernelPid, err := apiClient.GetKernelPid(context.Background(), &empty.Empty{})
if err != nil {
return err
}
fmt.Println("Get Kernel Pid ", kernelPid.Value)
process, err := os.FindProcess(int(kernelPid.Value))
if err != nil {
return err
}
fmt.Println("Kill exists Kernel ", kernelPid.Value)
err = process.Kill()
if err != nil {
return err
}
err = clientConn.Close()
if err != nil {
return err
}
conn2c = true
fmt.Println("Kill cmd and ReStart Kernel")
if cmd != nil && cmd.Process != nil {
err = cmd.Process.Kill()
if err != nil {
log.Println(err)
}
}
}
fmt.Println("Try to ReConnect")
return conn2Re
}
fmt.Println("Open GUI Successful.")
return conn2S
}
return
}