globus_client 0.6.0 → 0.8.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
  SHA256:
3
- metadata.gz: 48a7e0a937ea5e51b5803b69237c2d03afdc95a14a26008b6df31b708b086600
4
- data.tar.gz: 431c01307b660f6cab3240963e508f57d1d1a8412e75b3468b7c16a48fc220c6
3
+ metadata.gz: 40f9903f67d10be16104fe3664bf68dd467b24414cb7f0c84bfb6539cd2acee5
4
+ data.tar.gz: bbcc3c1f811df83d8a4d473ff3cd646b33d6f7f950aaa99c0f86e0e10165130d
5
5
  SHA512:
6
- metadata.gz: ccb73a4b9709b88f4bcf2bfcd59775beeee645c3b79b7c9a1083cb922ea4cb014ed07141579bf92532be103eb79bf23b7a65b727f0343b8f4ecec9f294fdfd05
7
- data.tar.gz: 4aa6ff81e7ac5109526ca7608c089e2b5a1f8f7ce4e4f9a8c4eabaf14805dc22d4c0380624aef82179dee222ef1e7997fd7a485355e152a13fd81f1f64e20425
6
+ metadata.gz: f5334d262c97ac5512d5a6bbaf9a0927e98fea577a318ba0b08c3dbac33bfbb53c01bdb95205df271886c36df2ce7144c078e7ae8deadc5bea8af9a8d9180479
7
+ data.tar.gz: a850d0854a936f24653d0ebf0bfd96be478ab2a0c6be908c1cd47defb3872b306281a35d56b76cff898cc48ba9340d20dde4d4a96051d36007d6c29d3f5a4a53
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- globus_client (0.6.0)
4
+ globus_client (0.8.0)
5
5
  activesupport (>= 4.2, < 8)
6
6
  faraday
7
7
  zeitwerk
@@ -23,7 +23,7 @@ GEM
23
23
  rexml
24
24
  diff-lcs (1.5.0)
25
25
  docile (1.4.0)
26
- faraday (2.7.1)
26
+ faraday (2.7.2)
27
27
  faraday-net_http (>= 2.0, < 3.1)
28
28
  ruby2_keywords (>= 0.0.4)
29
29
  faraday-net_http (3.0.2)
@@ -32,9 +32,9 @@ GEM
32
32
  concurrent-ruby (~> 1.0)
33
33
  json (2.6.3)
34
34
  language_server-protocol (3.17.0.2)
35
- minitest (5.16.3)
35
+ minitest (5.17.0)
36
36
  parallel (1.22.1)
37
- parser (3.1.3.0)
37
+ parser (3.2.0.0)
38
38
  ast (~> 2.4.1)
39
39
  public_suffix (5.0.1)
40
40
  rainbow (3.1.1)
@@ -47,45 +47,45 @@ GEM
47
47
  rspec-mocks (~> 3.12.0)
48
48
  rspec-core (3.12.0)
49
49
  rspec-support (~> 3.12.0)
50
- rspec-expectations (3.12.0)
50
+ rspec-expectations (3.12.2)
51
51
  diff-lcs (>= 1.2.0, < 2.0)
52
52
  rspec-support (~> 3.12.0)
53
- rspec-mocks (3.12.1)
53
+ rspec-mocks (3.12.2)
54
54
  diff-lcs (>= 1.2.0, < 2.0)
55
55
  rspec-support (~> 3.12.0)
56
56
  rspec-support (3.12.0)
57
- rubocop (1.39.0)
57
+ rubocop (1.42.0)
58
58
  json (~> 2.3)
59
59
  parallel (~> 1.10)
60
60
  parser (>= 3.1.2.1)
61
61
  rainbow (>= 2.2.2, < 4.0)
62
62
  regexp_parser (>= 1.8, < 3.0)
63
63
  rexml (>= 3.2.5, < 4.0)
64
- rubocop-ast (>= 1.23.0, < 2.0)
64
+ rubocop-ast (>= 1.24.1, < 2.0)
65
65
  ruby-progressbar (~> 1.7)
66
66
  unicode-display_width (>= 1.4.0, < 3.0)
67
- rubocop-ast (1.24.0)
67
+ rubocop-ast (1.24.1)
68
68
  parser (>= 3.1.1.0)
69
- rubocop-performance (1.15.1)
69
+ rubocop-performance (1.15.2)
70
70
  rubocop (>= 1.7.0, < 2.0)
71
71
  rubocop-ast (>= 0.4.0)
72
- rubocop-rspec (2.15.0)
72
+ rubocop-rspec (2.16.0)
73
73
  rubocop (~> 1.33)
74
74
  ruby-progressbar (1.11.0)
75
75
  ruby2_keywords (0.0.5)
76
- simplecov (0.21.2)
76
+ simplecov (0.22.0)
77
77
  docile (~> 1.1)
78
78
  simplecov-html (~> 0.11)
79
79
  simplecov_json_formatter (~> 0.1)
80
80
  simplecov-html (0.12.3)
81
81
  simplecov_json_formatter (0.1.4)
82
- standard (1.19.1)
82
+ standard (1.21.1)
83
83
  language_server-protocol (~> 3.17.0.2)
84
- rubocop (= 1.39.0)
85
- rubocop-performance (= 1.15.1)
84
+ rubocop (= 1.42.0)
85
+ rubocop-performance (= 1.15.2)
86
86
  tzinfo (2.0.5)
87
87
  concurrent-ruby (~> 1.0)
88
- unicode-display_width (2.3.0)
88
+ unicode-display_width (2.4.2)
89
89
  webmock (3.18.1)
90
90
  addressable (>= 2.8.0)
91
91
  crack (>= 0.3.2)
data/README.md CHANGED
@@ -57,7 +57,13 @@ def create_user_directory
57
57
  end
58
58
 
59
59
  def lookup_dir_contents
60
- GlobusClient.get_filenames(user_id: 'mjgiarlo@stanford.edu', path: 'mjgiarlo/work1234/version1')
60
+ GlobusClient.list_files(user_id: "mjgiarlo@stanford.edu", path: "mjgiarlo/work1234/version1") do |files|
61
+ files_count = files.count
62
+ total_size = files.sum(&:size)
63
+ files_list = files.map(&:name)
64
+
65
+ return [files_count, total_size, files_list]
66
+ end
61
67
  end
62
68
  # ...
63
69
  ```
@@ -78,8 +84,8 @@ $ export GLOBUS_CLIENT_ID=$(vault kv get -field=content puppet/application/sdr/g
78
84
  $ export GLOBUS_CLIENT_SECRET=$(vault kv get -field=content puppet/application/sdr/globus/{prod|qa|stage}/client_secret)
79
85
  $ export GLOBUS_ENDPOINT=$(vault kv get -field=content puppet/application/sdr/globus/{prod|qa|stage}/endpoint_uuid)
80
86
  $ export GLOBUS_UPLOADS_DIRECTORY=from_shared_configs
81
- # NOTE: The three args below are a user ID, a work ID, and a work version
82
- $ ./api_test.rb mjgiarlo 987 1
87
+ # NOTE: The two args below are a user ID (email) and a path such as a consumer might construct
88
+ $ ./api_test.rb mjgiarlo@stanford.edu mjgiarlo/work987/version1
83
89
 
84
90
  Initial directory permissions: rw
85
91
  Number of files in directory: 2
data/api_test.rb CHANGED
@@ -1,40 +1,56 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "benchmark"
4
5
  require "bundler/setup"
5
6
  require "globus_client"
6
7
 
7
- GlobusClient.configure(
8
- client_id: ENV["GLOBUS_CLIENT_ID"],
9
- client_secret: ENV["GLOBUS_CLIENT_SECRET"],
10
- uploads_directory: ENV["GLOBUS_UPLOADS_DIRECTORY"],
11
- transfer_endpoint_id: ENV["GLOBUS_ENDPOINT"]
12
- )
13
-
14
- user_id, path = *ARGV
15
-
16
- # Test public API methods here.
17
- GlobusClient.mkdir(user_id:, path:)
18
-
19
- user_exists = GlobusClient.user_exists?(user_id)
20
-
21
- # Not part of the public API but this allows us to test access changes
22
- before_permissions = GlobusClient::Endpoint.new(GlobusClient.config, user_id:, path:).send(:access_rule)["permissions"]
23
-
24
- files_count = GlobusClient.file_count(user_id:, path:)
25
-
26
- total_size = GlobusClient.total_size(user_id:, path:)
27
-
28
- GlobusClient.disallow_writes(user_id:, path:)
29
-
30
- files_list = GlobusClient.get_filenames(user_id:, path:)
31
-
32
- # Not part of the public API but this allows us to test access changes
33
- after_permissions = GlobusClient::Endpoint.new(GlobusClient.config, user_id:, path:).send(:access_rule)["permissions"]
34
-
35
- puts "User #{user_id} exists: #{user_exists}"
36
- puts "Initial directory permissions: #{before_permissions}"
37
- puts "Number of files in directory: #{files_count}"
38
- puts "Total size of files in directory: #{total_size}"
39
- puts "List of files in directory: #{files_list}"
40
- puts "Final directory permissions: #{after_permissions}"
8
+ Benchmark.bm(20) do |benchmark|
9
+ user_id, path = *ARGV
10
+
11
+ benchmark.report("Configure:") do
12
+ GlobusClient.configure(
13
+ client_id: ENV["GLOBUS_CLIENT_ID"],
14
+ client_secret: ENV["GLOBUS_CLIENT_SECRET"],
15
+ uploads_directory: ENV["GLOBUS_UPLOADS_DIRECTORY"],
16
+ transfer_endpoint_id: ENV["GLOBUS_ENDPOINT"]
17
+ )
18
+ end
19
+
20
+ benchmark.report("mkdir:") do
21
+ GlobusClient.mkdir(user_id:, path:)
22
+ end
23
+
24
+ benchmark.report("user_exists?:") do
25
+ @user_exists = GlobusClient.user_exists?(user_id)
26
+ end
27
+
28
+ benchmark.report("before_perms:") do
29
+ # Not part of the public API but this allows us to test access changes
30
+ @before_permissions = GlobusClient::Endpoint.new(GlobusClient.config, user_id:, path:).send(:access_rule)["permissions"]
31
+ end
32
+
33
+ benchmark.report("list_files:") do
34
+ GlobusClient.list_files(user_id:, path:) do |files|
35
+ @files_count = files.count
36
+ @total_size = files.sum(&:size)
37
+ @files_list = files.map(&:name)
38
+ end
39
+ end
40
+
41
+ benchmark.report("disallow_writes:") do
42
+ GlobusClient.disallow_writes(user_id:, path:)
43
+ end
44
+
45
+ benchmark.report("after_perms:") do
46
+ # Not part of the public API but this allows us to test access changes
47
+ @after_permissions = GlobusClient::Endpoint.new(GlobusClient.config, user_id:, path:).send(:access_rule)["permissions"]
48
+ end
49
+
50
+ puts "User #{user_id} exists: #{@user_exists}"
51
+ puts "Initial directory permissions: #{@before_permissions}"
52
+ puts "Number of files in directory: #{@files_count}"
53
+ puts "Total size of files in directory: #{@total_size}"
54
+ puts "List of files in directory: #{@files_list}"
55
+ puts "Final directory permissions: #{@after_permissions}"
56
+ end
@@ -5,6 +5,8 @@ class GlobusClient
5
5
  class Endpoint
6
6
  PATH_SEPARATOR = "/"
7
7
 
8
+ FileInfo = Struct.new(:name, :size)
9
+
8
10
  # @param config [#token, #uploads_directory, #transfer_endpoint_id, #transfer_url, #auth_url] configuration for the gem
9
11
  # @param path [String] the path to operate on
10
12
  # @param user_id [String] a Globus user ID (e.g., a @stanford.edu email address)
@@ -14,12 +16,10 @@ class GlobusClient
14
16
  @path = path
15
17
  end
16
18
 
17
- def file_count
18
- objects["total"]
19
- end
20
-
21
- def total_size
22
- files.sum { |file| file["size"] }
19
+ def list_files
20
+ ls_path(full_path, []).tap do |files|
21
+ yield files if block_given?
22
+ end
23
23
  end
24
24
 
25
25
  # Create a directory https://docs.globus.org/api/transfer/file_operations/#make_directory
@@ -56,17 +56,13 @@ class GlobusClient
56
56
  access_request(permissions: "r")
57
57
  end
58
58
 
59
- def get_filenames
60
- ls_path(full_path, [])
61
- end
62
-
63
59
  private
64
60
 
65
61
  attr_reader :config, :path, :user_id
66
62
 
67
63
  def connection
68
64
  # Transfer API connection
69
- Faraday.new(
65
+ @connection ||= Faraday.new(
70
66
  url: config.transfer_url,
71
67
  headers: {Authorization: "Bearer #{config.token}"}
72
68
  )
@@ -81,7 +77,7 @@ class GlobusClient
81
77
  # And this method returns:
82
78
  # ["/uploads/mjgiarlo/", "/uploads/mjgiarlo/work123/", "/uploads/mjgiarlo/work123/version1/"]
83
79
  def paths
84
- path_segments.map.with_index do |_segment, index|
80
+ @paths ||= path_segments.map.with_index do |_segment, index|
85
81
  File
86
82
  .join(config.uploads_directory, path_segments.slice(..index))
87
83
  .concat(PATH_SEPARATOR)
@@ -97,33 +93,23 @@ class GlobusClient
97
93
  path.split(PATH_SEPARATOR)
98
94
  end
99
95
 
100
- def objects
101
- # List files at an endpoint https://docs.globus.org/api/transfer/file_operations/#list_directory_contents
102
- response = connection.get("#{transfer_path}/ls?path=#{full_path}")
103
- return JSON.parse(response.body) if response.success?
104
-
105
- UnexpectedResponse.call(response)
106
- end
107
-
108
- def files
109
- objects["DATA"].select { |object| object["DATA_TYPE"] == "file" }
110
- end
111
-
112
96
  # @param filepath [String] an absolute path to look up contents e.g. /uploads/example/work123/version1
113
- # @param filenames [Array<String>] a list of filenames, with absolute filepaths
114
- def ls_path(filepath, filenames)
97
+ # @param files [Array<FileInfo>] an array of FileInfo structs, each of which has a name and a size
98
+ def ls_path(filepath, files)
115
99
  # List files recursively at an endpoint https://docs.globus.org/api/transfer/file_operations/#list_directory_contents
116
100
  response = connection.get("#{transfer_path}/ls?path=#{filepath}")
117
101
  if response.success?
118
102
  data = JSON.parse(response.body)["DATA"]
119
- data.select { |object| object["type"] == "file" }.map { |file| file["name"] }
120
- .each { |file| filenames << "#{filepath}#{file}" }
121
- data.select { |object| object["type"] == "dir" }.map { |dir| dir["name"] }
122
- .each { |dir| ls_path("#{filepath}#{dir}/", filenames) }
103
+ data
104
+ .select { |object| object["type"] == "file" }
105
+ .each { |file| files << FileInfo.new("#{filepath}#{file["name"]}", file["size"]) }
106
+ data
107
+ .select { |object| object["type"] == "dir" }
108
+ .each { |dir| ls_path("#{filepath}#{dir["name"]}/", files) }
123
109
  else
124
110
  UnexpectedResponse.call(response)
125
111
  end
126
- filenames
112
+ files
127
113
  end
128
114
 
129
115
  def access_request(permissions:)
@@ -20,7 +20,8 @@ class GlobusClient
20
20
  def exists?(user_id)
21
21
  get_identity_id(user_id)
22
22
  true
23
- rescue
23
+ # if no active user is returned
24
+ rescue RuntimeError
24
25
  false
25
26
  end
26
27
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GlobusClient
4
+ # Wraps API operations to request new access token if expired
5
+ class TokenWrapper
6
+ def self.refresh(config, &block)
7
+ yield
8
+ rescue UnexpectedResponse::UnauthorizedError
9
+ config.token = Authenticator.token(config.client_id, config.client_secret, config.auth_url)
10
+ yield
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GlobusClient
4
- VERSION = "0.6.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/globus_client.rb CHANGED
@@ -23,6 +23,8 @@ class GlobusClient
23
23
  def configure(client_id:, client_secret:, uploads_directory:, transfer_endpoint_id:, transfer_url: default_transfer_url, auth_url: default_auth_url)
24
24
  instance.config = OpenStruct.new(
25
25
  token: Authenticator.token(client_id, client_secret, auth_url),
26
+ client_id:,
27
+ client_secret:,
26
28
  uploads_directory:,
27
29
  transfer_endpoint_id:,
28
30
  transfer_url:,
@@ -32,7 +34,7 @@ class GlobusClient
32
34
  self
33
35
  end
34
36
 
35
- delegate :config, :disallow_writes, :file_count, :mkdir, :total_size, :user_exists?, :get_filenames, to: :instance
37
+ delegate :config, :disallow_writes, :file_count, :list_files, :mkdir, :total_size, :user_exists?, :get_filenames, to: :instance
36
38
 
37
39
  def default_transfer_url
38
40
  "https://transfer.api.globusonline.org"
@@ -46,33 +48,55 @@ class GlobusClient
46
48
  attr_accessor :config
47
49
 
48
50
  def mkdir(...)
49
- endpoint = Endpoint.new(config, ...)
50
- endpoint.mkdir
51
- endpoint.allow_writes
51
+ TokenWrapper.refresh(config) do
52
+ endpoint = Endpoint.new(config, ...)
53
+ endpoint.mkdir
54
+ endpoint.allow_writes
55
+ end
52
56
  end
53
57
 
54
58
  def disallow_writes(...)
55
- endpoint = Endpoint.new(config, ...)
56
- endpoint.disallow_writes
59
+ TokenWrapper.refresh(config) do
60
+ endpoint = Endpoint.new(config, ...)
61
+ endpoint.disallow_writes
62
+ end
63
+ end
64
+
65
+ # NOTE: Can't use the `...` (argument forwarding) operator here because we
66
+ # want to route the keyword args to `Endpoint#new` and the block arg to
67
+ # `Endpoint#list_files`
68
+ def list_files(**keywords, &block)
69
+ TokenWrapper.refresh(config) do
70
+ endpoint = Endpoint.new(config, **keywords)
71
+ endpoint.list_files(&block)
72
+ end
57
73
  end
58
74
 
59
75
  def file_count(...)
60
- endpoint = Endpoint.new(config, ...)
61
- endpoint.file_count
76
+ TokenWrapper.refresh(config) do
77
+ endpoint = Endpoint.new(config, ...)
78
+ endpoint.list_files { |files| return files.count }
79
+ end
62
80
  end
63
81
 
64
82
  def total_size(...)
65
- endpoint = Endpoint.new(config, ...)
66
- endpoint.total_size
83
+ TokenWrapper.refresh(config) do
84
+ endpoint = Endpoint.new(config, ...)
85
+ endpoint.list_files { |files| return files.sum(&:size) }
86
+ end
67
87
  end
68
88
 
69
89
  def get_filenames(...)
70
- endpoint = Endpoint.new(config, ...)
71
- endpoint.get_filenames
90
+ TokenWrapper.refresh(config) do
91
+ endpoint = Endpoint.new(config, ...)
92
+ endpoint.list_files { |files| return files.map(&:name) }
93
+ end
72
94
  end
73
95
 
74
96
  def user_exists?(...)
75
- identity = Identity.new(config)
76
- identity.exists?(...)
97
+ TokenWrapper.refresh(config) do
98
+ identity = Identity.new(config)
99
+ identity.exists?(...)
100
+ end
77
101
  end
78
102
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: globus_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Collier
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-12-14 00:00:00.000000000 Z
13
+ date: 2023-01-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -170,6 +170,7 @@ files:
170
170
  - lib/globus_client/authenticator.rb
171
171
  - lib/globus_client/endpoint.rb
172
172
  - lib/globus_client/identity.rb
173
+ - lib/globus_client/token_wrapper.rb
173
174
  - lib/globus_client/unexpected_response.rb
174
175
  - lib/globus_client/version.rb
175
176
  homepage: https://github.com/sul-dlss/globus_client