blob: c9cd56df376082ee459afc18169c61dd5acb3f51 [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 */
16package utils
17
khenaidoo2c6a0992019-04-29 13:46:56 -040018import (
19 "google.golang.org/grpc/codes"
20 "google.golang.org/grpc/status"
khenaidoo631fe542019-05-31 15:44:43 -040021 "os"
khenaidoo2c6a0992019-04-29 13:46:56 -040022 "reflect"
23 "time"
24)
25
khenaidoo1ce37ad2019-03-24 22:07:24 -040026type DeviceID struct {
27 Id string
28}
29
30type LogicalDeviceID struct {
31 Id string
32}
khenaidoo2c6a0992019-04-29 13:46:56 -040033
khenaidoo631fe542019-05-31 15:44:43 -040034func GetHostName() string {
35 return os.Getenv("HOSTNAME")
36}
37
khenaidoo2c6a0992019-04-29 13:46:56 -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 {
44 // Create a timeout channel
45 tChnl := make(chan *interface{})
46 go func() {
47 time.Sleep(time.Duration(timeout) * time.Millisecond)
48 tChnl <- nil
49 }()
50
51 errorsReceived := false
52 errors := make([]error, len(chnls))
53 cases := make([]reflect.SelectCase, len(chnls)+1)
54 for i, ch := range chnls {
55 cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)}
56 }
57 // Add the timeout channel
58 cases[len(chnls)] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tChnl)}
59
60 resultsReceived := make([]bool, len(errors)+1)
61 remaining := len(cases) - 1
62 for remaining > 0 {
63 index, value, ok := reflect.Select(cases)
64 if !ok { // closed channel
65 //Set the channel at that index to nil to disable this case, hence preventing it from interfering with other cases.
66 cases[index].Chan = reflect.ValueOf(nil)
khenaidoo68c930b2019-05-13 11:46:51 -040067 errors[index] = status.Error(codes.Internal, "channel closed")
khenaidoo2c6a0992019-04-29 13:46:56 -040068 errorsReceived = true
69 } else if index == len(chnls) { // Timeout has occurred
70 for k := range errors {
71 if !resultsReceived[k] {
khenaidoo68c930b2019-05-13 11:46:51 -040072 errors[k] = status.Error(codes.Aborted, "timeout")
khenaidoo2c6a0992019-04-29 13:46:56 -040073 }
74 }
75 errorsReceived = true
76 break
77 } else if value.IsNil() { // Nil means a good response
78 //do nothing
79 } else if err, ok := value.Interface().(error); ok { // error returned
80 errors[index] = err
81 errorsReceived = true
82 } else { // unknown value
83 errors[index] = status.Errorf(codes.Internal, "%s", value)
84 errorsReceived = true
85 }
86 resultsReceived[index] = true
87 remaining -= 1
88 }
89
90 if errorsReceived {
91 return errors
92 }
93 return nil
94}