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