Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TwitterApiConnectionインスタンスの生成をTwitterAccountで行う #330

Merged
merged 5 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions OpenTween.Tests/Api/TwitterApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
using Moq;
using OpenTween.Api.DataModel;
using OpenTween.Connection;
using OpenTween.SocialProtocol.Twitter;
using Xunit;

namespace OpenTween.Api
Expand All @@ -54,28 +53,21 @@ private void MyCommonSetup()
public void Initialize_Test()
{
using var twitterApi = new TwitterApi();
var apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
Assert.IsType<TwitterCredentialNone>(apiConnection.Credential);
var apiConnectionNone = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
Assert.IsType<TwitterCredentialNone>(apiConnectionNone.Credential);

var credential = new TwitterCredentialOAuth1(TwitterAppToken.GetDefault(), "*** AccessToken ***", "*** AccessSecret ***");
var accountState = new TwitterAccountState(100L, "hogehoge");
twitterApi.Initialize(credential, accountState);
using var apiConnection = new TwitterApiConnection(credential, new());
twitterApi.Initialize(apiConnection);

apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
Assert.Same(credential, apiConnection.Credential);
Assert.Same(accountState, twitterApi.AccountState);
Assert.Same(apiConnection, twitterApi.Connection);

// 複数回 Initialize を実行した場合は新たに TwitterApiConnection が生成される
var credential2 = new TwitterCredentialOAuth1(TwitterAppToken.GetDefault(), "*** AccessToken2 ***", "*** AccessSecret2 ***");
var accountState2 = new TwitterAccountState(200L, "foobar");
twitterApi.Initialize(credential2, accountState2);
using var apiConnection2 = new TwitterApiConnection(credential2, new());
twitterApi.Initialize(apiConnection2);

var oldApiConnection = apiConnection;
Assert.True(oldApiConnection.IsDisposed);

apiConnection = Assert.IsType<TwitterApiConnection>(twitterApi.Connection);
Assert.Same(credential2, apiConnection.Credential);
Assert.Same(accountState2, twitterApi.AccountState);
Assert.Same(apiConnection2, twitterApi.Connection);
}

private Mock<IApiConnection> CreateApiConnectionMock<T>(Action<T> verifyRequest)
Expand Down
24 changes: 5 additions & 19 deletions OpenTween/Api/TwitterApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,24 @@
using OpenTween.Api.DataModel;
using OpenTween.Connection;
using OpenTween.Models;
using OpenTween.SocialProtocol.Twitter;

namespace OpenTween.Api
{
public sealed class TwitterApi : IDisposable
{
public long CurrentUserId
=> this.AccountState.UserId;

public string CurrentScreenName
=> this.AccountState.UserName;

public IApiConnection Connection => this.ApiConnection;

internal IApiConnection ApiConnection;

public APIAuthType AuthType { get; private set; } = APIAuthType.None;

public TwitterAccountState AccountState { get; private set; } = new();
public APIAuthType AuthType
=> ((TwitterApiConnection)this.ApiConnection).Credential.AuthType;

public TwitterApi()
=> this.ApiConnection = new TwitterApiConnection(new TwitterCredentialNone());
=> this.ApiConnection = new TwitterApiConnection();

public void Initialize(ITwitterCredential credential, TwitterAccountState accountState)
public void Initialize(IApiConnection apiConnection)
{
this.AuthType = credential.AuthType;

var newInstance = new TwitterApiConnection(credential);
var oldInstance = Interlocked.Exchange(ref this.ApiConnection, newInstance);
oldInstance?.Dispose();

this.AccountState = accountState;
this.ApiConnection = apiConnection;
}

public async Task<TwitterStatus[]> StatusesHomeTimeline(int? count = null, TwitterStatusId? maxId = null, TwitterStatusId? sinceId = null)
Expand Down
3 changes: 2 additions & 1 deletion OpenTween/AppendSettingDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ private async void AddAccountButton_Click(object sender, EventArgs e)
};

using var twitterApi = new TwitterApi();
twitterApi.Initialize(new TwitterCredentialCookie(appToken), new());
using var apiConnection = new TwitterApiConnection(new TwitterCredentialCookie(appToken), new());
twitterApi.Initialize(apiConnection);
var twitterUser = await twitterApi.AccountVerifyCredentials();
newAccount.UserId = twitterUser.Id;
newAccount.Username = twitterUser.ScreenName;
Expand Down
25 changes: 17 additions & 8 deletions OpenTween/Connection/TwitterApiConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
using System.Web;
using OpenTween.Api;
using OpenTween.Api.DataModel;
using OpenTween.SocialProtocol.Twitter;

namespace OpenTween.Connection
{
Expand All @@ -56,14 +57,17 @@ public static string RestApiHost

internal ITwitterCredential Credential { get; }

private readonly TwitterAccountState accountState;

public TwitterApiConnection()
: this(new TwitterCredentialNone())
: this(new TwitterCredentialNone(), new())
{
}

public TwitterApiConnection(ITwitterCredential credential)
public TwitterApiConnection(ITwitterCredential credential, TwitterAccountState accountState)
{
this.Credential = credential;
this.accountState = accountState;

this.InitializeHttpClients();
Networking.WebProxyChanged += this.Networking_WebProxyChanged;
Expand Down Expand Up @@ -99,7 +103,7 @@ public async Task<ApiResponse> SendAsync(IHttpRequest request)
if (endpointName != null)
MyCommon.TwitterApiInfo.UpdateFromHeader(responseMessage.Headers, endpointName);

await TwitterApiConnection.CheckStatusCode(responseMessage)
await TwitterApiConnection.CheckStatusCode(responseMessage, this.accountState)
.ConfigureAwait(false);

var response = new ApiResponse(responseMessage);
Expand Down Expand Up @@ -165,13 +169,14 @@ public static async Task<T> HandleTimeout<T>(Func<CancellationToken, Task<T>> fu
return await task;
}

protected static async Task CheckStatusCode(HttpResponseMessage response)
protected static async Task CheckStatusCode(HttpResponseMessage response, TwitterAccountState? accountState)
{
var statusCode = response.StatusCode;

if ((int)statusCode >= 200 && (int)statusCode <= 299)
{
Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
if (accountState != null)
accountState.HasUnrecoverableError = false;
return;
}

Expand All @@ -185,7 +190,10 @@ protected static async Task CheckStatusCode(HttpResponseMessage response)
if (string.IsNullOrWhiteSpace(responseText))
{
if (statusCode == HttpStatusCode.Unauthorized)
Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
{
if (accountState != null)
accountState.HasUnrecoverableError = true;
}

throw new TwitterApiException(statusCode, responseText);
}
Expand All @@ -200,7 +208,8 @@ protected static async Task CheckStatusCode(HttpResponseMessage response)
var errorCodes = error.Errors.Select(x => x.Code);
if (errorCodes.Any(x => x == TwitterErrorCode.InternalError || x == TwitterErrorCode.SuspendedAccount))
{
Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
if (accountState != null)
accountState.HasUnrecoverableError = true;
}

throw new TwitterApiException(statusCode, error, responseText);
Expand Down Expand Up @@ -324,7 +333,7 @@ TwitterCredentialOAuth1 credential
var responseText = await content.ReadAsStringAsync()
.ConfigureAwait(false);

await TwitterApiConnection.CheckStatusCode(response)
await TwitterApiConnection.CheckStatusCode(response, accountState: null)
.ConfigureAwait(false);

var responseParams = HttpUtility.ParseQueryString(responseText);
Expand Down
6 changes: 0 additions & 6 deletions OpenTween/MyCommon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,6 @@ public static class DEFAULTTAB
public static bool DebugBuild = false;
#endif

public enum ACCOUNT_STATE
{
Valid,
Invalid,
}

public enum REPLY_ICONSTATE
{
None,
Expand Down
14 changes: 7 additions & 7 deletions OpenTween/MyLists.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace OpenTween
{
public partial class MyLists : OTBaseForm
{
private readonly TwitterApi twitterApi = null!;
private readonly Twitter twitter = null!;
private readonly string contextScreenName = null!;

/// <summary>自分が所有しているリスト</summary>
Expand All @@ -55,11 +55,11 @@ public partial class MyLists : OTBaseForm
public MyLists()
=> this.InitializeComponent();

public MyLists(string screenName, TwitterApi twitterApi)
public MyLists(string screenName, Twitter twitter)
{
this.InitializeComponent();

this.twitterApi = twitterApi;
this.twitter = twitter;
this.contextScreenName = screenName;

this.Text = screenName + Properties.Resources.MyLists1;
Expand Down Expand Up @@ -92,13 +92,13 @@ private async Task RefreshListBox()
private async Task FetchMembershipListIds()
{
var ownedListData = await TwitterLists.GetAllItemsAsync(x =>
this.twitterApi.ListsOwnerships(this.twitterApi.CurrentScreenName, cursor: x, count: 1000))
this.twitter.Api.ListsOwnerships(this.twitter.Username, cursor: x, count: 1000))
.ConfigureAwait(false);

this.ownedLists = ownedListData.Select(x => new ListElement(x, null!)).ToArray();

var listsUserAddedTo = await TwitterLists.GetAllItemsAsync(x =>
this.twitterApi.ListsMemberships(this.contextScreenName, cursor: x, count: 1000, filterToOwnedLists: true))
this.twitter.Api.ListsMemberships(this.contextScreenName, cursor: x, count: 1000, filterToOwnedLists: true))
.ConfigureAwait(false);

this.addedListIds = listsUserAddedTo.Select(x => x.Id).ToArray();
Expand All @@ -108,7 +108,7 @@ private async Task AddToList(ListElement list)
{
try
{
await this.twitterApi.ListsMembersCreate(list.Id, this.contextScreenName)
await this.twitter.Api.ListsMembersCreate(list.Id, this.contextScreenName)
.IgnoreResponse();

var index = this.ListsCheckedListBox.Items.IndexOf(list);
Expand All @@ -124,7 +124,7 @@ private async Task RemoveFromList(ListElement list)
{
try
{
await this.twitterApi.ListsMembersDestroy(list.Id, this.contextScreenName)
await this.twitter.Api.ListsMembersDestroy(list.Id, this.contextScreenName)
.IgnoreResponse();

var index = this.ListsCheckedListBox.Items.IndexOf(list);
Expand Down
2 changes: 1 addition & 1 deletion OpenTween/SendErrorReportForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ private bool CheckDmAvailable()
if (this.tw == null || !this.tw.AccessLevel.HasFlag(TwitterApiAccessLevel.DirectMessage))
return false;

if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid)
if (this.tw.AccountState.HasUnrecoverableError)
return false;

return true;
Expand Down
16 changes: 13 additions & 3 deletions OpenTween/SocialProtocol/Twitter/TwitterAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace OpenTween.SocialProtocol.Twitter
public class TwitterAccount : ISocialAccount
{
private readonly OpenTween.Twitter twLegacy = new(new());
private TwitterApiConnection apiConnection = new();

public Guid UniqueKey { get; }

Expand All @@ -54,7 +55,7 @@ public APIAuthType AuthType
=> this.Legacy.Api.AuthType;

public IApiConnection Connection
=> this.Legacy.Api.Connection;
=> this.apiConnection;

public TwitterAccount(Guid uniqueKey)
{
Expand All @@ -68,11 +69,20 @@ public void Initialize(UserAccount accountSettings, SettingCommon settingCommon)
Debug.Assert(accountSettings.UniqueKey == this.UniqueKey, "UniqueKey must be same as current value.");

var credential = accountSettings.GetTwitterCredential();
this.AccountState = new TwitterAccountState(accountSettings.UserId, accountSettings.Username);

this.AccountState = new TwitterAccountState(accountSettings.UserId, accountSettings.Username)
{
HasUnrecoverableError = credential is TwitterCredentialNone,
};

var newConnection = new TwitterApiConnection(credential, this.AccountState);
(this.apiConnection, var oldConnection) = (newConnection, this.apiConnection);
oldConnection.Dispose();

this.Query = this.CreateQueryInstance(credential.AuthType);
this.Mutation = this.CreateMutationInstance(credential.AuthType);

this.twLegacy.Initialize(credential, this.AccountState);
this.twLegacy.Initialize(newConnection, this.AccountState);
this.twLegacy.RestrictFavCheck = settingCommon.RestrictFavCheck;
}

Expand Down
2 changes: 2 additions & 0 deletions OpenTween/SocialProtocol/Twitter/TwitterAccountState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public class TwitterAccountState

public ISet<long> NoRetweetUserIds { get; set; } = new HashSet<long>();

public bool HasUnrecoverableError { get; set; } = true;

public TwitterAccountState()
: this(0L, "")
{
Expand Down
2 changes: 1 addition & 1 deletion OpenTween/SocialProtocol/Twitter/TwitterGraphqlMutation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task DeletePost(PostId postId)
TweetId = statusId,
};

await request.Send(this.account.Legacy.Api.Connection)
await request.Send(this.account.Connection)
.ConfigureAwait(false);
}

Expand Down
Loading
Loading