td 0.7.0
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/ChangeLog +16 -0
- data/README.rdoc +18 -0
- data/bin/td +6 -0
- data/lib/td/api.rb +305 -0
- data/lib/td/api_iface.rb +323 -0
- data/lib/td/command/account.rb +84 -0
- data/lib/td/command/common.rb +121 -0
- data/lib/td/command/database.rb +82 -0
- data/lib/td/command/import.rb +286 -0
- data/lib/td/command/list.rb +115 -0
- data/lib/td/command/query.rb +167 -0
- data/lib/td/command/server.rb +15 -0
- data/lib/td/command/table.rb +101 -0
- data/lib/td/command/td.rb +82 -0
- data/lib/td/config.rb +79 -0
- data/lib/td/error.rb +29 -0
- data/lib/td/version.rb +5 -0
- metadata +131 -0
data/ChangeLog
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
== 2011-08-06 version 0.7.0
|
3
|
+
|
4
|
+
* import subcommand accepts UNIX time integer value on --json and --msgpack format
|
5
|
+
* Renamed command name (trd -> td)
|
6
|
+
|
7
|
+
== 2011-07-18 version 0.6.3
|
8
|
+
|
9
|
+
* show-jobs: shows elapsed time
|
10
|
+
* query: updated behavior of the -w option for new api
|
11
|
+
* import: supported --json and --msgpack format
|
12
|
+
* Added 'version' command
|
13
|
+
|
14
|
+
|
15
|
+
== 2011-06-27 version 0.6.2
|
16
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= Treasure Data command line tool
|
2
|
+
|
3
|
+
= Getting Started
|
4
|
+
|
5
|
+
Install td command as a gem.
|
6
|
+
|
7
|
+
> gem install td
|
8
|
+
|
9
|
+
See help message for details.
|
10
|
+
|
11
|
+
> td
|
12
|
+
|
13
|
+
|
14
|
+
== Copyright
|
15
|
+
|
16
|
+
Copyright:: Copyright (c) 2011 Treasure Data Inc.
|
17
|
+
License:: Apache License, Version 2.0
|
18
|
+
|
data/bin/td
ADDED
data/lib/td/api.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'td/api_iface'
|
3
|
+
require 'td/error'
|
4
|
+
|
5
|
+
module TD
|
6
|
+
|
7
|
+
class API
|
8
|
+
def self.authenticate(user, password)
|
9
|
+
iface = APIInterface.new(nil)
|
10
|
+
apikey = iface.authenticate(user, password)
|
11
|
+
new(apikey)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.server_status
|
15
|
+
iface = APIInterface.new(nil)
|
16
|
+
iface.server_status
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(apikey)
|
20
|
+
@iface = APIInterface.new(apikey)
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :iface
|
24
|
+
|
25
|
+
def apikey
|
26
|
+
@iface.apikey
|
27
|
+
end
|
28
|
+
|
29
|
+
def server_status
|
30
|
+
@iface.server_status
|
31
|
+
end
|
32
|
+
|
33
|
+
# => true
|
34
|
+
def create_database(db_name)
|
35
|
+
@iface.create_database(db_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
# => true
|
39
|
+
def delete_database(db_name)
|
40
|
+
@iface.delete_database(db_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
# => [Database]
|
44
|
+
def databases
|
45
|
+
names = @iface.list_databases
|
46
|
+
names.map {|db_name|
|
47
|
+
Database.new(self, db_name)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
# => Database
|
52
|
+
def database(db_name)
|
53
|
+
names = @iface.list_databases
|
54
|
+
names.each {|n|
|
55
|
+
if n == db_name
|
56
|
+
return Database.new(self, db_name)
|
57
|
+
end
|
58
|
+
}
|
59
|
+
raise NotFoundError, "Database '#{db_name}' does not exist"
|
60
|
+
end
|
61
|
+
|
62
|
+
# => true
|
63
|
+
def create_table(db_name, table_name, type)
|
64
|
+
@iface.create_table(db_name, table_name, type)
|
65
|
+
end
|
66
|
+
|
67
|
+
# => true
|
68
|
+
def create_log_table(db_name, table_name)
|
69
|
+
create_table(db_name, table_name, :log)
|
70
|
+
end
|
71
|
+
|
72
|
+
# => true
|
73
|
+
def create_item_table(db_name, table_name)
|
74
|
+
create_table(db_name, table_name, :item)
|
75
|
+
end
|
76
|
+
|
77
|
+
# => type:Symbol
|
78
|
+
def delete_table(db_name, table_name)
|
79
|
+
@iface.delete_table(db_name, table_name)
|
80
|
+
end
|
81
|
+
|
82
|
+
# => [Table]
|
83
|
+
def tables(db_name)
|
84
|
+
m = @iface.list_tables(db_name)
|
85
|
+
m.map {|table_name,(type,count)|
|
86
|
+
Table.new(self, db_name, table_name, type, count)
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
# => Table
|
91
|
+
def table(db_name, table_name)
|
92
|
+
m = @iface.list_tables(db_name)
|
93
|
+
m.each_pair {|name,(type,count)|
|
94
|
+
if name == table_name
|
95
|
+
return Table.new(self, db_name, name, type, count)
|
96
|
+
end
|
97
|
+
}
|
98
|
+
raise NotFoundError, "Table '#{db_name}.#{table_name}' does not exist"
|
99
|
+
end
|
100
|
+
|
101
|
+
# => Job
|
102
|
+
def query(q, db_name=nil)
|
103
|
+
job_id = @iface.hive_query(q, db_name)
|
104
|
+
Job.new(self, job_id, :hive, q) # TODO url
|
105
|
+
end
|
106
|
+
|
107
|
+
# => [Job=]
|
108
|
+
def jobs(from=nil, to=nil)
|
109
|
+
js = @iface.list_jobs(from, to)
|
110
|
+
js.map {|job_id,type,status,query,start_at,end_at|
|
111
|
+
Job.new(self, job_id, type, query, status, nil, nil, nil, start_at, end_at)
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
# => Job
|
116
|
+
def job(job_id)
|
117
|
+
job_id = job_id.to_s
|
118
|
+
type, query, status, result, url, debug, start_at, end_at = @iface.show_job(job_id)
|
119
|
+
Job.new(self, job_id, type, query, status, url, result, debug, start_at, end_at)
|
120
|
+
end
|
121
|
+
|
122
|
+
# => type:Symbol, result:String, url:String
|
123
|
+
def job_status(job_id)
|
124
|
+
type, query, status, result, url, debug, start_at, end_at = @iface.show_job(job_id)
|
125
|
+
return query, status, result, url, debug, start_at, end_at
|
126
|
+
end
|
127
|
+
|
128
|
+
# => time:Flaot
|
129
|
+
def import(db_name, table_name, format, stream, stream_size=stream.lstat.size)
|
130
|
+
@iface.import(db_name, table_name, format, stream, stream_size)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
module TD
|
138
|
+
|
139
|
+
class APIObject
|
140
|
+
def initialize(api)
|
141
|
+
@api = api
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class Database < APIObject
|
146
|
+
def initialize(api, db_name, tables=nil)
|
147
|
+
super(api)
|
148
|
+
@db_name = db_name
|
149
|
+
@tables = tables
|
150
|
+
end
|
151
|
+
|
152
|
+
def name
|
153
|
+
@db_name
|
154
|
+
end
|
155
|
+
|
156
|
+
def tables
|
157
|
+
update_tables! unless @tables
|
158
|
+
@tables
|
159
|
+
end
|
160
|
+
|
161
|
+
def create_table(name, type)
|
162
|
+
@api.create_table(@db_name, name, type)
|
163
|
+
end
|
164
|
+
|
165
|
+
def create_log_table(name)
|
166
|
+
create_table(name, :log)
|
167
|
+
end
|
168
|
+
|
169
|
+
def create_item_table(name)
|
170
|
+
create_table(name, :item)
|
171
|
+
end
|
172
|
+
|
173
|
+
def table(table_name)
|
174
|
+
@api.table(@db_name, table_name)
|
175
|
+
end
|
176
|
+
|
177
|
+
def delete
|
178
|
+
@api.delete_database(@db_name)
|
179
|
+
end
|
180
|
+
|
181
|
+
def update_tables!
|
182
|
+
@tables = @api.tables(@db_name)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class Table < APIObject
|
187
|
+
def initialize(api, db_name, table_name, type, count)
|
188
|
+
super(api)
|
189
|
+
@db_name = db_name
|
190
|
+
@table_name = table_name
|
191
|
+
@type = type
|
192
|
+
@count = count
|
193
|
+
end
|
194
|
+
|
195
|
+
attr_reader :type, :count
|
196
|
+
|
197
|
+
def database_name
|
198
|
+
@db_name
|
199
|
+
end
|
200
|
+
|
201
|
+
def database
|
202
|
+
@api.database(@db_name)
|
203
|
+
end
|
204
|
+
|
205
|
+
def name
|
206
|
+
@table_name
|
207
|
+
end
|
208
|
+
|
209
|
+
def identifier
|
210
|
+
"#{@db_name}.#{@table_name}"
|
211
|
+
end
|
212
|
+
|
213
|
+
def delete
|
214
|
+
@api.delete_table(@db_name, @table_name)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class Job < APIObject
|
219
|
+
def initialize(api, job_id, type, query, status=nil, url=nil, result=nil, debug=nil, start_at=nil, end_at=nil)
|
220
|
+
super(api)
|
221
|
+
@job_id = job_id
|
222
|
+
@type = type
|
223
|
+
@url = url
|
224
|
+
@query = query
|
225
|
+
@status = status
|
226
|
+
@result = result
|
227
|
+
@debug = debug
|
228
|
+
@start_at = start_at
|
229
|
+
@end_at = end_at
|
230
|
+
end
|
231
|
+
|
232
|
+
attr_reader :job_id, :type
|
233
|
+
|
234
|
+
def wait(timeout=nil)
|
235
|
+
# TODO
|
236
|
+
end
|
237
|
+
|
238
|
+
def query
|
239
|
+
update_status! unless @query
|
240
|
+
@query
|
241
|
+
end
|
242
|
+
|
243
|
+
def status
|
244
|
+
update_status! unless @status
|
245
|
+
@status
|
246
|
+
end
|
247
|
+
|
248
|
+
def url
|
249
|
+
update_status! unless @url
|
250
|
+
@url
|
251
|
+
end
|
252
|
+
|
253
|
+
def debug
|
254
|
+
update_status! unless @debug
|
255
|
+
@debug
|
256
|
+
end
|
257
|
+
|
258
|
+
def start_at
|
259
|
+
update_status! unless @start_at
|
260
|
+
@start_at && !@start_at.empty? ? Time.parse(@start_at) : nil
|
261
|
+
end
|
262
|
+
|
263
|
+
def end_at
|
264
|
+
update_status! unless @end_at
|
265
|
+
@end_at && !@end_at.empty? ? Time.parse(@end_at) : nil
|
266
|
+
end
|
267
|
+
|
268
|
+
def result
|
269
|
+
return nil unless finished?
|
270
|
+
update_status! unless @result
|
271
|
+
@result.split("\n").map {|line|
|
272
|
+
# TODO format of the result is TSV for now
|
273
|
+
line.split("\t")
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
def finished?
|
278
|
+
update_status! unless @status
|
279
|
+
if @status == "success" || @status == "error"
|
280
|
+
return true
|
281
|
+
else
|
282
|
+
return false
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def running?
|
287
|
+
!finished?
|
288
|
+
end
|
289
|
+
|
290
|
+
def update_status!
|
291
|
+
query, status, result, url, debug, start_at, end_at = @api.job_status(@job_id)
|
292
|
+
@query = query
|
293
|
+
@status = status
|
294
|
+
@result = result
|
295
|
+
@url = url
|
296
|
+
@debug = debug
|
297
|
+
@start_at = start_at
|
298
|
+
@end_at = end_at
|
299
|
+
self
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
end
|
305
|
+
|
data/lib/td/api_iface.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
|
2
|
+
module TD
|
3
|
+
|
4
|
+
|
5
|
+
class APIInterface
|
6
|
+
def initialize(apikey)
|
7
|
+
require 'json'
|
8
|
+
@apikey = apikey
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO error check & raise appropriate errors
|
12
|
+
|
13
|
+
attr_reader :apikey
|
14
|
+
|
15
|
+
####
|
16
|
+
## Database API
|
17
|
+
##
|
18
|
+
|
19
|
+
# => [name:String]
|
20
|
+
def list_databases
|
21
|
+
code, body, res = get("/v3/database/list")
|
22
|
+
if code != "200"
|
23
|
+
raise_error("List databases failed", res)
|
24
|
+
end
|
25
|
+
# TODO format check
|
26
|
+
js = JSON.load(body)
|
27
|
+
names = js["databases"].map {|dbinfo| dbinfo['name'] }
|
28
|
+
return names
|
29
|
+
end
|
30
|
+
|
31
|
+
# => true
|
32
|
+
def delete_database(db)
|
33
|
+
code, body, res = post("/v3/database/delete/#{e db}")
|
34
|
+
if code != "200"
|
35
|
+
raise_error("Delete database failed", res)
|
36
|
+
end
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
|
40
|
+
# => true
|
41
|
+
def create_database(db)
|
42
|
+
code, body, res = post("/v3/database/create/#{e db}")
|
43
|
+
if code != "200"
|
44
|
+
raise_error("Create database failed", res)
|
45
|
+
end
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
####
|
51
|
+
## Table API
|
52
|
+
##
|
53
|
+
|
54
|
+
# => {name:String => [type:Symbol, count:Integer]}
|
55
|
+
def list_tables(db)
|
56
|
+
code, body, res = get("/v3/table/list/#{e db}")
|
57
|
+
if code != "200"
|
58
|
+
raise_error("List tables failed", res)
|
59
|
+
end
|
60
|
+
# TODO format check
|
61
|
+
js = JSON.load(body)
|
62
|
+
result = {}
|
63
|
+
js["tables"].map {|m|
|
64
|
+
name = m['name']
|
65
|
+
type = (m['type'] || '?').to_sym
|
66
|
+
count = (m['count'] || 0).to_i # TODO?
|
67
|
+
result[name] = [type, count]
|
68
|
+
}
|
69
|
+
return result
|
70
|
+
end
|
71
|
+
|
72
|
+
# => true
|
73
|
+
def create_table(db, table, type)
|
74
|
+
code, body, res = post("/v3/table/create/#{e db}/#{e table}/#{type}")
|
75
|
+
if code != "200"
|
76
|
+
raise_error("Create #{type} table failed", res)
|
77
|
+
end
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
|
81
|
+
# => true
|
82
|
+
def create_log_table(db, table)
|
83
|
+
create_table(db, table, :log)
|
84
|
+
end
|
85
|
+
|
86
|
+
# => true
|
87
|
+
def create_item_table(db, table)
|
88
|
+
create_table(db, table, :item)
|
89
|
+
end
|
90
|
+
|
91
|
+
# => type:Symbol
|
92
|
+
def delete_table(db, table)
|
93
|
+
code, body, res = post("/v3/table/delete/#{e db}/#{e table}")
|
94
|
+
if code != "200"
|
95
|
+
raise_error("Drop table failed", res)
|
96
|
+
end
|
97
|
+
# TODO format check
|
98
|
+
js = JSON.load(body)
|
99
|
+
type = (js['type'] || '?').to_sym
|
100
|
+
return type
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
####
|
105
|
+
## Job API
|
106
|
+
##
|
107
|
+
|
108
|
+
# => [(jobId:String, type:Symbol, status:String, start_at:String, end_at:String)]
|
109
|
+
def list_jobs(from=0, to=nil)
|
110
|
+
params = {}
|
111
|
+
params['from'] = from.to_s if from
|
112
|
+
params['to'] = to.to_s if to
|
113
|
+
code, body, res = get("/v3/job/list", params)
|
114
|
+
if code != "200"
|
115
|
+
raise_error("List jobs failed", res)
|
116
|
+
end
|
117
|
+
# TODO format check
|
118
|
+
js = JSON.load(body)
|
119
|
+
result = []
|
120
|
+
js['jobs'].each {|m|
|
121
|
+
job_id = m['job_id']
|
122
|
+
type = (m['type'] || '?').to_sym
|
123
|
+
status = m['status']
|
124
|
+
query = m['query']
|
125
|
+
start_at = m['start_at']
|
126
|
+
end_at = m['end_at']
|
127
|
+
result << [job_id, type, status, query, start_at, end_at]
|
128
|
+
}
|
129
|
+
return result
|
130
|
+
end
|
131
|
+
|
132
|
+
# => (type:Symbol, status:String, result:String, url:String)
|
133
|
+
def show_job(job_id)
|
134
|
+
code, body, res = get("/v3/job/show/#{e job_id}")
|
135
|
+
if code != "200"
|
136
|
+
raise_error("Show job failed", res)
|
137
|
+
end
|
138
|
+
# TODO format check
|
139
|
+
js = JSON.load(body)
|
140
|
+
# TODO debug
|
141
|
+
type = (js['type'] || '?').to_sym # TODO
|
142
|
+
query = js['query']
|
143
|
+
status = js['status']
|
144
|
+
result = js['result']
|
145
|
+
debug = js['debug']
|
146
|
+
url = js['url']
|
147
|
+
start_at = js['start_at']
|
148
|
+
end_at = js['end_at']
|
149
|
+
return [type, query, status, result, url, debug, start_at, end_at]
|
150
|
+
end
|
151
|
+
|
152
|
+
# => jobId:String
|
153
|
+
def hive_query(q, db=nil)
|
154
|
+
code, body, res = post("/v3/job/issue/hive/#{e db}", {'query'=>q})
|
155
|
+
if code != "200"
|
156
|
+
raise_error("Query failed", res)
|
157
|
+
end
|
158
|
+
# TODO format check
|
159
|
+
js = JSON.load(body)
|
160
|
+
return js['job_id'].to_s
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
####
|
165
|
+
## Import API
|
166
|
+
##
|
167
|
+
|
168
|
+
# => time:Float
|
169
|
+
def import(db, table, format, stream, stream_size=stream.lstat.size)
|
170
|
+
code, body, res = put("/v3/table/import/#{e db}/#{e table}/#{format}", stream, stream_size)
|
171
|
+
if code[0] != ?2
|
172
|
+
raise_error("Import failed", res)
|
173
|
+
end
|
174
|
+
# TODO format check
|
175
|
+
js = JSON.load(body)
|
176
|
+
time = js['time'].to_f
|
177
|
+
return time
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
####
|
182
|
+
## User API
|
183
|
+
##
|
184
|
+
|
185
|
+
# apikey:String
|
186
|
+
def authenticate(user, password)
|
187
|
+
code, body, res = post("/v3/user/authenticate", {'user'=>user, 'password'=>password})
|
188
|
+
if code != "200"
|
189
|
+
raise_error("Authentication failed", res)
|
190
|
+
end
|
191
|
+
# TODO format check
|
192
|
+
js = JSON.load(body)
|
193
|
+
apikey = js['apikey']
|
194
|
+
return apikey
|
195
|
+
end
|
196
|
+
|
197
|
+
####
|
198
|
+
## Server Status API
|
199
|
+
##
|
200
|
+
|
201
|
+
# => status:String
|
202
|
+
def server_status
|
203
|
+
code, body, res = get('/v3/system/server_status')
|
204
|
+
if code != "200"
|
205
|
+
return "Server is down (#{code})"
|
206
|
+
end
|
207
|
+
# TODO format check
|
208
|
+
js = JSON.load(body)
|
209
|
+
status = js['status']
|
210
|
+
return status
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
HOST = ENV['TD_API_SERVER'] || 'api.treasure-data.com'
|
215
|
+
PORT = 80
|
216
|
+
USE_SSL = false
|
217
|
+
BASE_URL = ''
|
218
|
+
|
219
|
+
def get(url, params=nil)
|
220
|
+
http, header = new_http
|
221
|
+
|
222
|
+
path = BASE_URL + url
|
223
|
+
if params && !params.empty?
|
224
|
+
path << "?"+params.map {|k,v|
|
225
|
+
"#{k}=#{e v}"
|
226
|
+
}.join('&')
|
227
|
+
end
|
228
|
+
|
229
|
+
request = Net::HTTP::Get.new(path, header)
|
230
|
+
|
231
|
+
response = http.request(request)
|
232
|
+
return [response.code, response.body, response]
|
233
|
+
end
|
234
|
+
|
235
|
+
def post(url, params=nil)
|
236
|
+
http, header = new_http
|
237
|
+
|
238
|
+
path = BASE_URL + url
|
239
|
+
|
240
|
+
request = Net::HTTP::Post.new(path, header)
|
241
|
+
request.set_form_data(params) if params
|
242
|
+
|
243
|
+
response = http.request(request)
|
244
|
+
return [response.code, response.body, response]
|
245
|
+
end
|
246
|
+
|
247
|
+
def put(url, stream, stream_size)
|
248
|
+
http, header = new_http
|
249
|
+
|
250
|
+
path = BASE_URL + url
|
251
|
+
|
252
|
+
header['Content-Type'] = 'application/octet-stream'
|
253
|
+
header['Content-Length'] = stream_size.to_s
|
254
|
+
|
255
|
+
request = Net::HTTP::Put.new(url, header)
|
256
|
+
if request.respond_to?(:body_stream=)
|
257
|
+
request.body_stream = stream
|
258
|
+
else # Ruby 1.8
|
259
|
+
request.body = stream.read
|
260
|
+
end
|
261
|
+
|
262
|
+
response = http.request(request)
|
263
|
+
return [response.code, response.body, response]
|
264
|
+
end
|
265
|
+
|
266
|
+
def new_http
|
267
|
+
require 'net/http'
|
268
|
+
require 'time'
|
269
|
+
|
270
|
+
http = Net::HTTP.new(HOST, PORT)
|
271
|
+
if USE_SSL
|
272
|
+
http.use_ssl = true
|
273
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
274
|
+
store = OpenSSL::X509::Store.new
|
275
|
+
http.cert_store = store
|
276
|
+
end
|
277
|
+
|
278
|
+
#http.read_timeout = options[:read_timeout]
|
279
|
+
|
280
|
+
header = {}
|
281
|
+
if @apikey
|
282
|
+
header['Authorization'] = "TD1 #{apikey}"
|
283
|
+
end
|
284
|
+
header['Date'] = Time.now.rfc2822
|
285
|
+
|
286
|
+
return http, header
|
287
|
+
end
|
288
|
+
|
289
|
+
def raise_error(msg, res)
|
290
|
+
begin
|
291
|
+
js = JSON.load(res.body)
|
292
|
+
msg = js['message']
|
293
|
+
error_code = js['error_code']
|
294
|
+
|
295
|
+
if res.code == "404"
|
296
|
+
raise NotFoundError, "#{error_code}: #{msg}"
|
297
|
+
elsif res.code == "409"
|
298
|
+
raise AlreadyExistsError, "#{error_code}: #{msg}"
|
299
|
+
else
|
300
|
+
raise APIError, "#{error_code}: #{msg}"
|
301
|
+
end
|
302
|
+
|
303
|
+
rescue
|
304
|
+
if res.code == "404"
|
305
|
+
raise NotFoundError, "#{msg}: #{res.body}"
|
306
|
+
elsif res.code == "409"
|
307
|
+
raise AlreadyExistsError, "#{msg}: #{res.body}"
|
308
|
+
else
|
309
|
+
raise APIError, "#{msg}: #{res.body}"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
# TODO error
|
313
|
+
end
|
314
|
+
|
315
|
+
def e(s)
|
316
|
+
require 'cgi'
|
317
|
+
CGI.escape(s.to_s)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
end
|
323
|
+
|