From 2f7ca5cefda8750ea183b9c4d9619af6d6ecd6a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=B9=BF?= Date: Fri, 5 Sep 2025 18:01:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86Unix=20socket=E9=80=9A=E4=BF=A1?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=91=BD=E5=90=8D=E7=AE=A1=E9=81=93=E5=B9=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0flag=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + cmd_daemon_test.go | 88 +++++++----------- flag.go | 127 +++++++++++++++++++++++++ flag_test.go | 226 +++++++++++++++++++++++++++++++++++++++++++++ main.go | 197 ++++++++++++++++++++++----------------- 5 files changed, 503 insertions(+), 136 deletions(-) create mode 100644 flag.go create mode 100644 flag_test.go diff --git a/.gitignore b/.gitignore index adf8f72..4f7dd1b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Go workspace file go.work +vendor/ \ No newline at end of file diff --git a/cmd_daemon_test.go b/cmd_daemon_test.go index f7ae9f8..fcb85fd 100644 --- a/cmd_daemon_test.go +++ b/cmd_daemon_test.go @@ -72,10 +72,10 @@ func TestRead(t *testing.T) { } func TestCmdDaemonListen(t *testing.T) { - socketPath := "/tmp/test.sock" + pipePath := "/tmp/test.pipe" daemon := &CmdDaemon{ - SocketPath: socketPath, - cmds: make(map[string]CmdHandler), + PipePath: pipePath, + cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 @@ -89,15 +89,18 @@ func TestCmdDaemonListen(t *testing.T) { } }() - // 等待服务器启动 - time.Sleep(1 * time.Second) + // 等待管道文件创建 + waitForPipe(t, pipePath) - // 模拟客户端连接 - conn, err := net.Dial("unix", socketPath) + // 打开命名管道进行写入 + pipe, err := os.OpenFile(pipePath, os.O_RDWR, 0) if err != nil { - t.Fatalf("Client connect failed: %v", err) + t.Fatalf("Failed to open pipe for writing: %v", err) } - defer conn.Close() + defer pipe.Close() + + // 将文件转换为io.ReadWriter接口,以便与现有的Read/Write函数兼容 + pipeConn := &pipeConnection{pipe} // 发送请求 req := CmdRequest{ @@ -106,13 +109,13 @@ func TestCmdDaemonListen(t *testing.T) { Args: "arg1", IsDebug: false, } - err = Write(conn, req) + err = Write(pipeConn, req) if err != nil { t.Errorf("Write failed: %v", err) } // 读取响应 - resp, err := Read[CmdResponse](conn) + resp, err := Read[CmdResponse](pipeConn) if err != nil { t.Fatalf("Read failed: %v", err) } @@ -125,10 +128,10 @@ func TestCmdDaemonListen(t *testing.T) { func TestCmdDaemonRun(t *testing.T) { // 这里我们假设有一个正在运行的服务器来处理请求 // 因此我们需要首先启动一个简单的服务器来测试Run方法 - socketPath := "/tmp/test_run.sock" + pipePath := "/tmp/test_run.pipe" daemon := &CmdDaemon{ - SocketPath: socketPath, - cmds: make(map[string]CmdHandler), + PipePath: pipePath, + cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 @@ -141,27 +144,17 @@ func TestCmdDaemonRun(t *testing.T) { go startTestDaemon(daemon, listening) // 等待直到监听开始 - // for循环中检查socket文件是否存在,如果存在退出循环,否则sleepeep 1秒 // 使用一个错误channel来传递错误 errChan := make(chan error) go func() { - listened := false - for { - - if listened { - break - } - if _, err := os.Stat(socketPath); err == nil { - listened = true - } - time.Sleep(1 * time.Second) - } + // 等待管道文件创建 + waitForPipe(t, pipePath) // 设置命令行参数 os.Args = []string{"cmd", "--debug", "test", "arg1"} ndaemon := &CmdDaemon{ - SocketPath: socketPath, + PipePath: pipePath, } // 执行Run方法 err := ndaemon.Run() @@ -240,10 +233,10 @@ func (h *UnknownCmdHandler) Usage() string { } func TestEmptyCommand(t *testing.T) { - socketPath := "/tmp/test_empty.sock" + pipePath := "/tmp/test_empty.pipe" daemon := &CmdDaemon{ - SocketPath: socketPath, - cmds: make(map[string]CmdHandler), + PipePath: pipePath, + cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 @@ -255,28 +248,17 @@ func TestEmptyCommand(t *testing.T) { // 启动守护进程 go startTestDaemon(daemon, listening) - // 等待直到监听开始 - // for循环中检查socket文件是否存在,如果存在退出循环,否则sleepeep 1秒 // 使用一个错误channel来传递错误 errChan := make(chan error) go func() { - listened := false - for { - - if listened { - break - } - if _, err := os.Stat(socketPath); err == nil { - listened = true - } - time.Sleep(1 * time.Second) - } + // 等待管道文件创建 + waitForPipe(t, pipePath) // 设置命令行参数 os.Args = []string{"cmd", "empty"} ndaemon := &CmdDaemon{ - SocketPath: socketPath, + PipePath: pipePath, } // 执行Run方法 err := ndaemon.Run() @@ -295,10 +277,10 @@ func TestEmptyCommand(t *testing.T) { } func TestUnknownCommand(t *testing.T) { - socketPath := "/tmp/test_unknown.sock" + pipePath := "/tmp/test_unknown.pipe" daemon := &CmdDaemon{ - SocketPath: socketPath, - cmds: make(map[string]CmdHandler), + PipePath: pipePath, + cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 @@ -312,13 +294,13 @@ func TestUnknownCommand(t *testing.T) { } }() - // 等待 socket 文件创建 - waitForSocket(t, socketPath) + // 等待管道文件创建 + waitForPipe(t, pipePath) // 设置命令行参数 os.Args = []string{"cmd", "unknown"} ndaemon := &CmdDaemon{ - SocketPath: socketPath, + PipePath: pipePath, } // 执行Run方法 err := ndaemon.Run() @@ -327,15 +309,15 @@ func TestUnknownCommand(t *testing.T) { } } -// waitForSocket 等待直到指定路径的 socket 文件被创建 -func waitForSocket(t *testing.T, path string) { +// waitForPipe 等待直到指定路径的命名管道文件被创建 +func waitForPipe(t *testing.T, path string) { timeout := time.After(5 * time.Second) ticker := time.Tick(500 * time.Millisecond) for { select { case <-timeout: - t.Fatal("Timed out waiting for socket") + t.Fatal("Timed out waiting for pipe") case <-ticker: if _, err := os.Stat(path); err == nil { return diff --git a/flag.go b/flag.go new file mode 100644 index 0000000..a451f2f --- /dev/null +++ b/flag.go @@ -0,0 +1,127 @@ +package gocmdDaemon + +import ( + "flag" + "fmt" + + "encoding/json" +) + +type MFlag struct { + flags map[string]interface{} + RemainArgs []string +} + +func (m *MFlag) Int(short string, long string, value int, usage string) { + var v int + m.flags[long] = &v + flag.IntVar(&v, short, value, usage) + flag.IntVar(&v, long, value, usage) +} + +func (m *MFlag) String(short string, long string, value string, usage string) { + var v string + m.flags[long] = &v + flag.StringVar(&v, short, value, usage) + flag.StringVar(&v, long, value, usage) +} + +func (m *MFlag) Bool(short string, long string, value bool, usage string) { + var v bool + m.flags[long] = &v + flag.BoolVar(&v, short, value, usage) + flag.BoolVar(&v, long, value, usage) +} + +func (m *MFlag) Parse() { + flag.Parse() + m.RemainArgs = flag.Args() +} + +func (m *MFlag) GetIntFlag(name string) int { + v, ok := m.flags[name] + if !ok { + return -1 + } + r := *(v.(*int)) + return r +} + +func (m *MFlag) GetStringFlag(name string) string { + v, ok := m.flags[name] + if !ok { + return "" + } + return *(v.(*string)) +} + +func (m *MFlag) GetBoolFlag(name string) bool { + v, ok := m.flags[name] + if !ok { + return false + } + return *(v.(*bool)) +} + +func (m *MFlag) MarshalJSON() ([]byte, error) { + result := make(map[string]interface{}) + for k, v := range m.flags { + // 判断值类型 + name := k + switch v.(type) { + case *int: + result[k] = m.GetIntFlag(name) + case *string: + result[k] = m.GetStringFlag(name) + case *bool: + result[k] = m.GetBoolFlag(name) + default: + continue + } + // result[k] = *(v.(*interface{})) + } + result["remainArgs"] = m.RemainArgs + return json.Marshal(result) +} + +func (m *MFlag) UnmarshalJSON(data []byte) error { + var result map[string]interface{} + err := json.Unmarshal(data, &result) + if err != nil { + return err + } + for k, v := range result { + if k == "remainArgs" { + m.RemainArgs = convert2StringSlice(v.([]interface{})) + continue + } + switch v.(type) { + case float64: + p := int(v.(float64)) + m.flags[k] = &p + case string: + p := v.(string) + m.flags[k] = &p + case bool: + p := v.(bool) + m.flags[k] = &p + default: + continue + } + } + return nil +} + +func convertSlice[T any, U any](input []T, convert func(T) U) []U { + result := make([]U, len(input)) + for i, v := range input { + result[i] = convert(v) + } + return result +} + +func convert2StringSlice[T any](input []T) []string { + return convertSlice(input, func(v T) string { + return fmt.Sprint(v) + }) +} diff --git a/flag_test.go b/flag_test.go new file mode 100644 index 0000000..1b81c19 --- /dev/null +++ b/flag_test.go @@ -0,0 +1,226 @@ +package gocmdDaemon + +import ( + "encoding/json" + "flag" + "fmt" + "os" + "testing" +) + +func TestMFlag_Int(t *testing.T) { + // 保存原始参数,以便测试后恢复 + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数 + os.Args = []string{"cmd", "-i", "123", "--int-flag", "456"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册标志 + m.Int("i", "int-flag", 0, "测试整数标志") + m.Parse() + + // 测试短标志 + if got := m.GetIntFlag("int-flag"); got != 456 { + t.Errorf("GetIntFlag() = %v, want %v", got, 456) + } +} + +func TestMFlag_String(t *testing.T) { + // 保存原始参数,以便测试后恢复 + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数 + os.Args = []string{"cmd", "-s", "hello", "--str-flag", "world"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册标志 + m.String("s", "str-flag", "", "测试字符串标志") + m.Parse() + + // 测试长标志 + if got := m.GetStringFlag("str-flag"); got != "world" { + t.Errorf("GetStringFlag() = %v, want %v", got, "world") + } +} + +func TestMFlag_Bool(t *testing.T) { + // 保存原始参数,以便测试后恢复 + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数 + os.Args = []string{"cmd", "-b", "--bool-flag"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册标志 + m.Bool("b", "bool-flag", false, "测试布尔标志") + m.Parse() + + // 测试布尔标志 + if got := m.GetBoolFlag("bool-flag"); !got { + t.Errorf("GetBoolFlag() = %v, want %v", got, true) + } +} + +func TestMFlag_GetNonExistentFlags(t *testing.T) { + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 测试获取不存在的标志 + if got := m.GetIntFlag("non-existent"); got != -1 { + t.Errorf("GetIntFlag() for non-existent flag = %v, want %v", got, -1) + } + + if got := m.GetStringFlag("non-existent"); got != "" { + t.Errorf("GetStringFlag() for non-existent flag = %v, want %v", got, "") + } + + if got := m.GetBoolFlag("non-existent"); got != false { + t.Errorf("GetBoolFlag() for non-existent flag = %v, want %v", got, false) + } +} + +func TestMFlag_RemainArgs(t *testing.T) { + // 保存原始参数,以便测试后恢复 + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数,包括剩余参数 + os.Args = []string{"cmd", "-i", "123", "arg1", "arg2", "arg3", "-d"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册标志 + m.Int("i", "int-flag", 0, "测试整数标志") + m.Parse() + + // 测试剩余参数 + expectedArgs := []string{"arg1", "arg2", "arg3", "-d"} + if len(m.RemainArgs) != len(expectedArgs) { + t.Errorf("RemainArgs length = %v, want %v", len(m.RemainArgs), len(expectedArgs)) + } + + for i, arg := range expectedArgs { + if i < len(m.RemainArgs) && m.RemainArgs[i] != arg { + t.Errorf("RemainArgs[%d] = %v, want %v", i, m.RemainArgs[i], arg) + } + } +} + +func TestMFlag_MultipleFlags(t *testing.T) { + // 保存原始参数,以便测试后恢复 + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数 + os.Args = []string{"cmd", "-i", "123", "-s", "hello", "-b", "subcmd", "-s", "h1"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册多个标志 + m.Int("i", "int-flag", 0, "测试整数标志") + m.String("s", "str-flag", "", "测试字符串标志") + m.Bool("b", "bool-flag", false, "测试布尔标志") + m.Parse() + + // 测试所有标志值 + if got := m.GetIntFlag("int-flag"); got != 123 { + t.Errorf("GetIntFlag() = %v, want %v", got, 123) + } + + if got := m.GetStringFlag("str-flag"); got != "hello" { + t.Errorf("GetStringFlag() = %v, want %v", got, "hello") + } + + if got := m.GetBoolFlag("bool-flag"); !got { + t.Errorf("GetBoolFlag() = %v, want %v", got, true) + } +} + +func TestMFlag_MarshalJSON(t *testing.T) { + oldArgs := os.Args + defer func() { os.Args = oldArgs }() + + // 重置flag包状态 + flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError) + + // 设置测试参数 + os.Args = []string{"cmd", "-i", "123", "-s", "hello", "-b", "subcmd", "-s", "h1"} + + m := &MFlag{ + flags: make(map[string]interface{}), + } + + // 注册多个标志 + m.Int("i", "int-flag", 0, "测试整数标志") + m.String("s", "str-flag", "", "测试字符串标志") + m.Bool("b", "bool-flag", false, "测试布尔标志") + m.Parse() + fmt.Println(m.GetIntFlag("int-flag")) + jsonBytes, err := m.MarshalJSON() + if err != nil { + t.Errorf("MarshalJSON() error = %v, want nil", err) + } + var result map[string]interface{} + err = json.Unmarshal(jsonBytes, &result) + if err != nil { + t.Errorf("UnmarshalJSON() error = %v, want nil", err) + } + if int(result["int-flag"].(float64)) != 123 { + t.Errorf("MarshalJSON() int-flag = %v, want %v", result["int-flag"], 123) + } + if result["str-flag"] != "hello" { + t.Errorf("MarshalJSON() str-flag = %v, want %v", result["str-flag"], "hello") + } + if result["bool-flag"] != true { + t.Errorf("MarshalJSON() bool-flag = %v, want %v", result["bool-flag"], true) + } + m1 := &MFlag{ + flags: make(map[string]interface{}), + } + err1 := json.Unmarshal(jsonBytes, m1) + if err1 != nil { + t.Errorf("UnmarshalJSON() error = %v, want nil", err) + } + if int(m1.GetIntFlag("int-flag")) != 123 { + t.Errorf("MarshalJSON() int-flag = %v, want %v", m1.GetIntFlag("int-flag"), 123) + } + if m1.GetStringFlag("str-flag") != "hello" { + t.Errorf("MarshalJSON() str-flag = %v, want %v", m1.GetStringFlag("str-flag"), "hello") + } + if m1.GetBoolFlag("bool-flag") != true { + t.Errorf("MarshalJSON() bool-flag = %v, want %v", m1.GetBoolFlag("bool-flag"), true) + } +} diff --git a/main.go b/main.go index 57bb775..a0d87bc 100644 --- a/main.go +++ b/main.go @@ -1,19 +1,22 @@ package gocmdDaemon import ( - "encoding/json" "fmt" "net" "os" "strings" + "syscall" + "time" + + "flag" "github.com/google/uuid" ) type CmdDaemon struct { - Name string // app cli command name - SocketPath string // unix socket path - cmds map[string]CmdHandler + Name string // app cli command name + PipePath string // named pipe path + cmds map[string]CmdHandler } type CmdRequest struct { Id string `json:"id"` @@ -33,6 +36,26 @@ type CmdConn struct { Id string } +// pipeConnection 是一个适配器,将 *os.File 转换为 net.Conn 接口 +type pipeConnection struct { + *os.File +} + +// 实现 net.Conn 接口所需的方法 +func (p *pipeConnection) LocalAddr() net.Addr { return &pipeAddr{p.Name()} } +func (p *pipeConnection) RemoteAddr() net.Addr { return &pipeAddr{p.Name()} } +func (p *pipeConnection) SetDeadline(t time.Time) error { return nil } +func (p *pipeConnection) SetReadDeadline(t time.Time) error { return nil } +func (p *pipeConnection) SetWriteDeadline(t time.Time) error { return nil } + +// pipeAddr 实现 net.Addr 接口 +type pipeAddr struct { + name string +} + +func (a *pipeAddr) Network() string { return "pipe" } +func (a *pipeAddr) String() string { return a.name } + func (c *CmdConn) Write(d string) error { resp := CmdResponse{ Id: c.Id, @@ -64,7 +87,7 @@ type CmdHandler interface { Usage() string } -// Listen 启动守护进程并监听Unix socket上的连接 +// Listen 启动守护进程并监听命名管道上的连接 // 参数: // // c: CmdDaemon 实例指针 @@ -73,59 +96,61 @@ type CmdHandler interface { // // error: 监听过程中发生的错误(如果有) func (c *CmdDaemon) Listen() error { - // 删除已存在的 socket 文件(如果存在) - if err := os.Remove(c.SocketPath); err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to remove existing socket file: %v", err) + // 删除已存在的命名管道(如果存在) + if err := os.Remove(c.PipePath); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to remove existing pipe: %v", err) } - // 监听 unix socket - listener, err := net.Listen("unix", c.SocketPath) + // 创建命名管道 + if err := syscall.Mkfifo(c.PipePath, 0666); err != nil { + return fmt.Errorf("failed to create named pipe: %v", err) + } + + // 设置管道文件权限 + if err := os.Chmod(c.PipePath, 0666); err != nil { + return fmt.Errorf("failed to set pipe permissions: %v", err) + } + pipe, err := os.OpenFile(c.PipePath, os.O_RDWR, 0) if err != nil { - return fmt.Errorf("failed to listen on socket: %v", err) - } - defer listener.Close() - - // 设置 socket 文件权限 - if err := os.Chmod(c.SocketPath, 0777); err != nil { - return fmt.Errorf("failed to set socket file permissions: %v", err) + return fmt.Errorf("failed to open pipe for reading: %v", err) } + defer pipe.Close() + // 将文件转换为io.ReadWriter接口,以便与现有的Read/Write函数兼容 + pipeConn := &pipeConnection{pipe} for { - conn, err := listener.Accept() + // 打开命名管道进行读取 + + // 处理请求 + // go func(pipe *os.File) { + + req, err := Read[CmdRequest](pipeConn) if err != nil { - return fmt.Errorf("failed to accept connection: %v", err) + _ = Write(pipeConn, CmdResponse{ + Error: "failed to read request: " + err.Error(), + Continue: false, + }) + break } - // 处理每个连接 - go func(conn net.Conn) { - defer conn.Close() + cmdHandler, ok := c.cmds[req.Cmd] + if !ok { + _ = Write(pipeConn, CmdResponse{ + Error: "unknown command: " + req.Cmd + "\n" + c.Usage(), + Continue: false, + }) + continue + } - req, err := Read[CmdRequest](conn) - if err != nil { - _ = Write(conn, CmdResponse{ - Error: "failed to read request: " + err.Error(), - Continue: false, - }) - return - } - - cmdHandler, ok := c.cmds[req.Cmd] - if !ok { - _ = Write(conn, CmdResponse{ - Error: "unknown command: " + req.Cmd + "\n" + c.Usage(), - Continue: false, - }) - return - } - - // 执行命令处理程序 - cmdConn := &CmdConn{Conn: conn, Id: req.Id} - err = cmdHandler.Handle(cmdConn, req) - if err != nil { - _ = cmdConn.End(err.Error() + cmdHandler.Usage()) - } - }(conn) + // 执行命令处理程序 + cmdConn := &CmdConn{Conn: pipeConn, Id: req.Id} + err = cmdHandler.Handle(cmdConn, req) + if err != nil { + _ = cmdConn.End(err.Error() + cmdHandler.Usage()) + } + // }(pipe) } + return nil } // Usage 生成命令使用说明 @@ -173,58 +198,64 @@ func (c *CmdDaemon) isDebug(cmd string) bool { // 返回: // // error: 执行过程中发生的错误(如果有) -func (c *CmdDaemon) Run() error { +func (c *CmdDaemon) Run() (*CmdResponse, error) { + // 定义flag: -debug 和 -daemon + // flag := flag.NewFlagSet(c.Name, flag.ContinueOnError) + var isDebug bool + flag.BoolVar(&isDebug, "debug", false, "Run command in debug mode") + flag.BoolVar(&isDebug, "d", false, "Run command in debug mode") + var daemon bool + flag.BoolVar(&daemon, "daemon", false, "Run command in daemon mode") + flag.BoolVar(&daemon, "D", false, "Run command in daemon mode") + flag.Parse() // 从命令参数中解析出是否debug 子命令和剩余参数字符串 - args := os.Args[1:] - isDebug := c.isDebug(args[0]) var remainingArgs []string cmd := "" - if isDebug { - if len(args) > 1 { - cmd = args[1] - remainingArgs = args[2:] - } else { - cmd = "help" - isDebug = false - remainingArgs = []string{} - } - } else { - if len(args) > 0 { - cmd = args[0] - remainingArgs = args[1:] - } else { - cmd = "help" - isDebug = false - remainingArgs = []string{} - } - } + // if isDebug { + // if len(args) > 1 { + // cmd = args[1] + // remainingArgs = args[2:] + // } else { + // cmd = "help" + // isDebug = false + // remainingArgs = []string{} + // } + // } else { + // if len(args) > 0 { + // cmd = args[0] + // remainingArgs = args[1:] + // } else { + // cmd = "help" + // isDebug = false + // remainingArgs = []string{} + // } + // } cmdReq := CmdRequest{ Args: strings.Join(remainingArgs, " "), Cmd: cmd, Id: uuid.New().String(), IsDebug: isDebug, } - // dial unix socket - conn, err := net.Dial("unix", c.SocketPath) + // 打开命名管道进行写入 + pipe, err := os.OpenFile(c.PipePath, os.O_RDWR, 0) if err != nil { - return err + return nil, fmt.Errorf("failed to open pipe for writing: %v", err) } - defer conn.Close() - // send cmd request - cmdReqJson, err := json.Marshal(cmdReq) + defer pipe.Close() + + // 将文件转换为io.ReadWriter接口,以便与现有的Read/Write函数兼容 + pipeConn := &pipeConnection{pipe} + + // 发送命令请求 + err = Write(pipeConn, cmdReq) if err != nil { - return err - } - _, err = conn.Write(cmdReqJson) - if err != nil { - return err + return nil, fmt.Errorf("failed to write request to pipe: %v", err) } for { - - resp, err := Read[CmdResponse](conn) + resp, err := Read[CmdResponse](pipeConn) if err != nil { - return err + return nil, fmt.Errorf("failed to read response from pipe: %v", err) } if resp.Error != "" { fmt.Println(resp.Error)