Documentation for the Unreal C++ Plugin
Loading...
Searching...
No Matches
ApexAPI.cpp
Go to the documentation of this file.
1// Copyright 2022 PixoVR Corp. All Rights Reserved.
2
3
4#include "ApexAPI.h"
5#include "VaRest/Public/VaRestSubsystem.h"
6#include "ApexSDK.h"
7#include "ApexSDKSettings.h"
9#include "HeadMountedDisplayFunctionLibrary.h"
10#include "GenericPlatform/GenericPlatformMisc.h"
11
12DEFINE_LOG_CATEGORY_STATIC(LogApexAPI, Log, All);
13
14#define Log(pmt, ...) UE_LOG(LogApexAPI, Log, TEXT(pmt), ##__VA_ARGS__)
15#define Warn(pmt, ...) UE_LOG(LogApexAPI, Warning, TEXT(pmt), ##__VA_ARGS__)
16#define Error(pmt, ...) UE_LOG(LogApexAPI, Error, TEXT(pmt), ##__VA_ARGS__)
17#define Fatal(pmt, ...) UE_LOG(LogApexAPI, Fatal, TEXT(pmt), ##__VA_ARGS__)
18
21 , ApexSettings(nullptr)
22 , LaunchToken(TEXT(""))
23{
24}
25
27{
29 {
31 }
32
33 if (ApexSettings != nullptr)
34 {
36
37 if (URL.IsEmpty())
38 {
39 Fatal("No URL available. Please set the Server URI in the settings.");
40 }
41 else
42 {
43 URL.RemoveFromEnd("/");
44 if (!URL.Contains("https://"))
45 {
46 if (URL.Contains("http://"))
47 {
48 URL = URL.Replace(TEXT("http://"), TEXT(""));
49 }
50
51 URL.InsertAt(0, "https://");
52 }
53 }
54
56
58 if (!WebSocketURL.IsEmpty())
59 {
60 WebSocketURL.RemoveFromEnd("/");
61 if (!WebSocketURL.Contains("wss://"))
62 {
63 FString URLBody, URLScheme;
64 if (WebSocketURL.Split("://", &URLScheme, &URLBody))
65 {
66 WebSocketURL = URLBody;
67 }
68
69 WebSocketURL = "wss://" + WebSocketURL;
70 }
71
72 if (!WebSocketURL.EndsWith("/ws"))
73 {
74 WebSocketURL = WebSocketURL + "/ws";
75 }
76
77 bWebSocketEnabled = true;
78 }
79 else
80 {
81 bWebSocketEnabled = false;
82 }
83
86 Log("Launching module %d version %s", LoadedModuleId, *ModuleVersion);
87 }
88}
89
90void UApexAPI::Initialize(FSubsystemCollectionBase& Collection)
91{
92 Super::Initialize(Collection);
93
94 VaRestSubsystem = GEngine->GetEngineSubsystem<UVaRestSubsystem>();
95 LauncherSubsystem = GEngine->GetEngineSubsystem<UPixoLauncherSubsystem>();
96
98
99 DeviceModel = UHeadMountedDisplayFunctionLibrary::GetHMDDeviceName().ToString();
100 // Tag PC launches specifically if there is no HMD available.
101 if (DeviceModel.Equals("None", ESearchCase::IgnoreCase))
102 {
103 DeviceModel = "PC";
104 }
105 DeviceId = FGenericPlatformMisc::GetDeviceId();
106 if (DeviceId.IsEmpty())
107 {
108 DeviceId = FGenericPlatformMisc::GetDeviceMakeAndModel();
109 }
110
112 {
113 ApexSocket = MakeUnique<ApexWebSocket>();
114
115 ApexSocket->OnApexWebSocketConnected().AddLambda([&]() -> void {OnWebSocketConnected.Broadcast(); OnStaticWebSocketConnected.Broadcast(); });
116 ApexSocket->OnApexWebSocketConnectFailed().AddLambda([&](const FString& Error) -> void {OnWebSocketConnectFailed.Broadcast(Error); OnStaticWebSocketConnectFailed.Broadcast(Error); });
117 ApexSocket->OnApexWebSocketDisconnected().AddLambda([&](int32 StatusCode, const FString& Reason, bool bWasClean) -> void {OnWebSocketDisconnected.Broadcast(StatusCode, Reason, bWasClean); OnStaticWebSocketDisconnected.Broadcast(StatusCode, Reason, bWasClean); });
118 ApexSocket->OnApexAuthCodeRetrieved().AddLambda([&](const FString& AuthorizationCode) -> void {OnAuthorizationCodeRetrieved.Broadcast(AuthorizationCode); OnStaticAuthorizationCodeRetrieved.Broadcast(AuthorizationCode); });
119 ApexSocket->OnApexAuthenticateComplete().AddLambda([&](UVaRestJsonObject* LoginJsonObject) -> void { HandleLogin(LoginJsonObject); });
120
121 ApexSocket->AttemptConnect(WebSocketURL);
122 }
123
124#if PLATFORM_ANDROID
126 if (!LaunchToken.IsEmpty())
127 {
128 Log("Found token: %s", *LaunchToken);
129 }
130 else
131 {
132 Log("Failed to find token.");
133 }
134#else
135 FString PassedLaunchToken;
136 if (FParse::Value(FCommandLine::Get(), TEXT("-PIXO_TOKEN="), PassedLaunchToken))
137 {
138 Log("Token found: %s.", *PassedLaunchToken);
139 LaunchToken = PassedLaunchToken;
140 }
141#endif
142}
143
145{
147 {
148 return ApexSocket->IsWebsocketConnected();
149 }
150
151 return false;
152}
153
154
156{
158 {
159 if (!ApexSocket->AttemptConnect(WebSocketURL))
160 {
161 Warn("Web Socket already connected.");
162 }
163 }
164}
165
167{
169 {
170 ApexSocket->RequestAuthorizationCode();
171 }
172}
173
175{
176 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::GET, EVaRestRequestContentType::none);
177 FString RequestURL = URL + "/ping";
178 Request->SetURL(RequestURL);
179
180 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnPingComplete(Request); });
181 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnPingFail(Request); });
182
183 Request->ExecuteProcessRequest();
184}
185
186void UApexAPI::OnPingComplete(const UVaRestRequestJSON* Request)
187{
188 Log("On Ping Completed!");
189 OnRequestComplete.Broadcast(EApexRequestType::Ping, Request);
191}
192
193void UApexAPI::OnPingFail(const UVaRestRequestJSON* Request)
194{
195 Log("On Ping Failed!");
196
197 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
198 FAPEXRequestFailed APEXFailedRequest;
199
200 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
201
202 OnRequestFail.Broadcast(EApexRequestType::Ping, Request, APEXFailedRequest);
204}
205
207{
208 // Now we build our fun request here!
209 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::GET, EVaRestRequestContentType::none);
210 FString RequestURL = URL + "/v2/auth/validate-signature";
211
212 // Temporary fix until validate signature has been added to the modules api
213 RequestURL = RequestURL.Replace(TEXT("modules."), TEXT(""));
214
215 Request->SetURL(RequestURL);
216 Request->SetHeader("Authorization: Bearer", LaunchToken);
217
218 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnLoginComplete(Request); });
219 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnLoginFail(Request); });
220
221 Request->ExecuteProcessRequest();
222}
223
228
229void UApexAPI::Login(const FString& InUserName, const FString& InPassword, bool bShouldLogout)
230{
231 if (bShouldLogout && CurrentActiveLogin.IsSet())
232 {
233 Logout();
234 }
235
236 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
237 FString RequestURL = URL + "/login";
238 Request->SetURL(RequestURL);
239
240 UVaRestJsonObject* LoginJson = VaRestSubsystem->ConstructVaRestJsonObject();
241 LoginJson->SetField("login", VaRestSubsystem->ConstructJsonValueString(InUserName));
242 LoginJson->SetField("password", VaRestSubsystem->ConstructJsonValueString(InPassword));
243
244 Request->SetRequestObject(LoginJson);
245
246 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnLoginComplete(Request); });
247 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnLoginFail(Request); });
248
249 Request->ExecuteProcessRequest();
250}
251
253{
254 return !LaunchToken.IsEmpty();
255}
256
258{
259 return CurrentActiveLogin.IsSet();
260}
261
262void UApexAPI::OnLoginComplete(const UVaRestRequestJSON* Request)
263{
264 // We have to handle errors that show up as valid messages.
265 bool FailedResponse = true;
266 if (Request->GetResponseCode() == 200)
267 {
268 if (!Request->GetResponseObject()->GetRootObject()->HasField("Error"))
269 {
270 FailedResponse = false;
271 HandleLogin(Request->GetResponseObject());
272 }
273 }
274
275 if (FailedResponse)
276 {
277 OnLoginFail(Request);
278 }
279}
280
281void UApexAPI::OnLoginFail(const UVaRestRequestJSON* Request)
282{
283 Log("Login failed with response code %i", Request->GetResponseCode());
284
285 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
286 FAPEXRequestFailed APEXFailedRequest;
287
288 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
289
290 OnRequestFail.Broadcast(EApexRequestType::Login, Request, APEXFailedRequest);
292}
293
294
295void UApexAPI::HandleLogin(UVaRestJsonObject* LoginJsonObject)
296{
297 Log("Login Completed!");
299 {
300 Warn("Replacing the current login.");
302 }
303
304 CurrentActiveLogin.FromJsonObject(GetUserJsonObject(LoginJsonObject->GetRootObject()));
305
307}
308
309TSharedRef<FJsonObject> UApexAPI::GetUserJsonObject(TSharedRef<FJsonObject> &RootJsonObject)
310{
311 if (RootJsonObject->HasField("User"))
312 {
313 return RootJsonObject->GetObjectField("User").ToSharedRef();
314 }
315
316 return RootJsonObject;
317}
318
320{
321 const UVaRestRequestJSON* DummyRequestJSON = VaRestSubsystem->ConstructVaRestRequest();
323 {
325 LaunchToken = nullptr;
326
327 OnRequestComplete.Broadcast(EApexRequestType::Logout, DummyRequestJSON);
328 OnStaticRequestComplete.Broadcast(EApexRequestType::Logout, DummyRequestJSON);
329 }
330 else
331 {
332 FAPEXRequestFailed APEXFailedRequest;
333 APEXFailedRequest.Error = true;
334 APEXFailedRequest.Message = "No user currently logged in.";
335
336 UVaRestJsonObject* ResponseObject = DummyRequestJSON->GetResponseObject();
337 ResponseObject->SetBoolField("Error", APEXFailedRequest.Error);
338 ResponseObject->SetStringField("Message", APEXFailedRequest.Message);
339
340 OnRequestFail.Broadcast(EApexRequestType::Logout, DummyRequestJSON, APEXFailedRequest);
341 OnStaticRequestFail.Broadcast(EApexRequestType::Logout, DummyRequestJSON);
342 }
343}
344
345void UApexAPI::OnLogoutComplete(const UVaRestRequestJSON* Request)
346{
347 bool FailedResponse = true;
348 if (Request->GetResponseCode() == 200)
349 {
350 if (!Request->GetResponseObject()->GetRootObject()->HasField("Error"))
351 {
354 }
355 }
356
357 if (FailedResponse)
358 {
359 OnLogoutFail(Request);
360 }
361}
362
363void UApexAPI::OnLogoutFail(const UVaRestRequestJSON* Request)
364{
365 Log("Logout failed with response code %i", Request->GetResponseCode());
366
367 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
368 FAPEXRequestFailed APEXFailedRequest;
369
370 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
371
372 OnRequestFail.Broadcast(EApexRequestType::Logout, Request, APEXFailedRequest);
374}
375
377{
378 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::GET, EVaRestRequestContentType::none);
379
380 FString OptionalParameters = TEXT("");
381 FString SerialNumber = LauncherSubsystem->GetDeviceSerialNumber();
382 if (!SerialNumber.IsEmpty())
383 {
384 OptionalParameters = "?serial=" + SerialNumber;
385 Log("Serial number: %s", *SerialNumber);
386 }
387
388 FStringFormatOrderedArguments FormatArguments;
389 FormatArguments.Add(FStringFormatArg(URL));
390 FormatArguments.Add(FStringFormatArg(CurrentActiveLogin.ID));
391 FormatArguments.Add(FStringFormatArg(InModuleId));
392 FormatArguments.Add(FStringFormatArg(OptionalParameters));
393
394 FString AccessURL = FString::Format(TEXT("{0}/access/user/{1}/module/{2}{3}"), FormatArguments);
395 Request->SetURL(AccessURL);
396 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
397
398 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnUserVerificationComplete(Request); });
399 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnUserVerificationFail(Request); });
400
401 Request->ExecuteProcessRequest();
402}
403
404void UApexAPI::OnUserVerificationComplete(const UVaRestRequestJSON* Request)
405{
406 bool FailedResponse = true;
407 if (Request->GetResponseCode() == 200)
408 {
409 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
410 if (!ResponseObject->GetRootObject()->HasField("error"))
411 {
412 Log("User Verification Completed!");
413
414 if (ResponseObject->HasField("access"))
415 {
416 FailedResponse = !ResponseObject->GetBoolField("access");
417 }
418
419 if (FailedResponse == false)
420 {
421 OnRequestComplete.Broadcast(EApexRequestType::Login, Request);
423 }
424 }
425 }
426
427 if (FailedResponse)
428 {
429 OnUserVerificationFail(Request);
430 }
431}
432
433void UApexAPI::OnUserVerificationFail(const UVaRestRequestJSON* Request)
434{
435 Log("User module access verification failed with response code %i", Request->GetResponseCode());
436
437 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
438 FAPEXRequestFailed APEXFailedRequest;
439 if (Request->GetResponseCode() == 200)
440 {
441 if (ResponseObject->GetRootObject()->HasField("access"))
442 {
443 APEXFailedRequest.Error = true;
444 APEXFailedRequest.Message = "User does not have access to this module.";
445 }
446 else
447 {
448 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
449 }
450 }
451
452 OnRequestFail.Broadcast(EApexRequestType::Login, Request, APEXFailedRequest);
454}
455
456bool UApexAPI::JoinSession(FString InScenarioId, const FXAPIExtension& InContextExtension, bool bIsMultiplayer)
457{
459 {
460 Error("Cannot join session with no active login.");
461 return false;
462 }
463
464 if (!InScenarioId.IsEmpty())
465 {
466 ScenarioId = InScenarioId;
467 }
468 else
469 {
470 ScenarioId = TEXT("<Unavailable>");
471 }
472
473 if (bSessionInProgress == true)
474 {
475 Error("Session is already in progress. The previous session didn't complete or a new session was started during an active session.");
476 }
477 else
478 {
479 GetWorld()->GetTimerManager().SetTimer(HeartbeatHandle, this, &UApexAPI::SendHeartbeat, 10.0f, true, 10.0f);
480 }
481
482 CurrentSessionGuid = FGuid::NewGuid();
483
484 // Finish filling this out
485 FXAPIStatement Statement;
486 FXAPIAgent Actor;
488 Actor.Name = FString::Printf(TEXT("%s %s"), *CurrentActiveLogin.FirstName, *CurrentActiveLogin.LastName);
489
490 FXAPIVerb Verb;
492 Verb.Display.Add("en", "Joined Session");
493
494 FXAPIActivity Activity;
495 FStringFormatOrderedArguments IdFormat({ LoadedModuleId, ScenarioId });
496 Activity.ID = FString::Format(TEXT("https://pixovr.com/xapi/objects/{0}/{1}"), IdFormat);
497
498 FXAPIContext Context;
500 Context.Revision = ModuleVersion;
501 Context.Platform = Platform;
502
503 FXAPIExtension ContextExtension;
504 if (!InContextExtension.IsEmpty())
505 {
506 ContextExtension.Clone(InContextExtension);
507 }
508
509 Context.Extensions = ContextExtension;
510 Context.Extensions.AddCustomString(Apex::Extensions::MODULE_IDS, FString::FromInt(LoadedModuleId));
511 Context.Extensions.AddString("device_id", DeviceId);
512 Context.Extensions.AddString("device_model", DeviceModel);
513
514 if (bIsMultiplayer)
515 {
516 Context.Extensions.AddString("multiplayer", "true");
517 }
518
519 Statement.Actor = Actor;
520 Statement.Verb = Verb;
521 Statement.Target = Activity;
522 Statement.Context = Context;
523
524 FJoinSessionData JoinData;
525 JoinData.DeviceId = DeviceId;
526 JoinData.IpAddress = "0.0.0.0"; // We should get rid of this as there isn't a good way to get external IP addresses
527 JoinData.ModuleId = LoadedModuleId;
528 JoinData.Uuid = CurrentSessionGuid.ToString();
530 JoinData.JsonData = Statement;
531
532 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
533 FString RequestURL = URL + "/event";
534 Request->SetURL(RequestURL);
535 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
536
537 UVaRestJsonObject* JoinSessionJson = VaRestSubsystem->ConstructVaRestJsonObject();
538 JoinSessionJson->SetRootObject(JoinData.ToJsonObject());
539
540 Request->SetRequestObject(JoinSessionJson);
541
542 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnJoinSessionComplete(Request); });
543 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnJoinSessionFail(Request); });
544
545 Request->ExecuteProcessRequest();
546
547 return true;
548}
549
550void UApexAPI::OnJoinSessionComplete(const UVaRestRequestJSON* Request)
551{
552 Log("Session was successfully joined.");
553 if (Request->GetResponseCode() == 200)
554 {
555 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
556 FPSessionData JoinSessionData;
557
558 JoinSessionData.FromJsonObject(ResponseObject->GetRootObject());
559 SessionId = JoinSessionData.SessionId;
560 }
561
562 bSessionInProgress = true;
565}
566
567void UApexAPI::OnJoinSessionFail(const UVaRestRequestJSON* Request)
568{
569 Log("Failed to join session. %d", Request->GetResponseCode());
570 bSessionInProgress = false;
571 CurrentSessionGuid.Invalidate();
572
573 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
574 FAPEXRequestFailed APEXFailedRequest;
575
576 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
577
578 OnRequestFail.Broadcast(EApexRequestType::JoinSession, Request, APEXFailedRequest);
580}
581
582bool UApexAPI::CompleteSession(const FSessionData& InSessionData)
583{
585 {
586 Error("Cannot complete session with no active login.");
587 return false;
588 }
589
590 if (bSessionInProgress == false)
591 {
592 Error("No current session in progress.");
593 return false;
594 }
595
596 GetWorld()->GetTimerManager().ClearTimer(HeartbeatHandle);
597
598 // Create our actor
599 FXAPIAgent Actor;
601 Actor.Name = FString::Printf(TEXT("%s %s"), *CurrentActiveLogin.FirstName, *CurrentActiveLogin.LastName);
602
603 // Create our verb
604 FXAPIVerb Verb;
606 Verb.Display.Add("en", "Completed Session");
607
608 // Create the session activity
609 FXAPIActivity Activity;
610 Activity.ID = FString::Printf(TEXT("https://pixovr.com/xapi/objects/%d/%s"), LoadedModuleId, *ScenarioId);
611
612 // Create our context
613 FXAPIContext Context;
615 Context.Revision = ModuleVersion;
616 Context.Platform = Platform;
617
618 // Build an extension for the context
619 Context.Extensions = InSessionData.AdditionalContextData;
620 Context.Extensions.AddCustomString(Apex::Extensions::MODULE_IDS, FString::FromInt(LoadedModuleId));
621 Context.Extensions.AddString("device_id", DeviceId);
622 Context.Extensions.AddString("device_model", DeviceModel);
623
624 // Create our results
625 FXAPIResult Result;
626 Result.Completion = InSessionData.Complete;
627 Result.Success = InSessionData.Success;
628 // Add score to the results
629 Result.Score.Min = InSessionData.ScoreMin;
630 Result.Score.Max = InSessionData.ScoreMax;
631 Result.Score.Raw = InSessionData.Score;
632 Result.Score.Scaled = InSessionData.ScoreScaled;
633 Result.Duration = FTimespan::FromSeconds(InSessionData.Duration);
634 Result.Extensions = InSessionData.AdditionalResultData;
635
636 // Create our statement and add the pieces
637 FXAPIStatement Statement;
638 Statement.Actor = Actor;
639 Statement.Verb = Verb;
640 Statement.Target = Activity;
641 Statement.Context = Context;
642 Statement.Result = Result;
643
644 FCompleteSessionData SessionData;
645 SessionData.DeviceId = DeviceId;
646 SessionData.ModuleId = LoadedModuleId;
647 SessionData.Uuid = CurrentSessionGuid.ToString();
649 SessionData.JsonData = Statement;
650 SessionData.SessionData = InSessionData;
651
652 // Now we create our request and send it!
653 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
654 FString RequestURL = URL + "/event";
655 Request->SetURL(RequestURL);
656 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
657
658 UVaRestJsonObject* CompleteSessionJson = VaRestSubsystem->ConstructVaRestJsonObject();
659 CompleteSessionJson->SetRootObject(SessionData.ToJsonObject());
660
661 Request->SetRequestObject(CompleteSessionJson);
662
663 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnCompleteSessionComplete(Request); });
664 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnCompleteSessionFail(Request); });
665
666 Request->ExecuteProcessRequest();
667
668 return true;
669}
670
671void UApexAPI::OnCompleteSessionComplete(const UVaRestRequestJSON* Request)
672{
673 Log("Session complete!");
674 bSessionInProgress = false;
675 CurrentSessionGuid.Invalidate();
678}
679
680void UApexAPI::OnCompleteSessionFail(const UVaRestRequestJSON* Request)
681{
682 Warn("Failed to complete session. %d", Request->GetResponseCode());
683
684 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
685 FAPEXRequestFailed APEXFailedRequest;
686
687 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
688
689 OnRequestFail.Broadcast(EApexRequestType::CompleteSession, Request, APEXFailedRequest);
691}
692
694{
695 FXAPIStatement EventStatement = InStatement;
697 {
698 Error("Cannot complete session with no active login.");
699 return false;
700 }
701
702 if (bSessionInProgress == false)
703 {
704 Error("No current session in progress.");
705 return false;
706 }
707
708 if (EventStatement.IsEmpty())
709 {
710 Error("No event data to send.");
711 return false;
712 }
713
714 if (!EventStatement.Actor.IsEmpty())
715 {
716 Warn("Actor data should not be filled out.");
717 }
718
719 if (EventStatement.Verb.IsEmpty())
720 {
721 Error("Verb missing from eventStatement.");
722 return false;
723 }
724
725 if (EventStatement.Verb.ID.IsEmpty())
726 {
727 Error("Verb ID missing from eventStatement.");
728 return false;
729 }
730
731 if (EventStatement.Target.IsEmpty())
732 {
733 Error("Object (target) missing from eventStatement.");
734 return false;
735 }
736
737 EventStatement.Actor.MBox = CurrentActiveLogin.Email;
738 EventStatement.Actor.Name = FString::Printf(TEXT("%s %s"), *CurrentActiveLogin.FirstName, *CurrentActiveLogin.LastName);
739
740 EventStatement.Context.Registration = CurrentSessionGuid;
741 EventStatement.Context.Revision = ModuleVersion;
742 EventStatement.Context.Platform = Platform;
743
744 EventStatement.Context.Extensions.AddString("device_id", DeviceId);
745 EventStatement.Context.Extensions.AddString("device_model", DeviceModel);
746
747 FSessionEventData Event;
748 Event.DeviceId = DeviceId;
749 Event.ModuleId = LoadedModuleId;
750 Event.Uuid = CurrentSessionGuid.ToString();
752 Event.JsonData = EventStatement;
753
754 // Now we create our request and send it!
755 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
756 FString RequestURL = URL + "/event";
757 Request->SetURL(RequestURL);
758 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
759
760 UVaRestJsonObject* CompleteSessionJson = VaRestSubsystem->ConstructVaRestJsonObject();
761 CompleteSessionJson->SetRootObject(Event.ToJsonObject());
762
763 Request->SetRequestObject(CompleteSessionJson);
764
765 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnSendSessionEventComplete(Request); });
766 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnSendSessionEventFail(Request); });
767
768 Request->ExecuteProcessRequest();
769
770 return true;
771}
772
773void UApexAPI::OnSendSessionEventComplete(const UVaRestRequestJSON* Request)
774{
775 Log("Session event was sent successfully.");
778}
779
780void UApexAPI::OnSendSessionEventFail(const UVaRestRequestJSON* Request)
781{
782 Warn("Failed to send session event. %d", Request->GetResponseCode());
783
784 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
785 FAPEXRequestFailed APEXFailedRequest;
786
787 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
788
789 OnRequestFail.Broadcast(EApexRequestType::SessionEvent, Request, APEXFailedRequest);
791}
792
793bool UApexAPI::FetchTopTen(FString Scenario, int OrgUnit)
794{
795 return FetchTopTen(-1, -1.f, Scenario, OrgUnit);
796}
797
799{
801}
802
803bool UApexAPI::FetchTopTenByUser(int UserId, FString Scenario, int OrgUnit)
804{
805 return FetchTopTen(UserId, -1.f, Scenario, OrgUnit);
806}
807
808bool UApexAPI::FetchTopTenByTimeRange(float TimePriorToToday, FString Scenario, int OrgUnit)
809{
810 return FetchTopTen(-1, TimePriorToToday, Scenario, OrgUnit);
811}
812
813bool UApexAPI::FetchTopTen(int UserId, float TimePriorToToday, FString Scenario, int OrgUnit)
814{
816 {
817 Error("Cannot complete session with no active login.");
818 return false;
819 }
820
821 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::GET, EVaRestRequestContentType::none);
822 FString URLFormat = "{url}/analytics/top10/module/{moduleId}";
823 FStringFormatNamedArguments FormatArguments;
824
825 if (UserId >= 0)
826 {
827 URLFormat += "/user/{userId}";
828 }
829
830 FString DataQueryFormat = "?";
831
832 if (!Scenario.IsEmpty())
833 {
834 DataQueryFormat += "scenario={moduleId}/{scenario}&";
835 }
836
837 if (TimePriorToToday > 0.0f)
838 {
839 DataQueryFormat += "dateRange={dateRange}&";
840 }
841
842 if (OrgUnit >= 0)
843 {
844 DataQueryFormat += "orgUnit={orgUnit}&";
845 }
846
847 if (DataQueryFormat.EndsWith("&"))
848 {
849 DataQueryFormat.RemoveFromEnd("&");
850 }
851
852 URLFormat += DataQueryFormat;
853
854 FormatArguments.Add("url", FStringFormatArg(URL));
855 FormatArguments.Add("moduleId", FStringFormatArg(LoadedModuleId));
856 FormatArguments.Add("userId", FStringFormatArg(UserId));
857 FormatArguments.Add("dateRange", FStringFormatArg(TimePriorToToday));
858 FormatArguments.Add("scenario", FStringFormatArg(Scenario));
859 FormatArguments.Add("orgUnit", FStringFormatArg(OrgUnit));
860 FString AnalyticsURL = FString::Format(*URLFormat, FormatArguments);
861 Request->SetURL(AnalyticsURL);
862 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
863
864 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnTopTenComplete(Request); });
865 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { OnTopTenFail(Request); });
866
867 Request->ExecuteProcessRequest();
868
869 return true;
870}
871
872void UApexAPI::OnTopTenComplete(const UVaRestRequestJSON* Request)
873{
874 bool FailedResponse = true;
875 if (Request->GetResponseCode() == 200)
876 {
877 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
878 if (ResponseObject->HasField("error"))
879 {
880 if (UVaRestJsonValue* ErrorField = ResponseObject->GetField("error"))
881 {
882 if (ErrorField->GetType() == EVaJson::Boolean && !ErrorField->AsBool())
883 {
884 Log("Successfully fetched top ten data!");
885
886 // It's not a failed response!
887 FailedResponse = false;
888
889 FTopTenData FetchedTopTenData;
890 FetchedTopTenData.FromJsonObject(ResponseObject->GetRootObject());
891
892 OnFetchTopTenComplete.Broadcast(Request, FetchedTopTenData);
893 OnStaticFetchTopTenComplete.Broadcast(Request, FetchedTopTenData);
894 }
895 }
896 }
897 }
898
899 if (FailedResponse)
900 {
901 OnTopTenFail(Request);
902 }
903}
904
905void UApexAPI::OnTopTenFail(const UVaRestRequestJSON* Request)
906{
907 Log("Fetch Top Ten failed with response code %i", Request->GetResponseCode());
908
909 UVaRestJsonObject* ResponseObject = Request->GetResponseObject();
910 FAPEXRequestFailed APEXFailedRequest;
911
912 APEXFailedRequest.FromJsonObject(ResponseObject->GetRootObject());
913
914 OnFetchTopTenFail.Broadcast(Request, APEXFailedRequest);
915 OnStaticFetchTopTenFail.Broadcast(Request, APEXFailedRequest);
916}
917
919{
920 if (SessionId < 0)
921 {
922 Error("Trying to send heartbeat without a valid session.");
923 return;
924 }
925
926 FHeartbeatEvent HeartbeatEvent;
927 HeartbeatEvent.SessionId = SessionId;
928
929 UVaRestRequestJSON* Request = VaRestSubsystem->ConstructVaRestRequestExt(EVaRestRequestVerb::POST, EVaRestRequestContentType::json);
930 FString RequestURL = URL.Replace(TEXT("modules."), TEXT("")) + "/heartbeat/pulse";
931 Request->SetURL(RequestURL);
932 Request->SetHeader("Authorization: Bearer", CurrentActiveLogin.SessionToken);
933
934 UVaRestJsonObject* HeartbeatJson = VaRestSubsystem->ConstructVaRestJsonObject();
935 HeartbeatJson->SetRootObject(HeartbeatEvent.ToJsonObject());
936
937 Request->SetRequestObject(HeartbeatJson);
938
939 Request->OnStaticRequestComplete.AddLambda([&](UVaRestRequestJSON* Request) -> void { Log("Heartbeat sent.") });
940 Request->OnStaticRequestFail.AddLambda([&](UVaRestRequestJSON* Request) -> void { Log("Failed to send heartbeat.") });
941
942 Request->ExecuteProcessRequest();
943}
944
945#undef Fatal
946#undef Error
947#undef Warn
948#undef Log
#define Error(pmt,...)
Definition ApexAPI.cpp:16
#define Fatal(pmt,...)
Definition ApexAPI.cpp:17
#define Warn(pmt,...)
Definition ApexAPI.cpp:15
DEFINE_LOG_CATEGORY_STATIC(LogApexAPI, Log, All)
#define Log(pmt,...)
Definition ApexAPI.cpp:14
@ Login
Definition ApexAPI.h:29
@ Logout
Definition ApexAPI.h:30
@ CompleteSession
Definition ApexAPI.h:33
@ Ping
Definition ApexAPI.h:28
@ JoinSession
Definition ApexAPI.h:31
@ SessionEvent
Definition ApexAPI.h:32
@ AuthorizationCode
static bool IsAvailable()
Definition ApexSDK.h:32
UApexSDKSettings * GetSettings() const
Definition ApexSDK.cpp:59
static FApexSDKModule & Get()
Definition ApexSDK.h:22
bool SendSessionEvent(const FXAPIStatement &InStatement)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:693
bool FetchTopTenByTimeRange(float TimePriorToToday, FString Scenario, int OrgUnit)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:808
void OnLogoutComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:345
bool IsLoggedIn()
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:257
void Login(const FString &InUserName, const FString &InPassword, bool bShouldLogout=true)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:229
bool bWebSocketEnabled
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:172
bool CompleteSession(const FSessionData &InSessionData)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:582
class UVaRestSubsystem * VaRestSubsystem
Definition ApexAPI.h:319
FOnStaticApexRequestFail OnStaticRequestFail
Definition ApexAPI.h:347
bool JoinSession(FString InScenarioId, const FXAPIExtension &InContextExtension, bool bIsMultiplayer=false)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:456
FString Platform
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:127
void Ping()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:174
class UPixoLauncherSubsystem * LauncherSubsystem
Definition ApexAPI.h:321
bool FetchTopTenByUser(int UserId, FString Scenario, int OrgUnit)
UFUNCTION(BlueprintCallable, Category = "Apex|API", meta=(DisplayName = "Fetch Top Ten By User"))
Definition ApexAPI.cpp:803
int SessionId
Definition ApexAPI.h:325
FOnStaticApexRequestComplete OnStaticRequestComplete
Definition ApexAPI.h:346
void OnTopTenFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:905
FOnStaticApexAuthCodeRetrieved OnStaticAuthorizationCodeRetrieved
Definition ApexAPI.h:397
void OnLoginComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:262
void OnJoinSessionComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:550
bool IsWebSocketConnected()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:144
FOnApexRequestComplete OnRequestComplete
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:338
void HandleLogin(class UVaRestJsonObject *LoginJsonObject)
Definition ApexAPI.cpp:295
void ConnectWebSocketService()
UFUNCTION(BlueprintCallable, Category = "Apex|API", meta = (Tooltip = "This function only needs to be...
Definition ApexAPI.cpp:155
FTimerHandle HeartbeatHandle
Definition ApexAPI.h:324
bool HasLaunchAuthToken()
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:252
FGuid CurrentSessionGuid
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:151
void OnJoinSessionFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:567
FString ModuleVersion
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:121
void SendHeartbeat()
Definition ApexAPI.cpp:918
FOnApexTopTenDataFail OnFetchTopTenFail
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:360
FOnApexWebSocketConnectFailed OnWebSocketConnectFailed
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:377
FOnApexRequestFail OnRequestFail
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:344
void SetupModuleSettings()
Definition ApexAPI.cpp:26
FOnApexWebSocketConnected OnWebSocketConnected
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:371
void OnSendSessionEventFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:780
void OnPingFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:193
void FilloutLaunchToken()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:224
FString LaunchToken
Definition ApexAPI.h:323
void OnLogoutFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:363
void OnSendSessionEventComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:773
FOnStaticApexWebSocketDisconnected OnStaticWebSocketDisconnected
Definition ApexAPI.h:395
void RequestAuthorizationCode()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:166
FOnApexTopTenDataComplete OnFetchTopTenComplete
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:354
virtual void Initialize(FSubsystemCollectionBase &Collection) override
Definition ApexAPI.cpp:90
void Logout()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:319
FString WebSocketURL
The API Websocket URL.
Definition ApexAPI.h:103
FString ScenarioId
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:109
FOnStaticApexTopTenDataFail OnStaticFetchTopTenFail
Definition ApexAPI.h:364
TUniquePtr< ApexWebSocket > ApexSocket
Definition ApexAPI.h:327
FUserSessionData CurrentActiveLogin
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:157
void VerifyModuleAccess(int InModuleId)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:376
bool FetchTopTen(FString Scenario, int OrgUnit)
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:793
class UApexSDKSettings * ApexSettings
Definition ApexAPI.h:320
FOnStaticApexTopTenDataComplete OnStaticFetchTopTenComplete
Definition ApexAPI.h:362
void OnUserVerificationComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:404
FString DeviceModel
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:139
FOnApexAuthCodeRetrieved OnAuthorizationCodeRetrieved
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:389
void OnTopTenComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:872
FString URL
The API URL.
Definition ApexAPI.h:92
void OnPingComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:186
TSharedRef< FJsonObject > GetUserJsonObject(TSharedRef< FJsonObject > &RootJsonObject)
Definition ApexAPI.cpp:309
int LoadedModuleId
UPROPERTY(BlueprintReadWrite, Meta=(DisplayName="Module Id"))
Definition ApexAPI.h:115
void LoginWithAuthToken()
UFUNCTION(BlueprintCallable, Category = "Apex|API")
Definition ApexAPI.cpp:206
FOnApexWebSocketDisconnected OnWebSocketDisconnected
UPROPERTY(BlueprintAssignable, Category = "Apex|Event")
Definition ApexAPI.h:383
FString DeviceId
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:133
void OnUserVerificationFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:433
void OnLoginFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:281
bool bSessionInProgress
UPROPERTY(BlueprintReadOnly)
Definition ApexAPI.h:166
void OnCompleteSessionFail(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:680
FOnStaticApexWebSocketConnectFailed OnStaticWebSocketConnectFailed
Definition ApexAPI.h:393
FOnStaticApexWebSocketConnected OnStaticWebSocketConnected
Definition ApexAPI.h:391
void OnCompleteSessionComplete(const class UVaRestRequestJSON *Request)
Definition ApexAPI.cpp:671
bool FetchTopTenByCurrentUser(FString Scenario)
UFUNCTION(BlueprintCallable, Category = "Apex|API", meta = (DisplayName = "Fetch Top Ten By User"))
Definition ApexAPI.cpp:798
FString ModuleVersion
UPROPERTY(Config, EditAnywhere, Category = "Apex", meta = (DisplayName = "Module Version"))
int ModuleId
UPROPERTY(Config, EditAnywhere, Category = "Apex", meta = (DisplayName = "Module ID"))
FString ServerURI
UPROPERTY(Config, EditAnywhere, Category = "Apex")
UCLASS(BlueprintType, Blueprintable, DisplayName = "PixoVR Launcher")
FString GetDeviceSerialNumber()
UFUNCTION(BlueprintCallable, Category = "PixoVR|Launcher")
FString GetApplicationExtra(const FString &ExtraKey)
UFUNCTION(BlueprintCallable, Category = "PixoVR|Launcher")
static const FString PIXOVR_SESSION_JOINED
static const FString PIXOVR_SESSION_EVENT
static const FString PIXOVR_SESSION_COMPLETE
static const FString MODULE_IDS
static const FString COMPLETED_SESSION
static const FString JOINED_SESSION
USTRUCT(BlueprintType)
Definition ApexTypes.h:99
FString Message
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Failed Request")
Definition ApexTypes.h:121
bool Error
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Failed Request")
Definition ApexTypes.h:107
virtual void FromJsonObject(const TSharedPtr< FJsonObject > &JObject) override
Definition ApexTypes.h:131
USTRUCT(BlueprintType)
Definition ApexTypes.h:292
FString Uuid
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Complete Session")
Definition ApexTypes.h:301
int ModuleId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Complete Session")
Definition ApexTypes.h:313
FString DeviceId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Complete Session")
Definition ApexTypes.h:319
FXAPIStatement JsonData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Complete Session")
Definition ApexTypes.h:325
FString EventType
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Complete Session")
Definition ApexTypes.h:307
virtual TSharedPtr< FJsonObject > ToJsonObject() const override
Definition ApexTypes.h:359
FSessionData SessionData
Definition ApexTypes.h:328
USTRUCT(BlueprintType)
Definition ApexTypes.h:929
virtual TSharedPtr< FJsonObject > ToJsonObject() const override
Definition ApexTypes.h:942
int SessionId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PixoVR|Hearbeat Event")
Definition ApexTypes.h:937
USTRUCT(BlueprintType)
Definition ApexTypes.h:16
virtual TSharedPtr< FJsonObject > ToJsonObject() const
Definition ApexTypes.h:58
FString IpAddress
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:48
FString DeviceId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:42
int ModuleId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:36
FXAPIStatement JsonData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:54
FString Uuid
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:24
FString EventType
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Join Session")
Definition ApexTypes.h:30
USTRUCT(BlueprintType)
Definition ApexTypes.h:159
virtual void FromJsonObject(const TSharedPtr< FJsonObject > &JObject) override
Definition ApexTypes.h:173
int SessionId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PixoVR|Platform|Session")
Definition ApexTypes.h:167
USTRUCT(BlueprintType)
Definition ApexTypes.h:193
bool Complete
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:202
float Score
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:214
float ScoreMin
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:226
float ScoreScaled
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:220
float ScoreMax
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:232
int Duration
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:238
FXAPIExtension AdditionalContextData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:245
FXAPIExtension AdditionalResultData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:251
bool Success
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Data")
Definition ApexTypes.h:208
USTRUCT(BlueprintType)
Definition ApexTypes.h:412
virtual TSharedPtr< FJsonObject > ToJsonObject() const override
Definition ApexTypes.h:449
FString DeviceId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Event")
Definition ApexTypes.h:438
FXAPIStatement JsonData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Event")
Definition ApexTypes.h:444
int ModuleId
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Event")
Definition ApexTypes.h:432
FString EventType
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Event")
Definition ApexTypes.h:426
FString Uuid
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|Session Event")
Definition ApexTypes.h:420
USTRUCT(BlueprintType)
Definition ApexTypes.h:855
virtual void FromJsonObject(const TSharedPtr< FJsonObject > &JObject) override
Definition ApexTypes.h:886
virtual void FromJsonObject(const TSharedPtr< FJsonObject > &JObject) override
Definition ApexTypes.h:601
int ID
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:544
FString FirstName
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:562
int OrgUnit
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:556
FString Email
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:574
FString LastName
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:568
FString SessionToken
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|User Session Data")
Definition ApexTypes.h:580
USTRUCT(BlueprintType)
Definition XAPITypes.h:565
FString ID
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Activity")
Definition XAPITypes.h:573
virtual bool IsEmpty() const override
Definition XAPITypes.h:594
USTRUCT(BlueprintType)
Definition XAPITypes.h:380
virtual bool IsEmpty() const override
Definition XAPITypes.h:421
FString MBox
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Agent")
Definition XAPITypes.h:395
FString Name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Agent")
Definition XAPITypes.h:388
USTRUCT(BlueprintType)
Definition XAPITypes.h:649
FString Revision
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Context")
Definition XAPITypes.h:685
FGuid Registration
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Context")
Definition XAPITypes.h:657
FXAPIExtension Extensions
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Context")
Definition XAPITypes.h:699
FString Platform
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Context")
Definition XAPITypes.h:692
USTRUCT(BlueprintType)
void Clone(const FXAPIExtension &InExtension)
TSharedPtr< FJsonValue > & AddString(FString InKey, const FString &InValue)
TSharedPtr< FJsonValue > & AddCustomString(FString InKey, const FString &InValue)
virtual bool IsEmpty() const override
FString Add(FString InLanguage, FString InValue)
Definition XAPITypes.h:57
USTRUCT(BlueprintType)
Definition XAPITypes.h:900
TOptional< FTimespan > Duration
Definition XAPITypes.h:914
FXAPIScore Score
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Result")
Definition XAPITypes.h:921
TOptional< bool > Success
Definition XAPITypes.h:905
TOptional< bool > Completion
Definition XAPITypes.h:903
FXAPIExtension Extensions
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Result")
Definition XAPITypes.h:928
FOptionalFloat Max
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Score")
Definition XAPITypes.h:833
FOptionalFloat Min
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Score")
Definition XAPITypes.h:826
FOptionalFloat Scaled
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Score")
Definition XAPITypes.h:812
FOptionalFloat Raw
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Score")
Definition XAPITypes.h:819
FXAPIAgent Actor
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Statement")
Definition XAPITypes.h:1032
FXAPIResult Result
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Statement")
Definition XAPITypes.h:1053
FXAPIContext Context
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Statement")
Definition XAPITypes.h:1060
FXAPIVerb Verb
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Statement")
Definition XAPITypes.h:1039
FXAPIActivity Target
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Statement")
Definition XAPITypes.h:1046
USTRUCT(BlueprintType)
Definition XAPITypes.h:1157
virtual bool IsEmpty() const override
Definition XAPITypes.cpp:60
USTRUCT(BlueprintType)
Definition XAPITypes.h:503
FString ID
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Verb")
Definition XAPITypes.h:511
FXAPILanguageMap Display
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Apex|XAPI|Verb")
Definition XAPITypes.h:518
virtual bool IsEmpty() const override
Definition XAPITypes.h:520