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.

204 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
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. if len(t.ch) == 1 {
  62. return
  63. }
  64. t.Lock()
  65. defer t.Unlock()
  66. if len(t.ch) == 1 {
  67. // 代表已经有任务了
  68. // 直接丢弃这次任务
  69. return
  70. }
  71. t.ch <- struct{}{}
  72. }
  73. //@author: [songzhibin97](https://github.com/songzhibin97)
  74. //@object: *T
  75. //@function: RunTask
  76. //@description: 启动任务
  77. func (t *T) RunTask() {
  78. fmt.Println("进入")
  79. // 这里做的make 是用于关闭上一个执行的任务
  80. ch := make(chan struct{})
  81. // 先run服务
  82. go t.f(ch)
  83. for {
  84. _, ok := <-t.ch
  85. if !ok {
  86. return
  87. }
  88. ch <- struct{}{}
  89. // 等待上一个关闭
  90. <-t.closeChan
  91. go t.f(ch)
  92. }
  93. }
  94. //@author: [songzhibin97](https://github.com/songzhibin97)
  95. //@object: t *T
  96. //@function: DefaultF
  97. //@description: 默认的StartFunction
  98. //@param: ch chan struct{}
  99. //@return: error
  100. func (t *T) DefaultF(ch chan struct{}) error {
  101. var buildCmd *exec.Cmd
  102. var cmd *exec.Cmd
  103. // 检测系统是否有编译环境
  104. _, err := exec.LookPath("go")
  105. if err != nil {
  106. return err
  107. }
  108. // build
  109. switch runtime.GOOS {
  110. case "windows":
  111. buildCmd = exec.Command("go", "build", "-o", "server.exe", "main.go")
  112. default:
  113. buildCmd = exec.Command("go", "build", "-o", "server", "main.go")
  114. }
  115. //cmd = exec.Command("go", "run", "main.go")
  116. err = buildCmd.Run()
  117. if err != nil {
  118. return err
  119. }
  120. fmt.Println("build 执行完成")
  121. // 执行
  122. switch runtime.GOOS {
  123. case "windows":
  124. cmd = exec.Command("server.exe")
  125. default:
  126. cmd = exec.Command("./server")
  127. }
  128. // 开始执行任务
  129. ctx, cancel := context.WithCancel(context.Background())
  130. err = t.echo(cmd, ctx)
  131. <-ch
  132. // 回收资源
  133. fmt.Println("pid:", t.p.Pid, "->Kill")
  134. err = t.p.Kill()
  135. cancel()
  136. // 发送关闭完成信号
  137. t.closeChan <- struct{}{}
  138. return err
  139. }
  140. //@author: [songzhibin97](https://github.com/songzhibin97)
  141. //@object: t *T
  142. //@function: echo
  143. //@description: 封装回显
  144. //@param: cmd *exec.Cmd, ctx context.Context
  145. //@return: error
  146. func (t *T) echo(cmd *exec.Cmd, ctx context.Context) error {
  147. var stdoutBuf bytes.Buffer
  148. stdoutIn, _ := cmd.StdoutPipe()
  149. var errStdout error
  150. stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
  151. err := cmd.Start()
  152. if err != nil {
  153. return err
  154. }
  155. go func(ctx context.Context) {
  156. _, errStdout = io.Copy(stdout, stdoutIn)
  157. select {
  158. case <-ctx.Done():
  159. return
  160. default:
  161. }
  162. }(ctx)
  163. t.p = cmd.Process
  164. fmt.Println("pid", t.p.Pid)
  165. go func() {
  166. _ = cmd.Wait()
  167. if errStdout != nil {
  168. fmt.Printf("failed to capture stdout or stderr\n")
  169. }
  170. fmt.Printf("%s\n", string(stdoutBuf.Bytes()))
  171. select {
  172. case <-ctx.Done():
  173. //_ = os.Stdout.Close()
  174. return
  175. default:
  176. }
  177. }()
  178. return nil
  179. }