#!/usr/bin/env ruby require 'commander/import' require 'houston' HighLine.track_eof = false # Fix for built-in Ruby Signal.trap("INT") {} # Suppress backtrace when exiting command program :version, Houston::VERSION program :description, 'A command-line interface for sending push notifications' program :help, 'Author', 'Mattt Thompson ' program :help, 'Website', 'https://github.com/mattt' program :help_formatter, :compact default_command :help command :push do |c| c.syntax = 'apn push TOKEN [...]' c.summary = 'Sends an Apple Push Notification to specified devices' c.description = '' c.example 'description', 'apn push -m "Hello, World" -b 57 -s sosumi.aiff' c.option '-m', '--alert ALERT', 'Body of the alert to send in the push notification' c.option '-b', '--badge NUMBER', 'Badge number to set with the push notification' c.option '-s', '--sound SOUND', 'Sound to play with the notification' c.option '-n', '--[no]-newsstand', 'Indicates content available for Newsstand' c.option '-d', '--data KEY=VALUE', Array, 'Passes custom data to payload (as comma-delimited "key=value" declarations)' c.option '-P', '--payload PAYLOAD', 'JSON payload for notifications' c.option '-e', '--environment ENV', [:production, :development], 'Environment to send push notification (production or development (default))' c.option '-c', '--certificate CERTIFICATE', 'Path to certificate (.pem) file' c.option '-p', '--[no]-passphrase', 'Prompt for a certificate passphrase' c.action do |args, options| say_error "One or more device tokens required" and abort if args.empty? @environment = options.environment.downcase.to_sym rescue :development say_error "Invalid environment,'#{@environment}' (should be either :development or :production)" and abort unless [:development, :production].include?(@environment) @certificate = options.certificate say_error "Missing certificate file option (-c /path/to/certificate.pem)" and abort unless @certificate say_error "Could not find certificate file '#{@certificate}'" and abort unless File.exists?(@certificate) @passphrase = options.passphrase ? password : "" @alert = options.alert @badge = options.badge.nil? ? nil : options.badge.to_i @sound = options.sound @content_available = options.newsstand if options.payload begin @data = JSON.parse(options.payload) rescue => message say_error "Exception parsing JSON payload: #{message}" and abort end elsif options.data begin @data = Hash[options.data.collect{|data| data.split(/\=/)}] rescue => message say_error "Exception parsing JSON payload: #{message}" and abort end end unless @alert or @badge or @newsstand or @data placeholder = "Enter your alert message" @alert = ask_editor placeholder say_error "Payload contents required" and abort if @alert.nil? or @alert == placeholder end @notifications = [] args.each do |token| notification = Houston::Notification.new(@data || {}) notification.token = token notification.alert = @alert if @alert notification.badge = @badge if @badge notification.sound = @sound if @sound notification.content_available = @content_available if @content_available @notifications << notification end client = @environment == :production ? Houston::Client.production : Houston::Client.development client.certificate = File.read(@certificate) client.passphrase = @passphrase begin client.push(*@notifications) rescue => message say_error "Exception sending notification: #{message}" and abort end say_ok "Push notifications successfully sent" end end