em-instagram 0.1
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/README.md +0 -0
- data/em-instagram.gemspec +30 -0
- data/lib/em-instagram.rb +74 -0
- data/lib/em-instagram/api/media.rb +34 -0
- data/lib/em-instagram/api/subscriptions.rb +37 -0
- data/lib/em-instagram/request.rb +22 -0
- data/lib/em-instagram/server.rb +39 -0
- data/lib/em-instagram/version.rb +5 -0
- metadata +118 -0
data/README.md
ADDED
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/em-instagram/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "em-instagram"
|
6
|
+
s.version = EventMachine::Instagram::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.date = '2013-04-03'
|
9
|
+
s.authors = ["Joe Pym"]
|
10
|
+
s.email = ["joe@joepym.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{}
|
13
|
+
s.description = %q{}
|
14
|
+
|
15
|
+
s.files = Dir["{lib,spec}/**/*", "[A-Z]*", "init.rb"]
|
16
|
+
s.require_path = "lib"
|
17
|
+
|
18
|
+
s.required_rubygems_version = ">= 1.3.4"
|
19
|
+
|
20
|
+
s.add_dependency "eventmachine"
|
21
|
+
s.add_dependency 'eventmachine_httpserver'
|
22
|
+
s.add_dependency 'em-http-request'
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec", '~> 2.5.0'
|
25
|
+
|
26
|
+
s.files = `git ls-files`.split("\n")
|
27
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
end
|
data/lib/em-instagram.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path('../em-instagram/request', __FILE__)
|
2
|
+
require File.expand_path('../em-instagram/server', __FILE__)
|
3
|
+
require File.expand_path('../em-instagram/api/subscriptions', __FILE__)
|
4
|
+
require File.expand_path('../em-instagram/api/media', __FILE__)
|
5
|
+
|
6
|
+
module EventMachine
|
7
|
+
class Instagram
|
8
|
+
include Subscriptions
|
9
|
+
include Media
|
10
|
+
|
11
|
+
BASE_URI = 'https://api.instagram.com'
|
12
|
+
PORT = 443
|
13
|
+
|
14
|
+
attr_reader :default_params, :host, :port, :server, :logger, :subscription_queue, :update_callback
|
15
|
+
|
16
|
+
def initialize(options = nil)
|
17
|
+
@host, @port, @server = [options[:host], options[:port], options[:server]]
|
18
|
+
@subscription_queue = EventMachine::Queue.new
|
19
|
+
@update_queue = EventMachine::Queue.new
|
20
|
+
@logger = options[:logger]
|
21
|
+
@default_params = {:client_id => options[:client_id], :client_secret => options[:client_secret]}
|
22
|
+
update
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch(update)
|
27
|
+
case update['object']
|
28
|
+
when 'geography'
|
29
|
+
fetch_geography update['object_id']
|
30
|
+
when 'tag'
|
31
|
+
fetch_tag update['object_id']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def stream(&block)
|
36
|
+
@streams ||= []
|
37
|
+
@streams << block
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_update(&block)
|
41
|
+
@update_callback = block
|
42
|
+
end
|
43
|
+
|
44
|
+
def update(data = nil)
|
45
|
+
@update_queue << data if data
|
46
|
+
@update_queue.pop do |item|
|
47
|
+
if @update_callback
|
48
|
+
@update_callback.call(item)
|
49
|
+
else
|
50
|
+
@logger.debug(item)
|
51
|
+
end
|
52
|
+
EventMachine::next_tick { update }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def receive_notification(data)
|
57
|
+
@streams.each { |stream| stream.call(data) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def request(method, path, options = {})
|
61
|
+
url = URI.join(BASE_URI, path).to_s
|
62
|
+
Request.new EventMachine::HttpRequest.new(url).send(method, options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def start_server(&block)
|
66
|
+
@host ||= '0.0.0.0'
|
67
|
+
@port ||= 8080
|
68
|
+
@server ||= Server
|
69
|
+
EventMachine.start_server(host, port, server) do |connection|
|
70
|
+
connection.subscriber = self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Instagram
|
3
|
+
module Media
|
4
|
+
def media(id)
|
5
|
+
request :get, "/v1/media/#{id}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def media_by_geography(object_id, params = {})
|
9
|
+
request :get, "/v1/geographies/#{object_id}/media/recent", :query => default_params.merge(params)
|
10
|
+
end
|
11
|
+
|
12
|
+
def media_by_tag(object_id, params = {})
|
13
|
+
request :get, "/v1/tags/#{object_id}/media/recent", :query => default_params.merge(params)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def fetch_geography(object_id)
|
18
|
+
@logger.debug "fetching #{object_id} updates..."
|
19
|
+
# TODO: figure out if min_id parameter would be appropriate for reading recent tagged media
|
20
|
+
request = media_by_geography(object_id)
|
21
|
+
request.errback { |error| @logger.debug "fetch error: #{error}"; EventMachine::add_timer(15) { fetch_geography object_id } }
|
22
|
+
request.callback { |media| @update_queue.push(*media) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_tag(object_id)
|
26
|
+
@logger.debug "fetching #{object_id} updates..."
|
27
|
+
# TODO: figure out if max_id or min_id parameter would be appropriate for reading recent tagged media
|
28
|
+
request = media_by_tag(object_id)
|
29
|
+
request.errback { |error| @logger.debug "fetch error: #{error}"; EventMachine::add_timer(15) { fetch_tag object_id } }
|
30
|
+
request.callback { |media| @update_queue.push(*media) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Instagram
|
3
|
+
module Subscriptions
|
4
|
+
def send_subscription(params = {})
|
5
|
+
request :post, "/v1/subscriptions", :body => default_params.merge(params)
|
6
|
+
end
|
7
|
+
|
8
|
+
def subscribe_to(options)
|
9
|
+
options = options.merge(:aspect => 'media', :callback_url => CALLBACK_URL)
|
10
|
+
request = send_subscription options.merge(:aspect => 'media', :callback_url => CALLBACK_URL)
|
11
|
+
request.errback { |error| @logger.debug "subscription error: #{error}"; EventMachine::add_timer(15) { subscribe_to options } }
|
12
|
+
request.callback { |response| @logger.debug "next subscription..."; EventMachine::next_tick { subscribe_next } }
|
13
|
+
end
|
14
|
+
|
15
|
+
def subscriptions(params = {})
|
16
|
+
request :get, "/v1/subscriptions", :query => default_params.merge(params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def subscribe(*args)
|
20
|
+
@subscription_queue.push(*args)
|
21
|
+
subscribe_next
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsubscribe(params = {})
|
25
|
+
request :delete, "/v1/subscriptions", :query => default_params.merge(params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def subscribe_next
|
29
|
+
if @subscription_queue.empty?
|
30
|
+
@logger.debug "subscribed."
|
31
|
+
else
|
32
|
+
@subscription_queue.pop { |hash| send_subscription(hash); subscribe_next }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Instagram
|
3
|
+
class Request
|
4
|
+
include Deferrable
|
5
|
+
|
6
|
+
def initialize(connection)
|
7
|
+
connection.errback { |response| fail response.error }
|
8
|
+
connection.callback { |response| process_instagram_response response }
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
def process_instagram_response(response)
|
13
|
+
case response.response_header.status
|
14
|
+
when 200
|
15
|
+
succeed JSON.parse(response.response)['data']
|
16
|
+
else
|
17
|
+
fail JSON.parse(response.response)['meta']['error_message']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class Instagram
|
3
|
+
module Server
|
4
|
+
include EventMachine::HttpServer
|
5
|
+
|
6
|
+
attr_accessor :subscriber
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@updates = EventMachine::Queue.new
|
10
|
+
process_update
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_http_request
|
15
|
+
response = EventMachine::DelegatedHttpResponse.new(self)
|
16
|
+
case @http_request_method
|
17
|
+
when 'GET'
|
18
|
+
params = CGI::parse(@http_query_string)
|
19
|
+
response.status = 200
|
20
|
+
response.content = params['hub.challenge']
|
21
|
+
when 'POST'
|
22
|
+
@updates.push(*JSON.load(@http_post_content))
|
23
|
+
response.status = 202
|
24
|
+
response.content = 'Accepted'
|
25
|
+
else
|
26
|
+
response.status = 405
|
27
|
+
response.content = 'Method Not Allowed'
|
28
|
+
end
|
29
|
+
|
30
|
+
response.send_response
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_update
|
34
|
+
@updates.pop { |data| subscriber.receive_notification data; EventMachine::next_tick { process_update } }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-instagram
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joe Pym
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: eventmachine_httpserver
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: em-http-request
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.5.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.5.0
|
78
|
+
description: ''
|
79
|
+
email:
|
80
|
+
- joe@joepym.com
|
81
|
+
executables: []
|
82
|
+
extensions: []
|
83
|
+
extra_rdoc_files: []
|
84
|
+
files:
|
85
|
+
- README.md
|
86
|
+
- em-instagram.gemspec
|
87
|
+
- lib/em-instagram.rb
|
88
|
+
- lib/em-instagram/api/media.rb
|
89
|
+
- lib/em-instagram/api/subscriptions.rb
|
90
|
+
- lib/em-instagram/request.rb
|
91
|
+
- lib/em-instagram/server.rb
|
92
|
+
- lib/em-instagram/version.rb
|
93
|
+
homepage: ''
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.3.4
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.23
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: ''
|
117
|
+
test_files: []
|
118
|
+
has_rdoc:
|