private static IStore LoadStore(Options options) { bool readOnlyMode = options.Seeds is null; IStore innerStore; switch (options.StoreType) { case "rocksdb": innerStore = new RocksDBStore.RocksDBStore(options.StorePath); break; case "default": innerStore = new DefaultStore( options.StorePath, flush: false, readOnly: readOnlyMode); break; default: // FIXME: give available store type as argument hint without code duplication. var availableStoreTypes = new[] { "rocksdb", "default" }; string longOptionName = options.GetType().GetProperty(nameof(options.StoreType)) .GetCustomAttribute <OptionAttribute>().LongName; throw new InvalidOptionValueException( "--" + longOptionName, options.StoreType, availableStoreTypes); } IStore store; if (options.Seeds.Any()) { // Wrap up store to use more useful features. store = new RichStore( innerStore, path: options.StorePath, flush: false, readOnly: readOnlyMode ); } else { // If there were no given seeds, // use the store directly. store = innerStore; } return(store); }
public static async Task Main(string[] args) { Options options = Options.Parse(args, Console.Error); var loggerConfig = new LoggerConfiguration(); loggerConfig = options.Debug ? loggerConfig.MinimumLevel.Debug() : loggerConfig.MinimumLevel.Information(); loggerConfig = loggerConfig .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .Enrich.FromLogContext() .WriteTo.Console(); Log.Logger = loggerConfig.CreateLogger(); bool readOnlyMode = options.Seeds is null; // Initialized DefaultStore. IStore store = new DefaultStore( path: options.StorePath, flush: false, readOnly: readOnlyMode ); if (options.Seeds.Any()) { // Warp up store. store = new RichStore( store, path: options.StorePath, flush: false, readOnly: readOnlyMode ); } IBlockPolicy <AppAgnosticAction> policy = new BlockPolicy <AppAgnosticAction>( null, blockIntervalMilliseconds: options.BlockIntervalMilliseconds, minimumDifficulty: options.MinimumDifficulty, difficultyBoundDivisor: options.DifficultyBoundDivisor); var blockChain = new BlockChain <AppAgnosticAction>(policy, store, options.GenesisBlock); Startup.BlockChainSingleton = blockChain; Startup.StoreSingleton = store; IWebHost webHost = WebHost.CreateDefaultBuilder() .UseStartup <ExplorerStartup <AppAgnosticAction, Startup> >() .UseSerilog() .UseUrls($"http://{options.Host}:{options.Port}/") .Build(); Swarm <AppAgnosticAction> swarm = null; if (options.Seeds.Any()) { Console.WriteLine( $"Seeds are {options.SeedStrings.Aggregate(string.Empty, (s, s1) => s + s1)}"); // TODO: Take privateKey as a CLI option // TODO: Take appProtocolVersion as a CLI option // TODO: Take host as a CLI option // TODO: Take listenPort as a CLI option if (options.IceServer is null) { Console.Error.WriteLine( "error: -s/--seed option requires -I/--ice-server as well." ); Environment.Exit(1); return; } Console.WriteLine("Creating Swarm."); var privateKey = new PrivateKey(); // FIXME: The appProtocolVersion should be fixed properly. swarm = new Swarm <AppAgnosticAction>( blockChain, privateKey, options.AppProtocolVersionToken is string t ? AppProtocolVersion.FromToken(t) : default(AppProtocolVersion), differentAppProtocolVersionEncountered: (p, pv, lv) => true, iceServers: new[] { options.IceServer } ); } using (var cts = new CancellationTokenSource()) using (swarm) { Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; cts.Cancel(); }; try { await Task.WhenAll( webHost.RunAsync(cts.Token), StartSwarmAsync(swarm, options.Seeds, cts.Token) ); } catch (OperationCanceledException) { await swarm?.StopAsync(waitFor : TimeSpan.FromSeconds(1)) .ContinueWith(_ => NetMQConfig.Cleanup(false)); } } }