github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/agent/mcorpc/client/util.go (about)

     1  // Copyright (c) 2020-2021, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package client
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"math"
    13  	"time"
    14  
    15  	"github.com/choria-io/go-choria/protocol"
    16  )
    17  
    18  // ParseReply parses a protocol reply into a RPC Reply
    19  func ParseReply(reply protocol.Reply) (*RPCReply, error) {
    20  	r, err := ParseReplyData([]byte(reply.Message()))
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	r.Time = reply.Time().UTC()
    26  	r.Sender = reply.SenderID()
    27  
    28  	return r, nil
    29  }
    30  
    31  // ParseReplyData parses reply data and populates a Reply and custom Data
    32  func ParseReplyData(source []byte) (*RPCReply, error) {
    33  	reply := &RPCReply{}
    34  
    35  	err := json.Unmarshal(source, reply)
    36  	if err != nil {
    37  		return reply, fmt.Errorf("could not decode source data: %s", err)
    38  	}
    39  
    40  	return reply, nil
    41  }
    42  
    43  // InGroups calls f for sub slices of a slice where every slice
    44  // is at most `size` big
    45  func InGroups(set []string, size int, f func([]string) error) error {
    46  	count := math.Ceil(float64(len(set)) / float64(size))
    47  
    48  	for i := 0; i < int(count); i++ {
    49  		start := i * int(size)
    50  		end := start + int(size)
    51  
    52  		if end > len(set) {
    53  			end = len(set)
    54  		}
    55  
    56  		err := f(set[start:end])
    57  		if err != nil {
    58  			return err
    59  		}
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  // InterruptableSleep sleep for the duration of the n'th wait cycle
    66  // in a way that can be interrupted by the context.  An error is returned
    67  // if the context cancels the sleep
    68  func InterruptableSleep(ctx context.Context, d time.Duration) error {
    69  	timer := time.NewTimer(d)
    70  
    71  	select {
    72  	case <-timer.C:
    73  		return nil
    74  	case <-ctx.Done():
    75  		return errors.New("sleep interrupted by context")
    76  	}
    77  }