shatter-rb 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.husky/commit-msg +5 -0
- data/.rubocop.yml +4 -0
- data/.ruby-version +1 -1
- data/.tool-versions +1 -1
- data/Gemfile +0 -2
- data/Gemfile.lock +51 -8
- data/Guardfile +72 -0
- data/README.md +76 -14
- data/commitlint.config.js +1 -0
- data/example_app/Gemfile +3 -2
- data/example_app/Gemfile.lock +9 -16
- data/example_app/app/application.rb +4 -0
- data/example_app/app/functions/hello_world_function.rb +8 -16
- data/example_app/app/service_definition.rb +2 -6
- data/example_app/application.rb +4 -2
- data/example_app/bin/service +2 -2
- data/example_app/config/environment.rb +13 -7
- data/example_app/config.ru +8 -0
- data/exe/console +1 -1
- data/exe/shatter +33 -23
- data/lib/shatter/config.rb +14 -4
- data/lib/shatter/service/base.rb +28 -35
- data/lib/shatter/service/discovery.rb +32 -19
- data/lib/shatter/service/function.rb +45 -31
- data/lib/shatter/service/response_pool.rb +12 -7
- data/lib/shatter/service/service_definition.rb +10 -4
- data/lib/shatter/util.rb +21 -5
- data/lib/shatter/version.rb +1 -1
- data/lib/shatter/web/application.rb +34 -32
- data/lib/shatter/web/server.rb +25 -18
- data/lib/shatter.rb +59 -11
- data/package.json +7 -0
- data/templates/Gemfile.template +1 -3
- data/templates/application.erb +2 -6
- data/templates/config.ru +8 -0
- data/templates/environment.rb.erb +9 -8
- data/templates/function_definition.ts.erb +5 -0
- data/templates/hello_world_function.rb.erb +6 -14
- data/templates/service_client.ts.erb +25 -0
- data/templates/service_definition.rb.erb +3 -7
- data/yarn.lock +1338 -0
- metadata +115 -25
- data/example_app/bin/console +0 -11
- data/lib/shatter/service/function_params.rb +0 -21
- data/shatter.gemspec +0 -51
data/lib/shatter/service/base.rb
CHANGED
@@ -1,71 +1,64 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'benchmark'
|
2
|
+
|
4
3
|
require "drb/drb"
|
5
|
-
require "zk"
|
6
4
|
require "concurrent-ruby"
|
7
5
|
|
8
6
|
# Server Side of the drb
|
9
7
|
module Shatter
|
10
8
|
module Service
|
11
9
|
class Base
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
class ReloadWrapper
|
11
|
+
def self.method_missing(method, *args, &)
|
12
|
+
Shatter::RELOAD_RW_LOCK.with_write_lock do
|
13
|
+
Shatter.reload
|
14
|
+
end
|
15
|
+
Shatter::RELOAD_RW_LOCK.with_read_lock do
|
16
|
+
Shatter::Service::Base.send(method, *args)
|
17
|
+
end
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
21
|
+
include Concurrent::Async
|
22
|
+
|
22
23
|
class << self
|
23
|
-
|
24
|
-
attr_writer :service_definition
|
24
|
+
attr_accessor :service_definition
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.response_for(uuid)
|
28
|
-
ResponsePool.instance.pool[uuid]
|
28
|
+
Shatter::Service::ResponsePool.instance.pool[uuid]
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.respond_to_missing?(method)
|
32
|
-
@service_definition.
|
32
|
+
@service_definition.new.respond_to?(method)
|
33
33
|
end
|
34
34
|
|
35
35
|
def self.set_static_result_for(uuid, result)
|
36
|
-
|
37
|
-
populate_pool_with_result(Time.now, {uuid:, result:}, nil)
|
36
|
+
populate_pool_with_result(Time.now, { uuid:, result: }, nil)
|
38
37
|
end
|
39
38
|
|
40
39
|
def self.method_missing(method, *args, &)
|
41
|
-
|
40
|
+
super unless respond_to_missing?(method)
|
42
41
|
uuid = args[0].is_a?(Hash) ? args[0][:uuid] : args[0].uuid
|
43
|
-
return {error:
|
42
|
+
return { error: "missing uuid" } if uuid.nil?
|
43
|
+
|
44
44
|
future = @service_definition.new.async.send(method, *args, &)
|
45
45
|
future.add_observer(self, :populate_pool_with_result)
|
46
46
|
end
|
47
47
|
|
48
|
-
def self.populate_pool_with_result(
|
49
|
-
if err
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
key = nil
|
55
|
-
key = Util.zookeeper_response_key(value[:uuid])
|
56
|
-
my_ip = ENV["HOST_NAME"] || "localhost"
|
57
|
-
host = "#{my_ip}:#{Shatter::Config.service_port}"
|
58
|
-
Shatter.logger.info "Recording location of #{value[:uuid]} at #{host} #{value}"
|
59
|
-
zk.create(key, host)
|
60
|
-
my_ip
|
61
|
-
rescue Exception => e
|
48
|
+
def self.populate_pool_with_result(_time, value, err)
|
49
|
+
Shatter.logger.info err if err
|
50
|
+
Shatter.logger.info "#{value[:uuid]} => #{value}" unless err
|
51
|
+
Shatter::Service::ResponsePool.instance.pool[value[:uuid]] = value
|
52
|
+
Shatter::Service::Discovery.populate_result_location(value[:uuid])
|
53
|
+
rescue StandardError => e
|
62
54
|
Shatter.logger.error e
|
63
55
|
raise e
|
64
56
|
end
|
65
57
|
|
66
58
|
def self.close
|
67
59
|
logger = Shatter.logger
|
68
|
-
logger.info "Closing down DRb service"
|
60
|
+
logger.info "Closing down DRb service: #{@service_instance}"
|
61
|
+
@service_instance.stop_service
|
69
62
|
port = Shatter::Config.service_port
|
70
63
|
uri = "localhost:#{port}"
|
71
64
|
logger.info "Removing my existnce at #{port} to zookeeper"
|
@@ -80,7 +73,7 @@ module Shatter
|
|
80
73
|
logger.info "Logging my existnce at #{uri} to zookeeper"
|
81
74
|
Shatter::Service::Discovery.register_service(uri)
|
82
75
|
logger.info "Starting DRb service"
|
83
|
-
DRb.start_service("druby://#{uri}", self)
|
76
|
+
@service_instance = DRb.start_service("druby://#{uri}", Shatter::Config.reload_classes ? ReloadWrapper : self)
|
84
77
|
logger.info "DRb service started"
|
85
78
|
DRb.thread.join
|
86
79
|
end
|
@@ -90,4 +83,4 @@ module Shatter
|
|
90
83
|
end
|
91
84
|
end
|
92
85
|
end
|
93
|
-
end
|
86
|
+
end
|
@@ -1,25 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zk"
|
1
4
|
module Shatter
|
2
5
|
module Service
|
3
6
|
class Discovery
|
4
7
|
class << self
|
8
|
+
def connection_pool
|
9
|
+
@connection_pool ||= ZK::Pool::Bounded.new(Shatter::Config.zookeeper_host)
|
10
|
+
end
|
5
11
|
|
6
12
|
def deregister_service(service_url)
|
7
|
-
zk =
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
zk.close
|
13
|
+
zk = connection_pool.checkout
|
14
|
+
key = Shatter::Util.instances_key
|
15
|
+
zk.delete("#{key}/#{service_url}") if zk.exists?("#{key}/#{service_url}")
|
16
|
+
connection_pool.checkin(zk)
|
12
17
|
end
|
13
18
|
|
14
19
|
def register_service(service_url)
|
15
20
|
Shatter.logger.info "Registering #{service_url} to zookeeper"
|
16
|
-
zk =
|
17
|
-
|
18
|
-
|
21
|
+
zk = connection_pool.checkout
|
22
|
+
key = Shatter::Util.instances_key
|
23
|
+
unless zk.exists?("#{key}/#{service_url}")
|
24
|
+
created = zk.create("#{key}/#{service_url}")
|
19
25
|
Shatter.logger.info "Registered #{created}"
|
20
26
|
end
|
21
|
-
|
22
|
-
zk.close
|
27
|
+
connection_pool.checkin(zk)
|
23
28
|
end
|
24
29
|
|
25
30
|
def service_instance_url
|
@@ -27,23 +32,31 @@ module Shatter
|
|
27
32
|
end
|
28
33
|
|
29
34
|
def service_instance_urls
|
30
|
-
zk =
|
31
|
-
urls = zk.children(
|
32
|
-
zk
|
35
|
+
zk = connection_pool.checkout
|
36
|
+
urls = zk.children(Shatter::Util.instances_key)
|
37
|
+
connection_pool.checkin(zk)
|
33
38
|
urls
|
34
39
|
end
|
35
40
|
|
41
|
+
def populate_result_location(uuid)
|
42
|
+
zk = connection_pool.checkout
|
43
|
+
zk.create(Util.zookeeper_response_key(uuid), my_host)
|
44
|
+
connection_pool.checkin(zk)
|
45
|
+
end
|
46
|
+
|
47
|
+
def my_host
|
48
|
+
my_ip = ENV["HOST_NAME"] || "localhost"
|
49
|
+
"#{my_ip}:#{Shatter::Config.service_port}"
|
50
|
+
end
|
51
|
+
|
36
52
|
def service_instance_url_for_uuid(uuid)
|
37
|
-
druby_instance_url = nil
|
38
53
|
key = Util.zookeeper_response_key(uuid)
|
39
|
-
zk =
|
54
|
+
zk = connection_pool.checkout
|
40
55
|
druby_instance_url = zk.get(key)[0] if zk.exists?(key)
|
41
|
-
zk
|
42
|
-
Shatter.logger.debug "Service instance url for #{uuid} - #{druby_instance_url}"
|
43
|
-
|
56
|
+
connection_pool.checkin(zk)
|
44
57
|
druby_instance_url
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
48
61
|
end
|
49
|
-
end
|
62
|
+
end
|
@@ -1,56 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
1
5
|
module Shatter
|
2
6
|
module Service
|
3
7
|
class Function
|
4
|
-
|
5
8
|
def self.define_param(name, type:, nullable: true)
|
6
|
-
|
7
|
-
|
9
|
+
@param_meta ||= {}
|
10
|
+
@param_meta[name] = { name:, type:, nullable: }
|
8
11
|
end
|
9
12
|
|
10
13
|
def self.meta
|
11
|
-
|
14
|
+
@param_meta || {}
|
12
15
|
end
|
16
|
+
define_param :uuid, nullable: false, type: "string"
|
13
17
|
|
14
|
-
|
18
|
+
attr_reader :params
|
15
19
|
|
16
20
|
def initialize(function_params)
|
17
21
|
@params = function_params
|
18
22
|
end
|
19
23
|
|
20
|
-
def params
|
21
|
-
Hash[@@param_meta.keys.map { |k| [k]}].merge(@params)
|
22
|
-
end
|
23
|
-
|
24
24
|
def call
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
{ result: nil, error: "Invalid Parameters" } unless valid_params?
|
26
|
+
{ result: nil, error: nil }.merge(invoke.merge(uuid: params[:uuid]))
|
27
|
+
rescue StandardError => e
|
28
|
+
Shatter.logger.error e.message
|
29
|
+
Shatter.logger.error e.backtrace
|
30
|
+
{ result: nil, error: "Something Went Wrong", uuid: params[:uuid] }
|
30
31
|
end
|
31
32
|
|
32
33
|
def valid_params?
|
33
|
-
self.class.meta.
|
34
|
-
|
35
|
-
val = @params[arg]
|
36
|
-
puts meta
|
37
|
-
raise "#{arg} cannot be nil" if !meta[:nullable] && val.nil?
|
38
|
-
raise "expected #{arg} to be a string" if meta[:type] == 'string' && !val.is_a?(String)
|
39
|
-
|
40
|
-
if meta[:type] == 'integer'
|
41
|
-
if !meta[:nullable] && val.nil?
|
42
|
-
raise 'value cannot be nil'
|
43
|
-
end
|
44
|
-
if !val.nil? && !val.is_a?(Integer)
|
45
|
-
raise "expected #{arg} to be an integer"
|
46
|
-
end
|
47
|
-
end
|
34
|
+
self.class.meta.each_key do |arg|
|
35
|
+
return false unless valid_param?(arg)
|
48
36
|
end
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def valid_param?(arg)
|
41
|
+
meta = self.class.meta[arg]
|
42
|
+
return false if meta.nil?
|
43
|
+
|
44
|
+
meta => type:, nullable:
|
45
|
+
val = value_for_arg(arg)
|
46
|
+
return nullable if val.nil?
|
47
|
+
|
48
|
+
return false if type == "string" && !val.is_a?(String)
|
49
|
+
return false if type == "integer" && !val.is_a?(Integer)
|
50
|
+
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def value_for_arg(arg)
|
55
|
+
@params[arg.to_s] || @params[arg.to_sym]
|
49
56
|
end
|
50
57
|
|
51
58
|
def self.invoke
|
52
|
-
raise
|
59
|
+
raise "cant invoke for base function"
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.to_typescript
|
63
|
+
function_nm = Shatter::Service::Base.service_definition.function_collection.to_a.detect do |fn_def|
|
64
|
+
fn_def[1] == self
|
65
|
+
end[0]
|
66
|
+
ERB.new(File.read("#{__dir__}/../../../templates/function_definition.ts.erb")).result(binding)
|
53
67
|
end
|
54
68
|
end
|
55
69
|
end
|
56
|
-
end
|
70
|
+
end
|
@@ -1,10 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
2
4
|
module Shatter
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module Service
|
6
|
+
class ResponsePool
|
7
|
+
include Singleton
|
8
|
+
attr_reader :pool
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@pool = {}
|
12
|
+
end
|
8
13
|
end
|
9
14
|
end
|
10
|
-
end
|
15
|
+
end
|
@@ -1,15 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "concurrent-ruby"
|
2
|
-
require 'set'
|
3
4
|
|
4
5
|
module Shatter
|
5
6
|
module Service
|
6
7
|
class ServiceDefinition
|
7
8
|
include Concurrent::Async
|
8
9
|
class << self
|
9
|
-
|
10
|
+
attr_accessor :function_collection
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.to_typescript
|
14
|
+
function_defs = @function_collection.values
|
15
|
+
ERB.new(File.read("#{__dir__}/../../../templates/service_client.ts.erb")).result(binding)
|
10
16
|
end
|
17
|
+
|
11
18
|
def self.register_function(identifier, function)
|
12
|
-
Shatter.logger.info "Registering function - #{identifier} for #{self}"
|
13
19
|
@function_collection ||= {}
|
14
20
|
@function_collection[identifier.to_s] = function
|
15
21
|
define_method identifier do |params|
|
@@ -18,4 +24,4 @@ module Shatter
|
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
21
|
-
end
|
27
|
+
end
|
data/lib/shatter/util.rb
CHANGED
@@ -1,19 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "singleton"
|
5
|
+
|
6
|
+
class String
|
7
|
+
def camel_case_lower
|
8
|
+
split("_").inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
|
9
|
+
end
|
10
|
+
end
|
4
11
|
|
5
12
|
module Shatter
|
6
13
|
module Util
|
7
14
|
class Logger < ::Logger
|
8
15
|
include Singleton
|
9
16
|
def initialize
|
10
|
-
super(
|
17
|
+
super($stdout, datetime_format: "%Y-%m-%d %H:%M:%S")
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
21
|
+
def self.instances_key
|
22
|
+
"/shater_service_instances"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.zookeeper_response_key_root
|
26
|
+
"/shatter::response_data_locations"
|
27
|
+
end
|
28
|
+
|
14
29
|
def self.zookeeper_response_key(uuid)
|
15
|
-
raise
|
16
|
-
|
30
|
+
raise "Cant produce key without uuid" if uuid.nil?
|
31
|
+
|
32
|
+
"#{zookeeper_response_key_root}/#{uuid}"
|
17
33
|
end
|
18
34
|
end
|
19
35
|
end
|
data/lib/shatter/version.rb
CHANGED
@@ -3,48 +3,50 @@
|
|
3
3
|
require "drb/drb"
|
4
4
|
require "concurrent-ruby"
|
5
5
|
|
6
|
-
require_relative "./application"
|
7
|
-
|
8
6
|
module Shatter
|
9
7
|
module Web
|
10
8
|
class Application
|
11
9
|
include Concurrent::Async
|
12
10
|
|
13
11
|
def response_for(uuid)
|
14
|
-
|
15
|
-
return
|
16
|
-
|
12
|
+
client = service_client(Shatter::Service::Discovery.service_instance_url_for_uuid(uuid))
|
13
|
+
return if client.nil?
|
14
|
+
|
15
|
+
client.response_for(uuid)
|
17
16
|
end
|
18
17
|
|
19
18
|
def route(uuid, path, params)
|
20
|
-
operation = path
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
.send(
|
34
|
-
operation.to_sym,
|
35
|
-
func_params
|
36
|
-
)
|
37
|
-
rescue ArgumentError => e
|
38
|
-
DRbObject.new_with_uri("druby://#{Shatter::Service::Discovery.service_instance_url}")
|
39
|
-
.set_static_result_for(uuid, {result: nil, error: e.message })
|
40
|
-
end
|
41
|
-
end
|
42
|
-
rescue Exception => e
|
43
|
-
Shatter.logger.error "caught error: #{e.message}"
|
44
|
-
Shatter.logger.error "#{e.backtrace.join("\n")}"
|
45
|
-
{ data:, error: e.message, uuid: }
|
19
|
+
operation = operation_for(path)
|
20
|
+
return unknown_operation(uuid) if operation.nil?
|
21
|
+
|
22
|
+
client = service_client
|
23
|
+
client.send(operation.to_sym, params.merge(uuid:))
|
24
|
+
rescue StandardError => e
|
25
|
+
error_response(uuid, e)
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def unknown_operation(uuid)
|
31
|
+
service_client.set_static_result_for(uuid, { result: nil, error: :unknown_operation })
|
46
32
|
end
|
47
33
|
|
34
|
+
def error_response(uuid, err)
|
35
|
+
Shatter.logger.error err
|
36
|
+
service_client.set_static_result_for(uuid, { result: nil, error: "Something went wrong" })
|
37
|
+
end
|
38
|
+
|
39
|
+
def service_client(druby_instance_url = Shatter::Service::Discovery.service_instance_url)
|
40
|
+
return if druby_instance_url.nil?
|
41
|
+
|
42
|
+
DRbObject.new_with_uri("druby://#{druby_instance_url}")
|
43
|
+
end
|
44
|
+
|
45
|
+
def operation_for(path)
|
46
|
+
operation = path.scan(%r{/(.+)$}).first&.first
|
47
|
+
function = Shatter::Service::Base.service_definition.function_collection[operation]
|
48
|
+
function.nil? ? nil : operation
|
49
|
+
end
|
48
50
|
end
|
49
51
|
end
|
50
|
-
end
|
52
|
+
end
|
data/lib/shatter/web/server.rb
CHANGED
@@ -6,40 +6,47 @@ require "json"
|
|
6
6
|
module Shatter
|
7
7
|
module Web
|
8
8
|
class Server
|
9
|
-
|
10
9
|
class << self
|
11
|
-
|
12
|
-
attr_writer :application
|
10
|
+
attr_accessor :application
|
13
11
|
end
|
14
12
|
|
15
13
|
def self.call(env)
|
16
14
|
request = Rack::Request.new(env)
|
17
|
-
path = env["PATH_INFO"]
|
18
15
|
if env["PATH_INFO"] == "/callbacks"
|
19
|
-
uuid = env[
|
20
|
-
|
21
|
-
elsif
|
22
|
-
|
16
|
+
uuid = env["QUERY_STRING"].split("=")[1]
|
17
|
+
handle_response_for_request(uuid)
|
18
|
+
elsif request.post?
|
19
|
+
handle_operation_request(env)
|
23
20
|
else
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
[404, {}, []]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.handle_operation_request(env)
|
26
|
+
request = Rack::Request.new(env)
|
27
|
+
params = begin
|
28
|
+
JSON.parse(request.body.read, { symbolize_names: true })
|
29
|
+
rescue StandardError
|
30
|
+
{}
|
29
31
|
end
|
32
|
+
uuid = SecureRandom.uuid
|
33
|
+
future = application.new.async.route(uuid, request.path, params)
|
34
|
+
future.add_observer(:service_callback, self)
|
35
|
+
[200, { "delay" => Shatter::Config.initial_delay, "location" => "/callbacks?uuid=#{uuid}" }, []]
|
30
36
|
end
|
31
37
|
|
32
|
-
def self.
|
38
|
+
def self.service_callback(_time, _value, error)
|
33
39
|
return if error.nil?
|
34
|
-
|
40
|
+
|
41
|
+
Shatter.logger.error error.to_s
|
35
42
|
end
|
36
43
|
|
37
|
-
def self.
|
44
|
+
def self.handle_response_for_request(uuid)
|
38
45
|
response = application.new.response_for(uuid)
|
39
46
|
return [200, {}, [response.to_json]] unless response.nil?
|
40
47
|
|
41
|
-
[200, { "delay" =>
|
48
|
+
[200, { "delay" => Shatter::Config.missing_result_delay, "location" => "/callbacks?uuid=#{uuid}" }, []]
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
45
|
-
end
|
52
|
+
end
|
data/lib/shatter.rb
CHANGED
@@ -1,21 +1,69 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require_relative "shatter/
|
9
|
-
require_relative "shatter/
|
10
|
-
require_relative "shatter/
|
11
|
-
require_relative "shatter/util"
|
12
|
-
|
13
|
-
$stdout.sync = true
|
3
|
+
require "zeitwerk"
|
4
|
+
require "concurrent/atomic/read_write_lock"
|
5
|
+
Dir["#{__dir__}/shatter/service/*.rb"].each { |file| require file }
|
6
|
+
Dir["#{__dir__}/shatter/web/*.rb"].each { |file| require file }
|
7
|
+
Dir["#{__dir__}/shatter/ext/*.rb"].each { |file| require file }
|
8
|
+
require_relative "./shatter/config"
|
9
|
+
require_relative "./shatter/util"
|
10
|
+
require_relative "./shatter/version"
|
14
11
|
|
15
12
|
module Shatter
|
16
13
|
class Error < StandardError; end
|
14
|
+
|
15
|
+
def self.root
|
16
|
+
current = Dir.pwd
|
17
|
+
root_dir = nil
|
18
|
+
|
19
|
+
while current.size >= 1 && root_dir.nil?
|
20
|
+
root_dir = current if Dir.children(current).include?("Gemfile")
|
21
|
+
current = File.expand_path("..", current) if root_dir.nil?
|
22
|
+
Dir.new(current)
|
23
|
+
end
|
24
|
+
root_dir
|
25
|
+
end
|
26
|
+
|
17
27
|
def self.logger
|
18
28
|
Util::Logger.instance
|
19
29
|
end
|
30
|
+
|
31
|
+
def self.config(&block)
|
32
|
+
block.call(Config) and return if block_given?
|
33
|
+
|
34
|
+
Config
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.loader
|
38
|
+
@loader
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.load_environment
|
42
|
+
require "#{Shatter.root}/config/environment.rb"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.reload
|
46
|
+
@loader.reload
|
47
|
+
link_definitions
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.load
|
51
|
+
# @loader = Zeitwerk::Loader.for_gem
|
52
|
+
@loader = Zeitwerk::Loader.new
|
53
|
+
@loader.tag = File.basename(__FILE__, ".rb")
|
54
|
+
@loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
55
|
+
Config.autoload_paths.each do |path|
|
56
|
+
@loader.push_dir(File.expand_path(path, root))
|
57
|
+
end
|
58
|
+
@loader.enable_reloading
|
59
|
+
@loader.setup # ready!
|
60
|
+
link_definitions
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.link_definitions
|
64
|
+
Shatter::Service::Base.service_definition = ServiceDefinition if Object.const_defined?("ServiceDefinition")
|
65
|
+
Shatter::Web::Server.application = Application if Object.const_defined?("Application")
|
66
|
+
end
|
20
67
|
# Your code goes here...
|
21
68
|
end
|
69
|
+
Shatter::RELOAD_RW_LOCK = Concurrent::ReadWriteLock.new
|
data/package.json
ADDED
data/templates/Gemfile.template
CHANGED
data/templates/application.erb
CHANGED
data/templates/config.ru
CHANGED
@@ -2,8 +2,16 @@
|
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
4
|
require "shatter"
|
5
|
+
require "rack/cors"
|
5
6
|
|
6
7
|
require_relative "./config/environment"
|
7
8
|
|
8
9
|
use Rack::CommonLogger
|
10
|
+
|
11
|
+
use Rack::Cors do
|
12
|
+
allow do
|
13
|
+
origins "*"
|
14
|
+
resource "*", headers: :any, methods: %i[get post patch put], expose: %w[delay location]
|
15
|
+
end
|
16
|
+
end
|
9
17
|
run Shatter::Web::Server
|