sails 0.1.0 → 0.1.1

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.
@@ -0,0 +1,103 @@
1
+ module Sails
2
+ class Daemon
3
+ class << self
4
+ attr_accessor :options, :mode, :app_name, :pid_file
5
+
6
+ def init(opts = {})
7
+ self.app_name = Sails.config.app_name
8
+ self.mode = opts[:mode]
9
+ self.app_name = "#{Sails::Daemon.app_name}-thread" if self.mode == "thread"
10
+ self.pid_file = Sails.root.join("tmp/#{Sails::Daemon.app_name}.pid")
11
+ self.options = options
12
+ end
13
+
14
+ def read_pid
15
+ if !File.exist?(pid_file)
16
+ return nil
17
+ end
18
+
19
+ pid = File.open(pid_file).read.to_i
20
+ begin
21
+ Process.getpgid(pid)
22
+ rescue
23
+ pid = nil
24
+ end
25
+ return pid
26
+ end
27
+
28
+ def start_process(options = {})
29
+ old_pid = read_pid
30
+ if old_pid != nil
31
+ puts "Current have #{app_name} process in running on pid #{old_pid}"
32
+ return
33
+ end
34
+
35
+ # start master process
36
+ @master_pid = fork_master_process!
37
+ File.open(pid_file, "w+") do |f|
38
+ f.puts @master_pid
39
+ end
40
+
41
+ puts "Started #{app_name} on pid: #{@master_pid}"
42
+
43
+ if options[:daemon] == false
44
+ Process.waitpid(@master_pid)
45
+ end
46
+ end
47
+
48
+ def fork_master_process!
49
+ fork do
50
+ $PROGRAM_NAME = self.app_name + " [master]"
51
+ @child_pid = fork_child_process!
52
+
53
+ Signal.trap("QUIT") {
54
+ Process.kill("QUIT", @child_pid)
55
+ exit
56
+ }
57
+
58
+ Signal.trap("USR2") {
59
+ Process.kill("USR2", @child_pid)
60
+ }
61
+
62
+ loop do
63
+ sleep 1
64
+ begin
65
+ Process.getpgid(@child_pid)
66
+ rescue Errno::ESRCH => e
67
+ # puts "Child not found, will restart..."
68
+ @child_pid = fork_child_process!
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def fork_child_process!
75
+ fork do
76
+ $PROGRAM_NAME = self.app_name
77
+ Sails.start!(self.mode)
78
+
79
+ Signal.trap("USR2") {
80
+ # TODO: reload Sails in current process
81
+ exit
82
+ }
83
+ end
84
+ end
85
+
86
+ def stop_process
87
+ pid = read_pid
88
+ if pid == nil
89
+ puts "#{app_name} process not found, pid #{pid}"
90
+ return
91
+ end
92
+
93
+ print "Stopping #{app_name} with pid: #{pid}..."
94
+ begin
95
+ Process.kill("QUIT", pid)
96
+ ensure
97
+ File.delete(pid_file)
98
+ end
99
+ puts " [Done]"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,56 @@
1
+ module Sails
2
+ module Service
3
+ # Like ActionController::Base
4
+ class Base
5
+ include ActiveSupport::Callbacks
6
+
7
+ define_callbacks :action
8
+
9
+ set_callback :action, :before do |object|
10
+ # TODO: only reload on files changed
11
+ Sails.reload!
12
+ end
13
+
14
+ set_callback :action, :after do |object|
15
+ ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
16
+ end
17
+
18
+ class << self
19
+ def internal_methods
20
+ controller = self.superclass
21
+ controller.public_instance_methods(true)
22
+ end
23
+
24
+ def action_methods
25
+ @action_methods ||= begin
26
+ # All public instance methods of this class, including ancestors
27
+ methods = (public_instance_methods(true) -
28
+ # Except for public instance methods of Base and its ancestors
29
+ internal_methods +
30
+ # Be sure to include shadowed public instance methods of this class
31
+ public_instance_methods(false)).uniq.map { |x| x.to_s }
32
+
33
+ # Clear out AS callback method pollution
34
+ Set.new(methods.reject { |method| method =~ /_one_time_conditions/ })
35
+ end
36
+ end
37
+ end
38
+
39
+ # Raise a Sails::Service::Exception (Thrift::Exception)
40
+ # if you want custom error you can override this method in you ApplicationService
41
+ def raise_error(code, msg = nil)
42
+ raise Exception.new(code: code, message: msg)
43
+ end
44
+
45
+ def action_methods
46
+ self.class.action_methods
47
+ end
48
+
49
+ # Sails.logger
50
+ # You can use this method in app/services
51
+ def logger
52
+ Sails.logger
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,22 @@
1
+ module Sails
2
+ module Service
3
+ # Thrift Exception
4
+ class Exception < ::Thrift::Exception
5
+ include ::Thrift::Struct, ::Thrift::Struct_Union
6
+ CODE = 1
7
+ MESSAGE = 2
8
+
9
+ FIELDS = {
10
+ CODE => {:type => ::Thrift::Types::I32, :name => 'code'},
11
+ MESSAGE => {:type => ::Thrift::Types::STRING, :name => 'message'}
12
+ }
13
+
14
+ def struct_fields; FIELDS; end
15
+
16
+ def validate
17
+ end
18
+
19
+ ::Thrift::Struct.generate_accessors self
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,60 @@
1
+ module Sails
2
+ module Service
3
+ class Interface
4
+ attr_accessor :services
5
+
6
+ def initialize
7
+ @services = []
8
+ Dir["#{Sails.root.join("app/services")}/*_service.rb"].each do |f|
9
+ if File.basename(f) =~ /^(.*)_service.rb$/
10
+ require f
11
+ mtd = $1.dup
12
+ klass_name = "#{mtd.camelize}Service"
13
+ @services << klass_name.constantize.new
14
+ end
15
+ end
16
+ define_service_methods!
17
+ end
18
+
19
+ private
20
+ def define_service_methods!
21
+ @services.each do |instance|
22
+ instance.action_methods.each do |method_name|
23
+ self.class.send(:define_method, method_name) do |*args, &block|
24
+ run_action(instance, method_name, *args, &block)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def run_action(instance, method_name, *args, &block)
31
+ instance.run_callbacks :action do
32
+ time = Time.now.to_f
33
+
34
+ Sails.logger.info "\nProcessing by \"#{method_name}\" at #{Time.now.to_s}" unless Sails.env.test?
35
+ Sails.logger.info " Parameters: { #{args.map(&:inspect).join(', ')} }" unless Sails.env.test?
36
+
37
+ begin
38
+ res = instance.send(method_name, *args, &block)
39
+ status = "Completed"
40
+ return res
41
+ rescue ActiveRecord::RecordNotFound => e
42
+ status = "Not Found"
43
+ instance.raise_error(404)
44
+ rescue Thrift::Exception => e
45
+ status = "Failed #{e.try(:code)}"
46
+ raise e
47
+ rescue => e
48
+ status = "Error 500"
49
+ Sails.logger.info "\"#{method_name}\" error : #{e.inspect}\n\n"
50
+ Sails.logger.info %Q(backtrace: #{e.backtrace.join("\n")}\n)
51
+ instance.raise_error(500)
52
+ ensure
53
+ elapsed = format('%.3f', (Time.now.to_f - time) * 1000)
54
+ Sails.logger.info "#{status} in (#{elapsed}ms).\n\n" unless Sails.env.test?
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
data/lib/sails/service.rb CHANGED
@@ -1,77 +1,10 @@
1
1
  module Sails
2
- class Service
3
- include ActiveSupport::Callbacks
4
- define_callbacks :action
5
-
6
- set_callback :action, :before do |object|
7
- end
8
-
9
- set_callback :action, :after do |object|
10
- ActiveRecord::Base.clear_active_connections! if defined?(ActiveRecord::Base)
11
- end
12
-
13
- def method_missing(method_name, *args, &block)
14
- run_callbacks :action do
15
- time = Time.now.to_f
16
-
17
- Sails.logger.info "\nProcessing by \"#{method_name}\" at #{Time.now.to_s}" unless Sails.env.test?
18
- Sails.logger.info " Parameters: { #{args.map(&:inspect).join(', ')} }" unless Sails.env.test?
19
-
20
- begin
21
- res = interface.send(method_name, *args, &block)
22
- status = "Completed"
23
- return res
24
- rescue ActiveRecord::RecordNotFound => e
25
- status = "Not Found"
26
- interface.raise_error(-1004)
27
- rescue ThriftServer::OperationFailed => e
28
- status = "Failed #{e.code}"
29
- raise e
30
- rescue => e
31
- status = "Error 500"
32
- Sails.logger.info "\"#{method_name}\" error : #{e.inspect}\n\n"
33
- Sails.logger.info %Q(backtrace: #{e.backtrace.join("\n")}\n)
34
- interface.raise_error(-1000)
35
- ensure
36
- elapsed = format('%.3f', (Time.now.to_f - time) * 1000)
37
- Sails.logger.info "#{status} in (#{elapsed}ms).\n\n" unless Sails.env.test?
38
- end
39
- end
40
- end
41
-
42
- def args
43
- @args ||= []
44
- end
45
-
46
- def initialize(*array)
47
- args.concat array
48
- end
49
-
50
- class Interface
51
- Dir["#{Sails.root.join("app/services")}/*_service.rb"].each do |f|
52
- next if 'base_service.rb' == File.basename(f)
53
- if File.basename(f) =~ /^(.*)_service.rb$/
54
- require f
55
- mtd = $1.dup
56
- klass_name = "#{mtd.camelize}Service"
57
- include klass_name.constantize
58
- end
59
- end
60
-
61
- def raise_error code, msg = nil
62
- raise ThriftServer::OperationFailed.new(
63
- code: code,
64
- message: msg
65
- )
66
- end
67
-
68
- def logger
69
- Sails.logger
70
- end
71
- end
72
-
73
- def interface
74
- @interface ||= Interface.new
75
- end
2
+ module Service
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Base
6
+ autoload :Config
7
+ autoload :Exception
8
+ autoload :Interface
76
9
  end
77
- end
10
+ end
@@ -7,11 +7,6 @@ Dir.glob('lib/tasks/*.rake').each { |r| import r }
7
7
 
8
8
  task :default => :test
9
9
 
10
- task :console do
11
- puts "Starting thrift-server console..."
12
- system "pry -I config/application.rb -r ./config/application.rb"
13
- end
14
-
15
10
  task :gen do
16
11
  puts "Generating thrift code..."
17
12
  system 'thrift \
@@ -1,6 +1,8 @@
1
- module ApplicationService
2
- extend ActiveSupport::Concern
3
-
1
+ class ApplicationService < Sails::Service::Base
4
2
  # def require_user!(user_id, access_token)
5
3
  # end
4
+
5
+ # def raise_error(code, msg = nil)
6
+ # raise YouCustomThriftException.new(code: code, message: msg)
7
+ # end
6
8
  end
@@ -8,9 +8,15 @@ require "app/services/handler"
8
8
  module Sails
9
9
  config.app_name = '<%= app_name %>'
10
10
  # Thrift Configs
11
- config.thrift_host = '127.0.0.1'
12
- config.thrift_port = 4000
13
- config.thrift_processor = Thrift::<%= app_name.capitalize %>::Processor
11
+ config.port = 4000
12
+
13
+ # Thrift protocol allows: :binary, :compact, default: :binary
14
+ # config.protocol = :binary
15
+
16
+ # Number of threads, default: 20
17
+ # config.thread_size = 20
18
+
19
+ config.processor = Thrift::<%= app_name.capitalize %>::Processor
14
20
 
15
21
  # config.autoload_paths += %W(app/workers)
16
22
 
@@ -0,0 +1,3 @@
1
+ module Sails
2
+ config.cache_classes = false
3
+ end
@@ -0,0 +1,3 @@
1
+ module Sails
2
+ config.cache_classes = true
3
+ end
@@ -0,0 +1,3 @@
1
+ module Sails
2
+ config.cache_classes = false
3
+ end
data/lib/sails/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Sails
2
2
  def self.version
3
- "0.1.0"
3
+ "0.1.1"
4
4
  end
5
5
  end
data/lib/sails.rb CHANGED
@@ -1,7 +1,40 @@
1
- require "sails/version"
2
- require "sails/base"
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'active_support/all'
4
+ require 'i18n'
5
+ require 'thrift'
6
+ require 'yaml'
3
7
  require "sails/rails"
4
- require "sails/cli"
5
- require "sails/service"
8
+ require "sails/base"
6
9
 
7
- Sails.init()
10
+ # Sails
11
+ #
12
+ # You can custom Sails configs in config/application.rb
13
+ #
14
+ # module Sails
15
+ # config.app_name = 'you_app_name'
16
+ # config.thrift.port = 7075
17
+ # config.thrift.processor = Thrift::YouAppName::Processor
18
+ #
19
+ # # Thrift Protocols can be use [:binary, :compact, :json]
20
+ # # http://jnb.ociweb.com/jnb/jnbJun2009.html#protocols
21
+ # config.thrift.procotol = :binary
22
+ #
23
+ # config.autoload_paths += %W(app/workers)
24
+ #
25
+ # config.i18n.default_locale = 'zh-CN'
26
+ #
27
+ # # cache store
28
+ # config.cache_store = [:dalli_store, '127.0.0.1' }]
29
+ # end
30
+ #
31
+ module Sails
32
+ extend ActiveSupport::Autoload
33
+
34
+ autoload :Config
35
+ autoload :Version
36
+ autoload :Service
37
+ autoload :CLI
38
+ autoload :Daemon
39
+ autoload :Console
40
+ end
data/sails.gemspec CHANGED
@@ -6,11 +6,11 @@ Gem::Specification.new do |s|
6
6
  s.name = "sails"
7
7
  s.version = Sails.version
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Jason Lee"]
10
- s.email = ["huacnlee@gmail.com"]
9
+ s.authors = ["Jason Lee", "P.S.V.R", "wxianfeng", "sapronlee","qhwa"]
10
+ s.email = ["huacnlee@gmail.com", "pmq2001@gmail.com", "wang.fl1429@gmail.com", "sapronlee@gmail.com","qhwa@163.com"]
11
11
  s.homepage = "https://github.com/huacnlee/sails"
12
- s.summary = %q{Sails, create Thrift Server use like Rails}
13
- s.description = %q{Sails, create Thrift Server use like Rails}
12
+ s.summary = %q{Sails, Help you to create Rails style Thrift Server}
13
+ s.description = %q{Sails, Help you to create Rails style Thrift Server}
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
16
  s.executables = ["sails"]
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Sails::CLI' do
4
+ let(:cli) { Sails::CLI.new }
5
+ describe '.start' do
6
+ it { expect(cli).to respond_to(:start) }
7
+ it {
8
+ expect(Sails::Daemon).to receive(:init)
9
+ expect(Sails::Daemon).to receive(:start_process)
10
+ cli.start
11
+ }
12
+ end
13
+
14
+ describe '.stop' do
15
+ it { expect(cli).to respond_to(:stop) }
16
+ it {
17
+ expect(Sails::Daemon).to receive(:init)
18
+ expect(Sails::Daemon).to receive(:stop_process)
19
+ cli.stop
20
+ }
21
+ end
22
+
23
+ describe '.restart' do
24
+ it { expect(cli).to respond_to(:restart) }
25
+ it {
26
+ # expect(Sails::Daemon).to receive(:init)
27
+ expect(Sails::Daemon).to receive(:stop_process)
28
+ expect(Sails::Daemon).to receive(:start_process)
29
+ cli.restart
30
+ }
31
+ end
32
+
33
+ describe '.new' do
34
+ it { expect(cli).to respond_to(:new) }
35
+ end
36
+
37
+ describe '.console' do
38
+ it { expect(cli).to respond_to(:console) }
39
+ end
40
+
41
+ describe '.version' do
42
+ it { expect(cli).to respond_to(:version) }
43
+ end
44
+ end
@@ -1 +1,28 @@
1
1
  # Logfile created on 2014-12-08 13:02:26 +0800 by logger.rb/44203
2
+ Cache clear: flushing all keys
3
+ Dalli::Server#connect 127.0.0.1:11211
4
+ Cache clear: flushing all keys
5
+ Cache clear: flushing all keys
6
+ Cache clear: flushing all keys
7
+ Cache clear: flushing all keys
8
+ Cache clear: flushing all keys
9
+ Cache clear: flushing all keys
10
+ Cache clear: flushing all keys
11
+ Cache clear: flushing all keys
12
+ Cache clear: flushing all keys
13
+ Cache clear: flushing all keys
14
+ Cache clear: flushing all keys
15
+ Cache clear: flushing all keys
16
+ Cache clear: flushing all keys
17
+ Cache clear: flushing all keys
18
+ Cache clear: flushing all keys
19
+ Cache clear: flushing all keys
20
+ Cache clear: flushing all keys
21
+ Cache clear: flushing all keys
22
+ Cache clear: flushing all keys
23
+ Cache clear: flushing all keys
24
+ Cache clear: flushing all keys
25
+ Cache clear: flushing all keys
26
+ Cache clear: flushing all keys
27
+ Cache clear: flushing all keys
28
+ Cache clear: flushing all keys
@@ -0,0 +1,5 @@
1
+ describe 'Rails' do
2
+ it { expect(Rails.logger).to eq Sails.logger }
3
+ it { expect(Rails.cache).to eq Sails.cache }
4
+ it { expect(Rails.env).to eq Sails.env }
5
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+
3
+ describe 'Sails' do
4
+ it { expect(Sails.version).not_to be_nil }
5
+
6
+ describe '#root' do
7
+ it 'should be a Pathname class' do
8
+ expect(Sails.root).to be_a(Pathname)
9
+ end
10
+
11
+ it 'should support Sails.root.join' do
12
+ expect(Sails.root.join("aaa").to_s).to eq File.join(Dir.pwd, "spec/dummy/aaa")
13
+ end
14
+
15
+ it 'should work' do
16
+ expect(Sails.root.to_s).to eq File.join(Dir.pwd, "spec/dummy")
17
+ end
18
+ end
19
+
20
+ describe '#logger' do
21
+ it 'should be a Logger class' do
22
+ expect(Sails.logger).to be_a(Logger)
23
+ end
24
+ end
25
+
26
+ describe '#config' do
27
+ it 'should work' do
28
+ expect(Sails.config).to be_a(Hash)
29
+ expect(Sails.config.autoload_paths).to be_a(Array)
30
+ end
31
+
32
+ describe 'Real config' do
33
+ it { expect(Sails.config.app_name).to eq 'hello' }
34
+ it { expect(Sails.config.host).to eq '1.1.1.1' }
35
+ it { expect(Sails.config.port).to eq 1000 }
36
+ it { expect(Sails.config.protocol).to eq :binary }
37
+ it { expect(Sails.config.thread_size).to eq 20 }
38
+ it { expect(Sails.config.i18n.default_locale).to eq :'zh-TW' }
39
+ it { expect(Sails.config.autoload_paths).to include("app/bar") }
40
+ end
41
+ end
42
+
43
+ describe '#cache' do
44
+ it { expect(Sails.cache).to be_a(ActiveSupport::Cache::DalliStore) }
45
+ it { expect(Sails.cache).to respond_to(:read, :write, :delete, :clear) }
46
+ end
47
+
48
+ describe '#thrift_protocol_class' do
49
+ it 'should work' do
50
+ allow(Sails.config).to receive(:protocol).and_return(:binary)
51
+ expect(Sails.thrift_protocol_class).to eq ::Thrift::BinaryProtocolFactory
52
+ allow(Sails.config).to receive(:protocol).and_return(:compact)
53
+ expect(Sails.thrift_protocol_class).to eq ::Thrift::CompactProtocolFactory
54
+ allow(Sails.config).to receive(:protocol).and_return(:json)
55
+ expect(Sails.thrift_protocol_class).to eq ::Thrift::JsonProtocolFactory
56
+ allow(Sails.config).to receive(:protocol).and_return(:xxx)
57
+ expect(Sails.thrift_protocol_class).to eq ::Thrift::BinaryProtocolFactory
58
+ end
59
+ end
60
+
61
+ describe '#reload!' do
62
+ it 'should work' do
63
+ s1 = Sails.service
64
+ Sails.reload!
65
+ expect(Sails.service).not_to eq s1
66
+ # TODO: test reload autoload_paths
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe 'Service' do
4
+ class SimpleService < Sails::Service::Base
5
+ def foo
6
+ end
7
+
8
+ def bar
9
+ end
10
+
11
+ private
12
+ def dar
13
+ end
14
+ end
15
+
16
+ let(:simple) { SimpleService.new }
17
+
18
+ describe '.raise_error' do
19
+ it { expect(simple).to respond_to(:raise_error) }
20
+ it {
21
+ expect { simple.raise_error(11,'foo') }.to raise_error do |error|
22
+ expect(error).to be_a(Sails::Service::Exception)
23
+ expect(error.code).to eq 11
24
+ expect(error.message).to eq 'foo'
25
+ end
26
+ }
27
+ end
28
+
29
+ describe '.action_methods' do
30
+ it { expect(simple.action_methods).to include("foo", "bar") }
31
+ it { expect(simple.action_methods.size).to eq 2 }
32
+ it { expect(simple.action_methods).not_to include("dar") }
33
+ end
34
+
35
+ describe '.logger' do
36
+ it { expect(simple.logger).to eq Sails.logger }
37
+ end
38
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,26 @@
1
1
  require_relative "../lib/sails"
2
2
 
3
3
  # Force set Sails root to spec/dummy
4
- Sails.root = File.expand_path("../dummy", __FILE__)
4
+ Sails.root = File.expand_path("../dummy", __FILE__)
5
+ $LOAD_PATH.unshift Sails.root
6
+
7
+ # for test Sails config
8
+ module Sails
9
+ config.app_name = 'hello'
10
+ config.host = '1.1.1.1'
11
+ config.port = 1000
12
+ config.i18n.default_locale = 'zh-TW'
13
+ config.autoload_paths += %W(app/bar)
14
+ config.cache_store = [:dalli_store, '127.0.0.1']
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+
19
+ config.before(:each) do
20
+ end
21
+
22
+ config.after(:each) do
23
+ end
24
+
25
+ config.raise_errors_for_deprecations!
26
+ end