mirror of
https://dev.azure.com/tstanciu94/PhantomMind/_git/Bitip
synced 2025-10-13 01:52:19 +03:00
Compare commits
2 Commits
11bd4fbe18
...
50320f8591
Author | SHA1 | Date | |
---|---|---|---|
|
50320f8591 | ||
|
0c2bdb3d11 |
@ -256,8 +256,8 @@ router.get('/version', (_req: Request, res: Response): void => {
|
|||||||
try {
|
try {
|
||||||
res.json({
|
res.json({
|
||||||
version: process.env.APP_VERSION || '1.0.0',
|
version: process.env.APP_VERSION || '1.0.0',
|
||||||
createdAt: process.env.CREATED_AT || 'unknown',
|
buildDate: process.env.CREATED_AT || 'unknown',
|
||||||
gitRevision: process.env.GIT_REVISION || 'unknown',
|
commitHash: process.env.GIT_REVISION || 'unknown',
|
||||||
service: 'Bitip GeoIP Service',
|
service: 'Bitip GeoIP Service',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
namespace Bitip.Client
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
16
src/clients/dotnet/Bitip.Client/Constants/ApiConstants.cs
Normal file
16
src/clients/dotnet/Bitip.Client/Constants/ApiConstants.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
namespace Bitip.Client.Constants
|
||||||
|
{
|
||||||
|
internal struct ApiKeys
|
||||||
|
{
|
||||||
|
public const string HttpHeader = "X-API-Key";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct ApiRoutes
|
||||||
|
{
|
||||||
|
public const string
|
||||||
|
Health = "health",
|
||||||
|
Version = "version";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
using Bitip.Client.Models;
|
||||||
|
using Bitip.Client.Services;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bitip.Client
|
||||||
|
{
|
||||||
|
public static class DependencyInjectionExtension
|
||||||
|
{
|
||||||
|
public static void UseBitipClient(this IServiceCollection services, string baseUrl, string apiKey)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(baseUrl));
|
||||||
|
if (string.IsNullOrWhiteSpace(apiKey))
|
||||||
|
throw new ArgumentException("Value cannot be null or whitespace.", nameof(apiKey));
|
||||||
|
|
||||||
|
services.Configure<BitipOptions>(options =>
|
||||||
|
{
|
||||||
|
options.BaseUrl = baseUrl;
|
||||||
|
options.ApiKey = apiKey;
|
||||||
|
});
|
||||||
|
services.AddHttpClient<IBitipClient, BitipClient>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
using Bitip.Client.Models;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bitip.Client.Extensions
|
||||||
|
{
|
||||||
|
internal static class HttpMessageExtensions
|
||||||
|
{
|
||||||
|
public static async Task<HttpResponseMessage> EnsureSuccessOperation(this HttpResponseMessage response, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
return response;
|
||||||
|
var errorResponse = await response.Content.ReadFromJsonAsync<ErrorResponse>(cancellationToken);
|
||||||
|
if (errorResponse is null)
|
||||||
|
throw new HttpRequestException("An error occurred while fetching Bitip information.");
|
||||||
|
var message = $"{errorResponse.Error}: {errorResponse.Message}";
|
||||||
|
if (!string.IsNullOrWhiteSpace(errorResponse.Ip))
|
||||||
|
message += $" (IP: {errorResponse.Ip})";
|
||||||
|
throw new HttpRequestException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
src/clients/dotnet/Bitip.Client/Models/BitipOptions.cs
Normal file
10
src/clients/dotnet/Bitip.Client/Models/BitipOptions.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
namespace Bitip.Client.Models
|
||||||
|
{
|
||||||
|
internal record BitipOptions
|
||||||
|
{
|
||||||
|
public required string BaseUrl { get; set; }
|
||||||
|
public required string ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
28
src/clients/dotnet/Bitip.Client/Models/SystemDtos.cs
Normal file
28
src/clients/dotnet/Bitip.Client/Models/SystemDtos.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bitip.Client.Models
|
||||||
|
{
|
||||||
|
internal record HealthResponse
|
||||||
|
{
|
||||||
|
public required string Status { get; init; }
|
||||||
|
public required string Service { get; init; }
|
||||||
|
public DateTime Timestamp { get; init; }
|
||||||
|
public string? Error { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal record VersionResponse
|
||||||
|
{
|
||||||
|
public required string Version { get; init; }
|
||||||
|
public required string CommitHash { get; init; }
|
||||||
|
public DateTime BuildDate { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal record ErrorResponse
|
||||||
|
{
|
||||||
|
public required string Error { get; init; }
|
||||||
|
public required string Message { get; init; }
|
||||||
|
public string? Ip { get; init; }
|
||||||
|
}
|
||||||
|
}
|
55
src/clients/dotnet/Bitip.Client/Services/BitipClient.cs
Normal file
55
src/clients/dotnet/Bitip.Client/Services/BitipClient.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
using Bitip.Client.Constants;
|
||||||
|
using Bitip.Client.Extensions;
|
||||||
|
using Bitip.Client.Models;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bitip.Client.Services
|
||||||
|
{
|
||||||
|
internal class BitipClient : IBitipClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
|
||||||
|
public BitipClient(HttpClient httpClient, IOptions<BitipOptions> options)
|
||||||
|
{
|
||||||
|
httpClient.BaseAddress = EnsureTrailingSlash(options.Value.BaseUrl);
|
||||||
|
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
httpClient.DefaultRequestHeaders.Add(ApiKeys.HttpHeader, options.Value.ApiKey);
|
||||||
|
|
||||||
|
_httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<HealthResponse> GetHealth(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var response = await _httpClient.GetAsync(ApiRoutes.Health, cancellationToken);
|
||||||
|
await response.EnsureSuccessOperation(cancellationToken);
|
||||||
|
var data = await response.Content.ReadFromJsonAsync<HealthResponse>(cancellationToken);
|
||||||
|
if (data is null)
|
||||||
|
throw new InvalidOperationException("The response content is null.");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<VersionResponse> GetVersion(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var response = await _httpClient.GetAsync(ApiRoutes.Version, cancellationToken);
|
||||||
|
await response.EnsureSuccessOperation(cancellationToken);
|
||||||
|
var data = await response.Content.ReadFromJsonAsync<VersionResponse>(cancellationToken);
|
||||||
|
if (data is null)
|
||||||
|
throw new InvalidOperationException("The response content is null.");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri EnsureTrailingSlash(string url)
|
||||||
|
{
|
||||||
|
var address = url.EndsWith("/") ? url : $"{url}/";
|
||||||
|
return new Uri(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/clients/dotnet/Bitip.Client/Services/IBitipClient.cs
Normal file
14
src/clients/dotnet/Bitip.Client/Services/IBitipClient.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright (c) 2025 Tudor Stanciu
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bitip.Client.Services
|
||||||
|
{
|
||||||
|
public interface IBitipClient
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,8 @@ import { pathCombine } from '@flare/utiliyo';
|
|||||||
|
|
||||||
interface VersionInfo {
|
interface VersionInfo {
|
||||||
version: string;
|
version: string;
|
||||||
createdAt: string;
|
buildDate: string;
|
||||||
gitRevision: string;
|
commitHash: string;
|
||||||
service: string;
|
service: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +90,8 @@ const App: React.FC = () => {
|
|||||||
{versionInfo && (
|
{versionInfo && (
|
||||||
<p className="version-info">
|
<p className="version-info">
|
||||||
Version {versionInfo.version}
|
Version {versionInfo.version}
|
||||||
{versionInfo.createdAt !== 'unknown' &&
|
{versionInfo.buildDate !== 'unknown' &&
|
||||||
` | Released ${new Date(versionInfo.createdAt).toLocaleString()}`}
|
` | Released ${new Date(versionInfo.buildDate).toLocaleString()}`}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -67,8 +67,8 @@ export interface IPResponse {
|
|||||||
|
|
||||||
export interface VersionInfo {
|
export interface VersionInfo {
|
||||||
version: string;
|
version: string;
|
||||||
createdAt: string;
|
buildDate: string;
|
||||||
gitRevision: string;
|
commitHash: string;
|
||||||
service: string;
|
service: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user