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
324 Debug.Log($"[ApexSystem] Login Token: {loginToken}");
325 }
326
327 void _ExitApplication(string returnTarget)
328 {
329 if(returnTarget == null)
330 {
331 returnTarget = "";
332 }
333
334 string returnTargetType = "app";
335
336 if(returnTarget.Contains("://"))
337 {
338 returnTargetType = "url";
339 }
340
341 Debug.Log("[ApexSystem] " + returnTarget + " " + returnTargetType);
342
343 string parameters = "";
344
345 Debug.Log("[ApexSystem] Building parameters for url.");
346
347 if(CurrentActiveLogin != null)
348 {
349 parameters += "pixotoken=" + CurrentActiveLogin.Token;
350 }
351
352 if(optionalParameter != null)
353 {
354 if (optionalParameter.Length > 0)
355 {
356 if (parameters.Length > 0)
357 parameters += "&";
358 parameters += "optional=" + optionalParameter;
359 }
360 }
361
362 if (returnTarget.Length > 0)
363 {
364 if (parameters.Length > 0)
365 parameters += "&";
366 parameters += "returntarget=" + returnTarget;
367 }
368
369 if (returnTargetType.Length > 0)
370 {
371 if (parameters.Length > 0)
372 parameters += "&";
373 parameters += "targettype=" + returnTargetType;
374 }
375
376 Debug.Log("[ApexSystem] Checking the return target parameter.");
377
378 if (returnTargetParameter != null)
379 {
380 if (returnTargetParameter.Length > 0)
381 {
382 Debug.Log("[ApexSystem] Had a valid return target parameter.");
383 if (targetTypeParameter.Equals("url", StringComparison.OrdinalIgnoreCase))
384 {
385 Debug.Log("[ApexSystem] Return Target is a URL.");
386
387 string returnURL = returnTargetParameter;
388 if (parameters.Length > 0)
389 {
390 if (!returnURL.Contains('?'))
391 returnURL += "?";
392 else
393 returnURL += "&";
394
395 returnURL += parameters;
396 }
397 Debug.Log("Custom Target: " + returnURL);
399 return;
400 }
401 else
402 {
403 Debug.Log("[ApexSystem] Return Target is a package name.");
404
405 List<string> keys = new List<string>(), values = new List<string>();
406
407 Debug.Log("[ApexSystem] Adding pixo token.");
408
409 if (CurrentActiveLogin != null)
410 {
411 keys.Add("pixotoken");
412 values.Add(CurrentActiveLogin.Token);
413 }
414
415 Debug.Log("[ApexSystem] Adding optional.");
416
417 if (optionalParameter.Length > 0)
418 {
419 keys.Add("optional");
420 values.Add(optionalParameter);
421 }
422
423 Debug.Log("[ApexSystem] Adding return target.");
424
425 if (returnTarget.Length > 0)
426 {
427 keys.Add("returntarget");
428 values.Add(returnTarget);
429 }
430
431 Debug.Log("[ApexSystem] Adding return target type.");
432
433 if (returnTargetType.Length > 0)
434 {
435 keys.Add("targettype");
436 values.Add(returnTargetType);
437 }
438
439 PixoPlatformUtilities.OpenApplication(returnTargetParameter, keys.ToArray(), values.ToArray());
440 return;
441 }
442 }
443 }
444
446 }
447
448 string GetEndpointFromTarget(PlatformServer target)
449 {
450 return target.ToUrlString();
451 }
452
453 string GetWebEndpointFromPlatformTarget(PlatformServer target)
454 {
455 int targetValue = (int)target;
456 WebPlatformServer webTarget = (WebPlatformServer)targetValue;
457
458 return webTarget.ToUrlString();
459 }
460
461 string GetPlatformEndpointFromPlatformTarget(PlatformServer target)
462 {
463 int targetValue = (int)target;
464 APIPlatformServer apiTarget = (APIPlatformServer)targetValue;
465
466 return apiTarget.ToUrlString();
467 }
468
470 {
472
473 if (webSocketUrl.Contains("://"))
474 {
475 webSocketUrl = webSocketUrl.Split(new string[] { "://" }, 2, StringSplitOptions.RemoveEmptyEntries)[1];
476 }
477
478 if (webSocketUrl.Contains("/"))
479 {
480 webSocketUrl = webSocketUrl.Split(new string[] { "/" }, 2, StringSplitOptions.RemoveEmptyEntries)[0];
481 }
482
483 webSocketUrl = "wss://" + webSocketUrl + "/ws";
484 }
485
486 void Start()
487 {
489 {
490 Debug.LogWarning($"{moduleVersion} is an invalid module version.");
492 deviceID = SystemInfo.deviceUniqueIdentifier;
493 deviceModel = SystemInfo.deviceModel;
494 platform = XRSettings.loadedDeviceName.Length > 0 ? XRSettings.loadedDeviceName : Application.platform.ToString();
495 clientIP = Utils.ApexUtils.GetLocalIP();
496 }
497
498 private void FixedUpdate()
500 if(webSocket != null)
501 {
503 }
504
506 {
507 heartbeatTimer -= Time.fixedDeltaTime;
508
509 if(heartbeatTimer <= 0.0f)
510 {
513 }
514 }
515 }
517 void ConnectWebsocket()
518 {
519 socketConnectTask = Task.Run(() => webSocket.Connect(new Uri(webSocketUrl)));
520 }
521
523 {
524 socketDisconnectTask = Task.Run(() => webSocket.CloseSocket());
525 }
526
529 Debug.Log("Websocket connected successfully.");
530 }
531
532 void OnWebSocketConnectFailed(string reason)
533 {
534 Debug.LogError("Websocket failed to connect with error: " + reason);
535 }
536
537 void OnWebSocketReceive(string data)
538 {
539 Debug.Log("Websocket received: " + data);
540 try
541 {
542 if (data.Contains("auth_code"))
543 {
544 var authCode = JsonConvert.DeserializeObject<AuthorizationCode>(data);
545 OnAuthorizationCodeReceived.Invoke(authCode.Code);
546 }
548 if (data.Contains("Token", StringComparison.OrdinalIgnoreCase))
549 {
550 object loginResponse = JsonConvert.DeserializeObject<LoginResponseContent>(data);
551 HandleLogin(true, loginResponse);
553 }
554 catch (Exception ex)
555 {
556 Debug.Log(ex.Message);
558 }
559
560 void OnWebSocketClosed(System.Net.WebSockets.WebSocketCloseStatus reason)
561 {
562 Debug.Log("Websocket closed with reason: " + reason);
563 }
564
566 {
568 return false;
569
570 string[] moduleVersionParts = moduleVersion.Split('.');
571
572 if (moduleVersionParts.Length != 3)
573 return false;
574
575 if (!IsModuleMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Major]))
576 return false;
577
578 if (!IsModuleNonMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Minor]))
579 return false;
580
581 if (!IsModuleNonMajorVersionPartValid(moduleVersionParts[(int)VersionParts.Patch]))
582 return false;
583
584 return true;
585 }
586
587 static readonly Regex VersionValidator = new Regex(@"^[0123456789.]+$");
589 {
591 }
592
593 bool IsModuleNonMajorVersionPartValid(string modulePart)
594 {
595 if (modulePart.Length <= 0)
596 return false;
597
598 if (modulePart.Length > 2)
599 return false;
600
601 return true;
602 }
603
604 bool IsModuleMajorVersionPartValid(string modulePart)
605 {
606 if (modulePart.Length <= 0)
607 return false;
608
609 if (modulePart.StartsWith("0"))
610 return false;
611
612 return true;
613 }
614
615 [Obsolete("ReturnToHub has been deprecated, please use ExitApplication.", true)]
616 public static void ReturnToHub()
618 Instance._ReturnToHub();
619 }
620
621 public static void ExitApplication(string returnTarget = "")
622 {
623 Instance._ExitApplication(returnTarget);
624 }
625
626 public static bool RequestAuthorizationCode()
627 {
628 return Instance._RequestAuthorizationCode();
629 }
630
631 public static void ChangePlatformServer(PlatformServer newServer)
632 {
633 Instance._ChangePlatformServer(newServer);
635
636 public static void Ping()
637 {
638 Instance._Ping();
639 }
640
641 public static bool LoginWithToken()
642 {
643 return LoginWithToken(Instance.loginToken);
644 }
645
646 public static bool LoginWithToken(string token)
647 {
648 return Instance._LoginWithToken(token);
649 }
650
651 public static bool Login(LoginData login)
652 {
653 return Instance._Login(login);
654 }
655
656 public static bool Login(string username, string password)
657 {
658 return Instance._Login(username, password);
659 }
660
661 public static bool CheckModuleAccess(int targetModuleID = -1)
662 {
663 return Instance._CheckModuleAccess(targetModuleID);
664 }
665
666 public static bool JoinSession(string scenarioID = null, Extension contextExtension = null)
667 {
668 return Instance._JoinSession(scenarioID, contextExtension);
669 }
670
671 public static bool CompleteSession(SessionData currentSessionData, Extension contextExtension = null, Extension resultExtension = null)
672 {
673 return Instance._CompleteSession(currentSessionData, contextExtension, resultExtension);
674 }
675
676 public static bool SendSimpleSessionEvent(string action, string targetObject, Extension contextExtension)
677 {
678 return Instance._SendSimpleSessionEvent(action, targetObject, contextExtension);
679 }
680
681 public static bool SendSessionEvent(Statement eventStatement)
682 {
683 return Instance._SendSessionEvent(eventStatement);
684 }
685
686 public static bool GetCurrentUser()
687 {
688 return GetUser();
689 }
690
691 public static bool GetUser(int userId = -1)
692 {
693 return Instance._GetUser(userId);
694 }
695
696 public static bool GetCurrentUserModules()
697 {
698 return GetUserModules();
699 }
700
701 public static bool GetUserModules(int userId = -1)
702 {
703 return Instance._GetUserModules(userId);
704 }
705
706 public static bool GetModulesList(string platformName)
707 {
708 return Instance._GetModuleList(platformName);
709 }
710
711 protected void _ChangePlatformServer(PlatformServer newServer)
712 {
713 PlatformTargetServer = newServer;
714
715 SetupAPI();
717
718 protected void _Ping()
719 {
722
723 public bool _LoginWithToken(string token)
724 {
725 if(token.Length <= 0)
727 return false;
728 }
729
730 Debug.Log($"[ApexSystem] Logging in with token: {token}");
732
733 return true;
734 }
735
736 protected bool _Login(LoginData login)
737 {
738 Debug.Log("[ApexSystem] _Login called.");
739 if (apexAPIHandler == null)
740 {
741 Debug.Log("[ApexSystem] API Handler is null.");
742 OnLoginFailed.Invoke(GenerateFailureResponse("There was an error reaching the platform, please contact your administrator."));
743 return false;
744 }
745
746 if (login.Login.Length <= 0)
747 {
748 Debug.Log("[Login] No user name.");
749 OnLoginFailed.Invoke(GenerateFailureResponse("No username or email entered."));
750 return false;
751 }
752
753 if(login.Password.Length <= 0)
754 {
755 Debug.Log("[Login] No password.");
756 login.Password = "<empty>";
757 }
758
759 apexAPIHandler.Login(login);
760
761 Debug.Log("[ApexSystem] Login called.");
762
763 return true;
764 }
765
766 protected bool _Login(string username, string password)
767 {
768 return _Login(new LoginData(username, password));
769 }
770
771 protected FailureResponse GenerateFailureResponse(string message)
772 {
773 FailureResponse failureResponse = new FailureResponse();
774 failureResponse.Error = "true";
775 failureResponse.HttpCode = "400";
776 failureResponse.Message = message;
777
778 return failureResponse;
779 }
780
781 public void _ParsePassedData()
782 {
783 var applicationArugments = PixoPlatformUtilities.ParseApplicationArguments();
784
785 if(applicationArugments == null)
786 {
787 Debug.Log("No arguments found for the application.");
788 return;
789 }
790
791 if (applicationArugments.ContainsKey("optional"))
792 optionalParameter = applicationArugments["optional"];
793
794 if (applicationArugments.ContainsKey("returntarget"))
795 returnTargetParameter = applicationArugments["returntarget"];
797 if (applicationArugments.ContainsKey("targettype"))
798 targetTypeParameter = applicationArugments["targettype"];
799
800 if (applicationArugments.ContainsKey("pixotoken"))
801 loginToken = applicationArugments["pixotoken"];
802 }
803
804 public bool _CheckModuleAccess(int targetModuleID = -1)
805 {
806 Debug.Log("[ApexSystem] _CheckModuleAccess called.");
807
808 if (currentActiveLogin == null)
809 {
810 Debug.LogError("[ApexSystem] Cannot check user's module access with no active login.");
811 return false;
812 }
813
814 if (targetModuleID <= -1)
815 {
816 targetModuleID = moduleID;
817 }
818
820
821 return true;
822 }
823
824 protected bool _JoinSession(string newScenarioID = null, Extension contextExtension = null)
825 {
826 if (currentActiveLogin == null)
827 {
828 Debug.LogError("[ApexSystem] Cannot join session with no active login.");
829 return false;
830 }
831
832 if(userAccessVerified == false)
833 {
834 return false;
835 }
836
837 if (newScenarioID != null)
838 {
839 scenarioID = newScenarioID;
840 }
841
842 if (sessionInProgress == true)
843 {
844 Debug.LogError("[ApexSystem] Session is already in progress." +
845 " The previous session didn't complete or a new session was started during an active session.");
846 }
847
848 currentSessionID = Guid.NewGuid();
849
850 Statement sessionStatement = new Statement();
851 Agent sessionActor = new Agent();
852 sessionActor.mbox = currentActiveLogin.Email;
853
854 Verb sessionVerb = new Verb();
855 sessionVerb.id = ApexVerbs.JOINED_SESSION;
856 sessionVerb.display = new LanguageMap();
857 sessionVerb.display.Add("en", "Joined Session");
858
859 Activity sessionActivity = new Activity();
860 sessionActivity.id = string.Format("https://pixovr.com/xapi/objects/{0}/{1}", moduleID, scenarioID);
861
862 Context sessionContext = new Context();
863 sessionContext.registration = currentSessionID;
864 sessionContext.revision = moduleVersion;
865 sessionContext.platform = platform;
866
867 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
868
869 sessionStatement.actor = sessionActor;
870 sessionStatement.verb = sessionVerb;
871 sessionStatement.target = sessionActivity;
872 sessionStatement.context = sessionContext;
873
874 JoinSessionData sessionData = new JoinSessionData();
875 sessionData.DeviceId = deviceID;
876 sessionData.IpAddress = clientIP;
877 sessionData.ModuleId = moduleID;
878 sessionData.Uuid = currentSessionID.ToString();
879 sessionData.EventType = ApexEventTypes.PIXOVR_SESSION_JOINED;
880 sessionData.JsonData = sessionStatement;
881
883
884 return true;
885 }
886
887 protected bool _SendSimpleSessionEvent(string verbName, string targetObject, Extension contextExtension)
888 {
889 if (userAccessVerified == false)
890 return false;
891
892 if (verbName == null)
893 return false;
894
895 if (verbName.Length == 0)
896 return false;
897
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 = new Uri("https://pixovr.com/xapi/verbs/" + verbName.Replace(' ', '_').ToLower());
905 sessionVerb.display = new LanguageMap();
906 sessionVerb.display.Add("en", verbName);
907
908 Activity sessionActivity = new Activity();
909 sessionActivity.id = string.Format("https://pixovr.com/xapi/objects/{0}/{1}/{2}", moduleID, scenarioID, targetObject.Replace(' ', '_').ToLower());
910
911 Context sessionContext = new Context();
912 sessionContext.registration = currentSessionID;
913 sessionContext.revision = moduleVersion;
914 sessionContext.platform = platform;
915
916 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
918 sessionStatement.actor = sessionActor;
919 sessionStatement.verb = sessionVerb;
920 sessionStatement.target = sessionActivity;
921 sessionStatement.context = sessionContext;
922
923 SessionEventData sessionEvent = new SessionEventData();
924 sessionEvent.DeviceId = deviceID;
925 sessionEvent.ModuleId = ModuleID;
926 sessionEvent.Uuid = currentSessionID.ToString();
927 sessionEvent.EventType = ApexEventTypes.PIXOVR_SESSION_EVENT;
928 sessionEvent.JsonData = sessionStatement;
929
931
932 return true;
933 }
934
935 protected bool _SendSessionEvent(Statement eventStatement)
936 {
937 if (userAccessVerified == false)
938 {
939 return false;
940 }
941
942 if (currentActiveLogin == null)
943 {
944 Debug.LogError("[ApexSystem] Cannot send a session event with no active login.");
945 return false;
946 }
947
948 if (sessionInProgress == false)
949 {
950 Debug.LogError("[ApexSystem] No session in progress to send event for.");
951 return false;
952 }
953
954 if(eventStatement == null)
955 {
956 Debug.LogError("[ApexSystem] No event data to send.");
957 return false;
958 }
959
960 if(eventStatement.actor != null)
961 {
962 Debug.LogWarning("[ApexSystem] Actor data should not be filled out.");
963 }
964
965 if(eventStatement.verb == null)
966 {
967 Debug.LogError("[ApexSystem] Verb missing from eventStatement.");
968 return false;
969 }
970
971 if(eventStatement.verb.id == null)
972 {
973 Debug.LogError("[ApexSystem] verb.id missing from eventStatement.");
974 return false;
975 }
976
977 if(eventStatement.target == null)
978 {
979 Debug.LogError("[ApexSystem] Object (target) missing from eventStatement.");
980 return false;
981 }
982
983 eventStatement.actor = new Agent();
984 eventStatement.actor.mbox = currentActiveLogin.Email;
985
986 if (eventStatement.context == null)
987 {
988 eventStatement.context = new Context();
989 }
990
991 eventStatement.context.registration = currentSessionID;
992 eventStatement.context.revision = ModuleVersion;
993 eventStatement.context.platform = platform;
994
995 eventStatement.context.extensions = AppendStandardContextExtension(eventStatement.context.extensions);
996
997 SessionEventData sessionEvent = new SessionEventData();
998 sessionEvent.DeviceId = deviceID;
999 sessionEvent.ModuleId = ModuleID;
1000 sessionEvent.Uuid = currentSessionID.ToString();
1001 sessionEvent.EventType = ApexEventTypes.PIXOVR_SESSION_EVENT;
1002 sessionEvent.JsonData = eventStatement;
1003
1005
1006 return true;
1007 }
1008
1009 protected bool _CompleteSession(SessionData currentSessionData, Extension contextExtension, Extension resultExtension)
1010 {
1011 if (userAccessVerified == false)
1012 {
1013 return false;
1014 }
1015
1016 if (currentActiveLogin == null)
1017 {
1018 Debug.LogError("[ApexSystem] Cannot complete session with no active login.");
1019 return false;
1020 }
1021
1022 if (sessionInProgress == false)
1023 {
1024 Debug.LogError("[ApexSystem] No session in progress to complete.");
1025 return false;
1026 }
1027
1028 // Create our actor
1029 Agent sessionActor = new Agent();
1030 sessionActor.mbox = currentActiveLogin.Email;
1031
1032 // Create our verb
1033 Verb sessionVerb = new Verb();
1034 sessionVerb.id = ApexVerbs.COMPLETED_SESSION;
1035 sessionVerb.display = new LanguageMap();
1036 sessionVerb.display.Add("en", "Completed Session");
1037
1038 // Create the session activity
1039 Activity sessionActivity = new Activity();
1040 sessionActivity.id = string.Format("https://pixovr.com/xapi/objects/{0}/{1}", moduleID, scenarioID);
1041
1042 // Create our context
1043 Context sessionContext = new Context();
1044 sessionContext.registration = currentSessionID;
1045 sessionContext.revision = moduleVersion;
1046 sessionContext.platform = platform;
1047
1048 sessionContext.extensions = AppendStandardContextExtension(contextExtension);
1049
1050 // Create our results
1051 Result sessionResult = new Result();
1052 sessionResult.completion = currentSessionData.Complete;
1053 sessionResult.success = currentSessionData.Success;
1054 // Add score to the results
1055 sessionResult.score = new Score();
1056 sessionResult.score.min = currentSessionData.MinimumScore;
1057 sessionResult.score.max = currentSessionData.MaximumScore;
1058 sessionResult.score.raw = currentSessionData.Score;
1059 sessionResult.score.scaled = DetermineScaledScore(currentSessionData.ScaledScore, currentSessionData.Score, currentSessionData.MaximumScore);
1060 sessionResult.duration = TimeSpan.FromSeconds(currentSessionData.Duration);
1061 if(resultExtension != null)
1062 {
1063 sessionResult.extensions = new Extensions(resultExtension.ToJObject());
1064 }
1065
1066 // Create our statement and add the pieces
1067 Statement sessionStatement = new Statement();
1068 sessionStatement.actor = sessionActor;
1069 sessionStatement.verb = sessionVerb;
1070 sessionStatement.target = sessionActivity;
1071 sessionStatement.context = sessionContext;
1072 sessionStatement.result = sessionResult;
1073
1074 CompleteSessionData sessionData = new CompleteSessionData();
1075 sessionData.DeviceId = deviceID;
1076 sessionData.ModuleId = moduleID;
1077 sessionData.Uuid = currentSessionID.ToString();
1078 sessionData.EventType = ApexEventTypes.PIXOVR_SESSION_COMPLETE;
1079 sessionData.JsonData = sessionStatement;
1080 sessionData.SessionDuration = currentSessionData.Duration;
1081 sessionData.Score = currentSessionData.Score;
1082 sessionData.ScoreMin = currentSessionData.MinimumScore;
1083 sessionData.ScoreMax = currentSessionData.MaximumScore;
1084 sessionData.ScoreScaled = DetermineScaledScore(currentSessionData.ScaledScore, currentSessionData.Score, currentSessionData.MaximumScore);
1085
1087
1088 return true;
1089 }
1090
1091 protected bool _SendHeartbeat()
1092 {
1093 Debug.Log("Sending heartbeat...");
1094 if (!sessionInProgress)
1095 return false;
1096
1097 if (currentActiveLogin == null)
1098 return false;
1099
1101
1102 return true;
1103 }
1104
1105 protected bool _GetUser(int userId = -1)
1106 {
1107 if (currentActiveLogin == null)
1108 return false;
1109
1110 if (userId < 0)
1111 {
1112 userId = currentActiveLogin.ID;
1113 }
1114
1116 return true;
1117 }
1118
1119 protected bool _GetUserModules(int userId = -1)
1120 {
1122 return false;
1123
1124 if (userId < 0)
1125 {
1126 userId = currentActiveLogin.ID;
1127 }
1128
1130 return true;
1131 }
1132
1133 protected bool _GetModuleList(string platformName)
1134 {
1136 return false;
1137
1139 return true;
1140 }
1141
1142 private float DetermineScaledScore(float scaledScore, float score, float maxScore)
1143 {
1144 float determinedScaledScore = scaledScore;
1145
1146 if(scaledScore < Mathf.Epsilon && score >= Mathf.Epsilon)
1147 {
1148 determinedScaledScore = (score / maxScore) * 100f;
1150
1151 return determinedScaledScore;
1152 }
1153
1154 private Extensions AppendStandardContextExtension(Extensions currentContextExtensions)
1155 {
1156 return AppendStandardContextExtension(new Extension(currentContextExtensions.ToJObject()));
1157 }
1158
1159 private Extensions AppendStandardContextExtension(Extension currentContextExtension)
1160 {
1161 Extension contextExtension;
1162 if (currentContextExtension != null)
1164 contextExtension = currentContextExtension;
1165 }
1166 else
1167 {
1168 contextExtension = new Extension();
1169 }
1170
1171 contextExtension.Add(ApexExtensionStrings.MODULE_ID, moduleID.ToString());
1172 contextExtension.AddSimple("device_id", deviceID);
1173 contextExtension.AddSimple("device_model", deviceModel);
1174 contextExtension.AddSimple("sdk_version", "unity-" + ApexUtils.SDKVersion);
1175
1176 return new Extensions(contextExtension.ToJObject());
1177 }
1178
1179 protected void OnAPIResponse(ResponseType response, HttpResponseMessage message, object responseData)
1180 {
1181 Debug.Log("[ApexSystem] On API Response");
1182 bool success = message.IsSuccessStatusCode;
1183 if(responseData is FailureResponse)
1185 success = success && (responseData is IFailure) && (!(responseData as FailureResponse).HasErrored());
1186 }
1187
1188 switch (response)
1190 case ResponseType.RT_PING:
1191 {
1192 if(success)
1193 {
1194 Debug.Log("[ApexSystem] Ping successful.");
1195 OnPingSuccess.Invoke(message);
1196 }
1197 else
1198 {
1199 Debug.Log("[ApexSystem] Ping failed.");
1200 OnPingFailed.Invoke(message);
1201 }
1202 break;
1203 }
1204 case ResponseType.RT_LOGIN:
1205 {
1206 Debug.Log("[ApexSystem] Calling to handle login.");
1207 HandleLogin(success, responseData);
1208 break;
1210 case ResponseType.RT_GET_USER:
1211 {
1212 if(success)
1213 {
1214 OnGetUserSuccess.Invoke(responseData as GetUserResponseContent);
1215 }
1216 else
1217 {
1218 FailureResponse failureData = responseData as FailureResponse;
1219 Debug.Log(string.Format("[ApexSystem] Failed to get user.\nError: {0}", failureData.Message));
1220 OnGetUserFailed.Invoke(responseData as FailureResponse);
1221 }
1222 break;
1223 }
1224 case ResponseType.RT_GET_USER_MODULES:
1225 {
1226 if (success)
1227 {
1228 OnGetUserModulesSuccess.Invoke(responseData as GetUserModulesResponse);
1229 }
1230 else
1231 {
1232 FailureResponse failureData = responseData as FailureResponse;
1233 Debug.Log(string.Format("[ApexSystem] Failed to get user.\nError: {0}", failureData.Message));
1234 OnGetUserFailed.Invoke(responseData as FailureResponse);
1235 }
1236 break;
1237 }
1238 case ResponseType.RT_SESSION_JOINED:
1239 {
1240 if(success)
1241 {
1242 JoinSessionResponse joinSessionResponse = responseData as JoinSessionResponse;
1243 Debug.Log(string.Format("[ApexSystem] Session Id is {0}.", joinSessionResponse.SessionId));
1244 heartbeatSessionID = joinSessionResponse.SessionId;
1245 sessionInProgress = true;
1246 OnJoinSessionSuccess.Invoke(message);
1247 }
1248 else
1249 {
1250 FailureResponse failureData = responseData as FailureResponse;
1251 Debug.Log(string.Format("[ApexSystem] Failed to join session.\nError: {0}", failureData.Message));
1252 currentSessionID = Guid.Empty;
1253 sessionInProgress = false;
1254 OnJoinSessionFailed.Invoke(responseData as FailureResponse);
1255 }
1256 break;
1257 }
1258 case ResponseType.RT_SESSION_COMPLETE:
1259 {
1260 if (success)
1261 {
1262 sessionInProgress = false;
1263 currentSessionID = Guid.Empty;
1264 OnCompleteSessionSuccess.Invoke(message);
1265 }
1266 else
1267 {
1268 FailureResponse failureData = responseData as FailureResponse;
1269 Debug.Log(string.Format("[ApexSystem] Failed to complete session.\nError: {0}", failureData.Message));
1270 OnCompleteSessionFailed.Invoke(responseData as FailureResponse);
1271 }
1272 break;
1273 }
1274 case ResponseType.RT_SESSION_EVENT:
1275 {
1276 if (success)
1277 {
1278 Debug.Log("[ApexSystem] Session event sent.");
1279 OnSendEventSuccess.Invoke(message);
1280 }
1281 else
1282 {
1283 FailureResponse failureData = responseData as FailureResponse;
1284 Debug.Log(string.Format("[ApexSystem] Failed to send session event.\nError: {0}", failureData.Message));
1285 OnSendEventFailed.Invoke(responseData as FailureResponse);
1286 }
1287 break;
1288 }
1289 case ResponseType.RT_GET_USER_ACCESS:
1290 {
1291 if (success)
1292 {
1293 var userAccessResponseContent = responseData as UserAccessResponseContent;
1294 if (userAccessResponseContent.Access)
1295 {
1296 if (userAccessResponseContent.PassingScore.HasValue)
1297 {
1298 currentActiveLogin.MinimumPassingScore = userAccessResponseContent.PassingScore.Value;
1299 }
1300
1301 userAccessVerified = true;
1303 }
1304 else
1305 {
1306 currentActiveLogin = null;
1307 userAccessVerified = false;
1309 {
1310 Error = "True",
1311 HttpCode = "401",
1312 Message = "User does not have access to module",
1313 });
1314 }
1315 }
1316 else
1317 {
1318 FailureResponse failureData = responseData as FailureResponse;
1319 Debug.Log(string.Format("[ApexSystem] Failed to get users module access data.\nError: {0}", failureData.Message));
1320
1321 OnModuleAccessFailed.Invoke(responseData as FailureResponse);
1322 }
1323 break;
1324 }
1325 case ResponseType.RT_GET_MODULES_LIST:
1326 {
1327 if(success)
1328 {
1329 OnGetOrganizationModulesSuccess.Invoke(responseData as List<OrgModule>);
1330 }
1331 else
1332 {
1333 FailureResponse failureData = responseData as FailureResponse;
1334 Debug.Log(string.Format("[ApexSystem] Failed to get org modules.\nError: {0}", failureData.Message));
1335
1336 OnGetOrganizationModulesFailed.Invoke(responseData as FailureResponse);
1337 }
1338
1339 break;
1340 }
1341 default:
1342 {
1343 break;
1344 }
1345 }
1346
1347 if(OnPlatformResponse != null)
1348 {
1349 OnPlatformResponse.Invoke(response, success, responseData);
1350 }
1351 }
1352
1353 protected void HandleLogin(bool successful, object responseData)
1354 {
1355 Debug.Log("[ApexSystem] Handling Login");
1356 userAccessVerified = false;
1357
1358 if (successful)
1359 {
1360 currentActiveLogin = responseData as LoginResponseContent;
1361
1362 OnLoginSuccess.Invoke();
1363
1365 {
1367 }
1368 }
1369 else
1370 {
1371 FailureResponse failureData = responseData as FailureResponse;
1372 Debug.Log(string.Format("[ApexSystem] Failed to log in.\nError: {0}", failureData.Message));
1373 OnLoginFailed.Invoke(responseData as FailureResponse);
1374 }
1375 }
1376
1377 void _ReturnToHub()
1378 {
1379 var token = currentActiveLogin.Token;
1380
1381 if(serverIP.Contains("apexsa.", StringComparison.CurrentCultureIgnoreCase) || serverIP.Contains("saudi.", StringComparison.CurrentCultureIgnoreCase))
1382 {
1383 Debug.Log($"pixovr://com.PixoVR.SA_TrainingAcademy?pixotoken={token}");
1384 Application.OpenURL($"pixovr://com.PixoVR.SA_TrainingAcademy?pixotoken={token}");
1385 }
1386 else
1387 {
1388 Debug.Log($"pixovr://com.PixoVR.PixoHub?pixotoken={token}");
1389 Application.OpenURL($"pixovr://com.PixoVR.PixoHub?pixotoken={token}");
1390 }
1391 }
1392
1394 {
1395 if(!webSocket.IsConnected())
1396 {
1398 }
1400 }
1401
1402 // TODO: Move to new plugin
1403 public static bool GenerateOneTimeLoginForCurrentUser()
1404 {
1405 if (Instance.currentActiveLogin == null)
1406 return false;
1408 return Instance._GenerateOneTimeLoginForUser(Instance.currentActiveLogin.ID);
1409 }
1410
1411 // TODO: Move to new plugin
1413 {
1414 if (currentActiveLogin == null)
1415 {
1416 Debug.LogError("[ApexSystem] No current user logged in.");
1417 return false;
1418 }
1419
1421 }
1422
1423 // TODO: Move to new plugin
1424 bool _GenerateOneTimeLoginForUser(int userId)
1425 {
1426 if (currentActiveLogin == null)
1427 {
1428 Debug.LogError("[ApexSystem] No user logged in to generate code.");
1429 return false;
1430 }
1431
1433 return true;
1434 }
1435 }
1436}
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
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
FailureResponse GenerateFailureResponse(string message)
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
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)
static bool GetModulesList(string platformName)
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 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 void ExitApplication(string returnTarget="")
static readonly Regex VersionValidator
OnApexFailureEvent OnGetOrganizationModulesFailed
bool _GenerateOneTimeLoginForUser(int userId)
float heartbeatTime
[SerializeField]
OnApexFailureEvent OnModuleAccessFailed
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)
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)
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:161
static bool DoesFileExistInSharedLocation(string fileName)
static string ReadFileFromSharedStorage(string fileName)
static bool OpenApplication(string applicationPath, string[] argumentKeys, string[] argumentValues)
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)