thinkingdata-ruby 1.2.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,409 +1,495 @@
1
- require 'securerandom'
2
- require 'thinkingdata-ruby/errors'
3
- require 'thinkingdata-ruby/version'
4
-
5
- module TDAnalytics
6
- @is_enable_log = false
7
- @is_stringent = false
8
-
9
- def self.set_enable_log(enable)
10
- unless [true, false].include? enable
11
- enable = false
12
- end
13
- @is_enable_log = enable
14
- end
15
-
16
- def self.get_enable_log
17
- @is_enable_log
18
- end
19
-
20
- def self.set_stringent(enable)
21
- unless [true, false].include? enable
22
- enable = false
23
- end
24
- @is_stringent = enable
25
- end
26
-
27
- def self.get_stringent
28
- @is_stringent
29
- end
30
-
31
- class Tracker
32
- LIB_PROPERTIES = {
33
- '#lib' => 'ruby',
34
- '#lib_version' => TDAnalytics::VERSION,
35
- }
36
-
37
- @@dynamic_block = nil
38
-
39
- def initialize(consumer, error_handler = nil, uuid: false)
40
- @error_handler = error_handler || ErrorHandler.new
41
- @consumer = consumer
42
- @super_properties = {}
43
- @uuid = uuid
44
- end
45
-
46
- # set common properties
47
- def set_super_properties(properties, skip_local_check = false)
48
- unless TDAnalytics::get_stringent == false || skip_local_check || _check_properties(:track, properties)
49
- @error_handler.handle(IllegalParameterError.new("Invalid super properties"))
50
- return false
51
- end
52
- properties.each do |k, v|
53
- if v.is_a?(Time)
54
- @super_properties[k] = _format_time(v)
55
- else
56
- @super_properties[k] = v
57
- end
58
- end
59
- end
60
-
61
- def clear_super_properties
62
- @super_properties = {}
63
- end
64
-
65
- def set_dynamic_super_properties(&block)
66
- @@dynamic_block = block
67
- end
68
-
69
- def clear_dynamic_super_properties
70
- @@dynamic_block = nil
71
- end
72
-
73
- # report ordinary event
74
- # event_name: (require) A string of 50 letters and digits that starts with '#' or a letter
75
- # distinct_id: (optional) distinct ID
76
- # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
77
- # properties: (optional) string、number、Time、boolean
78
- # time: (optional)Time
79
- # ip: (optional) ip
80
- # first_check_id: (optional) The value cannot be null for the first event
81
- # skip_local_check: (optional) check data or not
82
- def track(event_name: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil,first_check_id:nil, skip_local_check: false)
83
- begin
84
- _check_name event_name
85
- _check_id(distinct_id, account_id)
86
- unless skip_local_check
87
- _check_properties(:track, properties)
88
- end
89
- rescue TDAnalyticsError => e
90
- @error_handler.handle(e)
91
- return false
92
- end
93
-
94
- _internal_track(:track, event_name: event_name, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip, first_check_id: first_check_id)
95
- end
96
-
97
- # report overridable event
98
- def track_overwrite(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
99
- begin
100
- _check_name event_name
101
- _check_event_id event_id
102
- _check_id(distinct_id, account_id)
103
- unless skip_local_check
104
- _check_properties(:track_overwrite, properties)
105
- end
106
- rescue TDAnalyticsError => e
107
- @error_handler.handle(e)
108
- return false
109
- end
110
-
111
- _internal_track(:track_overwrite, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
112
- end
113
-
114
- # report updatable event
115
- def track_update(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
116
- begin
117
- _check_name event_name
118
- _check_event_id event_id
119
- _check_id(distinct_id, account_id)
120
- unless skip_local_check
121
- _check_properties(:track_update, properties)
122
- end
123
- rescue TDAnalyticsError => e
124
- @error_handler.handle(e)
125
- return false
126
- end
127
-
128
- _internal_track(:track_update, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
129
- end
130
-
131
- # set user properties. would overwrite existing names.
132
- def user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
133
- begin
134
- _check_id(distinct_id, account_id)
135
- _check_properties(:user_set, properties)
136
- rescue TDAnalyticsError => e
137
- @error_handler.handle(e)
138
- return false
139
- end
140
-
141
- _internal_track(:user_set, distinct_id: distinct_id, account_id: account_id, properties: properties, ip: ip)
142
- end
143
-
144
- # set user properties, If such property had been set before, this message would be neglected.
145
- def user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
146
- begin
147
- _check_id(distinct_id, account_id)
148
- _check_properties(:user_setOnce, properties)
149
- rescue TDAnalyticsError => e
150
- @error_handler.handle(e)
151
- return false
152
- end
153
-
154
- _internal_track(:user_setOnce,
155
- distinct_id: distinct_id,
156
- account_id: account_id,
157
- properties: properties,
158
- ip: ip,
159
- )
160
- end
161
-
162
- # to add user properties of array type.
163
- def user_append(distinct_id: nil, account_id: nil, properties: {})
164
- begin
165
- _check_id(distinct_id, account_id)
166
- _check_properties(:user_append, properties)
167
- rescue TDAnalyticsError => e
168
- @error_handler.handle(e)
169
- return false
170
- end
171
-
172
- _internal_track(:user_append,
173
- distinct_id: distinct_id,
174
- account_id: account_id,
175
- properties: properties,
176
- )
177
- end
178
-
179
- def user_uniq_append(distinct_id: nil, account_id: nil, properties: {})
180
- begin
181
- _check_id(distinct_id, account_id)
182
- _check_properties(:user_uniq_append, properties)
183
- rescue TDAnalyticsError => e
184
- @error_handler.handle(e)
185
- return false
186
- end
187
-
188
- _internal_track(:user_uniq_append,
189
- distinct_id: distinct_id,
190
- account_id: account_id,
191
- properties: properties,
192
- )
193
- end
194
-
195
- # clear the user properties of users.
196
- def user_unset(distinct_id: nil, account_id: nil, property: nil)
197
- properties = {}
198
- if property.is_a?(Array)
199
- property.each do |k|
200
- properties[k] = 0
201
- end
202
- else
203
- properties[property] = 0
204
- end
205
-
206
- begin
207
- _check_id(distinct_id, account_id)
208
- _check_properties(:user_unset, properties)
209
- rescue TDAnalyticsError => e
210
- @error_handler.handle(e)
211
- return false
212
- end
213
-
214
- _internal_track(:user_unset,
215
- distinct_id: distinct_id,
216
- account_id: account_id,
217
- properties: properties,
218
- )
219
- end
220
-
221
- # to accumulate operations against the property.
222
- def user_add(distinct_id: nil, account_id: nil, properties: {})
223
- begin
224
- _check_id(distinct_id, account_id)
225
- _check_properties(:user_add, properties)
226
- rescue TDAnalyticsError => e
227
- @error_handler.handle(e)
228
- return false
229
- end
230
-
231
- _internal_track(:user_add,
232
- distinct_id: distinct_id,
233
- account_id: account_id,
234
- properties: properties,
235
- )
236
- end
237
-
238
- # delete a user, This operation cannot be undone.
239
- def user_del(distinct_id: nil, account_id: nil)
240
- begin
241
- _check_id(distinct_id, account_id)
242
- rescue TDAnalyticsError => e
243
- @error_handler.handle(e)
244
- return false
245
- end
246
-
247
- _internal_track(:user_del,
248
- distinct_id: distinct_id,
249
- account_id: account_id,
250
- )
251
- end
252
-
253
- # report data immediately.
254
- def flush
255
- return true unless defined? @consumer.flush
256
- ret = true
257
- begin
258
- @consumer.flush
259
- rescue TDAnalyticsError => e
260
- @error_handler.handle(e)
261
- ret = false
262
- end
263
- ret
264
- end
265
-
266
- # Close and exit sdk
267
- def close
268
- return true unless defined? @consumer.close
269
- ret = true
270
- begin
271
- @consumer.close
272
- rescue TDAnalyticsError => e
273
- @error_handler.handle(e)
274
- ret = false
275
- end
276
- ret
277
- end
278
-
279
- private
280
-
281
- def _internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: nil)
282
- if type == :track || type == :track_update || type == :track_overwrite
283
- dynamic_properties = @@dynamic_block.respond_to?(:call) ? @@dynamic_block.call : {}
284
- properties = LIB_PROPERTIES.merge(@super_properties).merge(dynamic_properties).merge(properties)
285
- end
286
-
287
- data = {
288
- '#type' => type,
289
- }
290
-
291
- properties.each do |k, v|
292
- if v.is_a?(Time)
293
- properties[k] = _format_time(v)
294
- end
295
- end
296
-
297
- _move_preset_properties([:'#ip', :"#time", :"#app_id", :"#uuid"], data, properties: properties)
298
-
299
- if data[:'#time'] == nil
300
- if time == nil
301
- time = Time.now
302
- end
303
- data[:'#time'] = _format_time(time)
304
- end
305
-
306
- data['properties'] = properties
307
- data['#event_name'] = event_name if (type == :track || type == :track_update || type == :track_overwrite)
308
- data['#event_id'] = event_id if (type == :track_update || type == :track_overwrite)
309
- data['#account_id'] = account_id if account_id
310
- data['#distinct_id'] = distinct_id if distinct_id
311
- data['#ip'] = ip if ip
312
- data['#first_check_id'] = first_check_id if first_check_id
313
- data[:'#uuid'] = SecureRandom.uuid if @uuid and data[:'#uuid'] == nil
314
-
315
- ret = true
316
- begin
317
- @consumer.add(data)
318
- rescue TDAnalyticsError => e
319
- @error_handler.handle(e)
320
- ret = false
321
- end
322
-
323
- ret
324
- end
325
-
326
- def _format_time(time)
327
- time.strftime("%Y-%m-%d %H:%M:%S.#{((time.to_f * 1000.0).to_i % 1000).to_s.rjust(3, "0")}")
328
- end
329
-
330
- def _check_event_id(event_id)
331
- if TDAnalytics::get_stringent == false
332
- return true
333
- end
334
-
335
- raise IllegalParameterError.new("the event_id or property cannot be nil") if event_id.nil?
336
- true
337
- end
338
-
339
- def _check_name(name)
340
- if TDAnalytics::get_stringent == false
341
- return true
342
- end
343
-
344
- raise IllegalParameterError.new("the name of event or property cannot be nil") if name.nil?
345
-
346
- unless name.instance_of?(String) || name.instance_of?(Symbol)
347
- raise IllegalParameterError.new("#{name} is invalid. It must be String or Symbol")
348
- end
349
- true
350
- end
351
-
352
- def _check_properties(type, properties)
353
- if TDAnalytics::get_stringent == false
354
- return true
355
- end
356
-
357
- unless properties.instance_of? Hash
358
- return false
359
- end
360
-
361
- properties.each do |k, v|
362
- _check_name k
363
- next if v.nil?
364
- unless v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(Symbol) || v.is_a?(String) || v.is_a?(Time) || !!v == v || v.is_a?(Array)
365
- raise IllegalParameterError.new("The value of properties must be type in Integer, Float, Symbol, String, Array,and Time")
366
- end
367
-
368
- if type == :user_add
369
- raise IllegalParameterError.new("Property value for user add must be numbers") unless v.is_a?(Integer) || v.is_a?(Float)
370
- end
371
- if v.is_a?(Array)
372
- v.each_index do |i|
373
- if v[i].is_a?(Time)
374
- v[i] = _format_time(v[i])
375
- end
376
- end
377
- end
378
- end
379
- true
380
- end
381
-
382
- def _check_id(distinct_id, account_id)
383
- if TDAnalytics::get_stringent == false
384
- return true
385
- end
386
-
387
- raise IllegalParameterError.new("account id or distinct id must be provided.") if distinct_id.nil? && account_id.nil?
388
- end
389
-
390
- def _move_preset_properties(keys, data, properties: {})
391
- property_keys = properties.keys
392
- keys.each { |k|
393
- if property_keys.include? k
394
- data[k] = properties[k]
395
- properties.delete(k)
396
- end
397
- }
398
- end
399
- end
400
-
401
- class TELog
402
- def self.info(*msg)
403
- if TDAnalytics::get_enable_log
404
- print("[ThinkingEngine][#{Time.now}][info]-")
405
- puts(msg)
406
- end
407
- end
408
- end
409
- end
1
+ require 'securerandom'
2
+ require 'thinkingdata-ruby/td_errors'
3
+ require 'thinkingdata-ruby/td_version'
4
+
5
+ ##
6
+ # ThinkingData module
7
+ module ThinkingData
8
+ @is_enable_log = false
9
+ @is_stringent = false
10
+
11
+ ##
12
+ # Enable SDK log or not
13
+ # @param enable [Boolean] true or false
14
+ def self.set_enable_log(enable)
15
+ unless [true, false].include? enable
16
+ enable = false
17
+ end
18
+ @is_enable_log = enable
19
+ end
20
+
21
+ ##
22
+ # Get log status
23
+ # @return [Boolean] enable or not
24
+ def self.get_enable_log
25
+ @is_enable_log
26
+ end
27
+
28
+ ##
29
+ # Check or not parameter
30
+ # @param enable [Boolean] check or not
31
+ def self.set_stringent(enable)
32
+ unless [true, false].include? enable
33
+ enable = false
34
+ end
35
+ @is_stringent = enable
36
+ end
37
+
38
+ ##
39
+ # Get parameter check status of SDK
40
+ # @return [Boolean] check or not
41
+ def self.get_stringent
42
+ @is_stringent
43
+ end
44
+
45
+ ##
46
+ # Analytics class。 Provides the function of tracking data
47
+ class TDAnalytics
48
+ LIB_PROPERTIES = {
49
+ '#lib' => 'ruby',
50
+ '#lib_version' => ThinkingData::VERSION,
51
+ }
52
+
53
+ @dynamic_block = nil
54
+
55
+ ##
56
+ # Init function
57
+ # @param consumer [consumer] data consumer: TDLoggerConsumer | TDDebugConsumer | TDBatchConsumer
58
+ # @param error_handler [TDErrorHandler] custom error handler, process SDK error. It could be nil
59
+ # @param uuid [Boolean] Whether to automatically add uuid
60
+ def initialize(consumer, error_handler = nil, uuid: false)
61
+ @error_handler = error_handler || TDErrorHandler.new
62
+ @consumer = consumer
63
+ @super_properties = {}
64
+ @uuid_enable = uuid
65
+ TDLog.info("SDK init success.")
66
+ end
67
+
68
+ ##
69
+ # Set common properties
70
+ def set_super_properties(properties, skip_local_check = false)
71
+ unless ThinkingData::get_stringent == false || skip_local_check || _check_properties(:track, properties)
72
+ @error_handler.handle(IllegalParameterError.new("Invalid super properties"))
73
+ return false
74
+ end
75
+ properties.each do |k, v|
76
+ if v.is_a?(Time)
77
+ @super_properties[k] = _format_time(v)
78
+ else
79
+ @super_properties[k] = v
80
+ end
81
+ end
82
+ end
83
+
84
+ ##
85
+ # Clear super properties
86
+ def clear_super_properties
87
+ @super_properties = {}
88
+ end
89
+
90
+ ##
91
+ # Set dynamic super properties
92
+ def set_dynamic_super_properties(&block)
93
+ @dynamic_block = block
94
+ end
95
+
96
+ ##
97
+ # Clear dynamic super properties
98
+ def clear_dynamic_super_properties
99
+ @dynamic_block = nil
100
+ end
101
+
102
+ ##
103
+ # Report ordinary event
104
+ # event_name: (require) A string of 50 letters and digits that starts with '#' or a letter
105
+ # distinct_id: (optional) distinct ID
106
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
107
+ # properties: (optional) string、number、Time、boolean
108
+ # time: (optional)Time
109
+ # ip: (optional) ip
110
+ # first_check_id: (optional) The value cannot be null for the first event
111
+ # skip_local_check: (optional) check data or not
112
+ def track(event_name: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil,first_check_id:nil, skip_local_check: false)
113
+ begin
114
+ _check_name event_name
115
+ _check_id(distinct_id, account_id)
116
+ unless skip_local_check
117
+ _check_properties(:track, properties)
118
+ end
119
+ rescue TDAnalyticsError => e
120
+ @error_handler.handle(e)
121
+ return false
122
+ end
123
+
124
+ _internal_track(:track, event_name: event_name, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip, first_check_id: first_check_id)
125
+ end
126
+
127
+ ##
128
+ # Report overridable event
129
+ # event_name: (require) A string of 50 letters and digits that starts with '#' or a letter
130
+ # event_id: (require) string
131
+ # distinct_id: (optional) distinct ID
132
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
133
+ # properties: (optional) string、number、Time、boolean
134
+ # time: (optional)Time
135
+ # ip: (optional) ip
136
+ # skip_local_check: (optional) check data or not
137
+ def track_overwrite(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
138
+ begin
139
+ _check_name event_name
140
+ _check_event_id event_id
141
+ _check_id(distinct_id, account_id)
142
+ unless skip_local_check
143
+ _check_properties(:track_overwrite, properties)
144
+ end
145
+ rescue TDAnalyticsError => e
146
+ @error_handler.handle(e)
147
+ return false
148
+ end
149
+
150
+ _internal_track(:track_overwrite, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
151
+ end
152
+
153
+ ##
154
+ # Report updatable event
155
+ # event_name: (require) A string of 50 letters and digits that starts with '#' or a letter
156
+ # event_id: (require) string
157
+ # distinct_id: (optional) distinct ID
158
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
159
+ # properties: (optional) string、number、Time、boolean
160
+ # time: (optional)Time
161
+ # ip: (optional) ip
162
+ # skip_local_check: (optional) check data or not
163
+ def track_update(event_name: nil,event_id: nil, distinct_id: nil, account_id: nil, properties: {}, time: nil, ip: nil, skip_local_check: false)
164
+ begin
165
+ _check_name event_name
166
+ _check_event_id event_id
167
+ _check_id(distinct_id, account_id)
168
+ unless skip_local_check
169
+ _check_properties(:track_update, properties)
170
+ end
171
+ rescue TDAnalyticsError => e
172
+ @error_handler.handle(e)
173
+ return false
174
+ end
175
+
176
+ _internal_track(:track_update, event_name: event_name, event_id: event_id, distinct_id: distinct_id, account_id: account_id, properties: properties, time: time, ip: ip)
177
+ end
178
+
179
+ ##
180
+ # Set user properties. would overwrite existing names
181
+ # distinct_id: (optional) distinct ID
182
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
183
+ # properties: (optional) string、number、Time、boolean
184
+ # ip: (optional) ip
185
+ def user_set(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
186
+ begin
187
+ _check_id(distinct_id, account_id)
188
+ _check_properties(:user_set, properties)
189
+ rescue TDAnalyticsError => e
190
+ @error_handler.handle(e)
191
+ return false
192
+ end
193
+
194
+ _internal_track(:user_set, distinct_id: distinct_id, account_id: account_id, properties: properties, ip: ip)
195
+ end
196
+
197
+ ##
198
+ # Set user properties, If such property had been set before, this message would be neglected
199
+ # distinct_id: (optional) distinct ID
200
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
201
+ # properties: (optional) string、number、Time、boolean
202
+ # ip: (optional) ip
203
+ def user_set_once(distinct_id: nil, account_id: nil, properties: {}, ip: nil)
204
+ begin
205
+ _check_id(distinct_id, account_id)
206
+ _check_properties(:user_setOnce, properties)
207
+ rescue TDAnalyticsError => e
208
+ @error_handler.handle(e)
209
+ return false
210
+ end
211
+
212
+ _internal_track(:user_setOnce,
213
+ distinct_id: distinct_id,
214
+ account_id: account_id,
215
+ properties: properties,
216
+ ip: ip,
217
+ )
218
+ end
219
+
220
+ ##
221
+ # To append user properties of array type
222
+ # distinct_id: (optional) distinct ID
223
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
224
+ # properties: (optional) string、number、Time、boolean
225
+ def user_append(distinct_id: nil, account_id: nil, properties: {})
226
+ begin
227
+ _check_id(distinct_id, account_id)
228
+ _check_properties(:user_append, properties)
229
+ rescue TDAnalyticsError => e
230
+ @error_handler.handle(e)
231
+ return false
232
+ end
233
+
234
+ _internal_track(:user_append,
235
+ distinct_id: distinct_id,
236
+ account_id: account_id,
237
+ properties: properties,
238
+ )
239
+ end
240
+
241
+ ##
242
+ # To append user properties of array type. It filters out duplicate values
243
+ # distinct_id: (optional) distinct ID
244
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
245
+ # properties: (optional) string、number、Time、boolean
246
+ def user_uniq_append(distinct_id: nil, account_id: nil, properties: {})
247
+ begin
248
+ _check_id(distinct_id, account_id)
249
+ _check_properties(:user_uniq_append, properties)
250
+ rescue TDAnalyticsError => e
251
+ @error_handler.handle(e)
252
+ return false
253
+ end
254
+
255
+ _internal_track(:user_uniq_append,
256
+ distinct_id: distinct_id,
257
+ account_id: account_id,
258
+ properties: properties,
259
+ )
260
+ end
261
+
262
+ ##
263
+ # Clear the user properties of users
264
+ # distinct_id: (optional) distinct ID
265
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
266
+ # properties: (optional) string、number、Time、boolean
267
+ def user_unset(distinct_id: nil, account_id: nil, property: nil)
268
+ properties = {}
269
+ if property.is_a?(Array)
270
+ property.each do |k|
271
+ properties[k] = 0
272
+ end
273
+ else
274
+ properties[property] = 0
275
+ end
276
+
277
+ begin
278
+ _check_id(distinct_id, account_id)
279
+ _check_properties(:user_unset, properties)
280
+ rescue TDAnalyticsError => e
281
+ @error_handler.handle(e)
282
+ return false
283
+ end
284
+
285
+ _internal_track(:user_unset,
286
+ distinct_id: distinct_id,
287
+ account_id: account_id,
288
+ properties: properties,
289
+ )
290
+ end
291
+
292
+ ##
293
+ # To accumulate operations against the property
294
+ # distinct_id: (optional) distinct ID
295
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
296
+ # properties: (optional) string、number、Time、boolean
297
+ def user_add(distinct_id: nil, account_id: nil, properties: {})
298
+ begin
299
+ _check_id(distinct_id, account_id)
300
+ _check_properties(:user_add, properties)
301
+ rescue TDAnalyticsError => e
302
+ @error_handler.handle(e)
303
+ return false
304
+ end
305
+
306
+ _internal_track(:user_add,
307
+ distinct_id: distinct_id,
308
+ account_id: account_id,
309
+ properties: properties,
310
+ )
311
+ end
312
+
313
+ ##
314
+ # Delete a user, This operation cannot be undone
315
+ # distinct_id: (optional) distinct ID
316
+ # account_id: (optional) account ID. distinct_id, account_id can't both be empty.
317
+ def user_del(distinct_id: nil, account_id: nil)
318
+ begin
319
+ _check_id(distinct_id, account_id)
320
+ rescue TDAnalyticsError => e
321
+ @error_handler.handle(e)
322
+ return false
323
+ end
324
+
325
+ _internal_track(:user_del,
326
+ distinct_id: distinct_id,
327
+ account_id: account_id,
328
+ )
329
+ end
330
+
331
+ ##
332
+ # Report data immediately
333
+ def flush
334
+ TDLog.info("SDK flush data.")
335
+ return true unless defined? @consumer.flush
336
+ ret = true
337
+ begin
338
+ @consumer.flush
339
+ rescue TDAnalyticsError => e
340
+ @error_handler.handle(e)
341
+ ret = false
342
+ end
343
+ ret
344
+ end
345
+
346
+ ##
347
+ # Close and exit sdk
348
+ def close
349
+ return true unless defined? @consumer.close
350
+ ret = true
351
+ begin
352
+ @consumer.close
353
+ rescue TDAnalyticsError => e
354
+ @error_handler.handle(e)
355
+ ret = false
356
+ end
357
+
358
+ TDLog.info("SDK close.")
359
+
360
+ ret
361
+ end
362
+
363
+ private
364
+
365
+ def _internal_track(type, properties: {}, event_name: nil, event_id:nil, account_id: nil, distinct_id: nil, ip: nil,first_check_id: nil, time: nil)
366
+ if type == :track || type == :track_update || type == :track_overwrite
367
+ dynamic_properties = @dynamic_block.respond_to?(:call) ? @dynamic_block.call : {}
368
+ properties = LIB_PROPERTIES.merge(@super_properties).merge(dynamic_properties).merge(properties)
369
+ end
370
+
371
+ data = {
372
+ '#type' => type,
373
+ }
374
+
375
+ properties.each do |k, v|
376
+ if v.is_a?(Time)
377
+ properties[k] = _format_time(v)
378
+ end
379
+ end
380
+
381
+ _move_preset_properties([:'#ip', :"#time", :"#app_id", :"#uuid"], data, properties: properties)
382
+
383
+ if data[:'#time'] == nil
384
+ if time == nil
385
+ time = Time.now
386
+ end
387
+ data[:'#time'] = _format_time(time)
388
+ end
389
+
390
+ data['properties'] = properties
391
+ data['#event_name'] = event_name if (type == :track || type == :track_update || type == :track_overwrite)
392
+ data['#event_id'] = event_id if (type == :track_update || type == :track_overwrite)
393
+ data['#account_id'] = account_id if account_id
394
+ data['#distinct_id'] = distinct_id if distinct_id
395
+ data['#ip'] = ip if ip
396
+ data['#first_check_id'] = first_check_id if first_check_id
397
+ data[:'#uuid'] = SecureRandom.uuid if @uuid_enable and data[:'#uuid'] == nil
398
+
399
+ ret = true
400
+ begin
401
+ @consumer.add(data)
402
+ rescue TDAnalyticsError => e
403
+ @error_handler.handle(e)
404
+ ret = false
405
+ end
406
+
407
+ ret
408
+ end
409
+
410
+ def _format_time(time)
411
+ time.strftime("%Y-%m-%d %H:%M:%S.#{((time.to_f * 1000.0).to_i % 1000).to_s.rjust(3, "0")}")
412
+ end
413
+
414
+ def _check_event_id(event_id)
415
+ if ThinkingData::get_stringent == false
416
+ return true
417
+ end
418
+
419
+ raise IllegalParameterError.new("the event_id or property cannot be nil") if event_id.nil?
420
+ true
421
+ end
422
+
423
+ def _check_name(name)
424
+ if ThinkingData::get_stringent == false
425
+ return true
426
+ end
427
+
428
+ raise IllegalParameterError.new("the name of event or property cannot be nil") if name.nil?
429
+
430
+ unless name.instance_of?(String) || name.instance_of?(Symbol)
431
+ raise IllegalParameterError.new("#{name} is invalid. It must be String or Symbol")
432
+ end
433
+ true
434
+ end
435
+
436
+ def _check_properties(type, properties)
437
+ if ThinkingData::get_stringent == false
438
+ return true
439
+ end
440
+
441
+ unless properties.instance_of? Hash
442
+ return false
443
+ end
444
+
445
+ properties.each do |k, v|
446
+ _check_name k
447
+ next if v.nil?
448
+ unless v.is_a?(Integer) || v.is_a?(Float) || v.is_a?(Symbol) || v.is_a?(String) || v.is_a?(Time) || !!v == v || v.is_a?(Array)
449
+ raise IllegalParameterError.new("The value of properties must be type in Integer, Float, Symbol, String, Array,and Time")
450
+ end
451
+
452
+ if type == :user_add
453
+ raise IllegalParameterError.new("Property value for user add must be numbers") unless v.is_a?(Integer) || v.is_a?(Float)
454
+ end
455
+ if v.is_a?(Array)
456
+ v.each_index do |i|
457
+ if v[i].is_a?(Time)
458
+ v[i] = _format_time(v[i])
459
+ end
460
+ end
461
+ end
462
+ end
463
+ true
464
+ end
465
+
466
+ def _check_id(distinct_id, account_id)
467
+ if ThinkingData::get_stringent == false
468
+ return true
469
+ end
470
+
471
+ raise IllegalParameterError.new("account id or distinct id must be provided.") if distinct_id.nil? && account_id.nil?
472
+ end
473
+
474
+ def _move_preset_properties(keys, data, properties: {})
475
+ property_keys = properties.keys
476
+ keys.each { |k|
477
+ if property_keys.include? k
478
+ data[k] = properties[k]
479
+ properties.delete(k)
480
+ end
481
+ }
482
+ end
483
+ end
484
+
485
+ ##
486
+ # SDK log module
487
+ class TDLog
488
+ def self.info(*msg)
489
+ if ThinkingData::get_enable_log
490
+ print("[ThinkingData][#{Time.now}] ")
491
+ puts(msg)
492
+ end
493
+ end
494
+ end
495
+ end