spire_io 1.0.0 → 1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/spire/api.rb +27 -6
- data/lib/spire/api/application.rb +325 -0
- data/lib/spire/api/channel.rb +62 -1
- data/lib/spire/api/event.rb +27 -0
- data/lib/spire/api/{message.rb → member.rb} +6 -2
- data/lib/spire/api/notification.rb +100 -0
- data/lib/spire/api/resource.rb +0 -4
- data/lib/spire/api/session.rb +184 -10
- data/lib/spire/api/subscription.rb +45 -20
- data/lib/spire_io.rb +79 -3
- metadata +8 -6
    
        data/lib/spire/api.rb
    CHANGED
    
    | @@ -10,7 +10,10 @@ require "spire/api/session" | |
| 10 10 | 
             
            require "spire/api/account"
         | 
| 11 11 | 
             
            require "spire/api/channel"
         | 
| 12 12 | 
             
            require "spire/api/subscription"
         | 
| 13 | 
            -
            require "spire/api/ | 
| 13 | 
            +
            require "spire/api/event"
         | 
| 14 | 
            +
            require "spire/api/application"
         | 
| 15 | 
            +
            require "spire/api/member"
         | 
| 16 | 
            +
            require "spire/api/notification"
         | 
| 14 17 |  | 
| 15 18 | 
             
            class Spire
         | 
| 16 19 |  | 
| @@ -28,10 +31,6 @@ class Spire | |
| 28 31 | 
             
                  @url = url
         | 
| 29 32 | 
             
                end
         | 
| 30 33 |  | 
| 31 | 
            -
                def inspect
         | 
| 32 | 
            -
                  "#<Spire::API:0x#{object_id.to_s(16)} @url=#{@url.dump}>"
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 34 | 
             
                define_request(:discover) do
         | 
| 36 35 | 
             
                  {
         | 
| 37 36 | 
             
                    :method => :get,
         | 
| @@ -71,7 +70,8 @@ class Spire | |
| 71 70 | 
             
                    :body => {
         | 
| 72 71 | 
             
                      :email => info[:email],
         | 
| 73 72 | 
             
                      :password => info[:password],
         | 
| 74 | 
            -
                      :password_confirmation => info[:password_confirmation]
         | 
| 73 | 
            +
                      :password_confirmation => info[:password_confirmation],
         | 
| 74 | 
            +
                      :email_opt_in => info[:email_opt_in]
         | 
| 75 75 | 
             
                    }.to_json,
         | 
| 76 76 | 
             
                    :headers => { 
         | 
| 77 77 | 
             
                      "Accept" => mediaType("session"),
         | 
| @@ -99,6 +99,17 @@ class Spire | |
| 99 99 | 
             
                  }
         | 
| 100 100 | 
             
                end
         | 
| 101 101 |  | 
| 102 | 
            +
                define_request(:get_application) do |app_key|
         | 
| 103 | 
            +
                  {
         | 
| 104 | 
            +
                    :method => :get,
         | 
| 105 | 
            +
                    :url => @description["resources"]["applications"]["url"],
         | 
| 106 | 
            +
                    :query => {:application_key => app_key},
         | 
| 107 | 
            +
                    :headers => {
         | 
| 108 | 
            +
                      "Accept" => mediaType("applications"),
         | 
| 109 | 
            +
                      "Content-Type" => mediaType("applications")
         | 
| 110 | 
            +
                    }
         | 
| 111 | 
            +
                  }
         | 
| 112 | 
            +
                end
         | 
| 102 113 |  | 
| 103 114 | 
             
                def discover
         | 
| 104 115 | 
             
                  response = request(:discover)
         | 
| @@ -146,6 +157,16 @@ class Spire | |
| 146 157 | 
             
                  response
         | 
| 147 158 | 
             
                end
         | 
| 148 159 |  | 
| 160 | 
            +
                # Gets an application resource from a key without requiring any authentication
         | 
| 161 | 
            +
                # @param [String] application_key The application key
         | 
| 162 | 
            +
                def get_application(application_key)
         | 
| 163 | 
            +
                  response = request(:get_application, application_key)
         | 
| 164 | 
            +
                  if response.status != 200
         | 
| 165 | 
            +
                    raise "Error attempting to retrieve application (#{response.status}) #{response.body}"
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
                  API::Application.new(self, response.data)
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 149 170 | 
             
                # Returns a billing object than contains a list of all the plans available
         | 
| 150 171 | 
             
                # @param [String] info optional object description
         | 
| 151 172 | 
             
                # @return [Billing]
         | 
| @@ -0,0 +1,325 @@ | |
| 1 | 
            +
            require 'base64'
         | 
| 2 | 
            +
            class Spire
         | 
| 3 | 
            +
              class API
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class Application < Resource
         | 
| 6 | 
            +
                  attr_reader :resources
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def resource_name
         | 
| 9 | 
            +
                    "application"
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def initialize(spire, data)
         | 
| 13 | 
            +
                    super
         | 
| 14 | 
            +
                    @resources = data["resources"]
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  #Channels
         | 
| 18 | 
            +
                  define_request(:create_channel) do |name, message_limit, message_ttl|
         | 
| 19 | 
            +
                    collection = @resources["channels"]
         | 
| 20 | 
            +
                    capability = collection["capabilities"]["create"]
         | 
| 21 | 
            +
                    url = collection["url"]
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    body = {
         | 
| 24 | 
            +
                      :name => name,
         | 
| 25 | 
            +
                      :message_limit => message_limit,
         | 
| 26 | 
            +
                      :message_ttl => message_ttl
         | 
| 27 | 
            +
                    }.to_json
         | 
| 28 | 
            +
                    {
         | 
| 29 | 
            +
                      :method => :post,
         | 
| 30 | 
            +
                      :url => url,
         | 
| 31 | 
            +
                      :body => body,
         | 
| 32 | 
            +
                      :headers => {
         | 
| 33 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 34 | 
            +
                        "Accept" => @spire.mediaType("channel"),
         | 
| 35 | 
            +
                        "Content-Type" => @spire.mediaType("channel")
         | 
| 36 | 
            +
                      }
         | 
| 37 | 
            +
                    }
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  define_request(:channels) do
         | 
| 41 | 
            +
                    collection = @resources["channels"]
         | 
| 42 | 
            +
                    capability = collection["capabilities"]["all"]
         | 
| 43 | 
            +
                    url = collection["url"]
         | 
| 44 | 
            +
                    {
         | 
| 45 | 
            +
                      :method => :get,
         | 
| 46 | 
            +
                      :url => url,
         | 
| 47 | 
            +
                      :headers => {
         | 
| 48 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 49 | 
            +
                        "Accept" => @spire.mediaType("channels"),
         | 
| 50 | 
            +
                      }
         | 
| 51 | 
            +
                    }
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  define_request(:channel_by_name) do |name|
         | 
| 55 | 
            +
                    collection = @resources["channels"]
         | 
| 56 | 
            +
                    capability = collection["capabilities"]["get_by_name"]
         | 
| 57 | 
            +
                    url = collection["url"]
         | 
| 58 | 
            +
                    request = {
         | 
| 59 | 
            +
                      :method => :get,
         | 
| 60 | 
            +
                      :url => url,
         | 
| 61 | 
            +
                      :query => {:name => name},
         | 
| 62 | 
            +
                      :headers => {
         | 
| 63 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 64 | 
            +
                        "Accept" => @spire.mediaType("channels"),
         | 
| 65 | 
            +
                      }
         | 
| 66 | 
            +
                    }
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  #Subscriptions
         | 
| 70 | 
            +
                  define_request(:subscriptions) do
         | 
| 71 | 
            +
                    collection = @resources["subscriptions"]
         | 
| 72 | 
            +
                    capability = collection["capabilities"]["all"]
         | 
| 73 | 
            +
                    url = collection["url"]
         | 
| 74 | 
            +
                    {
         | 
| 75 | 
            +
                      :method => :get,
         | 
| 76 | 
            +
                      :url => url,
         | 
| 77 | 
            +
                      :headers => {
         | 
| 78 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 79 | 
            +
                        "Accept" => @spire.mediaType("subscriptions"),
         | 
| 80 | 
            +
                      }
         | 
| 81 | 
            +
                    }
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  define_request(:create_subscription) do |subscription_name, channel_urls|
         | 
| 85 | 
            +
                    collection = @resources["subscriptions"]
         | 
| 86 | 
            +
                    capability = collection["capabilities"]["create"]
         | 
| 87 | 
            +
                    url = collection["url"]
         | 
| 88 | 
            +
                    {
         | 
| 89 | 
            +
                      :method => :post,
         | 
| 90 | 
            +
                      :url => url,
         | 
| 91 | 
            +
                      :body => {
         | 
| 92 | 
            +
                        :channels => channel_urls,
         | 
| 93 | 
            +
                        :name => subscription_name
         | 
| 94 | 
            +
                      }.to_json,
         | 
| 95 | 
            +
                      :headers => {
         | 
| 96 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 97 | 
            +
                        "Accept" => @spire.mediaType("subscription"),
         | 
| 98 | 
            +
                        "Content-Type" => @spire.mediaType("subscription")
         | 
| 99 | 
            +
                      }
         | 
| 100 | 
            +
                    }
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  define_request(:subscription_by_name) do |name|
         | 
| 104 | 
            +
                    collection = @resources["subscriptions"]
         | 
| 105 | 
            +
                    capability = collection["capabilities"]["get_by_name"]
         | 
| 106 | 
            +
                    url = collection["url"]
         | 
| 107 | 
            +
                    request = {
         | 
| 108 | 
            +
                      :method => :get,
         | 
| 109 | 
            +
                      :url => url,
         | 
| 110 | 
            +
                      :query => {:name => name},
         | 
| 111 | 
            +
                      :headers => {
         | 
| 112 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 113 | 
            +
                        "Accept" => @spire.mediaType("subscriptions"),
         | 
| 114 | 
            +
                      }
         | 
| 115 | 
            +
                    }
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  #Members
         | 
| 119 | 
            +
                  define_request(:create_member) do |data|
         | 
| 120 | 
            +
                    collection = @resources["members"]
         | 
| 121 | 
            +
                    capability = collection["capabilities"]["create"]
         | 
| 122 | 
            +
                    url = collection["url"]
         | 
| 123 | 
            +
                    {
         | 
| 124 | 
            +
                      :method => :post,
         | 
| 125 | 
            +
                      :url => url,
         | 
| 126 | 
            +
                      :body => data.to_json,
         | 
| 127 | 
            +
                      :headers => {
         | 
| 128 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 129 | 
            +
                        "Accept" => @spire.mediaType("member"),
         | 
| 130 | 
            +
                        "Content-Type" => @spire.mediaType("member")
         | 
| 131 | 
            +
                      }
         | 
| 132 | 
            +
                    }
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                  define_request(:members) do
         | 
| 136 | 
            +
                    collection = @resources["members"]
         | 
| 137 | 
            +
                    capability = collection["capabilities"]["all"]
         | 
| 138 | 
            +
                    url = collection["url"]
         | 
| 139 | 
            +
                    {
         | 
| 140 | 
            +
                      :method => :get,
         | 
| 141 | 
            +
                      :url => url,
         | 
| 142 | 
            +
                      :headers => {
         | 
| 143 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 144 | 
            +
                        "Accept" => @spire.mediaType("members"),
         | 
| 145 | 
            +
                      }
         | 
| 146 | 
            +
                    }
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  define_request(:member_by_login) do |login|
         | 
| 150 | 
            +
                    collection = @resources["members"]
         | 
| 151 | 
            +
                    capability = collection["capabilities"]["get_by_login"]
         | 
| 152 | 
            +
                    url = collection["url"]
         | 
| 153 | 
            +
                    request = {
         | 
| 154 | 
            +
                      :method => :get,
         | 
| 155 | 
            +
                      :url => url,
         | 
| 156 | 
            +
                      :query => {:login => login},
         | 
| 157 | 
            +
                      :headers => {
         | 
| 158 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 159 | 
            +
                        "Accept" => @spire.mediaType("member"),
         | 
| 160 | 
            +
                      }
         | 
| 161 | 
            +
                    }
         | 
| 162 | 
            +
                  end
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                  define_request(:authenticate_with_post) do |data|
         | 
| 165 | 
            +
                    collection = @resources["authentication"]
         | 
| 166 | 
            +
                    url = collection["url"]
         | 
| 167 | 
            +
                    request = {
         | 
| 168 | 
            +
                      :method => :post,
         | 
| 169 | 
            +
                      :url => url,
         | 
| 170 | 
            +
                      :body => data.to_json,
         | 
| 171 | 
            +
                      :headers => {
         | 
| 172 | 
            +
                        "Accept" => @spire.mediaType("member"),
         | 
| 173 | 
            +
                      }
         | 
| 174 | 
            +
                    }
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  define_request(:authenticate) do |data|
         | 
| 178 | 
            +
                    collection = @resources["members"]
         | 
| 179 | 
            +
                    url = "#{collection["url"]}?login=#{data[:login]}"
         | 
| 180 | 
            +
                    auth = Base64.encode64("#{data[:login]}:#{data[:password]}").gsub("\n", '')
         | 
| 181 | 
            +
                    request = {
         | 
| 182 | 
            +
                      :method => :get,
         | 
| 183 | 
            +
                      :url => url,
         | 
| 184 | 
            +
                      :headers => {
         | 
| 185 | 
            +
                        "Accept" => @spire.mediaType("member"),
         | 
| 186 | 
            +
                        "Authorization" => "Basic #{auth}"
         | 
| 187 | 
            +
                      }
         | 
| 188 | 
            +
                    }
         | 
| 189 | 
            +
                  end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  #Authenticates with the application using basic auth
         | 
| 192 | 
            +
                  def authenticate(login, password)
         | 
| 193 | 
            +
                    response = request(:authenticate, {:login => login, :password => password})
         | 
| 194 | 
            +
                    unless response.status == 200
         | 
| 195 | 
            +
                      raise "Error authenticating for application #{self.name}: (#{response.status}) #{response.body}"
         | 
| 196 | 
            +
                    end
         | 
| 197 | 
            +
                    API::Member.new(@spire, response.data)
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                  #Alternative application authentication, without using basic auth
         | 
| 201 | 
            +
                  def authenticate_with_post(login, password)
         | 
| 202 | 
            +
                    response = request(:authenticate_with_post, {:login => login, :password => password})
         | 
| 203 | 
            +
                    unless response.status == 201
         | 
| 204 | 
            +
                      raise "Error authenticating for application #{self.name}: (#{response.status}) #{response.body}"
         | 
| 205 | 
            +
                    end
         | 
| 206 | 
            +
                    API::Member.new(@spire, response.data)
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  def create_member(member_data)
         | 
| 210 | 
            +
                    response = request(:create_member, member_data)
         | 
| 211 | 
            +
                    unless response.status == 201
         | 
| 212 | 
            +
                      raise "Error creating member for application #{self.name}: (#{response.status}) #{response.body}"
         | 
| 213 | 
            +
                    end
         | 
| 214 | 
            +
                    API::Member.new(@spire, response.data)
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
                  
         | 
| 217 | 
            +
                  def members
         | 
| 218 | 
            +
                    @members || members!
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                  def members!
         | 
| 222 | 
            +
                    response = request(:members)
         | 
| 223 | 
            +
                    unless response.status == 200
         | 
| 224 | 
            +
                      raise "Error getting members for application #{self.name}: (#{response.status}) #{response.body}"
         | 
| 225 | 
            +
                    end
         | 
| 226 | 
            +
                    @members = {}
         | 
| 227 | 
            +
                    response.data.each do |login, properties|
         | 
| 228 | 
            +
                      @members[login] = API::Member.new(@spire, properties)
         | 
| 229 | 
            +
                    end
         | 
| 230 | 
            +
                    @members
         | 
| 231 | 
            +
                  end
         | 
| 232 | 
            +
             | 
| 233 | 
            +
                  def get_member(member_login)
         | 
| 234 | 
            +
                    response = request(:member_by_login, member_login)
         | 
| 235 | 
            +
                    unless response.status == 200
         | 
| 236 | 
            +
                      raise "Error finding member with login #{member_login}: (#{response.status}) #{response.body}"
         | 
| 237 | 
            +
                    end
         | 
| 238 | 
            +
                    properties = response.data[member_login]
         | 
| 239 | 
            +
                    member = API::Member.new(@spire, properties)
         | 
| 240 | 
            +
                    @members[member_login] = member if @members.is_a?(Hash)
         | 
| 241 | 
            +
                    member
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
                  
         | 
| 244 | 
            +
                  def create_channel(name, options={})
         | 
| 245 | 
            +
                    message_limit = options[:message_limit]
         | 
| 246 | 
            +
                    message_ttl = options[:message_ttl]
         | 
| 247 | 
            +
                    response = request(:create_channel, name, message_limit, message_ttl)
         | 
| 248 | 
            +
                    unless response.status == 201
         | 
| 249 | 
            +
                      raise "Error creating Channel: (#{response.status}) #{response.body}"
         | 
| 250 | 
            +
                    end
         | 
| 251 | 
            +
                    properties = response.data
         | 
| 252 | 
            +
                    channels[name] = API::Channel.new(@spire, properties)
         | 
| 253 | 
            +
                  end
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                  def create_subscription(subscription_name, channel_names)
         | 
| 256 | 
            +
                    channel_urls = channel_names.flatten.map { |name| self.channels[name].url rescue nil }.compact
         | 
| 257 | 
            +
                    response = request(:create_subscription, subscription_name, channel_urls)
         | 
| 258 | 
            +
                    unless response.status == 201
         | 
| 259 | 
            +
                      raise "Error creating Subscription: (#{response.status}) #{response.body}"
         | 
| 260 | 
            +
                    end
         | 
| 261 | 
            +
                    data = response.data
         | 
| 262 | 
            +
                    subscription = API::Subscription.new(@spire, data) 
         | 
| 263 | 
            +
                    if subscription_name
         | 
| 264 | 
            +
                      subscriptions[data["name"]] = subscription
         | 
| 265 | 
            +
                    end
         | 
| 266 | 
            +
                    subscription
         | 
| 267 | 
            +
                  end
         | 
| 268 | 
            +
                  
         | 
| 269 | 
            +
                  def channels!
         | 
| 270 | 
            +
                    response = request(:channels)
         | 
| 271 | 
            +
                    unless response.status == 200
         | 
| 272 | 
            +
                      raise "Error retrieving Channels: (#{response.status}) #{response.body}"
         | 
| 273 | 
            +
                    end
         | 
| 274 | 
            +
                    channels_data = response.data
         | 
| 275 | 
            +
                    @channels = {}
         | 
| 276 | 
            +
                    channels_data.each do |name, properties|
         | 
| 277 | 
            +
                      @channels[name] = API::Channel.new(@spire, properties)
         | 
| 278 | 
            +
                    end
         | 
| 279 | 
            +
                    @channels
         | 
| 280 | 
            +
                  end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  def channels
         | 
| 283 | 
            +
                    @channels ||= channels!
         | 
| 284 | 
            +
                  end
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                  def subscriptions
         | 
| 287 | 
            +
                    @subscriptions ||= subscriptions!
         | 
| 288 | 
            +
                  end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                  def subscriptions!
         | 
| 291 | 
            +
                    response = request(:subscriptions)
         | 
| 292 | 
            +
                    unless response.status == 200
         | 
| 293 | 
            +
                      raise "Error retrieving Subscriptions: (#{response.status}) #{response.body}"
         | 
| 294 | 
            +
                    end
         | 
| 295 | 
            +
                    @subscriptions = {}
         | 
| 296 | 
            +
                    response.data.each do |name, properties|
         | 
| 297 | 
            +
                      @subscriptions[name] = API::Subscription.new(@spire, properties)
         | 
| 298 | 
            +
                    end
         | 
| 299 | 
            +
                    @subscriptions
         | 
| 300 | 
            +
                  end
         | 
| 301 | 
            +
                  
         | 
| 302 | 
            +
                  def get_channel(name)
         | 
| 303 | 
            +
                    response = request(:channel_by_name, name)
         | 
| 304 | 
            +
                    unless response.status == 200
         | 
| 305 | 
            +
                      raise "Error finding channel with name #{name}: (#{response.status}) #{response.body}"
         | 
| 306 | 
            +
                    end
         | 
| 307 | 
            +
                    properties = response.data[name]
         | 
| 308 | 
            +
                    channel = API::Channel.new(@spire, properties)
         | 
| 309 | 
            +
                    @channels[name] = channel if @channels.is_a?(Hash)
         | 
| 310 | 
            +
                    channel
         | 
| 311 | 
            +
                  end
         | 
| 312 | 
            +
                  
         | 
| 313 | 
            +
                  def get_subscription(name)
         | 
| 314 | 
            +
                    response = request(:subscription_by_name, name)
         | 
| 315 | 
            +
                    unless response.status == 200
         | 
| 316 | 
            +
                      raise "Error finding subscription with name #{name}: (#{response.status}) #{response.body}"
         | 
| 317 | 
            +
                    end
         | 
| 318 | 
            +
                    properties = response.data[name]
         | 
| 319 | 
            +
                    sub = API::Subscription.new(@spire, properties)
         | 
| 320 | 
            +
                    @subscriptions[name] = sub if @subscriptions.is_a?(Hash)
         | 
| 321 | 
            +
                    sub
         | 
| 322 | 
            +
                  end
         | 
| 323 | 
            +
                end
         | 
| 324 | 
            +
              end
         | 
| 325 | 
            +
            end
         | 
    
        data/lib/spire/api/channel.rb
    CHANGED
    
    | @@ -2,10 +2,32 @@ class Spire | |
| 2 2 | 
             
              class API
         | 
| 3 3 |  | 
| 4 4 | 
             
                class Channel < Resource
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  attr_reader :resources
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def initialize(spire, data)
         | 
| 9 | 
            +
                    super
         | 
| 10 | 
            +
                    @resources = data["resources"]
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 5 13 | 
             
                  def resource_name
         | 
| 6 14 | 
             
                    "channel"
         | 
| 7 15 | 
             
                  end
         | 
| 8 16 |  | 
| 17 | 
            +
                  define_request(:subscriptions) do
         | 
| 18 | 
            +
                    collection = @resources["subscriptions"]
         | 
| 19 | 
            +
                    capability = collection["capabilities"]["get_subscriptions"]
         | 
| 20 | 
            +
                    url = collection["url"]
         | 
| 21 | 
            +
                    {
         | 
| 22 | 
            +
                      :method => :get,
         | 
| 23 | 
            +
                      :url => url,
         | 
| 24 | 
            +
                      :headers => {
         | 
| 25 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 26 | 
            +
                        "Accept" => @spire.mediaType("subscriptions"),
         | 
| 27 | 
            +
                      }
         | 
| 28 | 
            +
                    }
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 9 31 | 
             
                  define_request(:publish) do |string|
         | 
| 10 32 | 
             
                    {
         | 
| 11 33 | 
             
                      :method => :post,
         | 
| @@ -19,15 +41,54 @@ class Spire | |
| 19 41 | 
             
                    }
         | 
| 20 42 | 
             
                  end
         | 
| 21 43 |  | 
| 44 | 
            +
                  define_request(:subscribe) do |name|
         | 
| 45 | 
            +
                    collection = @resources["subscriptions"]
         | 
| 46 | 
            +
                    capability = collection["capabilities"]["create"]
         | 
| 47 | 
            +
                    url = collection["url"]
         | 
| 48 | 
            +
                    {
         | 
| 49 | 
            +
                      :method => :post,
         | 
| 50 | 
            +
                      :url => url,
         | 
| 51 | 
            +
                      :body => {:name => name}.to_json,
         | 
| 52 | 
            +
                      :headers => {
         | 
| 53 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 54 | 
            +
                        "Accept" => @spire.mediaType("subscription"),
         | 
| 55 | 
            +
                        "Content-Type" => @spire.mediaType("subscription")
         | 
| 56 | 
            +
                      }
         | 
| 57 | 
            +
                    }
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def subscriptions
         | 
| 61 | 
            +
                    @subscriptions ||= subscriptions!
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def subscriptions!
         | 
| 65 | 
            +
                    response = request(:subscriptions)
         | 
| 66 | 
            +
                    unless response.status == 200
         | 
| 67 | 
            +
                      raise "Error getting subscriptions to #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                    @subscriptions = {}
         | 
| 70 | 
            +
                    response.data.each do |name, properties|
         | 
| 71 | 
            +
                      @subscriptions[name] = API::Subscription.new(@spire, properties)
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                    @subscriptions
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 22 76 | 
             
                  def publish(content)
         | 
| 23 77 | 
             
                    body = {:content => content}.to_json
         | 
| 24 78 | 
             
                    response = request(:publish, body)
         | 
| 25 79 | 
             
                    unless response.status == 201
         | 
| 26 80 | 
             
                      raise "Error publishing to #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 27 81 | 
             
                    end
         | 
| 28 | 
            -
                     | 
| 82 | 
            +
                    API::Message.new(@spire, response.data)
         | 
| 29 83 | 
             
                  end
         | 
| 30 84 |  | 
| 85 | 
            +
                  def subscribe(name = nil)
         | 
| 86 | 
            +
                    response = request(:subscribe, name)
         | 
| 87 | 
            +
                    unless response.status == 201
         | 
| 88 | 
            +
                      raise "Error creating subscription for #{self.name}: (#{response.status}) #{response.body}"
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
                    API::Subscription.new(@spire, response.data)
         | 
| 91 | 
            +
                  end
         | 
| 31 92 | 
             
                end
         | 
| 32 93 |  | 
| 33 94 | 
             
              end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            class Spire
         | 
| 2 | 
            +
              class API
         | 
| 3 | 
            +
                class Event < Resource
         | 
| 4 | 
            +
                  def resource_name
         | 
| 5 | 
            +
                    "event"
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                class Message < Event
         | 
| 10 | 
            +
                  def resource_name
         | 
| 11 | 
            +
                    "message"
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                class Join < Event
         | 
| 16 | 
            +
                  def resource_name
         | 
| 17 | 
            +
                    "join"
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                class Part < Event
         | 
| 22 | 
            +
                  def resource_name
         | 
| 23 | 
            +
                    "part"
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            class Spire
         | 
| 2 | 
            +
              class API
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                class Notification < Resource
         | 
| 5 | 
            +
                  def resource_name
         | 
| 6 | 
            +
                    "notification"
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
                  
         | 
| 9 | 
            +
                  define_request(:push) do |options|
         | 
| 10 | 
            +
                    {
         | 
| 11 | 
            +
                      :method => :post,
         | 
| 12 | 
            +
                      :url => @url,
         | 
| 13 | 
            +
                      :body => {
         | 
| 14 | 
            +
                        :device_tokens => options[:device_tokens],
         | 
| 15 | 
            +
                        :message => options[:message]
         | 
| 16 | 
            +
                      }.to_json,
         | 
| 17 | 
            +
                      :headers => {
         | 
| 18 | 
            +
                        "Authorization" => "Capability #{@capabilities["push"]}",
         | 
| 19 | 
            +
                        "Accept" => @spire.mediaType("notification"),
         | 
| 20 | 
            +
                        "Content-Type" => @spire.mediaType("notification")
         | 
| 21 | 
            +
                      }
         | 
| 22 | 
            +
                    }
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  define_request(:devices) do
         | 
| 26 | 
            +
                    devices = properties["resources"]["devices"]
         | 
| 27 | 
            +
                    capability = devices["capabilities"]["devices"]
         | 
| 28 | 
            +
                    {
         | 
| 29 | 
            +
                      :method => :get,
         | 
| 30 | 
            +
                      :url => devices["url"],
         | 
| 31 | 
            +
                      :headers => {
         | 
| 32 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 33 | 
            +
                        "Accept" => "application/json"
         | 
| 34 | 
            +
                      }
         | 
| 35 | 
            +
                    }
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                  define_request(:register_device) do |data|
         | 
| 39 | 
            +
                    devices = properties["resources"]["devices"]
         | 
| 40 | 
            +
                    capability = devices["capabilities"]["register_device"]
         | 
| 41 | 
            +
                    {
         | 
| 42 | 
            +
                      :method => :put,
         | 
| 43 | 
            +
                      :url => devices["url"],
         | 
| 44 | 
            +
                      :body => data.to_json,
         | 
| 45 | 
            +
                      :headers => {
         | 
| 46 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 47 | 
            +
                        "Accept" => "application/json",
         | 
| 48 | 
            +
                        "Content-Type" => "application/json"
         | 
| 49 | 
            +
                      }
         | 
| 50 | 
            +
                    }
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                  
         | 
| 53 | 
            +
                  define_request(:remove_device) do |data|
         | 
| 54 | 
            +
                    devices = properties["resources"]["devices"]
         | 
| 55 | 
            +
                    capability = devices["capabilities"]["remove_device"]
         | 
| 56 | 
            +
                    {
         | 
| 57 | 
            +
                      :method => :delete,
         | 
| 58 | 
            +
                      :url => devices["url"],
         | 
| 59 | 
            +
                      :body => data.to_json,
         | 
| 60 | 
            +
                      :headers => {
         | 
| 61 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 62 | 
            +
                        "Accept" => "application/json",
         | 
| 63 | 
            +
                        "Content-Type" => "application/json"
         | 
| 64 | 
            +
                      }
         | 
| 65 | 
            +
                    }
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                  
         | 
| 68 | 
            +
                  def send_notification(options={})
         | 
| 69 | 
            +
                    response = request(:push, options)
         | 
| 70 | 
            +
                    unless response.status == 200
         | 
| 71 | 
            +
                      raise "Error sending push notification #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                    response.data
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  def devices!
         | 
| 77 | 
            +
                    response = request(:devices)
         | 
| 78 | 
            +
                    unless response.status == 200
         | 
| 79 | 
            +
                      raise "Error getting device list #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                    response.data["devices"]
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                  
         | 
| 84 | 
            +
                  def register_device(device_token)
         | 
| 85 | 
            +
                    response = request(:register_device, :token => device_token)
         | 
| 86 | 
            +
                    unless response.status == 200
         | 
| 87 | 
            +
                      raise "Error adding device #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                    token = response.data["token"]
         | 
| 90 | 
            +
                    devices[token] = response.data
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
                  
         | 
| 93 | 
            +
                  def devices
         | 
| 94 | 
            +
                    @devices ||= {}
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                  
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
            end
         | 
    
        data/lib/spire/api/resource.rb
    CHANGED
    
    
    
        data/lib/spire/api/session.rb
    CHANGED
    
    | @@ -33,14 +33,20 @@ class Spire | |
| 33 33 | 
             
                    }
         | 
| 34 34 | 
             
                  end
         | 
| 35 35 |  | 
| 36 | 
            -
                  define_request(:create_channel) do |name|
         | 
| 36 | 
            +
                  define_request(:create_channel) do |name, limit, ttl|
         | 
| 37 37 | 
             
                    collection = @resources["channels"]
         | 
| 38 38 | 
             
                    capability = collection["capabilities"]["create"]
         | 
| 39 39 | 
             
                    url = collection["url"]
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    body = {
         | 
| 42 | 
            +
                      :name => name,
         | 
| 43 | 
            +
                      :limit => limit,
         | 
| 44 | 
            +
                      :ttl => ttl
         | 
| 45 | 
            +
                    }.to_json
         | 
| 40 46 | 
             
                    {
         | 
| 41 47 | 
             
                      :method => :post,
         | 
| 42 48 | 
             
                      :url => url,
         | 
| 43 | 
            -
                      :body =>  | 
| 49 | 
            +
                      :body => body,
         | 
| 44 50 | 
             
                      :headers => {
         | 
| 45 51 | 
             
                        "Authorization" => "Capability #{capability}",
         | 
| 46 52 | 
             
                        "Accept" => @spire.mediaType("channel"),
         | 
| @@ -63,7 +69,13 @@ class Spire | |
| 63 69 | 
             
                    }
         | 
| 64 70 | 
             
                  end
         | 
| 65 71 |  | 
| 66 | 
            -
                  define_request(:create_subscription) do | | 
| 72 | 
            +
                  define_request(:create_subscription) do |options|
         | 
| 73 | 
            +
                    name = options[:name]
         | 
| 74 | 
            +
                    channel_urls = options[:channel_urls]
         | 
| 75 | 
            +
                    expiration = options[:expiration]
         | 
| 76 | 
            +
                    device_token = options[:device_token]
         | 
| 77 | 
            +
                    notification_name = options[:notification_name]
         | 
| 78 | 
            +
             | 
| 67 79 | 
             
                    collection = @resources["subscriptions"]
         | 
| 68 80 | 
             
                    capability = collection["capabilities"]["create"]
         | 
| 69 81 | 
             
                    url = collection["url"]
         | 
| @@ -72,7 +84,10 @@ class Spire | |
| 72 84 | 
             
                      :url => url,
         | 
| 73 85 | 
             
                      :body => {
         | 
| 74 86 | 
             
                        :channels => channel_urls,
         | 
| 75 | 
            -
                        :name =>  | 
| 87 | 
            +
                        :name => name,
         | 
| 88 | 
            +
                        :expiration => expiration,
         | 
| 89 | 
            +
                        :device_token => device_token,
         | 
| 90 | 
            +
                        :notification_name => notification_name
         | 
| 76 91 | 
             
                      }.to_json,
         | 
| 77 92 | 
             
                      :headers => {
         | 
| 78 93 | 
             
                        "Authorization" => "Capability #{capability}",
         | 
| @@ -96,6 +111,81 @@ class Spire | |
| 96 111 | 
             
                      }
         | 
| 97 112 | 
             
                    }
         | 
| 98 113 | 
             
                  end
         | 
| 114 | 
            +
                  
         | 
| 115 | 
            +
                  define_request(:create_notification) do |options|
         | 
| 116 | 
            +
                    collection = @resources["notifications"]
         | 
| 117 | 
            +
                    capability = collection["capabilities"]["create"]
         | 
| 118 | 
            +
                    url = collection["url"]
         | 
| 119 | 
            +
                    {
         | 
| 120 | 
            +
                      :method => :post,
         | 
| 121 | 
            +
                      :url => url,
         | 
| 122 | 
            +
                      :body => {
         | 
| 123 | 
            +
                        :name => options[:name],
         | 
| 124 | 
            +
                        :mode => options[:mode]
         | 
| 125 | 
            +
                      }.to_json,
         | 
| 126 | 
            +
                      :headers => {
         | 
| 127 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 128 | 
            +
                        "Accept" => @spire.mediaType("notification"),
         | 
| 129 | 
            +
                        "Content-Type" => @spire.mediaType("notification")
         | 
| 130 | 
            +
                      }
         | 
| 131 | 
            +
                    }
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
                  
         | 
| 134 | 
            +
                  define_request(:notifications) do
         | 
| 135 | 
            +
                    collection = @resources["notifications"]
         | 
| 136 | 
            +
                    capability = collection["capabilities"]["all"]
         | 
| 137 | 
            +
                    url = collection["url"]
         | 
| 138 | 
            +
                    {
         | 
| 139 | 
            +
                      :method => :get,
         | 
| 140 | 
            +
                      :url => url,
         | 
| 141 | 
            +
                      :headers => {
         | 
| 142 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 143 | 
            +
                        "Accept" => @spire.mediaType("notifications"),
         | 
| 144 | 
            +
                      }
         | 
| 145 | 
            +
                    }
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  define_request(:applications) do
         | 
| 149 | 
            +
                    collection = @resources["applications"]
         | 
| 150 | 
            +
                    capability = collection["capabilities"]["all"]
         | 
| 151 | 
            +
                    request = {
         | 
| 152 | 
            +
                      :method => :get,
         | 
| 153 | 
            +
                      :url => collection["url"],
         | 
| 154 | 
            +
                      :headers => {
         | 
| 155 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 156 | 
            +
                        "Accept" => @spire.mediaType("applications"),
         | 
| 157 | 
            +
                      }
         | 
| 158 | 
            +
                    }
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                  define_request(:application_by_name) do |name|
         | 
| 162 | 
            +
                    collection = @resources["applications"]
         | 
| 163 | 
            +
                    capability = collection["capabilities"]["get_by_name"]
         | 
| 164 | 
            +
                    url = collection["url"]
         | 
| 165 | 
            +
                    request = {
         | 
| 166 | 
            +
                      :method => :get,
         | 
| 167 | 
            +
                      :url => url,
         | 
| 168 | 
            +
                      :query => {:name => name},
         | 
| 169 | 
            +
                      :headers => {
         | 
| 170 | 
            +
                        "Authorization" => "Capability #{capability}",
         | 
| 171 | 
            +
                        "Accept" => @spire.mediaType("applications"),
         | 
| 172 | 
            +
                      }
         | 
| 173 | 
            +
                    }
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  define_request(:create_application) do |data|
         | 
| 177 | 
            +
                    collection = @resources["applications"]
         | 
| 178 | 
            +
                    {
         | 
| 179 | 
            +
                      :method => :post,
         | 
| 180 | 
            +
                      :url => collection["url"],
         | 
| 181 | 
            +
                      :body => data.to_json,
         | 
| 182 | 
            +
                      :headers => {
         | 
| 183 | 
            +
                        "Authorization" => "Capability #{collection["capabilities"]["create"]}",
         | 
| 184 | 
            +
                        "Accept" => @spire.mediaType("application"),
         | 
| 185 | 
            +
                        "Content-Type" => @spire.mediaType("application")
         | 
| 186 | 
            +
                      }
         | 
| 187 | 
            +
                    }
         | 
| 188 | 
            +
                  end
         | 
| 99 189 |  | 
| 100 190 | 
             
                  attr_reader :url, :resources, :schema, :capabilities, :capability
         | 
| 101 191 |  | 
| @@ -116,8 +206,10 @@ class Spire | |
| 116 206 | 
             
                    @account = API::Account.new(@spire, @resources["account"]).get
         | 
| 117 207 | 
             
                  end
         | 
| 118 208 |  | 
| 119 | 
            -
                  def create_channel(name)
         | 
| 120 | 
            -
                     | 
| 209 | 
            +
                  def create_channel(name, options={})
         | 
| 210 | 
            +
                    limit = options[:limit]
         | 
| 211 | 
            +
                    ttl = options[:ttl]
         | 
| 212 | 
            +
                    response = request(:create_channel, name, limit, ttl)
         | 
| 121 213 | 
             
                    unless response.status == 201
         | 
| 122 214 | 
             
                      raise "Error creating Channel: (#{response.status}) #{response.body}"
         | 
| 123 215 | 
             
                    end
         | 
| @@ -125,20 +217,86 @@ class Spire | |
| 125 217 | 
             
                    channels[name] = API::Channel.new(@spire, properties)
         | 
| 126 218 | 
             
                  end
         | 
| 127 219 |  | 
| 128 | 
            -
                  def create_subscription(subscription_name, channel_names)
         | 
| 129 | 
            -
                    channel_urls = channel_names.flatten.map { |name| self.channels[name].url rescue nil } | 
| 130 | 
            -
                     | 
| 220 | 
            +
                  def create_subscription(subscription_name, channel_names, expiration=nil, device_token=nil, notification_name=nil, second_try=false)
         | 
| 221 | 
            +
                    channel_urls = channel_names.flatten.map { |name| self.channels[name].url rescue nil }
         | 
| 222 | 
            +
                    if channel_urls.size != channel_urls.compact.size
         | 
| 223 | 
            +
                      if !second_try
         | 
| 224 | 
            +
                        self.channels!
         | 
| 225 | 
            +
                        return create_subscription(subscription_name, channel_names, expiration, device_token, notification_name, true)
         | 
| 226 | 
            +
                      else
         | 
| 227 | 
            +
                        channel_urls = channel_urls.compact
         | 
| 228 | 
            +
                      end
         | 
| 229 | 
            +
                    end
         | 
| 230 | 
            +
                    response = request(:create_subscription, {
         | 
| 231 | 
            +
                      :name => subscription_name,
         | 
| 232 | 
            +
                      :channel_urls => channel_urls,
         | 
| 233 | 
            +
                      :expiration => expiration,
         | 
| 234 | 
            +
                      :device_token => device_token,
         | 
| 235 | 
            +
                      :notification_name => notification_name
         | 
| 236 | 
            +
                    })
         | 
| 237 | 
            +
             | 
| 131 238 | 
             
                    unless response.status == 201
         | 
| 132 239 | 
             
                      raise "Error creating Subscription: (#{response.status}) #{response.body}"
         | 
| 133 240 | 
             
                    end
         | 
| 134 241 | 
             
                    data = response.data
         | 
| 135 | 
            -
                    subscription = API::Subscription.new(@spire, data) | 
| 242 | 
            +
                    subscription = API::Subscription.new(@spire, data)
         | 
| 136 243 | 
             
                    if subscription_name
         | 
| 137 244 | 
             
                      subscriptions[data["name"]] = subscription
         | 
| 138 245 | 
             
                    end
         | 
| 139 246 | 
             
                    subscription
         | 
| 140 247 | 
             
                  end
         | 
| 141 248 |  | 
| 249 | 
            +
                  def get_application(name)
         | 
| 250 | 
            +
                    response = request(:application_by_name, name)
         | 
| 251 | 
            +
                    unless response.status == 200
         | 
| 252 | 
            +
                      raise "Error finding application with name #{name}: (#{response.status}) #{response.body}"
         | 
| 253 | 
            +
                    end
         | 
| 254 | 
            +
                    properties = response.data[name]
         | 
| 255 | 
            +
                    app = API::Application.new(@spire, properties)
         | 
| 256 | 
            +
                    @applications[name] = app if @applications.is_a?(Hash)
         | 
| 257 | 
            +
                    app
         | 
| 258 | 
            +
                  end
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                  def create_application(name, data = {})
         | 
| 261 | 
            +
                    data[:name] = name
         | 
| 262 | 
            +
                    response = request(:create_application, data)
         | 
| 263 | 
            +
                    unless response.status == 201
         | 
| 264 | 
            +
                      raise "Error creating Application (#{response.status}) #{response.body}"
         | 
| 265 | 
            +
                    end
         | 
| 266 | 
            +
                    properties = response.data
         | 
| 267 | 
            +
                    applications[name] = API::Application.new(@spire, properties)
         | 
| 268 | 
            +
                  end
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                  def applications!
         | 
| 271 | 
            +
                    response = request(:applications)
         | 
| 272 | 
            +
                    unless response.status == 200
         | 
| 273 | 
            +
                      raise "Error retrieving Applications (#{response.status}) #{response.body}"
         | 
| 274 | 
            +
                    end
         | 
| 275 | 
            +
                    applications_data = response.data
         | 
| 276 | 
            +
                    @applications = {}
         | 
| 277 | 
            +
                    applications_data.each do |name, properties|
         | 
| 278 | 
            +
                      @applications[name] = API::Application.new(@spire, properties)
         | 
| 279 | 
            +
                    end
         | 
| 280 | 
            +
                    @applications
         | 
| 281 | 
            +
                  end
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                  def applications
         | 
| 284 | 
            +
                    @applications ||= applications!
         | 
| 285 | 
            +
                  end
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                  def create_notification(options={})
         | 
| 288 | 
            +
                    response = request(:create_notification, options)
         | 
| 289 | 
            +
                    unless response.status == 201
         | 
| 290 | 
            +
                      raise "Error creating Notification: (#{response.status}) #{response.body}"
         | 
| 291 | 
            +
                    end
         | 
| 292 | 
            +
                    data = response.data
         | 
| 293 | 
            +
                    notification = API::Notification.new(@spire, data) 
         | 
| 294 | 
            +
                    if options[:name]
         | 
| 295 | 
            +
                      notifications[data["name"]] = notification
         | 
| 296 | 
            +
                    end
         | 
| 297 | 
            +
                    notification
         | 
| 298 | 
            +
                  end
         | 
| 299 | 
            +
                  
         | 
| 142 300 | 
             
                  def channels!
         | 
| 143 301 | 
             
                    response = request(:channels)
         | 
| 144 302 | 
             
                    unless response.status == 200
         | 
| @@ -171,6 +329,22 @@ class Spire | |
| 171 329 | 
             
                    end
         | 
| 172 330 | 
             
                    @subscriptions
         | 
| 173 331 | 
             
                  end
         | 
| 332 | 
            +
                  
         | 
| 333 | 
            +
                  def notifications
         | 
| 334 | 
            +
                    @notifications ||= notifications!
         | 
| 335 | 
            +
                  end
         | 
| 336 | 
            +
                  
         | 
| 337 | 
            +
                  def notifications!
         | 
| 338 | 
            +
                    response = request(:notifications)
         | 
| 339 | 
            +
                    unless response.status == 200
         | 
| 340 | 
            +
                      raise "Error retrieving Notifications: (#{response.status}) #{response.body}"
         | 
| 341 | 
            +
                    end
         | 
| 342 | 
            +
                    @notifications = {}
         | 
| 343 | 
            +
                    response.data.each do |name, properties|
         | 
| 344 | 
            +
                      @notifications[name] = API::Notification.new(@spire, properties)
         | 
| 345 | 
            +
                    end
         | 
| 346 | 
            +
                    @notifications
         | 
| 347 | 
            +
                  end
         | 
| 174 348 |  | 
| 175 349 | 
             
                end
         | 
| 176 350 |  | 
| @@ -8,65 +8,91 @@ class Spire | |
| 8 8 | 
             
                    "subscription"
         | 
| 9 9 | 
             
                  end
         | 
| 10 10 |  | 
| 11 | 
            -
                  define_request(: | 
| 11 | 
            +
                  define_request(:events) do |options|
         | 
| 12 12 | 
             
                    {
         | 
| 13 13 | 
             
                      :method => :get,
         | 
| 14 14 | 
             
                      :url => @url,
         | 
| 15 15 | 
             
                      :query => {
         | 
| 16 16 | 
             
                        "timeout" => options[:timeout],
         | 
| 17 | 
            -
                        "last | 
| 17 | 
            +
                        "last" => options[:last],
         | 
| 18 18 | 
             
                        "order-by" => options[:order_by],
         | 
| 19 19 | 
             
                        "delay" => options[:delay]
         | 
| 20 20 | 
             
                      },
         | 
| 21 21 | 
             
                      :headers => {
         | 
| 22 | 
            -
                        "Authorization" => "Capability #{@capabilities[" | 
| 22 | 
            +
                        "Authorization" => "Capability #{@capabilities["events"]}",
         | 
| 23 23 | 
             
                        "Accept" => @spire.mediaType("events")
         | 
| 24 24 | 
             
                      }
         | 
| 25 25 | 
             
                    }
         | 
| 26 26 | 
             
                  end
         | 
| 27 27 |  | 
| 28 | 
            +
                  EVENT_TYPES = ["message", "join", "part"]
         | 
| 29 | 
            +
             | 
| 28 30 | 
             
                  def listeners
         | 
| 29 | 
            -
                    @listeners | 
| 31 | 
            +
                    if @listeners
         | 
| 32 | 
            +
                      @listeners
         | 
| 33 | 
            +
                    else
         | 
| 34 | 
            +
                      @listeners = { }
         | 
| 35 | 
            +
                      EVENT_TYPES.each do |type|
         | 
| 36 | 
            +
                        @listeners[type] = []
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                      @listeners
         | 
| 39 | 
            +
                    end
         | 
| 30 40 | 
             
                  end
         | 
| 31 41 |  | 
| 32 | 
            -
                  def add_listener(&block)
         | 
| 33 | 
            -
                     | 
| 42 | 
            +
                  def add_listener(type="message", &block)
         | 
| 43 | 
            +
                    type.downcase!
         | 
| 44 | 
            +
                    if !EVENT_TYPES.include?(type)
         | 
| 45 | 
            +
                      throw "Listener type must be one of #{EVENT_TYPES}"
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    listeners[type] << block
         | 
| 34 49 | 
             
                    block
         | 
| 35 50 | 
             
                  end
         | 
| 36 51 |  | 
| 37 | 
            -
                  def  | 
| 52 | 
            +
                  def retrieve_events(options={})
         | 
| 38 53 | 
             
                    options[:last] ||= "0"
         | 
| 39 54 | 
             
                    options[:delay] ||= 0
         | 
| 40 55 | 
             
                    options[:order_by] ||= "desc"
         | 
| 41 56 |  | 
| 42 | 
            -
                    response = request(: | 
| 57 | 
            +
                    response = request(:events, options)
         | 
| 43 58 | 
             
                    unless response.status == 200
         | 
| 44 59 | 
             
                      raise "Error retrieving messages from #{self.class.name}: (#{response.status}) #{response.body}"
         | 
| 45 60 | 
             
                    end
         | 
| 46 | 
            -
                     | 
| 47 | 
            -
             | 
| 48 | 
            -
                     | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 61 | 
            +
                    @last = response.data["last"] if response.data and response.data["last"]
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    event_hash = {
         | 
| 64 | 
            +
                      :first => response.data["first"],
         | 
| 65 | 
            +
                      :last => response.data["last"]
         | 
| 66 | 
            +
                    }
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    EVENT_TYPES.each do |type|
         | 
| 69 | 
            +
                      type_pl = "#{type}s"
         | 
| 70 | 
            +
                      event_hash[type_pl.to_sym] = []
         | 
| 71 | 
            +
                      response.data[type_pl].each do |event|
         | 
| 72 | 
            +
                        klass_name = type.capitalize
         | 
| 73 | 
            +
                        klass = API.const_get(klass_name)
         | 
| 74 | 
            +
                        event_obj = klass.new(@spire, event)
         | 
| 75 | 
            +
                        event_hash[type_pl.to_sym].push(event_obj)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                        listeners[type].each do |listener|
         | 
| 78 | 
            +
                          listener.call(event_obj)
         | 
| 79 | 
            +
                        end
         | 
| 53 80 | 
             
                      end
         | 
| 54 81 | 
             
                    end
         | 
| 55 | 
            -
                     | 
| 82 | 
            +
                    event_hash
         | 
| 56 83 | 
             
                  end
         | 
| 57 84 |  | 
| 58 85 | 
             
                  def poll(options={})
         | 
| 59 86 | 
             
                    # timeout option of 0 means no long poll,
         | 
| 60 87 | 
             
                    # so we force it here.
         | 
| 61 88 | 
             
                    options[:timeout] = 0
         | 
| 62 | 
            -
                    options | 
| 63 | 
            -
                    retrieve_messages(options)
         | 
| 89 | 
            +
                    long_poll(options)
         | 
| 64 90 | 
             
                  end
         | 
| 65 91 |  | 
| 66 92 | 
             
                  def long_poll(options={})
         | 
| 67 93 | 
             
                    options[:timeout] ||= 30
         | 
| 68 94 | 
             
                    options[:last] = @last
         | 
| 69 | 
            -
                     | 
| 95 | 
            +
                    retrieve_events(options)
         | 
| 70 96 | 
             
                  end
         | 
| 71 97 |  | 
| 72 98 | 
             
                  def listen(options={})
         | 
| @@ -76,6 +102,5 @@ class Spire | |
| 76 102 | 
             
                  end
         | 
| 77 103 |  | 
| 78 104 | 
             
                end
         | 
| 79 | 
            -
             | 
| 80 105 | 
             
              end
         | 
| 81 106 | 
             
            end
         | 
    
        data/lib/spire_io.rb
    CHANGED
    
    | @@ -14,7 +14,9 @@ class Spire | |
| 14 14 | 
             
                @api = Spire::API.new(url)
         | 
| 15 15 | 
             
                @url = url
         | 
| 16 16 | 
             
                @channel_error_counts = {}
         | 
| 17 | 
            +
                @application_error_counts = {}
         | 
| 17 18 | 
             
                @subscription_error_counts = {}
         | 
| 19 | 
            +
                @notification_error_counts = {}
         | 
| 18 20 | 
             
                discover
         | 
| 19 21 | 
             
              end
         | 
| 20 22 |  | 
| @@ -143,6 +145,68 @@ class Spire | |
| 143 145 | 
             
            	def subscriptions
         | 
| 144 146 | 
             
            		@session.subscriptions.values
         | 
| 145 147 | 
             
            	end
         | 
| 148 | 
            +
            	
         | 
| 149 | 
            +
             | 
| 150 | 
            +
              def notification(name, mode="development")
         | 
| 151 | 
            +
                Notification.new(
         | 
| 152 | 
            +
                  @session.notifications[name] || find_or_create_notification(name, ssl_cert)
         | 
| 153 | 
            +
                )
         | 
| 154 | 
            +
              end
         | 
| 155 | 
            +
              
         | 
| 156 | 
            +
              def find_or_create_notification(notification_name, mode)
         | 
| 157 | 
            +
              	@notification_error_counts[notification_name] ||= 0
         | 
| 158 | 
            +
                begin
         | 
| 159 | 
            +
                  return @session.create_notification(
         | 
| 160 | 
            +
                      :name => notification_name,
         | 
| 161 | 
            +
                      :mode => mode
         | 
| 162 | 
            +
                    )
         | 
| 163 | 
            +
                rescue => error
         | 
| 164 | 
            +
                  if error.message =~ /409/
         | 
| 165 | 
            +
                  
         | 
| 166 | 
            +
                    if notification = @session.notification![notification_name]
         | 
| 167 | 
            +
                      return notification
         | 
| 168 | 
            +
                    else
         | 
| 169 | 
            +
                      @notification_error_counts[notification_name] += 1
         | 
| 170 | 
            +
                      retry unless @notification_error_counts >= RETRY_CREATION_LIMIT
         | 
| 171 | 
            +
                    end
         | 
| 172 | 
            +
                  
         | 
| 173 | 
            +
                  else
         | 
| 174 | 
            +
                    raise error
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
              end
         | 
| 178 | 
            +
              
         | 
| 179 | 
            +
             | 
| 180 | 
            +
              def applications
         | 
| 181 | 
            +
                @session.applications
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
              def applications!
         | 
| 185 | 
            +
                @session.applications!
         | 
| 186 | 
            +
              end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
              # Creates an application on spire.  Returns an Application object.  Will retry on a 409.
         | 
| 189 | 
            +
              # @param [String] Name of the application to find/create
         | 
| 190 | 
            +
              def find_or_create_application(name)
         | 
| 191 | 
            +
                @application_error_counts[name] ||= 0
         | 
| 192 | 
            +
                begin
         | 
| 193 | 
            +
                  return @session.create_application(name)
         | 
| 194 | 
            +
                # TODO custom error class for Conflict, which we can
         | 
| 195 | 
            +
                # then match here, instead of testing for error message
         | 
| 196 | 
            +
                rescue => error
         | 
| 197 | 
            +
                  if error.message =~ /409/
         | 
| 198 | 
            +
                    # Dear retry, I love you.  Affectionately, Matthew.
         | 
| 199 | 
            +
                    if application = @session.applications![name]
         | 
| 200 | 
            +
                      return application
         | 
| 201 | 
            +
                    else
         | 
| 202 | 
            +
                      @application_error_counts[name] += 1
         | 
| 203 | 
            +
                      retry unless @application_error_counts[name] >= RETRY_CREATION_LIMIT
         | 
| 204 | 
            +
                    end
         | 
| 205 | 
            +
                  else
         | 
| 206 | 
            +
                    raise error
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
                end
         | 
| 209 | 
            +
              end
         | 
| 146 210 |  | 
| 147 211 | 
             
              # Returns a billing object than contains a list of all the plans available
         | 
| 148 212 | 
             
              # @param [String] info optional object description
         | 
| @@ -210,7 +274,7 @@ class Spire | |
| 210 274 | 
             
                # misnamed method, here for backompat.  Should be something like #get_messages,
         | 
| 211 275 | 
             
                # because it only makes one request.
         | 
| 212 276 | 
             
                def listen(options={})
         | 
| 213 | 
            -
                  long_poll(options) | 
| 277 | 
            +
                  long_poll(options)
         | 
| 214 278 | 
             
                end
         | 
| 215 279 |  | 
| 216 280 | 
             
                # wraps the underlying Subscription#add_listener to
         | 
| @@ -221,7 +285,7 @@ class Spire | |
| 221 285 | 
             
                  listener_name ||= generate_listener_name
         | 
| 222 286 | 
             
                  listener = wrap_listener(&block)
         | 
| 223 287 | 
             
                  listeners[listener_name] = listener
         | 
| 224 | 
            -
                  __getobj__.add_listener(&listener)
         | 
| 288 | 
            +
                  __getobj__.add_listener("message", &listener)
         | 
| 225 289 | 
             
                end
         | 
| 226 290 |  | 
| 227 291 | 
             
                def remove_listener(arg)
         | 
| @@ -233,7 +297,7 @@ class Spire | |
| 233 297 | 
             
                  end
         | 
| 234 298 |  | 
| 235 299 | 
             
                  if listener
         | 
| 236 | 
            -
                    __getobj__.listeners.delete(listener)
         | 
| 300 | 
            +
                    __getobj__.listeners["message"].delete(listener)
         | 
| 237 301 | 
             
                  end
         | 
| 238 302 | 
             
                end
         | 
| 239 303 |  | 
| @@ -273,4 +337,16 @@ class Spire | |
| 273 337 |  | 
| 274 338 | 
             
              end
         | 
| 275 339 |  | 
| 340 | 
            +
              class Notification < SimpleDelegator
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                # this is required because Delegator's method_missing relies
         | 
| 343 | 
            +
                # on the object having a method defined, but in this case
         | 
| 344 | 
            +
                # the API::Subscription is also using method_missing
         | 
| 345 | 
            +
                def name
         | 
| 346 | 
            +
                  __getobj__.name
         | 
| 347 | 
            +
                end
         | 
| 348 | 
            +
                
         | 
| 349 | 
            +
                
         | 
| 350 | 
            +
              end
         | 
| 351 | 
            +
              
         | 
| 276 352 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,12 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: spire_io
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 11
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 1
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
               | 
| 10 | 
            -
              version: 1.0.0
         | 
| 8 | 
            +
              - 2
         | 
| 9 | 
            +
              version: "1.2"
         | 
| 11 10 | 
             
            platform: ruby
         | 
| 12 11 | 
             
            authors: 
         | 
| 13 12 | 
             
            - Dan Yoder
         | 
| @@ -17,7 +16,7 @@ autorequire: | |
| 17 16 | 
             
            bindir: bin
         | 
| 18 17 | 
             
            cert_chain: []
         | 
| 19 18 |  | 
| 20 | 
            -
            date: 2012- | 
| 19 | 
            +
            date: 2012-05-07 00:00:00 -07:00
         | 
| 21 20 | 
             
            default_executable: 
         | 
| 22 21 | 
             
            dependencies: 
         | 
| 23 22 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -142,8 +141,11 @@ extra_rdoc_files: [] | |
| 142 141 |  | 
| 143 142 | 
             
            files: 
         | 
| 144 143 | 
             
            - lib/spire/api/account.rb
         | 
| 144 | 
            +
            - lib/spire/api/application.rb
         | 
| 145 145 | 
             
            - lib/spire/api/channel.rb
         | 
| 146 | 
            -
            - lib/spire/api/ | 
| 146 | 
            +
            - lib/spire/api/event.rb
         | 
| 147 | 
            +
            - lib/spire/api/member.rb
         | 
| 148 | 
            +
            - lib/spire/api/notification.rb
         | 
| 147 149 | 
             
            - lib/spire/api/requestable.rb
         | 
| 148 150 | 
             
            - lib/spire/api/resource.rb
         | 
| 149 151 | 
             
            - lib/spire/api/session.rb
         |