blob: aad13482260a97da08c83e77ae8b5a151e45f363 [file] [log] [blame]
Matt Jeanneretcab955f2019-04-10 15:45:57 -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 */
16package utils
17
Matt Jeanneret384d8c92019-05-06 14:27:31 -040018import (
19 "google.golang.org/grpc/codes"
20 "google.golang.org/grpc/status"
Mahir Gunyele77977b2019-06-27 05:36:22 -070021 "os"
Matt Jeanneret384d8c92019-05-06 14:27:31 -040022 "reflect"
23 "time"
24)
25
Matt Jeanneretcab955f2019-04-10 15:45:57 -040026type DeviceID struct {
27 Id string
28}
29
30type LogicalDeviceID struct {
31 Id string
32}
Matt Jeanneret384d8c92019-05-06 14:27:31 -040033
Mahir Gunyele77977b2019-06-27 05:36:22 -070034func GetHostName() string {
35 return os.Getenv("HOSTNAME")
36}
37
Matt Jeanneret384d8c92019-05-06 14:27:31 -040038//WaitForNilOrErrorResponses waits on a variadic number of channels for either a nil response or an error
39//response. If an error is received from a given channel then the returned error array will contain that error.
40//The error will be at the index corresponding to the order in which the channel appear in the parameter list.
41//If no errors is found then nil is returned. This method also takes in a timeout in milliseconds. If a
42//timeout is obtained then this function will stop waiting for the remaining responses and abort.
43func WaitForNilOrErrorResponses(timeout int64, chnls ...chan interface{}) []error {
Manikkaraj kb1d51442019-07-23 10:41:02 -040044 if len(chnls) == 0 {
45 return nil
46 }
Matt Jeanneret384d8c92019-05-06 14:27:31 -040047 // Create a timeout channel
48 tChnl := make(chan *interface{})
49 go func() {
50 time.Sleep(time.Duration(timeout) * time.Millisecond)
51 tChnl <- nil
52 }()
53
54 errorsReceived := false
55 errors := make([]error, len(chnls))
56 cases := make([]reflect.SelectCase, len(chnls)+1)
57 for i, ch := range chnls {
58 cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
59 }
60 // Add the timeout channel
61 cases[len(chnls)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tChnl)}
62
63 resultsReceived := make([]bool, len(errors)+1)
64 remaining := len(cases) - 1
65 for remaining > 0 {
66 index, value, ok := reflect.Select(cases)
67 if !ok { // closed channel
68 //Set the channel at that index to nil to disable this case, hence preventing it from interfering with other cases.
69 cases[index].Chan = reflect.ValueOf(nil)
Matt Jeannereta93dbed2019-05-17 12:40:05 -040070 errors[index] = status.Error(codes.Internal, "channel closed")
Matt Jeanneret384d8c92019-05-06 14:27:31 -040071 errorsReceived = true
72 } else if index == len(chnls) { // Timeout has occurred
73 for k := range errors {
74 if !resultsReceived[k] {
Matt Jeannereta93dbed2019-05-17 12:40:05 -040075 errors[k] = status.Error(codes.Aborted, "timeout")
Matt Jeanneret384d8c92019-05-06 14:27:31 -040076 }
77 }
78 errorsReceived = true
79 break
80 } else if value.IsNil() { // Nil means a good response
81 //do nothing
82 } else if err, ok := value.Interface().(error); ok { // error returned
83 errors[index] = err
84 errorsReceived = true
85 } else { // unknown value
86 errors[index] = status.Errorf(codes.Internal, "%s", value)
87 errorsReceived = true
88 }
89 resultsReceived[index] = true
90 remaining -= 1
91 }
92
93 if errorsReceived {
94 return errors
95 }
96 return nil
97}