ipfs-cluster/rpcutil/rpcutil.go
Hector Sanjuan 3c3341e491 Monitor: add PublishMetric() to component interface
The monitor component should be in charge of deciding how it is
best to send metrics to other peers and what that means.

This adds the PublishMetric() method to the component interface
and moves that functionality from Cluster main component to the
basic monitor.

There is a behaviour change. Before, the metrics where sent only to
the leader, while the leader was the only peer to broadcast them everywhere.
Now, all peers broadcast all metrics everywhere. This is mostly
because we should not rely on the consensus layer providing a Leader(), so
we are taking the chance to remove this dependency.

Note that in any-case, pubsub monitoring should replace the
existing basic monitor. This is just paving the ground.

Additionally, in order to not duplicate the multiRPC code
in the monitor, I have moved that functionality to go-libp2p-gorpc
and added an rpcutil library to cluster which includes useful
methods to perform multiRPC requests (some of them existed in
util.go, others are new and help handling multiple contexts etc).

License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-07 14:26:06 +02:00

131 lines
3.8 KiB
Go

// Package rpcutil provides utility methods to perform go-libp2p-gorpc calls,
// particularly gorpc.MultiCall().
package rpcutil
import (
"context"
"time"
"github.com/ipfs/ipfs-cluster/api"
peer "github.com/libp2p/go-libp2p-peer"
)
// CtxsWithTimeout returns n contexts, derived from the given parent
// using the given timeout.
func CtxsWithTimeout(
parent context.Context,
n int,
timeout time.Duration,
) ([]context.Context, []context.CancelFunc) {
ctxs := make([]context.Context, n, n)
cancels := make([]context.CancelFunc, n, n)
for i := 0; i < n; i++ {
ctx, cancel := context.WithTimeout(parent, timeout)
ctxs[i] = ctx
cancels[i] = cancel
}
return ctxs, cancels
}
// CtxsWithCancel returns n cancellable contexts, derived from the given parent.
func CtxsWithCancel(
parent context.Context,
n int,
) ([]context.Context, []context.CancelFunc) {
ctxs := make([]context.Context, n, n)
cancels := make([]context.CancelFunc, n, n)
for i := 0; i < n; i++ {
ctx, cancel := context.WithCancel(parent)
ctxs[i] = ctx
cancels[i] = cancel
}
return ctxs, cancels
}
// Multicancel calls all the provided CancelFuncs. It
// is useful with "defer Multicancel()"
func Multicancel(cancels []context.CancelFunc) {
for _, cancel := range cancels {
cancel()
}
}
// The copy functions below are used in calls to Cluste.multiRPC()
// CopyPIDsToIfaces converts a peer.ID slice to an empty interface
// slice using pointers to each elements of the original slice.
// Useful to handle gorpc.MultiCall() replies.
func CopyPIDsToIfaces(in []peer.ID) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// CopyIDSerialsToIfaces converts an api.IDSerial slice to an empty interface
// slice using pointers to each elements of the original slice.
// Useful to handle gorpc.MultiCall() replies.
func CopyIDSerialsToIfaces(in []api.IDSerial) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// CopyIDSerialSliceToIfaces converts an api.IDSerial slice of slices
// to an empty interface slice using pointers to each elements of the
// original slice. Useful to handle gorpc.MultiCall() replies.
func CopyIDSerialSliceToIfaces(in [][]api.IDSerial) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// CopyPinInfoSerialToIfaces converts an api.PinInfoSerial slice to
// an empty interface slice using pointers to each elements of
// the original slice. Useful to handle gorpc.MultiCall() replies.
func CopyPinInfoSerialToIfaces(in []api.PinInfoSerial) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// CopyPinInfoSerialSliceToIfaces converts an api.PinInfoSerial slice of slices
// to an empty interface slice using pointers to each elements of the original
// slice. Useful to handle gorpc.MultiCall() replies.
func CopyPinInfoSerialSliceToIfaces(in [][]api.PinInfoSerial) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// CopyEmptyStructToIfaces converts an empty struct slice to an empty interface
// slice using pointers to each elements of the original slice.
// Useful to handle gorpc.MultiCall() replies.
func CopyEmptyStructToIfaces(in []struct{}) []interface{} {
ifaces := make([]interface{}, len(in), len(in))
for i := range in {
ifaces[i] = &in[i]
}
return ifaces
}
// RPCDiscardReplies returns a []interface{} slice made from a []struct{}
// slice of then given length. Useful for RPC methods which have no response
// types (so they use empty structs).
func RPCDiscardReplies(n int) []interface{} {
replies := make([]struct{}, n, n)
return CopyEmptyStructToIfaces(replies)
}