r_proxy 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/example.rb +9 -4
- data/lib/r_proxy/cache_pool.rb +37 -0
- data/lib/r_proxy/callback_service.rb +1 -0
- data/lib/r_proxy/check_snapshot_service.rb +7 -3
- data/lib/r_proxy/config.rb +6 -0
- data/lib/r_proxy/connection_handler.rb +15 -9
- data/lib/r_proxy/http_post_template.rb +1 -1
- data/lib/r_proxy/http_proxy_parser.rb +5 -6
- data/lib/r_proxy/master_process.rb +3 -2
- data/lib/r_proxy/proxy_server.rb +38 -2
- data/lib/r_proxy/target_connection.rb +3 -3
- data/lib/r_proxy/usage_manager.rb +59 -0
- data/lib/r_proxy/version.rb +1 -1
- data/lib/r_proxy.rb +2 -1
- metadata +4 -3
- data/lib/r_proxy/unbind_service.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb665c8aedadf57b45585d927e08de7e572dc1e5bfdca207a0f889b41791d4c9
|
4
|
+
data.tar.gz: 8fea768841cce3fc8741efdefdbee247b0a48abf680bf906d35f97e6fcbf2e43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e747ed1002a3a05330312691c9dbe2648c96859ff8af184dcd3c1e5f2738f58f37642343806f5ade14735c7a931e84f58a20279adf8bf3c088d5d71f66b5539e
|
7
|
+
data.tar.gz: b850bad10bf4b3d361bfcb8fa9d1fbe395dc6816c1e14afe3799d9be876fab53f1db3c8b25419116af121fb91e9f9141c7f0ca4cee0418ca15da93691c351ce8
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
a powerful ruby http proxy server, base on eventmachine
|
4
4
|
|
5
|
-
able to run in multi-process like nginx
|
5
|
+
able to run in multi-process like nginx workers
|
6
6
|
## Installation
|
7
7
|
|
8
8
|
Add this line to your application's Gemfile:
|
@@ -79,5 +79,5 @@ server.run!
|
|
79
79
|
|
80
80
|
## Contributing
|
81
81
|
|
82
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
82
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/nickoan/r_proxy.
|
83
83
|
|
data/example.rb
CHANGED
@@ -7,11 +7,16 @@ server.set(:port, 8080)
|
|
7
7
|
|
8
8
|
server.set(:instances, 3)
|
9
9
|
|
10
|
-
server.set(:disable_auth, true)
|
11
|
-
|
12
|
-
server.set(:enable_ssl,
|
10
|
+
#server.set(:disable_auth, true)
|
11
|
+
server.set(:disable_unbind_cb, false)
|
12
|
+
server.set(:enable_ssl, true)
|
13
13
|
|
14
|
-
server.set(:callback_url,'http://
|
14
|
+
server.set(:callback_url,'http://localhost:3000/api/proxy_callback')
|
15
|
+
|
16
|
+
server.set(:no_cache_below, 1 * 1024 * 1024 * 1024)
|
17
|
+
server.set(:cache_clear_threshold, 1)
|
18
|
+
server.set(:enable_force_quit, true)
|
19
|
+
server.set(:enable_cache, true)
|
15
20
|
|
16
21
|
server.set(:redis_url, "redis://@localhost:6379/1")
|
17
22
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RProxy
|
2
|
+
class CachePool
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@pool = {}
|
6
|
+
@able_write = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def []=(key, value)
|
10
|
+
return value if !@able_write
|
11
|
+
@pool[key] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
@pool[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def writable?
|
20
|
+
@able_write
|
21
|
+
end
|
22
|
+
|
23
|
+
def disable_write!
|
24
|
+
@able_write = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def enable_write!
|
28
|
+
@able_write = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def flush
|
32
|
+
tmp = @pool
|
33
|
+
@pool = {}
|
34
|
+
tmp
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -20,9 +20,13 @@ module RProxy
|
|
20
20
|
tmp = snapshot_value.to_i - result.to_i
|
21
21
|
|
22
22
|
if tmp >= @usage_threshold
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
begin
|
24
|
+
connection = RProxy::CallbackService.call(@cb_url, user, pass, tmp)
|
25
|
+
connection.assign_logger(@logger)
|
26
|
+
@redis.setex(s_key, @snapshot_expire_in, result)
|
27
|
+
rescue => e
|
28
|
+
@logger.error("callback service: @id:#{s_key}, #{e.message}") if @logger
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
data/lib/r_proxy/config.rb
CHANGED
@@ -40,6 +40,12 @@ module RProxy
|
|
40
40
|
add_config(:usage_threshold, 1 * 1024 * 1024 * 1024)
|
41
41
|
add_config(:proxy_buffer, 1024 * 1024 * 10) # default is 10M
|
42
42
|
|
43
|
+
add_config(:enable_cache, true)
|
44
|
+
add_config(:cache_clear_threshold, 200)
|
45
|
+
add_config(:no_cache_below, 500 * 1024 * 1024)
|
46
|
+
|
47
|
+
add_config(:enable_force_quit, true)
|
48
|
+
|
43
49
|
add_config(:disable_auth, false)
|
44
50
|
add_config(:disable_unbind_cb, false)
|
45
51
|
|
@@ -1,10 +1,9 @@
|
|
1
1
|
module RProxy
|
2
2
|
class ConnectionHandler < EM::Connection
|
3
|
-
def initialize(config)
|
3
|
+
def initialize(config, cache_pool)
|
4
4
|
@config = config
|
5
5
|
@logger = @config.logger
|
6
6
|
@redis = RProxy::RedisService.instance(@config.redis_url)
|
7
|
-
@http_parser = HttpProxyParser.new(@redis)
|
8
7
|
@disable_auth = @config.disable_auth
|
9
8
|
@disable_unbind_cb = @config.disable_unbind_cb
|
10
9
|
@buffer_size = @config.proxy_buffer
|
@@ -12,9 +11,11 @@ module RProxy
|
|
12
11
|
@username = nil
|
13
12
|
@password = nil
|
14
13
|
@target_connection = nil
|
15
|
-
|
16
|
-
@
|
14
|
+
@cache_pool = cache_pool
|
15
|
+
@usage_manager = RProxy::UsageManager.new(config, @cache_pool, @redis)
|
16
|
+
@http_parser = HttpProxyParser.new(@usage_manager)
|
17
17
|
@snapshot_service = RProxy::CheckSnapshotService.new(@redis, @config)
|
18
|
+
@enable_force_quit = config.enable_force_quit
|
18
19
|
end
|
19
20
|
|
20
21
|
def post_init
|
@@ -27,9 +28,11 @@ module RProxy
|
|
27
28
|
end
|
28
29
|
@port, @ip = Socket.unpack_sockaddr_in(get_peername)
|
29
30
|
|
30
|
-
@
|
31
|
-
|
32
|
-
|
31
|
+
if @enable_force_quit
|
32
|
+
@timer = EventMachine.add_timer(20) do
|
33
|
+
self.close_connection(false)
|
34
|
+
@timer = nil
|
35
|
+
end
|
33
36
|
end
|
34
37
|
rescue => e
|
35
38
|
if @logger
|
@@ -50,7 +53,7 @@ module RProxy
|
|
50
53
|
self,
|
51
54
|
@disable_unbind_cb,
|
52
55
|
@buffer_size,
|
53
|
-
@
|
56
|
+
@usage_manager)
|
54
57
|
@target_connection.assign_logger(@logger)
|
55
58
|
if !@disable_auth
|
56
59
|
@username = @http_parser.username
|
@@ -79,8 +82,11 @@ module RProxy
|
|
79
82
|
end
|
80
83
|
|
81
84
|
def unbind
|
85
|
+
if @timer
|
86
|
+
EventMachine.cancel_timer(@timer)
|
87
|
+
end
|
82
88
|
return if @disable_unbind_cb
|
83
|
-
@
|
89
|
+
@usage_manager.report_usage(@username, @password, get_proxied_bytes)
|
84
90
|
end
|
85
91
|
end
|
86
92
|
end
|
@@ -5,8 +5,8 @@ module RProxy
|
|
5
5
|
|
6
6
|
attr_reader :username, :password
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
@
|
8
|
+
def initialize(usage_manager)
|
9
|
+
@usage_manager = usage_manager
|
10
10
|
@max_connection_size = 4 * 1024
|
11
11
|
end
|
12
12
|
|
@@ -31,11 +31,10 @@ module RProxy
|
|
31
31
|
rescue
|
32
32
|
raise RProxy::HTTPNotSupport, "token parse failed #{token}"
|
33
33
|
end
|
34
|
-
key = "proxy:#{@username}-#{@password}"
|
35
|
-
value = @redis.get(key)
|
36
34
|
|
37
|
-
|
38
|
-
|
35
|
+
auth_result = @usage_manager.auth_user(@username, @password)
|
36
|
+
raise RProxy::HTTPAuthFailed if auth_result.nil?
|
37
|
+
auth_result
|
39
38
|
end
|
40
39
|
|
41
40
|
def parse_connect_request(data)
|
@@ -42,11 +42,11 @@ module RProxy
|
|
42
42
|
instance_amount = @config.instances
|
43
43
|
server = TCPServer.new(@config.host, @config.port)
|
44
44
|
instance_amount.times do
|
45
|
-
timestamp = Time.now.to_i
|
46
45
|
pid = Process.fork do
|
46
|
+
timestamp = (Time.now.to_f * 1000).round
|
47
47
|
begin
|
48
48
|
@logger.info("r_proxy @#{timestamp} process start....") if @logger
|
49
|
-
RProxy::ProxyServer.new(server, @config).run!
|
49
|
+
RProxy::ProxyServer.new(server, @config, timestamp).run!
|
50
50
|
rescue Interrupt
|
51
51
|
@logger.info("r_proxy TPC server instance @#{timestamp} closed now....") if @logger
|
52
52
|
rescue => e
|
@@ -57,6 +57,7 @@ module RProxy
|
|
57
57
|
|
58
58
|
Process.detach(pid)
|
59
59
|
@pids << pid
|
60
|
+
sleep(0.1)
|
60
61
|
end
|
61
62
|
|
62
63
|
EventMachine.kqueue=(true)
|
data/lib/r_proxy/proxy_server.rb
CHANGED
@@ -1,14 +1,50 @@
|
|
1
1
|
module RProxy
|
2
2
|
class ProxyServer
|
3
|
-
def initialize(sock, config)
|
3
|
+
def initialize(sock, config, instance_id)
|
4
4
|
@sock = sock
|
5
5
|
@config = config
|
6
|
+
@cache_pool = RProxy::CachePool.new
|
7
|
+
@logger = @config.logger
|
8
|
+
@instance_id = instance_id
|
6
9
|
end
|
7
10
|
|
8
11
|
def run!
|
9
12
|
Signal.trap("TERM") { exit! }
|
10
13
|
EventMachine.run do
|
11
|
-
|
14
|
+
|
15
|
+
if @config.enable_cache
|
16
|
+
@period_timer = EventMachine.add_periodic_timer(30) do
|
17
|
+
@cache_pool.disable_write!
|
18
|
+
|
19
|
+
tmp = @cache_pool.flush
|
20
|
+
|
21
|
+
report_and_clean_cache(tmp)
|
22
|
+
|
23
|
+
@cache_pool.enable_write!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
EventMachine.attach_server(@sock, RProxy::ConnectionHandler, @config, @cache_pool)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def report_and_clean_cache(cache)
|
34
|
+
return if cache.empty?
|
35
|
+
|
36
|
+
redis = RProxy::RedisService.instance(@config.redis_url)
|
37
|
+
time_start = (Time.now.to_f * 1000).floor
|
38
|
+
cache.each do |k, value|
|
39
|
+
used = value[:used]
|
40
|
+
next if used.nil? || used.zero?
|
41
|
+
redis.decrby(k, used)
|
42
|
+
end
|
43
|
+
time_end = (Time.now.to_f * 1000).floor
|
44
|
+
spend = time_end - time_start
|
45
|
+
|
46
|
+
if spend > @config.cache_clear_threshold
|
47
|
+
@logger.info("@#{@instance_id} clear cache: #{spend} ms, remove: #{cache.size} items") if @logger
|
12
48
|
end
|
13
49
|
end
|
14
50
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module RProxy
|
2
2
|
class TargetConnection < EM::Connection
|
3
3
|
|
4
|
-
def initialize(client, disable_cb, buffer_size,
|
4
|
+
def initialize(client, disable_cb, buffer_size, usage_manager)
|
5
5
|
@disable_unbind_callback = disable_cb
|
6
6
|
@client_connection = client
|
7
7
|
@buffer_size = buffer_size
|
8
|
-
@
|
8
|
+
@usage_manager = usage_manager
|
9
9
|
end
|
10
10
|
|
11
11
|
def assign_logger(logger)
|
@@ -27,7 +27,7 @@ module RProxy
|
|
27
27
|
|
28
28
|
def unbind
|
29
29
|
return if @disable_unbind_callback
|
30
|
-
@
|
30
|
+
@usage_manager.report_usage(@username, @password, get_proxied_bytes)
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RProxy
|
2
|
+
class UsageManager
|
3
|
+
def initialize(config, cache_pool, redis)
|
4
|
+
@enable_cache = config.enable_cache
|
5
|
+
@cache_pool = cache_pool
|
6
|
+
@redis = redis
|
7
|
+
@no_cache_below = config.no_cache_below
|
8
|
+
end
|
9
|
+
|
10
|
+
def auth_user(user, pass)
|
11
|
+
key = proxy_key(user, pass)
|
12
|
+
|
13
|
+
value = fetch_usage(key)
|
14
|
+
|
15
|
+
return value if !value.nil? && value.to_i > 0
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def report_usage(user, pass, value)
|
20
|
+
return if user.nil? || pass.nil? || value.nil?
|
21
|
+
|
22
|
+
key = proxy_key(user, pass)
|
23
|
+
cache = @cache_pool[key]
|
24
|
+
|
25
|
+
if cache.nil? || !@cache_pool.writable?
|
26
|
+
@redis.decrby(key, value)
|
27
|
+
else
|
28
|
+
tmp = cache[:used]
|
29
|
+
@cache_pool[key][:used] = tmp + value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def fetch_usage(key)
|
36
|
+
return @redis.get(key) if !@enable_cache || !@cache_pool.writable?
|
37
|
+
|
38
|
+
cache = @cache_pool[key]
|
39
|
+
|
40
|
+
if cache.nil?
|
41
|
+
value = @redis.get(key)
|
42
|
+
|
43
|
+
return value if !value.nil? && value.to_i <= @no_cache_below
|
44
|
+
|
45
|
+
@cache_pool[key] = {
|
46
|
+
usage: value,
|
47
|
+
used: 0
|
48
|
+
}
|
49
|
+
return value
|
50
|
+
end
|
51
|
+
|
52
|
+
cache[:usage]
|
53
|
+
end
|
54
|
+
|
55
|
+
def proxy_key(user, pass)
|
56
|
+
"proxy:#{user}-#{pass}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/r_proxy/version.rb
CHANGED
data/lib/r_proxy.rb
CHANGED
@@ -3,6 +3,8 @@ require 'r_proxy/version'
|
|
3
3
|
require 'eventmachine'
|
4
4
|
require 'redis'
|
5
5
|
require 'r_proxy/config'
|
6
|
+
require 'r_proxy/cache_pool'
|
7
|
+
require 'r_proxy/usage_manager'
|
6
8
|
require 'r_proxy/constants'
|
7
9
|
require 'r_proxy/check_snapshot_service'
|
8
10
|
require 'r_proxy/http_proxy_parser'
|
@@ -13,7 +15,6 @@ require 'r_proxy/process_handler'
|
|
13
15
|
|
14
16
|
require 'r_proxy/target_connection'
|
15
17
|
require 'r_proxy/connection_handler'
|
16
|
-
require 'r_proxy/unbind_service'
|
17
18
|
|
18
19
|
require 'r_proxy/callback_connection'
|
19
20
|
require 'r_proxy/http_post_template'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r_proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick An
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eventmachine
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- bin/setup
|
69
69
|
- example.rb
|
70
70
|
- lib/r_proxy.rb
|
71
|
+
- lib/r_proxy/cache_pool.rb
|
71
72
|
- lib/r_proxy/callback_connection.rb
|
72
73
|
- lib/r_proxy/callback_service.rb
|
73
74
|
- lib/r_proxy/check_snapshot_service.rb
|
@@ -81,7 +82,7 @@ files:
|
|
81
82
|
- lib/r_proxy/proxy_server.rb
|
82
83
|
- lib/r_proxy/redis_service.rb
|
83
84
|
- lib/r_proxy/target_connection.rb
|
84
|
-
- lib/r_proxy/
|
85
|
+
- lib/r_proxy/usage_manager.rb
|
85
86
|
- lib/r_proxy/version.rb
|
86
87
|
- r_proxy.gemspec
|
87
88
|
homepage: https://github.com/nickoan/r_proxy
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module RProxy
|
2
|
-
class UnbindService
|
3
|
-
|
4
|
-
def initialize(config, redis)
|
5
|
-
@config = config
|
6
|
-
@cb_url = config.callback_url
|
7
|
-
@redis = redis
|
8
|
-
@usage_threshold = @config.usage_threshold
|
9
|
-
@snapshot_expire_in = 15 * 60 # 15 min
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(user, pass, usage)
|
13
|
-
|
14
|
-
return if user.nil? || pass.nil? || usage.nil?
|
15
|
-
|
16
|
-
key = proxy_key(user, pass)
|
17
|
-
@redis.decrby(key, usage)
|
18
|
-
end
|
19
|
-
|
20
|
-
def proxy_key(user, pass)
|
21
|
-
"proxy:#{user}-#{pass}"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|