rtfs 0.1.2 → 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.
data/README.md CHANGED
@@ -1,19 +1,30 @@
1
1
  RTFS
2
2
  ====
3
3
 
4
- RTFS is a Ruby Client for TFS.
4
+ RTFS is a Ruby Client of [TFS](http://code.taobao.org/project/view/366/).
5
5
 
6
- [About TFS](http://code.taobao.org/project/view/366/)
6
+ For TFS integration with CarrierWave, see
7
+ [carrierwave-tfs](http://github.com/huacnlee/carrierwave-tfs) for more
8
+ information.
7
9
 
8
- This is basicly library for TFS access, you can use [carrierwave-tfs](http://github.com/huacnlee/carrierwave-tfs) for Carrierwave.
9
10
 
10
11
  Requirements
11
12
  ------------
12
13
 
13
- * Linux System (TFS only success build in Linux system.)
14
- * TFS
14
+ * <del>Linux System (tfstool can only be built on Linux Systems).</del>
15
+ * <del>tfstool</del>
15
16
 
16
- INSTALL
17
+ 2013-03-14
18
+
19
+ These are no longer valid requirements. TFS now favors
20
+ [Web Service API](http://baike.corp.taobao.com/index.php/CS_RD/tfs/use_web_service),
21
+ which requires nothing but a decent REST client of the language you choose.
22
+
23
+ See the [official documentation](http://baike.corp.taobao.com/index.php/CS_RD/tfs)
24
+ for more information about APIs and service applications.
25
+
26
+
27
+ Install
17
28
  -------
18
29
 
19
30
  ```bash
@@ -23,16 +34,16 @@ $ gem install rtfs
23
34
  Configure
24
35
  ---------
25
36
 
26
- create this files before using.
37
+ or How to integrate into Rails app.
27
38
 
28
- config/tfs.yml
39
+ Create `tfs.yml` in your rails app's config directory. The content of it should
40
+ look like this:
29
41
 
30
42
  ```yaml
43
+ # config/tfs.yml
31
44
  defaults: &defaults
32
- host: '127.0.0.1:3100'
33
- # or use WebService
34
45
  host: 'http://127.0.0.1:3900'
35
- appkey: "......."
46
+ appkey: "myprecious"
36
47
 
37
48
  development:
38
49
  <<: *defaults
@@ -44,21 +55,24 @@ production:
44
55
  <<: *defaults
45
56
  ```
46
57
 
47
- config/initialize/tfs.rb
58
+ Create an initializer too. Call it `tfs.rb` or whatever filename you fancy:
59
+
48
60
 
49
61
  ```ruby
62
+ # config/initializers/tfs.rb
50
63
  require 'rtfs'
51
64
  tfs_config = YAML.load_file("#{Rails.root}/config/tfs.yml")[Rails.env]
52
65
  $tfs = RTFS::Client.tfs(tfs_config.merge({:ns_addr => tfs_config['host']}))
53
66
  ```
54
67
 
55
- :ns_addr include http:// tfs used webservice
68
+ Then `$tfs` will be available as a global object.
56
69
 
57
70
 
58
- Usage
59
- -----
71
+ Simple Usage
72
+ ------------
60
73
 
61
74
  ```ruby
75
+ # app/controllers/users_controller.rb
62
76
  class UsersController < ApplicationController
63
77
  def save
64
78
  @user = User.new
@@ -68,7 +82,7 @@ class UsersController < ApplicationController
68
82
  end
69
83
  end
70
84
 
71
-
85
+ # app/models/user.rb
72
86
  class User < ActiveRecord::Base
73
87
  def avatar_url
74
88
  server_id = self.id % 4 + 1
@@ -77,9 +91,47 @@ class User < ActiveRecord::Base
77
91
  end
78
92
  ```
79
93
 
80
- Put local file to TFS
94
+ Put local file into TFS server:
81
95
 
82
96
  ```bash
97
+ $ bundle exec rails c
83
98
  irb> $tfs.put("~/Downloads/a.jpg")
84
99
  T1Ub1XXeFBXXb1upjX
85
- RTFS
100
+ RTFS
101
+ ```
102
+
103
+
104
+ API
105
+ ---
106
+
107
+ ```ruby
108
+ # initialize client.
109
+ tfs = RTFS::Client.new(:ns_addr => 'http://127.0.0.1:3800',
110
+ :appkey => 'myprecious',
111
+ :basedir => Rails.root.join('public'))
112
+
113
+ # simply put file.
114
+ tfs.put('foo.jpg') # ==> T1Ub1XXeFBXXb1upjX
115
+
116
+ # stat file.
117
+ tfs.stat('T1Ub1XXeFBXXb1upjX')
118
+
119
+ # remove file.
120
+ tfs.rm('T1Ub1XXeFBXXb1upjX')
121
+
122
+ # put named file, keep that name in TFS.
123
+ tfs.save('foo.jpg') # ==> 133/7463/foo.jpg
124
+
125
+ # remove named file.
126
+ tfs.del('foo.jpg') # ==> true
127
+
128
+ # put files under public folder, and preserve its name.
129
+ # will prepend the basedir in front of the file path passed in.
130
+ tfs.save('jquery.js')
131
+ ```
132
+
133
+
134
+ Executabes?
135
+ -----------
136
+
137
+ RTFS will be available as a executable binary soon. Stay tuned...
@@ -10,13 +10,10 @@ def require_local(suffix)
10
10
  end
11
11
 
12
12
  require 'rubygems'
13
- require 'nice-ffi'
14
13
  require 'yaml'
15
14
 
16
15
  # require_local 'rtfs/wrapper.rb'
17
16
  require 'rtfs/client.rb'
18
- require 'rtfs/web_service.rb'
19
- require 'rtfs/tfstool.rb'
20
17
  require 'rtfs/meta.rb'
21
18
  require 'rtfs/version.rb'
22
19
 
@@ -1,21 +1,203 @@
1
1
  # coding: utf-8
2
2
  # Code for client
3
3
  # by nowa<nowazhu@gmail.com> 2011-07-23
4
+ require 'rest-client'
5
+ require 'open-uri'
6
+ require 'digest'
7
+ require 'json'
8
+
4
9
  module RTFS
5
10
 
6
11
  class Client
7
12
 
8
13
  # 参数:
9
- # :ns_addr TFS 服务器地址,如 127.0.0.1:3100
10
- # :tfstool_path tfstool 安装路径,默认 /home/admin/tfs/bin/tfstool
14
+ # :root TFS WebService Root 服务器地址,如 127.0.0.1:3100
11
15
  def self.tfs(options)
12
- return nil unless options
13
- if options[:ns_addr].include?("http://")
14
- return RTFS::WebService.new(options)
16
+ self.new(options) if options
17
+ end
18
+
19
+ attr_accessor :nameservers
20
+ attr_accessor :appkey
21
+ attr_accessor :uid
22
+
23
+ def initialize(options)
24
+ # 通过 ns_addr 的地址获取负载均衡的地址
25
+ @nameservers = open("#{options[:ns_addr]}/tfs.list").read.split("\n")
26
+ @appkey = options[:appkey]
27
+
28
+ @basedir = options[:basedir]
29
+ @uid = options[:uid]
30
+
31
+ if @uid.nil? && !@basedir.nil?
32
+ (Digest::MD5.hexdigest(@basedir).to_i(16) % 10000)
33
+ end
34
+ end
35
+
36
+ # 获取文件
37
+ def get(tfs_name)
38
+ http_get("/v1/#{appkey}/#{tfs_name}")
39
+ end
40
+
41
+ # 上传文件
42
+ # 参数:
43
+ # file_path 需要上传的文件路径
44
+ # :ext 扩展名,默认会取 file_path 的扩展名, 如: .jpg
45
+ # 返回值
46
+ # T1lpVcXftHXXaCwpjX
47
+ def put(path, options = {})
48
+ ext = options[:ext] || File.extname(path)
49
+ path = path.to_s
50
+ resp = http_post("/v1/#{appkey}",
51
+ File.open(path.start_with?('/') ? path : fpath(path)).read,
52
+ :params => {
53
+ :suffix => ext,
54
+ :simple_name => options[:simple_name] || 0
55
+ },
56
+ :accept => :json)
57
+
58
+ json = JSON.parse(resp)
59
+ json && json['TFS_FILE_NAME']
60
+ end
61
+
62
+ # 上传文件 并返回完整 url (only for Taobao)
63
+ def put_and_get_url(path, options = {})
64
+ ext = options[:ext] || File.extname(path)
65
+ path = path.to_s
66
+ tname = put(path, :ext => ext)
67
+
68
+ "http://img0#{rand(4)+1}.taobaocdn.com/tfscom/#{t}#{ext}" unless tname.nil?
69
+ end
70
+
71
+ # 删除文件, 不能带扩展名
72
+ def rm(tname, options = {})
73
+ resp = http_delete("/v1/#{appkey}/#{tname}", :params => options)
74
+
75
+ resp && resp.code == 200
76
+ end
77
+
78
+ # 文件信息查看, 不能带扩展名
79
+ def stat(tname, options = {})
80
+ resp = http_get("/v1/#{appkey}/metadata/#{tname}", :params => options)
81
+
82
+ if resp && resp.code == 200
83
+ JSON.parse(resp)
84
+ end
85
+ end
86
+
87
+ def save(path, options = {})
88
+ path = path.to_s
89
+
90
+ if finger(path)
91
+ del(path)
92
+ save(path)
93
+ elsif create(path)
94
+ write(path)
95
+ end
96
+ end
97
+
98
+ def create(path, options = {})
99
+ resp = http_post(furl(path), nil,
100
+ :params => {:recursive => 1})
101
+
102
+ resp && resp.code == 201
103
+ end
104
+
105
+ def write(path, options = {})
106
+ data = File.open(fpath(path)).read
107
+ return if data.length == 0
108
+ resp = http_put(furl(path), data,
109
+ :params => {:offset => 0})
110
+
111
+ if resp && resp.code == 200
112
+ [appid, fuid(path), path].join('/')
113
+ end
114
+ end
115
+
116
+ def del(path, options = {})
117
+ resp = http_delete(furl(path))
118
+
119
+ resp && resp.code == 200
120
+ end
121
+
122
+ def finger(path, options = {})
123
+ begin
124
+ resp = http_head(furl(path))
125
+
126
+ resp && resp.code == 200
127
+ rescue RestClient::ResourceNotFound
128
+ # this rescue is intended.
129
+ # the purpose is to return nil if the path fingered returned 404.
130
+ # hence there's nothing more to do.
131
+ end
132
+ end
133
+
134
+ def appid
135
+ return @appid unless @appid.nil?
136
+
137
+ resp = http_get("/v2/#{appkey}/appid")
138
+
139
+ if resp && resp.code == 200
140
+ @appid = JSON.parse(resp)['APP_ID']
141
+ end
142
+ end
143
+
144
+
145
+ private
146
+
147
+ def http_get(url, *args)
148
+ RestClient.get("#{nameserver}#{url}", *args)
149
+ end
150
+
151
+ def http_post(url, *args)
152
+ RestClient.post("#{nameserver}#{url}", *args)
153
+ end
154
+
155
+ def http_delete(url, *args)
156
+ RestClient.delete("#{nameserver}#{url}", *args)
157
+ end
158
+
159
+ def http_put(url, *args)
160
+ RestClient.put("#{nameserver}#{url}", *args)
161
+ end
162
+
163
+ def http_head(url, *args)
164
+ RestClient.head("#{nameserver}#{url}", *args)
165
+ end
166
+
167
+ # 随机取一个 nameserver 用于访问,tfs.list 内容如下:
168
+ #
169
+ # 50
170
+ # 10.246.65.133:3900
171
+ # 10.246.65.132:3900
172
+ # 10.246.65.131:3900
173
+ # 10.246.65.130:3900
174
+ # 10.246.73.70:3900
175
+ # 10.246.73.71:3900
176
+ # 10.246.73.72:3900
177
+ #
178
+ def nameserver
179
+ # 现在第一行是 50,表示频次,访问 50 次就要更新
180
+ @nameservers[rand(@nameservers.size - 1) + 1]
181
+ end
182
+
183
+ # TFS 中需要这个 User ID,用来分散数据请求,减轻单台机器压力,最方便 uid 获取方式是,
184
+ # 对传入的文件路径做哈希,取后几位。但是如果要把 TFS 当普通 CDN 使用,
185
+ # 能够使用确定的 URL 更新文件的话,User ID 必须固定,只能不定期批量更新。
186
+ # 因此这里也允许使用实例化时传入的 uid 参数。
187
+ def fuid(path = nil)
188
+ if @uid.nil? && path.nil?
189
+ 1
15
190
  else
16
- return RTFS::Tfstool.new(options)
191
+ @uid || Digest::MD5.hexdigest(path).to_i(16) % 10000
17
192
  end
18
193
  end
19
194
 
195
+ def furl(path)
196
+ "/v2/#{appkey}/#{appid}/#{fuid(path)}/file/#{path}"
197
+ end
198
+
199
+ def fpath(path)
200
+ @basedir ? File.join(@basedir, path) : path
201
+ end
20
202
  end
21
203
  end
@@ -4,8 +4,8 @@
4
4
 
5
5
  module RTFS::Version
6
6
  MAJOR = 0
7
- MINOR = 1
8
- REVISION = 2
7
+ MINOR = 2
8
+ REVISION = 0
9
9
 
10
10
  class << self
11
11
  # Returns X.Y.Z formatted version string
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'open-uri'
3
+
4
+ describe 'Basic operations' do
5
+ it 'should put and remove file' do
6
+ fname = $tfs.put('spec/a.jpg')
7
+
8
+ f = open("http://img01.daily.taobaocdn.net/tfscom/#{fname}.jpg")
9
+ f.read.length.should eq(6511)
10
+
11
+ $tfs.rm(fname).should eq(true)
12
+ end
13
+
14
+ it 'should stat file' do
15
+ fname = $tfs.put('spec/a.jpg')
16
+ stat = $tfs.stat(fname)
17
+
18
+ stat.should.is_a? Hash
19
+ stat['FILE_NAME'].should eq(fname)
20
+ stat['SIZE'].should eq(6511)
21
+
22
+ $tfs.rm(fname)
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'open-uri'
3
+
4
+ describe 'custom operations' do
5
+ it 'should save named file' do
6
+ path = $tfs.save('spec/a.jpg')
7
+
8
+ f = open("http://img01.daily.taobaocdn.net/L1/#{path}")
9
+ f.read.length.should eq(6511)
10
+
11
+ $tfs.del('spec/a.jpg').should eq(true)
12
+ end
13
+
14
+ it 'should expose appid' do
15
+ $tfs.appid.should eq('133')
16
+ end
17
+
18
+ it 'should respect global uid settings' do
19
+ # 自动生成的 uid 是经过 % 10000 的,也就是说,不会超过 10000,
20
+ # 所以,自定义 uid 只要大于等于 10000,就尽管用吧
21
+ $tfs.uid = 10000
22
+ path = $tfs.save('spec/a.jpg')
23
+
24
+ path.should =~ /10000/
25
+
26
+ # $tfs.del('spec/a.jpg').should eq(true)
27
+ end
28
+ end
@@ -1,3 +1,8 @@
1
1
  require "rtfs"
2
2
 
3
- $tfs = RTFS::Client.tfs(:ns_addr => "http://10.232.4.44:3800", :appkey => '4f8fbb734d4d8')
3
+ RSpec.configure do |config|
4
+ config.color = true
5
+ end
6
+
7
+ $tfs = RTFS::Client.tfs(:ns_addr => 'http://10.232.4.44:3800',
8
+ :appkey => '4f8fbb734d4d8')
metadata CHANGED
@@ -1,26 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nowa Zhu
9
9
  - Jason Lee
10
10
  - Cricy
11
+ - Jake Chen
11
12
  autorequire:
12
13
  bindir: bin
13
14
  cert_chain: []
14
- date: 2012-11-23 00:00:00.000000000 Z
15
+ date: 2013-03-15 00:00:00.000000000 Z
15
16
  dependencies:
16
17
  - !ruby/object:Gem::Dependency
17
- name: nice-ffi
18
+ name: rest-client
18
19
  requirement: !ruby/object:Gem::Requirement
19
20
  none: false
20
21
  requirements:
21
22
  - - ! '>='
22
23
  - !ruby/object:Gem::Version
23
- version: '0.4'
24
+ version: 1.6.0
24
25
  type: :runtime
25
26
  prerelease: false
26
27
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,7 +29,23 @@ dependencies:
28
29
  requirements:
29
30
  - - ! '>='
30
31
  - !ruby/object:Gem::Version
31
- version: '0.4'
32
+ version: 1.6.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ requirement: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ type: :development
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
32
49
  - !ruby/object:Gem::Dependency
33
50
  name: rest-client
34
51
  requirement: !ruby/object:Gem::Requirement
@@ -37,7 +54,7 @@ dependencies:
37
54
  - - ! '>='
38
55
  - !ruby/object:Gem::Version
39
56
  version: 1.6.0
40
- type: :runtime
57
+ type: :development
41
58
  prerelease: false
42
59
  version_requirements: !ruby/object:Gem::Requirement
43
60
  none: false
@@ -45,11 +62,28 @@ dependencies:
45
62
  - - ! '>='
46
63
  - !ruby/object:Gem::Version
47
64
  version: 1.6.0
65
+ - !ruby/object:Gem::Dependency
66
+ name: rspec
67
+ requirement: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ version: '2.5'
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: '2.5'
48
81
  description:
49
82
  email:
50
83
  - nowazhu@gmail.com
51
84
  - huacnlee@gmail.com
52
85
  - feiyelanghai@gmail.com
86
+ - jakeplus@gmail.com
53
87
  executables: []
54
88
  extensions: []
55
89
  extra_rdoc_files:
@@ -57,24 +91,19 @@ extra_rdoc_files:
57
91
  - CHANGES.md
58
92
  - MIT-LICENSE
59
93
  files:
60
- - .gitignore
61
- - CHANGES.md
62
- - MIT-LICENSE
63
- - README.md
64
- - lib/rtfs.rb
65
94
  - lib/rtfs/client.rb
66
95
  - lib/rtfs/meta.rb
67
- - lib/rtfs/tfstool.rb
68
96
  - lib/rtfs/version.rb
69
- - lib/rtfs/web_service.rb
70
- - lib/rtfs/wrapper.rb
71
- - rtfs.gemspec
72
- - spec/a.jpg
73
- - spec/b.jpg
97
+ - lib/rtfs.rb
98
+ - README.md
99
+ - CHANGES.md
100
+ - MIT-LICENSE
101
+ - spec/basics_spec.rb
102
+ - spec/custom_spec.rb
74
103
  - spec/spec_helper.rb
75
- - spec/upload_spec.rb
76
104
  homepage: https://github.com/nowa/rtfs
77
- licenses: []
105
+ licenses:
106
+ - MIT
78
107
  post_install_message:
79
108
  rdoc_options: []
80
109
  require_paths:
@@ -98,7 +127,6 @@ signing_key:
98
127
  specification_version: 3
99
128
  summary: RTFS is a Ruby Client for TFS.
100
129
  test_files:
101
- - spec/a.jpg
102
- - spec/b.jpg
130
+ - spec/basics_spec.rb
131
+ - spec/custom_spec.rb
103
132
  - spec/spec_helper.rb
104
- - spec/upload_spec.rb
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- pkg/*
2
- .DS_Store
3
- *.gem
@@ -1,89 +0,0 @@
1
- # coding: utf-8
2
- module RTFS
3
-
4
- TFSTOOL_PATH = "/home/admin/tfs/bin/tfstool"
5
- class Tfstool
6
-
7
- attr_accessor :ns_addr
8
- attr_accessor :tfstool_path
9
-
10
- # 参数:
11
- # :ns_addr TFS 服务器地址,如 127.0.0.1:3100
12
- # :tfstool_path tfstool 安装路径,默认 /home/admin/tfs/bin/tfstool
13
- def initialize(options)
14
- return nil unless options
15
- @ns_addr = options[:ns_addr]
16
- @tfstool_path = options[:tfstool_path] ? options[:tfstool_path] : TFSTOOL_PATH
17
- if not File.exist?(@tfstool_path)
18
- puts "[RTFS] debuger: #{@tfstool_path}"
19
- raise NoTFSToolError.new
20
- end
21
- end
22
-
23
- # 获取文件
24
- def get(tfs_name, local_file=nil)
25
- local_file ||= tfs_name
26
- `#{tfstool_cmd} -i "get #{tfs_name} #{local_file}"`
27
- end
28
-
29
- # 上传文件
30
- # 参数:
31
- # file_path 需要上传的文件路径
32
- # :ext 扩展名,默认会取 file_path 的扩展名, 如: .jpg
33
- # 返回值
34
- # T1lpVcXftHXXaCwpjX
35
- def put(file_path, options = {})
36
- ext = options[:ext] || File.extname(file_path)
37
- tfs_name = "NULL"
38
- result = `#{tfstool_cmd} -i "put #{file_path} #{tfs_name} #{ext}"`
39
- # puts "result: #{result}"
40
- t = nil
41
- if result.include?("=> ")
42
- result = result.split("=> ").last
43
- if result.include?(",")
44
- t = result.split(",").first
45
- end
46
- end
47
- t.nil? ? nil : t
48
- end
49
-
50
- # 上传文件 并返回完整 url (only for Taobao)
51
- def put_and_get_url(file_path, options = {})
52
- ext = options[:ext] || File.extname(file_path)
53
- t = put(file_path, :ext => ext)
54
- t.nil? ? nil : "http://img03.taobaocdn.com/tfscom/#{t}#{ext}"
55
- end
56
-
57
- # 删除文件, 不能带扩展名
58
- def rm(tfs_name)
59
- `#{tfstool_cmd} -i "rm #{tfs_name}"`
60
- end
61
-
62
- # 改名, 不能带扩展名
63
- def rename(tfs_name, new_name)
64
- `#{tfstool_cmd} -i "rename #{tfs_name} #{new_name}"`
65
- end
66
-
67
- # 文件信息查看, 不能带扩展名
68
- def stat(tfs_name)
69
- result = `#{tfstool_cmd} -i "stat #{tfs_name}"`
70
- stat = {}
71
- result.split("\n").each do |line|
72
- line = line.split(':').map {|i| i.gsub!(" ", "")}
73
- stat["#{line.first}"] = line.last
74
- end
75
- stat
76
- end
77
-
78
- protected
79
- def tfstool_cmd
80
- "#{@tfstool_path} -n -s #{@ns_addr}"
81
- end
82
- end
83
-
84
- class NoTFSToolError < RuntimeError
85
- def to_s
86
- "You must install tfs from yum or source first!"
87
- end
88
- end # NoTFSToolError
89
- end
@@ -1,96 +0,0 @@
1
- # coding: utf-8
2
- require 'rest-client'
3
- require 'open-uri'
4
- require "json"
5
-
6
- module RTFS
7
- class WebService
8
-
9
- attr_accessor :appkey
10
- attr_accessor :ns_addrs
11
-
12
- def initialize(options)
13
- return nil unless options
14
- # 通过 ns_addr 的地址获取负载均衡的地址
15
- @ns_addrs ||= open("#{options[:ns_addr]}/tfs.list").read.split("\n")
16
- @appkey = options[:appkey]
17
- end
18
-
19
- # 随机取一个 ns_addr 用于访问
20
- # 50
21
- # 10.246.65.133:3900
22
- # 10.246.65.132:3900
23
- # 10.246.65.131:3900
24
- # 10.246.65.130:3900
25
- # 10.246.73.70:3900
26
- # 10.246.73.71:3900
27
- # 10.246.73.72:3900
28
- def ns_addr
29
-
30
- #现在第一行是50,表示频次,访问50次就要更新
31
- @ns_addrs[rand(@ns_addrs.size - 1) + 1]
32
- end
33
-
34
- # 获取文件
35
- def get(tfs_name, local_file=nil)
36
- RestClient.get(get_url("/v1/#{appkey}/#{tfs_name}"))
37
- end
38
-
39
- # 上传文件
40
- # 参数:
41
- # file_path 需要上传的文件路径
42
- # :ext 扩展名,默认会取 file_path 的扩展名, 如: .jpg
43
- # 返回值
44
- # T1lpVcXftHXXaCwpjX
45
- def put(file_path, options = {})
46
- ext = options[:ext] || File.extname(file_path)
47
- response = RestClient.post(get_url("/v1/#{appkey}",{:suffix => ext, :simple_name => options[:simple_name] || 0}),File.open(file_path).read, :accept => :json )
48
- json = JSON.parse(response)
49
- json && json["TFS_FILE_NAME"] ? json["TFS_FILE_NAME"] : nil
50
- end
51
-
52
- # 上传文件 并返回完整 url (only for Taobao)
53
- def put_and_get_url(file_path, options = {})
54
- ext = options[:ext] || File.extname(file_path)
55
- t = put(file_path, :ext => ext)
56
- t.nil? ? nil : "http://img0#{rand(4)+1}.taobaocdn.com/tfscom/#{t}#{ext}"
57
- end
58
-
59
- # 删除文件, 不能带扩展名
60
- def rm(tfs_name,options = {})
61
- response = RestClient.delete(get_url("/v1/#{appkey}/#{tfs_name}", options))
62
- response && response.code == 200 ? true : nil
63
- end
64
-
65
- # 改名, 不能带扩展名
66
- def rename(tfs_name, new_name)
67
- #`#{tfstool_cmd} -i "rename #{tfs_name} #{new_name}"`
68
- end
69
-
70
- # 文件信息查看, 不能带扩展名
71
- def stat(tfs_name,options = {})
72
- response = RestClient.get(get_url("/v1/#{appkey}/metadata/#{tfs_name}", options))
73
- response && response.code == 200 ? JSON.parse(response) : nil
74
- end
75
-
76
- def client_name
77
- "WebService"
78
- end
79
-
80
- private
81
-
82
- def appkey
83
- @appkey
84
- end
85
-
86
- def get_url(url,opts = {})
87
- return url unless opts
88
- url = "#{self.ns_addr}#{url}"
89
- params = []
90
- opts.each{ |k,v|
91
- params << "#{k}=#{v}"
92
- }
93
- url.include?("?") ? "#{url}&#{params.join("&")}" : "#{url}?#{params.join("&")}"
94
- end
95
- end
96
- end
@@ -1,68 +0,0 @@
1
- # coding: utf-8
2
- # 使用ffi和nice-ffi来调用动态库的c接口
3
- # tfsclient c api目前尚不完善,基于c接口的封装调用不能满足需求
4
- # 因此目前不使用该wrapper,文件暂存
5
- # by nowa<nowazhu@gmail.com> 2011-07-23
6
-
7
- module LibC
8
- extend FFI::Library
9
- # figures out the correct libc for each platform including Windows
10
- library = ffi_lib(FFI::Library::LIBC).first
11
-
12
- # Size_t not working properly on Windows
13
- find_type(:size_t) rescue typedef(:ulong, :size_t)
14
-
15
- # memory allocators
16
- attach_function :malloc, [:size_t], :pointer
17
- attach_function :free, [:pointer], :void
18
-
19
- # get a pointer to the free function; used for ZMQ::Message deallocation
20
- Free = library.find_symbol('free')
21
-
22
- # memory movers
23
- attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
24
- end # module LibC
25
-
26
- module LibRTFS
27
- extend NiceFFI::Library
28
-
29
- libs_dir = "/home/admin/tfs/lib/"
30
- pathset = NiceFFI::PathSet::DEFAULT.prepend(libs_dir)
31
-
32
- load_library("tfsclient_c", pathset)
33
-
34
- attach_function :t_initialize, [:string, :int, :int], :int
35
-
36
- #enum OpenFlag
37
- # {
38
- # T_READ = 1,
39
- # T_WRITE = 2,
40
- # T_CREATE = 4,
41
- # T_NEWBLK = 8,
42
- # T_NOLEASE = 16,
43
- # T_STAT = 32,
44
- # T_LARGE = 64
45
- # };
46
- attach_function :t_open, [:string, :string, :string, :int, :string], :int
47
- attach_function :t_read, [:int, :pointer, :int], :int
48
- attach_function :t_write, [:int, :pointer, :int], :int
49
- attach_function :t_lseek, [:int, :int, :int], :int
50
- attach_function :t_pread, [:int, :pointer, :int, :int], :int
51
- attach_function :t_pwrite, [:int, :pointer, :int, :int], :int
52
- attach_function :t_fstat, [:int, :pointer, :int], :int
53
- attach_function :t_close, [:int, :string, :int], :int
54
- attach_function :t_unlink, [:string, :string, :int], :int
55
- end
56
-
57
- # 下面这部分代码仅供测试LibRTFS
58
- # LibRTFS.t_initialize("10.232.35.32:3100", 5, 1000)
59
- # fd = LibRTFS.t_open("test", ".png", nil, 2, nil)
60
- # puts "fd: #{fd}"
61
- #
62
- # ori_file = nil
63
- # File.open("/home/xifeng/1.png", "r") do |f|
64
- # ori_file = f.read
65
- # end
66
- # buffer = LibC.malloc ori_file.size
67
- # buffer.write_string ori_file, ori_file.size
68
- # puts "write: #{LibRTFS.t_write(fd, buffer, ori_file.size)}"
@@ -1,19 +0,0 @@
1
- # coding: utf-8
2
- Gem::Specification.new do |s|
3
- s.name = "rtfs"
4
- s.version = "0.1.2"
5
- s.platform = Gem::Platform::RUBY
6
- s.has_rdoc = true
7
- s.extra_rdoc_files = ["README.md","CHANGES.md","MIT-LICENSE",]
8
- s.summary = "RTFS is a Ruby Client for TFS."
9
- s.author = ["Nowa Zhu","Jason Lee","Cricy"]
10
- s.email = ["nowazhu@gmail.com","huacnlee@gmail.com","feiyelanghai@gmail.com"]
11
- s.homepage = "https://github.com/nowa/rtfs"
12
- s.files = `git ls-files`.split("\n")
13
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
- s.require_paths = ["lib"]
15
- s.bindir = 'bin'
16
-
17
- s.add_dependency("nice-ffi", ">=0.4")
18
- s.add_dependency("rest-client", ">=1.6.0")
19
- end
data/spec/a.jpg DELETED
Binary file
data/spec/b.jpg DELETED
Binary file
@@ -1,14 +0,0 @@
1
- require "spec_helper"
2
- require "open-uri"
3
-
4
- describe "Base upload" do
5
- it "should upload" do
6
- fname = $tfs.put("spec/a.jpg")
7
- f = open("http://10.232.4.42/tfscom/#{fname}.jpg")
8
- f.read.length.should == 6153
9
-
10
- fname = $tfs.put("spec/b.jpg")
11
- f = open("http://10.232.4.42/tfscom/#{fname}.jpg")
12
- f.read.length.should == 114504
13
- end
14
- end