teneo_microservice 1.0.1 → 1.0.2
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 +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +9 -0
- data/Rakefile +5 -0
- data/lib/teneo_microservice/client.rb +8 -2
- data/lib/teneo_microservice/error_classes/env_settings_error.rb +5 -2
- data/lib/teneo_microservice/error_classes/socket_format_error.rb +3 -1
- data/lib/teneo_microservice/grpc_services/cloud_event_enum.rb +9 -1
- data/lib/teneo_microservice/server.rb +20 -4
- data/lib/teneo_microservice/service_orchestrator.rb +46 -5
- data/lib/teneo_microservice/util/convert.rb +24 -1
- data/lib/teneo_microservice/util/env.rb +10 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ecd068ae3cca435b92e05c35c8a2a349d82856b3b1038aee477a3ccb3bfb2e2
|
4
|
+
data.tar.gz: e767f8644a5713da4dd802c35dd91732fa5f86bf76de0c93858ae3370136b016
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2576f33c60eb8a7cefa49d14ba1b21d20fc5642eedf9f767867ffb6ea6dbd89eeb150da8b5d86fa87adfca02b55587f6444753ffe7311c3d015bd0298eeabef
|
7
|
+
data.tar.gz: b09387f2744ae63ab8528a9746ee811758997d9045bb7d18eb6d59de2f84efbd345c1d6abec4ed1120c6129d2e7779671e97a06c10a84cec744d2a37db75d3f8
|
data/Gemfile
CHANGED
@@ -6,6 +6,8 @@ gem 'debug', require: false # requires libyaml-dev to be installed on system (Ub
|
|
6
6
|
gem 'dotenv', groups: %i[development test]
|
7
7
|
gem 'grpc'
|
8
8
|
gem 'grpc-tools'
|
9
|
+
gem 'hanna'
|
10
|
+
gem 'logging', '~> 2.4'
|
9
11
|
gem 'protobuf'
|
10
12
|
gem 'rake', '~> 13.0'
|
11
13
|
gem 'rspec', '~> 3.0'
|
data/Gemfile.lock
CHANGED
@@ -42,6 +42,8 @@ GEM
|
|
42
42
|
google-protobuf (>= 3.25, < 5.0)
|
43
43
|
googleapis-common-protos-types (~> 1.0)
|
44
44
|
grpc-tools (1.69.0)
|
45
|
+
hanna (1.5.0)
|
46
|
+
rdoc (>= 4)
|
45
47
|
i18n (1.14.7)
|
46
48
|
concurrent-ruby (~> 1.0)
|
47
49
|
io-console (0.8.0)
|
@@ -50,9 +52,14 @@ GEM
|
|
50
52
|
reline (>= 0.4.2)
|
51
53
|
json (2.9.1)
|
52
54
|
language_server-protocol (3.17.0.3)
|
55
|
+
little-plugger (1.1.4)
|
53
56
|
logger (1.6.5)
|
57
|
+
logging (2.4.0)
|
58
|
+
little-plugger (~> 1.1)
|
59
|
+
multi_json (~> 1.14)
|
54
60
|
middleware (0.1.0)
|
55
61
|
minitest (5.25.4)
|
62
|
+
multi_json (1.15.0)
|
56
63
|
mutex_m (0.3.0)
|
57
64
|
parallel (1.26.3)
|
58
65
|
parser (3.3.7.0)
|
@@ -121,6 +128,8 @@ DEPENDENCIES
|
|
121
128
|
dotenv
|
122
129
|
grpc
|
123
130
|
grpc-tools
|
131
|
+
hanna
|
132
|
+
logging (~> 2.4)
|
124
133
|
protobuf
|
125
134
|
rake (~> 13.0)
|
126
135
|
rspec (~> 3.0)
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'bundler/setup' # Required to use gems from local vendor dir
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
require 'rubocop/rake_task'
|
6
|
+
require 'rdoc/task'
|
6
7
|
|
7
8
|
Bundler::GemHelper.install_tasks
|
8
9
|
|
@@ -10,6 +11,10 @@ RSpec::Core::RakeTask.new(:spec)
|
|
10
11
|
|
11
12
|
RuboCop::RakeTask.new
|
12
13
|
|
14
|
+
RDoc::Task.new do |rdoc|
|
15
|
+
rdoc.generator = 'hanna'
|
16
|
+
end
|
17
|
+
|
13
18
|
task default: %w[spec rubocop]
|
14
19
|
|
15
20
|
task :proto do
|
@@ -5,9 +5,15 @@ require_relative 'util/convert'
|
|
5
5
|
require_relative 'grpc_services/cloud_event_enum'
|
6
6
|
require_relative 'proto/cloud_event_services_pb'
|
7
7
|
|
8
|
-
|
8
|
+
##
|
9
|
+
# This class represents a client that can communicate with a single gRPC endpoint.
|
9
10
|
class Client
|
10
|
-
|
11
|
+
##
|
12
|
+
# The remote endpoint this client is set to communicate with.
|
13
|
+
attr_accessor :socket
|
14
|
+
##
|
15
|
+
# The object through which Client communicates.
|
16
|
+
attr_accessor :stub
|
11
17
|
|
12
18
|
def initialize(socket:)
|
13
19
|
Env.valid_settings?
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
#
|
3
|
+
##
|
4
|
+
# This class represents an error that should get raised when the
|
5
|
+
# environment variables do not provide the required attributes.
|
6
|
+
#
|
7
|
+
# Thus indicating a faulty configuration.
|
5
8
|
class EnvSettingsError < StandardError
|
6
9
|
def initialize(msg = 'ERROR: invalid settings in .env file')
|
7
10
|
super(msg)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
##
|
4
|
+
# This class represents an error that should get raised when the
|
5
|
+
# socket string has an invalid format.
|
4
6
|
class SocketFormatError < StandardError
|
5
7
|
def initialize(msg = 'invalid socket')
|
6
8
|
super(msg)
|
@@ -4,12 +4,20 @@ require 'securerandom'
|
|
4
4
|
|
5
5
|
require_relative '../util/convert'
|
6
6
|
|
7
|
-
|
7
|
+
##
|
8
|
+
# This class represents a stream of CloudEvents.
|
9
|
+
#
|
10
|
+
# Such a stream is only used in cases where the CloudEvent proto-generated code
|
11
|
+
# requires a stream of CloudEvents in the method argument list and/or
|
12
|
+
# the return value.
|
8
13
|
class CloudEventEnum
|
9
14
|
def initialize(array:)
|
10
15
|
@array = array
|
11
16
|
end
|
12
17
|
|
18
|
+
##
|
19
|
+
# each makes this class enumerable by returning an enumerator of
|
20
|
+
# the data given at initialization converted as CloudEvents.
|
13
21
|
def each
|
14
22
|
return enum_for(:each) unless block_given?
|
15
23
|
|
@@ -4,18 +4,27 @@ require_relative 'client'
|
|
4
4
|
require_relative 'service_orchestrator'
|
5
5
|
require_relative 'util/env'
|
6
6
|
|
7
|
-
|
7
|
+
##
|
8
|
+
# This class encapsulates both a gRPC endpoint and a list of gRPC clients.
|
9
|
+
#
|
10
|
+
# This makes Server able to function as a gRPC server while also being able
|
11
|
+
# to communicate with other gRPC endpoints.
|
8
12
|
class Server
|
9
|
-
|
13
|
+
##
|
14
|
+
# The endpoint this server is listening to.
|
15
|
+
attr_accessor :socket
|
16
|
+
##
|
17
|
+
# A list of clients used for communicating with all registered remote hosts.
|
18
|
+
attr_accessor :clients
|
10
19
|
|
11
20
|
def initialize
|
12
21
|
Env.valid_settings?
|
13
22
|
|
14
23
|
@socket = "#{ENV["LISTEN_ADDRESS"]}:#{ENV["PORT"]}"
|
15
|
-
|
24
|
+
remote_hosts = ENV['REMOTE_HOSTS'].split('|') unless ENV['REMOTE_HOSTS'].nil?
|
16
25
|
|
17
26
|
@clients = []
|
18
|
-
|
27
|
+
remote_hosts&.each do |remote|
|
19
28
|
client = Client.new(socket: remote)
|
20
29
|
@clients.push(client)
|
21
30
|
end
|
@@ -24,10 +33,17 @@ class Server
|
|
24
33
|
@orchestrator.initialize_listener
|
25
34
|
end
|
26
35
|
|
36
|
+
##
|
37
|
+
# register_service registers a service to the gRPC server.
|
38
|
+
#
|
39
|
+
# A service provides the actual executable methods used for communication,
|
40
|
+
# and registering these to the server makes them available for implementation.
|
27
41
|
def register_service(service:)
|
28
42
|
@orchestrator.add(service)
|
29
43
|
end
|
30
44
|
|
45
|
+
##
|
46
|
+
# start_listening_for_data readies the server for accepting traffic.
|
31
47
|
def start_listening_for_data
|
32
48
|
@orchestrator.start
|
33
49
|
end
|
@@ -1,20 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'logging'
|
3
4
|
require 'grpc'
|
4
5
|
|
5
6
|
require_relative 'error_classes/socket_format_error'
|
6
7
|
|
7
|
-
|
8
|
+
module GRPC
|
9
|
+
extend Logging.globally
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# This class represents a gRPC endpoint with which clients can communicate.
|
8
14
|
class ServiceOrchestrator
|
15
|
+
##
|
16
|
+
# The endpoint this server is listening to.
|
9
17
|
attr_accessor :socket
|
10
18
|
|
11
19
|
def initialize(socket:)
|
12
20
|
@socket = socket
|
21
|
+
|
22
|
+
Logging.logger.root.appenders = Logging.appenders.stdout
|
23
|
+
Logging.logger.root.level = configured_log_level
|
13
24
|
end
|
14
25
|
|
15
|
-
|
16
|
-
|
26
|
+
##
|
27
|
+
# configured_log_level returns the correct token to be used to set the
|
28
|
+
# gRPC log level based on the configured setting.
|
29
|
+
def configured_log_level
|
30
|
+
error_level_hash = {
|
31
|
+
'DEBUG' => :debug,
|
32
|
+
'INFO' => :info,
|
33
|
+
'WARN' => :warn,
|
34
|
+
'ERROR' => :error,
|
35
|
+
'FATAL' => :fatal
|
36
|
+
}
|
17
37
|
|
38
|
+
return :info unless error_level_hash.key?(ENV['LOG_LEVEL'])
|
39
|
+
|
40
|
+
error_level_hash[ENV['LOG_LEVEL']]
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# initialize_listener creates a usable traffic listener.
|
45
|
+
#
|
46
|
+
# It does not yet accept data at this point.
|
47
|
+
def initialize_listener
|
18
48
|
raise SocketFormatError unless @socket =~ /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}:\d{1,5}$/
|
19
49
|
|
20
50
|
@listener = GRPC::RpcServer.new
|
@@ -22,25 +52,36 @@ class ServiceOrchestrator
|
|
22
52
|
GRPC.logger.info("... running insecurely on #{@socket}")
|
23
53
|
end
|
24
54
|
|
55
|
+
##
|
56
|
+
# add registers a service to the gRPC server.
|
57
|
+
#
|
58
|
+
# A service provides the actual executable methods used for communication,
|
59
|
+
# and registering these to the server makes them available for implementation.
|
25
60
|
def add(service)
|
26
61
|
@listener.handle(service)
|
27
62
|
end
|
28
63
|
|
64
|
+
##
|
65
|
+
# start readies the server for accepting traffic.
|
29
66
|
def start
|
30
|
-
puts "listening insecurely on #{@socket}"
|
31
67
|
@listener.run_till_terminated_or_interrupted([1, 'int', 'SIGQUIT'])
|
32
68
|
end
|
33
69
|
|
70
|
+
##
|
71
|
+
# wait_till_running halts the program until the listener is running.
|
34
72
|
def wait_till_running
|
35
73
|
@listener.wait_till_running
|
36
74
|
end
|
37
75
|
|
76
|
+
##
|
77
|
+
# running? returns whether the listener is accepting traffic or not.
|
38
78
|
def running?
|
39
79
|
@listener.running?
|
40
80
|
end
|
41
81
|
|
82
|
+
##
|
83
|
+
# stop makes the listener not accept traffic anymore.
|
42
84
|
def stop
|
43
|
-
puts 'shutting down gRPC server'
|
44
85
|
@listener.stop if running?
|
45
86
|
end
|
46
87
|
end
|
@@ -6,8 +6,22 @@ require 'securerandom'
|
|
6
6
|
require_relative '../proto/cloud_event_services_pb'
|
7
7
|
require_relative '../grpc_services/cloud_event_enum'
|
8
8
|
|
9
|
-
|
9
|
+
##
|
10
|
+
# This module provides functionality for custom data conversion.
|
10
11
|
module Convert
|
12
|
+
##
|
13
|
+
# json_to_cloudevent encapsulates the given JSON-string into a CloudEvent.
|
14
|
+
#
|
15
|
+
# Apart from the data, the generated CloudEvent is initialized with:
|
16
|
+
# - A random UUID
|
17
|
+
# - Source (based on config settings)
|
18
|
+
# - SpecVersion (based on config settings)
|
19
|
+
# - Type (based on config settings)
|
20
|
+
# - Attributes whiwh contain:
|
21
|
+
# ° Datacontenttype set to application/json
|
22
|
+
# ° Timestamp
|
23
|
+
#
|
24
|
+
# Returns an error if the provided data is not a valid JSON-string.
|
11
25
|
def self.json_to_cloudevent(data:)
|
12
26
|
raise JSON::ParserError, "invalid JSON: '#{data}'" unless valid_json?(json: data)
|
13
27
|
|
@@ -24,6 +38,10 @@ module Convert
|
|
24
38
|
)
|
25
39
|
end
|
26
40
|
|
41
|
+
##
|
42
|
+
# generate_attributes returns a hash of default attributes containing:
|
43
|
+
# - Datacontenttype set to application/json
|
44
|
+
# - Timestamp
|
27
45
|
def self.generate_attributes
|
28
46
|
now = Time.now
|
29
47
|
|
@@ -40,10 +58,15 @@ module Convert
|
|
40
58
|
}
|
41
59
|
end
|
42
60
|
|
61
|
+
##
|
62
|
+
# array_to_cloudevent_enum converts an array of JSON-strings to an
|
63
|
+
# enumerator of CloudEvents.
|
43
64
|
def self.array_to_cloudevent_enum(array:)
|
44
65
|
CloudEventEnum.new(array: array)
|
45
66
|
end
|
46
67
|
|
68
|
+
##
|
69
|
+
# valid_json? checks if the provided JSON-string is valid.
|
47
70
|
def self.valid_json?(json:)
|
48
71
|
JSON.parse(json)
|
49
72
|
true
|
@@ -5,8 +5,17 @@ require 'securerandom'
|
|
5
5
|
require_relative '../error_classes/env_settings_error'
|
6
6
|
require_relative '../error_classes/socket_format_error'
|
7
7
|
|
8
|
-
|
8
|
+
##
|
9
|
+
# This module provides functionality for working with env variable settings.
|
9
10
|
module Env
|
11
|
+
##
|
12
|
+
# valid_settings? checks if all mandatory settings are present within the
|
13
|
+
# available environment variables.
|
14
|
+
#
|
15
|
+
# Raises an EnvSettingsError is not all mandatory settings are found.
|
16
|
+
#
|
17
|
+
# Raises a SocketFormatError if the socket information in the environment
|
18
|
+
# variables is invalid.
|
10
19
|
def self.valid_settings?
|
11
20
|
mandatory_settings = %w[LISTEN_ADDRESS PORT CLOUDEVENTS_SPEC_VERSION CLOUDEVENTS_TYPE_PREFIX]
|
12
21
|
mandatory_settings.each do |setting|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: teneo_microservice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruben Vanoverschelde
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grpc
|