cmd_Task.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package utils
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io"
  7. "os"
  8. "os/exec"
  9. "runtime"
  10. "sync"
  11. )
  12. type RunTask interface {
  13. AddTask()
  14. RunTask()
  15. }
  16. // T: Task任务
  17. type T struct {
  18. sync.Mutex
  19. // ch: 获取事件channel
  20. ch chan struct{}
  21. closeChan chan struct{}
  22. // 记录process对象
  23. p *os.Process
  24. // f: 执行任务
  25. f func(chan struct{}) error
  26. }
  27. // NewT: 实例化方法
  28. func NewT() *T {
  29. return newT(nil)
  30. }
  31. func newT(f func(chan struct{}) error) *T {
  32. t := &T{
  33. Mutex: sync.Mutex{},
  34. ch: make(chan struct{}, 1),
  35. closeChan: make(chan struct{}),
  36. f: f,
  37. }
  38. if f == nil {
  39. t.f = t.DefaultF
  40. }
  41. return t
  42. }
  43. func (t *T) AddTask() {
  44. if len(t.ch) == 1 {
  45. return
  46. }
  47. t.Lock()
  48. defer t.Unlock()
  49. if len(t.ch) == 1 {
  50. // 代表已经有任务了
  51. // 直接丢弃这次任务
  52. return
  53. }
  54. t.ch <- struct{}{}
  55. }
  56. func (t *T) RunTask() {
  57. fmt.Println("进入")
  58. // 这里做的make 是用于关闭上一个执行的任务
  59. ch := make(chan struct{})
  60. // 先run服务
  61. go t.f(ch)
  62. for {
  63. _, ok := <-t.ch
  64. if !ok {
  65. return
  66. }
  67. ch <- struct{}{}
  68. // 等待上一个关闭
  69. <-t.closeChan
  70. go t.f(ch)
  71. }
  72. }
  73. // DefaultF: 默认的StartFunction
  74. func (t *T) DefaultF(ch chan struct{}) error {
  75. var buildCmd *exec.Cmd
  76. var cmd *exec.Cmd
  77. // 检测系统是否有编译环境
  78. _, err := exec.LookPath("go")
  79. if err != nil {
  80. return err
  81. }
  82. // build
  83. switch runtime.GOOS {
  84. case "windows":
  85. buildCmd = exec.Command("go", "build", "-o", "server.exe", "main.go")
  86. default:
  87. buildCmd = exec.Command("go", "build", "-o", "server", "main.go")
  88. }
  89. //cmd = exec.Command("go", "run", "main.go")
  90. err = buildCmd.Run()
  91. if err != nil {
  92. return err
  93. }
  94. fmt.Println("build 执行完成")
  95. // 执行
  96. switch runtime.GOOS {
  97. case "windows":
  98. cmd = exec.Command("server.exe")
  99. default:
  100. cmd = exec.Command("./server")
  101. }
  102. // 开始执行任务
  103. ctx, cancel := context.WithCancel(context.Background())
  104. err = t.echo(cmd, ctx)
  105. <-ch
  106. // 回收资源
  107. fmt.Println("pid:", t.p.Pid, "->Kill")
  108. err = t.p.Kill()
  109. cancel()
  110. // 发送关闭完成信号
  111. t.closeChan <- struct{}{}
  112. return err
  113. }
  114. // echo: 封装回显
  115. func (t *T) echo(cmd *exec.Cmd, ctx context.Context) error {
  116. var stdoutBuf bytes.Buffer
  117. stdoutIn, _ := cmd.StdoutPipe()
  118. var errStdout error
  119. stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
  120. err := cmd.Start()
  121. if err != nil {
  122. return err
  123. }
  124. go func(ctx context.Context) {
  125. _, errStdout = io.Copy(stdout, stdoutIn)
  126. select {
  127. case <-ctx.Done():
  128. return
  129. default:
  130. }
  131. }(ctx)
  132. t.p = cmd.Process
  133. fmt.Println("pid", t.p.Pid)
  134. go func() {
  135. _ = cmd.Wait()
  136. if errStdout != nil {
  137. fmt.Printf("failed to capture stdout or stderr\n")
  138. }
  139. fmt.Printf("%s\n", string(stdoutBuf.Bytes()))
  140. select {
  141. case <-ctx.Done():
  142. //_ = os.Stdout.Close()
  143. return
  144. default:
  145. }
  146. }()
  147. return nil
  148. }