package rpc import ( "encoding/xml" "fmt" "net" ) type LuxRpcClient struct { conn net.Conn counter int } func LuxDialRpc(network string, address string) (LuxRpcClient, error) { conn, err := net.Dial(network, address) if err != nil { return LuxRpcClient{}, err } return LuxRpcClient{ conn: conn, counter: 0, }, nil } func (rpc *LuxRpcClient) Close() { rpc.conn.Close() } func (rpc *LuxRpcClient) Execute(request LuxRpcRequest) (LuxRpcResponse, LuxRpcError, error) { var rpcRes LuxRpcResponse var rpcErr LuxRpcError request.RequestID = rpc.counter rpc.counter++ xmlBytes, err := xml.Marshal(&request) if err != nil { log.Errorf("failed to marshal request: %v", err) return rpcRes, rpcErr, err } _, err = rpc.conn.Write(xmlBytes) if err != nil { log.Debugf("rpc client send failed: %v", err) return rpcRes, rpcErr, err } def := NewLuxRpcDefrag() part := make([]byte, 1500) for { n, err := rpc.conn.Read(part) if err != nil { log.Debugf("rpc client recv failed: %v", err) return rpcRes, rpcErr, err } if def.Feed(part[n:]) { // got full data, either its response or error if def.HasResponse() { xmlBytes := def.GetAndForget() if err := xml.Unmarshal(xmlBytes, &rpcRes); err != nil { return rpcRes, rpcErr, fmt.Errorf("failed to unmarshal rpc response %v: %s", err, string(xmlBytes)) } return rpcRes, rpcErr, nil } else if def.HasError() { xmlBytes := def.GetAndForget() if err := xml.Unmarshal(xmlBytes, &rpcErr); err != nil { return rpcRes, rpcErr, fmt.Errorf("failed to unmarshal rpc error %v: %s", err, string(xmlBytes)) } return rpcRes, rpcErr, nil } else { return rpcRes, rpcErr, fmt.Errorf("got unknown response from rpc server: %s", string(def.GetAndForget())) } } } }