require 'groupme' require 'json' require 'net/http' require 'net/https' require "groupme/cli/message" module Groupme module Cli # Represents a GroupMe session. This wraps the GroupMe API gem and has methods for accessing the data for # a specific session and sending messages. class Session def initialize token @token = token @client = GroupMe::Client.new(token: token) @current_chat_id = nil @new_msgs = Array.new @last_msg_id = 0 end # "Open" a chat with the specified name. This means that the CLI will display live messages from the # chat, and any messages you write will go to that chat as well. # Returns true if it succeeds and false otherwise. def open_chat name group = @client.groups.select {|g| g[:name] == name}[0] if group.nil? return false else @current_chat_id = group[:id] return true end end # Send a message to the current chat. def send_msg(msg, image=nil) with_valid_group do attachments = [] # process image attachments unless image.nil? url = make_img_url image attachments << {type: "image", url: url} end @client.create_message(@current_chat_id, msg, attachments) end end # Fetch messages from the currently open group that haven't been fetched yet. def new_messages # save the new messages messages = @new_msgs.clone # flush @new_msgs since we've seen these already now @new_msgs.clear return messages end # Query the API for "new" messages. In this case, "new" messages are ones that the programmer has not # been given (via a call to Session#new_messages) yet. def update_messages with_valid_group do messages = @client.messages(@current_chat_id, {since_id: @last_msg_id, limit: 20}) # look through the messages and save the new ones messages.each do |msg| sender = abbrev_name msg[:name] time = Time.at msg[:created_at] text = msg[:text] || "" # create a new Message object and push it onto the front of the new_msgs array message_obj = Message.new(sender: sender, time: time, text: text) @new_msgs.unshift message_obj # replace attachments with their types/urls since images and stuff aren't terminal-friendly replacements = msg[:attachments].map do |att| att[:type] == "image"? "[image @ #{att[:url]}]" : att[:type] end # add in the replacements, separated by newlines text << replacements.join("\n") # save the ID of the newest message unless messages.empty? @last_msg_id = messages[0][:id] end end end end def chat_is_open? !@current_chat_id.nil? end private # Make sure that a chat has been selected. If there's a valid chat open, execute the block; otherwise, # show a warning message and skip the block. This method assumes that the block being called depends on # the session having a group open. def with_valid_group if !chat_is_open? puts "You must open a chat before sending a message!" return end yield end # Abbreviate a user's name so it doesn't take up a ton of space def abbrev_name name name.split(' ') .map {|word| word.length > 8? word[0..3]+"." : word} .join(' ') end # Upload an image to GroupMe's image service and return the URL for it def make_img_url path # Obtain image file type (needed for the request) type = File.extname(path)[1..-1] # creat HTTP request uri = URI.parse "https://image.groupme.com/pictures" https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true headers = Hash.new # make headers headers['X-Access-Token'] = @token headers['Content-Type'] = "image/#{type}" # get the response and extract the image URL from it, or handle an error resp = https.post2(uri.path, File.read(path), headers) if resp.class == Net::HTTPOK data = JSON.parse resp.body return data["payload"]["picture_url"] else puts "An HTTP error occurred while trying to upload your image. We're profoundly sorry." end end end end end