blob: f06fd6eb574ae97bbc9469a8c4d20649aed036ed [file] [log] [blame]
khenaidoo1ce37ad2019-03-24 22:07:24 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
khenaidoo1ce37ad2019-03-24 22:07:24 -040017package utils
18
khenaidoo2c6a0992019-04-29 13:46:56 -040019import (
Rohan Agrawal31f21802020-06-12 05:38:46 +000020 "context"
khenaidoo631fe542019-05-31 15:44:43 -040021 "os"
khenaidoo2c6a0992019-04-29 13:46:56 -040022 "time"
npujar1d86a522019-11-14 17:11:16 +053023
24 "google.golang.org/grpc/codes"
25 "google.golang.org/grpc/status"
khenaidoo2c6a0992019-04-29 13:46:56 -040026)
27
khenaidoo442e7c72020-03-10 16:13:48 -040028// ResponseCallback is the function signature for callbacks to execute after a response is received.
Rohan Agrawal31f21802020-06-12 05:38:46 +000029type ResponseCallback func(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{})
khenaidoo442e7c72020-03-10 16:13:48 -040030
npujar1d86a522019-11-14 17:11:16 +053031// DeviceID represent device id attribute
khenaidoo1ce37ad2019-03-24 22:07:24 -040032type DeviceID struct {
npujar1d86a522019-11-14 17:11:16 +053033 ID string
khenaidoo1ce37ad2019-03-24 22:07:24 -040034}
35
npujar1d86a522019-11-14 17:11:16 +053036// LogicalDeviceID rpresent logical device id attribute
khenaidoo1ce37ad2019-03-24 22:07:24 -040037type LogicalDeviceID struct {
npujar1d86a522019-11-14 17:11:16 +053038 ID string
khenaidoo1ce37ad2019-03-24 22:07:24 -040039}
khenaidoo2c6a0992019-04-29 13:46:56 -040040
npujar1d86a522019-11-14 17:11:16 +053041// GetHostName returns host name
khenaidoo631fe542019-05-31 15:44:43 -040042func GetHostName() string {
43 return os.Getenv("HOSTNAME")
44}
45
npujar1d86a522019-11-14 17:11:16 +053046// Response -
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050047type Response struct {
48 *response
49}
50type response struct {
51 err error
52 ch chan struct{}
53 done bool
54}
55
npujar1d86a522019-11-14 17:11:16 +053056// NewResponse -
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050057func NewResponse() Response {
58 return Response{
59 &response{
60 ch: make(chan struct{}),
61 },
62 }
63}
64
A R Karthick5c28f552019-12-11 22:47:44 -080065// Fake a completed response.
66func DoneResponse() Response {
67 r := Response{
68 &response{
69 err: nil,
70 ch: make(chan struct{}),
71 done: true,
72 },
73 }
74 close(r.ch)
75 return r
76}
77
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050078// Error sends a response with the given error. It may only be called once.
79func (r Response) Error(err error) {
80 // if this is called twice, it will panic; this is intentional
81 r.err = err
82 r.done = true
83 close(r.ch)
84}
85
86// Done sends a non-error response unless Error has already been called, in which case this is a no-op.
87func (r Response) Done() {
88 if !r.done {
89 close(r.ch)
90 }
91}
92
khenaidoo2c6a0992019-04-29 13:46:56 -040093//WaitForNilOrErrorResponses waits on a variadic number of channels for either a nil response or an error
94//response. If an error is received from a given channel then the returned error array will contain that error.
95//The error will be at the index corresponding to the order in which the channel appear in the parameter list.
96//If no errors is found then nil is returned. This method also takes in a timeout in milliseconds. If a
97//timeout is obtained then this function will stop waiting for the remaining responses and abort.
khenaidoo442e7c72020-03-10 16:13:48 -040098func WaitForNilOrErrorResponses(timeout time.Duration, responses ...Response) []error {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050099 timedOut := make(chan struct{})
khenaidoo442e7c72020-03-10 16:13:48 -0400100 timer := time.AfterFunc(timeout, func() { close(timedOut) })
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500101 defer timer.Stop()
khenaidoo2c6a0992019-04-29 13:46:56 -0400102
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500103 gotError := false
104 errors := make([]error, 0, len(responses))
105 for _, response := range responses {
106 var err error
107 select {
108 case <-response.ch:
109 // if a response is already available, use it
110 err = response.err
111 default:
112 // otherwise, wait for either a response or a timeout
113 select {
114 case <-response.ch:
115 err = response.err
116 case <-timedOut:
117 err = status.Error(codes.Aborted, "timeout")
khenaidoo2c6a0992019-04-29 13:46:56 -0400118 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400119 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500120 gotError = gotError || err != nil
121 errors = append(errors, err)
khenaidoo2c6a0992019-04-29 13:46:56 -0400122 }
123
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500124 if gotError {
khenaidoo2c6a0992019-04-29 13:46:56 -0400125 return errors
126 }
127 return nil
128}