-
Notifications
You must be signed in to change notification settings - Fork 0
/
api.go
157 lines (132 loc) · 7.61 KB
/
api.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package protolator
import (
"github.com/golang/protobuf/proto"
)
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// This set of interfaces and methods is designed to allow protos to have Go methods attached
// to them, so that they may be automatically marshaled to human readable JSON (where the
// opaque byte fields are represented as their expanded proto contents) and back once again
// to standard proto messages.
//
// There are currently three different types of interfaces available for protos to implement:
//
// 1. StaticallyOpaque*FieldProto: These interfaces should be implemented by protos which have
// opaque byte fields whose marshaled type is known at compile time. This is mostly true
// for the signature oriented fields like the Envelope.Payload, or Header.ChannelHeader
//
// 2. VariablyOpaque*FieldProto: These interfaces are identical to the StaticallyOpaque*FieldProto
// definitions, with the exception that they are guaranteed to be evaluated after the
// StaticallyOpaque*FieldProto definitions. In particular, this allows for the type selection of
// a VariablyOpaque*FieldProto to depend on data populated by the StaticallyOpaque*FieldProtos.
// For example, the Payload.data field depends upon the Payload.Header.ChannelHeader.type field,
// which is along a statically marshaled path.
//
// 3. Dynamic*FieldProto: These interfaces are for messages which contain other messages whose
// attributes cannot be determined at compile time. For example, a ConfigValue message may evaluate
// the map field values["MSP"] successfully in an organization context, but not at all in a channel
// context. Because go is not a dynamic language, this dynamic behavior must be simulated by
// wrapping the underlying proto message in another type which can be configured at runtime with
// different contextual behavior. (See tests for examples)
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// StaticallyOpaqueFieldProto should be implemented by protos which have bytes fields which
// are the marshaled value of a fixed type
type StaticallyOpaqueFieldProto interface {
// StaticallyOpaqueFields returns the field names which contain opaque data
StaticallyOpaqueFields() []string
// StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
StaticallyOpaqueFieldProto(name string) (proto.Message, error)
}
// StaticallyOpaqueMapFieldProto should be implemented by protos which have maps to bytes fields
// which are the marshaled value of a fixed type
type StaticallyOpaqueMapFieldProto interface {
// StaticallyOpaqueFields returns the field names which contain opaque data
StaticallyOpaqueMapFields() []string
// StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
StaticallyOpaqueMapFieldProto(name string, key string) (proto.Message, error)
}
// StaticallyOpaqueSliceFieldProto should be implemented by protos which have maps to bytes fields
// which are the marshaled value of a fixed type
type StaticallyOpaqueSliceFieldProto interface {
// StaticallyOpaqueFields returns the field names which contain opaque data
StaticallyOpaqueSliceFields() []string
// StaticallyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
StaticallyOpaqueSliceFieldProto(name string, index int) (proto.Message, error)
}
// VariablyOpaqueFieldProto should be implemented by protos which have bytes fields which
// are the marshaled value depends upon the other contents of the proto
type VariablyOpaqueFieldProto interface {
// VariablyOpaqueFields returns the field names which contain opaque data
VariablyOpaqueFields() []string
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
VariablyOpaqueFieldProto(name string) (proto.Message, error)
}
// VariablyOpaqueMapFieldProto should be implemented by protos which have maps to bytes fields
// which are the marshaled value of a a message type determined by the other contents of the proto
type VariablyOpaqueMapFieldProto interface {
// VariablyOpaqueFields returns the field names which contain opaque data
VariablyOpaqueMapFields() []string
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
VariablyOpaqueMapFieldProto(name string, key string) (proto.Message, error)
}
// VariablyOpaqueSliceFieldProto should be implemented by protos which have maps to bytes fields
// which are the marshaled value of a a message type determined by the other contents of the proto
type VariablyOpaqueSliceFieldProto interface {
// VariablyOpaqueFields returns the field names which contain opaque data
VariablyOpaqueSliceFields() []string
// VariablyOpaqueFieldProto returns a newly allocated proto message of the correct
// type for the field name.
VariablyOpaqueSliceFieldProto(name string, index int) (proto.Message, error)
}
// DynamicFieldProto should be implemented by protos which have nested fields whose attributes
// (such as their opaque types) cannot be determined until runtime
type DynamicFieldProto interface {
// DynamicFields returns the field names which are dynamic
DynamicFields() []string
// DynamicFieldProto returns a newly allocated dynamic message, decorating an underlying
// proto message with the runtime determined function
DynamicFieldProto(name string, underlying proto.Message) (proto.Message, error)
}
// DynamicMapFieldProto should be implemented by protos which have maps to messages whose attributes
// (such as their opaque types) cannot be determined until runtime
type DynamicMapFieldProto interface {
// DynamicFields returns the field names which are dynamic
DynamicMapFields() []string
// DynamicMapFieldProto returns a newly allocated dynamic message, decorating an underlying
// proto message with the runtime determined function
DynamicMapFieldProto(name string, key string, underlying proto.Message) (proto.Message, error)
}
// DynamicSliceFieldProto should be implemented by protos which have slices of messages whose attributes
// (such as their opaque types) cannot be determined until runtime
type DynamicSliceFieldProto interface {
// DynamicFields returns the field names which are dynamic
DynamicSliceFields() []string
// DynamicSliceFieldProto returns a newly allocated dynamic message, decorating an underlying
// proto message with the runtime determined function
DynamicSliceFieldProto(name string, index int, underlying proto.Message) (proto.Message, error)
}
// DecoreatedProto should be implemented by the dynamic wrappers applied by the Dynamic*FieldProto interfaces
// This is necessary for the proto system to unmarshal, because it discovers proto message type by reflection
// (Rather than by interface definition as it probably should ( https://github.com/golang/protobuf/issues/291 )
type DecoratedProto interface {
// Underlying returns the underlying proto message which is being dynamically decorated
Underlying() proto.Message
}