turbine_rb 0.1.0
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/.rspec +3 -0
- data/.rubocop.yml +38 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +121 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +3 -0
- data/README.md +223 -0
- data/Rakefile +12 -0
- data/bin/turbine-build +7 -0
- data/bin/turbine-function +7 -0
- data/bin/turbine-record +7 -0
- data/bin/turbine-run +7 -0
- data/lib/service_pb.rb +33 -0
- data/lib/service_services_pb.rb +26 -0
- data/lib/templates/Dockerfile +6 -0
- data/lib/templates/app/Gemfile +5 -0
- data/lib/templates/app/app.json +8 -0
- data/lib/templates/app/app.rb +56 -0
- data/lib/templates/app/fixtures/demo.json +9 -0
- data/lib/templates/app/ignoregit +0 -0
- data/lib/turbine_pb.rb +100 -0
- data/lib/turbine_rb/client.rb +108 -0
- data/lib/turbine_rb/collection_patch.rb +12 -0
- data/lib/turbine_rb/records.rb +129 -0
- data/lib/turbine_rb/version.rb +5 -0
- data/lib/turbine_rb.rb +117 -0
- data/lib/turbine_services_pb.rb +30 -0
- data/lib/validate/validate_pb.rb +3 -0
- data/sig/turbine_framework.rbs +4 -0
- metadata +112 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler/setup"
|
5
|
+
require "turbine_rb"
|
6
|
+
|
7
|
+
class MyApp
|
8
|
+
def call(app)
|
9
|
+
database = app.resource(name: "demopg")
|
10
|
+
|
11
|
+
# ELT pipeline example
|
12
|
+
# records = database.records(collection: 'events')
|
13
|
+
# database.write(records: records, collection: 'events_copy')
|
14
|
+
|
15
|
+
# procedural API
|
16
|
+
records = database.records(collection: "events")
|
17
|
+
|
18
|
+
# This register the secret to be available in the turbine application
|
19
|
+
app.register_secrets("MY_ENV_TEST")
|
20
|
+
|
21
|
+
# you can also register several secrets at once
|
22
|
+
# app.register_secrets(["MY_ENV_TEST", "MY_OTHER_ENV_TEST"])
|
23
|
+
|
24
|
+
# Passthrough just has to match the signature
|
25
|
+
processed_records = app.process(records: records, process: Passthrough.new)
|
26
|
+
database.write(records: processed_records, collection: "events_copy")
|
27
|
+
|
28
|
+
# out_records = processed_records.join(records, key: "user_id", window: 1.day) # stream joins
|
29
|
+
|
30
|
+
# chaining API
|
31
|
+
# database.records(collection: "events").
|
32
|
+
# process_with(process: Passthrough.new).
|
33
|
+
# write_to(resource: database, collection: "events_copy")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# might be useful to signal that this is a special Turbine call
|
38
|
+
class Passthrough < TurbineRb::Process
|
39
|
+
def call(records:)
|
40
|
+
puts "got records: #{records}"
|
41
|
+
# to get the value of unformatted records, use record .value getter method
|
42
|
+
# records.map { |r| puts r.value }
|
43
|
+
#
|
44
|
+
# to transform unformatted records, use record .value setter method
|
45
|
+
# records.map { |r| r.value = "newdata" }
|
46
|
+
#
|
47
|
+
# to get the value of json formatted records, use record .get method
|
48
|
+
# records.map { |r| puts r.get("message") }
|
49
|
+
#
|
50
|
+
# to transform json formatted records, use record .set methods
|
51
|
+
# records.map { |r| r.set('message', 'goodbye') }
|
52
|
+
records
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
TurbineRb.register(MyApp.new)
|
File without changes
|
data/lib/turbine_pb.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: turbine.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
require 'google/protobuf/empty_pb'
|
7
|
+
require 'google/protobuf/timestamp_pb'
|
8
|
+
require 'google/protobuf/wrappers_pb'
|
9
|
+
require 'validate/validate_pb'
|
10
|
+
|
11
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
12
|
+
add_file("turbine.proto", :syntax => :proto3) do
|
13
|
+
add_message "turbine_core.InitRequest" do
|
14
|
+
optional :appName, :string, 1
|
15
|
+
optional :configFilePath, :string, 2
|
16
|
+
optional :language, :enum, 3, "turbine_core.Language"
|
17
|
+
optional :gitSHA, :string, 4
|
18
|
+
optional :turbineVersion, :string, 5
|
19
|
+
end
|
20
|
+
add_message "turbine_core.GetResourceRequest" do
|
21
|
+
optional :name, :string, 1
|
22
|
+
end
|
23
|
+
add_message "turbine_core.Resource" do
|
24
|
+
optional :name, :string, 1
|
25
|
+
end
|
26
|
+
add_message "turbine_core.Collection" do
|
27
|
+
optional :name, :string, 1
|
28
|
+
optional :stream, :string, 2
|
29
|
+
repeated :records, :message, 3, "turbine_core.Record"
|
30
|
+
end
|
31
|
+
add_message "turbine_core.Record" do
|
32
|
+
optional :key, :string, 1
|
33
|
+
optional :value, :bytes, 2
|
34
|
+
optional :timestamp, :message, 3, "google.protobuf.Timestamp"
|
35
|
+
end
|
36
|
+
add_message "turbine_core.ReadCollectionRequest" do
|
37
|
+
optional :resource, :message, 1, "turbine_core.Resource"
|
38
|
+
optional :collection, :string, 2
|
39
|
+
optional :configs, :message, 3, "turbine_core.Configs"
|
40
|
+
end
|
41
|
+
add_message "turbine_core.WriteCollectionRequest" do
|
42
|
+
optional :resource, :message, 1, "turbine_core.Resource"
|
43
|
+
optional :sourceCollection, :message, 2, "turbine_core.Collection"
|
44
|
+
optional :targetCollection, :string, 3
|
45
|
+
optional :configs, :message, 4, "turbine_core.Configs"
|
46
|
+
end
|
47
|
+
add_message "turbine_core.Configs" do
|
48
|
+
repeated :config, :message, 1, "turbine_core.Config"
|
49
|
+
end
|
50
|
+
add_message "turbine_core.Config" do
|
51
|
+
optional :field, :string, 1
|
52
|
+
optional :value, :string, 2
|
53
|
+
end
|
54
|
+
add_message "turbine_core.ProcessCollectionRequest" do
|
55
|
+
optional :process, :message, 1, "turbine_core.ProcessCollectionRequest.Process"
|
56
|
+
optional :collection, :message, 2, "turbine_core.Collection"
|
57
|
+
end
|
58
|
+
add_message "turbine_core.ProcessCollectionRequest.Process" do
|
59
|
+
optional :name, :string, 1
|
60
|
+
end
|
61
|
+
add_message "turbine_core.Secret" do
|
62
|
+
optional :name, :string, 1
|
63
|
+
optional :value, :string, 2
|
64
|
+
end
|
65
|
+
add_message "turbine_core.ListResourcesResponse" do
|
66
|
+
repeated :resources, :message, 1, "turbine_core.Resource"
|
67
|
+
end
|
68
|
+
add_message "turbine_core.GetSpecRequest" do
|
69
|
+
optional :image, :string, 1
|
70
|
+
end
|
71
|
+
add_message "turbine_core.GetSpecResponse" do
|
72
|
+
optional :spec, :bytes, 1
|
73
|
+
end
|
74
|
+
add_enum "turbine_core.Language" do
|
75
|
+
value :GOLANG, 0
|
76
|
+
value :PYTHON, 1
|
77
|
+
value :JAVASCRIPT, 2
|
78
|
+
value :RUBY, 3
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module TurbineCore
|
84
|
+
InitRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.InitRequest").msgclass
|
85
|
+
GetResourceRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.GetResourceRequest").msgclass
|
86
|
+
Resource = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Resource").msgclass
|
87
|
+
Collection = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Collection").msgclass
|
88
|
+
Record = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Record").msgclass
|
89
|
+
ReadCollectionRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.ReadCollectionRequest").msgclass
|
90
|
+
WriteCollectionRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.WriteCollectionRequest").msgclass
|
91
|
+
Configs = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Configs").msgclass
|
92
|
+
Config = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Config").msgclass
|
93
|
+
ProcessCollectionRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.ProcessCollectionRequest").msgclass
|
94
|
+
ProcessCollectionRequest::Process = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.ProcessCollectionRequest.Process").msgclass
|
95
|
+
Secret = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Secret").msgclass
|
96
|
+
ListResourcesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.ListResourcesResponse").msgclass
|
97
|
+
GetSpecRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.GetSpecRequest").msgclass
|
98
|
+
GetSpecResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.GetSpecResponse").msgclass
|
99
|
+
Language = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("turbine_core.Language").enummodule
|
100
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TurbineRb
|
4
|
+
module Client
|
5
|
+
class MissingSecretError < StandardError; end
|
6
|
+
|
7
|
+
class App
|
8
|
+
attr_reader :core_server
|
9
|
+
|
10
|
+
def initialize(grpc_server, is_recording: false)
|
11
|
+
@core_server = grpc_server
|
12
|
+
@is_recording = is_recording
|
13
|
+
end
|
14
|
+
|
15
|
+
def resource(name:)
|
16
|
+
req = TurbineCore::GetResourceRequest.new(name: name)
|
17
|
+
res = @core_server.get_resource(req)
|
18
|
+
Resource.new(res, self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(records:, process:)
|
22
|
+
unwrapped_records = records.unwrap if records.instance_of?(Collection)
|
23
|
+
|
24
|
+
pr = TurbineCore::ProcessCollectionRequest::Process.new(
|
25
|
+
name: process.class.name
|
26
|
+
)
|
27
|
+
|
28
|
+
req = TurbineCore::ProcessCollectionRequest.new(collection: unwrapped_records, process: pr)
|
29
|
+
@core_server.add_process_to_collection(req)
|
30
|
+
records.pb_collection = process.call(records: records.pb_collection) unless @is_recording
|
31
|
+
|
32
|
+
records
|
33
|
+
end
|
34
|
+
|
35
|
+
# register_secrets accepts either a single string or an array of strings
|
36
|
+
def register_secrets(secrets)
|
37
|
+
[*secrets].map do |secret|
|
38
|
+
raise MissingSecretError, "secret #{secret} is not an environment variable" unless ENV.key?(secret)
|
39
|
+
|
40
|
+
req = TurbineCore::Secret.new(name: secret, value: ENV[secret])
|
41
|
+
@core_server.register_secret(req)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Resource
|
46
|
+
attr_reader :pb_resource
|
47
|
+
|
48
|
+
def initialize(res, app)
|
49
|
+
@pb_resource = res
|
50
|
+
@app = app
|
51
|
+
end
|
52
|
+
|
53
|
+
def records(collection:, configs: nil)
|
54
|
+
req = TurbineCore::ReadCollectionRequest.new(resource: @pb_resource, collection: collection)
|
55
|
+
if configs
|
56
|
+
pb_configs = configs.keys.map { |key| TurbineCore::Config.new(field: key, value: configs[key]) }
|
57
|
+
req.configs = TurbineCore::Configs.new(config: pb_configs)
|
58
|
+
end
|
59
|
+
|
60
|
+
@app.core_server.read_collection(req).wrap(@app) # wrap in Collection to enable chaining
|
61
|
+
end
|
62
|
+
|
63
|
+
def write(records:, collection:, configs: nil)
|
64
|
+
if records.instance_of?(Collection) # it has been processed by a function, so unwrap back to gRPC collection
|
65
|
+
records = records.unwrap
|
66
|
+
end
|
67
|
+
|
68
|
+
req = TurbineCore::WriteCollectionRequest.new(resource: @pb_resource, sourceCollection: records,
|
69
|
+
targetCollection: collection)
|
70
|
+
|
71
|
+
if configs
|
72
|
+
pb_configs = configs.keys.map { |key| TurbineCore::Config.new(field: key, value: configs[key]) }
|
73
|
+
req.configs = TurbineCore::Configs.new(config: pb_configs)
|
74
|
+
end
|
75
|
+
|
76
|
+
@app.core_server.write_collection_to_resource(req)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Collection
|
81
|
+
attr_accessor :pb_collection, :pb_stream, :name
|
82
|
+
|
83
|
+
def initialize(name, collection, stream, app)
|
84
|
+
@name = name
|
85
|
+
@pb_collection = collection
|
86
|
+
@pb_stream = stream
|
87
|
+
@app = app
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_to(resource:, collection:, configs: nil)
|
91
|
+
resource.write(records: self, collection: collection, configs: configs)
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_with(process:)
|
95
|
+
@app.process(records: self, process: process)
|
96
|
+
end
|
97
|
+
|
98
|
+
def unwrap
|
99
|
+
TurbineCore::Collection.new( # convert back to TurbineCore::Collection
|
100
|
+
name: name,
|
101
|
+
records: pb_collection.to_a,
|
102
|
+
stream: pb_stream
|
103
|
+
)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "hash_dot"
|
5
|
+
|
6
|
+
module TurbineRb
|
7
|
+
class Record
|
8
|
+
attr_accessor :key, :value, :timestamp
|
9
|
+
|
10
|
+
def initialize(pb_record)
|
11
|
+
@key = pb_record.key
|
12
|
+
@timestamp = pb_record.timestamp
|
13
|
+
|
14
|
+
begin
|
15
|
+
@value = JSON.parse(pb_record.value)
|
16
|
+
rescue JSON::ParserError
|
17
|
+
@value = pb_record.value
|
18
|
+
end
|
19
|
+
|
20
|
+
@value = @value.to_dot if value_hash?
|
21
|
+
end
|
22
|
+
|
23
|
+
def serialize
|
24
|
+
Io::Meroxa::Funtime::Record.new(key: @key, value: @value.to_json, timestamp: @timestamp)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(key)
|
28
|
+
if value_string? || value_array?
|
29
|
+
@value
|
30
|
+
elsif cdc_format?
|
31
|
+
@value.send("payload.after.#{key}")
|
32
|
+
else
|
33
|
+
@value.send("payload.#{key}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def set(key, value)
|
38
|
+
if !value_hash?
|
39
|
+
@value = value
|
40
|
+
else
|
41
|
+
payload_key = cdc_format? ? "payload.after" : "payload"
|
42
|
+
|
43
|
+
begin
|
44
|
+
@value.send("#{payload_key}.#{key}")
|
45
|
+
rescue NoMethodError
|
46
|
+
schema = @value.send("schema.fields")
|
47
|
+
new_schema_field = { field: key, optional: true, type: "string" }.to_dot
|
48
|
+
|
49
|
+
if cdc_format?
|
50
|
+
schema_fields = schema.find { |f| f.field == "after" }
|
51
|
+
schema_fields.fields.unshift(new_schema_field)
|
52
|
+
else
|
53
|
+
schema.unshift(new_schema_field)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
@value.send("#{payload_key}.#{key}=", value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def unwrap!
|
62
|
+
return unless cdc_format?
|
63
|
+
|
64
|
+
payload = @value.send("payload")
|
65
|
+
schema = @value.send("schema.fields")
|
66
|
+
schema_fields = schema.find { |f| f.field == "after" }
|
67
|
+
unless schema_fields.nil?
|
68
|
+
schema_fields.delete("field")
|
69
|
+
schema_fields.name = @value.send("schema.name")
|
70
|
+
@value.send("schema=", schema_fields)
|
71
|
+
end
|
72
|
+
|
73
|
+
@value.send("payload=", payload.after)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def value_string?
|
79
|
+
@value.is_a?(String)
|
80
|
+
end
|
81
|
+
|
82
|
+
def value_array?
|
83
|
+
@value.is_a?(Array)
|
84
|
+
end
|
85
|
+
|
86
|
+
def value_hash?
|
87
|
+
@value.is_a?(Hash)
|
88
|
+
end
|
89
|
+
|
90
|
+
def json_schema?
|
91
|
+
value_hash? &&
|
92
|
+
@value.key?("payload") &&
|
93
|
+
@value.key?("schema")
|
94
|
+
end
|
95
|
+
|
96
|
+
def cdc_format?
|
97
|
+
json_schema? &&
|
98
|
+
@value.payload.key?("source")
|
99
|
+
end
|
100
|
+
|
101
|
+
def type_of_value(value)
|
102
|
+
case value
|
103
|
+
when String
|
104
|
+
"string"
|
105
|
+
when Integer
|
106
|
+
"int32"
|
107
|
+
when Float
|
108
|
+
"float32"
|
109
|
+
when true, false
|
110
|
+
"boolean"
|
111
|
+
else
|
112
|
+
"unsupported"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class Records < SimpleDelegator
|
118
|
+
def initialize(pb_records)
|
119
|
+
super
|
120
|
+
records = pb_records.map { |r| Record.new(r) }
|
121
|
+
__setobj__(records)
|
122
|
+
end
|
123
|
+
|
124
|
+
def unwrap!
|
125
|
+
records = __getobj__
|
126
|
+
records.each(&:unwrap!)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/turbine_rb.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "service_services_pb"
|
4
|
+
require "turbine_services_pb"
|
5
|
+
|
6
|
+
require "turbine_rb/collection_patch"
|
7
|
+
require "turbine_rb/version"
|
8
|
+
require "turbine_rb/client"
|
9
|
+
require "turbine_rb/records"
|
10
|
+
|
11
|
+
require "optparse"
|
12
|
+
require "fileutils"
|
13
|
+
|
14
|
+
require "grpc"
|
15
|
+
require "grpc/health/v1/health_pb"
|
16
|
+
require "grpc/health/checker"
|
17
|
+
|
18
|
+
module TurbineRb
|
19
|
+
class Error < StandardError; end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_reader :app, :process_klass
|
23
|
+
|
24
|
+
def register(app)
|
25
|
+
@app = app
|
26
|
+
end
|
27
|
+
|
28
|
+
def register_fn(fn_klass)
|
29
|
+
@process_klass = fn_klass
|
30
|
+
end
|
31
|
+
|
32
|
+
def serve
|
33
|
+
process_function = @process_klass.new
|
34
|
+
process_function_impl = ProcessImpl.new(process_function)
|
35
|
+
function_addr = ENV["MEROXA_FUNCTION_ADDR"] ||= "0.0.0.0:50500"
|
36
|
+
|
37
|
+
@grpc_server = GRPC::RpcServer.new
|
38
|
+
@grpc_server.add_http2_port(function_addr, :this_port_is_insecure)
|
39
|
+
@grpc_server.handle(process_function_impl)
|
40
|
+
@grpc_server.handle(HealthCheck)
|
41
|
+
puts "serving function #{process_function.class.name} on #{function_addr}"
|
42
|
+
@grpc_server.run_till_terminated_or_interrupted([1, "int", "SIGQUIT"])
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
app = TurbineRb::Client::App.new(init_core_server)
|
47
|
+
TurbineRb.app.call(app)
|
48
|
+
end
|
49
|
+
|
50
|
+
def record
|
51
|
+
app = TurbineRb::Client::App.new(init_core_server, is_recording: true)
|
52
|
+
TurbineRb.app.call(app)
|
53
|
+
end
|
54
|
+
|
55
|
+
def build
|
56
|
+
docker_file = File.join(__dir__, "templates", "Dockerfile")
|
57
|
+
dest_app = Dir.getwd
|
58
|
+
FileUtils.cp(docker_file, dest_app)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def init_core_server
|
64
|
+
# TODO: figure out what the deal is with :this_channel_is_insecure
|
65
|
+
core_server = TurbineCore::TurbineService::Stub.new(ENV["TURBINE_CORE_SERVER"], :this_channel_is_insecure)
|
66
|
+
git_sha = ARGV[0]
|
67
|
+
|
68
|
+
req = TurbineCore::InitRequest.new(
|
69
|
+
appName: app.class.name,
|
70
|
+
configFilePath: Dir.getwd,
|
71
|
+
language: :RUBY,
|
72
|
+
gitSHA: git_sha,
|
73
|
+
turbineVersion: Gem.loaded_specs["turbine_rb"].version.version
|
74
|
+
)
|
75
|
+
|
76
|
+
core_server.init(req)
|
77
|
+
core_server
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class ProcessImpl < Io::Meroxa::Funtime::Function::Service
|
82
|
+
def initialize(process)
|
83
|
+
@process = process
|
84
|
+
super()
|
85
|
+
end
|
86
|
+
|
87
|
+
def process(request, _call)
|
88
|
+
records = TurbineRb::Records.new(request.records)
|
89
|
+
|
90
|
+
# records are processed but not in proto format
|
91
|
+
processed_records = @process.call(records: records)
|
92
|
+
|
93
|
+
# to proto
|
94
|
+
serialized_records = processed_records.map(&:serialize)
|
95
|
+
|
96
|
+
Io::Meroxa::Funtime::ProcessRecordResponse.new(records: serialized_records)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Process
|
101
|
+
def self.inherited(subclass)
|
102
|
+
TurbineRb.register_fn(subclass)
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class HealthCheck < Grpc::Health::V1::Health::Service
|
108
|
+
def check(req, req_view)
|
109
|
+
checker = Grpc::Health::Checker.new
|
110
|
+
checker.set_status_for_services(
|
111
|
+
Grpc::Health::V1::HealthCheckResponse::ServingStatus::SERVING,
|
112
|
+
"function"
|
113
|
+
)
|
114
|
+
checker.check(req, req_view)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# Source: turbine.proto for package 'turbine_core'
|
3
|
+
|
4
|
+
require 'grpc'
|
5
|
+
require 'turbine_pb'
|
6
|
+
|
7
|
+
module TurbineCore
|
8
|
+
module TurbineService
|
9
|
+
class Service
|
10
|
+
|
11
|
+
include ::GRPC::GenericService
|
12
|
+
|
13
|
+
self.marshal_class_method = :encode
|
14
|
+
self.unmarshal_class_method = :decode
|
15
|
+
self.service_name = 'turbine_core.TurbineService'
|
16
|
+
|
17
|
+
rpc :Init, ::TurbineCore::InitRequest, ::Google::Protobuf::Empty
|
18
|
+
rpc :GetResource, ::TurbineCore::GetResourceRequest, ::TurbineCore::Resource
|
19
|
+
rpc :ReadCollection, ::TurbineCore::ReadCollectionRequest, ::TurbineCore::Collection
|
20
|
+
rpc :WriteCollectionToResource, ::TurbineCore::WriteCollectionRequest, ::Google::Protobuf::Empty
|
21
|
+
rpc :AddProcessToCollection, ::TurbineCore::ProcessCollectionRequest, ::TurbineCore::Collection
|
22
|
+
rpc :RegisterSecret, ::TurbineCore::Secret, ::Google::Protobuf::Empty
|
23
|
+
rpc :HasFunctions, ::Google::Protobuf::Empty, ::Google::Protobuf::BoolValue
|
24
|
+
rpc :ListResources, ::Google::Protobuf::Empty, ::TurbineCore::ListResourcesResponse
|
25
|
+
rpc :GetSpec, ::TurbineCore::GetSpecRequest, ::TurbineCore::GetSpecResponse
|
26
|
+
end
|
27
|
+
|
28
|
+
Stub = Service.rpc_stub_class
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: turbine_rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Meroxa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: grpc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.48'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.48'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hash_dot
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.5.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.5.0
|
41
|
+
description: |
|
42
|
+
Turbine is a data application framework for building
|
43
|
+
server-side applications that are event-driven,
|
44
|
+
respond to data in real-time, and scale using cloud-native best practices
|
45
|
+
email:
|
46
|
+
- production@meroxa.io
|
47
|
+
executables:
|
48
|
+
- turbine-function
|
49
|
+
- turbine-build
|
50
|
+
- turbine-record
|
51
|
+
- turbine-run
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- ".rspec"
|
56
|
+
- ".rubocop.yml"
|
57
|
+
- CHANGELOG.md
|
58
|
+
- CODE_OF_CONDUCT.md
|
59
|
+
- Gemfile
|
60
|
+
- Gemfile.lock
|
61
|
+
- Guardfile
|
62
|
+
- LICENSE.txt
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- bin/turbine-build
|
66
|
+
- bin/turbine-function
|
67
|
+
- bin/turbine-record
|
68
|
+
- bin/turbine-run
|
69
|
+
- lib/service_pb.rb
|
70
|
+
- lib/service_services_pb.rb
|
71
|
+
- lib/templates/Dockerfile
|
72
|
+
- lib/templates/app/Gemfile
|
73
|
+
- lib/templates/app/app.json
|
74
|
+
- lib/templates/app/app.rb
|
75
|
+
- lib/templates/app/fixtures/demo.json
|
76
|
+
- lib/templates/app/ignoregit
|
77
|
+
- lib/turbine_pb.rb
|
78
|
+
- lib/turbine_rb.rb
|
79
|
+
- lib/turbine_rb/client.rb
|
80
|
+
- lib/turbine_rb/collection_patch.rb
|
81
|
+
- lib/turbine_rb/records.rb
|
82
|
+
- lib/turbine_rb/version.rb
|
83
|
+
- lib/turbine_services_pb.rb
|
84
|
+
- lib/validate/validate_pb.rb
|
85
|
+
- sig/turbine_framework.rbs
|
86
|
+
homepage: https://github.com/meroxa/turbine-core/tree/main/lib/ruby/turbine_rb
|
87
|
+
licenses:
|
88
|
+
- LicenseRef-LICENSE.txt
|
89
|
+
metadata:
|
90
|
+
homepage_uri: https://github.com/meroxa/turbine-core/tree/main/lib/ruby/turbine_rb
|
91
|
+
source_code_uri: https://github.com/meroxa/turbine-core
|
92
|
+
changelog_uri: https://github.com/meroxa/turbine-core
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.6.0
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubygems_version: 3.3.7
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Meroxa data application framework for Ruby
|
112
|
+
test_files: []
|