1 // OpenTween - Client of Twitter
2 // Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
5 // This file is part of OpenTween.
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
23 using System.Collections.Generic;
26 using System.Net.Http;
27 using System.Runtime.Serialization;
29 using System.Threading.Tasks;
31 using OpenTween.Api.DataModel;
33 namespace OpenTween.Connection
35 public class TwitterApiConnection : IApiConnection, IDisposable
37 public Uri RestApiBase { get; set; } = new Uri("https://api.twitter.com/1.1/");
39 public bool IsDisposed { get; private set; } = false;
41 public string AccessToken { get; }
42 public string AccessSecret { get; }
44 internal HttpClient http;
46 public TwitterApiConnection(string accessToken, string accessSecret)
48 this.AccessToken = accessToken;
49 this.AccessSecret = accessSecret;
51 this.InitializeHttpClient(accessToken, accessSecret);
52 Networking.WebProxyChanged += this.Networking_WebProxyChanged;
55 public Task<T> GetAsync<T>(Uri uri, IDictionary<string, string> param)
56 => this.GetAsync<T>(uri, param, null);
58 public async Task<T> GetAsync<T>(Uri uri, IDictionary<string, string> param, string endpointName)
60 var requestUri = new Uri(this.RestApiBase, uri);
63 requestUri = new Uri(requestUri, "?" + MyCommon.BuildQueryString(param));
65 var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
69 using (var response = await this.http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
70 .ConfigureAwait(false))
72 await this.CheckStatusCode(response)
73 .ConfigureAwait(false);
75 if (endpointName != null)
76 MyCommon.TwitterApiInfo.UpdateFromHeader(response.Headers, endpointName);
78 using (var content = response.Content)
80 var responseText = await content.ReadAsStringAsync()
81 .ConfigureAwait(false);
85 return MyCommon.CreateDataFromJson<T>(responseText);
87 catch (SerializationException ex)
89 throw TwitterApiException.CreateFromException(ex, responseText);
94 catch (OperationCanceledException ex)
96 throw TwitterApiException.CreateFromException(ex);
100 public async Task<LazyJson<T>> PostLazyAsync<T>(Uri uri, IDictionary<string, string> param)
102 var requestUri = new Uri(this.RestApiBase, uri);
103 var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
105 using (var postContent = new FormUrlEncodedContent(param))
107 request.Content = postContent;
109 HttpResponseMessage response = null;
112 response = await this.http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
113 .ConfigureAwait(false);
115 await this.CheckStatusCode(response)
116 .ConfigureAwait(false);
118 var result = new LazyJson<T>(response);
123 catch (OperationCanceledException ex)
125 throw TwitterApiException.CreateFromException(ex);
134 public async Task<LazyJson<T>> PostLazyAsync<T>(Uri uri, IDictionary<string, string> param, IDictionary<string, IMediaItem> media)
136 var requestUri = new Uri(this.RestApiBase, uri);
137 var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
139 using (var postContent = new MultipartFormDataContent())
141 foreach (var kv in param)
142 postContent.Add(new StringContent(kv.Value), kv.Key);
144 foreach (var kv in media)
145 postContent.Add(new StreamContent(kv.Value.OpenRead()), kv.Key);
147 request.Content = postContent;
149 HttpResponseMessage response = null;
152 response = await this.http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
153 .ConfigureAwait(false);
155 await this.CheckStatusCode(response)
156 .ConfigureAwait(false);
158 var result = new LazyJson<T>(response);
163 catch (OperationCanceledException ex)
165 throw TwitterApiException.CreateFromException(ex);
174 protected async Task CheckStatusCode(HttpResponseMessage response)
176 var statusCode = response.StatusCode;
177 if (statusCode == HttpStatusCode.OK)
179 Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
184 using (var content = response.Content)
186 responseText = await content.ReadAsStringAsync()
187 .ConfigureAwait(false);
190 if (string.IsNullOrWhiteSpace(responseText))
192 if (statusCode == HttpStatusCode.Unauthorized)
193 Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
195 throw new TwitterApiException(statusCode, responseText);
200 var error = TwitterError.ParseJson(responseText);
202 if (error?.Errors == null || error.Errors.Length == 0)
203 throw new TwitterApiException(statusCode, responseText);
205 var errorCodes = error.Errors.Select(x => x.Code);
206 if (errorCodes.Any(x => x == TwitterErrorCode.InternalError || x == TwitterErrorCode.SuspendedAccount))
208 Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
211 throw new TwitterApiException(error, responseText);
213 catch (SerializationException)
215 throw new TwitterApiException(statusCode, responseText);
219 public void Dispose()
222 GC.SuppressFinalize(this);
225 protected virtual void Dispose(bool disposing)
230 this.IsDisposed = true;
234 Networking.WebProxyChanged -= this.Networking_WebProxyChanged;
239 ~TwitterApiConnection()
244 private void InitializeHttpClient(string accessToken, string accessSecret)
246 var handler = new OAuthHandler(Networking.CreateHttpClientHandler(),
247 ApplicationSettings.TwitterConsumerKey, ApplicationSettings.TwitterConsumerSecret,
248 accessToken, accessSecret);
250 this.http = Networking.CreateHttpClient(handler);
253 private void Networking_WebProxyChanged(object sender, EventArgs e)
255 this.InitializeHttpClient(this.AccessToken, this.AccessSecret);