163 lines
4.5 KiB
Go
163 lines
4.5 KiB
Go
|
// Package rpcutil provides utility methods to perform go-libp2p-gorpc calls,
|
||
|
// particularly gorpc.MultiCall().
|
||
|
package rpcutil
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"time"
|
||
|
|
||
|
"github.com/ipfs-cluster/ipfs-cluster/api"
|
||
|
)
|
||
|
|
||
|
// 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)
|
||
|
cancels := make([]context.CancelFunc, 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)
|
||
|
cancels := make([]context.CancelFunc, 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 Cluster.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))
|
||
|
// for i := range in {
|
||
|
// ifaces[i] = &in[i]
|
||
|
// }
|
||
|
// return ifaces
|
||
|
// }
|
||
|
|
||
|
// CopyIDsToIfaces converts an api.ID slice to an empty interface
|
||
|
// slice using pointers to each elements of the original slice.
|
||
|
// Useful to handle gorpc.MultiCall() replies.
|
||
|
func CopyIDsToIfaces(in []api.ID) []interface{} {
|
||
|
ifaces := make([]interface{}, len(in))
|
||
|
for i := range in {
|
||
|
in[i] = api.ID{}
|
||
|
ifaces[i] = &(in[i])
|
||
|
}
|
||
|
return ifaces
|
||
|
}
|
||
|
|
||
|
// CopyIDSliceToIfaces converts an api.ID slice of slices
|
||
|
// to an empty interface slice using pointers to each elements of the
|
||
|
// original slice. Useful to handle gorpc.MultiCall() replies.
|
||
|
func CopyIDSliceToIfaces(in [][]api.ID) []interface{} {
|
||
|
ifaces := make([]interface{}, len(in))
|
||
|
for i := range in {
|
||
|
ifaces[i] = &(in[i])
|
||
|
}
|
||
|
return ifaces
|
||
|
}
|
||
|
|
||
|
// CopyPinInfoToIfaces converts an api.PinInfo slice to
|
||
|
// an empty interface slice using pointers to each elements of
|
||
|
// the original slice. Useful to handle gorpc.MultiCall() replies.
|
||
|
func CopyPinInfoToIfaces(in []api.PinInfo) []interface{} {
|
||
|
ifaces := make([]interface{}, len(in))
|
||
|
for i := range in {
|
||
|
in[i] = api.PinInfo{}
|
||
|
ifaces[i] = &(in[i])
|
||
|
}
|
||
|
return ifaces
|
||
|
}
|
||
|
|
||
|
// CopyPinInfoSliceToIfaces converts an api.PinInfo slice of slices
|
||
|
// to an empty interface slice using pointers to each elements of the original
|
||
|
// slice. Useful to handle gorpc.MultiCall() replies.
|
||
|
func CopyPinInfoSliceToIfaces(in [][]api.PinInfo) []interface{} {
|
||
|
ifaces := make([]interface{}, len(in))
|
||
|
for i := range in {
|
||
|
ifaces[i] = &(in[i])
|
||
|
}
|
||
|
return ifaces
|
||
|
}
|
||
|
|
||
|
// CopyRepoGCSliceToIfaces converts an api.RepoGC slice to
|
||
|
// an empty interface slice using pointers to each elements of
|
||
|
// the original slice. Useful to handle gorpc.MultiCall() replies.
|
||
|
func CopyRepoGCSliceToIfaces(in []api.RepoGC) []interface{} {
|
||
|
ifaces := make([]interface{}, len(in))
|
||
|
for i := range in {
|
||
|
in[i] = api.RepoGC{}
|
||
|
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))
|
||
|
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)
|
||
|
return CopyEmptyStructToIfaces(replies)
|
||
|
}
|
||
|
|
||
|
// CheckErrs returns nil if all the errors in a slice are nil, otherwise
|
||
|
// it returns a single error formed by joining the error messages existing
|
||
|
// in the slice with a line-break.
|
||
|
func CheckErrs(errs []error) error {
|
||
|
errMsg := ""
|
||
|
|
||
|
for _, e := range errs {
|
||
|
if e != nil {
|
||
|
errMsg += fmt.Sprintf("%s\n", e.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if len(errMsg) > 0 {
|
||
|
return errors.New(errMsg)
|
||
|
}
|
||
|
return nil
|
||
|
}
|