blob: 71d5acd2d88b91bb543a5a834fc184c9c68d7787 [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"
Himani Chawlab4c25912020-11-12 17:16:38 +053021 "github.com/opencord/voltha-lib-go/v4/pkg/log"
npujar1d86a522019-11-14 17:11:16 +053022 "google.golang.org/grpc/codes"
23 "google.golang.org/grpc/status"
Himani Chawlab4c25912020-11-12 17:16:38 +053024 "os"
25 "time"
26)
27
28type contextKey string
29
30func (c contextKey) String() string {
31 return string(c)
32}
33
34var (
35 // RPCContextKey for keeping rpc name as metadata
36 rpcContextKey = contextKey("rpc")
khenaidoo2c6a0992019-04-29 13:46:56 -040037)
38
khenaidoo442e7c72020-03-10 16:13:48 -040039// ResponseCallback is the function signature for callbacks to execute after a response is received.
Rohan Agrawal31f21802020-06-12 05:38:46 +000040type ResponseCallback func(ctx context.Context, rpc string, response interface{}, reqArgs ...interface{})
khenaidoo442e7c72020-03-10 16:13:48 -040041
npujar1d86a522019-11-14 17:11:16 +053042// DeviceID represent device id attribute
khenaidoo1ce37ad2019-03-24 22:07:24 -040043type DeviceID struct {
npujar1d86a522019-11-14 17:11:16 +053044 ID string
khenaidoo1ce37ad2019-03-24 22:07:24 -040045}
46
npujar1d86a522019-11-14 17:11:16 +053047// LogicalDeviceID rpresent logical device id attribute
khenaidoo1ce37ad2019-03-24 22:07:24 -040048type LogicalDeviceID struct {
npujar1d86a522019-11-14 17:11:16 +053049 ID string
khenaidoo1ce37ad2019-03-24 22:07:24 -040050}
khenaidoo2c6a0992019-04-29 13:46:56 -040051
npujar1d86a522019-11-14 17:11:16 +053052// GetHostName returns host name
khenaidoo631fe542019-05-31 15:44:43 -040053func GetHostName() string {
54 return os.Getenv("HOSTNAME")
55}
56
npujar1d86a522019-11-14 17:11:16 +053057// Response -
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050058type Response struct {
59 *response
60}
61type response struct {
62 err error
63 ch chan struct{}
64 done bool
65}
66
npujar1d86a522019-11-14 17:11:16 +053067// NewResponse -
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050068func NewResponse() Response {
69 return Response{
70 &response{
71 ch: make(chan struct{}),
72 },
73 }
74}
75
A R Karthick5c28f552019-12-11 22:47:44 -080076// Fake a completed response.
77func DoneResponse() Response {
78 r := Response{
79 &response{
80 err: nil,
81 ch: make(chan struct{}),
82 done: true,
83 },
84 }
85 close(r.ch)
86 return r
87}
88
Kent Hagerman8da2f1e2019-11-25 17:28:09 -050089// Error sends a response with the given error. It may only be called once.
90func (r Response) Error(err error) {
91 // if this is called twice, it will panic; this is intentional
92 r.err = err
93 r.done = true
94 close(r.ch)
95}
96
97// Done sends a non-error response unless Error has already been called, in which case this is a no-op.
98func (r Response) Done() {
99 if !r.done {
100 close(r.ch)
101 }
102}
103
khenaidoo2c6a0992019-04-29 13:46:56 -0400104//WaitForNilOrErrorResponses waits on a variadic number of channels for either a nil response or an error
105//response. If an error is received from a given channel then the returned error array will contain that error.
106//The error will be at the index corresponding to the order in which the channel appear in the parameter list.
107//If no errors is found then nil is returned. This method also takes in a timeout in milliseconds. If a
108//timeout is obtained then this function will stop waiting for the remaining responses and abort.
khenaidoo442e7c72020-03-10 16:13:48 -0400109func WaitForNilOrErrorResponses(timeout time.Duration, responses ...Response) []error {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500110 timedOut := make(chan struct{})
khenaidoo442e7c72020-03-10 16:13:48 -0400111 timer := time.AfterFunc(timeout, func() { close(timedOut) })
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500112 defer timer.Stop()
khenaidoo2c6a0992019-04-29 13:46:56 -0400113
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500114 gotError := false
115 errors := make([]error, 0, len(responses))
116 for _, response := range responses {
117 var err error
118 select {
119 case <-response.ch:
120 // if a response is already available, use it
121 err = response.err
122 default:
123 // otherwise, wait for either a response or a timeout
124 select {
125 case <-response.ch:
126 err = response.err
127 case <-timedOut:
128 err = status.Error(codes.Aborted, "timeout")
khenaidoo2c6a0992019-04-29 13:46:56 -0400129 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400130 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500131 gotError = gotError || err != nil
132 errors = append(errors, err)
khenaidoo2c6a0992019-04-29 13:46:56 -0400133 }
134
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500135 if gotError {
khenaidoo2c6a0992019-04-29 13:46:56 -0400136 return errors
137 }
138 return nil
139}
Himani Chawlab4c25912020-11-12 17:16:38 +0530140
141func WithRPCMetadataContext(ctx context.Context, rpcName string) context.Context {
142 ctx = context.WithValue(ctx, rpcContextKey, rpcName)
143 return ctx
144}
145
146func GetRPCMetadataFromContext(ctx context.Context) string {
147 if ctx != nil {
148 if val, ok := ctx.Value(rpcContextKey).(string); ok {
149 return val
150 }
151 }
152 return ""
153}
154
155func WithRPCMetadataFromContext(targetCtx, sourceCtx context.Context) context.Context {
156 if sourceCtx != nil {
157 if val, ok := sourceCtx.Value(rpcContextKey).(string); ok {
158 targetCtx = context.WithValue(targetCtx, rpcContextKey, val)
159 }
160 }
161 return targetCtx
162}
163
164func WithSpanAndRPCMetadataFromContext(sourceCtx context.Context) context.Context {
165 targetCtx := context.Background()
166 if sourceCtx != nil {
167 targetCtx = log.WithSpanFromContext(targetCtx, sourceCtx)
168 targetCtx = WithRPCMetadataFromContext(targetCtx, sourceCtx)
169 }
170 return targetCtx
171}