};
Application.ThreadException += (s, e) => OnUnhandledException(e.Exception);
AppDomain.CurrentDomain.UnhandledException += (s, e) => OnUnhandledException((Exception)e.ExceptionObject);
+ AsyncTimer.UnhandledException += (s, e) => OnUnhandledException(e.Exception);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2019 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#nullable enable
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OpenTween
+{
+ public sealed class AsyncTimer : IDisposable
+ {
+ private readonly Func<Task> callback;
+ private readonly Timer timer;
+
+ public static event EventHandler<ThreadExceptionEventArgs>? UnhandledException;
+
+ public AsyncTimer(Func<Task> callback)
+ {
+ this.callback = callback;
+ this.timer = new Timer(this.TimerCallback);
+ }
+
+ private async void TimerCallback(object _)
+ {
+ try
+ {
+ await this.callback().ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ UnhandledException?.Invoke(this, new ThreadExceptionEventArgs(ex));
+ }
+ }
+
+ public void Change(TimeSpan dueTime, TimeSpan period)
+ => this.timer.Change(dueTime, period);
+
+ public void Dispose()
+ => this.timer.Dispose();
+ }
+}
<SubType>Code</SubType>
</Compile>
<Compile Include="ApplicationSettings.cs" />
+ <Compile Include="AsyncTimer.cs" />
<Compile Include="AtIdSupplement.cs">
<SubType>Form</SubType>
</Compile>
更新履歴
==== Ver 2.4.2-dev(2019/xx/xx)
+ * FIX: タブ更新時にエラーが発生するとプロセスが異常終了する場合がある不具合を修正
==== Ver 2.4.1(2019/09/25)
* FIX: 「タブを一覧の下に表示する」を無効にすると起動時にエラーが発生する不具合を修正 (thx @mulsys!)
private const int TIMER_DISABLED = 0;
private const int TIMER_ENABLED = 1;
- private readonly Timer throttlingTimer;
+ private readonly AsyncTimer throttlingTimer;
private readonly Func<Task> timerCallback;
private long lastCalledTick;
this.LastInvoked = DateTimeUtc.MinValue;
this.InvokeLeading = leading;
this.InvokeTrailing = trailing;
- this.throttlingTimer = new Timer(this.Execute);
+ this.throttlingTimer = new AsyncTimer(this.Execute);
}
public void Call()
}
}
- private async void Execute(object _)
+ private async Task Execute()
{
var lastCalled = this.LastCalled;
var lastInvoked = this.LastInvoked;
protected string? ApiBase;
protected IEnumerable<Regex>? UrlRegex = null;
- protected Timer UpdateTimer;
+ protected AsyncTimer UpdateTimer;
protected HttpClient http
=> this.localHttpClient ?? Networking.Http;
public ImgAzyobuziNet(HttpClient? http, bool autoupdate)
{
- this.UpdateTimer = new Timer(async _ => await this.LoadRegexAsync());
+ this.UpdateTimer = new AsyncTimer(this.LoadRegexAsync);
this.AutoUpdate = autoupdate;
this.Enabled = true;
public bool DisabledInDM { get; set; }
protected void StartAutoUpdate()
- => this.UpdateTimer.Change(0, 30 * 60 * 1000); // 30分おきに更新
+ => this.UpdateTimer.Change(TimeSpan.Zero, TimeSpan.FromMinutes(30)); // 30分おきに更新
protected void StopAutoUpdate()
- => this.UpdateTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ => this.UpdateTimer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
public async Task LoadRegexAsync()
{
{
public class TimelineScheduler
{
- private readonly Timer timer;
+ private readonly AsyncTimer timer;
private bool enabled = false;
private bool systemResumeMode = false;
}
public TimelineScheduler()
- => this.timer = new Timer(_ => this.TimerCallback());
+ => this.timer = new AsyncTimer(this.TimerCallback);
public void RefreshSchedule()
{
this.RefreshSchedule();
}
- private async void TimerCallback()
+ private async Task TimerCallback()
{
try
{