class Glima::GmailClient
Attributes
Public Class Methods
# File lib/glima/gmail_client.rb, line 88 def initialize(client_id, client_secret, token_store_path, user, datastore, context, logger = nil) @client_id = client_id @client_secret = client_secret @token_store_path = token_store_path @user = user @datastore = datastore @context = context @client = Google::Apis::GmailV1::GmailService.new @client.client_options.application_name = 'glima' if logger @logger = logger else # quiet @logger = ::Logger.new($stderr) @logger.formatter = proc {|severity, datetime, progname, msg| ""} end end
Public Instance Methods
# File lib/glima/gmail_client.rb, line 117 def auth unless credentials = authorizer.credentials(@user) raise AuthorizationError.new end @client.authorization = credentials @client.authorization.username = @user # for IMAP end
# File lib/glima/gmail_client.rb, line 106 def auth_interactively credentials = begin authorizer.auth_interactively(@user) rescue raise AuthorizationError.new end @client.authorization = credentials @client.authorization @client.authorization.username = @user # for IMAP end
# File lib/glima/gmail_client.rb, line 173 def batch(options = nil) @client.batch(options) do |batch_client| begin Thread.current[:glima_api_batch] = batch_client yield self ensure Thread.current[:glima_api_batch] = nil end end end
# File lib/glima/gmail_client.rb, line 144 def each_events(since:) options, response = {start_history_id: since}, nil loop do client.list_user_histories(me, options) do |res, err| raise err if err response = res end break unless response.history response.history.each do |h| Glima::Resource::History.new(h).to_events.each do |ev| yield ev end end break unless options[:page_token] = response.next_page_token end end
# File lib/glima/gmail_client.rb, line 200 def find_messages(query) qp = Glima::QueryParameter.new("+all", query) list_user_messages(me, qp.to_hash) do |res, error| STDERR.print "#{error}" if error return (res.messages || []).map(&:id) end rescue Glima::QueryParameter::FormatError => e STDERR.print "Error: " + e.message + "\n" end
# File lib/glima/gmail_client.rb, line 165 def get_user_label(id, fields: nil, options: nil, &block) client.get_user_label(me, id, fields: fields, options: options, &block) end
-
message types by format: | field/fromat: | list | minimal | raw | value type | |—————–
------
———-----
—————–| | id | ○ | ○ | ○ | string | | threadId | ○ | ○ | ○ | string | | labelIds | | ○ | ○ | string[] | | snippet | | ○ | ○ | string | | historyId | | ○ | ○ | unsinged long | | internalDate | | ○ | ○ | long | | sizeEstimate | | ○ | ○ | int | |—————–------
———-----
—————–| | payload | | | | object | | payload.headers | | | | key/value pairs | | raw | | | ○ | bytes |
# File lib/glima/gmail_client.rb, line 71 def get_user_smart_message(id) fmt = if @datastore.exist?(id) then "minimal" else "raw" end mail = nil @client.get_user_message(me, id, format: fmt) do |m, err| mail = Glima::Resource::Mail.new(@datastore.update(m)) if m yield(mail, err) end return mail end
# File lib/glima/gmail_client.rb, line 218 def label_by_id(label_id) labels.find {|label| label.id == label_id} end
# File lib/glima/gmail_client.rb, line 214 def label_by_name(label_name) labels.find {|label| label.name == label_name} end
# File lib/glima/gmail_client.rb, line 210 def labels @labels ||= client.list_user_labels(me).labels end
Find nearby messages from pivot_message `Nearby' message:
+ has same From: address + has near Date: field (+-1day)
with the pivot_message.
# File lib/glima/gmail_client.rb, line 45 def nearby_mails(pivot_mail) from = "from:#{pivot_mail.from}" date1 = (pivot_mail.date.to_date - 1).strftime("after:%Y/%m/%d") date2 = (pivot_mail.date.to_date + 2).strftime("before:%Y/%m/%d") query = "#{from} -in:trash #{date1} #{date2}" scan_batch("+all", query, false) do |mail| next if pivot_mail.id == mail.id yield mail end end
# File lib/glima/gmail_client.rb, line 82 def online? Socket.getifaddrs.select {|i| i.addr.ipv4? and ! i.addr.ipv4_loopback? }.map(&:addr).map(&:ip_address).length > 0 end
# File lib/glima/gmail_client.rb, line 184 def scan_batch(folder, search_or_range = nil, update_context = true, &block) qp = Glima::QueryParameter.new(folder, search_or_range, context) list_user_messages(me, qp.to_hash) do |res, error| fail "#{error}" if error ids = (res.messages || []).map(&:id) unless ids.empty? batch_on_messages(ids) do |message| yield Glima::Resource::Mail.new(message) if block end context.save_page_token(res.next_page_token) if update_context end end rescue Glima::QueryParameter::FormatError => e STDERR.print "Error: " + e.message + "\n" end
# File lib/glima/gmail_client.rb, line 169 def trash_user_message(id, fields: nil, options: nil, &block) client.trash_user_message(me, id, fields: fields, options: options, &block) end
# File lib/glima/gmail_client.rb, line 125 def watch(label = nil, &block) loop do @logger.info "[#{self.class}#watch] loop tick" curr_hid = get_user_profile(me).history_id.to_i last_hid ||= curr_hid # If server is changed at this point, we will miss the events. # so, we have to set the timeout and update history record. wait(label, 60) if last_hid == curr_hid each_events(since: last_hid) do |ev| yield ev last_hid = ev.history_id.to_i end end end
Private Instance Methods
# File lib/glima/gmail_client.rb, line 241 def batch_on_messages(ids, &block) @client.batch do |batch_client| ids.each do |id| fmt = if @datastore.exist?(id) then "minimal" else "raw" end batch_client.get_user_message(me, id, format: fmt) do |m, err| fail "#{err}" if err message = @datastore.update(m) yield message end end end end
# File lib/glima/gmail_client.rb, line 237 def client Thread.current[:glima_api_batch] || @client end
# File lib/glima/gmail_client.rb, line 233 def me 'me' end
label == nil means “[Gmail]/All Mail”
# File lib/glima/gmail_client.rb, line 256 def wait(label = nil, timeout_sec = 60) @logger.info "[#{self.class}#wait] Enter" if @imap.nil? || @imap.disconnected? @imap = Glima::ImapWatch.new("imap.gmail.com", @client.authorization, @logger) @logger.debug "[#{self.class}#wait] create new IMAPWatch #{@imap}" else @logger.debug "[#{self.class}#wait] use existing IMAPWatch #{@imap}" end begin @imap.wait(label&.name, timeout_sec) rescue => err @imap = nil @logger.info "[#{self.class}#wait] imap connection error. abandon current imap connection." @logger.info err @logger.info err.backtrace end @logger.info "[#{self.class}#wait] Exit" end