Example #1
0
        /// <summary>
        /// Creates an argument of a specific type by parsing the string
        /// </summary>
        /// <returns>The parsed object.</returns>
        /// <param name="value">The string to parse.</param>
        /// <param name="targettype">The type to parse to.</param>
        public static object ArgumentFromString(string value, Type targettype)
        {
            if (targettype.IsEnum)
            {
                var entries = ExpandEnvironmentVariables(value ?? "")
                              .Split('|')
                              .Select(x => Enum.Parse(targettype, x, true))
                              .ToArray();
                if (entries.Length == 1)
                {
                    return(entries.First());
                }
                else
                {
                    return(Enum.ToObject(
                               targettype,
                               entries.Select(x => (int)Convert.ChangeType(x, typeof(int))).Sum()
                               ));
                }
            }

            if (targettype.IsArray)
            {
                // TODO: Handle embedded comma values in strings?
                var args =
                    (value ?? "")
                    .Split(',')
                    .Select(x => ArgumentFromString((x ?? string.Empty).Trim(), targettype.GetElementType()))
                    .ToArray();

                // Manually convert to the right type
                var res = Array.CreateInstance(targettype.GetElementType(), args.Length);
                Array.Copy(args, res, args.Length);
                return(res);
            }

            if ((targettype.IsArray || targettype == typeof(string)) && string.Equals(value, "null", StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            if (targettype == typeof(TimeSpan))
            {
                return(ParseUtil.ParseDuration(ExpandEnvironmentVariables(value)));
            }
            if (targettype == typeof(int) || targettype == typeof(uint) || targettype == typeof(long) || targettype == typeof(ulong))
            {
                return(Convert.ChangeType(ParseUtil.ParseSize(ExpandEnvironmentVariables(value)), targettype));
            }
            if (targettype == typeof(bool))
            {
                return(ParseUtil.ParseBool(ExpandEnvironmentVariables(value)));
            }

            return(Convert.ChangeType(ExpandEnvironmentVariables(value), targettype));
        }
Example #2
0
        /// <summary>
        /// Configures the database and sets it up
        /// </summary>
        public override void AfterConfigure()
        {
            // If we share the database with another queue, share the connection as well
            lock (_lock)
                foreach (var m in _modules)
                {
                    if (m.Value.ConnectionClass == this.ConnectionClass && m.Value.ConnectionString == this.ConnectionString)
                    {
                        m_con = m.Value.m_con;
                        break;
                    }
                }

            // Initialize
            base.AfterConfigure();

            // The CLI will help us a little bit
            if (string.IsNullOrWhiteSpace(this.SelfUrl))
            {
                this.SelfUrl = Environment.GetEnvironmentVariable("CEEN_SELF_HTTPS_URL");
            }
            if (string.IsNullOrWhiteSpace(this.SelfUrl))
            {
                this.SelfUrl = Environment.GetEnvironmentVariable("CEEN_SELF_HTTP_URL");
            }

            if (string.IsNullOrWhiteSpace(this.SelfUrl))
            {
                throw new Exception($"The QueueModule needs to know the server url to call back to, please set the {nameof(SelfUrl)} variable");
            }

            // Remove trailing slashes to make it easier to concatenate strings
            this.SelfUrl = this.SelfUrl.Trim().TrimEnd('/');

            if (string.IsNullOrWhiteSpace(Name))
            {
                throw new Exception("The name of the queue cannot be empty");
            }
            if (string.IsNullOrWhiteSpace(SecureHeaderName))
            {
                throw new Exception("The secure header name cannot be empty");
            }
            if (string.IsNullOrWhiteSpace(Ratelimit))
            {
                throw new Exception("The rate limit value cannot be empty");
            }
            if (string.IsNullOrWhiteSpace(RetryBackoff))
            {
                throw new Exception("The retry backoff value cannot be empty");
            }
            if (MaxRetries <= 0)
            {
                throw new Exception("Invalid max retry count");
            }

            // Assign a random value
            if (string.IsNullOrWhiteSpace(SecureHeaderValue))
            {
                SecureHeaderValue = Guid.NewGuid().ToString();
            }

            var rl = Ratelimit.Split(new char[] { '/' }, 2);

            if (rl.Length != 2 || rl[0].Length < 1 || rl[1].Length < 1)
            {
                throw new Exception("Unable to parse the ratelimit");
            }
            if (rl[1][0] < '0' || rl[1][0] > '9')
            {
                rl[1] = '1' + rl[1];
            }

            m_ratelimitcount  = int.Parse(rl[0]);
            m_ratelimitWindow = ParseUtil.ParseDuration(rl[1]);
            if (m_ratelimitWindow.Ticks <= 0 || m_ratelimitcount <= 0)
            {
                throw new Exception("Invalid rate limit");
            }

            var rb = RetryBackoff.Split(new char[] { ';' }, 3);
            var re = new System.Text.RegularExpressions.Regex(@"(?<mode>[exp|lin|exponential|linear])\w+(?<rate>.+)");

            // Only have the exp/lin, compute start and limit
            if (rb.Length == 1)
            {
                var m = re.Match(rb[0]);
                if (!m.Success)
                {
                    throw new Exception("Unable to parse the backoff");
                }
                var duration = m.Groups["rate"].Value;
                var ps       = ParseUtil.ParseDuration(duration);
                rb = new string[] { duration, rb[0], $"{ps.TotalSeconds * MaxRetries}s" };
            }
            else if (rb.Length == 2)
            {
                // First is exp/lin, last is limit, compute start
                var m = re.Match(rb[0]);
                if (m.Success)
                {
                    rb = new string[] { m.Groups["rate"].Value, rb[0], rb[1] };
                }
                // Second is exp/lin, first is start, compute last
                else
                {
                    m = re.Match(rb[1]);
                    if (!m.Success)
                    {
                        throw new Exception("Unable to parse the backoff");
                    }

                    var duration = m.Groups["rate"].Value;
                    var ps       = ParseUtil.ParseDuration(duration);
                    rb = new string[] { rb[0], rb[1], $"{ps.TotalSeconds * MaxRetries}s" };
                }
            }

            var mx = re.Match(rb[1]);

            if (!mx.Success)
            {
                throw new Exception("Unable to parse the backoff");
            }

            m_initialbackoff     = ParseUtil.ParseDuration(rb[0]);
            m_maximumbackoff     = ParseUtil.ParseDuration(rb[2]);
            m_additionalbackoff  = ParseUtil.ParseDuration(mx.Groups["rate"].Value);
            m_exponentialBackoff = mx.Groups["mode"].Value.StartsWith("exp", true, System.Globalization.CultureInfo.InvariantCulture);

            if (m_initialbackoff.Ticks < 0 || m_maximumbackoff.Ticks < 0 || m_additionalbackoff.Ticks < 0)
            {
                throw new Exception("Invalid back-off values");
            }

            m_ratelimiter = new RateLimit(m_ratelimitcount, m_ratelimitWindow);

            lock (_lock)
                _modules.Add(Name, this);

            // Activate the runner
            SignalRunner();
        }