using System.Net.Http.Headers; using System.Text; using System.Text.Json; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace TentacleBot.Services; public class PalworldApiService { private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly string _baseUrl; public PalworldApiService( IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger logger) { _httpClient = httpClientFactory.CreateClient("PalworldApi"); _logger = logger; _baseUrl = configuration["Palworld:BaseUrl"] ?? throw new InvalidOperationException("Palworld:BaseUrl not configured"); var username = configuration["Palworld:Username"] ?? "admin"; var password = Environment.GetEnvironmentVariable("PALWORLD_PASSWORD") ?? throw new InvalidOperationException("PALWORLD_PASSWORD environment variable is not set"); var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials); _httpClient.Timeout = TimeSpan.FromSeconds(10); } public async Task GetInfoAsync() { return await GetAsync("info"); } public async Task GetPlayersAsync() { return await GetAsync("players"); } public async Task GetMetricsAsync() { return await GetAsync("metrics"); } private async Task GetAsync(string endpoint) { try { var url = $"{_baseUrl.TrimEnd('/')}/v1/api/{endpoint}"; var response = await _httpClient.GetAsync(url); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { _logger.LogError("Palworld API returned 401 Unauthorized. Check your Palworld:Username and Palworld:Password config."); return null; } response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); return JsonDocument.Parse(json); } catch (TaskCanceledException) { _logger.LogError("Palworld API request timed out at {Endpoint}", endpoint); return null; } catch (HttpRequestException ex) { _logger.LogError(ex, "HTTP error calling Palworld API {Endpoint}", endpoint); return null; } catch (JsonException ex) { _logger.LogError(ex, "Failed to parse Palworld API response from {Endpoint}", endpoint); return null; } } }