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

package utils
import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"runtime"
"sync"
)
//@author: [songzhibin97](https://github.com/songzhibin97)
//@interface_name: RunTask
//@description: Task接口
type RunTask interface {
AddTask()
RunTask()
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@struct_name: T
//@description: Task任务
type T struct {
sync.Mutex
// 获取事件channel
ch chan struct{}
closeChan chan struct{}
// 记录process对象
p *os.Process
// 执行任务
f func(chan struct{}) error
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: NewT
//@description: T的实例化方法
//@return: *T
func NewT() *T {
return newT(nil)
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@function: newT
//@description:
//@param: f func(chan struct{}) error
//@return: *T
func newT(f func(chan struct{}) error) *T {
t := &T{
Mutex: sync.Mutex{},
ch: make(chan struct{}, 1),
closeChan: make(chan struct{}),
f: f,
}
if f == nil {
t.f = t.DefaultF
}
return t
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: *T
//@function: AddTask
//@description: 添加任务
func (t *T) AddTask() {
select {
case t.ch <- struct{}{}:
default:
// 代表已经有任务了
// 直接丢弃这次任务
}
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: *T
//@function: RunTask
//@description: 启动任务
func (t *T) RunTask() {
fmt.Println("进入")
// 这里做的make 是用于关闭上一个执行的任务
ch := make(chan struct{})
// 先run服务
go t.f(ch)
for {
_, ok := <-t.ch
if !ok {
return
}
ch <- struct{}{}
// 等待上一个关闭
<-t.closeChan
go t.f(ch)
}
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: t *T
//@function: DefaultF
//@description: 默认的StartFunction
//@param: ch chan struct{}
//@return: error
func (t *T) DefaultF(ch chan struct{}) error {
var buildCmd *exec.Cmd
var cmd *exec.Cmd
// 检测系统是否有编译环境
_, err := exec.LookPath("go")
if err != nil {
return err
}
// build
switch runtime.GOOS {
case "windows":
buildCmd = exec.Command("go", "build", "-o", "server.exe", "main.go")
default:
buildCmd = exec.Command("go", "build", "-o", "server", "main.go")
}
//cmd = exec.Command("go", "run", "main.go")
err = buildCmd.Run()
if err != nil {
return err
}
fmt.Println("build 执行完成")
// 执行
switch runtime.GOOS {
case "windows":
cmd = exec.Command("server.exe")
default:
cmd = exec.Command("./server")
}
// 开始执行任务
ctx, cancel := context.WithCancel(context.Background())
err = t.echo(cmd, ctx)
<-ch
// 回收资源
fmt.Println("pid:", t.p.Pid, "->Kill")
err = t.p.Kill()
cancel()
// 发送关闭完成信号
t.closeChan <- struct{}{}
return err
}
//@author: [songzhibin97](https://github.com/songzhibin97)
//@object: t *T
//@function: echo
//@description: 封装回显
//@param: cmd *exec.Cmd, ctx context.Context
//@return: error
func (t *T) echo(cmd *exec.Cmd, ctx context.Context) error {
var stdoutBuf bytes.Buffer
stdoutIn, _ := cmd.StdoutPipe()
var errStdout error
stdout := io.MultiWriter(os.Stdout, &stdoutBuf)
err := cmd.Start()
if err != nil {
return err
}
go func(ctx context.Context) {
_, errStdout = io.Copy(stdout, stdoutIn)
select {
case <-ctx.Done():
return
default:
}
}(ctx)
t.p = cmd.Process
fmt.Println("pid", t.p.Pid)
go func() {
_ = cmd.Wait()
if errStdout != nil {
fmt.Printf("failed to capture stdout or stderr\n")
}
fmt.Printf("%s\n", string(stdoutBuf.Bytes()))
select {
case <-ctx.Done():
//_ = os.Stdout.Close()
return
default:
}
}()
return nil
}