fastdfs-client 1.4.4 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3763177868ef0c85ae82bcd8799ef7151abd6125
4
- data.tar.gz: f2be6ac0bd9c5cc03e61a24e78304a06dd974cf8
3
+ metadata.gz: ba4443192b50ffc2e07f6173e31d58ec42b33531
4
+ data.tar.gz: 53f3b35f8742cbfebfdd1092938f53714ef834c8
5
5
  SHA512:
6
- metadata.gz: c7ba9d398ab6a11e7462eb2b26f1282689fc879ac1d71ee69dc2b15f19f0b4271036637139f924cca74781c361c2a33b62a6e09ccc15ca3d3720b969618b889f
7
- data.tar.gz: 1a14a43c0e7f1e3c7739066f412ae7e206f79a7627e456baa01dbdc0f175f6f7ff80f3f455d75733396f69ef884ea0b08160501a497003c761a2b04309867b6c
6
+ metadata.gz: 03f0b6d523e8596f9c455fea0517897201b23755d7ab7ab871e0c98328820db4366f72fc73e3a732047496421f6f7bd89ef45317109846451289a7292532bed1
7
+ data.tar.gz: 0eb796a19af1869c3b17785f16474ef521139fa35018f348cb6f7a3c0d5a07484899a2ee03dd53d4b64566356b6645f3e210cdc55ec5a0a29c6c52e76eeedf20
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  *.gem
2
2
  Gemfile.lock
3
- tmp
3
+ tmp
4
+ .ruby-version
5
+ .byebug_history
data/README.md CHANGED
@@ -17,26 +17,49 @@ fastdfs client for ruby
17
17
  #
18
18
 
19
19
 
20
- tracker = Fastdfs::Client::Tracker.new("192.168.1.1", "22122")
20
+ tracker = Fastdfs::Client::Tracker.new(trackers: {host: "192.168.1.1", port: "22122"})
21
+
22
+ # multiple trackers server
23
+ # trackers: [
24
+ # {host: "192.168.1.1", port: "22122"},
25
+ # {host: "192.168.1.2", port: "22122"}
26
+ # ]
27
+
28
+ # socket connection KEEPALIVE
29
+ tracker.pipeline do |s|
30
+ files.each do |file|
31
+ s.upload(s)
32
+ end
33
+ end
21
34
 
22
- @storage = tracker.get_storage
35
+ # @file class includes [File, Tempfile, ActionDispatch::Http::UploadedFile]
36
+ @tracker.upload(@file)
37
+ #result: {group_name: "group1", path: "m1/xfsd/fds.jpg"}
23
38
 
24
- if @storage.is_a?(Fastdfs::Client::Storage)
39
+ @tracker.delete(path, group_name)
25
40
 
26
- @storage.upload(@file)
27
- # @file class includes [File, Tempfile, ActionDispatch::Http::UploadedFile]
28
- #result: {group_name: "group1", path: "m1/xfsd/fds.jpg"}
41
+ # flag params [cover, merge]
42
+ @tracker.set_metadata(path, group_name, {author: "kaka", width: "300"}, flag)
29
43
 
30
- @storage.delete(path, group_name)
44
+ @tracker.get_metadata(path, group_name)
45
+ #result: {author: "kaka", width: "300"}
31
46
 
32
- # flag params [cover, merge]
33
- @storage.set_metadata(path, group_name, {author: "kaka", width: "300"}, flag)
47
+ @tracker.download(path, group_name)
48
+ #result: #<Tempfile:/var/folders/m7/bt2j0rk54x555t44dpn4b7bm0000gn/T/test.jpg20160416-43738-1560vq3>
34
49
 
35
- @storage.get_metadata(path, group_name)
36
- #result: {author: "kaka", width: "300"}
37
50
 
38
- @storage.download(path, group_name)
39
- #result: #<Tempfile:/var/folders/m7/bt2j0rk54x555t44dpn4b7bm0000gn/T/test.jpg20160416-43738-1560vq3>
40
- end
51
+ # Make compatible 1.x version
52
+
53
+ @storage = tracker.get_storage
54
+
55
+ @storage.upload ...
56
+ @storage.delete ...
57
+ @storage.set_metadata ...
58
+ @storage.get_metadata ...
59
+ @storage.download ...
60
+
61
+ ```
62
+
63
+ ### License
41
64
 
42
- ```
65
+ [MIT License](https://opensource.org/licenses/MIT)
@@ -21,6 +21,12 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.6"
23
23
  spec.add_development_dependency "rspec", "~> 3.4"
24
- spec.add_development_dependency "debugger", "~> 1.6"
25
24
 
25
+ if RUBY_VERSION.start_with?('2.2')
26
+ # Call 'byebug' anywhere in the code to stop execution and get a debugger console
27
+ spec.add_development_dependency "byebug", "~> 9.1.0"
28
+ else
29
+ # Call 'debugger' anywhere in the code to stop execution and get a debugger console
30
+ spec.add_development_dependency "debugger", "~> 1.6"
31
+ end
26
32
  end
@@ -1,8 +1,9 @@
1
+ require 'fastdfs-client/version'
1
2
  require "fastdfs-client/extend_core"
3
+ require 'fastdfs-client/delegation'
2
4
  require 'fastdfs-client/socket'
3
5
  require 'fastdfs-client/client_proxy'
4
6
  require 'fastdfs-client/cmd'
5
7
  require 'fastdfs-client/proto_common'
6
8
  require 'fastdfs-client/utils'
7
- require "fastdfs-client/tracker"
8
-
9
+ require "fastdfs-client/tracker"
@@ -6,34 +6,44 @@ module Fastdfs
6
6
  class ClientProxy
7
7
  include MonitorMixin
8
8
 
9
- attr_accessor :host, :port, :socket
9
+ attr_accessor :host, :port, :socket, :alive
10
10
 
11
11
  def initialize(host, port, options = {})
12
12
  super()
13
13
  options ||= {}
14
- @host = host
15
- @port = port
14
+ @host, @port = host, port
15
+ @alive = options.delete(:alive) || false
16
16
 
17
- @socket = Socket.new(host, port, options[:socket])
17
+ @socket = Socket.new(host, port, options)
18
18
  end
19
19
 
20
20
  def dispose(cmd, header = [], content = [], &block)
21
21
  synchronize do
22
22
  @socket.connection do
23
- contents = Array(content)
24
- body_len = contents.map{|c| c.bytes.size }.inject(header.length){|sum, x| sum + x }
25
- full_header = ProtoCommon.header_bytes(cmd, body_len).concat(header)
26
- @socket.write(cmd, full_header)
27
- contents.each do |c|
28
- @socket.write(cmd, c)
23
+ begin
24
+ contents = Array(content)
25
+ body_len = contents.map{|c| c.bytes.size }.inject(header.length){|sum, x| sum + x }
26
+ full_header = ProtoCommon.header_bytes(cmd, body_len).concat(header)
27
+ @socket.socket.reload_data if Fastdfs::Client.mock_test && @socket.socket.respond_to?(:reload_data)
28
+ @socket.write(cmd, full_header)
29
+ contents.each do |c|
30
+ @socket.write(cmd, c)
31
+ end
32
+ @socket.receive &block
33
+ rescue Exception => e
34
+ close
35
+ @socket.response_obj.update(status: false, err_msg: e.message)
29
36
  end
30
- @socket.receive &block
31
- end
37
+
38
+ end
32
39
  end
33
40
  ensure
41
+ close unless @alive
42
+ end
43
+
44
+ def close
34
45
  @socket.close
35
46
  end
36
47
  end
37
-
38
48
  end
39
49
  end
@@ -0,0 +1,24 @@
1
+ module Fastdfs
2
+ module Client
3
+
4
+ module Delegation
5
+ module ClassMethods
6
+
7
+ def delegate(*methods, to:)
8
+ methods.each do |m|
9
+ class_eval <<-EVAL, __FILE__, __LINE__ + 1
10
+ def #{m}(*args, &block)
11
+ #{to}.#{m}(*args, &block)
12
+ end
13
+ EVAL
14
+ end
15
+ end
16
+ end
17
+
18
+ def self.included(receiver)
19
+ receiver.extend ClassMethods
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -9,12 +9,12 @@ module Fastdfs
9
9
  class Socket
10
10
  attr_accessor :socket, :host, :port
11
11
 
12
- def initialize(host, port, options = {})
12
+ def initialize(host, port, options)
13
13
  @host, @port = host, port
14
14
  @header_len = ProtoCommon::HEAD_LEN
15
15
  @options = options || {}
16
- @connection_timeout = @options[:connection_timeout] || 3
17
- @recv_timeout = @options[:recv_timeout] || 20
16
+ @connection_timeout = @options[:connection_timeout]
17
+ @recv_timeout = @options[:recv_timeout]
18
18
  end
19
19
 
20
20
  def write(*args)
@@ -39,7 +39,7 @@ module Fastdfs
39
39
  end
40
40
 
41
41
  def connected
42
- !@socket.closed?
42
+ @socket.nil? ? false : !@socket.closed?
43
43
  end
44
44
 
45
45
  def receive(&block)
@@ -55,13 +55,18 @@ module Fastdfs
55
55
  res_header
56
56
  end
57
57
 
58
+ def response_obj
59
+ Hash[status: true, err_msg: nil, result: nil]
60
+ end
61
+
58
62
  private
59
63
  def parseHeader
60
- err_msg = nil
61
- err_msg = "recv package size #{@header} is not equal #{@header_len}, cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header.length == @header_len || err_msg
62
- err_msg = "recv cmd: #{@header[8]} is not correct, expect recv code: #{CMD::RESP_CODE}, cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header[8] == CMD::RESP_CODE || err_msg
63
- err_msg = "recv erron #{@header[9]}, 0 is correct cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header[9] == 0 || err_msg
64
- {status: err_msg.nil?, err_msg: err_msg}
64
+ obj = response_obj
65
+ obj[:err_msg] = "recv package size #{@header} is not equal #{@header_len}, cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header.length == @header_len || obj[:err_msg]
66
+ obj[:err_msg] = "recv cmd: #{@header[8]} is not correct, expect recv code: #{CMD::RESP_CODE}, cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header[8] == CMD::RESP_CODE || obj[:err_msg]
67
+ obj[:err_msg] = "recv erron #{@header[9]}, 0 is correct cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header[9] == 0 || obj[:err_msg]
68
+ obj[:status] = obj[:err_msg].nil?
69
+ obj
65
70
  end
66
71
 
67
72
  def timeout_recv
@@ -4,25 +4,29 @@ module Fastdfs
4
4
  module Client
5
5
 
6
6
  class Storage
7
- attr_accessor :proxy, :options, :socket, :store_path
7
+ attr_accessor :proxy, :socket, :store_path
8
8
 
9
9
  def initialize(host, port, store_path = nil, options = {})
10
- @options = options || {}
11
- @options = store_path if store_path.is_a?(Hash)
12
-
13
- @proxy = ClientProxy.new(host, port, @options[:socket])
10
+ @store_path = 0
11
+ options = if store_path.is_a?(Hash)
12
+ store_path
13
+ else
14
+ @store_path = store_path
15
+ options
16
+ end
17
+
18
+ @proxy = ClientProxy.new(host, port, options)
14
19
  @socket = @proxy.socket
15
- @store_path = store_path || 0
16
20
  end
17
21
 
18
22
  def upload(_file, options = {})
19
23
  file, ext_name_bytes = convert_file_info(_file)
20
24
  size_byte = [@store_path].concat(file.size.to_eight_buffer).full_fill(0, file_size_len)
21
- content_len = file_size_len + extname_len + file.size
22
25
 
23
- @proxy.dispose(CMD::UPLOAD_FILE, size_byte + ext_name_bytes, IO.read(file)) do |body|
26
+ byte = size_byte + ext_name_bytes
27
+
28
+ @proxy.dispose(CMD::UPLOAD_FILE, byte , IO.read(file)) do |body|
24
29
  group_name_max_len = ProtoCommon::GROUP_NAME_MAX_LEN
25
-
26
30
  res = {group_name: body[0...group_name_max_len].strip, path: body[group_name_max_len..-1]}
27
31
  _set_metadata(res[:path], res[:group_name], options) unless options.blank?
28
32
  res
@@ -5,23 +5,75 @@ module Fastdfs
5
5
 
6
6
  class Tracker
7
7
 
8
- attr_accessor :options, :socket
8
+ include Delegation
9
+
10
+ attr_accessor :options
11
+
12
+ delegate :upload, :delete, :get_metadata, :set_metadata, :download, to: :get_storage
13
+
14
+ def initialize(options = {})
15
+ @options = default_options_merge(options)
16
+ @proxies = @options[:trackers].map do |tracker|
17
+ opt = tracker.fs_symbolize_keys
18
+ ClientProxy.new(opt[:host], opt[:port], extract_proxy_options.merge(alive: true))
19
+ end
9
20
 
10
- def initialize(host, port, options = {})
11
- @options = options
12
- @proxy = ClientProxy.new(host, port, @options[:socket])
13
- @socket = @proxy.socket
14
21
  end
15
22
 
16
- def get_storage
17
- res = @proxy.dispose(CMD::STORE_WITHOUT_GROUP_ONE) do |body|
23
+ def get_storage(alive = false)
24
+ res = proxy.dispose(CMD::STORE_WITHOUT_GROUP_ONE) do |body|
18
25
  storage_ip = body[ProtoCommon::IPADDR].strip
19
26
  storage_port = body[ProtoCommon::PORT].unpack("C*").to_pack_long
20
27
  store_path = body[ProtoCommon::TRACKER_BODY_LEN-1].unpack("C*")[0]
21
28
 
22
- Storage.new(storage_ip, storage_port, store_path, @options)
29
+ Storage.new(storage_ip, storage_port, store_path, extract_proxy_options.merge(alive: alive))
23
30
  end
24
- res[:status] ? res[:result] : res
31
+ raise res[:err_msg] unless res[:status]
32
+ res[:result]
33
+ end
34
+
35
+ def pipeline
36
+ storage = get_storage(true)
37
+ yield storage
38
+ storage
39
+ ensure
40
+ storage.proxy.close
41
+ end
42
+
43
+ private
44
+ def default_options_merge(options = {})
45
+ opts = default_options.merge(options)
46
+ tracker = {host: opts.delete(:host), port: opts.delete(:port)}
47
+ if !tracker[:host].nil?
48
+ opts[:trackers] = [tracker]
49
+ elsif opts[:trackers].is_a?(Hash)
50
+ opts[:trackers] = [opts[:trackers]]
51
+ end
52
+ opts
53
+ end
54
+
55
+ def default_options
56
+ {
57
+ host: nil,
58
+ port: nil,
59
+ trackers: [
60
+ {host: "127.0.0.1", port: "22122"}
61
+ ],
62
+ connection_timeout: 3,
63
+ recv_timeout: 20
64
+ }
65
+ end
66
+
67
+ def extract_proxy_options
68
+ keys = [:connection_timeout, :recv_timeout]
69
+ @options.select{|key| keys.include?(key) }
70
+ end
71
+
72
+ def proxy
73
+ @proxy_index ||= -1
74
+ @proxy_index += 1
75
+ @proxy_index = 0 if @proxy_index >= @proxies.length
76
+ @proxies[@proxy_index]
25
77
  end
26
78
  end
27
79
 
@@ -1,5 +1,10 @@
1
1
  module Fastdfs
2
2
  module Client
3
- VERSION = '1.4.4'
3
+ VERSION = '2.0.0'
4
+
5
+ def self.mock_test
6
+ false
7
+ end
8
+
4
9
  end
5
10
  end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ BLOG_URI = "http://168ta.com"
4
+
5
+ class Profile
6
+
7
+ def messages(limit, offset); [limit, offset] end
8
+
9
+ def blog; BLOG_URI end
10
+
11
+ def change_email; yield end
12
+
13
+ end
14
+
15
+ class User
16
+ include Fastdfs::Client::Delegation
17
+
18
+ delegate :messages, :blog, :change_email, to: :profile
19
+
20
+ def profile
21
+ Profile.new
22
+ end
23
+ end
24
+
25
+ describe Fastdfs::Client::Delegation do
26
+
27
+ let(:user){ User.new }
28
+
29
+ it "user should be three methods" do
30
+ expect(user.respond_to?(:messages)).to be_truthy
31
+ expect(user.respond_to?(:blog)).to be_truthy
32
+ expect(user.respond_to?(:change_email)).to be_truthy
33
+ expect(user.respond_to?(:title)).to be_falsey
34
+ end
35
+
36
+ it "user method receive argments" do
37
+ expect(user.messages(25, 0)).to eq([25, 0])
38
+ expect(user.blog).to eq(BLOG_URI)
39
+ expect(user.change_email{ "hello" }).to eq("hello")
40
+ end
41
+
42
+ it "argments of the execption" do
43
+ begin
44
+ user.messages(25)
45
+ rescue Exception => e
46
+ expect(e).to be_a_kind_of(ArgumentError)
47
+ end
48
+
49
+ begin
50
+ user.change_email
51
+ rescue Exception => e
52
+ expect(e).to be_a_kind_of(LocalJumpError)
53
+ end
54
+ end
55
+
56
+ end
@@ -5,18 +5,17 @@ class MockTCPSocket
5
5
  attr_accessor :host, :port, :cmd, :recv_offset, :connect_state
6
6
 
7
7
  def initialize(host, port)
8
- @host = host
9
- @port = port
10
- @recv_offset = 0
11
- @connect_state = true
12
- @cmd = nil
13
- @content = []
14
- @header = []
8
+ @host, @port = host, port
9
+ reload_data
15
10
  end
16
11
 
17
12
  def connection
18
- @content = []
19
- @header = []
13
+ reload_data
14
+ end
15
+
16
+ def reload_data
17
+ init_options
18
+ init_data
20
19
  end
21
20
 
22
21
  def write(*args)
@@ -51,69 +50,81 @@ class MockTCPSocket
51
50
  end
52
51
 
53
52
  def close
54
- @recv_offset = 0
53
+ init_options
55
54
  @connect_state = false
56
- @cmd = nil
57
55
  end
58
56
 
59
57
  def closed?
60
- @connect_state
58
+ !@connect_state
61
59
  end
62
60
 
63
61
  private
64
62
  def gate_tracker(len)
65
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
63
+ header = init_header_bytes
66
64
  header[7] = ProtoCommon::TRACKER_BODY_LEN
67
65
 
68
66
  group_name = Utils.array_merge([].fill(0, 0...16), TestConfig::GROUP_NAME.bytes)
69
67
  ip = Utils.array_merge([].fill(0, 0...15), TestConfig::STORAGE_IP.bytes)
70
68
  port = TestConfig::STORAGE_PORT.to_i.to_eight_buffer
71
69
  store_path = Array(TestConfig::STORE_PATH)
72
-
73
70
  (header+group_name+ip+port+store_path)[@recv_offset...@recv_offset+len].pack("C*")
74
71
  end
75
72
 
76
73
  def upload_file(len)
77
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
74
+ header = init_header_bytes
78
75
  group_name = Utils.array_merge([].fill(0, 0...16), TestConfig::GROUP_NAME.bytes)
79
76
  path = path_replace_extname
80
77
  file_path_bytes = path.bytes
81
78
  res = (group_name + file_path_bytes)
82
79
  header[7] = (header + res).length
83
- res = (header + res)
84
80
 
81
+ res = (header + res)
85
82
  res[@recv_offset...@recv_offset+len].pack("C*")
86
83
  end
87
84
 
88
85
  def delete_file(len)
89
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
86
+ header = init_header_bytes
90
87
  header.pack("C*")
91
88
  end
92
89
 
93
90
  def get_metadata(len)
94
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
91
+ header = init_header_bytes
95
92
  body = TestConfig::METADATA.map{|a| a.join(ProtoCommon::FILE_SEPERATOR)}.join(ProtoCommon::RECORD_SEPERATOR).bytes
96
93
  header[7] = body.length
97
94
  (header + body)[@recv_offset...@recv_offset+len].pack("C*")
98
95
  end
99
96
 
100
97
  def set_metadata(len)
101
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
98
+ header = init_header_bytes
102
99
  header.pack("C*")
103
100
  end
104
101
 
105
102
  def download_file(len)
106
- header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
103
+ header = init_header_bytes
107
104
  body = IO.read(TestConfig::FILE).bytes
108
105
  header[7] = body.length
109
106
  (header + body)[@recv_offset...@recv_offset+len].pack("C*")
110
107
  end
111
108
 
112
- private
109
+ def init_options
110
+ @recv_offset = 0
111
+ @connect_state = true
112
+ @cmd = nil
113
+ end
114
+
115
+ def init_data
116
+ @content = []
117
+ @header = []
118
+ end
119
+
113
120
  def path_replace_extname
114
121
  path = TestConfig::FILE_PATH
115
122
  extname = File.extname(path)
116
123
  path.gsub!(extname, ".#{@header[19..-1].reject{|i| i.zero? }.pack('C*')}")
117
124
  path
118
125
  end
126
+
127
+ def init_header_bytes
128
+ ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
129
+ end
119
130
  end
@@ -1,4 +1,8 @@
1
- require 'debugger'
1
+ if RUBY_VERSION.start_with?('2')
2
+ require 'byebug'
3
+ else
4
+ require 'debugger'
5
+ end
2
6
  require 'rspec'
3
7
  require 'rspec/core'
4
8
  require 'rspec/mocks'
@@ -7,6 +11,10 @@ require File.expand_path('../../lib/fastdfs-client', __FILE__)
7
11
  require File.expand_path('../test_config', __FILE__)
8
12
  require File.expand_path('../mock_tcp_socket', __FILE__)
9
13
 
14
+ Fastdfs::Client.class_eval do
15
+ def self.mock_test; true end
16
+ end
17
+
10
18
  FC = Fastdfs::Client
11
19
 
12
20
  RSpec.configure do |config|
@@ -14,7 +22,7 @@ RSpec.configure do |config|
14
22
  TCPSocket.stub(:new) do |h, p|
15
23
  MockTCPSocket.new(h, p)
16
24
  end
17
- end
25
+ end
18
26
  config.mock_with :rspec do |c|
19
27
  c.syntax = [:should, :expect]
20
28
  end
@@ -2,21 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  describe Fastdfs::Client::Storage do
4
4
 
5
- let(:host){ "192.168.9.16" }
6
- let(:port){ "22122" }
5
+ let(:server){ {host: "192.168.1.168", port: "22122"} }
6
+ let(:tracker){ FC::Tracker.new(trackers: server) }
7
7
 
8
- let(:tracker){ FC::Tracker.new(host, port) }
9
8
  let(:storage){ tracker.get_storage }
10
9
  let(:tempfile) do
11
- file = Tempfile.new([nil, "1.txt"])
10
+ file = Tempfile.new(["/tmp", "1.txt"])
12
11
  file.write("testtest")
13
12
  file.close
14
13
  file
15
14
  end
16
15
 
17
16
  it "initialize the server" do
18
- expect(FC::Socket).to receive(:new).with(host, port, nil)
19
- FC::Storage.new(host, port)
17
+ expect(FC::Socket).to receive(:new).with(server[:host], server[:port], {})
18
+ FC::Storage.new(server[:host], server[:port])
20
19
  end
21
20
 
22
21
  it "should have access to the storage connection" do
@@ -79,7 +78,7 @@ describe Fastdfs::Client::Storage do
79
78
  expect(storage.set_metadata(TestConfig::FILE_PATH, TestConfig::GROUP_NAME, TestConfig::METADATA)).to be_truthy
80
79
  end
81
80
 
82
- it "download the file to the local" do
81
+ it "download the file to the local" do
83
82
  res = storage.download(TestConfig::FILE_PATH, TestConfig::GROUP_NAME)
84
83
  expect(res[:status]).to be_truthy
85
84
  expect(res[:result]).to be_an_instance_of(Tempfile)
@@ -1,9 +1,10 @@
1
1
  module TestConfig
2
- STORAGE_IP = "192.168.8.23"
2
+ STORAGE_IP = "192.168.1.168"
3
3
  STORAGE_PORT = "23000"
4
4
  STORE_PATH = 0
5
5
  GROUP_NAME = "group1"
6
6
  FILE_PATH = "M00/04/47/wKgIF1cHcQyAeAF7AAACVHeY6n8267.png"
7
+ SOCKET_DEFAULT_OPTION = {connection_timeout: 3, recv_timeout: 20}
7
8
 
8
9
  METADATA = {
9
10
  width: "800",
@@ -1,21 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Fastdfs::Client::Tracker do
4
-
5
- let(:host){ "192.168.9.16" }
6
- let(:port){ "22122" }
7
-
8
- let(:tracker){ FC::Tracker.new(host, port) }
4
+ let(:server){ {host: "192.168.1.168", port: "22122"} }
5
+ let(:tracker){ FC::Tracker.new(trackers: server) }
9
6
 
10
7
  it "initialize the server" do
11
- expect(FC::Socket).to receive(:new).with(host, port, nil)
12
- FC::Tracker.new(host, port)
13
- end
14
-
15
- it "should have access to the storage connection" do
16
- expect(tracker.socket).to receive(:connection).and_return({})
17
- expect(tracker.socket).to receive(:close)
18
- tracker.get_storage
8
+ expect(FC::Socket).to receive(:new).with(server[:host], server[:port], TestConfig::SOCKET_DEFAULT_OPTION)
9
+ FC::Tracker.new(trackers: server)
19
10
  end
20
11
 
21
12
  it "should have access to the storage class" do
@@ -23,17 +14,20 @@ describe Fastdfs::Client::Tracker do
23
14
  end
24
15
 
25
16
  it "verify the server address and port" do
26
- expect(tracker.get_storage.socket.host).to eq(TestConfig::STORAGE_IP)
17
+ storage = tracker.get_storage
18
+ expect(storage.proxy.host).to eq(TestConfig::STORAGE_IP)
27
19
 
28
- expect(tracker.get_storage.socket.port.to_s).to eq(TestConfig::STORAGE_PORT)
29
- expect(tracker.get_storage.store_path).to eq(TestConfig::STORE_PATH)
20
+ expect(storage.proxy.port.to_s).to eq(TestConfig::STORAGE_PORT)
21
+ expect(storage.store_path).to eq(TestConfig::STORE_PATH)
30
22
  end
31
23
 
32
24
  it "get to the server failed" do
33
- result = FC::ProtoCommon.header_bytes(FC::CMD::RESP_CODE, 0, 22)
34
- MockTCPSocket.any_instance.stub("recv").and_return(result.pack("C*"))
35
- expect(tracker.get_storage).to be_a_kind_of(Hash)
36
- expect(tracker.get_storage[:status]).to be_falsey
25
+ if tracker.get_storage.socket.is_a?(MockTCPSocket)
26
+ result = FC::ProtoCommon.header_bytes(FC::CMD::RESP_CODE, 0, 22)
27
+ MockTCPSocket.any_instance.stub("recv").and_return(result.pack("C*"))
28
+ expect(tracker.get_storage).to be_a_kind_of(Hash)
29
+ expect(tracker.get_storage[:status]).to be_falsey
30
+ end
37
31
  end
38
32
 
39
33
  it "multi thread upload" do
@@ -48,7 +42,48 @@ describe Fastdfs::Client::Tracker do
48
42
  end
49
43
  end
50
44
 
51
- items.map{|item| item.join }
45
+ items.map(&:join)
46
+ end
47
+
48
+ it "should be storage methods" do
49
+ expect(tracker.respond_to?(:upload)).to be_truthy
50
+ expect(tracker.respond_to?(:delete)).to be_truthy
51
+ expect(tracker.respond_to?(:get_metadata)).to be_truthy
52
+ expect(tracker.respond_to?(:set_metadata)).to be_truthy
53
+ expect(tracker.respond_to?(:download)).to be_truthy
54
+ end
55
+
56
+ it "storage socket keepalive request" do
57
+ storage = tracker.pipeline do |storage|
58
+ res = storage.upload(File.open(File.expand_path("../page.png", __FILE__)))[:result]
59
+ expect(storage.socket.connected).to be_truthy
60
+
61
+ tmp = storage.set_metadata(res[:path], res[:group_name], TestConfig::METADATA)
62
+ expect(tmp[:status]).to be_truthy
63
+ expect(storage.socket.connected).to be_truthy
64
+
65
+ tmp = storage.get_metadata(res[:path], res[:group_name])
66
+ expect(tmp[:status]).to be_truthy
67
+ expect(storage.socket.connected).to be_truthy
68
+
69
+ tmp = storage.download(res[:path], res[:group_name])
70
+ expect(tmp[:status]).to be_truthy
71
+ expect(storage.socket.connected).to be_truthy
72
+ end
73
+ expect(storage.socket.connected).to be_falsey
52
74
  end
53
75
 
76
+ it "multiple trackers server proxy" do
77
+ trackers = [server]
78
+ two_server = {host: "192.168.1.169", port: "22122"}
79
+ trackers << two_server
80
+ ts = FC::Tracker.new(trackers: trackers)
81
+
82
+ 1.upto(6).each do |i|
83
+ proxy = ts.send(:proxy)
84
+ res = i % 2 == 0 ? two_server : server
85
+ expect({host: proxy.host, port: proxy.port}).to eq(res)
86
+ end
87
+
88
+ end
54
89
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastdfs-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ka Ka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-07 00:00:00.000000000 Z
11
+ date: 2017-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.4'
41
41
  - !ruby/object:Gem::Dependency
42
- name: debugger
42
+ name: byebug
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.6'
47
+ version: 9.1.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.6'
54
+ version: 9.1.0
55
55
  description: fastdfs upload file client for ruby
56
56
  email:
57
57
  - huxinghai1988@gmail.com
@@ -67,6 +67,7 @@ files:
67
67
  - lib/fastdfs-client.rb
68
68
  - lib/fastdfs-client/client_proxy.rb
69
69
  - lib/fastdfs-client/cmd.rb
70
+ - lib/fastdfs-client/delegation.rb
70
71
  - lib/fastdfs-client/extend_core.rb
71
72
  - lib/fastdfs-client/proto_common.rb
72
73
  - lib/fastdfs-client/socket.rb
@@ -75,6 +76,7 @@ files:
75
76
  - lib/fastdfs-client/utils.rb
76
77
  - lib/fastdfs-client/version.rb
77
78
  - spec/.DS_Store
79
+ - spec/delegation_spec.rb
78
80
  - spec/mock_tcp_socket.rb
79
81
  - spec/page.png
80
82
  - spec/spec_helper.rb
@@ -102,12 +104,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
104
  version: '0'
103
105
  requirements: []
104
106
  rubyforge_project:
105
- rubygems_version: 2.2.2
107
+ rubygems_version: 2.4.6
106
108
  signing_key:
107
109
  specification_version: 4
108
110
  summary: fastdfs upload file client for ruby
109
111
  test_files:
110
112
  - spec/.DS_Store
113
+ - spec/delegation_spec.rb
111
114
  - spec/mock_tcp_socket.rb
112
115
  - spec/page.png
113
116
  - spec/spec_helper.rb
@@ -115,4 +118,3 @@ test_files:
115
118
  - spec/test_config.rb
116
119
  - spec/tracker_spec.rb
117
120
  - spec/upload.rb
118
- has_rdoc: