gotelem/internal/gotelem/rpc.go

121 lines
3.1 KiB
Go
Raw Normal View History

2023-04-30 19:49:18 +00:00
package gotelem
2023-05-01 14:49:47 +00:00
import (
"net"
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
"github.com/tinylib/msgp/msgp"
)
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
// the target architecture is a subscribe function that
// takes a can FILTER. Then the server will emit notifications.
// that contain new can packets as they come in.
// this means that the client should be able to handle
// notify packets on top of response packets.
// we should register handlers. They should handle serialization
// and deserialization on their own. This way we avoid reflect.
// since reflected code can be more complex under the hood.
// ServiceFunc is a RPC service handler.
type ServiceFunc func(params msgp.Raw) (res msgp.MarshalSizer, err error)
// RPCConn is a single RPC communication pair.
type RPCConn struct {
// TODO: use io.readwritecloser?
conn net.Conn
handlers map[string]ServiceFunc
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
// indicates what messages we've used.
// TODO: use a channel to return a response?
// TODO: lock with mutex
ct map[uint32]struct{}
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// Call intiates an RPC call to a remote method and returns the
// response, or the error, if any.
// TODO: determine signature
// TODO: this should block?
func (rpc *RPCConn) Call(method string, params msgp.Marshaler) {
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// Notify initiates a notification to a remote method. It does not
// return any information. There is no response from the server.
// This method will not block. An error is returned if there is a local
// problem.
func (rpc *RPCConn) Notify(method string, params msgp.Marshaler) {
// TODO: return an error if there's a local problem?
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// Register a new handler to be called by the remote side. An error
// is returned if the handler name is already in use.
func (rpc *RPCConn) RegisterHandler(name string, fn ServiceFunc) error {
// TODO: check if name in use.
// TODO: mutex lock for sync (or use sync.map?
rpc.handlers[name] = fn
return nil
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// Serve runs the server. It will dispatch goroutines to handle each
// method call. This can (and should in most cases) be run in the background to allow for
// sending and receving on the same connection.
func (rpc *RPCConn) Serve() {
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
// construct a stream reader.
msgReader := msgp.NewReader(rpc.conn)
// read a request/notification from the connection.
var rawmsg msgp.Raw = make(msgp.Raw, 0, 4)
rawmsg.DecodeMsg(msgReader)
rpcIntf, err := parseRPC(rawmsg)
switch rpcObject := rpcIntf.(type) {
case Request:
// the object is a request - we must dispatch a goroutine
// that will call the handler and also send a return value.
go rpc.dispatch(rpcObject)
case Notification:
go rpc.dispatchNotif(rpcObject)
case Response:
// TODO: return response to caller.
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
}
func (rpc *RPCConn) dispatch(req Request) {
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
result, err := rpc.handlers[req.Method](req.Params)
2023-04-30 19:49:18 +00:00
if err != nil {
2023-05-01 14:49:47 +00:00
// log the error.
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// construct the response frame.
var rpcE *RPCError = MakeRPCError(err)
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
w := msgp.NewWriter(rpc.conn)
resBuf := make(msgp.Raw, result.Msgsize())
result.MarshalMsg(resBuf)
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
response := NewResponse(req.MsgId, *rpcE, resBuf)
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
response.EncodeMsg(w)
}
func (rpc *RPCConn) dispatchNotif(req Notification) {
2023-04-30 19:49:18 +00:00
2023-05-01 14:49:47 +00:00
_, err := rpc.handlers[req.Method](req.Params)
if err != nil {
// log the error.
2023-04-30 19:49:18 +00:00
}
2023-05-01 14:49:47 +00:00
// no need for response.
2023-04-30 19:49:18 +00:00
}