1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
package varlink
import (
"context"
"encoding/json"
"fmt"
"io"
"strings"
)
// Call is a method call retrieved by a Service. The connection from the
// client can be terminated by returning an error from the call instead
// of sending a reply or error reply.
type Call struct {
Conn ReadWriterContext
Request *[]byte
In *serviceCall
Continues bool
Upgrade bool
}
// WantsMore indicates if the calling client accepts more than one reply to this method call.
func (c *Call) WantsMore() bool {
return c.In.More
}
// WantsUpgrade indicates that the calling client wants the connection to be upgraded.
func (c *Call) WantsUpgrade() bool {
return c.In.Upgrade
}
// IsOneway indicate that the calling client does not expect a reply.
func (c *Call) IsOneway() bool {
return c.In.Oneway
}
// GetParameters retrieves the method call parameters.
func (c *Call) GetParameters(p interface{}) error {
if c.In.Parameters == nil {
return fmt.Errorf("empty parameters")
}
return json.Unmarshal(*c.In.Parameters, p)
}
func (c *Call) sendMessage(ctx context.Context, r *serviceReply) error {
if c.In.Oneway {
return nil
}
b, err := json.Marshal(r)
if err != nil {
return err
}
b = append(b, 0)
_, err = c.Conn.Write(ctx, b)
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
// Reply sends a reply to this method call.
func (c *Call) Reply(ctx context.Context, parameters interface{}) error {
if !c.Continues {
return c.sendMessage(ctx, &serviceReply{
Parameters: parameters,
})
}
if !c.In.More {
return fmt.Errorf("call did not set more, it does not expect continues")
}
return c.sendMessage(ctx, &serviceReply{
Continues: true,
Parameters: parameters,
})
}
// ReplyError sends an error reply to this method call.
func (c *Call) ReplyError(ctx context.Context, name string, parameters interface{}) error {
r := strings.LastIndex(name, ".")
if r <= 0 {
return fmt.Errorf("invalid error name")
}
if name[:r] == "org.varlink.service" {
return fmt.Errorf("refused to send org.varlink.service errors")
}
return c.sendMessage(ctx, &serviceReply{
Error: name,
Parameters: parameters,
})
}
|