em-nodes 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4b47ba8138b82b37389094a0e941603e8b1c4128
4
+ data.tar.gz: 2044009a60a4947aa14a752f7ecf4a41613e1ec7
5
+ SHA512:
6
+ metadata.gz: 39e256163916d4d2ef972524e2a7789498b16349063aefa8ce5b42226fc167fd7e36ff873a177bff39f55c04fedbb3a1441c960646285ddc2fbbcd46b4015ebf
7
+ data.tar.gz: 94abef2e1f64b5a7d9269d6811b671a1ad422567b6d2af54ac938796b4a1717a43c804c28517f115ab885153b2a389689c85945103fba5fe2835a8e2aaa1cd0d
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in em-nodes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 'Konstantin Makarchev'
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # EM::Nodes
2
+
3
+ Simple EM client server, and some stuffs
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'em-nodes'
10
+
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => :spec
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.verbose = false
8
+ end
9
+
data/em-nodes.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'em-nodes'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "em-nodes"
8
+ spec.version = EM::Nodes::VERSION
9
+ spec.authors = ["'Konstantin Makarchev'"]
10
+ spec.email = ["'kostya27@gmail.com'"]
11
+ spec.summary = %q{Simple EM client server, and some stuffs}
12
+ spec.description = %q{Simple EM client server, and some stuffs}
13
+ spec.homepage = "https://github.com/kostya/em-nodes"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "eventmachine"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,36 @@
1
+ require "bundler/setup"
2
+ Bundler.require
3
+ require 'irb'
4
+
5
+ class ChatClient < EM::Nodes::Client
6
+ def initialize(name)
7
+ @name = name
8
+ super
9
+ end
10
+
11
+ def who_are_you?
12
+ server.send_i_am @name
13
+ end
14
+
15
+ def say(msg)
16
+ puts msg
17
+ end
18
+
19
+ def unbind
20
+ super
21
+ EM.stop
22
+ end
23
+ end
24
+
25
+ def say(msg)
26
+ $cl.server.send_say(msg)
27
+ end
28
+
29
+ EM.run do
30
+ $cl = ChatClient.connect "127.0.0.1", 1999, ARGV.shift || "Vasya"
31
+
32
+ Thread.new do
33
+ IRB.start
34
+ EM.stop
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ require "bundler/setup"
2
+ Bundler.require
3
+
4
+ class ChatServer < EM::Nodes::Server
5
+ def post_init
6
+ super
7
+ client.send_who_are_you?
8
+ end
9
+
10
+ def i_am(name)
11
+ client.data.name = name
12
+ to_all "> coming #{name} <"
13
+ end
14
+
15
+ def say(msg)
16
+ to_all "#{client.data.name} say: #{msg}"
17
+ end
18
+
19
+ def to_all(msg)
20
+ self.class.clients.each { |cl| cl.send_say("#{Time.now} - " + msg.to_s) }
21
+ end
22
+
23
+ def unbind
24
+ super
25
+ to_all("quiting #{client.data.name}")
26
+ end
27
+ end
28
+
29
+ EM.run do
30
+ ChatServer.start('127.0.0.1', 1999)
31
+ end
data/lib/em-nodes.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'eventmachine'
2
+ require 'logger'
3
+
4
+ module EM::Nodes
5
+ VERSION = "0.1"
6
+
7
+ class << self
8
+ def logger=(logger)
9
+ @_logger = logger
10
+ end
11
+
12
+ def logger
13
+ @_logger ||= Logger.new(nil)
14
+ end
15
+
16
+ def exception(ex)
17
+ logger.error "Exception: #{ex.message} #{ex.backtrace * "\n"}"
18
+ end
19
+ end
20
+
21
+ autoload :Client, 'em-nodes/client'
22
+ autoload :Server, 'em-nodes/server'
23
+ autoload :Commands, 'em-nodes/commands'
24
+ autoload :AbstractCommand, 'em-nodes/abstract_command'
25
+ end
@@ -0,0 +1,19 @@
1
+ module EM::Nodes::AbstractCommand
2
+ COMMAND_PREFIX = 'send_'
3
+
4
+ def method_missing(method, *args)
5
+ method = method.to_s
6
+
7
+ unless method.start_with?(COMMAND_PREFIX)
8
+ EM::Nodes.logger.debug "unknown send #{method} #{args.inspect}"
9
+ super
10
+ return
11
+ end
12
+
13
+ if @alive
14
+ @connection.send_command(method.sub(COMMAND_PREFIX, ''), args)
15
+ else
16
+ EM::Nodes.logger.error "failed command attempt #{method}, connection dead"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ class EM::Nodes::Client < EM::Connection
2
+ autoload :Server, 'em-nodes/client/server'
3
+
4
+ attr_reader :server
5
+
6
+ include EM::P::ObjectProtocol
7
+ include EM::Nodes::Commands
8
+
9
+ def post_init
10
+ @server = EM::Nodes::Client::Server.new(self)
11
+ EM::Nodes.logger.debug "Connected to server"
12
+ end
13
+
14
+ def unbind
15
+ @server.disconnect!
16
+ EM::Nodes.logger.warn "connection has terminated"
17
+ end
18
+
19
+ def self.connect(host, port, *args, &block)
20
+ EM.connect(host, port, self, *args)
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ class EM::Nodes::Client::Server
2
+ include EM::Nodes::AbstractCommand
3
+
4
+ attr_accessor :connection, :alive
5
+ def initialize(conn)
6
+ @connection = conn
7
+ @alive = true
8
+ end
9
+
10
+ def disconnect!
11
+ @alive = false
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module EM::Nodes::Commands
2
+ def receive_object(h)
3
+ unless h.is_a?(Hash)
4
+ EM::Nodes.logger.error "received unknown object: #{obj.inspect}"
5
+ return
6
+ end
7
+
8
+ method = h[:method]
9
+ args = h[:args]
10
+ EM::Nodes.logger.debug "<= #{method} #{args}"
11
+ t = Time.now
12
+ send(method, *args)
13
+ EM::Nodes.logger.info "<= #{method} #{args} (#{Time.now - t}s)"
14
+ rescue Object => ex
15
+ EM::Nodes.exception(ex)
16
+ end
17
+
18
+ def send_command(method, args)
19
+ obj = {:method => method, :args => args}
20
+ EM::Nodes.logger.debug "=> #{method}"
21
+ EM.schedule { send_object(obj) }
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ require 'socket'
2
+
3
+ class EM::Nodes::Server < EM::Connection
4
+ autoload :Client, 'em-nodes/server/client'
5
+
6
+ attr_reader :client
7
+
8
+ include EM::P::ObjectProtocol
9
+ include EM::Nodes::Commands
10
+
11
+ class << self
12
+ def clients
13
+ @clients ||= []
14
+ end
15
+
16
+ def alive_clients
17
+ clients.select &:alive
18
+ end
19
+ end
20
+
21
+ def accept?(host, port)
22
+ true
23
+ end
24
+
25
+ def inactivity_timeout
26
+ 10 * 60 # 10 minutes default
27
+ end
28
+
29
+ def post_init
30
+ self.comm_inactivity_timeout = inactivity_timeout
31
+
32
+ port, host = Socket.unpack_sockaddr_in(get_peername)
33
+ unless accept?(host, port)
34
+ unbind
35
+ return
36
+ end
37
+
38
+ @client = EM::Nodes::Server::Client.new(self)
39
+ self.class.clients << @client
40
+ EM::Nodes.logger.info "Incomming connection from #{host}:#{port}"
41
+ end
42
+
43
+ def unbind
44
+ @client.disconnect!
45
+ self.class.clients.delete @client
46
+ EM::Nodes.logger.info "Client has disconnected"
47
+ end
48
+
49
+ def self.start(host, port, *args)
50
+ EM::Nodes.logger.info "start server on #{host}:#{port}"
51
+ EM.start_server host, port, self, *args
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require 'ostruct'
2
+
3
+ class EM::Nodes::Server::Client
4
+ include EM::Nodes::AbstractCommand
5
+
6
+ attr_accessor :connection, :alive
7
+ attr_reader :data
8
+
9
+ def initialize(conn)
10
+ @connection = conn
11
+ @alive = true
12
+ @data = OpenStruct.new
13
+ end
14
+
15
+ def disconnect!
16
+ @alive = false
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ $pong = []
4
+
5
+ class Client2 < EM::Nodes::Client
6
+ def pong(a)
7
+ $pong << a
8
+ EM.stop if $pong.size >= 2
9
+ end
10
+ end
11
+
12
+ class Server2 < EM::Nodes::Server
13
+ def ping(a)
14
+ client.send_pong(a)
15
+ end
16
+ end
17
+
18
+ describe "Simple spec" do
19
+ it "should work" do
20
+ EM.run do
21
+ $server2 = Server2.start('127.0.0.1', 19993)
22
+ $client21 = Client2.connect('127.0.0.1', 19993)
23
+ $client22 = Client2.connect('127.0.0.1', 19993)
24
+
25
+ $client21.server.send_ping(1)
26
+ $client22.server.send_ping(2)
27
+ end
28
+
29
+ $pong.should == [1, 2]
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class Client1 < EM::Nodes::Client
4
+ def initialize(name)
5
+ @name = name
6
+ super
7
+ end
8
+
9
+ def who_are_you?
10
+ server.send_i_am @name
11
+ end
12
+
13
+ def unbind
14
+ super
15
+ EM.stop
16
+ end
17
+ end
18
+
19
+ class Server1 < EM::Nodes::Server
20
+ def post_init
21
+ super
22
+ client.send_who_are_you?
23
+ end
24
+
25
+ def i_am(name)
26
+ client.data.name = name
27
+ $client1_result = { :name => name, :clients => Server1.clients.clone }
28
+ client.send_unbind
29
+ end
30
+ end
31
+
32
+ describe "Simple spec" do
33
+ it "should work" do
34
+ EM.run do
35
+ $server1 = Server1.start('127.0.0.1', 19992)
36
+ $client1 = Client1.connect('127.0.0.1', 19992, "haha")
37
+ end
38
+
39
+ $client1.should be_a(Client1)
40
+
41
+ $client1_result[:name].should == "haha"
42
+ $client1_result[:clients].size.should == 1
43
+ end
44
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ EM::Nodes.logger = Logger.new(File.dirname(__FILE__) + "/spec.log")
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-nodes
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - '''Konstantin Makarchev'''
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: eventmachine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Simple EM client server, and some stuffs
70
+ email:
71
+ - '''kostya27@gmail.com'''
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - em-nodes.gemspec
82
+ - examples/chat_client.rb
83
+ - examples/chat_server.rb
84
+ - lib/em-nodes.rb
85
+ - lib/em-nodes/abstract_command.rb
86
+ - lib/em-nodes/client.rb
87
+ - lib/em-nodes/client/server.rb
88
+ - lib/em-nodes/commands.rb
89
+ - lib/em-nodes/server.rb
90
+ - lib/em-nodes/server/client.rb
91
+ - spec/simple2_spec.rb
92
+ - spec/simple_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/kostya/em-nodes
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.1.4
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Simple EM client server, and some stuffs
118
+ test_files:
119
+ - spec/simple2_spec.rb
120
+ - spec/simple_spec.rb
121
+ - spec/spec_helper.rb