@@ -8,13 +8,24 @@ package nats_jetstream
8
8
import (
9
9
"bytes"
10
10
"context"
11
+ "fmt"
12
+ "strings"
11
13
12
14
"github.com/nats-io/nats.go"
13
15
14
16
"github.com/cloudevents/sdk-go/v2/binding"
15
17
"github.com/cloudevents/sdk-go/v2/binding/format"
18
+ "github.com/cloudevents/sdk-go/v2/binding/spec"
16
19
)
17
20
21
+ const (
22
+ // see https://github.com/cloudevents/spec/blob/main/cloudevents/bindings/nats-protocol-binding.md
23
+ prefix = "ce-"
24
+ contentTypeHeader = "content-type"
25
+ )
26
+
27
+ var specs = spec .WithPrefix (prefix )
28
+
18
29
// Message implements binding.Message by wrapping an *nats.Msg.
19
30
// This message *can* be read several times safely
20
31
type Message struct {
@@ -24,8 +35,15 @@ type Message struct {
24
35
25
36
// NewMessage wraps an *nats.Msg in a binding.Message.
26
37
// The returned message *can* be read several times safely
38
+ // The default encoding returned is EncodingStructured unless the NATS message contains a specversion header.
27
39
func NewMessage (msg * nats.Msg ) * Message {
28
- return & Message {Msg : msg , encoding : binding .EncodingStructured }
40
+ encoding := binding .EncodingStructured
41
+ if msg .Header != nil {
42
+ if msg .Header .Get (specs .PrefixedSpecVersionName ()) != "" {
43
+ encoding = binding .EncodingBinary
44
+ }
45
+ }
46
+ return & Message {Msg : msg , encoding : encoding }
29
47
}
30
48
31
49
var _ binding.Message = (* Message )(nil )
@@ -37,15 +55,91 @@ func (m *Message) ReadEncoding() binding.Encoding {
37
55
38
56
// ReadStructured transfers a structured-mode event to a StructuredWriter.
39
57
func (m * Message ) ReadStructured (ctx context.Context , encoder binding.StructuredWriter ) error {
58
+ if m .encoding != binding .EncodingStructured {
59
+ return binding .ErrNotStructured
60
+ }
40
61
return encoder .SetStructuredEvent (ctx , format .JSON , bytes .NewReader (m .Msg .Data ))
41
62
}
42
63
43
64
// ReadBinary transfers a binary-mode event to an BinaryWriter.
44
65
func (m * Message ) ReadBinary (ctx context.Context , encoder binding.BinaryWriter ) error {
45
- return binding .ErrNotBinary
66
+ if m .encoding != binding .EncodingBinary {
67
+ return binding .ErrNotBinary
68
+ }
69
+
70
+ version := m .GetVersion ()
71
+ if version == nil {
72
+ return binding .ErrNotBinary
73
+ }
74
+
75
+ var err error
76
+ for k , v := range m .Msg .Header {
77
+ headerValue := v [0 ]
78
+ if strings .HasPrefix (k , prefix ) {
79
+ attr := version .Attribute (k )
80
+ if attr != nil {
81
+ err = encoder .SetAttribute (attr , headerValue )
82
+ } else {
83
+ err = encoder .SetExtension (strings .TrimPrefix (k , prefix ), headerValue )
84
+ }
85
+ } else if k == contentTypeHeader {
86
+ err = encoder .SetAttribute (version .AttributeFromKind (spec .DataContentType ), headerValue )
87
+ }
88
+ if err != nil {
89
+ return err
90
+ }
91
+ }
92
+
93
+ if m .Msg .Data != nil {
94
+ err = encoder .SetData (bytes .NewBuffer (m .Msg .Data ))
95
+ }
96
+
97
+ return err
46
98
}
47
99
48
100
// Finish *must* be called when message from a Receiver can be forgotten by the receiver.
49
101
func (m * Message ) Finish (err error ) error {
50
102
return nil
51
103
}
104
+
105
+ // GetAttribute implements binding.MessageMetadataReader
106
+ func (m * Message ) GetAttribute (attributeKind spec.Kind ) (spec.Attribute , interface {}) {
107
+ key := withPrefix (attributeKind .String ())
108
+ if m .Msg .Header != nil {
109
+ headerValue := m .Msg .Header .Get (key )
110
+ if headerValue != "" {
111
+ version := m .GetVersion ()
112
+ return version .Attribute (key ), headerValue
113
+ }
114
+ }
115
+ return nil , nil
116
+ }
117
+
118
+ // GetExtension implements binding.MessageMetadataReader
119
+ func (m * Message ) GetExtension (name string ) interface {} {
120
+ key := withPrefix (name )
121
+ if m .Msg .Header != nil {
122
+ headerValue := m .Msg .Header .Get (key )
123
+ if headerValue != "" {
124
+ return headerValue
125
+ }
126
+ }
127
+ return nil
128
+ }
129
+
130
+ // GetVersion looks for specVersion header and returns a Version object
131
+ func (m * Message ) GetVersion () spec.Version {
132
+ if m .Msg .Header == nil {
133
+ return nil
134
+ }
135
+ versionValue := m .Msg .Header .Get (specs .PrefixedSpecVersionName ())
136
+ if versionValue == "" {
137
+ return nil
138
+ }
139
+ return specs .Version (versionValue )
140
+ }
141
+
142
+ // withPrefix prepends the prefix to the attribute name
143
+ func withPrefix (attributeName string ) string {
144
+ return fmt .Sprintf ("%s%s" , prefix , attributeName )
145
+ }
0 commit comments