legionio 0.3.5 → 1.2.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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +45 -0
  3. data/.github/workflows/rubocop.yml +28 -0
  4. data/.github/workflows/sourcehawk-scan.yml +20 -0
  5. data/.gitignore +15 -0
  6. data/.rubocop.yml +90 -0
  7. data/CHANGELOG.md +4 -0
  8. data/CODE_OF_CONDUCT.md +75 -0
  9. data/CONTRIBUTING.md +55 -0
  10. data/Dockerfile +9 -0
  11. data/Gemfile +10 -0
  12. data/INDIVIDUAL_CONTRIBUTOR_LICENSE.md +30 -0
  13. data/LICENSE +201 -0
  14. data/NOTICE.txt +9 -0
  15. data/README.md +162 -0
  16. data/SECURITY.md +9 -0
  17. data/attribution.txt +1 -0
  18. data/docker_deploy.rb +10 -0
  19. data/exe/legion +4 -0
  20. data/exe/legionio +53 -0
  21. data/exe/lex_gen +5 -0
  22. data/legionio.gemspec +53 -0
  23. data/lib/legion.rb +24 -0
  24. data/lib/legion/cli.rb +56 -0
  25. data/lib/legion/cli/chain.rb +35 -0
  26. data/lib/legion/cli/cohort.rb +10 -0
  27. data/lib/legion/cli/function.rb +41 -0
  28. data/lib/legion/cli/lex/actor.rb +31 -0
  29. data/lib/legion/cli/lex/exchange.rb +32 -0
  30. data/lib/legion/cli/lex/message.rb +32 -0
  31. data/lib/legion/cli/lex/queue.rb +45 -0
  32. data/lib/legion/cli/lex/runner.rb +70 -0
  33. data/lib/legion/cli/lex/templates/actor.erb +6 -0
  34. data/lib/legion/cli/lex/templates/actor_spec.erb +0 -0
  35. data/lib/legion/cli/lex/templates/base/bitbucket.yml.erb +69 -0
  36. data/lib/legion/cli/lex/templates/base/gemfile.erb +3 -0
  37. data/lib/legion/cli/lex/templates/base/gemspec.erb +26 -0
  38. data/lib/legion/cli/lex/templates/base/gitignore.erb +11 -0
  39. data/lib/legion/cli/lex/templates/base/lex.erb +9 -0
  40. data/lib/legion/cli/lex/templates/base/lex_spec.erb +5 -0
  41. data/lib/legion/cli/lex/templates/base/lic.erb +21 -0
  42. data/lib/legion/cli/lex/templates/base/rakefile.erb +6 -0
  43. data/lib/legion/cli/lex/templates/base/readme.md.erb +2 -0
  44. data/lib/legion/cli/lex/templates/base/rubocop.yml.erb +15 -0
  45. data/lib/legion/cli/lex/templates/base/spec_helper.rb.erb +11 -0
  46. data/lib/legion/cli/lex/templates/base/version.erb +7 -0
  47. data/lib/legion/cli/lex/templates/exchange.erb +11 -0
  48. data/lib/legion/cli/lex/templates/exchange_spec.erb +0 -0
  49. data/lib/legion/cli/lex/templates/message.erb +23 -0
  50. data/lib/legion/cli/lex/templates/message_spec.erb +0 -0
  51. data/lib/legion/cli/lex/templates/queue.erb +12 -0
  52. data/lib/legion/cli/lex/templates/queue_helper.erb +24 -0
  53. data/lib/legion/cli/lex/templates/queue_spec.erb +11 -0
  54. data/lib/legion/cli/lex/templates/runner.erb +11 -0
  55. data/lib/legion/cli/lex/templates/runner_spec.erb +11 -0
  56. data/lib/legion/cli/relationship.rb +22 -0
  57. data/lib/legion/cli/task.rb +49 -0
  58. data/lib/legion/cli/trigger.rb +88 -0
  59. data/lib/legion/cli/version.rb +5 -0
  60. data/lib/legion/extensions.rb +229 -0
  61. data/lib/legion/extensions/actors/base.rb +47 -0
  62. data/lib/legion/extensions/actors/defaults.rb +28 -0
  63. data/lib/legion/extensions/actors/every.rb +48 -0
  64. data/lib/legion/extensions/actors/loop.rb +32 -0
  65. data/lib/legion/extensions/actors/nothing.rb +15 -0
  66. data/lib/legion/extensions/actors/once.rb +40 -0
  67. data/lib/legion/extensions/actors/poll.rb +87 -0
  68. data/lib/legion/extensions/actors/subscription.rb +139 -0
  69. data/lib/legion/extensions/builders/actors.rb +61 -0
  70. data/lib/legion/extensions/builders/base.rb +36 -0
  71. data/lib/legion/extensions/builders/helpers.rb +24 -0
  72. data/lib/legion/extensions/builders/runners.rb +62 -0
  73. data/lib/legion/extensions/core.rb +131 -0
  74. data/lib/legion/extensions/data.rb +61 -0
  75. data/lib/legion/extensions/data/migrator.rb +33 -0
  76. data/lib/legion/extensions/data/model.rb +8 -0
  77. data/lib/legion/extensions/helpers/base.rb +82 -0
  78. data/lib/legion/extensions/helpers/cache.rb +23 -0
  79. data/lib/legion/extensions/helpers/core.rb +41 -0
  80. data/lib/legion/extensions/helpers/data.rb +23 -0
  81. data/lib/legion/extensions/helpers/lex.rb +48 -0
  82. data/lib/legion/extensions/helpers/logger.rb +44 -0
  83. data/lib/legion/extensions/helpers/task.rb +60 -0
  84. data/lib/legion/extensions/helpers/transport.rb +44 -0
  85. data/lib/legion/extensions/transport.rb +159 -0
  86. data/lib/legion/lex.rb +89 -0
  87. data/lib/legion/process.rb +124 -0
  88. data/lib/legion/runner.rb +57 -0
  89. data/lib/legion/runner/log.rb +10 -0
  90. data/lib/legion/runner/status.rb +69 -0
  91. data/lib/legion/service.rb +130 -0
  92. data/lib/legion/supervision.rb +15 -0
  93. data/lib/legion/version.rb +3 -0
  94. data/sourcehawk.yml +4 -0
  95. metadata +142 -168
@@ -0,0 +1,61 @@
1
+ require_relative 'base'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Builder
6
+ module Actors
7
+ include Legion::Extensions::Builder::Base
8
+
9
+ attr_reader :actors
10
+
11
+ def build_actors
12
+ @actors = {}
13
+ require_files(actor_files)
14
+ build_actor_list
15
+ build_meta_actor_list
16
+ end
17
+
18
+ def build_actor_list
19
+ actor_files.each do |file|
20
+ actor_name = file.split('/').last.sub('.rb', '')
21
+ actor_class = "#{lex_class}::Actor::#{actor_name.split('_').collect(&:capitalize).join}"
22
+ @actors[actor_name.to_sym] = {
23
+ extension: lex_class.to_s.downcase,
24
+ extension_name: extension_name,
25
+ actor_name: actor_name,
26
+ actor_class: Kernel.const_get(actor_class),
27
+ type: 'literal'
28
+ }
29
+ end
30
+ end
31
+
32
+ def build_meta_actor_list
33
+ @runners.each do |runner, attr|
34
+ next if @actors[runner.to_sym].is_a? Hash
35
+
36
+ actor_class = "#{attr[:extension_class]}::Actor::#{runner.to_s.split('_').collect(&:capitalize).join}"
37
+ build_meta_actor(runner, attr) unless Kernel.const_defined? actor_class
38
+ @actors[runner.to_sym] = {
39
+ extension: attr[:extension],
40
+ extension_name: attr[:extension_name],
41
+ actor_name: attr[:runner_name],
42
+ actor_class: Kernel.const_get(actor_class),
43
+ type: 'meta'
44
+ }
45
+ end
46
+ end
47
+
48
+ def build_meta_actor(runner, attr)
49
+ define_constant_two('Actor', root: lex_class)
50
+
51
+ Kernel.const_get("#{attr[:extension_class]}::Actor")
52
+ .const_set(runner.to_s.split('_').collect(&:capitalize).join, Class.new(Legion::Extensions::Actors::Subscription))
53
+ end
54
+
55
+ def actor_files
56
+ @actor_files ||= find_files('actors')
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ module Legion
2
+ module Extensions
3
+ module Builder
4
+ module Base
5
+ def find_files(name, path = extension_path)
6
+ files = []
7
+ return files unless Dir.exist? "#{path}/#{name}"
8
+
9
+ Dir["#{path}/#{name}/*.rb"].each do |file|
10
+ files.push(file)
11
+ end
12
+ files
13
+ end
14
+
15
+ def require_files(files)
16
+ files.each { |file| require file }
17
+ end
18
+
19
+ def const_defined_two?(item, root = Kernel)
20
+ root.const_defined?(item.to_s)
21
+ end
22
+
23
+ def define_constant_two(item, root: Kernel, type: Module)
24
+ return true if root.const_defined?(item)
25
+
26
+ root.const_set(item.to_s, type.new)
27
+ end
28
+
29
+ def define_get(item, root: Kernel, type: Module)
30
+ define_constant_two(item, root: root, type: type) if const_defined_two?(item, root: root)
31
+ root.const_get(item)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'base'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Builder
6
+ module Helpers
7
+ include Legion::Extensions::Builder::Base
8
+
9
+ def build_helpers
10
+ @helpers ||= []
11
+ @helpers.push(require_files(helper_files))
12
+ end
13
+
14
+ def helper_files
15
+ @helper_files ||= find_files('helpers')
16
+ end
17
+
18
+ def helpers
19
+ @helpers
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,62 @@
1
+ require_relative 'base'
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Builder
6
+ module Runners
7
+ include Legion::Extensions::Builder::Base
8
+
9
+ attr_reader :runners
10
+
11
+ def build_runners
12
+ @runners = {}
13
+ lex_class.const_set('Runners', Module.new) unless lex_class.const_defined?('Runners')
14
+ require_files(runner_files)
15
+ build_runner_list
16
+ end
17
+
18
+ def build_runner_list
19
+ runner_files.each do |file|
20
+ runner_name = file.split('/').last.sub('.rb', '')
21
+ runner_class = "#{lex_class}::Runners::#{runner_name.split('_').collect(&:capitalize).join}"
22
+ loaded_runner = Kernel.const_get(runner_class)
23
+
24
+ @runners[runner_name.to_sym] = {
25
+ extension: lex_class.to_s.downcase,
26
+ extension_name: extension_name,
27
+ extension_class: lex_class,
28
+ runner_name: runner_name,
29
+ runner_class: runner_class,
30
+ runner_path: file,
31
+ class_methods: {}
32
+ }
33
+
34
+ @runners[runner_name.to_sym][:scheduled_tasks] = loaded_runner.scheduled_tasks if loaded_runner.method_defined? :scheduled_tasks
35
+
36
+ if settings.key?(:runners) && settings[:runners].key?(runner_name.to_sym)
37
+ @runners[runner_name.to_sym][:desc] = settings[:runners][runner_name.to_sym][:desc]
38
+ end
39
+
40
+ loaded_runner.public_instance_methods(false).each do |runner_method|
41
+ @runners[runner_name.to_sym][:class_methods][runner_method] = {
42
+ args: loaded_runner.instance_method(runner_method).parameters
43
+ }
44
+ end
45
+
46
+ loaded_runner.methods(false).each do |runner_method|
47
+ next if %i[scheduled_tasks runner_description].include? runner_method
48
+
49
+ @runners[runner_name.to_sym][:class_methods][runner_method] = {
50
+ args: loaded_runner.method(runner_method).parameters
51
+ }
52
+ end
53
+ end
54
+ end
55
+
56
+ def runner_files
57
+ @runner_files ||= find_files('runners')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -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
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,61 @@
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
+ Legion::Logging.fatal 'testing inside run'
12
+ @models = []
13
+ @migrations = []
14
+ if Dir[File.expand_path("#{data_path}/migrations/*.rb")].count.positive?
15
+ log.debug('Has migrations, checking status')
16
+ run
17
+ end
18
+
19
+ models = Dir[File.expand_path("#{data_path}/models/*.rb")]
20
+ if models.count.positive?
21
+ log.debug('Including LEX models')
22
+ models.each do |file|
23
+ require file
24
+ end
25
+
26
+ models_class.constants.select do |model|
27
+ models_class.const_get(model).extend Legion::Extensions::Data::Model
28
+ end
29
+ end
30
+
31
+ true
32
+ end
33
+
34
+ def extension_model
35
+ Legion::Data::Model::Extension[namespace: lex_class.to_s]
36
+ end
37
+
38
+ def schema_version
39
+ extension_model.values[:schema_version]
40
+ end
41
+
42
+ def migrations_path
43
+ "#{data_path}/migrations/"
44
+ end
45
+
46
+ def migrate_class
47
+ @migrate_class ||= Legion::Extensions::Data::Migrator.new(migrations_path, lex_class.to_s, lex_name)
48
+ end
49
+
50
+ def run
51
+ Legion::Logging.fatal 'testing inside run'
52
+
53
+ return true if migrate_class.is_current?
54
+
55
+ log.debug('Running LEX schema migrator')
56
+ results = migrate_class.run
57
+ extension_model.update(schema_version: results)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,33 @@
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, _lex_name, **)
8
+ Legion::Logging.fatal @extension
9
+ @path = path
10
+ @extension = extension
11
+ super(Legion::Data::Connection.sequel, path)
12
+ end
13
+
14
+ def default_schema_column
15
+ :schema_version
16
+ end
17
+
18
+ def default_schema_table
19
+ :extensions
20
+ end
21
+
22
+ def schema_dataset
23
+ dataset = Legion::Data::Connection.sequel.from(default_schema_table).where(namespace: @extension)
24
+ return dataset unless dataset.count.positive?
25
+
26
+ Legion::Logging.unknown Legion::Data::Model::Extension.insert(active: 1, namespace: @extension, extension: lex_name)
27
+ Legion::Data::Connection.sequel.from(default_schema_table).where(namespace: @extension)
28
+ end
29
+ alias ds schema_dataset
30
+ end
31
+ end
32
+ end
33
+ 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