sails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f659284fee2c294ceb15bf368ea80f61c8331fc3
4
- data.tar.gz: 0f52d780eb04bafa7b4a63ef9d5460fce2ea8c2a
3
+ metadata.gz: 9910e5d27ef628ca22aec968edd2ed2a94604295
4
+ data.tar.gz: 6e72d2491ad1950a6a2e6946205a6ac84e266914
5
5
  SHA512:
6
- metadata.gz: 717ac7ec1138af2afe82d8460af64c0e5cafe6573fbe8e1b198124823074eaceba4514a93e9ca1da316c22b4eb9ec621468c53914f6721df3b583d664973619d
7
- data.tar.gz: 3aa695a566367311681b0439a7e16c48171c2595b228b3775411139cd6583f88f08518a1319e39f4dc77121e4234ba42c024d29a7188616d76cf39e5b05d42ba
6
+ metadata.gz: 91c9dc674800da1fcb081bafa44438b5a673f68300df5ddbfdbc207b1c216de6354972a9dcb9866db5af245bf18dbb2d51b983b85c9c89c53e52768116561840
7
+ data.tar.gz: df6d3b9110cf3d8c3c71e31ae5c0f0c9e0744b2cd6826dd98517356b0e8b2835637f5565904e186e292aa118d33d8df7d59a7326280ec5ad1e7ee44688cd9c7e
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.1.4
5
+
6
+ script: bundle exec rspec spec
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ ## 0.1.1
2
+
3
+ - Add `sails s`, `sails c` commands.
4
+ - Refactor service layer, use class to instead module.
5
+ - Support to custom Thrift protocol with `config.protocol = :binary`.
6
+ - Fix ThriftServer::OperationFailed not found error.
7
+ - Implement Master Process to manage and protect Child Process, keep it running/restart/stop, like Unicorn.
8
+ - Add Sails.reload! to reload cache classes.
9
+ - Sails console start with IRB class, and support `reload!`,`service` methods in console.
10
+
11
+ ## 0.1.0 / 2014-12-9
12
+
13
+ - First version release.
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+ gem 'dalli'
4
5
  gem 'rspec'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sails (0.1.0)
4
+ sails (0.1.1)
5
5
  activesupport (>= 3.2.0)
6
6
  thor
7
7
  thrift (>= 0.9.0)
@@ -15,6 +15,7 @@ GEM
15
15
  minitest (~> 5.1)
16
16
  thread_safe (~> 0.1)
17
17
  tzinfo (~> 1.1)
18
+ dalli (2.7.1)
18
19
  diff-lcs (1.2.5)
19
20
  i18n (0.6.11)
20
21
  json (1.8.1)
@@ -41,5 +42,6 @@ PLATFORMS
41
42
  ruby
42
43
 
43
44
  DEPENDENCIES
45
+ dalli
44
46
  rspec
45
47
  sails!
data/README.md CHANGED
@@ -3,17 +3,34 @@ Sails
3
3
 
4
4
  Sails, create [Thrift](thrift.apache.org) app server like Rails.
5
5
 
6
+ [![Build Status](https://travis-ci.org/huacnlee/sails.svg)](https://travis-ci.org/huacnlee/sails) [![Gem Version](https://badge.fury.io/rb/sails.svg)](http://badge.fury.io/rb/sails)
7
+
8
+ ## Features
9
+
10
+ - Rails style Thrift server;
11
+ - Nonblocking mode;
12
+ - I18n support;
13
+
6
14
  ## Installation
7
15
 
8
- ```
16
+ ```bash
9
17
  $ gem install sails
18
+ $ sails -h
19
+ ENV: development
20
+ Commands:
21
+ sails help [COMMAND] # Describe available commands or one specific command
22
+ sails new APP_NAME # Create a project
23
+ sails restart # Restart Thrift server
24
+ sails start # Start Thrift server
25
+ sails stop # Stop Thrift server
26
+ sails version # Show Sails version
10
27
  ```
11
28
 
12
29
  ## Usage
13
30
 
14
31
  ### Create new project
15
32
 
16
- ```
33
+ ```bash
17
34
  $ sails new foo
18
35
  $ cd foo
19
36
  $ sails start
@@ -27,7 +44,36 @@ You can edit Thrift IDL in `app_name.thrift`, and then generate it to ruby sourc
27
44
  $ rake gen
28
45
  ```
29
46
 
47
+ ## Client Connect
48
+
49
+ ```ruby
50
+ require "app/services/gen-rb/you_app_name"
51
+ @transport ||= Thrift::FramedTransport.new(::Thrift::Socket.new('127.0.0.1', 4000, 10))
52
+ @protocol ||= Thrift::BinaryProtocol.new(@transport)
53
+ @client ||= Thrift::YouAppName::Client.new(@protocol)
54
+ @transport.open()
55
+ puts @client.ping()
56
+ => Ping pong
57
+ ```
58
+
59
+ ## Deploy
60
+
61
+ ```
62
+ $ sails s --daemon
63
+ $ ps aux
64
+ jason 2408 0.1 0.2 2648176 13532 s003 S 12:14下午 0:00.02 you_sails_app
65
+ jason 2407 0.0 0.0 2604916 1016 s003 S 12:14下午 0:00.00 you_sails_app [master]
66
+ $ sails restart
67
+ $ sails stop
68
+ ```
30
69
 
31
70
  ## API Documents
32
71
 
33
- http://rdoc.info/github/huacnlee/sails
72
+ http://www.rubydoc.info/github/huacnlee/sails
73
+
74
+
75
+ ## TODO
76
+
77
+ - [ ] Reload without restart;
78
+ - [ ] Scaffold generator;
79
+ - [X] Multi processes;
data/lib/sails/base.rb CHANGED
@@ -1,38 +1,71 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
- require 'active_support/all'
4
- require 'i18n'
5
- require 'thrift'
6
- require 'yaml'
7
-
8
1
  Bundler.require()
9
2
 
10
3
  module Sails
11
4
  extend ActiveSupport::Autoload
5
+
6
+ autoload :Config
12
7
 
13
- class Config
14
- include ActiveSupport::Configurable
15
- end
16
-
8
+ # Sails.config
9
+ #
10
+ # Configs with Sails
11
+ # For example:
12
+ #
13
+ # Sails.config.app_name
14
+ # # => returns "You App Name"
15
+ #
16
+ # Sails.config.autoload_paths
17
+ # # => returns ['app/models','app/models/concerns', 'app/workers', 'app/services'...]
18
+ #
19
+ # Sails.config.cache_store = [:dalli_store, '127.0.0.1', { pool_size: 100 }]
20
+ # Sails.config.i18n.default_locale = 'zh-CN'
21
+ #
17
22
  def self.config
18
23
  return @config if defined?(@config)
19
24
  @config = Config.new.config
20
- @config.app_name = "Sails"
21
- @config.cache_store = [:memory_store]
22
- @config.autoload_paths = %W(app/models app/models/concerns app/workers app/services app/services/concerns lib)
23
- @config.i18n = I18n
24
- @config.i18n.load_path += Dir[Sails.root.join('config', 'locales', '*.{rb,yml}').to_s]
25
- @config.i18n.default_locale = :en
26
- @config.thrift_processor = nil
27
- @config
28
25
  end
29
26
 
27
+ # Sails.cache
28
+ #
29
+ # An abstract cache store class. There are multiple cache store
30
+ # implementations, each having its own additional features. See the classes
31
+ # under the ActiveSupport::Cache module, e.g.
32
+ # ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most
33
+ # popular cache store for large production websites.
34
+ #
35
+ # Some implementations may not support all methods beyond the basic cache
36
+ # methods of +fetch+, +write+, +read+, +exist?+, and +delete+.
37
+ #
38
+ # ActiveSupport::Cache::Store can store any serializable Ruby object.
39
+ #
40
+ # Sails.cache.read('city') # => nil
41
+ # Sails.cache.write('city', "Duckburgh")
42
+ # Sails.cache.read('city') # => "Duckburgh"
43
+ #
44
+ # Keys are always translated into Strings and are case sensitive. When an
45
+ # object is specified as a key and has a +cache_key+ method defined, this
46
+ # method will be called to define the key. Otherwise, the +to_param+
47
+ # method will be called. Hashes and Arrays can also be used as keys. The
48
+ # elements will be delimited by slashes, and the elements within a Hash
49
+ # will be sorted by key so they are consistent.
50
+ #
51
+ # Sails.cache.read('city') == Sails.cache.read(:city) # => true
52
+ #
53
+ # Nil values can be cached.
30
54
  def self.cache
31
55
  return @cache if defined?(@cache)
32
56
  @cache = ActiveSupport::Cache.lookup_store(self.config.cache_store)
33
57
  end
34
58
 
35
59
  # Sails.root
60
+ #
61
+ # This method returns a Pathname object which handles paths starting with a / as absolute (starting from the root of the filesystem). Compare:
62
+ #
63
+ # For example:
64
+ # >> Sails.root
65
+ # => #<Pathname:/some/path/to/project>
66
+ # >> Sails.root + "file"
67
+ # => #<Pathname:/some/path/to/project/file>
68
+ #
36
69
  def self.root
37
70
  @root ||= Pathname.new(Dir.pwd)
38
71
  end
@@ -41,11 +74,30 @@ module Sails
41
74
  @root = Pathname.new(root)
42
75
  end
43
76
 
44
- # Sails.env.development?
77
+ # Sails.env
78
+ #
79
+ # returns a string representing the current Sails environment.
80
+ # This will read from ENV['RAILS_ENV'] like Rails
81
+ #
82
+ # For example:
83
+ #
84
+ # Sails.env # in development mode
85
+ # => "development"
86
+ # Sails.env.development?
87
+ # => true
88
+ #
45
89
  def self.env
46
90
  @env ||= ActiveSupport::StringInquirer.new(ENV['RAILS_ENV'].presence || 'development')
47
91
  end
48
92
 
93
+ # Sails.logger
94
+ #
95
+ # returns a Logger class
96
+ # For example:
97
+ #
98
+ # Sails.logger.info "Hello world"
99
+ # Sails.logger.error "Hello world"
100
+ #
49
101
  def self.logger
50
102
  return @logger if defined?(@logger)
51
103
  @logger = Logger.new(File.join(Sails.root, "log/#{self.env}.log"))
@@ -56,21 +108,6 @@ module Sails
56
108
  @logger
57
109
  end
58
110
 
59
- def self.stdout_logger
60
- return @stdout_logger if defined?(@stdout_logger)
61
- @stdout_logger = Logger.new(STDOUT)
62
- @stdout_logger.formatter = proc { |severity, datetime, progname, msg|
63
- "#{msg}\n"
64
- }
65
- @stdout_logger
66
- end
67
-
68
- def self.load_initialize
69
- Dir["#{Sails.root}/config/initializers/*.rb"].each do |f|
70
- require f
71
- end
72
- end
73
-
74
111
  def self.init
75
112
  $:.unshift self.root.join("lib")
76
113
  # init root
@@ -80,7 +117,7 @@ module Sails
80
117
 
81
118
  ActiveSupport::Dependencies.autoload_paths += Sails.config.autoload_paths
82
119
 
83
- env_file = self.root.join('config/environments/',Sails.env)
120
+ env_file = self.root.join('config/environments/',Sails.env + ".rb")
84
121
  if File.exist?(env_file)
85
122
  require env_file
86
123
  end
@@ -93,31 +130,80 @@ module Sails
93
130
  @inited = true
94
131
  end
95
132
 
133
+ # Sails.service
134
+ #
135
+ # return a instance of Sails Service layer
136
+ #
137
+ # for example:
138
+ #
139
+ # class UsersService < Sails::Service::Base
140
+ # def check_name_exist?(name)
141
+ # User.check_name_exist?(name)
142
+ # end
143
+ # end
144
+ #
145
+ # class UsersServiceTest
146
+ # def test_check_name_exist?
147
+ # assert_equal(Sails.service.check_name_exist?(name), true)
148
+ # end
149
+ # end
150
+ #
151
+ def self.service
152
+ @service ||= Sails::Service::Interface.new
153
+ end
154
+
155
+ # Force reload Sails cache classes in config.autoload_paths
156
+ def self.reload!(opts = {})
157
+ force = opts[:force] || false
158
+ if force || config.cache_classes == false
159
+ @service = nil
160
+ ActiveSupport::Dependencies.clear
161
+ reload_server!
162
+ end
163
+ end
164
+
165
+ def self.reload_server!
166
+ if @server
167
+ new_processor = config.processor.new(self.service)
168
+ @server.instance_variable_set(:@processor, new_processor)
169
+ end
170
+ end
171
+
96
172
  def self.start!(type)
97
- if type == "thread"
173
+ @server_type = type
174
+ if @server_type == "thread"
98
175
  start_thread_pool_server!
99
176
  else
100
177
  start_non_blocking_server!
101
178
  end
102
179
  end
103
-
104
- def self.service
105
- @service ||= Sails::Service.new
180
+
181
+ def self.thrift_protocol_class
182
+ case config.protocol
183
+ when :compact
184
+ return ::Thrift::CompactProtocolFactory
185
+ when :json
186
+ return ::Thrift::JsonProtocolFactory
187
+ else
188
+ return ::Thrift::BinaryProtocolFactory
189
+ end
106
190
  end
107
191
 
192
+ # Start Thrift Server with Threaded mode
193
+ #
108
194
  def self.start_thread_pool_server!
109
- transport = ::Thrift::ServerSocket.new(nil, config.thrift_thread_port)
195
+ transport = ::Thrift::ServerSocket.new(nil, config.thread_port)
110
196
  transport_factory = ::Thrift::BufferedTransportFactory.new
111
- protocol_factory = ::Thrift::BinaryProtocolFactory.new
112
- processor = config.thrift_processor.new(self.service)
113
- server = ::Thrift::ThreadPoolServer.new(processor, transport, transport_factory, protocol_factory, Setting.pool_size)
197
+ protocol_factory = thrift_protocol_class.new
198
+ processor = config.processor.new(self.service)
199
+ @server = ::Thrift::ThreadPoolServer.new(processor, transport, transport_factory, protocol_factory, config.thread_size)
114
200
 
115
201
  puts "Boot on: #{Sails.root}"
116
202
  puts "[#{Time.now}] Starting the Sails with ThreadPool size: #{Setting.pool_size}..."
117
- puts "serve: #{config.thrift_host}:#{config.thrift_thread_port}"
203
+ puts "serve: 127.0.0.1:#{config.thread_port}"
118
204
 
119
205
  begin
120
- server.serve
206
+ @server.serve
121
207
  rescue => e
122
208
  puts "Start thrift server exception! \n #{e.inspect}"
123
209
  puts e.backtrace
@@ -129,19 +215,21 @@ module Sails
129
215
  end
130
216
  end
131
217
 
218
+ # Start Thrift Server with Event drive mode
132
219
  def self.start_non_blocking_server!
133
- transport = ::Thrift::ServerSocket.new(nil, config.thrift_port)
220
+ transport = ::Thrift::ServerSocket.new(nil, config.port)
134
221
  transport_factory = ::Thrift::FramedTransportFactory.new
135
- protocol_factory = ::Thrift::BinaryProtocolFactory.new
136
- processor = config.thrift_processor.new(self.service)
137
- server = ::Thrift::NonblockingServer.new(processor, transport, transport_factory)
222
+ protocol_factory = thrift_protocol_class.new
223
+ processor = config.processor.new(self.service)
224
+ @server = ::Thrift::NonblockingServer.new(processor, transport, transport_factory, protocol_factory, config.thread_size)
138
225
 
139
226
  puts "Boot on: #{Sails.root}"
140
227
  puts "[#{Time.now}] Starting the Sails with NonBlocking..."
141
- puts "serve: #{config.thrift_host}:#{config.thrift_port}"
228
+ puts "Protocol: #{thrift_protocol_class.name}"
229
+ puts "serve: 127.0.0.1:#{config.port}"
142
230
 
143
231
  begin
144
- server.serve
232
+ @server.serve
145
233
  rescue => e
146
234
  puts "Start thrift server exception! \n #{e.inspect}"
147
235
  puts e.backtrace
@@ -152,4 +240,22 @@ module Sails
152
240
  end
153
241
  end
154
242
  end
155
- end
243
+
244
+ private
245
+ def self.stdout_logger
246
+ return @stdout_logger if defined?(@stdout_logger)
247
+ @stdout_logger = Logger.new(STDOUT)
248
+ @stdout_logger.formatter = proc { |severity, datetime, progname, msg|
249
+ "#{msg}\n"
250
+ }
251
+ @stdout_logger
252
+ end
253
+
254
+ def self.load_initialize
255
+ Dir["#{Sails.root}/config/initializers/*.rb"].each do |f|
256
+ require f
257
+ end
258
+ end
259
+ end
260
+
261
+ Sails.init()
data/lib/sails/cli.rb CHANGED
@@ -2,76 +2,12 @@ require 'thor'
2
2
  require 'sails/version'
3
3
 
4
4
  module Sails
5
- class ThreadDaemon
6
- class << self
7
- attr_accessor :options, :mode, :app_name, :pid_file
8
-
9
- def init(opts = {})
10
- self.app_name = Sails.config.app_name
11
- self.mode = opts[:mode]
12
- self.app_name = "#{ThreadDaemon.app_name}-thread" if self.mode == "thread"
13
- self.pid_file = Sails.root.join("tmp/#{ThreadDaemon.app_name}.pid")
14
- self.options = options
15
- end
16
-
17
- def read_pid
18
- if !File.exist?(pid_file)
19
- return nil
20
- end
21
-
22
- pid = File.open(pid_file).read.to_i
23
- begin
24
- Process.getpgid(pid)
25
- rescue
26
- pid = nil
27
- end
28
- return pid
29
- end
30
-
31
- def start_process(options = {})
32
- $PROGRAM_NAME = self.app_name
33
- old_pid = read_pid
34
- if old_pid != nil
35
- puts "Current have #{app_name} process in running on pid #{old_pid}"
36
- return
37
- end
38
-
39
- pid = fork do
40
- Sails.start!(self.mode)
41
- end
42
- File.open(pid_file, "w+") do |f|
43
- f.puts pid
44
- end
45
-
46
- puts "Started #{app_name} on pid: #{pid}"
47
-
48
- if options[:daemon] == false
49
- Process.waitpid(pid)
50
- end
51
- end
52
-
53
- def stop_process
54
- pid = read_pid
55
- if pid == nil
56
- puts "#{app_name} process not found, pid #{pid}"
57
- return
58
- end
59
-
60
- print "Stopping #{app_name} with pid: #{pid}..."
61
- begin
62
- Process.kill("QUIT", pid)
63
- ensure
64
- File.delete(pid_file)
65
- end
66
- puts " [Done]"
67
- end
68
- end
69
- end
70
-
71
5
  class CLI < Thor
72
6
  include Thor::Actions
73
7
 
74
8
  map '-v' => :version
9
+ map 's' => :start
10
+ map 'c' => :console
75
11
 
76
12
  def self.source_root
77
13
  __dir__
@@ -83,27 +19,36 @@ module Sails
83
19
  end
84
20
  }
85
21
 
22
+ # sails start
23
+ #
24
+ # Start a thrift app server
86
25
  option :daemon, type: :boolean, default: false
87
26
  option :mode, default: 'nonblocking'
88
27
  desc "start", "Start Thrift server"
89
28
  def start()
90
- ThreadDaemon.init(mode: options[:mode])
91
- ThreadDaemon.start_process(daemon: options[:daemon])
29
+ Sails::Daemon.init(mode: options[:mode])
30
+ Sails::Daemon.start_process(daemon: options[:daemon])
92
31
  end
93
32
 
33
+ # sails stop
34
+ #
35
+ # Stop thrift app server
94
36
  option :mode, default: 'nonblocking'
95
37
  desc "stop", "Stop Thrift server"
96
38
  def stop()
97
- ThreadDaemon.init(mode: options[:mode])
98
- ThreadDaemon.stop_process
39
+ Sails::Daemon.init(mode: options[:mode])
40
+ Sails::Daemon.stop_process
99
41
  end
100
-
42
+
43
+ # sails restart
44
+ #
45
+ # Restart thrift app server
101
46
  option :mode, default: 'nonblocking'
102
47
  desc "restart", "Restart Thrift server"
103
48
  def restart()
104
- ThreadDaemon.init(mode: options[:mode])
105
- ThreadDaemon.stop_process
106
- ThreadDaemon.start_process(daemon: true)
49
+ Sails::Daemon.init(mode: options[:mode])
50
+ Sails::Daemon.stop_process
51
+ Sails::Daemon.start_process(daemon: true)
107
52
  end
108
53
 
109
54
  desc "new APP_NAME", "Create a project"
@@ -125,6 +70,11 @@ module Sails
125
70
  @rel_dir = nil
126
71
  end
127
72
 
73
+ desc "console", "Enter Sails console"
74
+ def console
75
+ Sails::Console.start(Sails.root.join("config/application.rb"))
76
+ end
77
+
128
78
  desc "version", "Show Sails version"
129
79
  def version
130
80
  puts "Sails #{Sails.version}"
@@ -0,0 +1,25 @@
1
+ module Sails
2
+ class Config
3
+ include ActiveSupport::Configurable
4
+
5
+ def initialize
6
+ init_defaults!
7
+ end
8
+
9
+ def init_defaults!
10
+ config.app_name = "Sails"
11
+ config.cache_store = [:memory_store]
12
+ config.autoload_paths = %W(app/models app/models/concerns app/workers app/services app/services/concerns lib)
13
+ config.i18n = I18n
14
+ config.i18n.load_path += Dir[Sails.root.join('config', 'locales', '*.{rb,yml}').to_s]
15
+ config.i18n.default_locale = :en
16
+ config.cache_classes = false
17
+
18
+ config.port = 4000
19
+ config.thread_port = 4001
20
+ config.processor = nil
21
+ config.thread_size = 20
22
+ config.protocol = :binary
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ require "irb"
2
+ require "irb/ext/loader"
3
+
4
+ module Sails
5
+ module ConsoleMethods
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ end
10
+
11
+ def service
12
+ Sails.service
13
+ end
14
+
15
+ def reload!
16
+ puts "Reloading..."
17
+ Sails.reload!(force: true)
18
+ return true
19
+ end
20
+ end
21
+
22
+ class Console
23
+ class << self
24
+ def start(app_path)
25
+ new(app_path).start
26
+ end
27
+ end
28
+
29
+ def initialize(app_path)
30
+ @app_path = app_path
31
+ end
32
+
33
+ def start
34
+ puts "Loading #{Sails.env} environment (Sails #{Sails.version})"
35
+ IRB.conf[:IRB_NAME] = "Sails console"
36
+ require @app_path
37
+ ARGV.clear
38
+ if defined?(IRB::ExtendCommandBundle)
39
+ IRB::ExtendCommandBundle.send :include, Sails::ConsoleMethods
40
+ end
41
+ IRB.start()
42
+ end
43
+ end
44
+ end