blob: 383696a4278162a4ba2e36370868fed2b3cb8ca6 [file] [log] [blame]
Scott Bakere7144bc2019-10-01 14:16:47 -07001/*
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 */
16
17package afrouter
18
19import (
Scott Bakere7144bc2019-10-01 14:16:47 -070020 "github.com/golang/protobuf/proto"
Scott Bakerf579f132019-10-24 14:31:41 -070021 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Scott Baker4989fe92019-10-09 17:03:06 -070022 "google.golang.org/grpc/encoding"
Scott Bakere7144bc2019-10-01 14:16:47 -070023)
24
Scott Baker4989fe92019-10-09 17:03:06 -070025/*
26 * encoding.Codec renamed grpc.Codec's String() method to Name()
27 *
28 * grpc.ForceCodec() expects an encoding.Codec, alternative use of grpc.Codec is deprecated
29 * grpc.CustomCodec() expects a grpc.Codec, has no mechanism to use encoding.Codec
30 *
31 * Make an interface that supports them both.
32 */
33type hybridCodec interface {
34 encoding.Codec
35 String() string
36}
37
38func Codec() hybridCodec {
Scott Bakere7144bc2019-10-01 14:16:47 -070039 return CodecWithParent(&protoCodec{})
40}
41
Scott Baker4989fe92019-10-09 17:03:06 -070042func CodecWithParent(parent encoding.Codec) hybridCodec {
Scott Bakere7144bc2019-10-01 14:16:47 -070043 return &transparentRoutingCodec{parent}
44}
45
46type transparentRoutingCodec struct {
Scott Baker4989fe92019-10-09 17:03:06 -070047 parentCodec encoding.Codec
Scott Bakere7144bc2019-10-01 14:16:47 -070048}
49
50// responseFrame is a frame being "returned" to whomever established the connection
51type responseFrame struct {
52 payload []byte
53 router Router
54 method string
55 backend *backend
56 metaKey string
57 metaVal string
58}
59
60// requestFrame is a frame coming in from whomever established the connection
61type requestFrame struct {
62 payload []byte
63 router Router
64 backend *backend
65 connection *connection // optional, if the router preferred one connection over another
66 err error
67 methodInfo methodDetails
68 serialNo string
69 metaKey string
70 metaVal string
71}
72
73func (cdc *transparentRoutingCodec) Marshal(v interface{}) ([]byte, error) {
74 switch t := v.(type) {
75 case *responseFrame:
76 return t.payload, nil
77 case *requestFrame:
78 return t.payload, nil
79 default:
80 return cdc.parentCodec.Marshal(v)
81 }
82}
83
84func (cdc *transparentRoutingCodec) Unmarshal(data []byte, v interface{}) error {
85 switch t := v.(type) {
86 case *responseFrame:
87 t.payload = data
88 // This is where the affinity is established on a northbound response
Scott Baker4989fe92019-10-09 17:03:06 -070089
90 /*
91 * NOTE: Ignoring this error is intentional. MethodRouter returns
92 * error when a reply is not processed for northbound affinity,
93 * but we still need to unmarshal it.
94 *
95 * TODO: Investigate error-return semantics of ReplyHandler.
96 */
97 _ = t.router.ReplyHandler(v)
Scott Bakere7144bc2019-10-01 14:16:47 -070098 return nil
99 case *requestFrame:
100 t.payload = data
101 // This is were the afinity value is pulled from the payload
102 // and the backend selected.
103 t.backend, t.connection = t.router.Route(v)
104 name := "<nil>"
105 if t.backend != nil {
106 name = t.backend.name
107 }
108 log.Debugf("Routing returned %s for method %s", name, t.methodInfo.method)
109
110 return nil
111 default:
112 return cdc.parentCodec.Unmarshal(data, v)
113 }
114}
115
Scott Baker4989fe92019-10-09 17:03:06 -0700116func (cdc *transparentRoutingCodec) Name() string {
117 return cdc.parentCodec.Name()
118}
119
Scott Bakere7144bc2019-10-01 14:16:47 -0700120func (cdc *transparentRoutingCodec) String() string {
Scott Baker4989fe92019-10-09 17:03:06 -0700121 return cdc.Name()
Scott Bakere7144bc2019-10-01 14:16:47 -0700122}
123
124// protoCodec is a Codec implementation with protobuf. It is the default Codec for gRPC.
125type protoCodec struct{}
126
127func (protoCodec) Marshal(v interface{}) ([]byte, error) {
128 return proto.Marshal(v.(proto.Message))
129}
130
131func (protoCodec) Unmarshal(data []byte, v interface{}) error {
132 return proto.Unmarshal(data, v.(proto.Message))
133}
134
Scott Baker4989fe92019-10-09 17:03:06 -0700135func (protoCodec) Name() string {
Scott Bakere7144bc2019-10-01 14:16:47 -0700136 return "protoCodec"
137}