public static ILogStreamerConfiguration Load(string sourceUri, string explicitUpstreamUri)
        {
            string content = string.Empty;

            if (sourceUri.StartsWith("http://")) {
                var contentResult = Http.GET(sourceUri);
                if (contentResult == null || !contentResult.IsSuccessStatusCode) {
                    throw new ArgumentException(string.Format(
                        "Http.GET(\"{0}\") returned {1}",
                        sourceUri,
                        contentResult == null ? "null" : "status " + contentResult.StatusCode
                        ));
                }

                content = contentResult.Body;

            } else {
                if (sourceUri.StartsWith("file://")) {
                    sourceUri = sourceUri.Substring(7);
                }

                content = File.ReadAllText(sourceUri);
            }

            var cfg = new Configuration();
            cfg.PopulateFromJson(content);

            cfg.ListenUri = CleanUri(cfg.ListenUri);

            if (string.IsNullOrWhiteSpace(explicitUpstreamUri))
            {
                cfg.UpstreamUri = CleanUri(cfg.UpstreamUri);
            }
            else
            {
                cfg.UpstreamUri = CleanUri(explicitUpstreamUri);
            }

            return cfg.ToConfiguration();
        }
 void SettleAndApplyDefaults(Configuration cfg)
 {
     firstKey = cfg.FirstUserOid == 0 ? Db.Environment.FirstUserOid : (ulong)cfg.FirstUserOid;
     lastKey = cfg.LastUserOid == 0 ? Db.Environment.LastUserOid : (ulong)cfg.LastUserOid;
     reconnectMin = cfg.ReconnectMinimumWaitSeconds == 0 ? LogStreamerConfiguration.DefaultReconnectMinimumWaitSeconds : (int)cfg.ReconnectMinimumWaitSeconds;
     reconnectMax = cfg.ReconnectMaximumWaitSeconds == 0 ? LogStreamerConfiguration.DefaultReconnectMaximumWaitSeconds : (int)cfg.ReconnectMaximumWaitSeconds;
 }
 public void SetContent(Configuration cfg)
 {
     cfg.ValidateContent();
     SettleAndApplyDefaults(cfg);
     content = cfg;
 }
        /// <summary>
        /// The LogStreamer sample application allows simple transaction log
        /// streaming between Starcounter databases. It accepts three kinds
        /// of command line parameters.
        /// 
        /// An URI or file path ending with ".logstreamer.xml" is taken to be
        /// the source of a LogStreamer configuration to use. If it is a local
        /// file path, the file will be created if necessary.
        /// 
        /// Any other string not starting with '@' will be taken as the
        /// upstream URI to use. Either or both of these parameters may be
        /// omitted.
        /// 
        /// Parameters starting with '@' are documented in code, but should
        /// not be needed for general use.
        /// 
        /// Usually when starting LogStreamer, you'll want to launch it into
        /// a specific database. If you prefer, you can do that from the
        /// command line using something like this:
        /// 
        ///  star.exe -d=DBNAME LogStreamer.exe
        /// 
        /// </summary>
        /// <param name="args">Command line parameters.</param>
        static void Main(string[] args)
        {
            string upstreamUri = null;
            bool streamingEnabled = true;
            bool generateConfigFile = false;
            bool useFileLog = false;
            var options = new HandlerOptions() {
                SkipRequestFilters = true
            };

            // Provide a host local handler for the default config.
            // Don't move this one - it must be present for the configuration loader
            // if default configuration is in effect.
            Handle.GET(DefaultRelativeUri, HandleGETDefaultConfigFile, options);

            // Provide a handler for some more throughout sample configuration
            Handle.GET(SampleRelativeUri, HandleGETSampleConfigFile, options);

            foreach (var arg in args) {
                if (arg == null || arg.Length < 1)
                    continue;

                // If you pass .config.json, we take it. Otherwise,
                // we consider it the upstream URI

                if (arg[0] != '@') {
                    if (arg.EndsWith(".config.json")) {
                        _configUri = arg;
                    } else {
                        upstreamUri = arg;
                    }
                } else if (arg.Equals("@disabled", StringComparison.CurrentCultureIgnoreCase) || arg.Equals("@paused", StringComparison.CurrentCultureIgnoreCase)) {
                    streamingEnabled = false;
                } else if (arg.Equals("@enabled", StringComparison.CurrentCultureIgnoreCase)) {
                    streamingEnabled = true;
                } else if (arg.Equals("@generate", StringComparison.CurrentCultureIgnoreCase)) {
                    generateConfigFile = true;
                } else if (arg.Equals("@logfile", StringComparison.CurrentCultureIgnoreCase)) {
                    useFileLog = true;
                } else {
                    Console.WriteLine("Warning: Ignoring unrecognized argument '{0}'", arg);
                }
            }

            if (string.IsNullOrWhiteSpace(_configUri)) {
                // Apply the default URI, and then make sure the log streamer
                // is disabled until explicitly told otherwise
                string filePath = GetDefaultFilePath();
                if (generateConfigFile || File.Exists(filePath)) {
                    _configUri = "file://" + filePath;
                } else {
                    _configUri = "http://localhost:" + StarcounterEnvironment.Default.UserHttpPort + DefaultRelativeUri;
                    streamingEnabled = false;
                }
            }

            if (generateConfigFile) {
                if (!_configUri.Contains("://")) {
                    _configUri = "file://" + _configUri;
                }
                if (_configUri.StartsWith("file://")) {
                    var cfg = new Configuration();
                    cfg.ApplyDefaults();
                    if (!string.IsNullOrWhiteSpace(upstreamUri)) {
                        cfg.UpstreamUri = LogStreamerConfiguration.CleanUri(upstreamUri);
                    }
                    File.WriteAllText(_configUri.Substring(7), ConfigToJson(cfg.ToConfiguration()));
                } else {
                    Console.WriteLine("Can't generate config file for URI '{0}'", _configUri);
                }
            }

            _config = LogStreamerConfiguration.Load(_configUri, upstreamUri);

            Console.WriteLine(
                "Starting LogStreamer in {0}, OID range {1} - {2}. UpstreamUri: '{3}'.",
                Db.Environment.DatabaseName,
                Db.Environment.FirstUserOid,
                Db.Environment.LastUserOid,
                _config.UpstreamUri ?? ""
                );

            // Ensure that the FirstUserOid and LastUserOid match what we actually have.
            if (_config.FirstUserOid != Db.Environment.FirstUserOid) {
                throw new ArgumentException("FirstUserOid mismatch: config " + _config.FirstUserOid + " != " + Db.Environment.FirstUserOid + " actual");
            }
            if (_config.LastUserOid != Db.Environment.LastUserOid) {
                throw new ArgumentException("LastUserOid mismatch: config " + _config.LastUserOid + " != " + Db.Environment.LastUserOid + " actual");
            }

            Handle.GET(BaseUri, HandleGETRoot);
            Handle.GET(BaseUri + "/log", HandleGETLog);
            Handle.GET(BaseUri + "/config", HandleGETConfig);
            Handle.GET<string>(BaseUri + "?{?}", HandleGETRootParam);
            Handle.GET(BaseUri + "/config/upstreamwhitelist", HandleGETUpstreamWhitelist);
            Handle.GET(BaseUri + "/config/downstreamwhitelist", HandleGETDownstreamWhitelist);

            string logFilePath = null;
            if (useFileLog) {
                logFilePath = Path.Combine(GetConfigDirectory(), "logs", "logstreamer", Db.Environment.DatabaseNameLower + ".logstreamer.log");
                (new FileInfo(logFilePath)).Directory.Create();
            }
            _logger = new Logger(logFilePath);

            Status = "Not connected.";

            if (!string.IsNullOrWhiteSpace(_config.ListenUri)) {
                _server = new LogStreamerParent(_logger, _servermanager, _serverCts.Token, _config);
            }

            StreamingEnabled = streamingEnabled;
        }
        private static Response HandleGETSampleConfigFile()
        {
            var cfg = new Configuration();
            cfg.ApplyDefaults();

            int prio;
            string table;

            var r = new Random();
            if (r.Next(100) < 50) {
                prio = r.Next(2);
                table = "Invoice";
                cfg.AddToUpstreamWhitelist(table, prio);
                cfg.AddToDownstreamWhitelist(table, prio);
            }
            if (r.Next(100) < 50) {
                prio = r.Next(2);
                table = "InvoiceRow";
                cfg.AddToUpstreamWhitelist(table, prio);
                cfg.AddToDownstreamWhitelist(table, prio);
            }

            return cfg;
        }
 private static Response HandleGETDefaultConfigFile()
 {
     var cfg = new Configuration();
     cfg.ApplyDefaults();
     return cfg;
 }
 static private Configuration GetConfiguration()
 {
     Configuration conf = Db.SQL<Configuration>("SELECT c FROM LogStreamer.Configuration c WHERE c.DatabaseGuid = ?", Db.Environment.DatabaseGuid.ToString()).First;
     if (conf == null)
     {
         conf = new Configuration()
         {
             DatabaseGuid = Db.Environment.DatabaseGuid.ToString(),
             ParentUri = System.Environment.MachineName + ":" + StarcounterEnvironment.Default.UserHttpPort,
             ParentGuid = "",
             ReconnectMinimumWaitSeconds = 1,
             ReconnectMaximumWaitSeconds = 60 * 60 * 24,
         };
     }
     return conf;
 }