Exemple #1
0
        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();
        }
Exemple #2
0
        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();
            });
        }
Exemple #3
0
 /// <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;
 }
Exemple #4
0
        /// <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"/> &gt; 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()
            };
        }