File: lingr.rb

package info (click to toggle)
ruby-net-irc 0.0.9-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 408 kB
  • sloc: ruby: 7,268; makefile: 3
file content (327 lines) | stat: -rw-r--r-- 9,815 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# Ruby client for the Lingr[http://www.lingr.com] API.  For more details and tutorials, see the 
# {Lingr API Reference}[http://wiki.lingr.com/dev/show/API+Reference] pages on the {Lingr Developer Wiki}[http://wiki.lingr.com].
#
# All methods return a hash with two keys:
# * :succeeded - <tt>true</tt> if the method succeeded, <tt>false</tt> otherwise
# * :response - a Hash version of the response document received from the server
#
# = api_client.rb
#
# Lingr API client
#
#
# Original written by Lingr.
# Modified by cho45 <cho45@lowreal.net>
#  * Use json gem instead of gsub/eval.
#  * Raise APIError when api fails.
#  * Rename class name to Lingr::Client.

$KCODE = 'u' # used by json
require "rubygems"
require "net/http"
require "json"
require "uri"
require "timeout"

module Lingr
	class Client
		class ClientError < StandardError; end
		class APIError < ClientError
			def initialize(error)
				@error = error || {
					"message" => "socket error",
					"code"    => 0,
				}
				super(@error["message"])
			end

			def code
				@error["code"]
			end
		end

		attr_accessor :api_key
		# 0 = quiet, 1 = some debug info, 2 = more debug info
		attr_accessor :verbosity
		attr_accessor :session
		attr_accessor :timeout

		def initialize(api_key, verbosity=0, hostname='www.lingr.com')
			@api_key   = api_key
			@host      = hostname
			@verbosity = verbosity
			@timeout   = 60
		end

		# Create a new API session
		#
		def create_session(client_type='automaton')
			if @session
				@error_info = nil
				raise ClientError, "already in a session"
			end

			ret = do_api :post, 'session/create', { :api_key => @api_key, :client_type => client_type }, false
			@session = ret["session"]
			ret
		end

		# Verify a session id.  If no session id is passed, verifies the current session id for this ApiClient
		#
		def verify_session(session_id=nil)
			do_api :get, 'session/verify', { :session => session_id || @session }, false
		end

		# Destroy the current API session
		# 
		def destroy_session
			ret = do_api :post, 'session/destroy', { :session => @session }
			@session = nil
			ret
		end

		# Get a list of the currently hot rooms
		#
		def get_hot_rooms(count=nil)
			do_api :get, 'explore/get_hot_rooms', { :api_key => @api_key }.merge(count ? { :count => count} : {}), false
		end

		# Get a list of the newest rooms
		#
		def get_new_rooms(count=nil)
			do_api :get, 'explore/get_new_rooms', { :api_key => @api_key }.merge(count ? { :count => count} : {}), false
		end

		# Get a list of the currently hot tags
		#
		def get_hot_tags(count=nil)
			do_api :get, 'explore/get_hot_tags', { :api_key => @api_key }.merge(count ? { :count => count} : {}), false
		end

		# Get a list of all tags 
		#
		def get_all_tags(count=nil)
			do_api :get, 'explore/get_all_tags', { :api_key => @api_key }.merge(count ? { :count => count} : {}), false
		end

		# Search room name, description, and tags for keywords.  Keywords can be a String or an Array.
		#
		def search(keywords)
			do_api :get, 'explore/search', { :api_key => @api_key, :q => keywords.is_a?(Array) ? keywords.join(',') : keywords }, false
		end

		# Search room tags. Tagnames can be a String or an Array.
		#
		def search_tags(tagnames)
			do_api :get, 'explore/search_tags', { :api_key => @api_key, :q => tagnames.is_a?(Array) ? tagnames.join(',') : tagnames }, false
		end

		# Search archives. If room_id is non-nil, the search is limited to the archives of that room.
		#
		def search_archives(query, room_id=nil)
			params = { :api_key => @api_key, :q => query }
			params.merge!({ :id => room_id }) if room_id
			do_api :get, 'explore/search_archives', params, false
		end

		# Authenticate a user within the current API session
		#
		def login(email, password)
			do_api :post, 'auth/login', { :session => @session, :email => email, :password => password }
		end

		# Log out the currently-authenticated user in the session, if any
		#
		def logout
			do_api :post, 'auth/logout', { :session => @session }
		end

		# Get information about the currently-authenticated user
		#
		def get_user_info
			do_api :get, 'user/get_info', { :session => @session }
		end

		# Start observing the currently-authenticated user
		#
		def start_observing_user
			do_api :post, 'user/start_observing', { :session => @session }
		end

		# Observe the currently-authenticated user, watching for profile changes
		#
		def observe_user(ticket, counter)
			do_api :get, 'user/observe', { :session => @session, :ticket => ticket, :counter => counter }
		end

		# Stop observing the currently-authenticated user
		#
		def stop_observing_user(ticket)
			do_api :post, 'user/stop_observing', { :session => @session, :ticket =>ticket }
		end

		# Get information about a chatroom, including room description, current occupants, recent messages, etc.
		# 
		def get_room_info(room_id, counter=nil, password=nil)
			params = { :api_key => @api_key, :id => room_id }
			params.merge!({ :counter => counter }) if counter
			params.merge!({ :password => password }) if password
			do_api :get, 'room/get_info', params, false
		end

		# Create a chatroom
		#
		# options is a Hash containing any of the parameters allowed for room.create.  If the :image key is present 
		# in options, its value must be a hash with the keys :filename, :mime_type, and :io
		#
		def create_room(options)
			do_api :post, 'room/create', options.merge({ :session => @session })
		end

		# Change the settings for a chatroom
		#
		# options is a Hash containing any of the parameters allowed for room.create.  If the :image key is present 
		# in options, its value must be a hash with the keys :filename, :mime_type, and :io.  To change the id for 
		# a room, use the key :new_id
		#
		def change_settings(room_id, options)
			do_api :post, 'room/change_settings', options.merge({ :session => @session })
		end

		# Delete a chatroom
		#
		def delete_room(room_id)
			do_api :post, 'room/delete', { :id => room_id, :session => @session }
		end

		# Enter a chatroom
		#
		def enter_room(room_id, nickname=nil, password=nil, idempotent=false)
			params = { :session => @session, :id => room_id }
			params.merge!({ :nickname => nickname }) if nickname
			params.merge!({ :password => password }) if password
			params.merge!({ :idempotent => 'true' }) if idempotent
			do_api :post, 'room/enter', params
		end

		# Poll for messages in a chatroom
		#
		def get_messages(ticket, counter, user_messages_only=false)
			do_api :get, 'room/get_messages', { :session => @session, :ticket => ticket, :counter => counter, :user_messages_only => user_messages_only }
		end

		# Observe a chatroom, waiting for events to occur in the room
		#
		def observe_room(ticket, counter)
			do_api :get, 'room/observe', { :session => @session, :ticket => ticket, :counter => counter }
		end

		# Set your nickname in a chatroom
		#
		def set_nickname(ticket, nickname)
			do_api :post, 'room/set_nickname', { :session => @session, :ticket => ticket, :nickname => nickname }
		end

		# Say something in a chatroom.  If target_occupant_id is not nil, a private message
		# is sent to the indicated occupant.
		#
		def say(ticket, msg, target_occupant_id = nil)
			params = { :session => @session, :ticket => ticket, :message => msg }
			params.merge!({ :occupant_id => target_occupant_id}) if target_occupant_id
			do_api :post, 'room/say', params
		end

		# Exit a chatroom
		#
		def exit_room(ticket)
			do_api :post, 'room/exit', { :session => @session, :ticket => ticket }
		end

		private

		def do_api(method, path, parameters, require_session=true)
			if require_session and !@session
				raise ClientError, "not in a session"
			end

			response = Timeout.timeout(@timeout) {
				JSON.parse(self.send(method, url_for(path), parameters.merge({ :format => 'json' })))
			}

			unless success?(response)
				raise APIError, response["error"]
			end

			response
		end

		def url_for(method)
			"http://#{@host}/#{@@PATH_BASE}#{method}"
		end

		def get(url, params)
			uri = URI.parse(url)
			path = uri.path
			q = params.inject("?") {|s, p| s << "#{p[0].to_s}=#{URI.encode(p[1].to_s, /./)}&"}.chop
			path << q if q.length > 0

			Net::HTTP.start(uri.host, uri.port) do |http|
				http.read_timeout = @timeout
				req = Net::HTTP::Get.new(path)
				req.basic_auth(uri.user, uri.password) if uri.user
				parse_result http.request(req)
			end
		end

		def post(url, params)
			if !params.find {|p| p[1].is_a?(Hash)}
				params = params.inject({}){|hash,(k,v)| hash[k.to_s] = v; hash}
				parse_result Net::HTTP.post_form(URI.parse(url), params)
			else
				boundary = 'lingr-api-client' + (0x1000000 + rand(0x1000000).to_s(16))

				query = params.collect { |p|
					ret = ["--#{boundary}"]

					if p[1].is_a?(Hash)
						ret << "Content-Disposition: form-data; name=\"#{URI.encode(p[0].to_s)}\"; filename=\"#{p[1][:filename]}\""
						ret << "Content-Transfer-Encoding: binary"
						ret << "Content-Type: #{p[1][:mime_type]}"
						ret << ""
						ret << p[1][:io].read
					else
						ret << "Content-Disposition: form-data; name=\"#{URI.encode(p[0].to_s)}\""
						ret << ""
						ret << p[1]
					end

					ret.join("\r\n")
				}.join('') + "--#{boundary}--\r\n"

				uri = URI.parse(url)
				Net::HTTP.start(uri.host, uri.port) do |http|
					http.read_timeout = @timeout
					parse_result http.post2(uri.path, query, "Content-Type" => "multipart/form-data; boundary=#{boundary}")
				end
			end
		end

		def parse_result(result)
			return nil if !result || result.code != '200' || (!result['Content-Type'] || result['Content-Type'].index('text/javascript') != 0)
#			puts
#			puts
#			puts result.body
#			puts
#			puts
			result.body
		end

		def success?(response)
			return false if !response
			response["status"] and response["status"] == 'ok'
		end


		@@PATH_BASE = 'api/'
	end
end