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>";
var username = "<BLOCKDB_USERNAME>";
var password = "<BLOCKDB_PASSWORD>";
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret) ||
string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
Console.WriteLine("Set BLOCKDB_CLIENT_ID, BLOCKDB_CLIENT_SECRET, BLOCKDB_USERNAME, BLOCKDB_PASSWORD");
return 1;
}
var tokenHolder = new TokenHolder();
using var http = new HttpClient();
var tokens = await RequestPasswordTokenAsync(clientId!, clientSecret!, username!, password!);
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 grant, fallback to password)
_ = 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 && !string.IsNullOrEmpty(username))
newTokens = await RequestPasswordTokenAsync(clientId!, clientSecret!, username!, password!);
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));
}
static async Task<TokenResult?> RequestPasswordTokenAsync(string clientId, string clientSecret, string username, string password)
{
var body = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("scope", Scope)
});
return await PostTokenRequestAsync(clientId, clientSecret, body);
}
static 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);
}
static 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);
}
static 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; } }
}