using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
const string TokenUrl = "https://user.blockdb.io/api/authorization/token";
const string Scope = "offline_access api";
var clientId = "<BLOCKDB_CLIENT_ID>";
var clientSecret = "<BLOCKDB_CLIENT_SECRET>";
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret))
{
Console.WriteLine("Set BLOCKDB_CLIENT_ID and BLOCKDB_CLIENT_SECRET");
return 1;
}
var tokenHolder = new TokenHolder();
using var http = new HttpClient();
var tokens = await RequestClientCredentialsTokenAsync(clientId!, clientSecret!);
if (tokens == null) { Console.WriteLine("Failed to get initial token."); return 1; }
tokenHolder.Set(tokens.Value.AccessToken!, tokens.Value.RefreshToken ?? "");
// Background: refresh token every 14 minutes (refresh_token if available, else client_credentials)
_ = Task.Run(async () =>
{
while (true)
{
await Task.Delay(TimeSpan.FromMinutes(14));
try
{
var refreshToken = tokenHolder.GetRefreshToken();
TokenResult? newTokens = null;
if (!string.IsNullOrEmpty(refreshToken))
newTokens = await RequestRefreshTokenAsync(clientId!, clientSecret!, refreshToken);
if (newTokens == null)
newTokens = await RequestClientCredentialsTokenAsync(clientId!, clientSecret!);
if (newTokens != null)
tokenHolder.Set(newTokens.Value.AccessToken, newTokens.Value.RefreshToken ?? refreshToken ?? "");
}
catch (Exception ex) { Console.WriteLine("Token refresh failed: " + ex.Message); }
}
});
// Main: get blocks every 1 min
while (true)
{
var response = await GetBlocksAsync(http, tokenHolder.GetAccessToken());
response.EnsureSuccessStatusCode();
Console.WriteLine($"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC] {await response.Content.ReadAsStringAsync()}");
await Task.Delay(TimeSpan.FromMinutes(1));
}
async Task<TokenResult?> RequestClientCredentialsTokenAsync(string clientId, string clientSecret)
{
var body = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("scope", Scope)
});
return await PostTokenRequestAsync(clientId, clientSecret, body);
}
async Task<TokenResult?> RequestRefreshTokenAsync(string clientId, string clientSecret, string refreshToken)
{
var body = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", refreshToken)
});
return await PostTokenRequestAsync(clientId, clientSecret, body);
}
async Task<TokenResult?> PostTokenRequestAsync(string clientId, string clientSecret, HttpContent body)
{
var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));
using var tokenClient = new HttpClient();
tokenClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var res = await tokenClient.PostAsync(TokenUrl, body);
if (!res.IsSuccessStatusCode) return null;
var json = await res.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
var accessToken = root.TryGetProperty("access_token", out var at) ? at.GetString() : null;
var refreshToken = root.TryGetProperty("refresh_token", out var rt) ? rt.GetString() : null;
if (string.IsNullOrEmpty(accessToken)) return null;
return new TokenResult(accessToken, refreshToken);
}
async Task<HttpResponseMessage> GetBlocksAsync(HttpClient http, string token)
{
var req = new HttpRequestMessage(HttpMethod.Post, "https://api.blockdb.io/v1/evm/raw/blocks");
req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
req.Content = new StringContent("{\"chain_id\":1,\"from_block\":12345678,\"to_block\":12345999,\"limit\":10}", Encoding.UTF8, "application/json");
return await http.SendAsync(req);
}
readonly record struct TokenResult(string AccessToken, string? RefreshToken);
class TokenHolder
{
private string _accessToken = "";
private string _refreshToken = "";
private readonly object _lock = new();
public void Set(string accessToken, string refreshToken) { lock (_lock) { _accessToken = accessToken; _refreshToken = refreshToken ?? ""; } }
public string GetAccessToken() { lock (_lock) { return _accessToken; } }
public string GetRefreshToken() { lock (_lock) { return _refreshToken; } }
}