diff --git a/client.go b/client.go index 683d03958644376d588c0c8e7ba6da708084f6d7..8788b951dd2ff566b50331d633f80f224527ce8e 100644 --- a/client.go +++ b/client.go @@ -170,6 +170,8 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { return DialHTTP(rawurl) case "ws", "wss": return DialWebsocket(ctx, rawurl, "") + case "tcp": + return DialTCP(ctx, rawurl) case "stdio": return DialStdIO(ctx) case "": diff --git a/ipc.go b/ipc.go index 221daa08b6ee3c2af164d6676ce6fd875ab2a595..35dd3d75926fc1e12eadf8e887e9fd684ed5aa50 100644 --- a/ipc.go +++ b/ipc.go @@ -19,6 +19,7 @@ package jrpc import ( "context" "net" + "net/url" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -39,6 +40,41 @@ func (s *Server) ServeListener(l net.Listener) error { } } +// DialTCP create a new TCP client that connects to the given endpoint. +// +// The context is used for the initial connection establishment. It does not +// affect subsequent interactions with the client. +func DialTCP(ctx context.Context, endpoint string) (*Client, error) { + parsed, err := url.Parse(endpoint) + if err != nil { + return nil, err + } + ans := make(chan *Client) + errc := make(chan error) + go func() { + client, err := newClient(ctx, func(ctx context.Context) (ServerCodec, error) { + conn, err := net.Dial("tcp", parsed.Host) + if err != nil { + return nil, err + } + return NewCodec(conn), nil + }) + if err != nil { + errc <- err + return + } + ans <- client + }() + select { + case err := <-errc: + return nil, err + case a := <-ans: + return a, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + // DialIPC create a new IPC client that connects to the given endpoint. On Unix it assumes // the endpoint is the full path to a unix socket, and Windows the endpoint is an // identifier for a named pipe.