-
Notifications
You must be signed in to change notification settings - Fork 217
/
spec.go
233 lines (210 loc) · 6.56 KB
/
spec.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package spec
import (
"fmt"
"strings"
ce "github.com/cloudevents/sdk-go/pkg/cloudevents"
"github.com/cloudevents/sdk-go/pkg/cloudevents/types"
)
// Version provides meta-data for a single spec-version.
type Version interface {
// String name of the version, e.g. "1.0"
String() string
// Prefix for attribute names.
Prefix() string
// Attribute looks up a prefixed attribute name (case insensitive).
// Returns nil if not found.
Attribute(name string) Attribute
// Attributes returns all the context attributes for this version.
Attributes() []Attribute
// NewContext returns a new context for this version.
NewContext() ce.EventContext
// Convert translates a context to this version.
Convert(ce.EventContextConverter) ce.EventContext
// SetAttribute sets named attribute to value.
//
// Name is case insensitive.
// Does nothing if name does not start with prefix.
SetAttribute(context ce.EventContextWriter, name string, value interface{}) error
// Attribute looks up the attribute from kind.
// Returns nil if not found.
AttributeFromKind(kind Kind) Attribute
}
// Versions contains all known versions with the same attribute prefix.
type Versions struct {
prefix string
all []Version
m map[string]Version
svnames []string
}
// Versions returns the list of all known versions, most recent first.
func (vs *Versions) Versions() []Version { return vs.all }
// Version returns the named version.
func (vs *Versions) Version(name string) (Version, error) {
if v := vs.m[name]; v != nil {
return v, nil
}
return nil, fmt.Errorf("invalid spec version %#v", name)
}
// Latest returns the latest Version
func (vs *Versions) Latest() Version { return vs.all[0] }
// SpecVersionNames returns distinct names of the specversion
// attribute used in all versions, newest first.
// Names are prefixed.
func (vs *Versions) SpecVersionNames() []string { return vs.svnames }
// Prefix is the lowercase attribute name prefix.
func (vs *Versions) Prefix() string { return vs.prefix }
// FindVersion calls getAttr with known (prefixed) spec-version attribute names
// till it finds a valid version.
func (vs *Versions) FindVersion(getAttr func(string) string) (Version, error) {
for _, sv := range vs.svnames {
if v, err := vs.Version(getAttr(sv)); err == nil {
return v, nil
}
}
return nil, fmt.Errorf("CloudEvents spec-version not found")
}
type attribute struct {
accessor
name string
version Version
}
func (a *attribute) Name() string { return a.name }
func (a *attribute) Version() Version { return a.version }
type version struct {
prefix string
context ce.EventContext
convert func(ce.EventContextConverter) ce.EventContext
attrMap map[string]Attribute
attrs []Attribute
}
func (v *version) Attribute(name string) Attribute { return v.attrMap[strings.ToLower(name)] }
func (v *version) Attributes() []Attribute { return v.attrs }
func (v *version) String() string { return v.context.GetSpecVersion() }
func (v *version) Prefix() string { return v.prefix }
func (v *version) NewContext() ce.EventContext { return v.context.Clone() }
// HasPrefix is a case-insensitive prefix check.
func (v *version) HasPrefix(name string) bool {
return strings.HasPrefix(strings.ToLower(name), v.prefix)
}
func (v *version) Convert(c ce.EventContextConverter) ce.EventContext { return v.convert(c) }
func (v *version) SetAttribute(c ce.EventContextWriter, name string, value interface{}) error {
if a := v.Attribute(name); a != nil { // Standard attribute
return a.Set(c, value)
}
name = strings.ToLower(name)
var err error
if strings.HasPrefix(name, v.prefix) { // Extension attribute
value, err = types.Validate(value)
if err == nil {
err = c.SetExtension(strings.TrimPrefix(name, v.prefix), value)
}
}
return err
}
func (v *version) AttributeFromKind(kind Kind) Attribute {
for _, a := range v.Attributes() {
if a.Kind() == kind {
return a
}
}
return nil
}
func newVersion(
prefix string,
context ce.EventContext,
convert func(ce.EventContextConverter) ce.EventContext,
attrs ...*attribute,
) *version {
v := &version{
prefix: strings.ToLower(prefix),
context: context,
convert: convert,
attrMap: map[string]Attribute{},
attrs: make([]Attribute, len(attrs)),
}
for i, a := range attrs {
a.name = prefix + a.name
a.version = v
v.attrs[i] = a
v.attrMap[strings.ToLower(a.name)] = a
}
return v
}
// WithPrefix returns a set of versions with prefix added to all attribute names.
func WithPrefix(prefix string) *Versions {
attr := func(name string, kind Kind) *attribute {
return &attribute{accessor: acc[kind], name: name}
}
vs := &Versions{
m: map[string]Version{},
svnames: []string{
prefix + "specversion",
prefix + "cloudEventsVersion",
},
all: []Version{
newVersion(prefix, ce.EventContextV1{}.AsV1(),
func(c ce.EventContextConverter) ce.EventContext { return c.AsV1() },
attr("id", ID),
attr("source", Source),
attr("specversion", SpecVersion),
attr("type", Type),
attr("datacontenttype", DataContentType),
attr("dataschema", DataSchema),
attr("subject", Subject),
attr("time", Time),
),
newVersion(prefix, ce.EventContextV03{}.AsV03(),
func(c ce.EventContextConverter) ce.EventContext { return c.AsV03() },
attr("specversion", SpecVersion),
attr("type", Type),
attr("source", Source),
attr("schemaurl", DataSchema),
attr("subject", Subject),
attr("id", ID),
attr("time", Time),
attr("datacontenttype", DataContentType),
),
newVersion(prefix, ce.EventContextV02{}.AsV02(),
func(c ce.EventContextConverter) ce.EventContext { return c.AsV02() },
attr("specversion", SpecVersion),
attr("type", Type),
attr("source", Source),
attr("schemaurl", DataSchema),
attr("id", ID),
attr("time", Time),
attr("contenttype", DataContentType),
),
newVersion(prefix, ce.EventContextV01{}.AsV01(),
func(c ce.EventContextConverter) ce.EventContext { return c.AsV01() },
attr("cloudEventsVersion", SpecVersion),
attr("eventType", Type),
attr("source", Source),
attr("schemaURL", DataSchema),
attr("eventID", ID),
attr("eventTime", Time),
attr("contentType", DataContentType),
),
},
}
for _, v := range vs.all {
vs.m[v.String()] = v
}
return vs
}
// New returns a set of versions
func New() *Versions { return WithPrefix("") }
// Built-in un-prefixed versions.
var (
VS *Versions
V01 Version
V02 Version
V03 Version
V1 Version
)
func init() {
VS = New()
V01, _ = VS.Version("0.1")
V02, _ = VS.Version("0.2")
V03, _ = VS.Version("0.3")
V1, _ = VS.Version("1.0")
}