alipan-sdk 0.1.1 → 0.1.3

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
  SHA256:
3
- metadata.gz: d3f53b591622f3f464672c3e9bb90f51cf0de5d3cd60442513700cb2b13df5ac
4
- data.tar.gz: 635f457fddba0eddd3909dd3f53b872801dfaa041555b802082a9a2850857abd
3
+ metadata.gz: 48a3d90f95f3aec2c203b662aadf32aadf77877a399bebe105ca1283a703afa6
4
+ data.tar.gz: 295a90bea8c0add091d0bda3ec02cfe81787932d2558c06b7afbddc6f49976e2
5
5
  SHA512:
6
- metadata.gz: bcf71c608206c88d31caf4782fe724538128f56acfdfcbe5a88aa13c2413a2d243c2962cef5f6f2af3eae6bbb30ee39e0b7868f80860cda4cd587df7633387bb
7
- data.tar.gz: 87807a884d03c3bc416625f100f28c86813f701dbdd6cb495118e17d1450bb7dbc829662d0a1c58ab3185cafb535f787f277ed4cd13801ebd073df8d26994468
6
+ metadata.gz: 6f73f95422319ff361f1a29b218208f6f1634b3febd1321b8f5cb89af3a11a486808259f59d72e89e09e3af7ab245480ad6f29ce56644aa6c8f09151bb4419cd
7
+ data.tar.gz: 2e14c6f8c68b773c8cdaab666c960f023e5e377e4c8ed8dd41852d0f05efd9de5fe69850bb8e991bfe8d5aeb5055541a01239dccaf4be811fa975f9a6f03ed1f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
- ## [Unreleased]
1
+ ## Change Log
2
2
 
3
3
  ## [0.1.0] - 2025-06-20
4
4
 
5
5
  - Initial release
6
+
7
+ ## [0.1.3] - 2025-07-08
8
+
9
+ - 添加获取文件、上传文件方法
data/README.md CHANGED
@@ -35,9 +35,15 @@ client = Alipan::Client.new({:access_token=>"xxx"})
35
35
  ### 获取drive
36
36
  drive = client.get_drive
37
37
 
38
- ### 获取object
38
+ ### 获取文件列表
39
39
  objects = drive.list_objects
40
40
 
41
+ ### 获取文件
42
+ objects = drive.get_object(key, opts = {}, &block)
43
+
44
+ ### 上传文件
45
+ objects = drive.put_object(key, opts = {}, &block)
46
+
41
47
  ## 更多
42
48
 
43
49
  更多文档请查看:
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alipan
4
+ class Adapter
5
+
6
+ def initialize()
7
+ @producer = Fiber.new do
8
+ yield self if block_given?
9
+ nil
10
+ end
11
+ end
12
+
13
+ def read(length = nil, outbuf = nil)
14
+ chunk = @producer.resume
15
+ outbuf.replace(chunk) if outbuf && chunk
16
+ chunk
17
+ end
18
+
19
+ def write(chunk)
20
+ Fiber.yield chunk.to_s.force_encoding(Encoding::ASCII_8BIT)
21
+ end
22
+
23
+ alias << write
24
+
25
+ def closed?
26
+ false
27
+ end
28
+
29
+ def close
30
+ end
31
+ end
32
+ end
data/lib/alipan/drive.rb CHANGED
@@ -13,5 +13,38 @@ module Alipan
13
13
  def list_objects(opts = {})
14
14
  Iterator::Objects.new(@protocol, resource_drive_id, 'root', opts).to_enum
15
15
  end
16
+
17
+ def get_object(key, opts = {}, &block)
18
+ obj = nil
19
+ file = opts[:file]
20
+ if file
21
+ File.open(File.expand_path(file), 'wb') do |f|
22
+ obj = @protocol.get_object(resource_drive_id, key, opts) do |chunk|
23
+ f.write(chunk)
24
+ end
25
+ end
26
+ elsif block
27
+ obj = @protocol.get_object(resource_drive_id, key, opts, &block)
28
+ else
29
+ obj = @protocol.get_object(resource_drive_id, key, opts)
30
+ end
31
+
32
+ obj
33
+ end
34
+
35
+ def put_object(key, opts = {}, &block)
36
+ file = opts[:file]
37
+
38
+ if file
39
+ @protocol.put_object(resource_drive_id, key, opts) do |sw|
40
+ File.open(File.expand_path(file), 'rb') do |f|
41
+ sw << f.read(Protocol::STREAM_CHUNK_SIZE) until f.eof?
42
+ end
43
+ end
44
+ else
45
+ @protocol.put_object(resource_drive_id, key, opts, &block)
46
+ end
47
+ end
48
+
16
49
  end
17
50
  end
data/lib/alipan/http.rb CHANGED
@@ -16,6 +16,10 @@ module Alipan
16
16
  @config = config
17
17
  end
18
18
 
19
+ def handle_response(r, &block)
20
+ r.read_body { |chunk| yield chunk }
21
+ end
22
+
19
23
  def get(resources = {}, http_options = {}, &block)
20
24
  do_request('GET', resources, http_options, &block)
21
25
  end
@@ -45,7 +49,7 @@ module Alipan
45
49
  def do_request(verb, resources = {}, http_options = {}, &block)
46
50
  sub_res = resources[:sub_res]
47
51
 
48
- headers = http_options[:headers] || {}
52
+ headers = {}
49
53
  headers['Content-Type'] ||= DEFAULT_CONTENT_TYPE
50
54
  headers[AUTH_HEADER] = @config.access_token if @config.access_token
51
55
 
@@ -55,21 +59,23 @@ module Alipan
55
59
  block_response = ->(r) { handle_response(r, &block) } if block
56
60
  request = RestClient::Request.new(
57
61
  :method => verb,
58
- :url => "https://open.aliyundrive.com#{sub_res}",
59
- :headers => headers,
62
+ :url => "#{sub_res}".start_with?("/") ? "https://open.aliyundrive.com#{sub_res}" : "#{sub_res}",
63
+ :headers => http_options[:headers] || headers,
60
64
  :payload => http_options[:body],
61
65
  :block_response => block_response,
62
66
  :open_timeout => @config.open_timeout || OPEN_TIMEOUT,
63
67
  :read_timeout => @config.read_timeout || READ_TIMEOUT
64
68
  )
65
- response = request.execute do |resp, &blk|
66
- if resp.code >= 300
67
- e = RuntimeError.new JSON.parse(resp.body)
68
- logger.error(e.to_s)
69
- raise e
70
- else
71
- resp.return!(&blk)
72
- end
69
+ begin
70
+ response = request.execute
71
+ rescue RestClient::ExceptionWithResponse => e
72
+ response = e.response
73
+ response = RestClient::Response.create(response.body, Net::HTTPResponse.new('1.1', 200, 'OK'), request)
74
+ end
75
+
76
+ unless response.is_a?(RestClient::Response)
77
+ response = RestClient::Response.create(nil, response, request)
78
+ response.return!
73
79
  end
74
80
 
75
81
  logger.debug("Received HTTP response, code: #{response.code}, headers: " \
@@ -79,3 +85,13 @@ module Alipan
79
85
  end
80
86
  end
81
87
  end
88
+
89
+ module RestClient
90
+ module Payload
91
+ class Base
92
+ def headers
93
+ ({'Content-Length' => size.to_s} if size) || {}
94
+ end
95
+ end
96
+ end
97
+ end
data/lib/alipan/object.rb CHANGED
@@ -6,12 +6,7 @@ module Alipan
6
6
  attrs :drive_id, :file_id, :parent_file_id,
7
7
  :name, :size, :file_extension, :content_hash,
8
8
  :category, :type, :thumbnail, :url, :created_at,
9
- :updated_at, :play_cursor, :video_media_metadata,
10
- :video_preview_metadata
9
+ :updated_at, :video_media_metadata, :video_preview_metadata
11
10
 
12
- def initialize(opts = {}, protocol = nil)
13
- super(opts)
14
- @protocol = protocol
15
- end
16
11
  end
17
12
  end
@@ -6,6 +6,8 @@ module Alipan
6
6
  class Protocol
7
7
  include Common::Logging
8
8
 
9
+ STREAM_CHUNK_SIZE = 16 * 1024
10
+
9
11
  def initialize(config)
10
12
  @config = config
11
13
  @http = HTTP.new(config)
@@ -27,13 +29,14 @@ module Alipan
27
29
  :backup_drive_id => body.fetch(:backup_drive_id.to_s),
28
30
  :folder_id => body.fetch(:folder_id.to_s)
29
31
  }, self)
32
+
30
33
  logger.info("Done get drive, drive: #{drive}")
31
34
 
32
35
  drive
33
36
  end
34
37
 
35
38
  def list_objects(drive_id, parent_file_id, opts = {})
36
- logger.info("Begin list objects, options: #{opts}")
39
+ logger.debug("Begin list object, drive: #{drive_id}, options: #{opts}")
37
40
 
38
41
  payload = {
39
42
  :drive_id => drive_id,
@@ -46,7 +49,6 @@ module Alipan
46
49
 
47
50
  objects = body[:items.to_s].map do |item|
48
51
  Object.new(
49
- {
50
52
  :drive_id => item.fetch(:drive_id.to_s),
51
53
  :file_id => item.fetch(:file_id.to_s),
52
54
  :parent_file_id => item.fetch(:parent_file_id.to_s),
@@ -60,11 +62,9 @@ module Alipan
60
62
  :url => item.fetch(:url.to_s),
61
63
  :created_at => item.fetch(:created_at.to_s),
62
64
  :updated_at => item.fetch(:updated_at.to_s),
63
- :play_cursor => item.fetch(:play_cursor.to_s),
64
65
  :video_media_metadata => item.fetch(:video_media_metadata.to_s),
65
- :video_preview_metadata => item.fetch(:video_preview_metadata.to_s)
66
- }, self)
67
- end
66
+ :video_preview_metadata => item.fetch(:video_preview_metadata.to_s))
67
+ end || []
68
68
 
69
69
  more = {
70
70
  :marker => body[:next_marker.to_s]
@@ -74,5 +74,155 @@ module Alipan
74
74
 
75
75
  [objects, more]
76
76
  end
77
+
78
+ def get_object(drive_id, object_name, opts = {}, &block)
79
+ logger.debug("Begin get object, drive_id: #{drive_id}, "\
80
+ "object: #{object_name}")
81
+
82
+ payload = {
83
+ :drive_id => drive_id,
84
+ :file_path => "#{object_name}".start_with?("/") ? "#{object_name}" : "/#{object_name}"
85
+ }
86
+
87
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/get_by_path"}, {:body => payload.to_json})
88
+ body = JSON.parse(r.body)
89
+
90
+ if body.fetch(:code.to_s, '') == 'NotFound.File'
91
+ return nil
92
+ end
93
+
94
+ obj = Object.new(
95
+ :drive_id => body.fetch(:drive_id.to_s),
96
+ :file_id => body.fetch(:file_id.to_s),
97
+ :parent_file_id => body.fetch(:parent_file_id.to_s),
98
+ :name => body.fetch(:name.to_s),
99
+ :size => body.fetch(:size.to_s),
100
+ :file_extension => body.fetch(:file_extension.to_s),
101
+ :content_hash => body.fetch(:content_hash.to_s),
102
+ :category => body.fetch(:category.to_s),
103
+ :type => body.fetch(:type.to_s),
104
+ :thumbnail => body.fetch(:thumbnail.to_s),
105
+ :url => body.fetch(:url.to_s),
106
+ :created_at => body.fetch(:created_at.to_s),
107
+ :updated_at => body.fetch(:updated_at.to_s),
108
+ :video_media_metadata => body.fetch(:video_media_metadata.to_s),
109
+ :video_preview_metadata => body.fetch(:video_preview_metadata.to_s))
110
+
111
+ if block_given?
112
+ if obj.type == 'folder' || obj.file_id.nil?
113
+ yield nil
114
+ else
115
+ payload = {
116
+ :drive_id => drive_id,
117
+ :file_id => obj.file_id
118
+ }
119
+
120
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/getDownloadUrl"}, {:body => payload.to_json})
121
+ body = JSON.parse(r.body)
122
+
123
+ @http.get( {:sub_res => body.fetch(:url.to_s)}, {:headers => {}}, &block)
124
+ end
125
+ end
126
+
127
+ logger.debug("Done get object")
128
+
129
+ obj
130
+ end
131
+
132
+ def put_object(drive_id, object_name, opts = {}, &block)
133
+ logger.debug("Begin put object, drive_id: #{drive_id}, object: "\
134
+ "#{object_name}, options: #{opts}")
135
+
136
+ obj = nil
137
+ need_dirs = Array.new
138
+ parent_file_id = 'root'
139
+ obj_dirname = File.dirname(object_name)
140
+ dirname = "#{obj_dirname}".start_with?("/") ? "#{obj_dirname}" : "/#{obj_dirname}"
141
+
142
+ until dirname == '/'
143
+ payload = {
144
+ :drive_id => drive_id,
145
+ :file_path => dirname
146
+ }
147
+
148
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/get_by_path"}, {:body => payload.to_json})
149
+ body = JSON.parse(r.body)
150
+
151
+ if body.fetch(:code.to_s, '') == 'NotFound.File'
152
+ need_dirs.unshift File.basename(dirname)
153
+ else
154
+ if body.fetch(:type.to_s) != 'folder'
155
+ e = RuntimeError.new "File #{dirname} has already existed!"
156
+ logger.error(e.to_s)
157
+ raise e
158
+ else
159
+ parent_file_id = body.fetch(:file_id.to_s)
160
+ break
161
+ end
162
+ end
163
+
164
+ dirname = File.dirname(dirname)
165
+ end
166
+
167
+ need_dirs.each do |need_dir|
168
+ payload = {
169
+ :drive_id => drive_id,
170
+ :parent_file_id => parent_file_id,
171
+ :name => need_dir,
172
+ :type => 'folder',
173
+ :check_name_mode => 'refuse'
174
+ }
175
+
176
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/create"}, {:body => payload.to_json})
177
+ body = JSON.parse(r.body)
178
+
179
+ if body.fetch(:exist.to_s) == true && body.fetch(:type.to_s) != 'folder'
180
+ e = RuntimeError.new "File #{dirname} has already existed!"
181
+ logger.error(e.to_s)
182
+ raise e
183
+ end
184
+
185
+ parent_file_id = body.fetch(:file_id.to_s)
186
+ end
187
+
188
+ payload = {
189
+ :drive_id => drive_id,
190
+ :parent_file_id => parent_file_id,
191
+ :name => File.basename(object_name),
192
+ :type => 'file',
193
+ :check_name_mode => 'refuse'
194
+ }
195
+
196
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/create"}, {:body => payload.to_json})
197
+ body = JSON.parse(r.body)
198
+
199
+ file_id = body.fetch(:file_id.to_s)
200
+ upload_id = body.fetch(:upload_id.to_s)
201
+
202
+ body.fetch('part_info_list', Array.new).each do |part|
203
+ payload = Alipan::Adapter.new(&block)
204
+
205
+ @http.put( {:sub_res => part.fetch(:upload_url.to_s)}, { :headers => { 'Content-Type' => '', 'Transfer-Encoding' => 'chunked' }, :body => payload })
206
+
207
+ payload = {
208
+ :drive_id => drive_id,
209
+ :file_id => file_id,
210
+ :upload_id => upload_id
211
+ }
212
+
213
+ r = @http.post( {:sub_res => "/adrive/v1.0/openFile/complete"}, {:body => payload.to_json})
214
+ body = JSON.parse(r.body)
215
+
216
+ obj = Object.new(
217
+ :drive_id => body.fetch(:drive_id.to_s),
218
+ :file_id => body.fetch(:file_id.to_s),
219
+ :size => body.fetch(:size.to_s),
220
+ :parent_file_id => body.fetch(:parent_file_id.to_s),
221
+ :name => body.fetch(:name.to_s))
222
+ end
223
+
224
+ obj
225
+ end
226
+
77
227
  end
78
228
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alipan
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/alipan.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pry'
4
3
  require_relative "alipan/common"
5
4
  require_relative "alipan/config"
6
5
  require_relative "alipan/client"
@@ -9,3 +8,4 @@ require_relative "alipan/protocol"
9
8
  require_relative "alipan/iterator"
10
9
  require_relative "alipan/drive"
11
10
  require_relative "alipan/object"
11
+ require_relative "alipan/adapter"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alipan-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - freeshenls
@@ -36,6 +36,7 @@ files:
36
36
  - README.md
37
37
  - Rakefile
38
38
  - lib/alipan.rb
39
+ - lib/alipan/adapter.rb
39
40
  - lib/alipan/client.rb
40
41
  - lib/alipan/common.rb
41
42
  - lib/alipan/common/logging.rb