You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
3.7 KiB

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