pomelo-citrus 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +20 -0
- data/Rakefile +0 -0
- data/citrus.gemspec +35 -0
- data/lib/citrus.rb +18 -0
- data/lib/citrus/application.rb +237 -0
- data/lib/citrus/citrus.rb +27 -0
- data/lib/citrus/common/remote/backend/msg_remote.rb +57 -0
- data/lib/citrus/common/remote/frontend/channel_remote.rb +73 -0
- data/lib/citrus/common/remote/frontend/session_remote.rb +108 -0
- data/lib/citrus/common/service/backend_session_service.rb +265 -0
- data/lib/citrus/common/service/channel_service.rb +485 -0
- data/lib/citrus/common/service/connection_service.rb +71 -0
- data/lib/citrus/common/service/filter_service.rb +92 -0
- data/lib/citrus/common/service/handler_service.rb +63 -0
- data/lib/citrus/common/service/session_service.rb +446 -0
- data/lib/citrus/components/backend_session.rb +32 -0
- data/lib/citrus/components/channel.rb +33 -0
- data/lib/citrus/components/component.rb +19 -0
- data/lib/citrus/components/connection.rb +48 -0
- data/lib/citrus/components/connector.rb +265 -0
- data/lib/citrus/components/master.rb +40 -0
- data/lib/citrus/components/monitor.rb +48 -0
- data/lib/citrus/components/proxy.rb +195 -0
- data/lib/citrus/components/push_scheduler.rb +74 -0
- data/lib/citrus/components/remote.rb +71 -0
- data/lib/citrus/components/server.rb +61 -0
- data/lib/citrus/components/session.rb +41 -0
- data/lib/citrus/connectors/commands/handshake.rb +22 -0
- data/lib/citrus/connectors/commands/heartbeat.rb +22 -0
- data/lib/citrus/connectors/commands/kick.rb +22 -0
- data/lib/citrus/connectors/common/coder.rb +21 -0
- data/lib/citrus/connectors/common/handler.rb +21 -0
- data/lib/citrus/connectors/ws_connector.rb +110 -0
- data/lib/citrus/connectors/ws_socket.rb +75 -0
- data/lib/citrus/filters/handler/handler_filter.rb +19 -0
- data/lib/citrus/filters/handler/too_busy.rb +16 -0
- data/lib/citrus/filters/rpc/rpc_filter.rb +19 -0
- data/lib/citrus/filters/rpc/too_busy.rb +16 -0
- data/lib/citrus/master/master.rb +60 -0
- data/lib/citrus/master/starter.rb +73 -0
- data/lib/citrus/master/watchdog.rb +83 -0
- data/lib/citrus/modules/console.rb +45 -0
- data/lib/citrus/modules/console_module.rb +35 -0
- data/lib/citrus/modules/master_watcher.rb +88 -0
- data/lib/citrus/modules/monitor_watcher.rb +86 -0
- data/lib/citrus/monitor/monitor.rb +61 -0
- data/lib/citrus/push_schedulers/buffer.rb +16 -0
- data/lib/citrus/push_schedulers/direct.rb +76 -0
- data/lib/citrus/server/server.rb +327 -0
- data/lib/citrus/util/app_util.rb +203 -0
- data/lib/citrus/util/constants.rb +19 -0
- data/lib/citrus/util/countdown_latch.rb +42 -0
- data/lib/citrus/util/events.rb +14 -0
- data/lib/citrus/util/module_util.rb +68 -0
- data/lib/citrus/util/path_util.rb +50 -0
- data/lib/citrus/util/utils.rb +49 -0
- data/lib/citrus/version.rb +7 -0
- metadata +241 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Connectors
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Connectors
|
10
|
+
# Commands
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Commands
|
14
|
+
# HeartBeat
|
15
|
+
#
|
16
|
+
#
|
17
|
+
class HeartBeat
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Connectors
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Connectors
|
10
|
+
# Commands
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Commands
|
14
|
+
# Kick
|
15
|
+
#
|
16
|
+
#
|
17
|
+
class Kick
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Connectors
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Connectors
|
10
|
+
# Common
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Common
|
14
|
+
# Coder
|
15
|
+
#
|
16
|
+
#
|
17
|
+
module Coder
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Connectors
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Connectors
|
10
|
+
# Common
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Common
|
14
|
+
# Handler
|
15
|
+
#
|
16
|
+
#
|
17
|
+
module Handler
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
require 'json'
|
6
|
+
require 'websocket-eventmachine-server'
|
7
|
+
require 'citrus/connectors/ws_socket'
|
8
|
+
|
9
|
+
module Citrus
|
10
|
+
# Connectors
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Connectors
|
14
|
+
# WsConnector
|
15
|
+
#
|
16
|
+
#
|
17
|
+
class WsConnector
|
18
|
+
include Utils::EventEmitter
|
19
|
+
|
20
|
+
# Create a new websocket connector
|
21
|
+
#
|
22
|
+
# @param [Integer] port
|
23
|
+
# @param [String] host
|
24
|
+
# @param [Hash] args
|
25
|
+
def initialize port, host, args={}
|
26
|
+
@port = port
|
27
|
+
@host = host
|
28
|
+
@args = args
|
29
|
+
|
30
|
+
@heartbeats = args[:heartbeats] || true
|
31
|
+
@heartbeat_timeout = args[:heartbeat_timeout] || 0.06
|
32
|
+
@heartbeat_interval = args[:heartbeat_interval] || 0.025
|
33
|
+
|
34
|
+
@cur_id = 0
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start the connector to listen to the specified port
|
38
|
+
def start &block
|
39
|
+
begin
|
40
|
+
@server = WebSocket::EventMachine::Server.start(:host => @host, :port => @port) { |ws|
|
41
|
+
ws.onopen {
|
42
|
+
ws_socket = WsSocket.new @cur_id, ws
|
43
|
+
@cur_id += 1
|
44
|
+
emit :connection, ws_socket
|
45
|
+
ws_socket.on(:closing) { |reason|
|
46
|
+
ws_socket.send({ 'route' => 'on_kick', 'reason' => reason })
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
rescue => err
|
51
|
+
end
|
52
|
+
EM.next_tick { block_given? and yield }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Stop the connector
|
56
|
+
#
|
57
|
+
# @param [Boolean] force
|
58
|
+
def stop force=false, &block
|
59
|
+
@server.close
|
60
|
+
EM.next_tick { block_given? and yield }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Encode message
|
64
|
+
#
|
65
|
+
# @param [Integer, NilClass] req_id
|
66
|
+
# @param [String] route
|
67
|
+
# @param [Object] msg
|
68
|
+
def encode req_id, route, msg
|
69
|
+
if req_id
|
70
|
+
compose_response req_id, route, msg
|
71
|
+
else
|
72
|
+
componse_push route, msg
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Decode message
|
77
|
+
#
|
78
|
+
# @param [String] msg
|
79
|
+
def decode msg
|
80
|
+
begin
|
81
|
+
JSON.parse msg
|
82
|
+
rescue => err
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Compose response message
|
89
|
+
#
|
90
|
+
# @param [Integer] msg_id
|
91
|
+
# @param [String] route
|
92
|
+
# @param [Hash] msg_body
|
93
|
+
#
|
94
|
+
# @private
|
95
|
+
def compose_response msg_id, route, msg_body
|
96
|
+
{ 'id' => msg_id, 'body' => msg_body }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Compose push message
|
100
|
+
#
|
101
|
+
# @param [String] route
|
102
|
+
# @param [Hash] msg_body
|
103
|
+
#
|
104
|
+
# @private
|
105
|
+
def compose_push route, msg_body
|
106
|
+
{ 'route' => route, 'body' => msg_body }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 25 July 2014
|
4
|
+
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Citrus
|
8
|
+
# Connectors
|
9
|
+
#
|
10
|
+
#
|
11
|
+
module Connectors
|
12
|
+
# WsSocket
|
13
|
+
#
|
14
|
+
#
|
15
|
+
class WsSocket
|
16
|
+
include Utils::EventEmitter
|
17
|
+
|
18
|
+
attr_reader :id, :remote_address
|
19
|
+
|
20
|
+
# Create a new ws socket
|
21
|
+
#
|
22
|
+
# @param [Integer] id
|
23
|
+
# @param [Object] ws
|
24
|
+
def initialize id, ws
|
25
|
+
@id = id
|
26
|
+
@ws = ws
|
27
|
+
|
28
|
+
port, ip = Socket.unpack_sockaddr_in @ws.get_peername
|
29
|
+
@remote_address = {
|
30
|
+
:port => port,
|
31
|
+
:ip => ip
|
32
|
+
}
|
33
|
+
|
34
|
+
@ws.onclose { emit :disconnect }
|
35
|
+
@ws.onerror { |err| emit :error }
|
36
|
+
@ws.onmessage { |msg, type| emit :message, msg }
|
37
|
+
|
38
|
+
@state = :state_inited
|
39
|
+
end
|
40
|
+
|
41
|
+
# Send message to the client
|
42
|
+
#
|
43
|
+
# @param [Hash] msg
|
44
|
+
def send msg
|
45
|
+
return unless @state == :state_inited
|
46
|
+
@ws.send msg.to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
# Disconnect the client
|
50
|
+
def disconnect
|
51
|
+
return if @state == :state_closed
|
52
|
+
@state = :state_closed
|
53
|
+
@ws.close
|
54
|
+
end
|
55
|
+
|
56
|
+
# Batch version for send
|
57
|
+
#
|
58
|
+
# @param [Array] msgs
|
59
|
+
def send_batch msgs
|
60
|
+
@ws.send encode_batch(msgs)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# Encode batch messages
|
66
|
+
#
|
67
|
+
# @param [Array] msgs
|
68
|
+
#
|
69
|
+
# @private
|
70
|
+
def encode_batch msgs
|
71
|
+
msgs.to_json
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 21 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# HandlerFilter
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class HandlerFilter
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
#
|
13
|
+
#
|
14
|
+
#
|
15
|
+
def initialize
|
16
|
+
@name = ''
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/filters/handler/handler_filter'
|
6
|
+
|
7
|
+
module Citrus
|
8
|
+
# TooBusy
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class TooBusy < HandlerFilter
|
12
|
+
def initialize
|
13
|
+
@name = 'too_busy'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 21 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# RpcFilter
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class RpcFilter
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
#
|
13
|
+
#
|
14
|
+
#
|
15
|
+
def initialize
|
16
|
+
@name = ''
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/filters/rpc/rpc_filter'
|
6
|
+
|
7
|
+
module Citrus
|
8
|
+
# TooBusy
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class TooBusy < RpcFilter
|
12
|
+
def initialize
|
13
|
+
@name = 'too_busy'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 18 July 2014
|
4
|
+
|
5
|
+
require 'citrus/master/starter'
|
6
|
+
require 'citrus/util/module_util'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Master
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Master
|
13
|
+
# Master
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Master
|
17
|
+
include Starter
|
18
|
+
include Utils::ModuleUtil
|
19
|
+
|
20
|
+
# Create a new master
|
21
|
+
#
|
22
|
+
# @param [Object] app
|
23
|
+
# @param [Hash] args
|
24
|
+
def initialize app, args={}
|
25
|
+
@app = app
|
26
|
+
@master = true
|
27
|
+
@master_info = app.master
|
28
|
+
@modules = []
|
29
|
+
@close_watcher = args[:close_watcher]
|
30
|
+
@console_service = CitrusAdmin::ConsoleService.create_master_console(
|
31
|
+
args.merge({
|
32
|
+
:env => app.env,
|
33
|
+
:port => @master_info[:port]
|
34
|
+
})
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Start master
|
39
|
+
def start &block
|
40
|
+
register_default_modules
|
41
|
+
load_modules
|
42
|
+
@console_service.start { |err|
|
43
|
+
exit if err
|
44
|
+
start_modules { |err|
|
45
|
+
if err
|
46
|
+
block_given? and yield err
|
47
|
+
return
|
48
|
+
end
|
49
|
+
run_servers
|
50
|
+
block_given? and yield
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
# Stop master
|
56
|
+
def stop &block
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 19 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Master
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Master
|
10
|
+
# Starter
|
11
|
+
#
|
12
|
+
#
|
13
|
+
module Starter
|
14
|
+
include Utils
|
15
|
+
|
16
|
+
# Run servers
|
17
|
+
def run_servers
|
18
|
+
condition = @app.start_id || @app.type
|
19
|
+
case condition
|
20
|
+
when :master
|
21
|
+
when :all
|
22
|
+
@app.servers_map.each { |server_id, server|
|
23
|
+
run_server server
|
24
|
+
}
|
25
|
+
else
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run server
|
30
|
+
#
|
31
|
+
# @param [Hash] server
|
32
|
+
def run_server server, &block
|
33
|
+
if local? server[:host]
|
34
|
+
options = []
|
35
|
+
options << sprintf('%s', $0)
|
36
|
+
options << sprintf('env=%s', @app.env)
|
37
|
+
server.each { |key, value|
|
38
|
+
options << sprintf('%s=%s', key, value)
|
39
|
+
}
|
40
|
+
local_run 'ruby', nil, options
|
41
|
+
else
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
#
|
47
|
+
#
|
48
|
+
def ssh_run
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
#
|
53
|
+
#
|
54
|
+
def local_run cmd, host, options
|
55
|
+
spawn_process cmd, host, options
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
#
|
60
|
+
#
|
61
|
+
def spawn_process cmd, host, options
|
62
|
+
child = fork {
|
63
|
+
exec cmd + options.inject('') { |res, str| res += ' ' + str }
|
64
|
+
}
|
65
|
+
EM.watch_process child, Module.new {
|
66
|
+
define_method(:process_exited) {
|
67
|
+
Process.wait child
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|