fastdfs-client 0.0.5 → 1.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -2
- data/lib/fastdfs-client.rb +1 -1
- data/lib/fastdfs-client/client_proxy.rb +32 -0
- data/lib/fastdfs-client/extend_core.rb +3 -0
- data/lib/fastdfs-client/storage.rb +37 -53
- data/lib/fastdfs-client/tracker.rb +8 -13
- data/lib/fastdfs-client/version.rb +1 -1
- data/spec/storage_spec.rb +45 -39
- data/spec/tracker_spec.rb +4 -4
- metadata +2 -2
- data/lib/fastdfs-client/hook.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84bd058d40b079c23d2cc236c651aa48a5a4e4f9
|
4
|
+
data.tar.gz: 21b8ffd285416638286d3181134790665ce17c44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de8034cd485d98fa4825ccb745e408f1e41052162c7bd86b75c25bcf08d7c5204cac57107ca3c2566770298f09d7fbc5ad8b0df0872f7bcfbfd8087e4ec525da
|
7
|
+
data.tar.gz: 3de188e4493f56da22ce8ffb66c4d6cf332536381c0ec38de294a3e2d1acbd7bc02fec557302c062e17e4c3abaec93f2ff58e3f04149f9bd01bdac76e697d770
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
data/lib/fastdfs-client.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "fastdfs-client/extend_core"
|
2
2
|
require 'fastdfs-client/socket'
|
3
|
+
require 'fastdfs-client/client_proxy'
|
3
4
|
require 'fastdfs-client/cmd'
|
4
5
|
require 'fastdfs-client/proto_common'
|
5
6
|
require 'fastdfs-client/utils'
|
6
|
-
require 'fastdfs-client/hook'
|
7
7
|
require "fastdfs-client/tracker"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Fastdfs
|
2
|
+
module Client
|
3
|
+
|
4
|
+
class ClientProxy
|
5
|
+
attr_accessor :data, :header, :content, :socket
|
6
|
+
|
7
|
+
def initialize(cmd, socket, content_len, header = [])
|
8
|
+
@cmd = cmd
|
9
|
+
socket.connection
|
10
|
+
@socket = socket
|
11
|
+
@header = ProtoCommon.header_bytes(cmd, content_len) + header
|
12
|
+
@content = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def push_content
|
16
|
+
raise "argument not block!" unless block_given?
|
17
|
+
@content << yield
|
18
|
+
end
|
19
|
+
|
20
|
+
def dispose(&block)
|
21
|
+
@socket.write(@cmd, @header)
|
22
|
+
@content.each do |c|
|
23
|
+
@socket.write(@cmd, c)
|
24
|
+
end
|
25
|
+
@socket.receive &block
|
26
|
+
ensure
|
27
|
+
@socket.close
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -4,11 +4,6 @@ module Fastdfs
|
|
4
4
|
module Client
|
5
5
|
|
6
6
|
class Storage
|
7
|
-
extend Hook
|
8
|
-
|
9
|
-
before(:upload, :delete, :get_metadata, ){ @socket.connection }
|
10
|
-
after(:upload, :delete, :get_metadata, ){ @socket.close }
|
11
|
-
|
12
7
|
attr_accessor :host, :port, :group_name, :store_path, :socket, :options
|
13
8
|
|
14
9
|
def initialize(host, port, store_path = nil, options = {})
|
@@ -22,23 +17,33 @@ module Fastdfs
|
|
22
17
|
@store_path = store_path || 0
|
23
18
|
end
|
24
19
|
|
25
|
-
def upload(file)
|
26
|
-
|
20
|
+
def upload(file, options = {})
|
21
|
+
ext_name_bs = File.extname(file)[1..-1].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)
|
24
|
+
|
25
|
+
client = ClientProxy.new(CMD::UPLOAD_FILE, @socket, content_len, size_byte + ext_name_bs)
|
26
|
+
client.push_content{ IO.read(file) }
|
27
|
+
client.dispose do |body|
|
28
|
+
group_name_max_len = ProtoCommon::GROUP_NAME_MAX_LEN
|
29
|
+
|
30
|
+
res = {group_name: body[0...group_name_max_len].strip, path: body[group_name_max_len..-1]}
|
31
|
+
_set_metadata(res[:path], res[:group_name], options) unless options.blank?
|
32
|
+
res
|
33
|
+
end
|
27
34
|
end
|
28
35
|
|
29
36
|
def delete(path, group_name = nil)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@socket.receive{ true }
|
37
|
+
path_bytes = group_path_bytes(path, group_name).flatten
|
38
|
+
client = ClientProxy.new(CMD::DELETE_FILE, @socket, path_bytes.length, path_bytes)
|
39
|
+
client.dispose
|
34
40
|
end
|
35
41
|
|
36
42
|
def get_metadata(path, group_name = nil)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
res = content.split(ProtoCommon::RECORD_SEPERATOR).map do |c|
|
43
|
+
path_bytes = group_path_bytes(path, group_name).flatten
|
44
|
+
client = ClientProxy.new(CMD::GET_METADATA, @socket, path_bytes.length, path_bytes)
|
45
|
+
client.dispose do |body|
|
46
|
+
res = body.split(ProtoCommon::RECORD_SEPERATOR).map do |c|
|
42
47
|
c.split(ProtoCommon::FILE_SEPERATOR)
|
43
48
|
end.flatten
|
44
49
|
Utils.symbolize_keys(Hash[*res])
|
@@ -46,8 +51,6 @@ module Fastdfs
|
|
46
51
|
end
|
47
52
|
|
48
53
|
def set_metadata(path, group_name = nil, options = {}, flag = :cover)
|
49
|
-
cmd = CMD::SET_METADATA
|
50
|
-
|
51
54
|
unless options.is_a?(Hash)
|
52
55
|
flag = options
|
53
56
|
options = {}
|
@@ -57,28 +60,15 @@ module Fastdfs
|
|
57
60
|
options = group_name
|
58
61
|
group_name = nil
|
59
62
|
end
|
60
|
-
|
61
|
-
group_bytes, path_bytes = group_path_bytes(path, group_name)
|
62
|
-
meta_bytes = meta_to_bytes(options)
|
63
|
-
|
64
|
-
size_bytes = Utils.number_to_buffer(path_bytes.length) + Utils.number_to_buffer(meta_bytes.length)
|
65
|
-
size_bytes = (size_bytes).fill(0, size_bytes.length...16)
|
66
|
-
total = size_bytes.length + flag.length + group_bytes.length + path_bytes.length + meta_bytes.length
|
67
|
-
header_bytes = ProtoCommon.header_bytes(cmd, total)
|
68
|
-
@socket.write(cmd, (header_bytes + size_bytes + flag.bytes + group_bytes + path_bytes))
|
69
|
-
@socket.write(cmd, meta_bytes)
|
70
|
-
@socket.receive
|
63
|
+
_set_metadata(path, group_name, options, flag)
|
71
64
|
end
|
72
65
|
|
73
66
|
def download(path, group_name = nil)
|
74
|
-
|
75
|
-
group_bytes, path_bytes = group_path_bytes(path, group_name)
|
67
|
+
path_bytes = group_path_bytes(path, group_name).flatten
|
76
68
|
download_bytes = Utils.number_to_buffer(0) + Utils.number_to_buffer(0)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
@socket.write(cmd, header_bytes + download_bytes + group_bytes + path_bytes)
|
81
|
-
@socket.receive do |body|
|
69
|
+
data = download_bytes + path_bytes
|
70
|
+
client = ClientProxy.new(CMD::DOWNLOAD_FILE, @socket, data.length, data)
|
71
|
+
client.dispose do |body|
|
82
72
|
create_tempfile(path, body) if body
|
83
73
|
end
|
84
74
|
end
|
@@ -86,7 +76,7 @@ module Fastdfs
|
|
86
76
|
private
|
87
77
|
def group_path_bytes(path, group_name = nil)
|
88
78
|
group_name, path = extract_path!(path, group_name)
|
89
|
-
group_bytes = group_name.bytes.
|
79
|
+
group_bytes = group_name.bytes.full_fill(0, ProtoCommon::GROUP_NAME_MAX_LEN)
|
90
80
|
[group_bytes, path.bytes]
|
91
81
|
end
|
92
82
|
|
@@ -105,24 +95,18 @@ module Fastdfs
|
|
105
95
|
return group_name, path
|
106
96
|
end
|
107
97
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
ext_name_bs = extname.bytes.fill(0, extname.length...@extname_len)
|
113
|
-
hex_len_bytes = Utils.number_to_buffer(file.size)
|
114
|
-
size_byte = [@store_path].concat(hex_len_bytes).fill(0, (hex_len_bytes.length+1)...@size_len)
|
98
|
+
def _set_metadata(path, group_name = nil, options = {}, flag = :cover)
|
99
|
+
flag = convert_meta_flag(flag)
|
100
|
+
group_bytes, path_bytes = group_path_bytes(path, group_name)
|
101
|
+
meta_bytes = meta_to_bytes(options)
|
115
102
|
|
116
|
-
|
117
|
-
|
103
|
+
size_bytes = Utils.number_to_buffer(path_bytes.length) + Utils.number_to_buffer(meta_bytes.length)
|
104
|
+
size_bytes = (size_bytes).full_fill(0, 16)
|
105
|
+
total = size_bytes.length + flag.length + group_bytes.length + path_bytes.length + meta_bytes.length
|
118
106
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
group_name_max_len = ProtoCommon::GROUP_NAME_MAX_LEN
|
123
|
-
|
124
|
-
{group_name: body[0...group_name_max_len].strip, path: body[group_name_max_len..-1]}
|
125
|
-
end
|
107
|
+
client = ClientProxy.new(CMD::SET_METADATA, @socket, total, (size_bytes + flag.bytes + group_bytes + path_bytes))
|
108
|
+
client.push_content{ meta_bytes }
|
109
|
+
client.dispose
|
126
110
|
end
|
127
111
|
|
128
112
|
def convert_meta_flag(flag)
|
@@ -4,10 +4,6 @@ module Fastdfs
|
|
4
4
|
module Client
|
5
5
|
|
6
6
|
class Tracker
|
7
|
-
extend Hook
|
8
|
-
|
9
|
-
before(:get_storage){ @socket.connection }
|
10
|
-
after(:get_storage){ @socket.close }
|
11
7
|
|
12
8
|
attr_accessor :socket, :cmd, :options
|
13
9
|
|
@@ -17,16 +13,15 @@ module Fastdfs
|
|
17
13
|
end
|
18
14
|
|
19
15
|
def get_storage
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
storage_ip = @socket.content[ProtoCommon::IPADDR].strip
|
26
|
-
storage_port = @socket.content[ProtoCommon::PORT].unpack("C*").to_pack_long
|
27
|
-
store_path = @socket.content[ProtoCommon::TRACKER_BODY_LEN-1].unpack("C*")[0]
|
16
|
+
client = ClientProxy.new(@cmd, @socket, 0)
|
17
|
+
res = client.dispose do |body|
|
18
|
+
storage_ip = body[ProtoCommon::IPADDR].strip
|
19
|
+
storage_port = body[ProtoCommon::PORT].unpack("C*").to_pack_long
|
20
|
+
store_path = body[ProtoCommon::TRACKER_BODY_LEN-1].unpack("C*")[0]
|
28
21
|
|
29
|
-
|
22
|
+
Storage.new(storage_ip, storage_port, store_path, options)
|
23
|
+
end
|
24
|
+
res[:status] ? res[:result] : res
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
data/spec/storage_spec.rb
CHANGED
@@ -8,47 +8,53 @@ describe Fastdfs::Client::Storage do
|
|
8
8
|
let(:tracker){ FC::Tracker.new(host, port) }
|
9
9
|
let(:storage){ tracker.get_storage }
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
11
|
+
it "initialize the server" do
|
12
|
+
expect(FC::Socket).to receive(:new).with(host, port, nil)
|
13
|
+
FC::Storage.new(host, port)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have access to the storage connection" do
|
17
|
+
expect(storage.socket).to receive(:connection)
|
18
|
+
expect(storage.socket).to receive(:close)
|
19
|
+
storage.upload(TestConfig::FILE)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have access to the storage connection for 2 items" do
|
23
|
+
expect(storage.socket).to receive(:connection).at_most(2).times
|
24
|
+
expect(storage.socket).to receive(:close).at_most(2).times
|
25
|
+
storage.upload(TestConfig::FILE, {author: "kaka", width: "800"})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should the result attributes group_name and path" do
|
29
|
+
res = storage.upload(TestConfig::FILE)
|
30
|
+
expect(res[:status]).to be_truthy
|
31
|
+
expect(res[:result]).to include(:group_name)
|
32
|
+
expect(res[:result]).to include(:path)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can delete file by group and path" do
|
36
|
+
res = storage.upload(TestConfig::FILE)[:result]
|
37
|
+
storage.delete(res[:path], res[:group_name])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can delete file raise exception" do
|
41
|
+
res = storage.upload(TestConfig::FILE)[:result]
|
42
|
+
result = FC::ProtoCommon.header_bytes(FC::CMD::RESP_CODE, 0, 22)
|
43
|
+
TCPSocket.any_instance.stub("recv").and_return(result.pack("C*"))
|
44
|
+
expect( storage.delete("fdsaf", res[:group_name])[:status] ).to be_falsey
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can get metadata results" do
|
48
|
+
res = storage.get_metadata("#{TestConfig::GROUP_NAME}/#{TestConfig::FILE_NAME}")
|
49
|
+
expect(res[:result]).to eq(TestConfig::METADATA)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can set metadata" do
|
53
|
+
expect(storage.set_metadata(TestConfig::FILE_NAME, TestConfig::GROUP_NAME, TestConfig::METADATA)).to be_truthy
|
54
|
+
end
|
49
55
|
|
50
56
|
it "download the file to the local" do
|
51
|
-
res = storage.download(
|
57
|
+
res = storage.download(TestConfig::FILE_NAME, TestConfig::GROUP_NAME)
|
52
58
|
expect(res[:status]).to be_truthy
|
53
59
|
expect(res[:result]).to be_an_instance_of(Tempfile)
|
54
60
|
expect(IO.read(res[:result])).to eq(IO.read(TestConfig::FILE))
|
data/spec/tracker_spec.rb
CHANGED
@@ -30,10 +30,10 @@ describe Fastdfs::Client::Tracker do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "run server flow" do
|
33
|
-
storage = tracker.get_storage
|
34
|
-
puts "#{storage.host}, #{storage.port}"
|
35
|
-
results = storage.upload(File.open("/Users/huxinghai/Documents/shark/app/assets/images/page.png"))
|
36
|
-
puts results
|
33
|
+
# storage = tracker.get_storage
|
34
|
+
# puts "#{storage.host}, #{storage.port}"
|
35
|
+
# results = storage.upload(File.open("/Users/huxinghai/Documents/shark/app/assets/images/page.png"))
|
36
|
+
# puts results
|
37
37
|
# puts storage.delete(results[:path], results[:group_name])
|
38
38
|
end
|
39
39
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastdfs-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ka Ka
|
@@ -37,9 +37,9 @@ files:
|
|
37
37
|
- README.md
|
38
38
|
- fastdfs-client.gemspec
|
39
39
|
- lib/fastdfs-client.rb
|
40
|
+
- lib/fastdfs-client/client_proxy.rb
|
40
41
|
- lib/fastdfs-client/cmd.rb
|
41
42
|
- lib/fastdfs-client/extend_core.rb
|
42
|
-
- lib/fastdfs-client/hook.rb
|
43
43
|
- lib/fastdfs-client/proto_common.rb
|
44
44
|
- lib/fastdfs-client/socket.rb
|
45
45
|
- lib/fastdfs-client/storage.rb
|
data/lib/fastdfs-client/hook.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Hook
|
2
|
-
def before(*meth_names, &callback)
|
3
|
-
meth_names.each{|meth_name| add_hook :before, meth_name, &callback }
|
4
|
-
end
|
5
|
-
|
6
|
-
def after(*meth_names, &callback)
|
7
|
-
meth_names.each{|meth_name| add_hook :after, meth_name, &callback }
|
8
|
-
end
|
9
|
-
|
10
|
-
def hooks
|
11
|
-
@hooks ||= Hash.new do |hash, method_name|
|
12
|
-
hash[method_name] = { before: [], after: [], hijacked: false }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def add_hook(where, meth_name, &callback)
|
17
|
-
hooks[meth_name][where] << callback
|
18
|
-
ensure_hijacked meth_name
|
19
|
-
end
|
20
|
-
|
21
|
-
def method_added(meth_name)
|
22
|
-
ensure_hijacked meth_name if hooks.has_key? meth_name
|
23
|
-
end
|
24
|
-
|
25
|
-
def ensure_hijacked(meth_name)
|
26
|
-
return if hooks[meth_name][:hijacked] || !instance_methods.include?(meth_name)
|
27
|
-
meth = instance_method meth_name
|
28
|
-
_hooks = hooks
|
29
|
-
_hooks[meth_name][:hijacked] = true
|
30
|
-
define_method meth_name do |*args, &block|
|
31
|
-
_hooks[meth_name][:before].each do |callback|
|
32
|
-
self.instance_exec(&callback)
|
33
|
-
end
|
34
|
-
begin
|
35
|
-
return_value = meth.bind(self).call *args, &block
|
36
|
-
ensure
|
37
|
-
_hooks[meth_name][:after].each do |callback|
|
38
|
-
self.instance_exec(&callback)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
return_value
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|