Skip to content

Commit f272ba6

Browse files
committed
Add support for Core bundle
1 parent 0001096 commit f272ba6

File tree

5 files changed

+530
-0
lines changed

5 files changed

+530
-0
lines changed

IPinfo.Tests/IPApiCoreTest.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Xunit;
4+
5+
using IPinfo.Models;
6+
7+
namespace IPinfo.Tests
8+
{
9+
public class IPApiCoreTest
10+
{
11+
[Fact]
12+
public void TestGetDetailsIPV4()
13+
{
14+
string ip = "8.8.8.8";
15+
IPinfoClientCore client = new IPinfoClientCore.Builder()
16+
.AccessToken(Environment.GetEnvironmentVariable("IPINFO_TOKEN"))
17+
.Build();
18+
19+
IPResponseCore actual = client.IPApi.GetDetails(ip);
20+
21+
Assert.Equal("8.8.8.8", actual.IP);
22+
Assert.Equal("dns.google", actual.Hostname);
23+
Assert.False(actual.Bogon);
24+
25+
// Geo assertions
26+
Assert.NotNull(actual.Geo);
27+
Assert.NotNull(actual.Geo.City);
28+
Assert.NotNull(actual.Geo.Region);
29+
Assert.NotNull(actual.Geo.RegionCode);
30+
Assert.Equal("US", actual.Geo.CountryCode);
31+
Assert.Equal("United States", actual.Geo.Country);
32+
Assert.Equal("United States", actual.Geo.CountryName);
33+
Assert.False(actual.Geo.IsEU);
34+
Assert.NotNull(actual.Geo.Continent);
35+
Assert.NotNull(actual.Geo.ContinentCode);
36+
Assert.NotEqual(0, actual.Geo.Latitude);
37+
Assert.NotEqual(0, actual.Geo.Longitude);
38+
Assert.NotNull(actual.Geo.Timezone);
39+
Assert.NotNull(actual.Geo.PostalCode);
40+
Assert.Equal("🇺🇸", actual.Geo.CountryFlag.Emoji);
41+
Assert.Equal("U+1F1FA U+1F1F8", actual.Geo.CountryFlag.Unicode);
42+
Assert.Equal("https://cdn.ipinfo.io/static/images/countries-flags/US.svg", actual.Geo.CountryFlagURL);
43+
Assert.Equal("USD", actual.Geo.CountryCurrency.Code);
44+
Assert.Equal("$", actual.Geo.CountryCurrency.Symbol);
45+
Assert.Equal("NA", actual.Geo.ContinentInfo.Code);
46+
Assert.Equal("North America", actual.Geo.ContinentInfo.Name);
47+
48+
// AS assertions
49+
Assert.NotNull(actual.As);
50+
Assert.Equal("AS15169", actual.As.Asn);
51+
Assert.NotNull(actual.As.Name);
52+
Assert.NotNull(actual.As.Domain);
53+
Assert.NotNull(actual.As.Type);
54+
55+
// Network flags
56+
Assert.False(actual.IsAnonymous);
57+
Assert.True(actual.IsAnycast);
58+
Assert.True(actual.IsHosting);
59+
Assert.False(actual.IsMobile);
60+
Assert.False(actual.IsSatellite);
61+
}
62+
63+
[Fact]
64+
public void TestGetDetailsIPV6()
65+
{
66+
string ip = "2001:4860:4860::8888";
67+
IPinfoClientCore client = new IPinfoClientCore.Builder()
68+
.AccessToken(Environment.GetEnvironmentVariable("IPINFO_TOKEN"))
69+
.Build();
70+
71+
IPResponseCore actual = client.IPApi.GetDetails(ip);
72+
73+
Assert.Equal("2001:4860:4860::8888", actual.IP);
74+
75+
// Geo assertions
76+
Assert.NotNull(actual.Geo);
77+
Assert.Equal("US", actual.Geo.CountryCode);
78+
Assert.Equal("United States", actual.Geo.Country);
79+
Assert.NotNull(actual.Geo.City);
80+
Assert.NotNull(actual.Geo.Region);
81+
82+
// AS assertions
83+
Assert.NotNull(actual.As);
84+
Assert.NotNull(actual.As.Asn);
85+
Assert.NotNull(actual.As.Name);
86+
Assert.NotNull(actual.As.Domain);
87+
88+
// Network flags
89+
Assert.False(actual.IsAnonymous);
90+
Assert.False(actual.IsMobile);
91+
Assert.False(actual.IsSatellite);
92+
}
93+
94+
[Fact]
95+
public void TestBogonIPV4()
96+
{
97+
string ip = "127.0.0.1";
98+
IPinfoClientCore client = new IPinfoClientCore.Builder()
99+
.AccessToken(Environment.GetEnvironmentVariable("IPINFO_TOKEN"))
100+
.Build();
101+
102+
IPResponseCore actual = client.IPApi.GetDetails(ip);
103+
104+
Assert.Equal("127.0.0.1", actual.IP);
105+
Assert.True(actual.Bogon);
106+
}
107+
108+
[Fact]
109+
public void TestBogonIPV6()
110+
{
111+
string ip = "2001:0:c000:200::0:255:1";
112+
IPinfoClientCore client = new IPinfoClientCore.Builder()
113+
.AccessToken(Environment.GetEnvironmentVariable("IPINFO_TOKEN"))
114+
.Build();
115+
116+
IPResponseCore actual = client.IPApi.GetDetails(ip);
117+
118+
Assert.Equal("2001:0:c000:200::0:255:1", actual.IP);
119+
Assert.True(actual.Bogon);
120+
}
121+
}
122+
}

src/IPinfo/Apis/IPApiCore.cs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using System.Net;
2+
using System.Threading.Tasks;
3+
using System.Threading;
4+
5+
using IPinfo.Utilities;
6+
using IPinfo.Http.Client;
7+
using IPinfo.Http.Request;
8+
using IPinfo.Models;
9+
using IPinfo.Http.Response;
10+
using IPinfo.Cache;
11+
12+
namespace IPinfo.Apis
13+
{
14+
/// <summary>
15+
/// IPApiCore.
16+
/// </summary>
17+
public sealed class IPApiCore : BaseApi
18+
{
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="IPApiCore"/> class.
21+
/// </summary>
22+
/// <param name="httpClient"> httpClient. </param>
23+
/// <param name="token"> token. </param>
24+
/// <param name="cacheHandler"> cacheHandler. </param>
25+
internal IPApiCore(IHttpClient httpClient, string token, CacheHandler cacheHandler)
26+
: base(httpClient, token, cacheHandler)
27+
{
28+
this.BaseUrl = "https://api.ipinfo.io/lookup/";
29+
}
30+
31+
/// <summary>
32+
/// Retrieves details of an IP address.
33+
/// </summary>
34+
/// <param name="ipAddress">The IP address of the user to retrieve details for.</param>
35+
/// <returns>Returns the Models.IPResponseCore response from the API call.</returns>
36+
public Models.IPResponseCore GetDetails(
37+
IPAddress ipAddress)
38+
{
39+
string ipString = ipAddress?.ToString();
40+
return this.GetDetails(ipString);
41+
}
42+
43+
/// <summary>
44+
/// Retrieves details of an IP address.
45+
/// </summary>
46+
/// <param name="ipAddress">The IP address of the user to retrieve details for.</param>
47+
/// <returns>Returns the Models.IPResponseCore response from the API call.</returns>
48+
public Models.IPResponseCore GetDetails(
49+
string ipAddress = "")
50+
{
51+
Task<Models.IPResponseCore> t = this.GetDetailsAsync(ipAddress);
52+
ApiHelper.RunTaskSynchronously(t);
53+
return t.Result;
54+
}
55+
56+
/// <summary>
57+
/// Retrieves details of an IP address.
58+
/// </summary>
59+
/// <param name="ipAddress">The IP address of the user to retrieve details for.</param>
60+
/// <param name="cancellationToken">Cancellation token if the request is cancelled. </param>
61+
/// <returns>Returns the Models.IPResponseCore response from the API call.</returns>
62+
public Task<Models.IPResponseCore> GetDetailsAsync(
63+
IPAddress ipAddress,
64+
CancellationToken cancellationToken = default)
65+
{
66+
string ipString = ipAddress?.ToString();
67+
return this.GetDetailsAsync(ipString, cancellationToken);
68+
}
69+
70+
/// <summary>
71+
/// Retrieves details of an IP address.
72+
/// </summary>
73+
/// <param name="ipAddress">The IP address of the user to retrieve details for.</param>
74+
/// <param name="cancellationToken">Cancellation token if the request is cancelled. </param>
75+
/// <returns>Returns the Models.IPResponseCore response from the API call.</returns>
76+
public async Task<Models.IPResponseCore> GetDetailsAsync(
77+
string ipAddress = "",
78+
CancellationToken cancellationToken = default)
79+
{
80+
if (string.IsNullOrEmpty(ipAddress))
81+
{
82+
ipAddress = "";
83+
}
84+
85+
// first check the data in the cache if cache is available
86+
IPResponseCore ipResponse = (IPResponseCore)GetFromCache(ipAddress);
87+
if (ipResponse != null)
88+
{
89+
return ipResponse;
90+
}
91+
92+
if (BogonHelper.IsBogon(ipAddress))
93+
{
94+
ipResponse = new IPResponseCore()
95+
{
96+
IP = ipAddress,
97+
Bogon = true
98+
};
99+
return ipResponse;
100+
}
101+
102+
// prepare the API call request to fetch the response.
103+
HttpRequest httpRequest = this.CreateGetRequest(this.BaseUrl + ipAddress);
104+
// invoke request and get response.
105+
HttpStringResponse response = await this.GetClientInstance().ExecuteAsStringAsync(httpRequest, cancellationToken).ConfigureAwait(false);
106+
HttpContext context = new HttpContext(httpRequest, response);
107+
108+
// handle errors defined at the API level.
109+
this.ValidateResponse(context);
110+
111+
var responseModel = JsonHelper.ParseIPResponseCore(response.Body);
112+
113+
SetInCache(ipAddress, responseModel);
114+
return responseModel;
115+
}
116+
}
117+
}

src/IPinfo/IPinfoClientCore.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
3+
using IPinfo.Http.Client;
4+
using IPinfo.Apis;
5+
using IPinfo.Cache;
6+
using IPinfo.Utilities;
7+
8+
namespace IPinfo
9+
{
10+
/// <summary>
11+
/// The gateway for IPinfo Core SDK. This class holds the configuration of the SDK.
12+
/// </summary>
13+
public sealed class IPinfoClientCore
14+
{
15+
private readonly IHttpClient _httpClient;
16+
private readonly CacheHandler _cacheHandler;
17+
private readonly Lazy<IPApiCore> _ipApi;
18+
19+
private IPinfoClientCore(
20+
string accessToken,
21+
IHttpClient httpClient,
22+
CacheHandler cacheHandler,
23+
IHttpClientConfiguration httpClientConfiguration)
24+
{
25+
this._httpClient = httpClient;
26+
this._cacheHandler = cacheHandler;
27+
this.HttpClientConfiguration = httpClientConfiguration;
28+
29+
this._ipApi = new Lazy<IPApiCore>(
30+
() => new IPApiCore(this._httpClient, accessToken, cacheHandler));
31+
}
32+
33+
/// <summary>
34+
/// Gets IPApiCore.
35+
/// </summary>
36+
public IPApiCore IPApi => this._ipApi.Value;
37+
38+
/// <summary>
39+
/// Gets the configuration of the Http Client associated with this client.
40+
/// </summary>
41+
public IHttpClientConfiguration HttpClientConfiguration { get; }
42+
43+
/// <summary>
44+
/// Gets the configuration of the Http Client associated with this client.
45+
/// </summary>
46+
public ICache Cache { get => _cacheHandler?.Cache; }
47+
48+
/// <summary>
49+
/// Builder class.
50+
/// </summary>
51+
public class Builder
52+
{
53+
private string _accessToken = "";
54+
private HttpClientConfiguration.Builder _httpClientConfig = new HttpClientConfiguration.Builder();
55+
private IHttpClient _httpClient;
56+
private CacheHandler _cacheHandler = new CacheHandler();
57+
58+
/// <summary>
59+
/// Sets credentials for BearerAuth.
60+
/// </summary>
61+
/// <param name="accessToken">AccessToken.</param>
62+
/// <returns>Builder.</returns>
63+
public Builder AccessToken(string accessToken)
64+
{
65+
this._accessToken = accessToken;
66+
return this;
67+
}
68+
69+
/// <summary>
70+
/// Sets HttpClientConfig.
71+
/// </summary>
72+
/// <param name="action"> Action. </param>
73+
/// <returns>Builder.</returns>
74+
public Builder HttpClientConfig(Action<HttpClientConfiguration.Builder> action)
75+
{
76+
if (action is null)
77+
{
78+
throw new ArgumentNullException(nameof(action));
79+
}
80+
81+
action(this._httpClientConfig);
82+
return this;
83+
}
84+
85+
/// <summary>
86+
/// Sets the ICache implementation for the Builder.
87+
/// </summary>
88+
/// <param name="cache"> ICache implementation. Pass null to disable the cache.</param>
89+
/// <returns>Builder.</returns>
90+
public Builder Cache(ICache cache)
91+
{
92+
// Null is allowed here, which is being used to indicate that user do not want the cache.
93+
if(cache == null)
94+
{
95+
this._cacheHandler = null;
96+
}
97+
else
98+
{
99+
this._cacheHandler = new CacheHandler(cache);
100+
}
101+
return this;
102+
}
103+
104+
/// <summary>
105+
/// Creates an object of the IPinfoClientCore using the values provided for the builder.
106+
/// </summary>
107+
/// <returns>IPinfoClientCore.</returns>
108+
public IPinfoClientCore Build()
109+
{
110+
this._httpClient = new HttpClientWrapper(this._httpClientConfig.Build());
111+
112+
return new IPinfoClientCore(
113+
_accessToken,
114+
_httpClient,
115+
_cacheHandler,
116+
_httpClientConfig.Build());
117+
}
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)