functions_framework 0.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,43 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "functions_framework/cloud_events/content_type"
16
- require "functions_framework/cloud_events/errors"
17
- require "functions_framework/cloud_events/event"
18
- require "functions_framework/cloud_events/http_binding"
19
- require "functions_framework/cloud_events/json_format"
20
-
21
- module FunctionsFramework
22
- ##
23
- # CloudEvents implementation.
24
- #
25
- # This is a Ruby implementation of the [CloudEvents](https://cloudevents.io)
26
- # [1.0 specification](https://github.com/cloudevents/spec/blob/master/spec.md).
27
- #
28
- module CloudEvents
29
- # @private
30
- SUPPORTED_SPEC_VERSIONS = ["1.0"].freeze
31
-
32
- class << self
33
- ##
34
- # The spec versions supported by this implementation.
35
- #
36
- # @return [Array<String>]
37
- #
38
- def supported_spec_versions
39
- SUPPORTED_SPEC_VERSIONS
40
- end
41
- end
42
- end
43
- end
@@ -1,139 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module FunctionsFramework
16
- module CloudEvents
17
- ##
18
- # A parsed content-type header.
19
- #
20
- # This object represents the information contained in a Content-Type,
21
- # obtained by parsing the header according to RFC 2045.
22
- #
23
- # Case-insensitive fields, such as media_type and subtype, are normalized
24
- # to lower case.
25
- #
26
- class ContentType
27
- ##
28
- # Parse the given header value
29
- #
30
- # @param string [String] Content-Type header value in RFC 2045 format
31
- #
32
- def initialize string
33
- @string = string
34
- # TODO: This handles simple cases but is not RFC-822 compliant.
35
- sections = string.to_s.split ";"
36
- media_type, subtype = sections.shift.split "/"
37
- subtype_prefix, subtype_format = subtype.split "+"
38
- @media_type = media_type.strip.downcase
39
- @subtype = subtype.strip.downcase
40
- @subtype_prefix = subtype_prefix.strip.downcase
41
- @subtype_format = subtype_format&.strip&.downcase
42
- @params = initialize_params sections
43
- @canonical_string = "#{@media_type}/#{@subtype}" +
44
- @params.map { |k, v| "; #{k}=#{v}" }.join
45
- end
46
-
47
- ##
48
- # The original header content string
49
- # @return [String]
50
- #
51
- attr_reader :string
52
- alias to_s string
53
-
54
- ##
55
- # A "canonical" header content string with spacing and capitalization
56
- # normalized.
57
- # @return [String]
58
- #
59
- attr_reader :canonical_string
60
-
61
- ##
62
- # The media type.
63
- # @return [String]
64
- #
65
- attr_reader :media_type
66
-
67
- ##
68
- # The entire content subtype (which could include an extension delimited
69
- # by a plus sign)
70
- # @return [String]
71
- #
72
- attr_reader :subtype
73
-
74
- ##
75
- # The portion of the content subtype before any plus sign.
76
- # @return [String]
77
- #
78
- attr_reader :subtype_prefix
79
-
80
- ##
81
- # The portion of the content subtype after any plus sign, or nil if there
82
- # is no plus sign in the subtype.
83
- # @return [String,nil]
84
- #
85
- attr_reader :subtype_format
86
-
87
- ##
88
- # An array of parameters, each element as a two-element array of the
89
- # parameter name and value.
90
- # @return [Array<Array(String,String)>]
91
- #
92
- attr_reader :params
93
-
94
- ##
95
- # An array of values for the given parameter name
96
- # @param key [String]
97
- # @return [Array<String>]
98
- #
99
- def param_values key
100
- key = key.downcase
101
- @params.inject([]) { |a, (k, v)| key == k ? a << v : a }
102
- end
103
-
104
- ##
105
- # The first value of the "charset" parameter, or nil if there is no
106
- # charset.
107
- # @return [String,nil]
108
- #
109
- def charset
110
- param_values("charset").first
111
- end
112
-
113
- ## @private
114
- def == other
115
- other.is_a?(ContentType) && canonical_string == other.canonical_string
116
- end
117
- alias eql? ==
118
-
119
- ## @private
120
- def hash
121
- canonical_string.hash
122
- end
123
-
124
- private
125
-
126
- def initialize_params sections
127
- params = sections.map do |s|
128
- k, v = s.split "="
129
- [k.strip.downcase, v.strip]
130
- end
131
- params.sort! do |(k1, v1), (k2, v2)|
132
- a = k1 <=> k2
133
- a.zero? ? v1 <=> v2 : a
134
- end
135
- params
136
- end
137
- end
138
- end
139
- end
@@ -1,42 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module FunctionsFramework
16
- module CloudEvents
17
- ##
18
- # Base class for all CloudEvents errors.
19
- #
20
- class CloudEventsError < ::RuntimeError
21
- end
22
-
23
- ##
24
- # Errors indicating unsupported or incorrectly formatted HTTP content or
25
- # headers.
26
- #
27
- class HttpContentError < CloudEventsError
28
- end
29
-
30
- ##
31
- # Errors indicating an unsupported or incorrect spec version.
32
- #
33
- class SpecVersionError < CloudEventsError
34
- end
35
-
36
- ##
37
- # Errors related to CloudEvent attributes.
38
- #
39
- class AttributeError < CloudEventsError
40
- end
41
- end
42
- end
@@ -1,79 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "date"
16
- require "uri"
17
-
18
- require "functions_framework/cloud_events/event/v1"
19
-
20
- module FunctionsFramework
21
- module CloudEvents
22
- ##
23
- # CloudEvent object.
24
- #
25
- # An Event object represents a complete event, including both its data and
26
- # its context attributes. The following are true of all event objects:
27
- #
28
- # * Event classes are defined within this module. For example, events
29
- # conforming to the CloudEvents 1.0 specification are of type
30
- # {FunctionsFramework::CloudEvents::Event::V1}.
31
- # * All event classes include this module, so you can use
32
- # `is_a? FunctionsFramework::CloudEvents::Event` to test whether an
33
- # object is an event.
34
- # * All event objects are immutable. Data and atribute values can be
35
- # retrieved but not modified. To "modify" an event, make a copy with
36
- # the desired changes. Generally, event classes will provide a helper
37
- # method for this purpose.
38
- # * All event objects have a `spec_version` method that returns the
39
- # version of the CloudEvents spec implemented by that event. (Other
40
- # methods may be different, depending on the spec version.)
41
- #
42
- # To create an event, you may either:
43
- #
44
- # * Construct an instance of the event class directly, for example by
45
- # calling {Event::V1.new} and passing a set of attributes.
46
- # * Call {Event.create} and pass a spec version and a set of attributes.
47
- # This will choose the appropriate event class based on the version.
48
- # * Decode an event from another representation. For example, use
49
- # {CloudEvents::JsonFormat} to decode an event from JSON, or use
50
- # {CloudEvents::HttpBinding} to decode an event from an HTTP request.
51
- #
52
- # See https://github.com/cloudevents/spec/blob/master/spec.md for more
53
- # information about CloudEvents.
54
- #
55
- module Event
56
- class << self
57
- ##
58
- # Create a new cloud event object with the given version. Generally,
59
- # you must also pass additional keyword arguments providing the event's
60
- # data and attributes. For example, if you pass `1.0` as the
61
- # `spec_version`, the remaining keyword arguments will be passed
62
- # through to the {Event::V1.new} constructor.
63
- #
64
- # @param spec_version [String] The required `specversion` field.
65
- # @param kwargs [keywords] Additional parameters for the event.
66
- #
67
- def create spec_version:, **kwargs
68
- case spec_version
69
- when /^1(\.|$)/
70
- V1.new spec_version: spec_version, **kwargs
71
- else
72
- raise SpecVersionError, "Unrecognized specversion: #{spec_version}"
73
- end
74
- end
75
- alias new create
76
- end
77
- end
78
- end
79
- end
@@ -1,363 +0,0 @@
1
- # Copyright 2020 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require "date"
16
- require "uri"
17
-
18
- module FunctionsFramework
19
- module CloudEvents
20
- module Event
21
- ##
22
- # A CloudEvents V1 data type.
23
- #
24
- # This object a complete CloudEvent, including the event data and its
25
- # context attributes. It supports the standard required and optional
26
- # attributes defined in CloudEvents V1, and arbitrary extension
27
- # attributes. All attribute values can be obtained (in their string form)
28
- # via the {Event::V1#[]} method. Additionally, standard attributes have
29
- # their own accessor methods that may return typed objects (such as
30
- # `DateTime` for the `time` attribute).
31
- #
32
- # This object is immutable. The data and attribute values can be
33
- # retrieved but not modified. To obtain an event with modifications, use
34
- # the {#with} method to create a copy with the desired changes.
35
- #
36
- # See https://github.com/cloudevents/spec/blob/master/spec.md for
37
- # descriptions of the standard attributes.
38
- #
39
- class V1
40
- include Event
41
-
42
- ##
43
- # Create a new cloud event object with the given data and attributes.
44
- #
45
- # Event attributes may be presented as keyword arguments, or as a Hash
46
- # passed in via the `attributes` argument (but not both).
47
- #
48
- # The following standard attributes are supported and exposed as
49
- # attribute methods on the object.
50
- #
51
- # * **:spec_version** (or **:specversion**) [`String`] - _required_ -
52
- # The CloudEvents spec version (i.e. the `specversion` field.)
53
- # * **:id** [`String`] - _required_ - The event `id` field.
54
- # * **:source** [`String`, `URI`] - _required_ - The event `source`
55
- # field.
56
- # * **:type** [`String`] - _required_ - The event `type` field.
57
- # * **:data** [`Object`] - _optional_ - The data associated with the
58
- # event (i.e. the `data` field.)
59
- # * **:data_content_type** (or **:datacontenttype**) [`String`,
60
- # {ContentType}] - _optional_ - The content-type for the data, if
61
- # the data is a string (i.e. the event `datacontenttype` field.)
62
- # * **:data_schema** (or **:dataschema**) [`String`, `URI`] -
63
- # _optional_ - The event `dataschema` field.
64
- # * **:subject** [`String`] - _optional_ - The event `subject` field.
65
- # * **:time** [`String`, `DateTime`, `Time`] - _optional_ - The
66
- # event `time` field.
67
- #
68
- # Any additional attributes are assumed to be extension attributes.
69
- # They are not available as separate methods, but can be accessed via
70
- # the {Event::V1#[]} operator.
71
- #
72
- # @param attributes [Hash] The data and attributes, as a hash.
73
- # @param args [keywords] The data and attributes, as keyword arguments.
74
- #
75
- def initialize attributes: nil, **args # rubocop:disable Metrics/AbcSize
76
- args = keys_to_strings(attributes || args)
77
- @attributes = {}
78
- @spec_version, _unused = interpret_string args, ["specversion", "spec_version"], required: true
79
- raise SpecVersionError, "Unrecognized specversion: #{@spec_version}" unless /^1(\.|$)/ =~ @spec_version
80
- @id, _unused = interpret_string args, ["id"], required: true
81
- @source, @source_string = interpret_uri args, ["source"], required: true
82
- @type, _unused = interpret_string args, ["type"], required: true
83
- @data, _unused = interpret_value args, ["data"], allow_nil: true
84
- @data_content_type, @data_content_type_string =
85
- interpret_content_type args, ["datacontenttype", "data_content_type"]
86
- @data_schema, @data_schema_string = interpret_uri args, ["dataschema", "data_schema"]
87
- @subject, _unused = interpret_string args, ["subject"]
88
- @time, @time_string = interpret_date_time args, ["time"]
89
- @attributes.merge! args
90
- end
91
-
92
- ##
93
- # Create and return a copy of this event with the given changes. See
94
- # the constructor for the parameters that can be passed. In general,
95
- # you can pass a new value for any attribute, or pass `nil` to remove
96
- # an optional attribute.
97
- #
98
- # @param changes [keywords] See {#initialize} for a list of arguments.
99
- # @return [FunctionFramework::CloudEvents::Event]
100
- #
101
- def with **changes
102
- attributes = @attributes.merge keys_to_strings changes
103
- V1.new attributes: attributes
104
- end
105
-
106
- ##
107
- # Return the value of the given named attribute. Both standard and
108
- # extension attributes are supported.
109
- #
110
- # Attribute names must be given as defined in the standard CloudEvents
111
- # specification. For example `specversion` rather than `spec_version`.
112
- #
113
- # Results are given in their "raw" form, generally a string. This may
114
- # be different from what is returned from corresponding attribute
115
- # methods. For example:
116
- #
117
- # event["time"] # => String rfc3339 representation
118
- # event.time # => DateTime object
119
- # event.time_string # => String rfc3339 representation
120
- #
121
- # @param key [String,Symbol] The attribute name.
122
- # @return [String,nil]
123
- #
124
- def [] key
125
- @attributes[key.to_s]
126
- end
127
-
128
- ##
129
- # Return a hash representation of this event.
130
- #
131
- # @return [Hash]
132
- #
133
- def to_h
134
- @attributes.dup
135
- end
136
-
137
- ##
138
- # The `id` field. Required.
139
- #
140
- # @return [String]
141
- #
142
- attr_reader :id
143
-
144
- ##
145
- # The `source` field as a `URI` object. Required.
146
- #
147
- # @return [URI]
148
- #
149
- attr_reader :source
150
-
151
- ##
152
- # The string representation of the `source` field. Required.
153
- #
154
- # @return [String]
155
- #
156
- attr_reader :source_string
157
-
158
- ##
159
- # The `type` field. Required.
160
- #
161
- # @return [String]
162
- #
163
- attr_reader :type
164
-
165
- ##
166
- # The `specversion` field. Required.
167
- #
168
- # @return [String]
169
- #
170
- attr_reader :spec_version
171
- alias specversion spec_version
172
-
173
- ##
174
- # The event-specific data, or `nil` if there is no data.
175
- #
176
- # Data may be one of the following types:
177
- # * Binary data, represented by a `String` using the `ASCII-8BIT`
178
- # encoding.
179
- # * A string in some other encoding such as `UTF-8` or `US-ASCII`.
180
- # * Any JSON data type, such as String, boolean, Integer, Array, or
181
- # Hash
182
- #
183
- # @return [Object]
184
- #
185
- attr_reader :data
186
-
187
- ##
188
- # The optional `datacontenttype` field as a
189
- # {FunctionsFramework::CloudEvents::ContentType} object, or `nil` if
190
- # the field is absent.
191
- #
192
- # @return [FunctionsFramework::CloudEvents::ContentType,nil]
193
- #
194
- attr_reader :data_content_type
195
- alias datacontenttype data_content_type
196
-
197
- ##
198
- # The string representation of the optional `datacontenttype` field, or
199
- # `nil` if the field is absent.
200
- #
201
- # @return [String,nil]
202
- #
203
- attr_reader :data_content_type_string
204
- alias datacontenttype_string data_content_type_string
205
-
206
- ##
207
- # The optional `dataschema` field as a `URI` object, or `nil` if the
208
- # field is absent.
209
- #
210
- # @return [URI,nil]
211
- #
212
- attr_reader :data_schema
213
- alias dataschema data_schema
214
-
215
- ##
216
- # The string representation of the optional `dataschema` field, or
217
- # `nil` if the field is absent.
218
- #
219
- # @return [String,nil]
220
- #
221
- attr_reader :data_schema_string
222
- alias dataschema_string data_schema_string
223
-
224
- ##
225
- # The optional `subject` field, or `nil` if the field is absent.
226
- #
227
- # @return [String,nil]
228
- #
229
- attr_reader :subject
230
-
231
- ##
232
- # The optional `time` field as a `DateTime` object, or `nil` if the
233
- # field is absent.
234
- #
235
- # @return [DateTime,nil]
236
- #
237
- attr_reader :time
238
-
239
- ##
240
- # The rfc3339 string representation of the optional `time` field, or
241
- # `nil` if the field is absent.
242
- #
243
- # @return [String,nil]
244
- #
245
- attr_reader :time_string
246
-
247
- ## @private
248
- def == other
249
- other.is_a?(V1) && @attributes == other.instance_variable_get(:@attributes)
250
- end
251
- alias eql? ==
252
-
253
- ## @private
254
- def hash
255
- @hash ||= @attributes.hash
256
- end
257
-
258
- private
259
-
260
- def keys_to_strings hash
261
- result = {}
262
- hash.each do |key, val|
263
- result[key.to_s] = val
264
- end
265
- result
266
- end
267
-
268
- def interpret_string args, keys, required: false
269
- interpret_value args, keys, required: required do |value|
270
- case value
271
- when ::String
272
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
273
- [value, value]
274
- else
275
- raise AttributeError, "Illegal type for #{keys.last}:" \
276
- " String expected but #{value.class} found"
277
- end
278
- end
279
- end
280
-
281
- def interpret_uri args, keys, required: false
282
- interpret_value args, keys, required: required do |value|
283
- case value
284
- when ::String
285
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
286
- begin
287
- [::URI.parse(value), value]
288
- rescue ::URI::InvalidURIError => e
289
- raise AttributeError, "Illegal format for #{keys.last}: #{e.message}"
290
- end
291
- when ::URI::Generic
292
- [value, value.to_s]
293
- else
294
- raise AttributeError, "Illegal type for #{keys.last}:" \
295
- " String or URI expected but #{value.class} found"
296
- end
297
- end
298
- end
299
-
300
- def interpret_date_time args, keys, required: false
301
- interpret_value args, keys, required: required do |value|
302
- case value
303
- when ::String
304
- begin
305
- [::DateTime.rfc3339(value), value]
306
- rescue ::Date::Error => e
307
- raise AttributeError, "Illegal format for #{keys.last}: #{e.message}"
308
- end
309
- when ::DateTime
310
- [value, value.rfc3339]
311
- when ::Time
312
- value = value.to_datetime
313
- [value, value.rfc3339]
314
- else
315
- raise AttributeError, "Illegal type for #{keys.last}:" \
316
- " String, Time, or DateTime expected but #{value.class} found"
317
- end
318
- end
319
- end
320
-
321
- def interpret_content_type args, keys, required: false
322
- interpret_value args, keys, required: required do |value|
323
- case value
324
- when ::String
325
- raise AttributeError, "The #{keys.last} field cannot be empty" if value.empty?
326
- [ContentType.new(value), value]
327
- when ContentType
328
- [value, value.to_s]
329
- else
330
- raise AttributeError, "Illegal type for #{keys.last}:" \
331
- " String, or ContentType expected but #{value.class} found"
332
- end
333
- end
334
- end
335
-
336
- def interpret_value args, keys, required: false, allow_nil: false
337
- value = nil
338
- found = false
339
- keys.each do |key|
340
- key_present = args.key? key
341
- val = args.delete key
342
- if allow_nil && key_present || !allow_nil && !val.nil?
343
- value = val
344
- found = true
345
- end
346
- end
347
- if found
348
- if block_given?
349
- converted, raw = yield value
350
- else
351
- converted = raw = value
352
- end
353
- @attributes[keys.first] = raw
354
- [converted, raw]
355
- else
356
- raise AttributeError, "The #{keys.last} field is required" if required
357
- [nil, nil]
358
- end
359
- end
360
- end
361
- end
362
- end
363
- end