Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spike on a full redesign of the client #326

Merged
merged 4 commits into from Apr 22, 2024
Merged

Spike on a full redesign of the client #326

merged 4 commits into from Apr 22, 2024

Conversation

mjgiarlo
Copy link
Member

@mjgiarlo mjgiarlo commented Jan 12, 2024

Why was this change made?

Connects to #261

This commit adds a new public interface for sdr-client to see if we can make a less complex interaction with the client workable. See #261 for more rationale and analysis.

The work in this PR is only the bits of sdr-client that google-books and the sdr-client CLI depends on as a start, with some changes likely needed for Argo, H2, and the infra-integration-tests.

Note: the intent of this PR is not to rewrite and refactor the entire world, but to do sufficient internal refactoring to create a new seam (the public interface) to enable future internal refactoring. Until we move to a narrower interface, sdr-client refactors are extremely difficult to do.

Goals of the re-design include:

  • Provide an interface for handling operations that rely on asynchronous interactions (ones that rely on SDR API background jobs)
  • Build in smart token refreshing
  • Keep the client interface as tidy as can be defended instead of expecting consumers to knit together implementation details
  • Do this in a way that does not break any current interfaces, and allows us to move over to the new interfaces gradually at our own pace

Why do this at all? We've learned lessons about client gem design over the past couple years and sdr-client could use some refreshing based on these lessons.

Ultimately the goal is to promote the new client, as implemented in the SdrClient::RedesignedClient module, to the main module namespace and delete the old code entirely. We can do that once we've moved over google-books, argo, H2, the integration-tests, and the SDR CLI to the new interface and tested it all in QA and stage.

How was this change tested?

  • CI
  • integration tests

lib/sdr-client.rb Outdated Show resolved Hide resolved
Comment on lines 8 to 23
require 'zeitwerk'

require 'sdr_client/version'
require 'sdr_client/unexpected_response'
require 'sdr_client/deposit'
require 'sdr_client/update'
require 'sdr_client/credentials'
require 'sdr_client/find'
require 'sdr_client/login'
require 'sdr_client/login_prompt'
require 'sdr_client/connection'
require 'sdr_client/background_job_results'
loader = Zeitwerk::Loader.for_gem
loader.inflector.inflect(
'md5' => 'MD5',
'sha1' => 'SHA1'
)
loader.setup
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we don't have to add manual require statements whenever we add a new class or rename a class to the client.

Comment on lines 150 to 190
def with_token_refresh_when_unauthorized
response = yield

# if unauthorized, token has likely expired. try to get a new token and then retry the same request(s).
if response.status == 401
config.token = Authenticator.token
response = yield
end

response
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automagic token refreshing.

Comment on lines +39 to +52
def logger
SdrClient::RedesignedClient.config.logger
end

def client
SdrClient::RedesignedClient.instance
end
Copy link
Member Author

@mjgiarlo mjgiarlo Jan 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the client instance and the logger from singleton config so we don't have to pass params around everywhere.


module SdrClient
class RedesignedClient
# Wraps operations waiting for results from jobs
Copy link
Member Author

@mjgiarlo mjgiarlo Jan 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deal with background/async interactions on behalf of consumers.

spec/spec_helper.rb Outdated Show resolved Hide resolved
@mjgiarlo mjgiarlo force-pushed the redesign-spike branch 20 times, most recently from 5268f30 to c63b37d Compare March 13, 2024 20:45
Comment on lines +1 to +10
#!/usr/bin/env ruby
# frozen_string_literal: true

$LOAD_PATH.unshift 'lib'

require 'sdr_client'
require 'sdr_client/redesigned_client'
require 'sdr_client/redesigned_client/cli'

SdrClient::RedesignedClient::CLI.start(ARGV)
Copy link
Member Author

@mjgiarlo mjgiarlo Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little CLI wrapper that uses only classes in the redesigned module space. This lets us test the changes and make sure they function as expected in the CLI.

Comment on lines +3 to +7
module SdrClient
class RedesignedClient
class CLI < Thor
# The stored credentials
class Credentials
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The credentials file is now only needed by the CLI since usage in applications will handle authorization via automagic token refreshes.

Comment on lines +29 to +53
def deposit_model # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
check_files_exist!
child_files_match! unless options[:request_builder]

file_metadata = UploadFilesMetadataBuilder.build(files: files, mime_types: mime_types, basepath: basepath)
upload_responses = UploadFiles.upload(file_metadata: file_metadata,
filepath_map: filepath_map)
if options[:request_builder]
@model = StructuralGrouper.group(
request_builder: options[:request_builder],
upload_responses: upload_responses,
grouping_strategy: options[:grouping_strategy],
file_set_strategy: options[:file_set_strategy]
)
child_files_match!
end

new_request_dro = UpdateDroWithFileIdentifiers.update(request_dro: model,
upload_responses: upload_responses)
CreateResource.run(accession: accession,
priority: options[:priority],
assign_doi: options[:assign_doi],
metadata: new_request_dro)
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is a bit messy because it's taking the place of two separate classes in the old design. Further internal refactoring would be good after we switch to the new public interface.

def initialize(apo:, source_id:, **options)
@apo = apo
@source_id = source_id
@options = options
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move all non-required options to an options param instead of having a giant list of keyword params.

module SdrClient
class RedesignedClient
# Handles unexpected responses
class UnexpectedResponse
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle unexpected responses all in one spot.

@mjgiarlo mjgiarlo marked this pull request as ready for review April 2, 2024 15:47
Copy link
Contributor

@justinlittman justinlittman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ka-ching

@mjgiarlo mjgiarlo merged commit e0f8019 into main Apr 22, 2024
5 checks passed
@mjgiarlo mjgiarlo deleted the redesign-spike branch April 22, 2024 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants