fastdfs-client 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e0b3352eb6ff6a305d8083b19000e950632c6db
4
- data.tar.gz: 80788d168fa8726c71cf8da1f9ef325e145da3c1
3
+ metadata.gz: a8009a29d5b18921a4b3d9f628a9f7eaea019635
4
+ data.tar.gz: ac88fd2d1e51070637b34496619e750ccda97d57
5
5
  SHA512:
6
- metadata.gz: 4e4a2a249cd266bcac2fe453f7a0120f53589a006328a355b78475016ec91facb337c4d965164f872bcd188744c09dde55474d82810c26f400eaf57760fc0368
7
- data.tar.gz: e555aba138f34c8088a3709e5426426a79bab48fea3edba8b033d89418bf1e2c9c477300ff1caafe5c7815f1ef21b6acc83bdf666fabd965c6799d71647f5b13
6
+ metadata.gz: 445d9a50ccb21df204e0210cb968610831e137352d94a2c2fc62504c48864af9ef28190f1552b0e38476d91a6621925d7361706616361c9e2da638874c21ea01
7
+ data.tar.gz: 928522790ed79785a931dd0ac000c5ee977f6f5329a5ff74102522a5da3a26ab3daf9271835fe41867deba809380867445e8b136e554d6cc267885b10305046e
data/README.md CHANGED
@@ -21,18 +21,21 @@ fastdfs client for ruby
21
21
 
22
22
  @storage = tracker.get_storage
23
23
 
24
- @storage.upload(@file)
25
- #result: {group_name: "group1", path: "m1/xfsd/fds.jpg"}
24
+ if @storage.is_a?(Fastdfs::Client::Storage)
26
25
 
27
- @storage.delete(path, group_name)
26
+ @storage.upload(@file)
27
+ #result: {group_name: "group1", path: "m1/xfsd/fds.jpg"}
28
28
 
29
- # flag params [cover, merge]
30
- @storage.set_metadata(path, group_name, {author: "kaka", width: "300"}, flag)
29
+ @storage.delete(path, group_name)
31
30
 
32
- @storage.get_metadata(path, group_name)
33
- #result: {author: "kaka", width: "300"}
31
+ # flag params [cover, merge]
32
+ @storage.set_metadata(path, group_name, {author: "kaka", width: "300"}, flag)
34
33
 
35
- @storage.download(path, group_name)
36
- #result: #<Tempfile:/var/folders/m7/bt2j0rk54x555t44dpn4b7bm0000gn/T/test.jpg20160416-43738-1560vq3>
34
+ @storage.get_metadata(path, group_name)
35
+ #result: {author: "kaka", width: "300"}
36
+
37
+ @storage.download(path, group_name)
38
+ #result: #<Tempfile:/var/folders/m7/bt2j0rk54x555t44dpn4b7bm0000gn/T/test.jpg20160416-43738-1560vq3>
39
+ end
37
40
 
38
41
  ```
@@ -4,4 +4,5 @@ require 'fastdfs-client/client_proxy'
4
4
  require 'fastdfs-client/cmd'
5
5
  require 'fastdfs-client/proto_common'
6
6
  require 'fastdfs-client/utils'
7
- require "fastdfs-client/tracker"
7
+ require "fastdfs-client/tracker"
8
+
@@ -17,12 +17,14 @@ module Fastdfs
17
17
  @socket = Socket.new(host, port, options[:socket])
18
18
  end
19
19
 
20
- def dispose(cmd, content_len, header = [], content = [], &block)
20
+ def dispose(cmd, header = [], content = [], &block)
21
21
  synchronize do
22
- @socket.connection do
23
- full_header = ProtoCommon.header_bytes(cmd, content_len) + header
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)
24
26
  @socket.write(cmd, full_header)
25
- Array(content).each do |c|
27
+ contents.each do |c|
26
28
  @socket.write(cmd, c)
27
29
  end
28
30
  @socket.receive &block
@@ -9,6 +9,16 @@ module Fastdfs
9
9
  GET_METADATA = 15
10
10
  SET_METADATA = 13
11
11
  DOWNLOAD_FILE = 14
12
+
13
+ MAPPING_NAME = {
14
+ 101 => "GET STORAGE",
15
+ 11 => "UPLOAD FILE",
16
+ 101 => "RESP CODE",
17
+ 12 => "DELETE FILE",
18
+ 15 => "GET METADATA",
19
+ 13 => "SET METADATA",
20
+ 14 => "DOWNLOAD FILE"
21
+ }
12
22
  end
13
23
 
14
24
  end
@@ -1,4 +1,3 @@
1
-
2
1
  class Array
3
2
  def to_pack_long
4
3
  self.each_with_index.inject(0){|s, item| s = s | (item[0] << (56 - (item[1] * 8))); s }
@@ -9,7 +8,6 @@ class Array
9
8
  end
10
9
  end
11
10
 
12
-
13
11
  class NilClass
14
12
  def blank?
15
13
  true
@@ -28,6 +26,11 @@ class Object
28
26
  end
29
27
  end
30
28
 
29
+ class Integer
30
+ def to_eight_buffer
31
+ 8.times.map{|i| (self >> (56 - 8 * i)) & 255}
32
+ end
33
+ end
31
34
 
32
35
  class Hash
33
36
 
@@ -20,7 +20,7 @@ module Fastdfs
20
20
  SET_METADATA_FLAG_MERGE = "M"
21
21
 
22
22
  def self.header_bytes(cmd, hex_long, erron=0)
23
- hex_bytes = Utils.number_to_buffer(hex_long)
23
+ hex_bytes = hex_long.to_eight_buffer
24
24
  header = hex_bytes.fill(0, hex_bytes.length...HEAD_LEN)
25
25
  header[8] = cmd
26
26
  header[9] = erron
@@ -7,7 +7,7 @@ module Fastdfs
7
7
  module Client
8
8
 
9
9
  class Socket
10
- attr_accessor :header, :content, :header_len, :cmd, :socket, :host, :port
10
+ attr_accessor :socket, :host, :port
11
11
 
12
12
  def initialize(host, port, options = {})
13
13
  @host, @port = host, port
@@ -19,7 +19,6 @@ module Fastdfs
19
19
  end
20
20
 
21
21
  def write(*args)
22
- debugger if args[1] == 119
23
22
  @cmd = args.shift
24
23
  pkg = args.shift
25
24
 
@@ -60,9 +59,9 @@ module Fastdfs
60
59
  private
61
60
  def parseHeader
62
61
  err_msg = nil
63
- err_msg = "recv package size #{@header} is not equal #{@header_len}, cmd: #{@cmd}" unless @header.length == @header_len || err_msg
64
- err_msg = "recv cmd: #{@header[8]} is not correct, expect recv code: #{CMD::RESP_CODE}, cmd: #{@cmd}" unless @header[8] == CMD::RESP_CODE || err_msg
65
- err_msg = "recv erron #{@header[9]}, 0 is correct cmd: #{@cmd}" unless @header[9] == 0 || err_msg
62
+ err_msg = "recv package size #{@header} is not equal #{@header_len}, cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header.length == @header_len || err_msg
63
+ 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
64
+ err_msg = "recv erron #{@header[9]}, 0 is correct cmd: #{CMD::MAPPING_NAME[@cmd]}" unless @header[9] == 0 || err_msg
66
65
  {status: err_msg.nil?, err_msg: err_msg}
67
66
  end
68
67
 
@@ -4,7 +4,7 @@ module Fastdfs
4
4
  module Client
5
5
 
6
6
  class Storage
7
- attr_accessor :group_name, :store_path, :proxy, :options, :socket
7
+ attr_accessor :proxy, :options, :socket, :store_path
8
8
 
9
9
  def initialize(host, port, store_path = nil, options = {})
10
10
  @options = options || {}
@@ -12,17 +12,15 @@ module Fastdfs
12
12
 
13
13
  @proxy = ClientProxy.new(host, port, @options[:socket])
14
14
  @socket = @proxy.socket
15
- @extname_len = ProtoCommon::EXTNAME_LEN
16
- @size_len = ProtoCommon::SIZE_LEN
17
15
  @store_path = store_path || 0
18
16
  end
19
17
 
20
- def upload(file, options = {})
21
- ext_name_bs = File.extname(file)[1..@extname_len].to_s.bytes.full_fill(0, @extname_len)
22
- size_byte = ([@store_path] + Utils.number_to_buffer(file.size)).full_fill(0, @size_len)
23
- content_len = (@size_len + @extname_len + file.size)
18
+ def upload(_file, options = {})
19
+ file, ext_name_bytes = convert_file_info(_file)
20
+ 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
24
22
 
25
- @proxy.dispose(CMD::UPLOAD_FILE, content_len, size_byte + ext_name_bs, IO.read(file)) do |body|
23
+ @proxy.dispose(CMD::UPLOAD_FILE, size_byte + ext_name_bytes, IO.read(file)) do |body|
26
24
  group_name_max_len = ProtoCommon::GROUP_NAME_MAX_LEN
27
25
 
28
26
  res = {group_name: body[0...group_name_max_len].strip, path: body[group_name_max_len..-1]}
@@ -32,13 +30,13 @@ module Fastdfs
32
30
  end
33
31
 
34
32
  def delete(path, group_name = nil)
35
- path_bytes = group_path_bytes(path, group_name).flatten
36
- @proxy.dispose(CMD::DELETE_FILE, path_bytes.length, path_bytes)
33
+ header_bytes = group_path_bytes(path, group_name).flatten
34
+ @proxy.dispose(CMD::DELETE_FILE, header_bytes)
37
35
  end
38
36
 
39
37
  def get_metadata(path, group_name = nil)
40
- path_bytes = group_path_bytes(path, group_name).flatten
41
- @proxy.dispose(CMD::GET_METADATA, path_bytes.length, path_bytes) do |body|
38
+ header_bytes = group_path_bytes(path, group_name).flatten
39
+ @proxy.dispose(CMD::GET_METADATA, header_bytes) do |body|
42
40
  res = body.split(ProtoCommon::RECORD_SEPERATOR).map do |c|
43
41
  c.split(ProtoCommon::FILE_SEPERATOR)
44
42
  end.flatten
@@ -54,9 +52,8 @@ module Fastdfs
54
52
 
55
53
  def download(path, group_name = nil)
56
54
  path_bytes = group_path_bytes(path, group_name).flatten
57
- download_bytes = Utils.number_to_buffer(0) + Utils.number_to_buffer(0)
58
- data = download_bytes + path_bytes
59
- @proxy.dispose(CMD::DOWNLOAD_FILE, data.length, data) do |body|
55
+ header_bytes = 0.to_eight_buffer.concat(0.to_eight_buffer).concat(path_bytes)
56
+ @proxy.dispose(CMD::DOWNLOAD_FILE, header_bytes) do |body|
60
57
  create_tempfile(path, body) if body
61
58
  end
62
59
  end
@@ -87,10 +84,9 @@ module Fastdfs
87
84
  group_bytes, path_bytes = group_path_bytes(path, group_name)
88
85
  meta_bytes = meta_to_bytes(options)
89
86
 
90
- size_bytes = Utils.number_to_buffer(path_bytes.length) + Utils.number_to_buffer(meta_bytes.length)
91
- size_bytes = (size_bytes).full_fill(0, 16)
92
- total = size_bytes.length + flag.length + group_bytes.length + path_bytes.length + meta_bytes.length
93
- @proxy.dispose(CMD::SET_METADATA, total, (size_bytes + flag.bytes + group_bytes + path_bytes), meta_bytes.pack("C*"))
87
+ size_bytes = path_bytes.length.to_eight_buffer.concat(meta_bytes.length.to_eight_buffer).full_fill(0, 16)
88
+ # total = size_bytes.length + flag.length + group_bytes.length + path_bytes.length + meta_bytes.length
89
+ @proxy.dispose(CMD::SET_METADATA, (size_bytes + flag.bytes + group_bytes + path_bytes), meta_bytes.pack("C*"))
94
90
  end
95
91
 
96
92
  def convert_meta_flag(flag)
@@ -117,7 +113,21 @@ module Fastdfs
117
113
  tmp.close
118
114
  tmp
119
115
  end
120
-
116
+
117
+ def extname_len; ProtoCommon::EXTNAME_LEN end;
118
+ def file_size_len; ProtoCommon::SIZE_LEN end;
119
+
120
+ def convert_file_info(file)
121
+ if file.class.name == "ActionDispatch::Http::UploadedFile"
122
+ return file.tempfile, convert_extname_bytes(file.original_filename)
123
+ else
124
+ return file, convert_extname_bytes(file.path)
125
+ end
126
+ end
127
+
128
+ def convert_extname_bytes(file_name)
129
+ File.extname(file_name)[1..extname_len].to_s.bytes.full_fill(0, extname_len)
130
+ end
121
131
  end
122
132
 
123
133
  end
@@ -4,8 +4,8 @@ module Fastdfs
4
4
  module Client
5
5
 
6
6
  class Tracker
7
-
8
- attr_accessor :socket, :cmd, :options, :socket
7
+
8
+ attr_accessor :options, :socket
9
9
 
10
10
  def initialize(host, port, options = {})
11
11
  @options = options
@@ -15,7 +15,7 @@ module Fastdfs
15
15
  end
16
16
 
17
17
  def get_storage
18
- res = @proxy.dispose(@cmd, 0) do |body|
18
+ res = @proxy.dispose(@cmd) do |body|
19
19
  storage_ip = body[ProtoCommon::IPADDR].strip
20
20
  storage_port = body[ProtoCommon::PORT].unpack("C*").to_pack_long
21
21
  store_path = body[ProtoCommon::TRACKER_BODY_LEN-1].unpack("C*")[0]
@@ -1,9 +1,5 @@
1
1
  module Utils
2
2
 
3
- def self.number_to_buffer(num)
4
- 8.times.map{|i| (num >> (56 - 8 * i)) & 255}
5
- end
6
-
7
3
  def self.array_merge(arr1, arr2)
8
4
  raise "argument must be array" unless arr1.is_a?(Array) || arr2.is_a?(Array)
9
5
  arr2.each_with_index.map{|v, i| arr1[i] = v }
@@ -1,5 +1,5 @@
1
1
  module Fastdfs
2
2
  module Client
3
- VERSION = '1.3.0'
3
+ VERSION = '1.4.0'
4
4
  end
5
5
  end
@@ -10,16 +10,28 @@ class MockTCPSocket
10
10
  @recv_offset = 0
11
11
  @connect_state = true
12
12
  @cmd = nil
13
+ @content = []
14
+ @header = []
15
+ end
16
+
17
+ def connection
18
+ @content = []
19
+ @header = []
13
20
  end
14
21
 
15
22
  def write(*args)
16
23
  pkg = args[0].unpack("C*")
24
+ if @header.length <= 0
25
+ @header = pkg
26
+ else
27
+ @content.concat(pkg)
28
+ end
17
29
  @cmd ||= pkg[8]
18
30
  sleep(rand(0..4))
19
31
  end
20
32
 
21
33
  def recv(len)
22
- sleep(rand(0..3))
34
+ sleep(rand(0..2))
23
35
  data = case @cmd
24
36
  when 101
25
37
  gate_tracker(len)
@@ -55,7 +67,7 @@ class MockTCPSocket
55
67
 
56
68
  group_name = Utils.array_merge([].fill(0, 0...16), TestConfig::GROUP_NAME.bytes)
57
69
  ip = Utils.array_merge([].fill(0, 0...15), TestConfig::STORAGE_IP.bytes)
58
- port = Utils.number_to_buffer(TestConfig::STORAGE_PORT.to_i)
70
+ port = TestConfig::STORAGE_PORT.to_i.to_eight_buffer
59
71
  store_path = Array(TestConfig::STORE_PATH)
60
72
 
61
73
  (header+group_name+ip+port+store_path)[@recv_offset...@recv_offset+len].pack("C*")
@@ -64,8 +76,9 @@ class MockTCPSocket
64
76
  def upload_file(len)
65
77
  header = ProtoCommon.header_bytes(CMD::RESP_CODE, 0)
66
78
  group_name = Utils.array_merge([].fill(0, 0...16), TestConfig::GROUP_NAME.bytes)
67
- file_name = TestConfig::FILE_NAME.bytes
68
- res = (group_name + file_name)
79
+ path = path_replace_extname
80
+ file_path_bytes = path.bytes
81
+ res = (group_name + file_path_bytes)
69
82
  header[7] = (header + res).length
70
83
  res = (header + res)
71
84
 
@@ -95,4 +108,12 @@ class MockTCPSocket
95
108
  header[7] = body.length
96
109
  (header + body)[@recv_offset...@recv_offset+len].pack("C*")
97
110
  end
111
+
112
+ private
113
+ def path_replace_extname
114
+ path = TestConfig::FILE_PATH
115
+ extname = File.extname(path)
116
+ path.gsub!(extname, ".#{@header[19..-1].reject{|i| i.zero? }.pack('C*')}")
117
+ path
118
+ end
98
119
  end
@@ -2,6 +2,7 @@ require 'debugger'
2
2
  require 'rspec'
3
3
  require 'rspec/core'
4
4
  require 'rspec/mocks'
5
+ require 'upload'
5
6
  require File.expand_path('../../lib/fastdfs-client', __FILE__)
6
7
  require File.expand_path('../test_config', __FILE__)
7
8
  require File.expand_path('../mock_tcp_socket', __FILE__)
@@ -7,6 +7,12 @@ describe Fastdfs::Client::Storage do
7
7
 
8
8
  let(:tracker){ FC::Tracker.new(host, port) }
9
9
  let(:storage){ tracker.get_storage }
10
+ let(:tempfile) do
11
+ file = Tempfile.new([nil, "1.txt"])
12
+ file.write("testtest")
13
+ file.close
14
+ file
15
+ end
10
16
 
11
17
  it "initialize the server" do
12
18
  expect(FC::Socket).to receive(:new).with(host, port, nil)
@@ -26,10 +32,16 @@ describe Fastdfs::Client::Storage do
26
32
  end
27
33
 
28
34
  it "tempfile upload " do
29
- file = Tempfile.new("1.txt")
30
- file.write("testtest")
31
- file.close
32
- expect(storage.upload(file)[:status]).to be_truthy
35
+ res = storage.upload(tempfile)
36
+ expect(res[:status]).to be_truthy
37
+ expect(File.extname(res[:result][:path])).to eq(".txt")
38
+ end
39
+
40
+ it "ActionDispatch::Http::UploadedFile upload" do
41
+ file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: "test.tt")
42
+ res = storage.upload(file)
43
+ expect(res[:status]).to be_truthy
44
+ expect(File.extname(res[:result][:path])).to eq(".tt")
33
45
  end
34
46
 
35
47
  describe "upload file test " do
@@ -64,11 +76,11 @@ describe Fastdfs::Client::Storage do
64
76
  end
65
77
 
66
78
  it "can set metadata" do
67
- expect(storage.set_metadata(TestConfig::FILE_NAME, TestConfig::GROUP_NAME, TestConfig::METADATA)).to be_truthy
79
+ expect(storage.set_metadata(TestConfig::FILE_PATH, TestConfig::GROUP_NAME, TestConfig::METADATA)).to be_truthy
68
80
  end
69
81
 
70
82
  it "download the file to the local" do
71
- res = storage.download(TestConfig::FILE_NAME, TestConfig::GROUP_NAME)
83
+ res = storage.download(TestConfig::FILE_PATH, TestConfig::GROUP_NAME)
72
84
  expect(res[:status]).to be_truthy
73
85
  expect(res[:result]).to be_an_instance_of(Tempfile)
74
86
  expect(IO.read(res[:result])).to eq(IO.read(TestConfig::FILE))
@@ -3,7 +3,7 @@ module TestConfig
3
3
  STORAGE_PORT = "23000"
4
4
  STORE_PATH = 0
5
5
  GROUP_NAME = "group1"
6
- FILE_NAME = "M00/04/47/wKgIF1cHcQyAeAF7AAACVHeY6n8267.png"
6
+ FILE_PATH = "M00/04/47/wKgIF1cHcQyAeAF7AAACVHeY6n8267.png"
7
7
 
8
8
  METADATA = {
9
9
  width: "800",
@@ -43,7 +43,7 @@ describe Fastdfs::Client::Tracker do
43
43
  res = storage.upload(File.open(File.expand_path("../page.png", __FILE__)))
44
44
  expect(res[:status]).to be_truthy
45
45
  results = res[:result]
46
- results = storage.delete(results[:path], results[:group_name])
46
+ res = storage.delete(results[:path], results[:group_name])
47
47
  expect(res[:status]).to be_truthy
48
48
  end
49
49
  end
@@ -0,0 +1,59 @@
1
+ module ActionDispatch
2
+ module Http
3
+
4
+ class UploadedFile
5
+ attr_accessor :original_filename
6
+
7
+ attr_accessor :content_type
8
+
9
+ attr_accessor :tempfile
10
+ alias :to_io :tempfile
11
+
12
+ attr_accessor :headers
13
+
14
+ def initialize(hash)
15
+ @tempfile = hash[:tempfile]
16
+ raise(ArgumentError, ":tempfile is required") unless @tempfile
17
+
18
+ @original_filename = hash[:filename]
19
+ if @original_filename
20
+ begin
21
+ @original_filename.encode!(Encoding::UTF_8)
22
+ rescue EncodingError
23
+ @original_filename.force_encoding(Encoding::UTF_8)
24
+ end
25
+ end
26
+ @content_type = hash[:type]
27
+ @headers = hash[:head]
28
+ end
29
+
30
+ def read(length=nil, buffer=nil)
31
+ @tempfile.read(length, buffer)
32
+ end
33
+
34
+ def open
35
+ @tempfile.open
36
+ end
37
+
38
+ def close(unlink_now=false)
39
+ @tempfile.close(unlink_now)
40
+ end
41
+
42
+ def path
43
+ @tempfile.path
44
+ end
45
+
46
+ def rewind
47
+ @tempfile.rewind
48
+ end
49
+
50
+ def size
51
+ @tempfile.size
52
+ end
53
+
54
+ def eof?
55
+ @tempfile.eof?
56
+ end
57
+ end
58
+ end
59
+ 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.3.0
4
+ version: 1.4.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: 2016-09-08 00:00:00.000000000 Z
11
+ date: 2016-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,6 +81,7 @@ files:
81
81
  - spec/storage_spec.rb
82
82
  - spec/test_config.rb
83
83
  - spec/tracker_spec.rb
84
+ - spec/upload.rb
84
85
  homepage: https://github.com/huxinghai1988/fastdfs-client-ruby.git
85
86
  licenses:
86
87
  - MIT
@@ -113,4 +114,5 @@ test_files:
113
114
  - spec/storage_spec.rb
114
115
  - spec/test_config.rb
115
116
  - spec/tracker_spec.rb
117
+ - spec/upload.rb
116
118
  has_rdoc: