|
@@ -3,6 +3,7 @@ package main
|
|
|
import (
|
|
import (
|
|
|
"bufio"
|
|
"bufio"
|
|
|
"context"
|
|
"context"
|
|
|
|
|
+ "encoding/json"
|
|
|
"errors"
|
|
"errors"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"io"
|
|
"io"
|
|
@@ -69,35 +70,40 @@ func main() {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- term() // 启动终端模拟器卍
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ fmt.Printf("[%s] 正在连接目标设备...\n", MODULE_NAME)
|
|
|
|
|
|
|
|
-// SHELL终端模拟器
|
|
|
|
|
-// 1, 连接远程设备, 是否成功
|
|
|
|
|
-// 2, 等待用户输入, 封装请求
|
|
|
|
|
-// 3, 没有用户输入, 封装心跳
|
|
|
|
|
-// 4, 发送请求数据, 远程执行
|
|
|
|
|
-// 5, 耗时用户请求, 允许中断, Ctrl+C
|
|
|
|
|
-// 6, 等待返回结果, 打印输出
|
|
|
|
|
-// 7, 循环等待下次, 直到退出
|
|
|
|
|
-func term() {
|
|
|
|
|
var pingState atomic.Bool
|
|
var pingState atomic.Bool
|
|
|
- var executing atomic.Bool
|
|
|
|
|
|
|
+ heartbeatLoop(&pingState) // -启动-设备在线-心跳检测-
|
|
|
|
|
+ for {
|
|
|
|
|
+ if pingState.Load() { //// 等待成功连接上目标设备卍
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("[%s] 无法连接目标设备!!\n", MODULE_NAME)
|
|
|
|
|
+ time.Sleep(1 * time.Second)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ term(&pingState) /////////////////// 启动终端模拟器卍
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func term(pingState *atomic.Bool) {
|
|
|
|
|
+ var executing atomic.Bool // 是否有正在执行中的命令
|
|
|
|
|
+ var interrupted atomic.Bool // 用户是否按键取消了命令
|
|
|
|
|
|
|
|
- // -在线-心跳检测
|
|
|
|
|
- heartbeatLoop(&pingState)
|
|
|
|
|
|
|
+ interruptLoop(&executing, &interrupted) // Ctrl+C卍
|
|
|
|
|
|
|
|
- // Ctrl+C中断处理
|
|
|
|
|
- interruptLoop(&executing)
|
|
|
|
|
|
|
+ printWelcome()
|
|
|
|
|
|
|
|
reader := bufio.NewReader(os.Stdin)
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
for {
|
|
for {
|
|
|
if !pingState.Load() {
|
|
if !pingState.Load() {
|
|
|
- fmt.Printf("[%s] 无法连接目标设备!!\n", MODULE_NAME)
|
|
|
|
|
|
|
+ fmt.Printf("[%s] 目标设备连接丢失!!\n", MODULE_NAME)
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fmt.Print("\033[?25h") // 显示光标
|
|
fmt.Print("\033[?25h") // 显示光标
|
|
|
|
|
+ if interrupted.Swap(false) {
|
|
|
|
|
+ fmt.Println("^C")
|
|
|
|
|
+ }
|
|
|
fmt.Printf("root@%s:%s# ", coupler.imei, coupler.cwd)
|
|
fmt.Printf("root@%s:%s# ", coupler.imei, coupler.cwd)
|
|
|
|
|
|
|
|
input, err := reader.ReadString('\n')
|
|
input, err := reader.ReadString('\n')
|
|
@@ -153,16 +159,16 @@ func help() {
|
|
|
fmt.Println(h)
|
|
fmt.Println(h)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func interruptLoop(executing *atomic.Bool) {
|
|
|
|
|
|
|
+func interruptLoop(executing *atomic.Bool, interrupted *atomic.Bool) {
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
signal.Notify(sigCh, syscall.SIGINT)
|
|
signal.Notify(sigCh, syscall.SIGINT)
|
|
|
go func() {
|
|
go func() {
|
|
|
for range sigCh {
|
|
for range sigCh {
|
|
|
|
|
+ interrupted.Store(true)
|
|
|
if executing.Load() {
|
|
if executing.Load() {
|
|
|
_, _ = coupler.stop()
|
|
_, _ = coupler.stop()
|
|
|
}
|
|
}
|
|
|
- fmt.Print("\n^C\n")
|
|
|
|
|
- } // end for
|
|
|
|
|
|
|
+ }
|
|
|
}()
|
|
}()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -170,13 +176,38 @@ func heartbeatLoop(pingState *atomic.Bool) {
|
|
|
go func() {
|
|
go func() {
|
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
|
defer ticker.Stop()
|
|
defer ticker.Stop()
|
|
|
|
|
+
|
|
|
|
|
+ pingFailCount := 0
|
|
|
|
|
+ pong := ""
|
|
|
for range ticker.C {
|
|
for range ticker.C {
|
|
|
resp, err := coupler.ping()
|
|
resp, err := coupler.ping()
|
|
|
- if err == nil && resp.Error == nil && resp.Result != nil && string(resp.Result) == "pong" {
|
|
|
|
|
|
|
+ if err == nil && resp.Error == nil && resp.Result != nil &&
|
|
|
|
|
+ json.Unmarshal(resp.Result, &pong) == nil && pong == "pong" {
|
|
|
pingState.Store(true)
|
|
pingState.Store(true)
|
|
|
|
|
+ pingFailCount = 0
|
|
|
} else {
|
|
} else {
|
|
|
- pingState.Store(false)
|
|
|
|
|
- } // end if
|
|
|
|
|
|
|
+ pingFailCount++
|
|
|
|
|
+ if pingFailCount >= 3 { ///// 连续3次ping失败, 可以认为设备离线
|
|
|
|
|
+ pingState.Store(false)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
} // end for
|
|
} // end for
|
|
|
}()
|
|
}()
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+func printWelcome() {
|
|
|
|
|
+ welcome := `
|
|
|
|
|
+ _ _ _ _ _ _ _ _
|
|
|
|
|
+| \ | (_) | | | (_) | |
|
|
|
|
|
+| \| |_| |_ ___| |__ _| | | ___
|
|
|
|
|
+| . | | __/ __| '_ \| | | |/ _ \
|
|
|
|
|
+| |\ | | || (__| | | | | | | __/
|
|
|
|
|
+|_| \_|_|\__\___|_| |_|_|_|_|\___|
|
|
|
|
|
+
|
|
|
|
|
+═══════════════════════════════════
|
|
|
|
|
+ 云飞科技 RTU远程运维终端
|
|
|
|
|
+═══════════════════════════════════
|
|
|
|
|
+提示: 输入'quit'命令, 可退出终端模拟器
|
|
|
|
|
+`
|
|
|
|
|
+ fmt.Println(welcome)
|
|
|
|
|
+}
|