Skip to content

Commit

Permalink
Merge pull request #330 from opentween/api-connection-dependency
Browse files Browse the repository at this point in the history
TwitterApiConnectionインスタンスの生成をTwitterAccountで行う
  • Loading branch information
upsilon authored May 10, 2024
2 parents 622bbcf + 2028aac commit 7a515c3
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 114 deletions.
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

0 comments on commit 7a515c3

Please sign in to comment.