turbine_rb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|