private void HandleApiResponse(JToken data)
        {
            if (data == null && data.Children().Count() != 2)
            {
                return;
            }

            var idToken = data.SelectToken("id");

            if (idToken == null)
            {
                throw new Exception("response id not found.");
            }

            string id = idToken.ToObject <string>();

            TaskCompletionSource <JToken> openTask;

            if (!OpenTasks.TryGetValue(id, out openTask))
            {
                return;
            }

            OpenTasks.Remove(id);
            OpenTaskTimes.Remove(id);

            openTask.SetResult(data.SelectToken("result"));
        }
        protected override void HandleApiResponse(IEnumerable <object> args)
        {
            var data = args.Cast <JToken>().First();

            if (data == null && data.Children().Count() != 2)
            {
                return;
            }

            var idToken = data.SelectToken("id");

            if (idToken == null)
            {
                throw new Exception("response id not found.");
            }

            string id = idToken.ToObject <string>();

            OpenTask openTask;

            if (!OpenTasks.TryGetValue(id, out openTask))
            {
                return;
            }

            OpenTasks.Remove(id);

            openTask.PromiseTask.SetResult(data.SelectToken("result"));
        }
        public async Task <JToken> SendApiRequest(Request request)
        {
            if (request.Type == "identityFromPermissions" && !Paired)
            {
                return(false);
            }

            await Pair();

            if (!Paired)
            {
                throw new Exception("The user did not allow this app to connect to their Scatter");
            }

            var tcs = new TaskCompletionSource <JToken>();

            request.Id     = UtilsHelper.RandomNumber(24);
            request.Appkey = StorageProvider.GetAppkey();
            request.Nonce  = StorageProvider.GetNonce() ?? "";

            var nextNonce = UtilsHelper.RandomNumberBytes();

            request.NextNonce = UtilsHelper.ByteArrayToHexString(Sha256Manager.GetHash(nextNonce));
            StorageProvider.SetNonce(UtilsHelper.ByteArrayToHexString(nextNonce));

            OpenTasks.Add(request.Id, tcs);
            OpenTaskTimes.Add(request.Id, DateTime.Now);

            await Send("api", new { data = request, plugin = AppName });

            return(await tcs.Task);
        }
        protected void HandlePairedResponse(bool?paired)
        {
            Paired = paired.GetValueOrDefault();

            if (Paired)
            {
                var storedAppKey = StorageProvider.GetAppkey();

                string hashed = storedAppKey.StartsWith("appkey:") ?
                                UtilsHelper.ByteArrayToHexString(Sha256Manager.GetHash(Encoding.UTF8.GetBytes(storedAppKey))) :
                                storedAppKey;

                if (string.IsNullOrWhiteSpace(storedAppKey) ||
                    storedAppKey != hashed)
                {
                    StorageProvider.SetAppkey(hashed);
                }
            }

            OpenTask openTask;

            if (!OpenTasks.TryGetValue(PairOpenId, out openTask))
            {
                return;
            }

            openTask.PromiseTask.SetResult(Paired);
            openTask.TaskTimeoutMS = int.MaxValue;
        }
        /// <summary>
        /// Pair appication to registered applications in scatter
        /// </summary>
        /// <param name="passthrough">pass through rekey process</param>
        /// <param name="timeout">set response timeout that overrides the default one</param>
        /// <returns></returns>
        public async Task Pair(bool passthrough = false, int?timeout = null)
        {
            var pairOpenTask = new TaskCompletionSource <object>();
            var openTask     = new OpenTask()
            {
                PromiseTask     = pairOpenTask,
                TaskRequestTime = DateTime.Now,
                TaskTimeoutMS   = timeout.HasValue ? timeout.Value : TimeoutMS
            };

            if (OpenTasks.ContainsKey(PairOpenId))
            {
                OpenTasks[PairOpenId] = openTask;
            }
            else
            {
                OpenTasks.Add(PairOpenId, openTask);
            }

            await SockIO.EmitAsync("pair", new RequestWrapper()
            {
                data = new PairRequest()
                {
                    appkey      = StorageProvider.GetAppkey(),
                    passthrough = passthrough,
                    origin      = AppName
                },
                plugin = AppName
            });

            await pairOpenTask.Task;
        }
        private void TimeoutOpenTasksCheck()
        {
            while (Socket.State == WebSocketState.Open)
            {
                var now   = DateTime.Now;
                int count = 0;

                foreach (var ttKey in OpenTaskTimes.Keys)
                {
                    if ((now - OpenTaskTimes[ttKey]).TotalMilliseconds >= TimeoutMS)
                    {
                        TaskCompletionSource <JToken> openTask = OpenTasks[ttKey];

                        OpenTasks.Remove(ttKey);
                        OpenTaskTimes.Remove(ttKey);

                        openTask.SetResult(JToken.FromObject(new ApiError()
                        {
                            Code    = "0",
                            IsError = "true",
                            Message = "Request timeout."
                        }));
                    }

                    //sleep checking each 10 requests
                    if ((count % 10) == 0)
                    {
                        Thread.Sleep(1000);
                    }

                    count++;
                }
            }
        }
        public void RefreshOpenTasks()
        {
            if (_settings.ServerSettings.JsonDirectory == null)
            {
                throw new DistSimException("Jsondirectory was null");
            }

            if (_settings.ServerSettings.JsonDirectory.Count == 0)
            {
                throw new DistSimException("Jsondirectory was empty");
            }

            foreach (string singledir in _settings.ServerSettings.JsonDirectory)
            {
                if (OpenTasks.Count > 1000)
                {
                    break;
                }

                DirectoryInfo di = new DirectoryInfo(singledir);
                if (!di.Exists)
                {
                    di.Create();
                    Thread.Sleep(100);
                }
                var files         = di.GetFiles("*.json");
                var activeFiles   = ActiveTasks.Select(x => x.OriginalJsonFilePath).ToList();
                var openTaskFiles = OpenTasks.Select(x => x.OriginalJsonFilePath).ToList();
                foreach (var fileInfo in files)
                {
                    if (activeFiles.Contains(fileInfo.FullName))
                    {
                        _logger.Info("Currently processing " + fileInfo.Name, _threadId);
                        continue;
                    }

                    if (openTaskFiles.Contains(fileInfo.FullName))
                    {
                        _logger.Info("Currently in queue " + fileInfo.Name, _threadId);
                        continue;
                    }

                    ServerExecutionTask set = new ServerExecutionTask(fileInfo.FullName, fileInfo.Name, Guid.NewGuid().ToString());
                    OpenTasks.Enqueue(set);
                    _logger.Info("Created a job for " + fileInfo.Name, _threadId);
                    if (OpenTasks.Count > 1000)
                    {
                        break;
                    }
                }
            }
        }
        protected IEnumerator TimeoutOpenTasksCheck()
        {
            while (SockIO.GetState() == WebSocketState.Open)
            {
                var           now          = DateTime.Now;
                int           count        = 0;
                List <string> toRemoveKeys = new List <string>();

                foreach (var key in OpenTasks.Keys.ToList())
                {
                    OpenTask openTask;
                    if (!OpenTasks.TryGetValue(key, out openTask))
                    {
                        continue;
                    }

                    if ((now - openTask.TaskRequestTime).TotalMilliseconds >= openTask.TaskTimeoutMS)
                    {
                        toRemoveKeys.Add(key);
                    }

                    //sleep checking each 10 requests
                    if ((count % ScatterConstants.OPEN_TASK_NR_CHECK) == 0)
                    {
                        count = 0;
                        yield return(WaitForOpenTasksCheck(ScatterConstants.OPEN_TASK_CHECK_INTERVAL_SECS));
                    }

                    count++;
                }

                foreach (var key in toRemoveKeys)
                {
                    OpenTask openTask;
                    if (!OpenTasks.TryGetValue(key, out openTask))
                    {
                        continue;
                    }

                    OpenTasks.Remove(key);

                    openTask.PromiseTask.SetResult(BuildApiError());
                }
                yield return(WaitForOpenTasksCheck(ScatterConstants.OPEN_TASK_CHECK_INTERVAL_SECS));
            }
        }
        /// <summary>
        /// Send api request to scatter
        /// </summary>
        /// <typeparam name="TRequest">Request type param</typeparam>
        /// <typeparam name="TReturn">Return type param</typeparam>
        /// <param name="request">Request object</param>
        /// <param name="timeout">set response timeout that overrides the default one</param>
        /// <returns></returns>
        public async Task <TReturn> SendApiRequest <TRequest, TReturn>(Request <TRequest> request, int?timeout = null)
        {
            if (request.type == "identityFromPermissions" && !Paired)
            {
                return(default(TReturn));
            }

            await Pair();

            if (!Paired)
            {
                throw new Exception("The user did not allow this app to connect to their Scatter");
            }

            var tcs = new TaskCompletionSource <object>();

            do
            {
                request.id = UtilsHelper.RandomNumber(24);
            }while (OpenTasks.ContainsKey(request.id));

            request.appkey = StorageProvider.GetAppkey();
            request.nonce  = StorageProvider.GetNonce() ?? "";

            var nextNonce = UtilsHelper.RandomNumberBytes();

            request.nextNonce = UtilsHelper.ByteArrayToHexString(Sha256Manager.GetHash(nextNonce));
            StorageProvider.SetNonce(UtilsHelper.ByteArrayToHexString(nextNonce));

            OpenTasks.Add(request.id, new OpenTask()
            {
                PromiseTask     = tcs,
                TaskRequestTime = DateTime.Now,
                TaskTimeoutMS   = timeout.HasValue ? timeout.Value : TimeoutMS
            });

            await SockIO.EmitAsync("api", new RequestWrapper()
            {
                data   = request,
                plugin = AppName
            });

            return(BuildApiResponse <TReturn>(await tcs.Task));
        }