Documentation for the Unity C# Library
Loading...
Searching...
No Matches
ApexSystem.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Net.Http;
4using System.Text.RegularExpressions;
5using System.Threading.Tasks;
6using Newtonsoft.Json;
10using TinCan;
11using UnityEngine;
12using UnityEngine.XR;
13
14#if MANAGE_XR
15using MXR.SDK;
16#endif
17
18namespace PixoVR.Apex
19{
20 public delegate void PlatformResponse(ResponseType type, bool wasSuccessful, object responseData);
21
22 [DefaultExecutionOrder(-50)]
23 public class ApexSystem : ApexSingleton<ApexSystem>
24 {
25 private enum VersionParts : int
26 {
27 Major = 0,
28 Minor,
29 Patch,
30 }
31
32 public static string ServerIP
33 {
34 get { return Instance.serverIP; }
35 set { }
36 }
37
38 public static int ModuleID
39 {
40 get { return Instance.moduleID; }
41 set { Instance.moduleID = value; }
42 }
43
44 public static string ModuleName
45 {
46 get { return Instance.moduleName; }
47 set { Instance.moduleName = value; }
48 }
49
50 public static string ModuleVersion
51 {
52 get { return Instance.moduleVersion; }
53 set { Instance.moduleVersion = value; }
54 }
55
56 public static string ScenarioID
57 {
58 get { return Instance.scenarioID; }
59 set { Instance.scenarioID = value; }
60 }
61
63 {
64 get { return Instance.currentActiveLogin; }
65 set { }
66 }
67
68 public static bool RunSetupOnAwake
69 {
70 get { return Instance.runSetupOnAwake; }
71 set { Instance.runSetupOnAwake = value; }
72 }
73
74 public static bool LoginCheckModuleAccess
75 {
76 get { return Instance.loginCheckModuleAccess; }
77 set { }
78 }
79
80 public static string DeviceSerialNumber
81 {
82 get { return Instance.deviceSerialNumber; }
83 set { }
84 }
85
86 public static string PassedLoginToken
87 {
88 get { return Instance.loginToken; }
89 set { }
90 }
91
92 public static string OptionalData
93 {
94 get { return Instance.optionalParameter; }
95 set { Instance.optionalParameter = value; }
96 }
97
98 public static string ReturnTarget
99 {
100 get { return Instance.returnTargetParameter; }
101 set
102 {
103 if (value != null)
104 {
105 Instance.returnTargetParameter = value;
106 }
107 else
108 {
109 Instance.returnTargetParameter = "";
110 }
111
112 if (Instance.returnTargetParameter.Contains("://"))
113 {
114 TargetType = "url";
115 }
116 else
117 {
118 TargetType = "app";
119 }
120 }
121 }
122
123 public static string TargetType
124 {
125 get { return Instance.targetTypeParameter; }
126 private set { Instance.targetTypeParameter = value; }
127 }
128
129 [SerializeField, EndpointDisplay]
131
132 [SerializeField]
133 protected string serverIP = "";
134
135 [SerializeField]
136 protected int moduleID = 0;
137
138 [SerializeField]
139 protected string moduleName = "Generic";
140
141 [SerializeField]
142 protected string moduleVersion = "0.00.00";
143
144 [SerializeField]
145 protected string scenarioID = "Generic";
146
147 [SerializeField]
148 public bool runSetupOnAwake = true;
149
150 [SerializeField]
151 public bool loginCheckModuleAccess = true;
152
153 [SerializeField]
154 protected float heartbeatTime = 5.0f;
155
156 protected string webSocketUrl;
157 protected string deviceID;
158 protected string deviceModel;
159 protected string platform;
160 protected string clientIP;
161 protected Guid currentSessionID;
162 protected int heartbeatSessionID;
163 protected float heartbeatTimer;
164 protected bool sessionInProgress;
165 protected bool userAccessVerified = false;
166 protected string deviceSerialNumber = "";
167
168 protected string loginToken = "";
169 protected string optionalParameter = "";
170 protected string returnTargetParameter = "";
171 protected string targetTypeParameter = "";
172
174 protected APIHandler apexAPIHandler;
176 protected Task<bool> socketConnectTask;
177 protected Task socketDisconnectTask;
178
181
187
190
196
199
206 public PlatformResponse OnPlatformResponse = null;
213 void Awake()
217#if UNITY_IOS || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
219#endif
220 if (runSetupOnAwake)
222 Debug.Log("[ApexSystem] Running on awake!");
226 DontDestroyOnLoad(gameObject);
227#if MANAGE_XR
228 InitMXRSDK();
229#endif
232#if MANAGE_XR
233 async void InitMXRSDK()
235 await MXRManager.InitAsync();
236 MXRManager.System.OnDeviceStatusChange += OnDeviceStatusChanged;
237 deviceSerialNumber = MXRManager.System.DeviceStatus.serial;
238 }
240 void OnDeviceStatusChanged(DeviceStatus newDeviceStatus)
241 {
242 deviceSerialNumber = newDeviceStatus.serial;
244#endif
247 Application.deepLinkActivated += OnDeepLinkActivated;
248 if (!string.IsNullOrEmpty(Application.absoluteURL))
250 // Cold start and Application.absoluteURL not null so process Deep Link.
251 OnDeepLinkActivated(Application.absoluteURL);
253 }
255
256 void OnDeepLinkActivated(string url)
257 {
258 // Update DeepLink Manager global variable, so URL can be accessed from anywhere.
260 _ParsePassedData(urlArguments);
262
264 {
265 Debug.Log("SetupPlatformConfiguration");
266
267#if UNITY_ANDROID
269 {
270 Debug.Log("Found pixoconfig.cnf");
271
272 string configContent = PixoAndroidUtils.ReadFileFromSharedStorage("pixoconfig.cnf");
273
274 if (configContent.Length > 0)
275 {
276 Debug.Log("Configuration is not empty.");
277 ConfigurationTypes configData = JsonConvert.DeserializeObject<ConfigurationTypes>(configContent);
278 if (configData == null)
279 {
280 Debug.Log("Failed to deserialize the config.");
281 return;
282 }
283
284 // Parse out the platform target to utilize the unity built in config values
285 if (configData.Platform.Contains("NA", StringComparison.CurrentCultureIgnoreCase))
286 {
287 if (configData.Platform.Contains("Production", StringComparison.CurrentCultureIgnoreCase))
288 {
289 Debug.Log("NA Production platform target.");
290 PlatformTargetServer = PlatformServer.NA_PRODUCTION;
291 }
292
293 if (configData.Platform.Contains("Dev", StringComparison.CurrentCultureIgnoreCase))
294 {
295 Debug.Log("NA Dev platform target.");
297 }
298
299 if (configData.Platform.Contains("Stage", StringComparison.CurrentCultureIgnoreCase))
300 {
301 Debug.Log("NA Stage platform target.");
303 }
305 else if (configData.Platform.Contains("SA", StringComparison.CurrentCultureIgnoreCase))
306 {
307 Debug.Log("SA Production platform target.");
308 PlatformTargetServer = PlatformServer.SA_PRODUCTION;
309 }
310
311 // TODO (MGruber): Add a custom value, but this requires multiple configuration values to be saved.
312 // Need to save the normal headset api endpoint, web api endpoint and platform api endpoint. 3 VALUES! D:
313 }
314 }
315#endif
316 }
317
318 void SetupAPI()
319 {
320 Debug.Log("Mac Address: " + ApexUtils.GetMacAddress());
321 if (serverIP.Length == 0)
322 {
324 }
325
327
328 if (apexAPIHandler != null)
329 {
330 Debug.Log("[ApexSystem] Apex API Handler is not null!");
331 }
332
333 // TODO: Move to new plugin
336 apexAPIHandler.OnAPIResponse += OnAPIResponse;
337
338 if (webSocket != null)
339 {
341 {
343 }
344 }
345
346 webSocket = new ApexWebsocket();
348 webSocket.OnConnectFailed.AddListener((reason) => OnWebSocketConnectFailed(reason));
349 webSocket.OnReceive.AddListener((data) => OnWebSocketReceive(data));
350 webSocket.OnClosed.AddListener((reason) => OnWebSocketClosed(reason));
351
353
354 var applicationArugments = PixoPlatformUtilities.ParseApplicationArguments();
355 _ParsePassedData(applicationArugments);
356 if(!string.IsNullOrEmpty(loginToken))
357 {
358 Debug.Log($"[ApexSystem] Login Token: {loginToken}");
359 }
360 }
361
362 // TODO: Rename the entered 'returnTarget' and the passed returnTargetParameter.
363 void _ExitApplication(string returnTarget)
364 {
365 if (returnTarget == null)
367 returnTarget = "";
368 }
369
370 string returnTargetType = "app";
371
372 if (returnTarget.Contains("://"))
373 {
374 returnTargetType = "url";
375 }
376
377 Debug.Log("[ApexSystem] " + returnTarget + " " + returnTargetType);
378
379 string parameters = "";
380
381 Debug.Log("[ApexSystem] Building parameters for url.");
382
383 if (CurrentActiveLogin != null)
384 {
385 parameters += "pixotoken=" + CurrentActiveLogin.Token;
386 }
387
388 if (optionalParameter != null)
389 {
390 if (optionalParameter.Length > 0)
391 {
392 if (parameters.Length > 0)
393 parameters += "&";
394 parameters += "optional=" + optionalParameter;
395 }
396 }
397
398 if (returnTarget.Length > 0)
399 {
400 if (parameters.Length > 0)
401 parameters += "&";
402 parameters += "returntarget=" + returnTarget;
403 }
404
405 if (returnTargetType.Length > 0)
406 {
407 if (parameters.Length > 0)
408 parameters += "&";
409 parameters += "targettype=" + returnTargetType;
410 }
412 Debug.Log("[ApexSystem] Checking the return target parameter.");
413
414 if (returnTargetParameter != null)
415 {
416 if (returnTargetParameter.Length > 0)
417 {
418 Debug.Log("[ApexSystem] Had a valid return target parameter.");
419 if (targetTypeParameter.Equals("url", StringComparison.OrdinalIgnoreCase))
420 {
421 Debug.Log("[ApexSystem] Return Target is a URL.");
422
423 string returnURL = returnTargetParameter;
424 if (parameters.Length > 0)
425 {
426 if (!returnURL.Contains('?'))
427 returnURL += "?";
428 else
429 returnURL += "&";
430
431 returnURL += parameters;
432 }
433 Debug.Log("Custom Target: " + returnURL);
435 return;
436 }
437 else
438 {
439 Debug.Log("[ApexSystem] Return Target is a package name.");
440
441 List<string> keys = new List<string>(),
442 values = new List<string>();
443
444 Debug.Log("[ApexSystem] Adding pixo token.");
445
446 if (CurrentActiveLogin != null)
447 {
448 keys.Add("pixotoken");
449 values.Add(CurrentActiveLogin.Token);
450 }
451
452 Debug.Log("[ApexSystem] Adding optional.");
453
454 if (optionalParameter.Length > 0)
455 {
456 keys.Add("optional");
457 values.Add(optionalParameter);
458 }
459
460 Debug.Log("[ApexSystem] Adding return target.");
461
462 if (returnTarget.Length > 0)
463 {
464 keys.Add("returntarget");
465 values.Add(returnTarget);
466 }
467
468 Debug.Log("[ApexSystem] Adding return target type.");
469
470 if (returnTargetType.Length > 0)
471 {
472 keys.Add("targettype");
473 values.Add(returnTargetType);
474 }
475
476 PixoPlatformUtilities.OpenApplication(returnTargetParameter, keys.ToArray(), values.ToArray());
477 return;
478 }
479 }
480 }
481
483 }
484
485 string GetEndpointFromTarget(PlatformServer target)
486 {
487 return target.ToUrlString();
488 }
489
490 string GetWebEndpointFromPlatformTarget(PlatformServer target)
491 {
492 int targetValue = (int)target;
493 WebPlatformServer webTarget = (WebPlatformServer)targetValue;
494
495 return webTarget.ToUrlString();
496 }
497
498 string GetPlatformEndpointFromPlatformTarget(PlatformServer target)
499 {
500 int targetValue = (int)target;
501 APIPlatformServer apiTarget = (APIPlatformServer)targetValue;
502
503 return apiTarget.ToUrlString();
504 }
505
507 {
509
510 if (webSocketUrl.Contains("://"))
511 {
512 webSocketUrl = webSocketUrl.Split(new string[] { "://" }, 2, StringSplitOptions.RemoveEmptyEntries)[1];
513 }
514
515 if (webSocketUrl.Contains("/"))
516 {
517 webSocketUrl = webSocketUrl.Split(new string[] { "/" }, 2, StringSplitOptions.RemoveEmptyEntries)[0];
518 }
519
520 webSocketUrl = "wss://" + webSocketUrl + "/ws";
521 }
522
523 void Start()
524 {
526 {
527 Debug.LogWarning($"{moduleVersion} is an invalid module version.");
528 }
529 deviceID = SystemInfo.deviceUniqueIdentifier;
530 deviceModel = SystemInfo.deviceModel;
531 platform =
532 XRSettings.loadedDeviceName.Length > 0 ? XRSettings.loadedDeviceName : Application.platform.ToString();
533 clientIP = Utils.ApexUtils.GetLocalIP();
534 }
535
536 private void FixedUpdate()
537 {
538 if (webSocket != null)
539 {
541 }
542
544 {
545 heartbeatTimer -= Time.fixedDeltaTime;
547 if (heartbeatTimer <= 0.0f)
548 {
551 }
552 }
553 }
555 void ConnectWebsocket()
556 {
557 socketConnectTask = Task.Run(() => webSocket.Connect(new Uri(webSocketUrl)));
558 }
559
561 {
562 socketDisconnectTask = Task.Run(() => webSocket.CloseSocket());
563 }
564
566 {
567 Debug.Log("Websocket connected successfully.");
568 }
569
570 void OnWebSocketConnectFailed(string reason)
572 Debug.LogError("Websocket failed to connect with error: " + reason);
573 }
574
575 void OnWebSocketReceive(string data)
576 {
577 Debug.Log("Websocket received: " + data);
578 try
579 {
580 if (data.Contains("auth_code"))
581 {
582 var authCode = JsonConvert.DeserializeObject<AuthorizationCode>(data);
583 OnAuthorizationCodeReceived.Invoke(authCode.Code);
585
586 if (data.Contains("Token", StringComparison.OrdinalIgnoreCase))
587 {
588 object loginResponse = JsonConvert.DeserializeObject<LoginResponseContent>(data);
589 HandleLogin(true, loginResponse);
590 }
591 }
592 catch (Exception ex)
593 {
594 Debug.Log(ex.Message);
595 }
596 }
597
598 void OnWebSocketClosed(System.Net.WebSockets.WebSocketCloseStatus reason)
599 {
600 Debug.Log("Websocket closed with reason: " + reason);
601 }
602
604 {
605 if (IsModuleVersionOnlyNumerical() == false)
606 return false;
607
608 string[] moduleVersionParts = moduleVersion.Split('.');
609
610 if (moduleVersionParts.Length != 3)
611 return false;
612
613 if (!IsModuleMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Major]))
614 return false;
615
616 if (!IsModuleNonMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Minor]))
617 return false;
619 if (!IsModuleNonMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Patch]))
620 return false;
621
622 return true;
624
625 static readonly Regex VersionValidator = new Regex(@"^[0123456789.]+$");
626
628 {
629 return VersionValidator.IsMatch(moduleVersion);
630 }
631
632 bool IsModuleNonMajorVersionPartValid(string modulePart)
633 {
634 if (modulePart.Length <= 0)
635 return false;
636
637 if (modulePart.Length > 2)
638 return false;
639
640 return true;
641 }
642
643 bool IsModuleMajorVersionPartValid(string modulePart)
644 {
645 if (modulePart.Length <= 0)
646 return false;
647
648 if (modulePart.StartsWith("0"))
649 return false;
650
651 return true;
652 }
653
654 [Obsolete("ReturnToHub has been deprecated, please use ExitApplication.", true)]
655 public static void ReturnToHub()
656 {
657 Instance._ReturnToHub();
658 }
659
660 public static void ExitApplication(string returnTarget = "")
661 {
662 Instance._ExitApplication(returnTarget);
663 }
664
665 public static bool RequestAuthorizationCode()
666 {
667 return Instance._RequestAuthorizationCode();
668 }
669
670 public static void ChangePlatformServer(PlatformServer newServer)
671 {
672 Instance._ChangePlatformServer(newServer);
674
675 public static void Ping()
676 {
677 Instance._Ping();
678 }
679
680 public static bool LoginWithToken()
681 {
682 return LoginWithToken(Instance.loginToken);
683 }
684
685 public static bool LoginWithToken(string token)
686 {
687 return Instance._LoginWithToken(token);
688 }
689
690 public static bool Login(LoginData login)
692 return Instance._Login(login);
693 }
694
695 public static bool Login(string username, string password)
696 {
697 return Instance._Login(username, password);
698 }
699
700 public static bool CheckModuleAccess(int targetModuleID = -1)
701 {
702 return Instance._CheckModuleAccess(targetModuleID);
704
705 public static bool JoinSession(string scenarioID = null, Extension contextExtension = null)
706 {
707 return Instance._JoinSession(scenarioID, contextExtension);
709
710 public static bool CompleteSession(
711 SessionData currentSessionData,
712 Extension contextExtension = null,
713 Extension resultExtension = null
714 )
715 {
716 return Instance._CompleteSession(currentSessionData, contextExtension, resultExtension);
717 }
719 public static bool SendSimpleSessionEvent(string action, string targetObject, Extension contextExtension)
720 {
721 return Instance._SendSimpleSessionEvent(action, targetObject, contextExtension);
722 }
724 public static bool SendSessionEvent(Statement eventStatement)
725 {
726 return Instance._SendSessionEvent(eventStatement);
727 }
729 public static bool GetCurrentUser()
730 {
731 return GetUser();
732 }
734 public static bool GetUser(int userId = -1)
735 {
736 return Instance._GetUser(userId);
737 }
739 public static bool GetCurrentUserModules()
740 {
741 return GetUserModules();
742 }
744 public static bool GetUserModules(int userId = -1)
745 {
746 return Instance._GetUserModules(userId);
747 }
749 public static bool GetModulesList(string platformName)
750 {
751 return Instance._GetModuleList(platformName);
752 }
754 protected void _ChangePlatformServer(PlatformServer newServer)
755 {
756 PlatformTargetServer = newServer;
757
759 }
760
761 protected void _Ping()
762 {
764 }
765
766 public bool _LoginWithToken(string token)
768 if (token.Length <= 0)
769 {
770 return false;
771 }
773 Debug.Log($"[ApexSystem] Logging in with token: {token}");
775
776 return true;
778
779 protected bool _Login(LoginData login)
780 {
781 Debug.Log("[ApexSystem] _Login called.");
782 if (apexAPIHandler == null)
783 {
784 Debug.Log("[ApexSystem] API Handler is null.");
785 OnLoginFailed.Invoke(
787 "There was an error reaching the platform, please contact your administrator."
788 )
789 );
790 return false;
791 }
793 if (login.Login.Length <= 0)
794 {
795 Debug.Log("[Login] No user name.");
796 OnLoginFailed.Invoke(GenerateFailureResponse("No username or email entered."));
797 return false;
798 }
799
800 if (login.Password.Length <= 0)
801 {
802 Debug.Log("[Login] No password.");
803 login.Password = "<empty>";
804 }
805
806 apexAPIHandler.Login(login);
807
808 Debug.Log("[ApexSystem] Login called.");
810 return true;
811 }
812
813 protected bool _Login(string username, string password)
815 return _Login(new LoginData(username, password));
816 }
817
818 protected FailureResponse GenerateFailureResponse(string message)
819 {
820 FailureResponse failureResponse = new FailureResponse();
821 failureResponse.Error = "true";
822 failureResponse.HttpCode = "400";
823 failureResponse.Message = message;
824
825 return failureResponse;
826 }
828 protected void _ParsePassedData(Dictionary<string, string> arguments)
829 {
830 if (arguments == null)
831 {
832 Debug.Log("No arguments found for the application.");
833 return;
834 }
835
836 if (arguments.ContainsKey("optional"))
837 optionalParameter = arguments["optional"];
838
839 if (arguments.ContainsKey("returntarget"))
840 returnTargetParameter = arguments["returntarget"];
841
842 if (arguments.ContainsKey("targettype"))
843 targetTypeParameter = arguments["targettype"];
844
845 if (arguments.ContainsKey("pixotoken"))
846 loginToken = arguments["pixotoken"];
847 }
848
849
850
851 public bool _CheckModuleAccess(int targetModuleID = -1)
852 {
853 Debug.Log("[ApexSystem] _CheckModuleAccess called.");
854
855 if (currentActiveLogin == null)
856 {
857 Debug.LogError("[ApexSystem] Cannot check user's module access with no active login.");
858 return false;
859 }
860
861 if (targetModuleID <= -1)
862 {
863 targetModuleID = moduleID;
864 }
865
867
868 return true;
869 }
870
871 protected bool _JoinSession(string newScenarioID = null, Extension contextExtension = null)
872 {
873 if (currentActiveLogin == null)
874 {
875 Debug.LogError("[ApexSystem] Cannot join session with no active login.");
876 return false;
877 }
878
879 if (userAccessVerified == false)
880 {
881 return false;
882 }
883
884 if (newScenarioID != null)
885 {
886 scenarioID = newScenarioID;
887 }
888
889 if (sessionInProgress == true)
890 {
891 Debug.LogError(
892 "[ApexSystem] Session is already in progress."
893 + " The previous session didn't complete or a new session was started during an active session."
894 );
895 }
896
897 currentSessionID = Guid.NewGuid();
898
899 Statement sessionStatement = new Statement();
900 Agent sessionActor = new Agent();
901 sessionActor.mbox = currentActiveLogin.Email;
902
903 Verb sessionVerb = new Verb();
904 sessionVerb.id = ApexVerbs.JOINED_SESSION;
905 sessionVerb.display = new LanguageMap();
906 sessionVerb.display.Add("en", "Joined Session");
907
908 Activity sessionActivity = new Activity();
909 sessionActivity.id = string.Format("https://pixovr.com/xapi/objects/{0}/{1}", moduleID, scenarioID);
910
911 Context sessionContext = new Context();
912 sessionContext.registration = currentSessionID;
913 sessionContext.revision = moduleVersion;
914 sessionContext.platform = platform;
915
916 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
917
918 sessionStatement.actor = sessionActor;
919 sessionStatement.verb = sessionVerb;
920 sessionStatement.target = sessionActivity;
921 sessionStatement.context = sessionContext;
922
923 JoinSessionData sessionData = new JoinSessionData();
924 sessionData.DeviceId = deviceID;
925 sessionData.IpAddress = clientIP;
926 sessionData.ModuleId = moduleID;
927 sessionData.Uuid = currentSessionID.ToString();
928 sessionData.EventType = ApexEventTypes.PIXOVR_SESSION_JOINED;
929 sessionData.JsonData = sessionStatement;
930
932
933 return true;
934 }
935
936 protected bool _SendSimpleSessionEvent(string verbName, string targetObject, Extension contextExtension)
937 {
938 if (userAccessVerified == false)
939 return false;
940
941 if (verbName == null)
942 return false;
943
944 if (verbName.Length == 0)
945 return false;
946
947 Statement sessionStatement = new Statement();
948 Agent sessionActor = new Agent();
949 sessionActor.mbox = currentActiveLogin.Email;
950
951 Verb sessionVerb = new Verb();
952 sessionVerb.id = new Uri("https://pixovr.com/xapi/verbs/" + verbName.Replace(' ', '_').ToLower());
953 sessionVerb.display = new LanguageMap();
954 sessionVerb.display.Add("en", verbName);
955
956 Activity sessionActivity = new Activity();
957 sessionActivity.id = string.Format(
958 "https://pixovr.com/xapi/objects/{0}/{1}/{2}",
959 moduleID,
961 targetObject.Replace(' ', '_').ToLower()
962 );
963
964 Context sessionContext = new Context();
965 sessionContext.registration = currentSessionID;
966 sessionContext.revision = moduleVersion;
967 sessionContext.platform = platform;
968
969 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
970
971 sessionStatement.actor = sessionActor;
972 sessionStatement.verb = sessionVerb;
973 sessionStatement.target = sessionActivity;
974 sessionStatement.context = sessionContext;
975
976 SessionEventData sessionEvent = new SessionEventData();
977 sessionEvent.DeviceId = deviceID;
978 sessionEvent.ModuleId = ModuleID;
979 sessionEvent.Uuid = currentSessionID.ToString();
980 sessionEvent.EventType = ApexEventTypes.PIXOVR_SESSION_EVENT;
981 sessionEvent.JsonData = sessionStatement;
982
985 return true;
986 }
987
988 protected bool _SendSessionEvent(Statement eventStatement)
989 {
990 if (userAccessVerified == false)
991 {
992 return false;
993 }
994
995 if (currentActiveLogin == null)
996 {
997 Debug.LogError("[ApexSystem] Cannot send a session event with no active login.");
998 return false;
999 }
1000
1001 if (sessionInProgress == false)
1002 {
1003 Debug.LogError("[ApexSystem] No session in progress to send event for.");
1004 return false;
1005 }
1006
1007 if (eventStatement == null)
1008 {
1009 Debug.LogError("[ApexSystem] No event data to send.");
1010 return false;
1011 }
1012
1013 if (eventStatement.actor != null)
1014 {
1015 Debug.LogWarning("[ApexSystem] Actor data should not be filled out.");
1016 }
1017
1018 if (eventStatement.verb == null)
1019 {
1020 Debug.LogError("[ApexSystem] Verb missing from eventStatement.");
1021 return false;
1022 }
1023
1024 if (eventStatement.verb.id == null)
1025 {
1026 Debug.LogError("[ApexSystem] verb.id missing from eventStatement.");
1027 return false;
1028 }
1029
1030 if (eventStatement.target == null)
1031 {
1032 Debug.LogError("[ApexSystem] Object (target) missing from eventStatement.");
1033 return false;
1034 }
1035
1036 eventStatement.actor = new Agent();
1037 eventStatement.actor.mbox = currentActiveLogin.Email;
1038
1039 if (eventStatement.context == null)
1040 {
1041 eventStatement.context = new Context();
1042 }
1043
1044 eventStatement.context.registration = currentSessionID;
1045 eventStatement.context.revision = ModuleVersion;
1046 eventStatement.context.platform = platform;
1047
1048 eventStatement.context.extensions = AppendStandardContextExtension(eventStatement.context.extensions);
1049
1050 SessionEventData sessionEvent = new SessionEventData();
1051 sessionEvent.DeviceId = deviceID;
1052 sessionEvent.ModuleId = ModuleID;
1053 sessionEvent.Uuid = currentSessionID.ToString();
1054 sessionEvent.EventType = ApexEventTypes.PIXOVR_SESSION_EVENT;
1055 sessionEvent.JsonData = eventStatement;
1056
1058
1059 return true;
1060 }
1061
1062 protected bool _CompleteSession(
1063 SessionData currentSessionData,
1064 Extension contextExtension,
1065 Extension resultExtension
1066 )
1067 {
1068 if (userAccessVerified == false)
1069 {
1070 return false;
1071 }
1072
1073 if (currentActiveLogin == null)
1074 {
1075 Debug.LogError("[ApexSystem] Cannot complete session with no active login.");
1076 return false;
1077 }
1078
1079 if (sessionInProgress == false)
1080 {
1081 Debug.LogError("[ApexSystem] No session in progress to complete.");
1082 return false;
1083 }
1084
1085 // Create our actor
1086 Agent sessionActor = new Agent();
1087 sessionActor.mbox = currentActiveLogin.Email;
1088
1089 // Create our verb
1090 Verb sessionVerb = new Verb();
1091 sessionVerb.id = ApexVerbs.COMPLETED_SESSION;
1092 sessionVerb.display = new LanguageMap();
1093 sessionVerb.display.Add("en", "Completed Session");
1094
1095 // Create the session activity
1096 Activity sessionActivity = new Activity();
1097 sessionActivity.id = string.Format("https://pixovr.com/xapi/objects/{0}/{1}", moduleID, scenarioID);
1098
1099 // Create our context
1100 Context sessionContext = new Context();
1101 sessionContext.registration = currentSessionID;
1102 sessionContext.revision = moduleVersion;
1103 sessionContext.platform = platform;
1104
1105 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
1106
1107 // Create our results
1108 Result sessionResult = new Result();
1109 sessionResult.completion = currentSessionData.Complete;
1110 sessionResult.success = currentSessionData.Success;
1111 // Add score to the results
1112 sessionResult.score = new Score();
1113 sessionResult.score.min = currentSessionData.MinimumScore;
1114 sessionResult.score.max = currentSessionData.MaximumScore;
1115 sessionResult.score.raw = currentSessionData.Score;
1116 sessionResult.score.scaled = DetermineScaledScore(
1117 currentSessionData.ScaledScore,
1118 currentSessionData.Score,
1119 currentSessionData.MaximumScore
1120 );
1121 sessionResult.duration = TimeSpan.FromSeconds(currentSessionData.Duration);
1122 if (resultExtension != null)
1123 {
1124 sessionResult.extensions = new Extensions(resultExtension.ToJObject());
1125 }
1126
1127 // Create our statement and add the pieces
1128 Statement sessionStatement = new Statement();
1129 sessionStatement.actor = sessionActor;
1130 sessionStatement.verb = sessionVerb;
1131 sessionStatement.target = sessionActivity;
1132 sessionStatement.context = sessionContext;
1133 sessionStatement.result = sessionResult;
1134
1135 CompleteSessionData sessionData = new CompleteSessionData();
1136 sessionData.DeviceId = deviceID;
1137 sessionData.ModuleId = moduleID;
1138 sessionData.Uuid = currentSessionID.ToString();
1139 sessionData.EventType = ApexEventTypes.PIXOVR_SESSION_COMPLETE;
1140 sessionData.JsonData = sessionStatement;
1141 sessionData.SessionDuration = currentSessionData.Duration;
1142 sessionData.Score = currentSessionData.Score;
1143 sessionData.ScoreMin = currentSessionData.MinimumScore;
1144 sessionData.ScoreMax = currentSessionData.MaximumScore;
1145 sessionData.ScoreScaled = DetermineScaledScore(
1146 currentSessionData.ScaledScore,
1147 currentSessionData.Score,
1148 currentSessionData.MaximumScore
1149 );
1150
1152
1153 return true;
1154 }
1155
1156 protected bool _SendHeartbeat()
1157 {
1158 Debug.Log("Sending heartbeat...");
1159 if (!sessionInProgress)
1160 return false;
1161
1162 if (currentActiveLogin == null)
1163 return false;
1164
1166
1167 return true;
1168 }
1169
1170 protected bool _GetUser(int userId = -1)
1171 {
1172 if (currentActiveLogin == null)
1173 return false;
1174
1175 if (userId < 0)
1176 {
1177 userId = currentActiveLogin.ID;
1178 }
1179
1181 return true;
1182 }
1183
1184 protected bool _GetUserModules(int userId = -1)
1185 {
1186 if (currentActiveLogin == null)
1187 return false;
1188
1189 if (userId < 0)
1190 {
1191 userId = currentActiveLogin.ID;
1192 }
1193
1195 return true;
1196 }
1197
1198 protected bool _GetModuleList(string platformName)
1199 {
1200 if (currentActiveLogin == null)
1201 return false;
1202
1204 return true;
1205 }
1206
1207 private float DetermineScaledScore(float scaledScore, float score, float maxScore)
1208 {
1209 float determinedScaledScore = scaledScore;
1210
1211 if (scaledScore < Mathf.Epsilon && score >= Mathf.Epsilon)
1212 {
1213 determinedScaledScore = (score / maxScore) * 100f;
1214 }
1215
1216 return determinedScaledScore;
1217 }
1219 private Extensions AppendStandardContextExtension(Extensions currentContextExtensions)
1220 {
1221 return AppendStandardContextExtension(new Extension(currentContextExtensions.ToJObject()));
1222 }
1223
1224 private Extensions AppendStandardContextExtension(Extension currentContextExtension)
1225 {
1226 Extension contextExtension;
1227 if (currentContextExtension != null)
1228 {
1229 contextExtension = currentContextExtension;
1230 }
1231 else
1233 contextExtension = new Extension();
1234 }
1235
1236 contextExtension.Add(ApexExtensionStrings.MODULE_ID, moduleID.ToString());
1237 contextExtension.AddSimple("device_id", deviceID);
1238 contextExtension.AddSimple("device_model", deviceModel);
1239 contextExtension.AddSimple("sdk_version", "unity-" + ApexUtils.SDKVersion);
1240
1241 return new Extensions(contextExtension.ToJObject());
1242 }
1243
1244 protected void OnAPIResponse(ResponseType response, HttpResponseMessage message, object responseData)
1245 {
1246 Debug.Log("[ApexSystem] On API Response");
1247 bool success = message.IsSuccessStatusCode;
1248 if (responseData is FailureResponse)
1249 {
1250 success = success && (responseData is IFailure) && (!(responseData as FailureResponse).HasErrored());
1251 }
1252
1253 switch (response)
1254 {
1255 case ResponseType.RT_PING:
1256 {
1257 if (success)
1258 {
1259 Debug.Log("[ApexSystem] Ping successful.");
1260 OnPingSuccess.Invoke(message);
1261 }
1262 else
1263 {
1264 Debug.Log("[ApexSystem] Ping failed.");
1265 OnPingFailed.Invoke(message);
1266 }
1267 break;
1268 }
1269 case ResponseType.RT_LOGIN:
1270 {
1271 Debug.Log("[ApexSystem] Calling to handle login.");
1272 HandleLogin(success, responseData);
1273 break;
1274 }
1275 case ResponseType.RT_GET_USER:
1276 {
1277 if (success)
1278 {
1279 OnGetUserSuccess.Invoke(responseData as GetUserResponseContent);
1280 }
1281 else
1282 {
1283 FailureResponse failureData = responseData as FailureResponse;
1284 Debug.Log(string.Format("[ApexSystem] Failed to get user.\nError: {0}", failureData.Message));
1285 OnGetUserFailed.Invoke(responseData as FailureResponse);
1286 }
1287 break;
1288 }
1289 case ResponseType.RT_GET_USER_MODULES:
1290 {
1291 if (success)
1293 OnGetUserModulesSuccess.Invoke(responseData as GetUserModulesResponse);
1294 }
1295 else
1296 {
1297 FailureResponse failureData = responseData as FailureResponse;
1298 Debug.Log(string.Format("[ApexSystem] Failed to get user.\nError: {0}", failureData.Message));
1299 OnGetUserFailed.Invoke(responseData as FailureResponse);
1300 }
1301 break;
1302 }
1303 case ResponseType.RT_SESSION_JOINED:
1304 {
1305 if (success)
1306 {
1307 JoinSessionResponse joinSessionResponse = responseData as JoinSessionResponse;
1308 Debug.Log(string.Format("[ApexSystem] Session Id is {0}.", joinSessionResponse.SessionId));
1309 heartbeatSessionID = joinSessionResponse.SessionId;
1310 sessionInProgress = true;
1311 OnJoinSessionSuccess.Invoke(message);
1312 }
1313 else
1314 {
1315 FailureResponse failureData = responseData as FailureResponse;
1316 Debug.Log(
1317 string.Format("[ApexSystem] Failed to join session.\nError: {0}", failureData.Message)
1318 );
1319 currentSessionID = Guid.Empty;
1320 sessionInProgress = false;
1321 OnJoinSessionFailed.Invoke(responseData as FailureResponse);
1322 }
1323 break;
1324 }
1325 case ResponseType.RT_SESSION_COMPLETE:
1326 {
1327 if (success)
1328 {
1329 sessionInProgress = false;
1330 currentSessionID = Guid.Empty;
1331 OnCompleteSessionSuccess.Invoke(message);
1332 }
1333 else
1334 {
1335 FailureResponse failureData = responseData as FailureResponse;
1336 Debug.Log(
1337 string.Format("[ApexSystem] Failed to complete session.\nError: {0}", failureData.Message)
1338 );
1339 OnCompleteSessionFailed.Invoke(responseData as FailureResponse);
1340 }
1341 break;
1342 }
1343 case ResponseType.RT_SESSION_EVENT:
1344 {
1345 if (success)
1346 {
1347 Debug.Log("[ApexSystem] Session event sent.");
1348 OnSendEventSuccess.Invoke(message);
1349 }
1350 else
1351 {
1352 FailureResponse failureData = responseData as FailureResponse;
1353 Debug.Log(
1354 string.Format("[ApexSystem] Failed to send session event.\nError: {0}", failureData.Message)
1355 );
1356 OnSendEventFailed.Invoke(responseData as FailureResponse);
1357 }
1358 break;
1359 }
1360 case ResponseType.RT_GET_USER_ACCESS:
1361 {
1362 if (success)
1363 {
1364 var userAccessResponseContent = responseData as UserAccessResponseContent;
1365 if (userAccessResponseContent.Access)
1366 {
1367 if (userAccessResponseContent.PassingScore.HasValue)
1368 {
1369 currentActiveLogin.MinimumPassingScore = userAccessResponseContent.PassingScore.Value;
1370 }
1371
1372 userAccessVerified = true;
1374 }
1375 else
1376 {
1377 currentActiveLogin = null;
1378 userAccessVerified = false;
1379 OnModuleAccessFailed.Invoke(
1380 new FailureResponse()
1381 {
1382 Error = "True",
1383 HttpCode = "401",
1384 Message = "User does not have access to module",
1385 }
1386 );
1387 }
1388 }
1389 else
1390 {
1391 FailureResponse failureData = responseData as FailureResponse;
1392 Debug.Log(
1393 string.Format(
1394 "[ApexSystem] Failed to get users module access data.\nError: {0}",
1395 failureData.Message
1396 )
1397 );
1398
1399 OnModuleAccessFailed.Invoke(responseData as FailureResponse);
1400 }
1401 break;
1402 }
1403 case ResponseType.RT_GET_MODULES_LIST:
1404 {
1405 if (success)
1406 {
1407 OnGetOrganizationModulesSuccess.Invoke(responseData as List<OrgModule>);
1408 }
1409 else
1410 {
1411 FailureResponse failureData = responseData as FailureResponse;
1412 Debug.Log(
1413 string.Format("[ApexSystem] Failed to get org modules.\nError: {0}", failureData.Message)
1414 );
1415
1416 OnGetOrganizationModulesFailed.Invoke(responseData as FailureResponse);
1417 }
1418
1419 break;
1420 }
1421 case ResponseType.RT_GEN_AUTH_LOGIN:
1422 {
1423 if (success)
1424 {
1426 }
1427 else
1428 {
1429 FailureResponse failureData = responseData as FailureResponse;
1430 Debug.Log(string.Format("[ApexSystem] Failed to get module.\nError: {0}", failureData.Message));
1431 OnGeneratedAssistedLoginFailed.Invoke(responseData as FailureResponse);
1432 }
1433 break;
1434 }
1435 default:
1436 {
1437 break;
1438 }
1439 }
1440
1441 if (OnPlatformResponse != null)
1442 {
1443 OnPlatformResponse.Invoke(response, success, responseData);
1444 }
1445 }
1446
1447 protected void HandleLogin(bool successful, object responseData)
1448 {
1449 Debug.Log("[ApexSystem] Handling Login");
1450 userAccessVerified = false;
1451
1452 if (successful)
1453 {
1454 currentActiveLogin = responseData as LoginResponseContent;
1455
1456 OnLoginSuccess.Invoke();
1457
1459 {
1461 }
1462 }
1463 else
1464 {
1465 FailureResponse failureData = responseData as FailureResponse;
1466 Debug.Log(string.Format("[ApexSystem] Failed to log in.\nError: {0}", failureData.Message));
1467 OnLoginFailed.Invoke(responseData as FailureResponse);
1468 }
1469 }
1470
1471 void _ReturnToHub()
1472 {
1473 var token = currentActiveLogin.Token;
1474
1475 if (
1476 serverIP.Contains("apexsa.", StringComparison.CurrentCultureIgnoreCase)
1477 || serverIP.Contains("saudi.", StringComparison.CurrentCultureIgnoreCase)
1478 )
1479 {
1480 Debug.Log($"pixovr://com.PixoVR.SA_TrainingAcademy?pixotoken={token}");
1481 Application.OpenURL($"pixovr://com.PixoVR.SA_TrainingAcademy?pixotoken={token}");
1482 }
1483 else
1484 {
1485 Debug.Log($"pixovr://com.PixoVR.PixoHub?pixotoken={token}");
1486 Application.OpenURL($"pixovr://com.PixoVR.PixoHub?pixotoken={token}");
1487 }
1488 }
1489
1491 {
1492 if (!webSocket.IsConnected())
1493 {
1497 }
1498
1499 public static bool GenerateOneTimeLoginForCurrentUser()
1500 {
1501 if (Instance.currentActiveLogin == null)
1502 return false;
1503
1504 return Instance._GenerateOneTimeLoginForUser();
1505 }
1506
1508 {
1509 if (currentActiveLogin == null)
1510 {
1511 Debug.LogError("[ApexSystem] No current user logged in.");
1512 return false;
1513 }
1514
1516 }
1517
1520 if (currentActiveLogin == null)
1521 {
1522 Debug.LogError("[ApexSystem] No user logged in to generate code.");
1523 return false;
1524 }
1525
1527 return true;
1528 }
1529 }
1530}
async void SendHeartbeat(string authToken, int sessionId)
async void GetUserModules(string authToken, int userId)
async void JoinSession(string authToken, JoinSessionData joinData)
async void LoginWithToken(string token)
async void CompleteSession(string authToken, CompleteSessionData completionData)
async void Login(LoginData login)
async void SendSessionEvent(string authToken, SessionEventData sessionEvent)
void SetPlatformEndpoint(string endpointUrl)
async void GetUserData(string authToken, int userId)
void SetWebEndpoint(string endpointUrl)
async void GetModuleAccess(int moduleId, int userId, string serialNumber)
async void GenerateAssistedLogin(string authToken)
async void GetModuleList(string authToken, string platform)
const string PIXOVR_SESSION_COMPLETE
const string PIXOVR_SESSION_EVENT
const string PIXOVR_SESSION_JOINED
static readonly string MODULE_ID
ApexWebsocket webSocket
OnHttpResponseEvent OnPingSuccess
Extensions AppendStandardContextExtension(Extensions currentContextExtensions)
OnGeneratedAssistedLoginSuccessEvent OnGeneratedAssistedLoginSuccess
bool runSetupOnAwake
[SerializeField]
static string PassedLoginToken
Definition ApexSystem.cs:87
static bool LoginCheckModuleAccess
Definition ApexSystem.cs:75
static bool GetCurrentUser()
static bool RunSetupOnAwake
Definition ApexSystem.cs:69
FailureResponse GenerateFailureResponse(string message)
OnApexFailureEvent OnJoinSessionFailed
string GetPlatformEndpointFromPlatformTarget(PlatformServer target)
void _ChangePlatformServer(PlatformServer newServer)
int moduleID
[SerializeField]
static bool Login(string username, string password)
OnApexFailureEvent OnGeneratedAssistedLoginFailed
static string ModuleName
Definition ApexSystem.cs:45
OnHttpResponseEvent OnPingFailed
static bool SendSessionEvent(Statement eventStatement)
string GetWebEndpointFromPlatformTarget(PlatformServer target)
void OnAPIResponse(ResponseType response, HttpResponseMessage message, object responseData)
OnHttpResponseEvent OnJoinSessionSuccess
static void ReturnToHub()
OnApexFailureEvent OnGetUserFailed
OnAuthCodeReceived OnAuthorizationCodeReceived
OnGetOrgModulesSuccessEvent OnGetOrganizationModulesSuccess
bool _JoinSession(string newScenarioID=null, Extension contextExtension=null)
bool _Login(LoginData login)
static bool RequestAuthorizationCode()
bool _CompleteSession(SessionData currentSessionData, Extension contextExtension, Extension resultExtension)
void SetupPlatformConfiguration()
PlatformResponse OnPlatformResponse
static bool GetUser(int userId=-1)
OnHttpResponseEvent OnCompleteSessionSuccess
string moduleVersion
[SerializeField]
string GetEndpointFromTarget(PlatformServer target)
bool _SendSimpleSessionEvent(string verbName, string targetObject, Extension contextExtension)
OnApexFailureEvent OnCompleteSessionFailed
OnLoginSuccessEvent OnLoginSuccess
void OnWebSocketConnectFailed(string reason)
static bool CheckModuleAccess(int targetModuleID=-1)
OnApexFailureEvent OnSendEventFailed
void OnWebSocketReceive(string data)
void HandleLogin(bool successful, object responseData)
static bool GetUserModules(int userId=-1)
static LoginResponseContent CurrentActiveLogin
Definition ApexSystem.cs:63
static bool SendSimpleSessionEvent(string action, string targetObject, Extension contextExtension)
static string ReturnTarget
Definition ApexSystem.cs:99
static string ServerIP
Definition ApexSystem.cs:33
static string TargetType
float DetermineScaledScore(float scaledScore, float score, float maxScore)
APIHandler apexAPIHandler
static bool GetCurrentUserModules()
void _ExitApplication(string returnTarget)
static bool GetModulesList(string platformName)
Task< bool > socketConnectTask
static void ChangePlatformServer(PlatformServer newServer)
static string ModuleVersion
Definition ApexSystem.cs:51
static bool LoginWithToken()
bool _Login(string username, string password)
static bool JoinSession(string scenarioID=null, Extension contextExtension=null)
bool loginCheckModuleAccess
[SerializeField]
bool _GenerateOneTimeLoginForCurrentUser()
OnApexFailureEvent OnGetUserModulesFailed
bool _SendSessionEvent(Statement eventStatement)
OnApexFailureEvent OnLoginFailed
static bool Login(LoginData login)
static string ScenarioID
Definition ApexSystem.cs:57
void _ParsePassedData(Dictionary< string, string > arguments)
static string DeviceSerialNumber
Definition ApexSystem.cs:81
LoginResponseContent currentActiveLogin
bool _LoginWithToken(string token)
static void ExitApplication(string returnTarget="")
static readonly Regex VersionValidator
OnApexFailureEvent OnGetOrganizationModulesFailed
float heartbeatTime
[SerializeField]
OnApexFailureEvent OnModuleAccessFailed
static string OptionalData
Definition ApexSystem.cs:93
string scenarioID
[SerializeField]
OnModuleAccessSuccessEvent OnModuleAccessSuccess
bool _GetUser(int userId=-1)
OnGetUserSuccessEvent OnGetUserSuccess
OnHttpResponseEvent OnSendEventSuccess
static bool GenerateOneTimeLoginForCurrentUser()
bool _CheckModuleAccess(int targetModuleID=-1)
bool _GenerateOneTimeLoginForUser()
static bool CompleteSession(SessionData currentSessionData, Extension contextExtension=null, Extension resultExtension=null)
bool IsModuleVersionOnlyNumerical()
string serverIP
[SerializeField]
void OnWebSocketClosed(System.Net.WebSockets.WebSocketCloseStatus reason)
bool _GetModuleList(string platformName)
static bool LoginWithToken(string token)
PlatformServer PlatformTargetServer
OnGetUserModulesSuccessEvent OnGetUserModulesSuccess
Extensions AppendStandardContextExtension(Extension currentContextExtension)
string moduleName
[SerializeField]
bool IsModuleNonMajorVersionPartValid(string modulePart)
bool _GetUserModules(int userId=-1)
bool IsModuleMajorVersionPartValid(string modulePart)
void OnDeepLinkActivated(string url)
static readonly Uri JOINED_SESSION
static readonly Uri COMPLETED_SESSION
async Task< bool > Connect(Uri endpoint, int attemptTries=3)
OnWebSocketReceive OnReceive
OnWebSocketConnectFailed OnConnectFailed
OnWebSocketClosed OnClosed
OnWebSocketConnectSuccessful OnConnectSuccess
[Serializable]
Definition ApexTypes.cs:162
static bool DoesFileExistInSharedLocation(string fileName)
static string ReadFileFromSharedStorage(string fileName)
static bool OpenApplication(string applicationPath, string[] argumentKeys, string[] argumentValues)
static Dictionary< string, string > ParseURLArguments(string url)
static Dictionary< string, string > ParseApplicationArguments()
static string GetMacAddress()
Definition ApexUtils.cs:21
void Add(Uri key, string value)
void AddSimple(string key, string value)
override JObject ToJObject(TCAPIVersion version)
delegate void PlatformResponse(ResponseType type, bool wasSuccessful, object responseData)