class GoogleDrive::PersistentSession

Constants

THREAD_KEY
VERSION

Public Class Methods

login() click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 13
def self.login
  self.new
end
new() click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 17
def initialize
  @highline = HighLine.new
  ensure_login
end

Private Instance Methods

ensure_login() click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 24
def ensure_login
  store_credential unless credential_stored?
  credential = storage.authorize

  if credential.expired?
    refresh(credential)
  end

  unless session
    login_with_oauth(credential.access_token)
  end
end
fetch_access_token(credential, queue, server, server_thread) click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 115
def fetch_access_token(credential, queue, server, server_thread)
  puts "Open this page in web browser: #{credential.authorization_uri}"
  code = queue.pop
  server.shutdown
  server_thread.join
  unless code
    raise 'authorization failed'
  end
  credential.code = code

  credential.fetch_access_token!
  storage.write_credentials(credential)
  login_with_oauth(credential.access_token)
end
login_with_oauth(access_token) click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 140
def login_with_oauth(access_token)
  Thread.current[THREAD_KEY] = GoogleDrive.login_with_oauth(access_token)
end
method_missing(method_name, *args , &block) click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 144
def method_missing(method_name, *args , &block)
  ensure_login
  session.send(method_name, *args, &block)
end
refresh(credential) click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 130
def refresh(credential)
  credential.refresh!
  storage.write_credentials(credential)
  login_with_oauth(credential.access_token)
end
session() click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 136
def session
  Thread.current[THREAD_KEY]
end
store_credential() click to toggle source
# File lib/google_drive/persistent_session/persistent_session.rb, line 37
def store_credential
  client_id = ask('Enter CLIENT ID: ')
  client_secret = ask('Enter CLIENT SECRET: ') {|q| q.echo = false }
  puts # line break

  # Use loopback IP address redirect option
  # https://developers.google.com/identity/protocols/oauth2/native-app#redirect-uri_loopback
  server = WEBrick::HTTPServer.new(Port: 0, AccessLog: [])
  queue = Thread::SizedQueue.new(1)
  health_token = SecureRandom.uuid
  server.mount_proc('/') do |req, resp|
    resp.content_type = 'text/plain'
    if req.request_method != 'GET'
      resp.status = 405
      res.body = 'Method Not Allowed'
      next
    end

    case req.path
    when '/'
      # redirect
      params = URI.decode_www_form(req.query_string).to_h
      if params.key?('code')
        code = params.fetch('code')
        resp.status = 200
        resp.body = 'Successfully authorized. Back to console'
        queue.push(code)
      else
        resp.status = 400
        resp.body = 'Failed to authorize: code is missing'
        queue.push(nil)
      end
    when '/health'
      resp.status = 200
      resp.body = health_token
    else
      resp.status = 404
      resp.body = 'not found'
    end
  end
  server_thread = Thread.start { server.start }
  credential =  Google::Auth::UserRefreshCredentials.new(
    :client_id => client_id,
    :client_secret => client_secret,
    :scope => [
      'https://www.googleapis.com/auth/drive',
      'https://spreadsheets.google.com/feeds/'
    ],
    :redirect_uri => "http://127.0.0.1:#{server.config[:Port]}",
    :grant_type => 'authorization_code'
  )

  server_launched = false
  60.times do |i|
    begin
      resp = Net::HTTP.get_response('127.0.0.1', '/health', server.config[:Port])
      resp.value
      if resp.body == health_token
        server_launched = true
        break
      else
        $stderr.puts "  Server returned unknown response: #{resp.body}"
        sleep 1
      end
    rescue => e
      $stderr.puts "  Waiting server launch: #{e.class}: #{e.message}"
      sleep 1
    end
  end
  unless server_launched
    server.shutdown
    server_thread.join
    raise 'Failed to start HTTP server'
  end
  fetch_access_token(credential, queue, server, server_thread)
  storage.write_credentials(credential)
end