public void RunCore() { Logging.Log.Instance.DiscordLibraryLevel.Level = System.Diagnostics.SourceLevels.Warning; Console.Write("Discord Authentication Token > "); string DiscordAuthorizationToken = Console.ReadLine(); string ImgurAuthenticationSecret = "Q", OAuthAccessToken = "Q", OAuthRefreshToken = "Q"; Console.Write("Imgur Authentication ID > "); string ImgurAuthenticationID = Console.ReadLine(); Console.Write("Imgur Authentication Secret > "); ImgurAuthenticationSecret = Console.ReadLine(); Console.Write("Imgur OAuth Access Token > "); OAuthAccessToken = Console.ReadLine(); /* * Console.Write("Imgur OAuth Refresh Token > "); * OAuthRefreshToken=Console.ReadLine(); */ SingleThreadReadWriteLock ShutdownLock = new SingleThreadReadWriteLock(); Discord.DiscordInterfacerMain _Discord; Imgur.ImgurInterfacer _Imgur; Application.CacheingTaglistRepository RepositoryTaglists; Program Core = new Program( new ProcessLatestCommentsActivity( _Imgur = new Imgur.ImgurInterfacerMain( new DataAccess.SettingsRepositoryMain(@"DataAccess\Settings1.xml"), ImgurAuthenticationID, ImgurAuthenticationSecret, "wereleven", 77530931, OAuthAccessToken, OAuthRefreshToken, "bearer", DateTimeOffset.UtcNow + TimeSpan.FromDays(11), TimeSpan.FromSeconds(11), 0.1F, 140, "#", ShutdownLock ), new DataAccess.SettingsRepositoryMain(@"DataAccess\Settings1.xml"), RepositoryTaglists = new CacheingTaglistRepository(new DataAccess.TaglistRepositoryMain(@"DataAccess\Taglists.xml")), new ProcessCommentActivity( new Imgur.ImgurCommandParser("@Tagaroo2", _Imgur), new ProcessTagCommandActivity( _Imgur, _Discord = new Discord.DiscordInterfacerMain( DiscordAuthorizationToken, 388542416225042435UL, 388542416225042439UL, 388542416225042439UL, "/", 2000 ), RepositoryTaglists ) ) ), _Imgur, _Discord, new DataAccess.TaglistRepositoryMain(@"DataAccess\Taglists.xml"), new DataAccess.SettingsRepositoryMain(@"DataAccess\Settings1.xml"), ShutdownLock ); Core.Run(); }
public void RunDebugSynchronized() { var SynchronizationContext = new SingleThreadSynchronizationContext( new NullSynchronizationContext(), SingleThreadSynchronizationContext.Options.NoSynchronousExecution ); System.Threading.SynchronizationContext.SetSynchronizationContext(SynchronizationContext); SynchronizationContext.RunOnCurrentThread(async() => { /* * Infrastructure.TaskScheduler Scheduler=new Infrastructure.TaskScheduler(); * Scheduler.AddTask(ScheduledTask.NewLaterTask( * TimeSpan.FromSeconds(2), * () => { * Console.WriteLine("Two seconds"); * return Task.CompletedTask; * } * )); * Scheduler.AddTask(ScheduledTask.NewImmediateTask( * TimeSpan.FromSeconds(6), * () => { * Console.WriteLine("Six seconds"); * return Task.CompletedTask; * } * )); * Scheduler.AddTask(ScheduledTask.NewLaterTask( * TimeSpan.FromSeconds(30), * () => { * Console.WriteLine("Shutdown"); * Scheduler.Stop(); * return Task.CompletedTask; * } * )); * await Scheduler.Run(); */ SingleThreadReadWriteLock Lock = new SingleThreadReadWriteLock(); await Lock.EnterReadLock(); Task EnterReadSecond = Lock.EnterReadLock().ContinueWith( _ => Lock.ExitReadLock(), System.Threading.CancellationToken.None, TaskContinuationOptions.RunContinuationsAsynchronously | TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.LazyCancellation | TaskContinuationOptions.OnlyOnRanToCompletion, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext() ); Task EnterWrite = Lock.EnterWriteLock(); Lock.ExitReadLock(); await EnterWrite; Task EnterReadThird = Lock.EnterReadLock(); Lock.ExitWriteLock(); await EnterReadThird; Lock.ExitReadLock(); SynchronizationContext.Finish(); }); }
/// <param name="ApplicationShutdownLock"> /// This should be the same instance as passed to other objects; /// this class will acquire a write lock on the lock /// before allowing the process to shutdown cleanly /// </param> public Program( ProcessLatestCommentsActivity ActivityProcessComments, ImgurInterfacer Imgur, DiscordInterfacer Discord, TaglistRepository RepositoryTaglists, SettingsRepository RepositorySettings, SingleThreadReadWriteLock ApplicationShutdownLock ) { this.Imgur = Imgur; this.Discord = Discord; this.RepositoryTaglists = RepositoryTaglists; this.RepositorySettings = RepositorySettings; this.ActivityProcessComments = ActivityProcessComments; this.ApplicationShutdownLock = ApplicationShutdownLock; }
/// <returns> /// Non-zero <see cref="Return_ConfigurationLoadError"/> if there is a problem reading Configuration data from Settings.xml; /// non-zero <see cref="Return_ApplicationStartError"/> if there is some other problem during startup, /// 0 otherwise /// </returns> public static int _Main(string SettingsFilePath = null) { CrashHandler ProcessCrashHandler = new CrashHandler(AppDomain.CurrentDomain, Console.Error); //Log to STDOUT by default Log.Instance.AddTraceListener(new TextWriterTraceListener(Console.Out, "StdOutListener"), true); //Log all messages sent to the Bootstrap logger until the application's Configuration can be read and applied (other loggers are not used until after the Configuration is applied) Log.Instance.BootstrapLevel.Level = SourceLevels.Verbose; Log.Bootstrap_.LogInfo("Tagaroo {0}; application starting", typeof(EntryPoint).Assembly.GetName().Version.ToString(3)); //Robustness — Use locale-invariant comparison/formatting/e.t.c. rules by default, to mitigate aginst bugs caused by varying host system locales CultureInfo.CurrentCulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; SettingsRepository RepositorySettings = new SettingsRepositoryMain( SettingsFilePath ?? DefaultSettingsFilePath ); Log.Bootstrap_.LogVerbose("Initializing Settings repository"); RepositorySettings.Initialize(); Log.Bootstrap_.LogInfo("Loading Configuration"); ApplicationConfiguration Configuration; try{ Configuration = RepositorySettings.LoadConfiguration().GetAwaiter().GetResult(); }catch (DataAccessException Error) { Log.Bootstrap_.LogError("Unable to start; could not load application configuration: " + Error.Message); return(Return_ConfigurationLoadError); } Log.Bootstrap_.LogInfo("Applying Configuration"); Log.Bootstrap_.LogVerbose("Applying Configuration: Logging"); Log.Instance.BootstrapLevel.Level = Configuration.LogLevelBootstrap; Log.Instance.ApplicationLevel.Level = Configuration.LogLevelApplication; Log.Instance.ImgurLevel.Level = Configuration.LogLevelImgur; Log.Instance.DiscordLevel.Level = Configuration.LogLevelDiscord; Log.Instance.DiscordLibraryLevel.Level = Configuration.LogLevelDiscordLibrary; Log.Instance.ImgurBandwidthLevel.Level = Configuration.LogLevelImgurBandwidth; Log.Bootstrap_.LogVerbose("Applying Configuration: Constructing Application"); SingleThreadReadWriteLock ApplicationShutdownLock = new SingleThreadReadWriteLock(); TaglistRepository RepositoryTaglists = new TaglistRepositoryMain( Configuration.TaglistDataFilePath ); CacheingTaglistRepository RepositoryTaglistsCacheing = new CacheingTaglistRepository(RepositoryTaglists); ImgurInterfacer Imgur = new ImgurInterfacerMain( RepositorySettings, Configuration.ImgurClientID, Configuration.ImgurClientSecret, Configuration.ImgurUserAccountUsername, Configuration.ImgurUserAccountID, Configuration.ImgurOAuthAccessToken, Configuration.ImgurOAuthRefreshToken, Configuration.ImgurOAuthTokenType, Configuration.ImgurOAuthTokenExpiry, Configuration.ImgurPostCommentDelay, Configuration.ImgurAPIBandwidthWarningThreshhold, Configuration.ImgurMaximumCommentLengthUTF16CodeUnits, Configuration.ImgurMentionPrefix, ApplicationShutdownLock ); DiscordInterfacer Discord = new DiscordInterfacerMain( Configuration.DiscordAuthenticationToken, Configuration.DiscordGuildID, Configuration.DiscordChannelIDLog, Configuration.DiscordChannelIDCommands, Configuration.DiscordCommandPrefix, Configuration.DiscordMaximumMessageLengthUTF16CodeUnits ); Program Application = new Program( new ProcessLatestCommentsActivity( Imgur, RepositorySettings, RepositoryTaglistsCacheing, new ProcessCommentActivity( new ImgurCommandParser(Configuration.ImgurCommandPrefix, Imgur), new ProcessTagCommandActivity( Imgur, Discord, RepositoryTaglistsCacheing ) ) ), Imgur, Discord, RepositoryTaglists, RepositorySettings, ApplicationShutdownLock ); //Create Discord logging output if configured to do so Log.Bootstrap_.LogVerbose("Applying Configuration: Logging output"); if (Configuration.LogToDiscord) { Log.Instance.AddTraceListener( new DiscordTraceListener("DiscordListener", Discord, new TextWriterTraceListener(Console.Out)), false ); Log.Instance.RemoveTraceListener("StdOutListener"); Log.Instance.DiscordLibrary.AddListener(new TextWriterTraceListener(Console.Out, "StdOutListener")); } Log.Bootstrap_.LogInfo("Configuration applied; starting application"); //Execution will be within this method while the application is running bool startupsuccess = Application.Run(); Log.Bootstrap_.LogInfo("Application ended"); if (!startupsuccess) { return(Return_ApplicationStartError); } return(0); }
/// <summary> /// <para> /// Preconditions: /// <paramref name="PostCommentDelay"/> is non-negative and not greater than <see cref="Int32.MaxValue"/> milliseconds; /// 0 ≤ <paramref name="PercentageRemainingAPIBandwidthWarningThreshhold"/> ≤ 1; /// <paramref name="MaximumCommentLength"/> > 0 /// </para> /// </summary> /// <param name="ApplicationAuthenticationID"> /// The "Client ID" portion of the Imgur API Key /// with which to connect to the Imgur API with /// </param> /// <param name="ApplicationAuthenticationSecret"> /// The "Client Secret" portion of the Imgur API Key /// with which to connect to the Imgur API with /// </param> /// <param name="UserName"> /// The identifying username of the Imgur account /// with which the application is to perform actions as /// </param> /// <param name="UserID"> /// The identifying numeric ID of the Imgur account /// with which the application is to perform actions as /// </param> /// <param name="UserAuthenticationToken"> /// The "Access Token" portion of the OAuth Token /// that grants access to the Imgur account to perform actions as /// </param> /// <param name="UserAuthenticationRefreshToken"> /// The "Refresh Token" portion of the OAuth Token, /// which is used to generate a new "Access Token" when the existing one expires /// </param> /// <param name="UserAuthenticationTokenType"> /// The "Token Type" portion of the OAuth Token, /// which typically seems to be "bearer" /// </param> /// <param name="TokenExpiresAt"> /// The date–time at which the "Access Token" of the OAuth Token expires; /// if not known this can simply be set to a date–time in the past /// to acquire a new "Access Token" and expiry upon the first call requiring an OAuth Token /// </param> /// <param name="PostCommentDelay"> /// The time to wait after posting a Comment before allowing another Comment to be posted /// </param> /// <param name="PercentageRemainingAPIBandwidthWarningThreshhold"> /// A percentage value between 0 and 1 inclusive that marks the threshhold /// at which <see cref="LogRemainingBandwidth"/> will promote Informational messages to Warnings, /// measured as the remaining amount of daily-alloted API bandwidth. /// </param> /// <param name="MaximumCommentLength"> /// The maximum permitted length of an Imgur Comment, /// which seems to be measured in UTF-16 Code Units /// </param> /// <param name="MentionPrefix"> /// The prefix prepended to Imgur usernames in order to mention them; /// should normally be "@", but can be changed for testing purposes. /// </param> /// <param name="RepositorySettings"> /// A data access repository for the application's settings, /// which will be called to save any changes made to the OAuth Token, /// which may be updated automatically when close to or passed expiry, or manually /// </param> /// <param name="ApplicationShutdownLock"> /// Read–Write lock that the application will acquire a write lock on before shutting down; /// the <see cref="ImgurInterfacer"/> will acquire a read lock on it /// when in the middle of operations that must be completed, /// most notably during <see cref="MentionUsers"/> /// </param> public ImgurInterfacerMain( SettingsRepository RepositorySettings, string ApplicationAuthenticationID, string ApplicationAuthenticationSecret, string UserName, int UserID, string UserAuthenticationToken, string UserAuthenticationRefreshToken, string UserAuthenticationTokenType, DateTimeOffset TokenExpiresAt, TimeSpan PostCommentDelay, float PercentageRemainingAPIBandwidthWarningThreshhold, short MaximumCommentLength, string MentionPrefix, SingleThreadReadWriteLock ApplicationShutdownLock ) { if (ApplicationShutdownLock is null) { throw new ArgumentNullException(); } if (PostCommentDelay < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(PostCommentDelay)); } if (PercentageRemainingAPIBandwidthWarningThreshhold < 0 || PercentageRemainingAPIBandwidthWarningThreshhold > 1) { throw new ArgumentOutOfRangeException(nameof(PercentageRemainingAPIBandwidthWarningThreshhold)); } if (MaximumCommentLength <= 0) { throw new ArgumentOutOfRangeException(nameof(MaximumCommentLength)); } DateTimeOffset Now = DateTimeOffset.UtcNow; int ExpiryTime; try{ ExpiryTime = checked ((int)Math.Floor((TokenExpiresAt - Now).TotalSeconds)); }catch (OverflowException) { ExpiryTime = TokenExpiresAt > Now ? int.MaxValue : int.MinValue; } this.Client = new AuthenticationImpl.ImgurClient( ApplicationAuthenticationID ); this.ClientAuthenticated = new AuthenticationImpl.ImgurClient( ApplicationAuthenticationID, ApplicationAuthenticationSecret, new ModelsImpl.OAuth2Token( UserAuthenticationToken, UserAuthenticationRefreshToken, UserAuthenticationTokenType, UserID.ToString("D", CultureInfo.InvariantCulture), UserName, ExpiryTime ) ); this.APIOAuth = new EndpointsImpl.OAuth2Endpoint(ClientAuthenticated); this.APIBandwidth = new EndpointsImpl.RateLimitEndpoint(Client); this.APIUserAccount = new AccountEndpointEnhanced(Client); this.APIComments = new EndpointsImpl.CommentEndpoint(ClientAuthenticated); this.APIImage = new EndpointsImpl.ImageEndpoint(Client); this.APIAlbum = new EndpointsImpl.AlbumEndpoint(Client); this.UserID = UserID; this.PostCommentDelay = PostCommentDelay; this.PercentageRemainingAPIBandwidthWarningThreshhold = PercentageRemainingAPIBandwidthWarningThreshhold; this.MaximumCommentLength = (ushort)MaximumCommentLength; this.RepositorySettings = RepositorySettings; this.MentionPrefix = MentionPrefix ?? string.Empty; this.ApplicationShutdownLock = ApplicationShutdownLock; //See ImgurErrorJSONContractResolver for why this is needed JsonConvert.DefaultSettings = () => new JsonSerializerSettings() { ContractResolver = new ImgurErrorJSONContractResolver() }; }