legionio 0.3.5 → 0.4.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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +136 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +94 -0
  6. data/CHANGELOG.md +37 -0
  7. data/Dockerfile +9 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +162 -0
  11. data/Rakefile +32 -0
  12. data/bitbucket-pipelines.yml +20 -0
  13. data/docker_deploy.rb +8 -0
  14. data/exe/legion +4 -0
  15. data/exe/legionio +53 -0
  16. data/exe/lex_gen +5 -0
  17. data/legionio.gemspec +64 -0
  18. data/lib/legion.rb +25 -0
  19. data/lib/legion/cli.rb +56 -0
  20. data/lib/legion/cli/chain.rb +35 -0
  21. data/lib/legion/cli/cohort.rb +10 -0
  22. data/lib/legion/cli/function.rb +41 -0
  23. data/lib/legion/cli/lex/actor.rb +31 -0
  24. data/lib/legion/cli/lex/exchange.rb +32 -0
  25. data/lib/legion/cli/lex/message.rb +32 -0
  26. data/lib/legion/cli/lex/queue.rb +45 -0
  27. data/lib/legion/cli/lex/runner.rb +70 -0
  28. data/lib/legion/cli/lex/templates/actor.erb +6 -0
  29. data/lib/legion/cli/lex/templates/actor_spec.erb +0 -0
  30. data/lib/legion/cli/lex/templates/base/bitbucket.yml.erb +69 -0
  31. data/lib/legion/cli/lex/templates/base/gemfile.erb +3 -0
  32. data/lib/legion/cli/lex/templates/base/gemspec.erb +26 -0
  33. data/lib/legion/cli/lex/templates/base/gitignore.erb +11 -0
  34. data/lib/legion/cli/lex/templates/base/lex.erb +9 -0
  35. data/lib/legion/cli/lex/templates/base/lex_spec.erb +5 -0
  36. data/lib/legion/cli/lex/templates/base/lic.erb +21 -0
  37. data/lib/legion/cli/lex/templates/base/rakefile.erb +6 -0
  38. data/lib/legion/cli/lex/templates/base/readme.md.erb +2 -0
  39. data/lib/legion/cli/lex/templates/base/rubocop.yml.erb +15 -0
  40. data/lib/legion/cli/lex/templates/base/spec_helper.rb.erb +11 -0
  41. data/lib/legion/cli/lex/templates/base/version.erb +7 -0
  42. data/lib/legion/cli/lex/templates/exchange.erb +11 -0
  43. data/lib/legion/cli/lex/templates/exchange_spec.erb +0 -0
  44. data/lib/legion/cli/lex/templates/message.erb +23 -0
  45. data/lib/legion/cli/lex/templates/message_spec.erb +0 -0
  46. data/lib/legion/cli/lex/templates/queue.erb +12 -0
  47. data/lib/legion/cli/lex/templates/queue_helper.erb +24 -0
  48. data/lib/legion/cli/lex/templates/queue_spec.erb +11 -0
  49. data/lib/legion/cli/lex/templates/runner.erb +11 -0
  50. data/lib/legion/cli/lex/templates/runner_spec.erb +11 -0
  51. data/lib/legion/cli/relationship.rb +22 -0
  52. data/lib/legion/cli/task.rb +49 -0
  53. data/lib/legion/cli/trigger.rb +88 -0
  54. data/lib/legion/cli/version.rb +5 -0
  55. data/lib/legion/extensions.rb +219 -0
  56. data/lib/legion/extensions/actors/base.rb +47 -0
  57. data/lib/legion/extensions/actors/every.rb +48 -0
  58. data/lib/legion/extensions/actors/loop.rb +32 -0
  59. data/lib/legion/extensions/actors/nothing.rb +15 -0
  60. data/lib/legion/extensions/actors/once.rb +40 -0
  61. data/lib/legion/extensions/actors/poll.rb +87 -0
  62. data/lib/legion/extensions/actors/subscription.rb +139 -0
  63. data/lib/legion/extensions/builders/actors.rb +61 -0
  64. data/lib/legion/extensions/builders/base.rb +36 -0
  65. data/lib/legion/extensions/builders/helpers.rb +24 -0
  66. data/lib/legion/extensions/builders/runners.rb +58 -0
  67. data/lib/legion/extensions/core.rb +131 -0
  68. data/lib/legion/extensions/data.rb +58 -0
  69. data/lib/legion/extensions/data/migrator.rb +28 -0
  70. data/lib/legion/extensions/data/model.rb +8 -0
  71. data/lib/legion/extensions/helpers/base.rb +82 -0
  72. data/lib/legion/extensions/helpers/cache.rb +23 -0
  73. data/lib/legion/extensions/helpers/core.rb +41 -0
  74. data/lib/legion/extensions/helpers/data.rb +23 -0
  75. data/lib/legion/extensions/helpers/lex.rb +48 -0
  76. data/lib/legion/extensions/helpers/logger.rb +44 -0
  77. data/lib/legion/extensions/helpers/task.rb +60 -0
  78. data/lib/legion/extensions/helpers/transport.rb +44 -0
  79. data/lib/legion/extensions/transport.rb +159 -0
  80. data/lib/legion/lex.rb +89 -0
  81. data/lib/legion/process.rb +124 -0
  82. data/lib/legion/runner.rb +55 -0
  83. data/lib/legion/runner/log.rb +10 -0
  84. data/lib/legion/runner/status.rb +69 -0
  85. data/lib/legion/service.rb +130 -0
  86. data/lib/legion/supervision.rb +15 -0
  87. data/lib/legion/version.rb +3 -0
  88. metadata +239 -38
@@ -0,0 +1,131 @@
1
+ require_relative 'builders/actors'
2
+ require_relative 'builders/helpers'
3
+ require_relative 'builders/runners'
4
+
5
+ require_relative 'helpers/core'
6
+ require_relative 'helpers/task'
7
+ require_relative 'helpers/logger'
8
+ require_relative 'helpers/lex'
9
+ require_relative 'helpers/transport'
10
+ require_relative 'helpers/data'
11
+ require_relative 'helpers/cache'
12
+
13
+ require_relative 'actors/base'
14
+ require_relative 'actors/every'
15
+ require_relative 'actors/loop'
16
+ require_relative 'actors/once'
17
+ require_relative 'actors/poll'
18
+ require_relative 'actors/subscription'
19
+ require_relative 'actors/nothing'
20
+
21
+ module Legion
22
+ module Extensions
23
+ module Core
24
+ include Legion::Extensions::Helpers::Transport
25
+ include Legion::Extensions::Helpers::Lex
26
+
27
+ include Legion::Extensions::Builder::Runners
28
+ include Legion::Extensions::Builder::Helpers
29
+ include Legion::Extensions::Builder::Actors
30
+
31
+ def autobuild
32
+ @actors = {}
33
+ @meta_actors = {}
34
+ @runners = {}
35
+ @helpers = []
36
+
37
+ @queues = {}
38
+ @exchanges = {}
39
+ @messages = {}
40
+ build_settings
41
+ build_transport
42
+ build_data if Legion::Settings[:data][:connected] && data_required?
43
+ build_helpers
44
+ build_runners
45
+ build_actors
46
+ end
47
+
48
+ def data_required?
49
+ false
50
+ end
51
+
52
+ def transport_required?
53
+ true
54
+ end
55
+
56
+ def cache_required?
57
+ false
58
+ end
59
+
60
+ def crypt_required?
61
+ false
62
+ end
63
+
64
+ def vault_required?
65
+ false
66
+ end
67
+
68
+ def build_data
69
+ auto_generate_data
70
+ lex_class::Data.build
71
+ end
72
+
73
+ def build_transport
74
+ if File.exist? "#{extension_path}/transport/autobuild.rb"
75
+ require "#{extension_path}/transport/autobuild"
76
+ extension_class::Transport::AutoBuild.build
77
+ log.warn 'still using transport::autobuild, please upgrade'
78
+ elsif File.exist? "#{extension_path}/transport.rb"
79
+ require "#{extension_path}/transport"
80
+ extension_class::Transport.build
81
+ else
82
+ auto_generate_transport
83
+ extension_class::Transport.build
84
+ end
85
+ end
86
+
87
+ def build_settings # rubocop:disable Metrics/AbcSize
88
+ if Legion::Settings[:extensions].key?(lex_name.to_sym)
89
+ Legion::Settings[:default_extension_settings].each do |key, value|
90
+ Legion::Settings[:extensions][lex_name.to_sym][key.to_sym] = if Legion::Settings[:extensions][lex_name.to_sym].key?(key.to_sym)
91
+ value.merge(Legion::Settings[:extensions][lex_name.to_sym][key.to_sym])
92
+ else
93
+ value
94
+ end
95
+ end
96
+ else
97
+ Legion::Settings[:extensions][lex_name.to_sym] = Legion::Settings[:default_extension_settings]
98
+ end
99
+
100
+ default_settings.each do |key, value|
101
+ Legion::Settings[:extensions][lex_name.to_sym][key.to_sym] = if Legion::Settings[:extensions][lex_name.to_sym].key?(key.to_sym)
102
+ value.merge(Legion::Settings[:extensions][lex_name.to_sym][key.to_sym])
103
+ else
104
+ value
105
+ end
106
+ end
107
+ end
108
+
109
+ def default_settings
110
+ {}
111
+ end
112
+
113
+ def auto_generate_transport
114
+ require 'legion/extensions/transport'
115
+ log.debug 'running meta magic to generate a transport base class'
116
+ return if Kernel.const_defined? "#{lex_class}::Transport"
117
+
118
+ Kernel.const_get(lex_class.to_s).const_set('Transport', Module.new { extend Legion::Extensions::Transport })
119
+ end
120
+
121
+ def auto_generate_data
122
+ require 'legion/extensions/data'
123
+ log.debug 'running meta magic to generate a data base class'
124
+ Kernel.const_get(lex_class.to_s).const_set('Data', Module.new { extend Legion::Extensions::Data })
125
+ rescue StandardError => e
126
+ log.error e.message
127
+ log.error e.backtrace
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,58 @@
1
+ require 'legion/extensions/data/migrator'
2
+ require 'legion/extensions/data/model'
3
+
4
+ module Legion
5
+ module Extensions
6
+ module Data
7
+ include Legion::Extensions::Helpers::Data
8
+ include Legion::Extensions::Helpers::Logger
9
+
10
+ def build
11
+ @models = []
12
+ @migrations = []
13
+ if Dir[File.expand_path("#{data_path}/migrations/*.rb")].count.positive?
14
+ log.debug('Has migrations, checking status')
15
+ run
16
+ end
17
+
18
+ models = Dir[File.expand_path("#{data_path}/models/*.rb")]
19
+ if models.count.positive?
20
+ log.debug('Including LEX models')
21
+ models.each do |file|
22
+ require file
23
+ end
24
+
25
+ models_class.constants.select do |model|
26
+ models_class.const_get(model).extend Legion::Extensions::Data::Model
27
+ end
28
+ end
29
+
30
+ true
31
+ end
32
+
33
+ def extension_model
34
+ Legion::Data::Model::Extension[namespace: lex_class.to_s]
35
+ end
36
+
37
+ def schema_version
38
+ extension_model.values[:schema_version]
39
+ end
40
+
41
+ def migrations_path
42
+ "#{data_path}/migrations/"
43
+ end
44
+
45
+ def migrate_class
46
+ @migrate_class ||= Legion::Extensions::Data::Migrator.new(migrations_path, lex_class.to_s)
47
+ end
48
+
49
+ def run
50
+ return true if migrate_class.is_current?
51
+
52
+ log.debug('Running LEX schema migrator')
53
+ results = migrate_class.run
54
+ extension_model.update(schema_version: results)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,28 @@
1
+ require 'sequel/extensions/migration'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Data
6
+ class Migrator < Sequel::IntegerMigrator
7
+ def initialize(path, extension, **)
8
+ @path = path
9
+ @extension = extension
10
+ super(Legion::Data::Connection.sequel, path)
11
+ end
12
+
13
+ def default_schema_column
14
+ :schema_version
15
+ end
16
+
17
+ def default_schema_table
18
+ :extensions
19
+ end
20
+
21
+ def schema_dataset
22
+ Legion::Data::Connection.sequel.from(default_schema_table).where(namespace: @extension)
23
+ end
24
+ alias ds schema_dataset
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ module Legion
2
+ module Extensions
3
+ module Data
4
+ module Model
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,82 @@
1
+ module Legion
2
+ module Extensions
3
+ module Helpers
4
+ module Base
5
+ def lex_class
6
+ @lex_class ||= Kernel.const_get(calling_class_array[0..2].join('::'))
7
+ end
8
+ alias extension_class lex_class
9
+
10
+ def lex_name
11
+ @lex_name ||= calling_class_array[2].gsub(/(?<!^)[A-Z]/) { "_#{Regexp.last_match(0)}" }.downcase
12
+ end
13
+ alias extension_name lex_name
14
+ alias lex_filename lex_name
15
+
16
+ def lex_const
17
+ @lex_const ||= calling_class_array[2]
18
+ end
19
+
20
+ def calling_class
21
+ @calling_class ||= respond_to?(:ancestors) ? ancestors.first : self.class
22
+ end
23
+
24
+ def calling_class_array
25
+ @calling_class_array ||= calling_class.to_s.split('::')
26
+ end
27
+
28
+ def actor_class
29
+ calling_class
30
+ end
31
+
32
+ def actor_name
33
+ @actor_name ||= calling_class_array.last.gsub(/(?<!^)[A-Z]/) { "_#{Regexp.last_match(0)}" }.downcase
34
+ end
35
+
36
+ def actor_const
37
+ @actor_const ||= calling_class_array.last
38
+ end
39
+
40
+ def runner_class
41
+ @runner_class ||= Kernel.const_get(actor_class.to_s.sub!('Actor', 'Runners'))
42
+ end
43
+
44
+ def runner_name
45
+ @runner_name ||= runner_class.to_s.split('::').last.gsub(/(?<!^)[A-Z]/) { "_#{Regexp.last_match(0)}" }.downcase
46
+ end
47
+
48
+ def runner_const
49
+ @runner_const ||= runner_class.to_s.split('::').last
50
+ end
51
+
52
+ def full_path
53
+ @full_path ||= "#{Gem::Specification.find_by_name("lex-#{lex_name}").gem_dir}/lib/legion/extensions/#{lex_filename}"
54
+ end
55
+ alias extension_path full_path
56
+
57
+ def from_json(string)
58
+ Legion::JSON.load(string)
59
+ end
60
+
61
+ def normalize(thing)
62
+ if thing.is_a? String
63
+ to_json(from_json(thing))
64
+ else
65
+ from_json(to_json(thing))
66
+ end
67
+ end
68
+
69
+ def to_dotted_hash(hash, recursive_key = '')
70
+ hash.each_with_object({}) do |(k, v), ret|
71
+ key = recursive_key + k.to_s
72
+ if v.is_a? Hash
73
+ ret.merge! to_dotted_hash(v, "#{key}.")
74
+ else
75
+ ret[key.to_sym] = v
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require 'legion/extensions/helpers/base'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Helpers
6
+ module Cache
7
+ include Legion::Extensions::Helpers::Base
8
+
9
+ def cache_namespace
10
+ @cache_namespace ||= lex_name
11
+ end
12
+
13
+ def cache_set(key, value, ttl: 60, **)
14
+ Legion::Cache.set(cache_namespace + key, value, ttl: ttl)
15
+ end
16
+
17
+ def cache_get(key)
18
+ Legion::Cache.get(cache_namespace + key)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ require_relative 'base'
2
+ module Legion
3
+ module Extensions
4
+ module Helpers
5
+ module Core
6
+ include Legion::Extensions::Helpers::Base
7
+
8
+ def settings
9
+ if Legion::Settings[:extensions].key?(lex_filename.to_sym)
10
+ Legion::Settings[:extensions][lex_filename.to_sym]
11
+ else
12
+ { logger: { level: 'info', extended: false, internal: false } }
13
+ end
14
+ end
15
+
16
+ # looks local, then in crypt, then settings, then cache, then env
17
+ def find_setting(name, **opts)
18
+ log.debug ".find_setting(#{name}) called"
19
+ return opts[name.to_sym] if opts.key? name.to_sym
20
+
21
+ string_name = "#{lex_name}_#{name.to_s.downcase}"
22
+ if Legion::Settings[:crypt][:vault][:connected] && Legion::Crypt.exist?(lex_name)
23
+ log.debug "looking for #{string_name} in Legion::Crypt"
24
+ crypt_result = Legion::Crypt.get(lex_name)
25
+ return crypt_result[name.to_sym] if crypt_result.is_a?(Hash) && crypt_result.key?(name.to_sym)
26
+ end
27
+ return settings[name.to_sym] if settings.key? name.to_sym
28
+
29
+ if Legion::Settings[:cache][:connected]
30
+ log.debug "looking for #{string_name} in Legion::Cache"
31
+ cache_result = Legion::Cache.get(string_name)
32
+ return cache_result unless cache_result.nil?
33
+ end
34
+
35
+ ENV[string_name] if ENV.key? string_name
36
+ nil
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require 'legion/extensions/helpers/base'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Helpers
6
+ module Data
7
+ include Legion::Extensions::Helpers::Base
8
+
9
+ def data_path
10
+ @data_path ||= "#{full_path}/data"
11
+ end
12
+
13
+ def data_class
14
+ @data_class ||= lex_class::Data
15
+ end
16
+
17
+ def models_class
18
+ @models_class ||= data_class::Model
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ module Legion
2
+ module Extensions
3
+ module Helpers
4
+ module Lex
5
+ include Legion::Extensions::Helpers::Core
6
+ include Legion::Extensions::Helpers::Logger
7
+
8
+ def function_example(function, example)
9
+ function_set(function, :example, example)
10
+ end
11
+
12
+ def function_options(function, options)
13
+ function_set(function, :options, options)
14
+ end
15
+
16
+ def function_desc(function, desc)
17
+ function_set(function, :desc, desc)
18
+ end
19
+
20
+ def function_set(function, key, value)
21
+ unless respond_to? function
22
+ log.debug "function_#{key} called but function doesn't exist, f: #{function}"
23
+ return nil
24
+ end
25
+ settings[:functions] = {} if settings[:functions].nil?
26
+ settings[:functions][function] = {} if settings[:functions][function].nil?
27
+ settings[:functions][function][key] = value
28
+ end
29
+
30
+ def runner_desc(desc)
31
+ settings[:runners] = {} if settings[:runners].nil?
32
+ settings[:runners][actor_name.to_sym] = {} if settings[:runners][actor_name.to_sym].nil?
33
+ settings[:runners][actor_name.to_sym][:desc] = desc
34
+ end
35
+
36
+ def self.included(base)
37
+ base.send :extend, Legion::Extensions::Helpers::Core if base.instance_of?(Class)
38
+ base.send :extend, Legion::Extensions::Helpers::Logger if base.instance_of?(Class)
39
+ base.extend base if base.instance_of?(Module)
40
+ end
41
+
42
+ def default_settings
43
+ { logger: { level: 'info' }, workers: 1, runners: {}, functions: {} }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end