更新启动逻辑
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
dist/
|
||||
pdf/
|
||||
../log/
|
||||
/log/
|
||||
|
||||
@@ -19,7 +19,7 @@ cp .env.example .env
|
||||
|
||||
## 运行
|
||||
|
||||
**运营推荐**:直接双击或运行 `transit.exe`(无参数),按中文菜单选择「单次执行」或「定时执行」。
|
||||
**运营推荐**:直接双击或运行 `transit.exe`(无参数)。交互菜单 **10 秒内无操作** 将自动进入「定时执行(常驻)」;也可用菜单手动选「单次执行」或「定时执行」。超时秒数:`MENU_AUTO_SERVE_TIMEOUT_SEC`(默认 10)。
|
||||
|
||||
**完整命令说明**(单次 / 定时 / 计划任务 / 排错):见 **[docs/COMMANDS.md](docs/COMMANDS.md)**。
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ func isInteractiveTerminal() bool {
|
||||
// runInteractiveMenu 无参数时展示中文菜单,供运营选择单次或定时。
|
||||
func runInteractiveMenu() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
timeout := menuAutoServeTimeout()
|
||||
for {
|
||||
fmt.Println()
|
||||
fmt.Println("======== 互联网医院监管中转 ========")
|
||||
@@ -86,9 +87,13 @@ func runInteractiveMenu() {
|
||||
fmt.Println(" 2) 定时执行(常驻,按 .env 中 CRON 每天跑)")
|
||||
fmt.Println(" 3) 查看日志(Web 控制台,不跑定时)")
|
||||
fmt.Println(" 0) 退出")
|
||||
fmt.Printf("%v 内未选择将自动启动「2) 定时执行(常驻)」\n", timeout.Round(time.Second))
|
||||
fmt.Print("请选择 [0-3]: ")
|
||||
choice, _ := reader.ReadString('\n')
|
||||
choice = strings.TrimSpace(choice)
|
||||
choice, timedOut := readLineTimeout(reader, timeout)
|
||||
if timedOut {
|
||||
choice = "2"
|
||||
fmt.Println("已超时,自动选择: 2) 定时执行(常驻)")
|
||||
}
|
||||
switch choice {
|
||||
case "1":
|
||||
runInteractiveSync(reader)
|
||||
@@ -145,10 +150,14 @@ func runInteractiveServe(reader *bufio.Reader) {
|
||||
fmt.Printf(" 默认 cron: %s(每天 22:00)\n", expr)
|
||||
}
|
||||
fmt.Println("启动后进程将常驻,到点自动执行 step=all。")
|
||||
timeout := menuAutoServeTimeout()
|
||||
fmt.Printf("%v 内未确认将自动启动定时服务\n", timeout.Round(time.Second))
|
||||
fmt.Print("确认启动定时服务? [Y/n]: ")
|
||||
confirm, _ := reader.ReadString('\n')
|
||||
confirm = strings.TrimSpace(strings.ToLower(confirm))
|
||||
if confirm == "n" || confirm == "no" {
|
||||
confirm, timedOut := readLineTimeout(reader, timeout)
|
||||
if timedOut {
|
||||
fmt.Println("已超时,自动确认启动。")
|
||||
}
|
||||
if !serveConfirmYes(confirm, timedOut) {
|
||||
fmt.Println("已取消。")
|
||||
return
|
||||
}
|
||||
|
||||
49
cmd/transit/menu_io.go
Normal file
49
cmd/transit/menu_io.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const defaultMenuAutoServeTimeout = 10 * time.Second
|
||||
|
||||
// menuAutoServeTimeout 交互菜单自动进入常驻的超时;可由 MENU_AUTO_SERVE_TIMEOUT_SEC 覆盖。
|
||||
func menuAutoServeTimeout() time.Duration {
|
||||
v := strings.TrimSpace(os.Getenv("MENU_AUTO_SERVE_TIMEOUT_SEC"))
|
||||
if v == "" {
|
||||
return defaultMenuAutoServeTimeout
|
||||
}
|
||||
sec, err := strconv.Atoi(v)
|
||||
if err != nil || sec <= 0 {
|
||||
return defaultMenuAutoServeTimeout
|
||||
}
|
||||
return time.Duration(sec) * time.Second
|
||||
}
|
||||
|
||||
// readLineTimeout 在 timeout 内等待一行;超时返回 timedOut=true。
|
||||
// 注意:Windows 控制台无法在超时后取消阻塞读,后台 goroutine 仍会等到用户按 Enter。
|
||||
func readLineTimeout(r *bufio.Reader, timeout time.Duration) (line string, timedOut bool) {
|
||||
ch := make(chan string, 1)
|
||||
go func() {
|
||||
s, _ := r.ReadString('\n')
|
||||
ch <- s
|
||||
}()
|
||||
select {
|
||||
case s := <-ch:
|
||||
return strings.TrimSpace(s), false
|
||||
case <-time.After(timeout):
|
||||
return "", true
|
||||
}
|
||||
}
|
||||
|
||||
// serveConfirmYes 是否启动定时常驻(超时视为确认)。
|
||||
func serveConfirmYes(confirm string, timedOut bool) bool {
|
||||
if timedOut {
|
||||
return true
|
||||
}
|
||||
c := strings.TrimSpace(strings.ToLower(confirm))
|
||||
return c != "n" && c != "no"
|
||||
}
|
||||
61
cmd/transit/menu_io_test.go
Normal file
61
cmd/transit/menu_io_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestReadLineTimeout_returnsBeforeDeadline(t *testing.T) {
|
||||
r := bufio.NewReader(bytes.NewBufferString("hello\n"))
|
||||
line, timedOut := readLineTimeout(r, 2*time.Second)
|
||||
if timedOut {
|
||||
t.Fatal("expected input, got timeout")
|
||||
}
|
||||
if line != "hello" {
|
||||
t.Fatalf("line=%q", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadLineTimeout_timesOut(t *testing.T) {
|
||||
pr, _ := io.Pipe()
|
||||
r := bufio.NewReader(pr)
|
||||
_, timedOut := readLineTimeout(r, 50*time.Millisecond)
|
||||
if !timedOut {
|
||||
t.Fatal("expected timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeConfirmYes(t *testing.T) {
|
||||
if !serveConfirmYes("", false) {
|
||||
t.Fatal("empty should confirm")
|
||||
}
|
||||
if !serveConfirmYes("y", false) {
|
||||
t.Fatal("y should confirm")
|
||||
}
|
||||
if !serveConfirmYes("", true) {
|
||||
t.Fatal("timeout should confirm")
|
||||
}
|
||||
if serveConfirmYes("n", false) {
|
||||
t.Fatal("n should cancel")
|
||||
}
|
||||
if serveConfirmYes("no", false) {
|
||||
t.Fatal("no should cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMenuAutoServeTimeout_default(t *testing.T) {
|
||||
t.Setenv("MENU_AUTO_SERVE_TIMEOUT_SEC", "")
|
||||
if menuAutoServeTimeout() != defaultMenuAutoServeTimeout {
|
||||
t.Fatalf("got %v", menuAutoServeTimeout())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMenuAutoServeTimeout_env(t *testing.T) {
|
||||
t.Setenv("MENU_AUTO_SERVE_TIMEOUT_SEC", "5")
|
||||
if menuAutoServeTimeout() != 5*time.Second {
|
||||
t.Fatalf("got %v", menuAutoServeTimeout())
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,12 @@ go run ./cmd/transit
|
||||
2) 定时执行(常驻,按 .env 中 CRON 每天跑)
|
||||
3) 查看日志(Web 控制台,不跑定时)
|
||||
0) 退出
|
||||
10s 内未选择将自动启动「2) 定时执行(常驻)」
|
||||
请选择 [0-3]:
|
||||
```
|
||||
|
||||
- 选 **1**:再输入 `step`(默认 all)、`date`(回车=按 ANCHOR_OFFSET_DAYS 推算,默认昨日)。
|
||||
- **10 秒无输入**:自动选择 **2** 并进入确认步骤;确认步骤同样 **10 秒无输入** 则自动启动常驻(适合双击 `transit.exe` 无人值守)。超时秒数可用环境变量 `MENU_AUTO_SERVE_TIMEOUT_SEC`(正整数,默认 10)调整。
|
||||
- 选 **1**:再输入 `step`(默认 all)、`date`(回车=按 ANCHOR_OFFSET_DAYS 推算,默认昨日);该路径仍须手动输入,无自动超时。
|
||||
- 选 **2**:显示当前 cron 配置,确认后进程常驻,到点自动 `step=all`,并启动 Web 控制台(默认 `http://127.0.0.1:8765/`)。
|
||||
- 选 **3**:仅启动 Web,可浏览文件日志与本机同步流水(测试同步需选 2 用 serve)。
|
||||
- 选 **0**:退出。
|
||||
|
||||
Reference in New Issue
Block a user