functions_framework 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +201 -0
- data/README.md +218 -0
- data/bin/functions-framework +19 -0
- data/lib/functions_framework.rb +237 -0
- data/lib/functions_framework/cli.rb +113 -0
- data/lib/functions_framework/cloud_events.rb +143 -0
- data/lib/functions_framework/cloud_events/binary_content.rb +59 -0
- data/lib/functions_framework/cloud_events/content_type.rb +139 -0
- data/lib/functions_framework/cloud_events/event.rb +277 -0
- data/lib/functions_framework/cloud_events/json_structure.rb +88 -0
- data/lib/functions_framework/function.rb +75 -0
- data/lib/functions_framework/registry.rb +137 -0
- data/lib/functions_framework/server.rb +436 -0
- data/lib/functions_framework/testing.rb +244 -0
- data/lib/functions_framework/version.rb +21 -0
- metadata +187 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright 2020 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "functions_framework/cli"
|
18
|
+
|
19
|
+
::FunctionsFramework::CLI.new.parse_args(::ARGV).run
|
@@ -0,0 +1,237 @@
|
|
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 "logger"
|
16
|
+
|
17
|
+
require "functions_framework/cloud_events"
|
18
|
+
require "functions_framework/function"
|
19
|
+
require "functions_framework/registry"
|
20
|
+
require "functions_framework/version"
|
21
|
+
|
22
|
+
##
|
23
|
+
# The Functions Framework for Ruby.
|
24
|
+
#
|
25
|
+
# Functions Framework is an open source framework for writing lightweight,
|
26
|
+
# portable Ruby functions that run in a serverless environment. For general
|
27
|
+
# information about the Functions Framework, see
|
28
|
+
# https://github.com/GoogleCloudPlatform/functions-framework.
|
29
|
+
# To get started with the functions framework for Ruby, see
|
30
|
+
# https://github.com/GoogleCloudPlatform/functions-framework-ruby for basic
|
31
|
+
# examples.
|
32
|
+
#
|
33
|
+
# ## Inside the FunctionsFramework module
|
34
|
+
#
|
35
|
+
# The FunctionsFramework module includes the main entry points for the
|
36
|
+
# functions framework. Use the {FunctionsFramework.http},
|
37
|
+
# {FunctionsFramework.event}, or {FunctionsFramework.cloud_event} methods to
|
38
|
+
# define functions. To serve functions via a web service, invoke the
|
39
|
+
# `functions-framework` executable, or use the {FunctionsFramework.start} or
|
40
|
+
# {FunctionsFramework.run} methods.
|
41
|
+
#
|
42
|
+
# ## Internal modules
|
43
|
+
#
|
44
|
+
# Here is a roadmap to the internal modules in the Ruby functions framework.
|
45
|
+
#
|
46
|
+
# * {FunctionsFramework::CloudEvents} provides an implementation of the
|
47
|
+
# [CloudEvents](https://cloudevents.io) specification. In particular, if
|
48
|
+
# you define an event function, you will receive the event as a
|
49
|
+
# {FunctionsFramework::CloudEvents::Event} object.
|
50
|
+
# * {FunctionsFramework::CLI} is the implementation of the
|
51
|
+
# `functions-framework` executable. Most apps will not need to interact
|
52
|
+
# with this class directly.
|
53
|
+
# * {FunctionsFramework::Function} is the internal representation of a
|
54
|
+
# function, indicating the type of function (http or cloud event), the
|
55
|
+
# name of the function, and the block of code implementing it. Most apps
|
56
|
+
# do not need to interact with this class directly.
|
57
|
+
# * {FunctionsFramework::Registry} looks up functions by name. When you
|
58
|
+
# define a set of named functions, they are added to a registry, and when
|
59
|
+
# you start a server and specify the target function by name, it is looked
|
60
|
+
# up from the registry. Most apps do not need to interact with this class
|
61
|
+
# directly.
|
62
|
+
# * {FunctionsFramework::Server} is a web server that makes a function
|
63
|
+
# available via HTTP. It wraps the Puma web server and runs a specific
|
64
|
+
# {FunctionsFramework::Function}. Many apps can simply run the
|
65
|
+
# `functions-framework` executable to spin up a server. However, if you
|
66
|
+
# need closer control over your execution environment, you can use the
|
67
|
+
# {FunctionsFramework::Server} class to run a server. Note that, in most
|
68
|
+
# cases, it is easier to use the {FunctionsFramework.start} or
|
69
|
+
# {FunctionsFramework.run} wrapper methods rather than instantiate a
|
70
|
+
# {FunctionsFramework::Server} class directly.
|
71
|
+
# * {FunctionsFramework::Testing} provides helpers that are useful when
|
72
|
+
# writing unit tests for functions.
|
73
|
+
#
|
74
|
+
module FunctionsFramework
|
75
|
+
@global_registry = Registry.new
|
76
|
+
@logger = ::Logger.new ::STDERR
|
77
|
+
@logger.level = ::Logger::INFO
|
78
|
+
|
79
|
+
##
|
80
|
+
# The default target function name. If you define a function without
|
81
|
+
# specifying a name, or run the framework without giving a target, this name
|
82
|
+
# is used.
|
83
|
+
#
|
84
|
+
# @return [String]
|
85
|
+
#
|
86
|
+
DEFAULT_TARGET = "function".freeze
|
87
|
+
|
88
|
+
##
|
89
|
+
# The default source file path. The CLI loads functions from this file if no
|
90
|
+
# source file is given explicitly.
|
91
|
+
#
|
92
|
+
# @return [String]
|
93
|
+
#
|
94
|
+
DEFAULT_SOURCE = "./app.rb".freeze
|
95
|
+
|
96
|
+
class << self
|
97
|
+
##
|
98
|
+
# The "global" registry that holds events defined by the
|
99
|
+
# {FunctionsFramework} class methods.
|
100
|
+
#
|
101
|
+
# @return [FunctionsFramework::Registry]
|
102
|
+
#
|
103
|
+
attr_accessor :global_registry
|
104
|
+
|
105
|
+
##
|
106
|
+
# A "global" logger that is used by the framework's web server, and can
|
107
|
+
# also be used by functions.
|
108
|
+
#
|
109
|
+
# @return [Logger]
|
110
|
+
#
|
111
|
+
attr_accessor :logger
|
112
|
+
|
113
|
+
##
|
114
|
+
# Define a function that response to HTTP requests.
|
115
|
+
#
|
116
|
+
# You must provide a name for the function, and a block that implemets the
|
117
|
+
# function. The block should take a single `Rack::Request` argument. It
|
118
|
+
# should return one of the following:
|
119
|
+
# * A standard 3-element Rack response array. See
|
120
|
+
# https://github.com/rack/rack/blob/master/SPEC
|
121
|
+
# * A `Rack::Response` object.
|
122
|
+
# * A simple String that will be sent as the response body.
|
123
|
+
# * A Hash object that will be encoded as JSON and sent as the response
|
124
|
+
# body.
|
125
|
+
#
|
126
|
+
# ## Example
|
127
|
+
#
|
128
|
+
# FunctionsFramework.http "my-function" do |request|
|
129
|
+
# "I received a request for #{request.url}"
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# @param name [String] The function name. Defaults to {DEFAULT_TARGET}.
|
133
|
+
# @param block [Proc] The function code as a proc.
|
134
|
+
# @return [self]
|
135
|
+
#
|
136
|
+
def http name = DEFAULT_TARGET, &block
|
137
|
+
global_registry.add_http name, &block
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Define a function that responds to CloudEvents.
|
143
|
+
#
|
144
|
+
# You must provide a name for the function, and a block that implemets the
|
145
|
+
# function. The block should take two arguments: the event _data_ and the
|
146
|
+
# event _context_. Any return value is ignored.
|
147
|
+
#
|
148
|
+
# The event data argument will be one of the following types:
|
149
|
+
# * A `String` (with encoding `ASCII-8BIT`) if the data is in the form of
|
150
|
+
# binary data. You may choose to perform additional interpretation of
|
151
|
+
# the binary data using information in the content type provided by the
|
152
|
+
# context argument.
|
153
|
+
# * Any data type that can be represented in JSON (i.e. `String`,
|
154
|
+
# `Integer`, `Array`, `Hash`, `true`, `false`, or `nil`) if the event
|
155
|
+
# came with a JSON payload. The content type may also be set in the
|
156
|
+
# context if the data is a String.
|
157
|
+
#
|
158
|
+
# The context argument will be of type {FunctionsFramework::CloudEvents::Event},
|
159
|
+
# and will contain CloudEvents context attributes such as `id` and `type`.
|
160
|
+
#
|
161
|
+
# See also {FunctionsFramework.cloud_event} which defines a function that
|
162
|
+
# takes a single argument of type {FunctionsFramework::CloudEvents::Event}.
|
163
|
+
#
|
164
|
+
# ## Example
|
165
|
+
#
|
166
|
+
# FunctionsFramework.event "my-function" do |data, context|
|
167
|
+
# FunctionsFramework.logger.info "Event data: #{data.inspect}"
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# @param name [String] The function name. Defaults to {DEFAULT_TARGET}.
|
171
|
+
# @param block [Proc] The function code as a proc.
|
172
|
+
# @return [self]
|
173
|
+
#
|
174
|
+
def event name = DEFAULT_TARGET, &block
|
175
|
+
global_registry.add_event name, &block
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Define a function that responds to CloudEvents.
|
181
|
+
#
|
182
|
+
# You must provide a name for the function, and a block that implemets the
|
183
|
+
# function. The block should take _one_ argument: the event object of type
|
184
|
+
# {FunctionsFramework::CloudEvents::Event}. Any return value is ignored.
|
185
|
+
#
|
186
|
+
# See also {FunctionsFramework.event} which creates a function that takes
|
187
|
+
# data and context as separate arguments.
|
188
|
+
#
|
189
|
+
# ## Example
|
190
|
+
#
|
191
|
+
# FunctionsFramework.cloud_event "my-function" do |event|
|
192
|
+
# FunctionsFramework.logger.info "Event data: #{event.data.inspect}"
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# @param name [String] The function name. Defaults to {DEFAULT_TARGET}.
|
196
|
+
# @param block [Proc] The function code as a proc.
|
197
|
+
# @return [self]
|
198
|
+
#
|
199
|
+
def cloud_event name = DEFAULT_TARGET, &block
|
200
|
+
global_registry.add_cloud_event name, &block
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# Start the functions framework server in the background. The server will
|
206
|
+
# look up the given target function name in the global registry.
|
207
|
+
#
|
208
|
+
# @param target [String] The name of the function to run
|
209
|
+
# @yield [FunctionsFramework::Server::Config] A config object that can be
|
210
|
+
# manipulated to configure the server.
|
211
|
+
# @return [FunctionsFramework::Server]
|
212
|
+
#
|
213
|
+
def start target, &block
|
214
|
+
require "functions_framework/server"
|
215
|
+
function = global_registry[target]
|
216
|
+
raise ::ArgumentError, "Undefined function: #{target.inspect}" if function.nil?
|
217
|
+
server = Server.new function, &block
|
218
|
+
server.respond_to_signals
|
219
|
+
server.start
|
220
|
+
end
|
221
|
+
|
222
|
+
##
|
223
|
+
# Run the functions framework server and block until it stops. The server
|
224
|
+
# will look up the given target function name in the global registry.
|
225
|
+
#
|
226
|
+
# @param target [String] The name of the function to run
|
227
|
+
# @yield [FunctionsFramework::Server::Config] A config object that can be
|
228
|
+
# manipulated to configure the server.
|
229
|
+
# @return [self]
|
230
|
+
#
|
231
|
+
def run target, &block
|
232
|
+
server = start target, &block
|
233
|
+
server.wait_until_stopped
|
234
|
+
self
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,113 @@
|
|
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 "optparse"
|
16
|
+
|
17
|
+
require "functions_framework"
|
18
|
+
|
19
|
+
module FunctionsFramework
|
20
|
+
##
|
21
|
+
# Implementation of the functions-framework executable.
|
22
|
+
#
|
23
|
+
class CLI
|
24
|
+
##
|
25
|
+
# Create a new CLI, setting arguments to their defaults.
|
26
|
+
#
|
27
|
+
def initialize
|
28
|
+
@target = ::ENV["FUNCTION_TARGET"] || ::FunctionsFramework::DEFAULT_TARGET
|
29
|
+
@source = ::ENV["FUNCTION_SOURCE"] || ::FunctionsFramework::DEFAULT_SOURCE
|
30
|
+
@env = nil
|
31
|
+
@port = nil
|
32
|
+
@bind = nil
|
33
|
+
@min_threads = nil
|
34
|
+
@max_threads = nil
|
35
|
+
@detailed_errors = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Parse the given command line arguments.
|
40
|
+
# Exits if argument parsing failed.
|
41
|
+
#
|
42
|
+
# @param argv [Array<String>]
|
43
|
+
# @return [self]
|
44
|
+
#
|
45
|
+
def parse_args argv # rubocop:disable Metrics/MethodLength
|
46
|
+
option_parser = ::OptionParser.new do |op| # rubocop:disable Metrics/BlockLength
|
47
|
+
op.on "-t", "--target TARGET",
|
48
|
+
"Set the name of the function to execute (defaults to #{DEFAULT_TARGET})" do |val|
|
49
|
+
@target = val
|
50
|
+
end
|
51
|
+
op.on "-s", "--source SOURCE",
|
52
|
+
"Set the source file to load (defaults to #{DEFAULT_SOURCE})" do |val|
|
53
|
+
@source = val
|
54
|
+
end
|
55
|
+
op.on "-p", "--port PORT", "Set the port to listen to (defaults to 8080)" do |val|
|
56
|
+
@port = val.to_i
|
57
|
+
end
|
58
|
+
op.on "-b", "--bind BIND", "Set the address to bind to (defaults to 0.0.0.0)" do |val|
|
59
|
+
@bind = val
|
60
|
+
end
|
61
|
+
op.on "-e", "--environment ENV", "Set the Rack environment" do |val|
|
62
|
+
@env = val
|
63
|
+
end
|
64
|
+
op.on "--min-threads NUM", "Set the minimum threead pool size" do |val|
|
65
|
+
@min_threads = val
|
66
|
+
end
|
67
|
+
op.on "--max-threads NUM", "Set the maximum threead pool size" do |val|
|
68
|
+
@max_threads = val
|
69
|
+
end
|
70
|
+
op.on "--[no-]detailed-errors", "Set whether to show error details" do |val|
|
71
|
+
@detailed_errors = val
|
72
|
+
end
|
73
|
+
op.on "-v", "--verbose", "Increase log verbosity" do
|
74
|
+
::FunctionsFramework.logger.level -= 1
|
75
|
+
end
|
76
|
+
op.on "-q", "--quiet", "Decrease log verbosity" do
|
77
|
+
::FunctionsFramework.logger.level += 1
|
78
|
+
end
|
79
|
+
op.on "--help", "Display help" do
|
80
|
+
puts op
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
end
|
84
|
+
option_parser.parse! argv
|
85
|
+
unless argv.empty?
|
86
|
+
warn "Unrecognized arguments: #{argv}"
|
87
|
+
puts op
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Run the configured server, and block until it stops.
|
95
|
+
# @return [self]
|
96
|
+
#
|
97
|
+
def run
|
98
|
+
FunctionsFramework.logger.info \
|
99
|
+
"FunctionsFramework: Loading functions from #{@source.inspect}..."
|
100
|
+
load @source
|
101
|
+
server = ::FunctionsFramework.start @target do |config|
|
102
|
+
config.rack_env = @env
|
103
|
+
config.port = @port
|
104
|
+
config.bind_addr = @bind
|
105
|
+
config.show_error_details = @detailed_errors
|
106
|
+
config.min_threads = @min_threads
|
107
|
+
config.max_threads = @max_threads
|
108
|
+
end
|
109
|
+
server.wait_until_stopped
|
110
|
+
self
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,143 @@
|
|
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/binary_content"
|
16
|
+
require "functions_framework/cloud_events/content_type"
|
17
|
+
require "functions_framework/cloud_events/event"
|
18
|
+
|
19
|
+
module FunctionsFramework
|
20
|
+
##
|
21
|
+
# CloudEvents implementation.
|
22
|
+
#
|
23
|
+
# This is a Ruby implementation of the [CloudEvents](https://cloudevents.io)
|
24
|
+
# [1.0 specification](https://github.com/cloudevents/spec/blob/master/spec.md).
|
25
|
+
# It provides for unmarshaling of events from Rack environment data from
|
26
|
+
# binary (i.e. header-based) format, as well as structured (body-based) and
|
27
|
+
# batch formats. A standard JSON structure parser is included. It is also
|
28
|
+
# possible to register handlers for other formats.
|
29
|
+
#
|
30
|
+
# TODO: Unmarshaling of events is implemented, but marshaling is not.
|
31
|
+
#
|
32
|
+
module CloudEvents
|
33
|
+
@structured_formats = {}
|
34
|
+
@batched_formats = {}
|
35
|
+
|
36
|
+
class << self
|
37
|
+
##
|
38
|
+
# Register a handler for the given structured format.
|
39
|
+
# The handler object must respond to the method
|
40
|
+
# `#decode_structured_content`. See
|
41
|
+
# {FunctionsFramework::CloudEvents::JsonStructure} for an example.
|
42
|
+
#
|
43
|
+
# @param format [String] The subtype format that should be handled by
|
44
|
+
# this handler
|
45
|
+
# @param handler [#decode_structured_content] The handler object
|
46
|
+
# @return [self]
|
47
|
+
#
|
48
|
+
def register_structured_format format, handler
|
49
|
+
handlers = @structured_formats[format.to_s.strip.downcase] ||= []
|
50
|
+
handlers << handler unless handlers.include? handler
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Register a handler for the given batched format.
|
56
|
+
# The handler object must respond to the method
|
57
|
+
# `#decode_batched_content`. See
|
58
|
+
# {FunctionsFramework::CloudEvents::JsonStructure} for an example.
|
59
|
+
#
|
60
|
+
# @param format [String] The subtype format that should be handled by
|
61
|
+
# this handler
|
62
|
+
# @param handler [#decode_batched_content] The handler object
|
63
|
+
# @return [self]
|
64
|
+
#
|
65
|
+
def register_batched_format format, handler
|
66
|
+
handlers = @batched_formats[format.to_s.strip.downcase] ||= []
|
67
|
+
handlers << handler unless handlers.include? handler
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Decode an event from the given Rack environment hash. Following the
|
73
|
+
# CloudEvents spec, this chooses a handler based on the Content-Type of
|
74
|
+
# the request.
|
75
|
+
#
|
76
|
+
# @param env [Hash] The Rack environment
|
77
|
+
# @return [FunctionsFramework::CloudEvents::Event] if the request
|
78
|
+
# includes a single structured or binary event
|
79
|
+
# @return [Array<FunctionsFramework::CloudEvents::Event>] if the request
|
80
|
+
# includes a batch of structured events
|
81
|
+
#
|
82
|
+
def decode_rack_env env
|
83
|
+
content_type_header = env["CONTENT_TYPE"]
|
84
|
+
raise "Missing content-type header" unless content_type_header
|
85
|
+
content_type = ContentType.new content_type_header
|
86
|
+
if content_type.media_type == "application"
|
87
|
+
case content_type.subtype_prefix
|
88
|
+
when "cloudevents"
|
89
|
+
return decode_structured_content env["rack.input"], content_type
|
90
|
+
when "cloudevents-batch"
|
91
|
+
return decode_batched_content env["rack.input"], content_type
|
92
|
+
end
|
93
|
+
end
|
94
|
+
BinaryContent.decode_rack_env env, content_type
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Decode a single event from the given content data. This should be
|
99
|
+
# passed the request body, if the Content-Type is of the form
|
100
|
+
# `application/cloudevents+format`.
|
101
|
+
#
|
102
|
+
# @param input [IO] An IO-like object providing the content
|
103
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType] the
|
104
|
+
# content type
|
105
|
+
# @return [FunctionsFramework::CloudEvents::Event]
|
106
|
+
#
|
107
|
+
def decode_structured_content input, content_type
|
108
|
+
handlers = @structured_formats[content_type.subtype_format] || []
|
109
|
+
handlers.reverse_each do |handler|
|
110
|
+
event = handler.decode_structured_content input, content_type
|
111
|
+
return event if event
|
112
|
+
end
|
113
|
+
raise "Unknown cloudevents format: #{content_type.subtype_format.inspect}"
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Decode a batch of events from the given content data. This should be
|
118
|
+
# passed the request body, if the Content-Type is of the form
|
119
|
+
# `application/cloudevents-batch+format`.
|
120
|
+
#
|
121
|
+
# @param input [IO] An IO-like object providing the content
|
122
|
+
# @param content_type [FunctionsFramework::CloudEvents::ContentType] the
|
123
|
+
# content type
|
124
|
+
# @return [Array<FunctionsFramework::CloudEvents::Event>]
|
125
|
+
#
|
126
|
+
def decode_batched_content input, content_type
|
127
|
+
handlers = @batched_formats[content_type.subtype_format] || []
|
128
|
+
handlers.reverse_each do |handler|
|
129
|
+
events = handler.decode_batched_content input, content_type
|
130
|
+
return events if events
|
131
|
+
end
|
132
|
+
raise "Unknown cloudevents batch format: #{content_type.subtype_format.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
require "functions_framework/cloud_events/json_structure"
|
139
|
+
|
140
|
+
FunctionsFramework::CloudEvents.register_structured_format \
|
141
|
+
"json", FunctionsFramework::CloudEvents::JsonStructure
|
142
|
+
FunctionsFramework::CloudEvents.register_batched_format \
|
143
|
+
"json", FunctionsFramework::CloudEvents::JsonStructure
|