· 7 years ago · Jan 04, 2019, 11:58 PM
1extends Node
2
3export(String) var identity_pool_id = ""
4export(String) var account_id = ""
5export(String) var app_id = ""
6export(String) var app_package_name = ""
7export(String) var app_title = ""
8export(String) var api_endpoint = ""
9export(String) var api_key = ""
10export(String) var app_version_code = ""
11export(String) var app_version_name = ""
12export(bool) var log_to_output = false
13
14var _session_id = ""
15var _request
16var _request_data
17var _request_callback
18var _refreshing_credentials = false
19var _refreshing_request
20var _previous_request
21var _session_start_timestamp = ""
22var _session_start_unix = 0
23var _focus_lost_unix = 0
24var _focus_lost_max = 5
25var _focus_lost_time = 0
26var _has_focus = true
27var _settings = {
28 identity = {
29 identity_id = "",
30 access_key_id = "",
31 expiration = 0,
32 secret_key = "",
33 session_token = ""
34 },
35 client_id = ""
36}
37var _settings_filename = "godot.analytics"
38func get_settings():
39 return _settings
40func load_data():
41 var data = File.new()
42 if not data.file_exists("user://"+_settings_filename):
43 return false
44 data.open("user://"+_settings_filename, File.READ)
45 while not data.eof_reached():
46 var settings_json = parse_json(data.get_line())
47 if settings_json == null:
48 break
49 _settings = settings_json
50 data.close()
51 return true
52func _save_data():
53 if _settings.client_id == "":
54 _settings.client_id = _create_guid()
55 var data = File.new()
56 data.open("user://"+_settings_filename, File.WRITE)
57 data.store_line(JSON.print(_settings))
58 data.close()
59func _ready():
60 pause_mode = PAUSE_MODE_PROCESS
61 get_tree().set_auto_accept_quit(false)
62 _request = HTTPRequest.new()
63 _request.use_threads = true
64 add_child(_request)
65 _refreshing_request = HTTPRequest.new()
66 _refreshing_request.use_threads = true
67 add_child(_refreshing_request)
68 _refreshing_request.connect("request_completed", self, "_identity_credentials_received")
69 if !load_data():
70 _save_data()
71 _settings_data_ready()
72 else:
73 _settings_data_ready()
74func _process(delta):
75 if !_has_focus:
76 if _session_id != "":
77 _focus_lost_time += delta
78 if _focus_lost_time > _focus_lost_max:
79 _end_session()
80func _settings_data_ready():
81 if _settings.identity.identity_id != "":
82 _start_session()
83 else:
84 _request_new_identity_id()
85func _create_request_data(event_type, attributes = {}, metrics = {}):
86 var payload = {
87 timestamp = _get_amz_timestamp(),
88 eventType = event_type,
89 session = JSON.print({
90 id = _session_id,
91 startTimestamp = _session_start_timestamp
92 }),
93 clientContext = _get_client_context(),
94 secretAccessKey = _settings.identity.secret_key,
95 accessKeyId = _settings.identity.access_key_id,
96 sessionToken = _settings.identity.session_token,
97 attributes = JSON.print(attributes),
98 metrics = JSON.print(metrics)
99 }
100 return payload
101func _notification(what):
102 if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
103 _end_session()
104 yield(get_tree().create_timer(1.0),"timeout")
105 get_tree().quit()
106 if what == MainLoop.NOTIFICATION_WM_FOCUS_OUT:
107 _has_focus = false
108 _focus_lost_unix = OS.get_unix_time()
109 if what == MainLoop.NOTIFICATION_WM_FOCUS_IN:
110 _focus_lost_time = 0
111 _has_focus = true
112 if _session_id == "":
113 _start_session()
114func _start_session():
115 if _session_id != "":
116 return
117 if log_to_output:
118 print("starting session")
119 _session_start_unix = OS.get_unix_time()
120 _session_id = _create_guid()
121 _session_start_timestamp = _get_amz_timestamp()
122 var request_data = _create_request_data('_session.start')
123 _make_request(request_data, "_session_start_complete")
124 pass
125func _end_session():
126 if log_to_output:
127 print("ending session")
128 var request_data = _create_request_data('_session.stop')
129 request_data.timestamp = _get_amz_timestamp()
130 request_data.session = JSON.print({
131 id = _session_id,
132 startTimestamp = _session_start_timestamp,
133 stopTimestamp = request_data.timestamp,
134 duration = (OS.get_unix_time() - _session_start_unix) * 1000
135 })
136 _session_id = ""
137 _make_request(request_data, "_session_end_complete")
138func _session_end_complete(result, code, headers, body):
139 var response = JSON.parse(body.get_string_from_utf8()).result
140 if log_to_output:
141 print("end session response: ")
142 print(response)
143 _request.disconnect("request_completed", self, "_session_end_complete")
144 if !_check_error(response):
145 _previous_request = true
146 _request_credentials_for_identity()
147 return
148func _event_callback(result, code, headers, body):
149 var response = JSON.parse(body.get_string_from_utf8()).result
150 if log_to_output:
151 print("event response: ")
152 print(response)
153 _request.disconnect("request_completed", self, "_event_callback")
154 if !_check_error(response):
155 _previous_request = true
156 _request_credentials_for_identity()
157 return
158func _check_error(response):
159 response = JSON.print(response)
160 if (response.find("expired") > -1 || response.find("invalid") > -1) && response.find("token") > -1:
161 return false
162 return true
163func _make_request(request_data, callback):
164 _request_data = request_data
165 _request_callback = callback
166 if !_token_valid(request_data):
167 _previous_request = true
168 _request_credentials_for_identity()
169 else:
170 _request.connect("request_completed", self, callback)
171 var headers = ["Content-Type: application/json"]
172 if api_key.length() > 1:
173 headers.append("x-api-key: "+api_key)
174 _request.request(api_endpoint, headers, true, HTTPClient.METHOD_POST, JSON.print(request_data))
175 pass
176func _token_valid(request_data):
177 var current_time = OS.get_unix_time_from_datetime(OS.get_date(true))
178 if current_time > _settings.identity.expiration:
179 return false
180 return true
181func record_event(event_type, attributes = {}, metrics = {}):
182 var request_data = _create_request_data(event_type, attributes, metrics)
183 if log_to_output:
184 print("sending event")
185 _make_request(request_data, "_event_callback")
186 pass
187func _session_start_complete(result, code, headers, body):
188 var response = JSON.parse(body.get_string_from_utf8()).result
189 if log_to_output:
190 print("start session response: ")
191 print(response)
192 _request.disconnect("request_completed", self, "_session_start_complete")
193 if !_check_error(response):
194 _previous_request = true
195 _request_credentials_for_identity()
196 return
197func _get_client_context():
198 return JSON.print({
199 client = {
200 app_package_name = app_package_name,
201 app_title = app_title,
202 app_version_code = app_version_code,
203 app_version_name = app_version_name,
204 client_id = _settings.client_id
205 },
206 custom = {},
207 env = {
208 platform = _get_platform(OS.get_name()),
209 },
210 version = "v2.0",
211 services = {
212 mobile_analytics = {
213 app_id = app_id
214 }
215 }
216 })
217func _get_platform(os_name):
218 match os_name:
219 "Android":
220 return os_name
221 "iOS":
222 return "iPhone OS"
223 "Windows":
224 return os_name
225 "X11":
226 return "Linux"
227 "OSX":
228 return "Mac OS"
229 "HTML5":
230 return os_name
231func _request_new_identity_id():
232 if log_to_output:
233 print("requesting new federated identity id")
234 var request = HTTPRequest.new()
235 add_child(request)
236 _request.use_threads = true
237 var payload = {
238 IdentityPoolId = identity_pool_id,
239 AccountId = account_id
240 }
241 _request.connect("request_completed", self, "_identity_id_received")
242 _request.request("https://cognito-identity.us-east-1.amazonaws.com", ["Host: cognito-identity.us-east-1.amazonaws.com","X-Amz-Date: "+_get_amz_date(true), "X-Amz-Target: com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetId", "Content-Type: application/x-amz-json-1.1"], true, HTTPClient.METHOD_POST, JSON.print(payload))
243func _identity_id_received(result, code, headers, body):
244 var response = JSON.parse(body.get_string_from_utf8()).result
245 if log_to_output:
246 print("identity id received")
247 print(response)
248 _request.disconnect("request_completed", self, "_identity_id_received")
249 _settings.identity.identity_id = response.IdentityId
250 _save_data()
251 _request_credentials_for_identity()
252 pass
253func _request_credentials_for_identity():
254 if log_to_output:
255 print("requesting credentials for identity")
256 if _refreshing_credentials:
257 return
258 _refreshing_credentials = true
259 var payload = {
260 IdentityId = _settings.identity.identity_id,
261 }
262 _refreshing_request.request("https://cognito-identity.us-east-1.amazonaws.com", ["Host: cognito-identity.us-east-1.amazonaws.com","X-Amz-Date: "+_get_amz_date(true), "X-Amz-Target: com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetCredentialsForIdentity", "Content-Type: application/x-amz-json-1.1"], true, HTTPClient.METHOD_POST, JSON.print(payload))
263func _identity_credentials_received(result, code, headers, body):
264 _refreshing_credentials = false
265 var response = JSON.parse(body.get_string_from_utf8()).result
266 if log_to_output:
267 print("received credentials for identity")
268 print(response)
269 _settings.identity.access_key_id = response.Credentials.AccessKeyId
270 _settings.identity.expiration = response.Credentials.Expiration
271 _settings.identity.secret_key = response.Credentials.SecretKey
272 _settings.identity.session_token = response.Credentials.SessionToken
273 _save_data()
274 if _previous_request:
275 _previous_request = false
276 _request_data.sessionToken = _settings.identity.session_token
277 _request_data.accessKeyId = _settings.identity.access_key_id
278 _request_data.secretAccessKey = _settings.identity.secret_key
279 _make_request(_request_data, _request_callback)
280 else:
281 _start_session()
282func _get_amz_date(with_time):
283 var datetime = OS.get_datetime(true)
284 var year = String(datetime.year)
285 var month = _add_leading_zero(datetime.month)
286 var day = _add_leading_zero(datetime.day)
287 var hour = _add_leading_zero(datetime.hour)
288 var minute = _add_leading_zero(datetime.minute)
289 var second = _add_leading_zero(datetime.second)
290 if with_time:
291 return year + month + day + "T" + hour + minute + second + "Z"
292 return year + month + day
293func _get_amz_timestamp():
294 var datetime = OS.get_datetime(true)
295 var year = String(datetime.year)
296 var month = _add_leading_zero(datetime.month)
297 var day = _add_leading_zero(datetime.day)
298 var hour = _add_leading_zero(datetime.hour)
299 var minute = _add_leading_zero(datetime.minute)
300 var second = _add_leading_zero(datetime.second)
301 return year +"-" + month + "-" + day + "T" + hour +":"+ minute +":" + second +".0123Z"
302func _add_leading_zero(number):
303 var number_string = String(number)
304 if number_string.length() == 1:
305 return "0"+number_string
306 return number_string
307func _create_guid():
308 randomize()
309 var guid = ""
310 var random_chars = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","0","1","2","3","4","5","6","7","8","9","0","1","2","3","4","5","6","7","8","9","0","1","2","3","4","5","6","7","8","9"]
311 for i in range(0, 32):
312 guid += random_chars[randi() % (random_chars.size() - 1)]
313 var g1 = guid.substr(0,8)
314 var g2 = guid.substr(8,4)
315 var g3 = guid.substr(12,4)
316 var g4 = guid.substr(16, 4)
317 var g5 = guid.substr(20, 12)
318 return g1 + "-" + g2 + "-" + g3 + "-" + g4 + "-" + g5