Example #1
0
        private BWebServiceResponse OnRequest_Internal(HttpListenerContext _Context, Action <string> _ErrorMessageAction)
        {
            //GET is supported for easy calls from terraform scripts since it only has GET request support out of the box.
            //https://www.terraform.io/docs/providers/http/data_source.html
            //POST calls are recommended to use over GET.

            if (_Context.Request.HttpMethod != "DELETE")
            {
                _ErrorMessageAction?.Invoke("ScheduleRequest: DELETE methods are accepted. But received request method:  " + _Context.Request.HttpMethod);
                return(BWebResponse.MethodNotAllowed("DELETE methods are accepted. But received request method: " + _Context.Request.HttpMethod));
            }

            JObject ParsedBody = null;

            if (_Context.Request.HttpMethod == "DELETE")
            {
                using (var InputStream = _Context.Request.InputStream)
                {
                    using (var ResponseReader = new StreamReader(InputStream))
                    {
                        try
                        {
                            ParsedBody = JObject.Parse(ResponseReader.ReadToEnd());
                        }
                        catch (Exception e)
                        {
                            _ErrorMessageAction?.Invoke("Read request body stage has failed. Exception: " + e.Message + ", Trace: " + e.StackTrace);
                            return(BWebResponse.BadRequest("Malformed request body. Request must be a valid json form."));
                        }
                    }
                }
            }

            if (!ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.URL_PROPERTY) ||
                ParsedBody[ScheduledUrlTaskDBEntry.URL_PROPERTY].Type != JTokenType.String)
            {
                return(BWebResponse.BadRequest("Request must contain all necessary fields validly. Given argument: " + ParsedBody.ToString()));
            }

            string Url = (string)ParsedBody[ScheduledUrlTaskDBEntry.URL_PROPERTY];

            if (!Uri.TryCreate(Url, UriKind.Absolute, out Uri UriResult) ||
                (UriResult.Scheme != Uri.UriSchemeHttp && UriResult.Scheme != Uri.UriSchemeHttps))
            {
                return(BWebResponse.BadRequest("Given field " + ScheduledUrlTaskDBEntry.URL_PROPERTY + " is invalid. Given argument: " + ParsedBody.ToString()));
            }

            if (!DatabaseService.DeleteItem(
                    ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                    ScheduledUrlTaskDBEntry.KEY_NAME_TASK_URL,
                    new BPrimitiveType(WebUtility.UrlEncode(Url)),
                    out JObject _,
                    EBReturnItemBehaviour.DoNotReturn,
                    _ErrorMessageAction))
            {
                return(BWebResponse.InternalError("Database delete operation has failed."));
            }

            return(BWebResponse.StatusOK("Task has been unscheduled."));
        }
Example #2
0
        private BWebServiceResponse OnRequest_Internal(HttpListenerContext _Context, Action <string> _ErrorMessageAction)
        {
            //Any verb is accepted.

            var StartTimestamp = MSSinceEpoch();

            if (!DatabaseService.ScanTable(
                    ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                    out List <JObject> URLTasks_UrlEncoded,
                    _ErrorMessageAction))
            {
                return(BWebResponse.StatusOK("Table does not exist or ScanTable operation has failed.")); //Still ok.
            }
            if (URLTasks_UrlEncoded.Count == 0)
            {
                return(BWebResponse.StatusOK("There is no task in the database."));
            }

            var URLTasks = new List <ScheduledUrlTaskDBEntry>();

            foreach (var Current in URLTasks_UrlEncoded)
            {
                URLTasks.Add(JsonConvert.DeserializeObject <ScheduledUrlTaskDBEntry>(Current.ToString()));
            }

            long RemainedMS = 50000 - (MSSinceEpoch() - StartTimestamp); //60-50=10 seconds is for possible delays.

            while (RemainedMS > 0)
            {
                var BeforeTS = MSSinceEpoch();
                SecondCheck(_Context, URLTasks, _ErrorMessageAction);

                var Diff = MSSinceEpoch() - BeforeTS;
                if (Diff < 10000)
                {
                    Thread.Sleep(10000 - (int)Diff);
                }
                RemainedMS -= (MSSinceEpoch() - BeforeTS);
            }

            return(BWebResponse.StatusAccepted("Request has been accepted."));
        }
Example #3
0
        private void SecondCheck(HttpListenerContext _Context, List <ScheduledUrlTaskDBEntry> _URLTasks, Action <string> _ErrorMessageAction)
        {
            var WaitUntil = new ManualResetEvent(false);
            var Counter   = new ConcurrentStack <bool>();

            var DeleteItems = new ConcurrentQueue <ScheduledUrlTaskDBEntry>();
            var FailedItems = new ConcurrentQueue <ScheduledUrlTaskDBEntry>();
            var UpdateItems = new ConcurrentQueue <ScheduledUrlTaskDBEntry>();

            var TimeHasComeFor = new List <ScheduledUrlTaskDBEntry>();

            foreach (var URLTask in _URLTasks)
            {
                if (URLTask.ScheduledToTime < new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds())
                {
                    TimeHasComeFor.Add(URLTask);
                    Counter.Push(true);
                }
            }
            foreach (var Current in TimeHasComeFor)
            {
                var Process = Current;
                BTaskWrapper.Run(() =>
                {
                    var bRequestSuccess = PerformHttpRequest(out int StatusCode, Process.Url, Process.Verb, Process.Headers, Process.Body, _ErrorMessageAction);

                    bool bDeleted = false;
                    foreach (int CancelReturnCode in Process.CancelOnReturnCodes)
                    {
                        if (CancelReturnCode == StatusCode)
                        {
                            bDeleted = true;
                            DeleteItems.Enqueue(Process);
                            break;
                        }
                    }

                    if (!bDeleted)
                    {
                        if (bRequestSuccess)
                        {
                            if (Process.bCancelRetryOnSuccess)
                            {
                                DeleteItems.Enqueue(Process);
                            }
                            else
                            {
                                if (Process.RetryCount == -1 ||
                                    (Process.RetriedCount + 1) <= Process.RetryCount)
                                {
                                    UpdateItems.Enqueue(Process);
                                }
                                else
                                {
                                    DeleteItems.Enqueue(Process);
                                }
                            }
                        }
                        else
                        {
                            FailedItems.Enqueue(Process);
                        }
                    }

                    Counter.TryPop(out bool _);
                    if (Counter.IsEmpty)
                    {
                        try
                        {
                            WaitUntil.Set();
                        }
                        catch (Exception) { }
                    }
                });
            }

            try
            {
                if (TimeHasComeFor.Count > 0)
                {
                    WaitUntil.WaitOne();
                }
                WaitUntil.Close();
            }
            catch (Exception) { }

            while (FailedItems.TryDequeue(out ScheduledUrlTaskDBEntry Failed))
            {
                if (Failed.RetryCount == -1 ||
                    (Failed.RetriedCount + 1) <= Failed.RetryCount)
                {
                    Failed.RetriedCount++;
                    Failed.ScheduledToTime = new DateTimeOffset(DateTime.UtcNow.AddSeconds(Failed.RetryInSeconds)).ToUnixTimeSeconds();

                    DatabaseService.UpdateItem(
                        ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                        ScheduledUrlTaskDBEntry.KEY_NAME_TASK_URL,
                        new BPrimitiveType(WebUtility.UrlEncode(Failed.Url)),
                        JObject.Parse(JsonConvert.SerializeObject(Failed)),
                        out JObject _,
                        EBReturnItemBehaviour.DoNotReturn,
                        null,
                        _ErrorMessageAction);
                }
                else
                {
                    DeleteItems.Enqueue(Failed);
                }
            }

            while (UpdateItems.TryDequeue(out ScheduledUrlTaskDBEntry Update))
            {
                Update.RetriedCount++;
                Update.ScheduledToTime = new DateTimeOffset(DateTime.UtcNow.AddSeconds(Update.RetryInSeconds)).ToUnixTimeSeconds();

                DatabaseService.UpdateItem(
                    ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                    ScheduledUrlTaskDBEntry.KEY_NAME_TASK_URL,
                    new BPrimitiveType(WebUtility.UrlEncode(Update.Url)),
                    JObject.Parse(JsonConvert.SerializeObject(Update)),
                    out JObject _,
                    EBReturnItemBehaviour.DoNotReturn,
                    null,
                    _ErrorMessageAction);
            }

            while (DeleteItems.TryDequeue(out ScheduledUrlTaskDBEntry Delete))
            {
                DatabaseService.DeleteItem(
                    ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                    ScheduledUrlTaskDBEntry.KEY_NAME_TASK_URL,
                    new BPrimitiveType(WebUtility.UrlEncode(Delete.Url)),
                    out JObject _,
                    EBReturnItemBehaviour.DoNotReturn,
                    _ErrorMessageAction);
            }
        }
Example #4
0
        private BWebServiceResponse OnRequest_Internal(HttpListenerContext _Context, Action <string> _ErrorMessageAction)
        {
            //GET is supported for easy calls from terraform scripts since it only has GET request support out of the box.
            //https://www.terraform.io/docs/providers/http/data_source.html
            //POST calls are recommended to use over GET.

            if (_Context.Request.HttpMethod != "GET" && _Context.Request.HttpMethod != "POST")
            {
                _ErrorMessageAction?.Invoke("ScheduleRequest: GET and POST methods are accepted. But received request method:  " + _Context.Request.HttpMethod);
                return(BWebResponse.MethodNotAllowed("GET and POST methods are accepted. But received request method: " + _Context.Request.HttpMethod));
            }

            JObject ParsedBody = null;

            if (_Context.Request.HttpMethod == "GET")
            {
                if (!UrlParameters.ContainsKey("serialized"))
                {
                    return(BWebResponse.BadRequest("Malformed request. Url parameters must contain serialized= key."));
                }

                try
                {
                    ParsedBody = JObject.Parse(WebUtility.UrlDecode(UrlParameters["serialized"]));
                }
                catch (Exception e)
                {
                    _ErrorMessageAction?.Invoke("Read request body stage has failed. Exception: " + e.Message + ", Trace: " + e.StackTrace + ", Content: " + UrlParameters["serialized"]);
                    return(BWebResponse.BadRequest("Malformed request body. Request must be a valid json form."));
                }
            }
            else
            {
                using (var InputStream = _Context.Request.InputStream)
                {
                    using (var ResponseReader = new StreamReader(InputStream))
                    {
                        try
                        {
                            ParsedBody = JObject.Parse(ResponseReader.ReadToEnd());
                        }
                        catch (Exception e)
                        {
                            _ErrorMessageAction?.Invoke("Read request body stage has failed. Exception: " + e.Message + ", Trace: " + e.StackTrace);
                            return(BWebResponse.BadRequest("Malformed request body. Request must be a valid json form."));
                        }
                    }
                }
            }

            if (!ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.URL_PROPERTY) ||
                ParsedBody[ScheduledUrlTaskDBEntry.URL_PROPERTY].Type != JTokenType.String ||
                !ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.VERB_PROPERTY) ||
                ParsedBody[ScheduledUrlTaskDBEntry.VERB_PROPERTY].Type != JTokenType.String ||
                (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.HEADERS_PROPERTY) &&
                 ParsedBody[ScheduledUrlTaskDBEntry.HEADERS_PROPERTY].Type != JTokenType.Object) ||
                (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.BODY_PROPERTY) &&
                 ParsedBody[ScheduledUrlTaskDBEntry.BODY_PROPERTY].Type != JTokenType.Object) ||
                !ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.RETRY_COUNT_PROPERTY) ||
                ParsedBody[ScheduledUrlTaskDBEntry.RETRY_COUNT_PROPERTY].Type != JTokenType.Integer ||
                (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.CANCEL_RETRY_ON_SUCCESS_PROPERTY) &&
                 ParsedBody[ScheduledUrlTaskDBEntry.CANCEL_RETRY_ON_SUCCESS_PROPERTY].Type != JTokenType.Boolean) ||
                (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.CANCEL_ON_RETURN_CODES_PROPERTY) &&
                 ParsedBody[ScheduledUrlTaskDBEntry.CANCEL_ON_RETURN_CODES_PROPERTY].Type != JTokenType.Array) ||
                !ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.RETRY_IN_SECONDS_PROPERTY) ||
                ParsedBody[ScheduledUrlTaskDBEntry.RETRY_IN_SECONDS_PROPERTY].Type != JTokenType.Integer)
            {
                return(BWebResponse.BadRequest("Request must contain all necessary fields validly. Given argument: " + ParsedBody.ToString()));
            }

            var    Body = new JObject();
            bool   bCancelRetryOnSuccess = true;
            var    CancelOnReturnCodes   = new JArray();
            string Url = (string)ParsedBody[ScheduledUrlTaskDBEntry.URL_PROPERTY];

            if (!Uri.TryCreate(Url, UriKind.Absolute, out Uri UriResult) ||
                (UriResult.Scheme != Uri.UriSchemeHttp && UriResult.Scheme != Uri.UriSchemeHttps))
            {
                return(BWebResponse.BadRequest("Given field " + ScheduledUrlTaskDBEntry.URL_PROPERTY + " is invalid. Given argument: " + ParsedBody.ToString()));
            }
            string Verb = (string)ParsedBody[ScheduledUrlTaskDBEntry.VERB_PROPERTY];

            if (Verb != "GET" && Verb != "POST" && Verb != "PUT" && Verb != "DELETE")
            {
                return(BWebResponse.BadRequest("Field " + ScheduledUrlTaskDBEntry.VERB_PROPERTY + " must be one of these: GET, POST, PUT, DELETE. Given argument: " + ParsedBody.ToString()));
            }

            JObject Headers;

            if (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.HEADERS_PROPERTY))
            {
                Headers = (JObject)ParsedBody[ScheduledUrlTaskDBEntry.HEADERS_PROPERTY];
            }
            else
            {
                Headers = new JObject();
            }

            if (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.BODY_PROPERTY))
            {
                if (Verb == "GET" || Verb == "DELETE")
                {
                    return(BWebResponse.BadRequest("GET/DELETE requests cannot contain field " + ScheduledUrlTaskDBEntry.BODY_PROPERTY + ", given argument: " + ParsedBody.ToString()));
                }
                Body = (JObject)ParsedBody[ScheduledUrlTaskDBEntry.BODY_PROPERTY];
            }
            else if (Verb == "POST" || Verb == "PUT")
            {
                return(BWebResponse.BadRequest("POST/PUT requests must contain field " + ScheduledUrlTaskDBEntry.BODY_PROPERTY + ", given argument: " + ParsedBody.ToString()));
            }

            if (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.CANCEL_RETRY_ON_SUCCESS_PROPERTY))
            {
                bCancelRetryOnSuccess = (bool)ParsedBody[ScheduledUrlTaskDBEntry.CANCEL_RETRY_ON_SUCCESS_PROPERTY];
            }

            if (ParsedBody.ContainsKey(ScheduledUrlTaskDBEntry.CANCEL_ON_RETURN_CODES_PROPERTY))
            {
                CancelOnReturnCodes = (JArray)ParsedBody[ScheduledUrlTaskDBEntry.CANCEL_ON_RETURN_CODES_PROPERTY];
                foreach (var Item in CancelOnReturnCodes)
                {
                    if (Item.Type != JTokenType.Integer)
                    {
                        return(BWebResponse.BadRequest("All elements of " + ScheduledUrlTaskDBEntry.CANCEL_ON_RETURN_CODES_PROPERTY + " must be integer"));
                    }
                }
            }

            int RetryCount = (int)ParsedBody[ScheduledUrlTaskDBEntry.RETRY_COUNT_PROPERTY];

            if (RetryCount < -1)
            {
                return(BWebResponse.BadRequest("Field " + ScheduledUrlTaskDBEntry.RETRY_COUNT_PROPERTY + " must be greater than or equal to -1. Given argument: " + ParsedBody.ToString()));
            }
            int RetryInSeconds = (int)ParsedBody[ScheduledUrlTaskDBEntry.RETRY_IN_SECONDS_PROPERTY];

            if (RetryInSeconds < 0)
            {
                return(BWebResponse.BadRequest("Field " + ScheduledUrlTaskDBEntry.RETRY_IN_SECONDS_PROPERTY + " must be greater than or equal to 0. Given argument: " + ParsedBody.ToString()));
            }

            if (!DatabaseService.UpdateItem(
                    ScheduledUrlTaskDBEntry.DBSERVICE_SCHEDULED_URL_TASKS_TABLE(),
                    ScheduledUrlTaskDBEntry.KEY_NAME_TASK_URL,
                    new BPrimitiveType(WebUtility.UrlEncode(Url)),
                    JObject.Parse(JsonConvert.SerializeObject(new ScheduledUrlTaskDBEntry()
            {
                Url = Url,
                Verb = Verb,
                Body = Body,
                Headers = Headers,
                RetryCount = RetryCount,
                bCancelRetryOnSuccess = bCancelRetryOnSuccess,
                CancelOnReturnCodes = CancelOnReturnCodes,
                RetryInSeconds = RetryInSeconds,
                ScheduledToTime = new DateTimeOffset(DateTime.UtcNow.AddSeconds(RetryInSeconds)).ToUnixTimeSeconds()
            })),
                    out _,
                    EBReturnItemBehaviour.DoNotReturn,
                    null,
                    _ErrorMessageAction))
            {
                return(BWebResponse.InternalError("Database write operation has failed."));
            }

            return(BWebResponse.StatusOK("Task has been scheduled."));
        }