globus_client 0.6.0 → 0.8.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 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