static void HandleOpt(ParsedOpts results, string arg, OptDef opt, string value) { if (opt != null) { Opt optVal = results.Opts[opt.Long]; if (value != null) { if (!opt.Value) { results.Error = String.Format("Argument '{0}' doesn't take a value", arg); } else if (optVal.Count > 0) { results.Error = String.Format("Multiple values found for '{0}'", arg); } else { optVal.Value = value; } } else if (opt.Value) { results.Error = String.Format("Argument '{0}' requires a value", arg); } optVal.Count++; } else { results.Error = String.Format("Unrecognized argument: '{0}'", arg); } }
static void ConfigureGlobalSettings(ParsedOpts parsedArgs) { var logLevel = (LogEventLevel)Math.Max((int)(LogEventLevel.Information - parsedArgs["verbose"].Count), 0); var logConfig = new LoggerConfiguration() .Enrich.FromLogContext() .MinimumLevel.Is(logLevel) .Filter.ByExcluding(e => IsHealthPingEvent(e)); if (IsDevelopmentEnvironment(parsedArgs)) { logConfig.WriteTo.LiterateConsole( outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {RequestId}] {Message}{NewLine}{Exception}" ); LoadEnvironmentVariables(parsedArgs); } else { logConfig.WriteTo.Console(new RenderedCompactJsonFormatter()); } // string honeycomb_key = Environment.GetEnvironmentVariable("HONEYCOMB_KEY"); // if (honeycomb_key != null) // { // Console.WriteLine("(Honeycomb configured.)"); // logConfig.WriteTo.Honeycomb("server", honeycomb_key); // } Serilog.Log.Logger = logConfig.CreateLogger(); DocumentStore.InitializeLogging(); }
static int DoShowAll(ParsedOpts args) { var profileStore = new UserProfileStore(); var aggregateStore = new AggregateRiverStore(); UserProfile profile = profileStore.GetProfileFor(args["user"].Value).Result; foreach (RiverDefinition rd in profile.Rivers) { Console.WriteLine("Loading {0} ({1})...", rd.Name, rd.Id); River river = aggregateStore.LoadAggregate(rd.Id).Result; if (river.UpdatedFeeds.Feeds.Count > 0) { foreach (FeedSegment feed in river.UpdatedFeeds.Feeds) { DumpFeed(feed); } } else { Console.WriteLine("No data for {0}", rd.Name); } } return(0); }
static int Main(string[] args) { try { Console.OutputEncoding = System.Text.Encoding.UTF8; ParsedOpts parsedArgs = Options.ParseArguments(args); if (parsedArgs.Error != null) { Console.Error.WriteLine(parsedArgs.Error); Console.Error.WriteLine(Options.GetHelp(parsedArgs.Verb)); return(1); } if (parsedArgs["help"].Flag) { Console.WriteLine(Options.GetHelp(parsedArgs.Verb)); return(0); } ConfigureGlobalSettings(parsedArgs); int result = parsedArgs.Verb.Handler(parsedArgs); Serilog.Log.CloseAndFlush(); return(result); } catch (Exception e) { Console.WriteLine(e); return(99); } }
static int DoInvite(ParsedOpts args) { var store = new InvitationStore(); Invitation invite = store.CreateInvitation(null).Result; string code = Uri.EscapeDataString(invite.Code); Console.WriteLine( $"Created invitation {invite.Code}: https://beta.rivers.friendlyhedgehog.com/signup?code={code}" ); return(0); }
static bool IsDevelopmentEnvironment(ParsedOpts parsedArgs) { if (!parsedArgs.Opts.ContainsKey("environment")) { return(true); } if (parsedArgs["environment"].Value.ToLowerInvariant() == "development") { return(true); } return(false); }
static int DoResetLogins(ParsedOpts args) { string user = args["user"].Value; var profileStore = new UserProfileStore(); var profile = profileStore.GetProfileFor(user).Result; var newProfile = profile.With(logins: new LoginCookie[0]); profileStore.SaveProfileFor(user, newProfile).Wait(); Console.WriteLine("OK"); return(0); }
static void LoadEnvironmentVariables(ParsedOpts parsedArgs) { // Assumes you're running from the source tree, since production doesn't have the deployment tool. string env; if (parsedArgs.Opts.TryGetValue("environment", out Opt envOpt)) { env = envOpt.Value.ToLowerInvariant(); } else { env = "development"; } string secretsFile = System.IO.Path.Combine("..", "deploy", "secrets.json"); if (File.Exists(secretsFile)) { Console.WriteLine("Reading secrets from the secret file..."); var client = new AmazonKeyManagementServiceClient(Amazon.RegionEndpoint.USWest2); var secretList = JsonConvert.DeserializeObject <JArray>(File.ReadAllText(secretsFile)); foreach (JObject secret in secretList) { string targetEnvironment = secret.Value <string>("env"); if (targetEnvironment == "all" || targetEnvironment == env) { string name = secret.Value <string>("name"); string value = secret.Value <string>("value"); Console.WriteLine("Decrypting {0}", name); var response = client.DecryptAsync(new Amazon.KeyManagementService.Model.DecryptRequest { CiphertextBlob = new MemoryStream(Convert.FromBase64String(value)), EncryptionContext = { { "application", "onceandfuture" }, }, }).Result; byte[] bytes = new byte[response.Plaintext.Length]; response.Plaintext.Read(bytes, 0, bytes.Length); string plainValue = System.Text.Encoding.UTF8.GetString(bytes).Trim(); Console.WriteLine("Setting {0}", name); System.Environment.SetEnvironmentVariable(name, plainValue); } } } }
static int DoThumbnail(ParsedOpts args) { Uri url = new Uri(args["url"].Value); ThumbnailResponse sourceImage = new ThumbnailExtractor().FindImageAsync(url).Result; if (sourceImage == null) { Console.Error.WriteLine("No image found @ {0}.", url); return(1); } Console.WriteLine(JsonConvert.SerializeObject(sourceImage, Formatting.Indented)); return(0); }
static int DoFindFeed(ParsedOpts args) { string url = args["url"].Value; Console.WriteLine("Finding feed for {0}...", url); IList <Uri> found = FeedDetector.GetFeedUrls(args["url"].Value).Result; foreach (Uri uri in found) { Console.WriteLine("{0}", uri.AbsoluteUri); } Console.WriteLine("Found {0} feeds", found.Count); return(0); }
static int DoSetPassword(ParsedOpts args) { string user = args["user"].Value; string password = args["password"].Value; var profileStore = new UserProfileStore(); var profile = profileStore.GetProfileFor(user).Result; var newProfile = profile.With( password: AuthenticationManager.EncryptPassword(password), logins: new LoginCookie[0]); profileStore.SaveProfileFor(user, newProfile).Wait(); Console.WriteLine("OK"); return(0); }
static int DoSetEmail(ParsedOpts args) { string user = args["user"].Value; string email = args["email"].Value; var profileStore = new UserProfileStore(); var profile = profileStore.GetProfileFor(user).Result; var newProfile = profile.With( email: email, emailVerified: false); profileStore.SaveProfileFor(user, newProfile).Wait(); Console.WriteLine("OK"); return(0); }
static int DoShowSingle(ParsedOpts args) { Uri feedUrl; if (!Uri.TryCreate(args["feed"].Value, UriKind.Absolute, out feedUrl)) { Console.Error.WriteLine("Feed not a valid url: {0}", args["feed"].Value); return(100); } River river = null; if (args["noload"].Flag) { // Make sure to follow redirects... for (int i = 0; i < 30; i++) { var cleanRiver = new River(metadata: new RiverFeedMeta(originUrl: feedUrl)); river = new RiverLoader().UpdateAsync(cleanRiver).Result; if (river.Metadata.LastStatus != HttpStatusCode.Moved) { break; } feedUrl = river.Metadata.OriginUrl; Console.WriteLine("(Following redirect to {0})", feedUrl); } } else { var feedStore = new RiverFeedStore(); river = feedStore.LoadRiverForFeed(feedUrl).Result; } if (river.UpdatedFeeds.Feeds.Count > 0) { foreach (FeedSegment feed in river.UpdatedFeeds.Feeds) { DumpFeed(feed); } } else { Console.WriteLine("No data for {0}", feedUrl); } return(0); }
static int DoUpdateForUser(ParsedOpts args) { string user = args["user"].Value; var subscriptionStore = new UserProfileStore(); var parser = new RiverLoader(); Console.WriteLine("Refreshing for {0}...", user); Stopwatch loadTimer = Stopwatch.StartNew(); UserProfile profile = subscriptionStore.GetProfileFor(user).Result; var tasks = from rd in profile.Rivers select parser.RefreshAggregateRiverWithFeeds(rd.Id, rd.Feeds); Task.WhenAll(tasks).Wait(); Console.WriteLine("Refreshed {0} rivers in {1}", profile.Rivers.Count, loadTimer.Elapsed); return(0); }
static int DoSubscribe(ParsedOpts args) { string user = args["user"].Value; string feed = args["feed"].Value; string riverName = args["river"].Value; // Check feed. var parser = new RiverLoader(); var feedStore = new RiverFeedStore(); River feedRiver = parser.FetchAndUpdateRiver(new Uri(feed)).Result; if (feedRiver.Metadata.LastStatus < (HttpStatusCode)200 || feedRiver.Metadata.LastStatus >= (HttpStatusCode)400) { Console.Error.WriteLine("Could not fetch feed {0}", feed); return(-1); } var subscriptionStore = new UserProfileStore(); UserProfile profile = subscriptionStore.GetProfileFor(user).Result; RiverDefinition river = profile.Rivers.FirstOrDefault(r => r.Name == riverName); UserProfile newProfile; if (river == null) { newProfile = profile.With( rivers: profile.Rivers.Add( new RiverDefinition( name: riverName, id: SyndicationUtil.MakeID(), feeds: new Uri[] { feedRiver.Metadata.OriginUrl }))); } else { var newRiver = river.With(feeds: river.Feeds.Add(feedRiver.Metadata.OriginUrl)); newProfile = profile.With(rivers: profile.Rivers.Replace(river, newRiver)); } subscriptionStore.SaveProfileFor(user, newProfile).Wait(); Console.WriteLine("OK"); return(0); }
static int DoUpdateSingleFeed(ParsedOpts args) { Uri feedUrl; if (!Uri.TryCreate(args["feed"].Value, UriKind.Absolute, out feedUrl)) { Console.Error.WriteLine("Feed not a valid url: {0}", args["feed"].Value); return(100); } var parser = new RiverLoader(); Console.WriteLine("Refreshing {0}...", feedUrl); Stopwatch loadTimer = Stopwatch.StartNew(); parser.FetchAndUpdateRiver(feedUrl).Wait(); Console.WriteLine("Refreshed {0} in {1}", feedUrl, loadTimer.Elapsed); return(0); }
static int DoServe(ParsedOpts args) { // read configuration values from environment variables var config = new ConfigurationBuilder() .AddEnvironmentVariables() .Build(); // use Kestrel server with cwd content root var host = new WebHostBuilder() .UseConfiguration(config) .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup <WebStartup>() .UseUrls(args["url"].Value) .UseEnvironment(args["environment"].Value) .Build(); host.Run(); return(0); }
static int DoShow(ParsedOpts args) { if (args["feed"].Value != null) { return(DoShowSingle(args)); } else if (args["user"].Value != null) { return(DoShowAll(args)); } else if (args["river"].Value != null) { return(DoShowRiver(args)); } else { Console.Error.WriteLine("Must specify user, feed, or river."); return(-1); } }
static int DoShowRiver(ParsedOpts args) { string aggregateId = args["river"].Value; var aggregateStore = new AggregateRiverStore(); River river = aggregateStore.LoadAggregate(aggregateId).Result; if (river.UpdatedFeeds.Feeds.Count > 0) { foreach (FeedSegment feed in river.UpdatedFeeds.Feeds) { DumpFeed(feed); } } else { Console.WriteLine("No data for {0}", aggregateId); } return(0); }
static int DoUnsubscribe(ParsedOpts args) { string user = args["user"].Value; Uri feed = new Uri(args["feed"].Value); string riverName = args["river"].Value; var subscriptionStore = new UserProfileStore(); UserProfile profile = subscriptionStore.GetProfileFor(user).Result; RiverDefinition river = profile.Rivers.FirstOrDefault(r => r.Name == riverName); if (river == null) { Console.WriteLine("River {0} not found.", riverName); return(0); } RiverDefinition newRiver = river.With(feeds: river.Feeds.Remove(feed)); UserProfile newProfile = profile.With(rivers: profile.Rivers.Replace(river, newRiver)); subscriptionStore.SaveProfileFor(user, newProfile).Wait(); Console.WriteLine("OK"); return(0); }
static int DoUpdate(ParsedOpts args) { if (args["feed"].Value != null) { return(DoUpdateSingleFeed(args)); } else if (args["user"].Value != null) { if (args["river"].Value != null) { return(DoUpdateForRiver(args)); } else { return(DoUpdateForUser(args)); } } else { Console.Error.WriteLine("Must specify either user or feed."); return(-1); } }
static int DoList(ParsedOpts args) { string user = args["user"].Value; UserProfile profile = new UserProfileStore().GetProfileFor(user).Result; foreach (var river in profile.Rivers) { Console.WriteLine("{0} ({1}):", river.Name, river.Id); if (river.Feeds.Count > 0) { foreach (var feed in river.Feeds) { Console.WriteLine(" {0}", feed); } } else { Console.WriteLine(" No feeds."); } Console.WriteLine(); } return(0); }
public ParsedOpts ParseArguments(string[] args) { ParsedOpts results = new ParsedOpts(); for (int i = 0; i < Options.Count; i++) { results.Opts[Options[i].Long] = new Opt(Options[i]); } List <OptDef> verbOptions = null; for (int argIndex = 0; argIndex < args.Length; argIndex++) { OptDef opt; string arg = args[argIndex]; if (arg.StartsWith("--", StringComparison.Ordinal)) { string[] parts = arg.Substring(2).Split(new char[] { '=' }, 2); string longArg = parts[0]; string val = null; if (parts.Length == 2) { val = parts[1]; } opt = Options.Find(o => String.Equals(o.Long, longArg)); if (opt == null && verbOptions != null) { opt = verbOptions.Find(o => String.Equals(o.Long, longArg)); } HandleOpt(results, arg, opt, val); } else if (arg[0] == '-') { if (arg.Length == 1) { results.Error = String.Format("Unrecognized argument: '{0}'", arg); } else { for (int flagIndex = 1; flagIndex < arg.Length; flagIndex++) { string val = null; char flag = arg[flagIndex]; if (flagIndex + 1 < arg.Length && arg[flagIndex] == '=') { val = arg.Substring(flagIndex + 2); flagIndex = arg.Length; } opt = Options.Find(o => o.Short == flag); if (opt == null && verbOptions != null) { opt = verbOptions.Find(o => o.Short == flag); } HandleOpt(results, flag.ToString(), opt, val); if (results.Error != null) { break; } } } } else { if (results.Verb == null && this.Verbs.Count > 0) { VerbDef verbdef; if (!this.Verbs.TryGetValue(arg, out verbdef)) { results.Error = String.Format("Unknown verb: {0}", arg); } else { results.Verb = verbdef; verbOptions = verbdef.Options; for (int verbOptionIndex = 0; verbOptionIndex < verbOptions.Count; verbOptionIndex++) { results.Opts[verbOptions[verbOptionIndex].Long] = new Opt(verbOptions[verbOptionIndex]); } } } else { results.Error = String.Format("Unrecognized argument: '{0}'", arg); } } if (results.Error != null) { break; } } // Check for missing verb if (results.Error == null && results.Verb == null && this.Verbs.Count > 0) { results.Error = String.Format( "Did not find a verb; specify one of: {0}", String.Join(", ", this.Verbs.Keys)); } // Check for missing required option if (results.Error == null) { foreach (Opt opt in results.Opts.Values) { if (opt.Option.Required && opt.Count == 0) { results.Error = String.Format("Missing required option {0}", opt.Option.Long); break; } } } return(results); }