masyo 0.0.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.
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.travis.yml +13 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +33 -0
- data/LICENSE +19 -0
- data/README.md +12 -0
- data/Rakefile +2 -0
- data/bin/masyo +33 -0
- data/lib/extentions/tcp_socket.rb +8 -0
- data/lib/masyo/buffer.rb +33 -0
- data/lib/masyo/client.rb +50 -0
- data/lib/masyo/event.rb +29 -0
- data/lib/masyo/server.rb +73 -0
- data/lib/masyo/version.rb +3 -0
- data/lib/masyo.rb +44 -0
- data/masyo.gemspec +19 -0
- data/sample.god +16 -0
- data/spec/masyo/buffer_spec.rb +54 -0
- data/spec/masyo/client_spec.rb +36 -0
- data/spec/masyo/event_spec.rb +65 -0
- data/spec/masyo/server_spec.rb +87 -0
- data/spec/masyo_spec.rb +29 -0
- data/spec/spec_helper.rb +2 -0
- data/tmp/.gitkeep +0 -0
- data/vendor/bundles/.gitkeep +0 -0
- metadata +94 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
masyo (0.0.1)
|
5
|
+
slop
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.0.7)
|
11
|
+
diff-lcs (1.1.3)
|
12
|
+
method_source (0.8)
|
13
|
+
pry (0.9.10)
|
14
|
+
coderay (~> 1.0.5)
|
15
|
+
method_source (~> 0.8)
|
16
|
+
slop (~> 3.3.1)
|
17
|
+
rspec (2.11.0)
|
18
|
+
rspec-core (~> 2.11.0)
|
19
|
+
rspec-expectations (~> 2.11.0)
|
20
|
+
rspec-mocks (~> 2.11.0)
|
21
|
+
rspec-core (2.11.1)
|
22
|
+
rspec-expectations (2.11.3)
|
23
|
+
diff-lcs (~> 1.1.3)
|
24
|
+
rspec-mocks (2.11.2)
|
25
|
+
slop (3.3.3)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
masyo!
|
32
|
+
pry
|
33
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2012 Takatoshi Matsumoto <toqoz403@gmail.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is furnished
|
8
|
+
to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Masyo(魔性)
|
2
|
+
|
3
|
+
## Description
|
4
|
+
Casual TCP Proxy
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
```sh
|
9
|
+
$ cd /path-to-masyo
|
10
|
+
$ bundle install --path=vendor/bundles
|
11
|
+
$ bundle exec ruby bin/masyo -listen_port #{LISTEN_PORT} --server_host #{PROXY_TARGET_HOST} --server_port #{PROXY_TARGET_PORT}
|
12
|
+
```
|
data/Rakefile
ADDED
data/bin/masyo
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require "slop"
|
5
|
+
argv = ARGV.dup
|
6
|
+
slop = Slop.new(:strict => true, :help => true)
|
7
|
+
slop.banner "$ bundle exec ruby bin/masyo [options]\n"
|
8
|
+
slop.on :b, :buffer_size=, "buffer byte size(default is 0)"
|
9
|
+
slop.on :listen_port=, "listen port (default is 2000)"
|
10
|
+
slop.on :server_host=, "target server host (default is \"0.0.0.0\")"
|
11
|
+
slop.on :server_port=, "target server port (default is 24224)"
|
12
|
+
|
13
|
+
begin
|
14
|
+
slop.parse!(argv)
|
15
|
+
rescue => e
|
16
|
+
puts e
|
17
|
+
exit!
|
18
|
+
end
|
19
|
+
options = slop.to_hash
|
20
|
+
unless options[:help]
|
21
|
+
options.delete(:help)
|
22
|
+
options[:listen_port] = (options[:listen_port] || 2000).to_i
|
23
|
+
options[:server_host] ||= "0.0.0.0"
|
24
|
+
options[:server_port] = (options[:server_port] || 24224).to_i
|
25
|
+
options[:buffer_size] = (options[:buffer_size] || 0).to_i
|
26
|
+
|
27
|
+
root = File.expand_path("../..", __FILE__)
|
28
|
+
$LOAD_PATH.unshift root
|
29
|
+
$LOAD_PATH.unshift File.join(root, 'lib')
|
30
|
+
|
31
|
+
require "masyo"
|
32
|
+
Masyo.run options
|
33
|
+
end
|
data/lib/masyo/buffer.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Masyo
|
4
|
+
class BufferOverflowException < StandardError; end
|
5
|
+
|
6
|
+
class Buffer
|
7
|
+
attr_accessor :maxlen, :buffer
|
8
|
+
|
9
|
+
def initialize(maxlen = 0)
|
10
|
+
@maxlen = maxlen
|
11
|
+
@buffer = ""
|
12
|
+
end
|
13
|
+
|
14
|
+
def take!
|
15
|
+
b = buffer
|
16
|
+
clear!
|
17
|
+
b
|
18
|
+
end
|
19
|
+
|
20
|
+
def push(str)
|
21
|
+
if buffer.bytesize + str.bytesize <= maxlen
|
22
|
+
self.buffer += str
|
23
|
+
else
|
24
|
+
raise BufferOverflowException
|
25
|
+
end
|
26
|
+
end
|
27
|
+
alias_method :<<, :push
|
28
|
+
|
29
|
+
def clear!
|
30
|
+
self.buffer = ""
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/masyo/client.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module Masyo
|
6
|
+
class Client
|
7
|
+
def initialize(host, port, buffer)
|
8
|
+
@host = host
|
9
|
+
@port = port
|
10
|
+
@buffer = buffer
|
11
|
+
|
12
|
+
if buffer.maxlen > 0
|
13
|
+
extend BufferedClient
|
14
|
+
else
|
15
|
+
extend PlainClient
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
extend ::Forwardable
|
20
|
+
def_delegators :Masyo, :logger
|
21
|
+
end
|
22
|
+
|
23
|
+
module PlainClient
|
24
|
+
def post(msg)
|
25
|
+
::TCPSocket.open(@host, @port) { |socket|
|
26
|
+
socket.write msg
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module BufferedClient
|
32
|
+
def post(msg)
|
33
|
+
::TCPSocket.open(@host, @port) { |socket|
|
34
|
+
begin
|
35
|
+
buffer << msg
|
36
|
+
rescue BufferOverflowException
|
37
|
+
# clear buffer
|
38
|
+
socket.write buffer.take!
|
39
|
+
begin
|
40
|
+
buffer << msg
|
41
|
+
rescue BufferOverflowException
|
42
|
+
# post without using buffer
|
43
|
+
#
|
44
|
+
socket.write msg
|
45
|
+
end
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/masyo/event.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Masyo
|
4
|
+
module Event
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.event_types.each do |e|
|
8
|
+
base.class_eval {
|
9
|
+
define_method("on_#{e}") do |&handler|
|
10
|
+
events[e] ||= []
|
11
|
+
events[e] << handler
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def events
|
18
|
+
@events ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def trigger_event(name, *arg)
|
22
|
+
if events[name]
|
23
|
+
events[name].each do |f|
|
24
|
+
f.call *arg
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/masyo/server.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'masyo/event'
|
5
|
+
|
6
|
+
module Masyo
|
7
|
+
class Server
|
8
|
+
attr_accessor :tcp_server, :socket_to_client
|
9
|
+
TO_CLIENT_SOCKET_TIMEOUT = 3
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def event_types
|
13
|
+
[ :read, :close ]
|
14
|
+
end
|
15
|
+
|
16
|
+
def open(*args)
|
17
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 1..2)" if args.size <= 0 || args.size >= 2
|
18
|
+
|
19
|
+
server = new(args.first)
|
20
|
+
return server unless block_given?
|
21
|
+
begin
|
22
|
+
yield server
|
23
|
+
ensure
|
24
|
+
# for sending buffer to server before socket close.
|
25
|
+
server.trigger_event :close
|
26
|
+
server.close unless server.closed?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
include Event
|
32
|
+
|
33
|
+
def initialize(port)
|
34
|
+
raise ArgumentError, "#{port} is not a Integer" unless port.is_a? Integer
|
35
|
+
@tcp_server = ::TCPServer.new(port)
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
loop {
|
40
|
+
Thread.start(tcp_server.accept) do |to_client|
|
41
|
+
handle_request to_client
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_request(to_client)
|
47
|
+
begin
|
48
|
+
loop {
|
49
|
+
begin
|
50
|
+
input = to_client.recv_nonblock(2048)
|
51
|
+
rescue ::IO::WaitReadable
|
52
|
+
if ::IO.select([ to_client ], nil, nil, TO_CLIENT_SOCKET_TIMEOUT)
|
53
|
+
retry
|
54
|
+
else
|
55
|
+
# timeout!
|
56
|
+
break
|
57
|
+
end
|
58
|
+
else
|
59
|
+
break if !input || input == "" || input == "quit"
|
60
|
+
|
61
|
+
trigger_event :read, input
|
62
|
+
end
|
63
|
+
}
|
64
|
+
ensure
|
65
|
+
to_client.close_immediately unless to_client.closed?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
extend ::Forwardable
|
70
|
+
def_delegators :tcp_server, :close, :closed?
|
71
|
+
def_delegators :Masyo, :logger
|
72
|
+
end
|
73
|
+
end
|
data/lib/masyo.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
require 'masyo/version'
|
7
|
+
require 'masyo/server'
|
8
|
+
require 'masyo/client'
|
9
|
+
require 'masyo/buffer'
|
10
|
+
require 'extentions/tcp_socket'
|
11
|
+
|
12
|
+
module Masyo
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def run(opts = {})
|
16
|
+
opts = {
|
17
|
+
listen_port: 2000,
|
18
|
+
server_host: "0.0.0.0",
|
19
|
+
server_port: 24224 ,
|
20
|
+
buffer_size: 0
|
21
|
+
}.merge(opts)
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
24
|
+
buffer = Buffer.new opts[:buffer_size]
|
25
|
+
client = Client.new(opts[:server_host], opts[:server_port], buffer)
|
26
|
+
Server.open(opts[:listen_port]) do |server|
|
27
|
+
logger.info "listen #{opts[:listen_port]} port."
|
28
|
+
|
29
|
+
server.on_read do |msg|
|
30
|
+
client.post msg
|
31
|
+
end
|
32
|
+
|
33
|
+
server.on_close {
|
34
|
+
client.post buffer.take!
|
35
|
+
}
|
36
|
+
|
37
|
+
server.start
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
@logger ||= Logger.new STDOUT
|
43
|
+
end
|
44
|
+
end
|
data/masyo.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/masyo/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Takatoshi Matsumoto"]
|
6
|
+
gem.email = ["toqoz403@gmail.com"]
|
7
|
+
gem.description = "simple tcp proxy server written in ruby"
|
8
|
+
gem.summary = "masyo"
|
9
|
+
gem.homepage = "https://github.com/ToQoz/Masyo"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "masyo"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Masyo::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "slop"
|
19
|
+
end
|
data/sample.god
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
God.watch do |w|
|
4
|
+
root = File.expand_path("../", __FILE__)
|
5
|
+
|
6
|
+
w.name = "Masyo"
|
7
|
+
w.start = "bundle exec ruby #{File.join(root, 'bin', 'masyo')} --listen_port 2001 --server_host 0.0.0.0 --server_port 24224"
|
8
|
+
w.interval = 180.second
|
9
|
+
w.keepalive
|
10
|
+
|
11
|
+
w.start_if do |start|
|
12
|
+
start.condition(:process_running) do |c|
|
13
|
+
c.running = false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Masyo::Buffer do
|
6
|
+
let (:instance) { described_class.new 100 }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
context 'when given a number for args' do
|
10
|
+
it 'should set it to maxlen' do
|
11
|
+
described_class.new(100).maxlen.should eq(100)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
context 'when given none for args' do
|
15
|
+
it 'should set 0 to maxlen' do
|
16
|
+
described_class.new.maxlen.should eq(0)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#clear!' do
|
22
|
+
it 'should clear buffer' do
|
23
|
+
instance.buffer = "toqoz.should be_cool."
|
24
|
+
instance.clear!
|
25
|
+
instance.buffer.should eq("")
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#take!' do
|
31
|
+
it 'should return buffer and clear buffer' do
|
32
|
+
instance.buffer = "toqoz.should be_cool."
|
33
|
+
instance.take!.should eq("toqoz.should be_cool.")
|
34
|
+
instance.buffer.should eq("")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#push' do
|
39
|
+
context 'when given string `don\'t` over buffer' do
|
40
|
+
it 'should add string as buffer' do
|
41
|
+
str = Array.new(100, "a").join("")
|
42
|
+
instance.push str
|
43
|
+
instance.buffer.should eq(str)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context 'when given string over buffer' do
|
47
|
+
it 'raise error' do
|
48
|
+
proc {
|
49
|
+
instance.push Array.new(101, "a").join("")
|
50
|
+
}.should raise_error(Masyo::BufferOverflowException)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Masyo::Client do
|
6
|
+
describe '#initialize' do
|
7
|
+
let(:buffered_client) {
|
8
|
+
buffer = double(maxlen: 100)
|
9
|
+
described_class.new("0.0.0.0", 8080, buffer)
|
10
|
+
}
|
11
|
+
let(:plain_client) {
|
12
|
+
buffer = double(maxlen: 0)
|
13
|
+
described_class.new("0.0.0.0", 8080, buffer)
|
14
|
+
}
|
15
|
+
|
16
|
+
context 'when buffer_size > 0' do
|
17
|
+
it 'should use BufferedClient#post as #post' do
|
18
|
+
buffered_client.method("post").owner.should eq(Masyo::BufferedClient)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when buffer_size == 0' do
|
23
|
+
it 'should use PlainClient#post as #post' do
|
24
|
+
plain_client.method("post").owner.should eq(Masyo::PlainClient)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#post' do
|
30
|
+
let (:instance) { described_class.new("0.0.0.0", 8212, double(maxlen: 10)) }
|
31
|
+
it 'should call TCPSocket.open' do
|
32
|
+
TCPSocket.should_receive(:open).with(kind_of(String), kind_of(Numeric))
|
33
|
+
instance.post("dummy message")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Masyo::Event do
|
6
|
+
let(:instance) do
|
7
|
+
mod = described_class
|
8
|
+
Class.new {
|
9
|
+
class << self
|
10
|
+
def event_types
|
11
|
+
[ :xxx ]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
include mod
|
16
|
+
}.new
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.included' do
|
20
|
+
context 'when included' do
|
21
|
+
it 'define methods for event_types(return by base class methods)' do
|
22
|
+
instance.respond_to?(:on_xxx).should be_true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#on_*' do
|
28
|
+
describe '#on_xxx' do
|
29
|
+
it 'should store given block as event callback' do
|
30
|
+
callback = proc {}
|
31
|
+
instance.on_xxx(&callback)
|
32
|
+
instance.events.should eq({ xxx: [ callback ] })
|
33
|
+
end
|
34
|
+
end
|
35
|
+
context '#on_invalid_event' do
|
36
|
+
it 'should `not` store given block as event callback' do
|
37
|
+
proc {
|
38
|
+
callback = proc {}
|
39
|
+
instance.on_invalid_event(&callback)
|
40
|
+
}.should raise_error(NoMethodError)
|
41
|
+
|
42
|
+
instance.events.should eq({})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#trigger_event' do
|
48
|
+
context 'when given exist event anme' do
|
49
|
+
it 'should trigger all event for #{name}(first args)' do
|
50
|
+
callback = proc {}
|
51
|
+
callback.should_receive(:call)
|
52
|
+
instance.on_xxx(&callback)
|
53
|
+
instance.trigger_event :xxx
|
54
|
+
end
|
55
|
+
end
|
56
|
+
context 'when given `not` exist event anme' do
|
57
|
+
it 'should not trigger all event for #{name}(first args)' do
|
58
|
+
callback = proc {}
|
59
|
+
callback.should_not_receive(:call)
|
60
|
+
instance.on_invalid_event(&callback) rescue
|
61
|
+
instance.trigger_event :invalid_event
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Masyo::Server do
|
6
|
+
let (:instance) { described_class.new(8183) }
|
7
|
+
let (:logger) { double(info: true, error: true) }
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
instance.close
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.open' do
|
14
|
+
context 'when given over 2 args' do
|
15
|
+
it 'should recieve ArgumentError' do
|
16
|
+
proc { described_class.open(8183, "hoge", "foo") }.should raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
context 'when given non-number value as first arg' do
|
20
|
+
it 'should recieve ArgumentError' do
|
21
|
+
proc { described_class.open("9090") }.should raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#initialize' do
|
27
|
+
it 'store ::TCPServer as instance variable' do
|
28
|
+
instance.tcp_server.is_a?(::TCPServer).should be_true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#handle_request' do
|
33
|
+
let (:socket) { double(close_immediately: nil, closed?: false) }
|
34
|
+
|
35
|
+
context 'when BasicSocket#recv_nonblock raise IO::WaitReadable' do
|
36
|
+
before :each do
|
37
|
+
socket.stub(:recv_nonblock).and_raise(StandardError.new.extend(IO::WaitReadable))
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should call IO.select.' do
|
41
|
+
IO.should_receive(:select).
|
42
|
+
with([ socket ], nil, nil, described_class::TO_CLIENT_SOCKET_TIMEOUT).
|
43
|
+
and_return(false)
|
44
|
+
instance.handle_request(socket)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when BasicSocket#recv_nonblock don't raise IO::WaitReadable" do
|
49
|
+
let (:input) { "dummy_input" }
|
50
|
+
|
51
|
+
before :each do
|
52
|
+
socket.stub(:recv_nonblock).and_return(input, "")
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'and when input is not false, nil, "", "quit"' do
|
56
|
+
it 'should call trigger_event with :read as first arg, and input as second arg' do
|
57
|
+
instance.should_receive(:trigger_event).with(:read, input)
|
58
|
+
proc {
|
59
|
+
instance.handle_request(socket)
|
60
|
+
}.should_not raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when raise Exception except IO::WaitReadable' do
|
66
|
+
it 'should close socket and not catch Exceptions.' do
|
67
|
+
socket.stub(:recv_nonblock).and_raise(StandardError)
|
68
|
+
socket.should_receive(:close_immediately)
|
69
|
+
|
70
|
+
proc {
|
71
|
+
instance.handle_request(socket)
|
72
|
+
}.should raise_error(StandardError)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe ::TCPServer do
|
79
|
+
describe '#close_immediately' do
|
80
|
+
it 'should receive setsockopt with relavant options and close' do
|
81
|
+
socket = described_class.new(8183)
|
82
|
+
socket.should_receive(:setsockopt).with(Socket::SOL_SOCKET, Socket::SO_LINGER, [1,0].pack('ii'))
|
83
|
+
socket.should_receive(:close)
|
84
|
+
socket.close_immediately
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/spec/masyo_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Masyo do
|
6
|
+
describe "#run" do
|
7
|
+
before :each do
|
8
|
+
Masyo::Buffer.stub(:new)
|
9
|
+
Masyo::Client.stub(:new)
|
10
|
+
Masyo::Server.stub(:open)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set Thread.abort_on_exception = true" do
|
14
|
+
Thread.should_receive(:abort_on_exception=).with(true)
|
15
|
+
described_class.run
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should call Server.open with port" do
|
19
|
+
Masyo::Server.should_receive(:open).with(kind_of(Numeric))
|
20
|
+
described_class.run
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#logger" do
|
25
|
+
it 'should return Logger instance.' do
|
26
|
+
described_class.logger.is_a?(Logger).should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tmp/.gitkeep
ADDED
File without changes
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: masyo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Takatoshi Matsumoto
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: slop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: simple tcp proxy server written in ruby
|
31
|
+
email:
|
32
|
+
- toqoz403@gmail.com
|
33
|
+
executables:
|
34
|
+
- masyo
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- .rspec
|
40
|
+
- .travis.yml
|
41
|
+
- Gemfile
|
42
|
+
- Gemfile.lock
|
43
|
+
- LICENSE
|
44
|
+
- README.md
|
45
|
+
- Rakefile
|
46
|
+
- bin/masyo
|
47
|
+
- lib/extentions/tcp_socket.rb
|
48
|
+
- lib/masyo.rb
|
49
|
+
- lib/masyo/buffer.rb
|
50
|
+
- lib/masyo/client.rb
|
51
|
+
- lib/masyo/event.rb
|
52
|
+
- lib/masyo/server.rb
|
53
|
+
- lib/masyo/version.rb
|
54
|
+
- masyo.gemspec
|
55
|
+
- sample.god
|
56
|
+
- spec/masyo/buffer_spec.rb
|
57
|
+
- spec/masyo/client_spec.rb
|
58
|
+
- spec/masyo/event_spec.rb
|
59
|
+
- spec/masyo/server_spec.rb
|
60
|
+
- spec/masyo_spec.rb
|
61
|
+
- spec/spec_helper.rb
|
62
|
+
- tmp/.gitkeep
|
63
|
+
- vendor/bundles/.gitkeep
|
64
|
+
homepage: https://github.com/ToQoz/Masyo
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.8.23
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: masyo
|
88
|
+
test_files:
|
89
|
+
- spec/masyo/buffer_spec.rb
|
90
|
+
- spec/masyo/client_spec.rb
|
91
|
+
- spec/masyo/event_spec.rb
|
92
|
+
- spec/masyo/server_spec.rb
|
93
|
+
- spec/masyo_spec.rb
|
94
|
+
- spec/spec_helper.rb
|