using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Forms; using Neighbourhood.omg.lol.Models; using System.Diagnostics; using System.Net.Http.Json; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; namespace Neighbourhood.omg.lol { public class RestService { HttpClient _client; JsonSerializerOptions _serializerOptions; public const string BaseUrl = "https://api.omg.lol"; public RestService(string? token = null) { _client = new HttpClient(); _client.BaseAddress = new Uri(BaseUrl); _client.DefaultRequestHeaders.UserAgent.Add(new System.Net.Http.Headers.ProductInfoHeaderValue(App.Name, App.Version)); _serializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, WriteIndented = true }; AddToken(token); } public T? Deserialize(string str) { T? responseObj = default(T); try { responseObj = JsonSerializer.Deserialize(str, _serializerOptions); } catch (JsonException ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); Debug.WriteLine(str); } return responseObj; } public void AddToken(string? token = null) { if (token == null) token = Task.Run(() => SecureStorage.GetAsync("accounttoken")).GetAwaiter().GetResult(); if (token != null) _client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); } public void RemoveToken() { _client.DefaultRequestHeaders.Remove("Authorization"); } private async Task Get(string uri, CancellationToken cancellationToken = default) where T : IOmgLolResponseData { T? responseData = default(T); try { HttpResponseMessage response = await _client.GetAsync(uri, cancellationToken: cancellationToken); if (response.IsSuccessStatusCode) { string str = await response.Content.ReadAsStringAsync(); try { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request == null || (responseObj?.Request?.Success ?? false)) { responseData = responseObj!.Response; } } catch (JsonException ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); Debug.WriteLine(str); } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task Post(string uri, TData data, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData { TResponse? responseData = default(TResponse); try { HttpResponseMessage response = await _client.PostAsJsonAsync(uri, data, _serializerOptions, cancellationToken: cancellationToken); string str = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task PostBinary(string uri, FileResult? fileResult = null, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData { TResponse? responseData = default(TResponse); try { if (fileResult != null) using (var fileStream = await fileResult.OpenReadAsync()) { Uri url = new Uri(_client.BaseAddress?.AbsoluteUri + uri); if (string.IsNullOrEmpty(url.Query)) uri += "?binary"; else if (!url.Query.Contains("binary")) uri += "&binary"; HttpContent fileStreamContent = new StreamContent(fileStream); fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(fileResult.ContentType ?? "application/octet-stream"); fileStreamContent.Headers.ContentLength = fileStream.Length; HttpResponseMessage response = await _client.PostAsync(uri, fileStreamContent, cancellationToken: cancellationToken); string str = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task PostMultipart(string uri, TData? data = null, FileResult? fileResult = null, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData where TData : class { if(fileResult != null) { using (var fileStream = await fileResult.OpenReadAsync()) return await PostMultipart(uri, data: data, fileStream: fileStream, fileName: fileResult.FileName, contentType: fileResult.ContentType); } else return await PostMultipart(uri, data, fileStream: null); } private async Task PostMultipart(string uri, TData? data = null, Stream? fileStream = null, string? fileName = null, string? contentType = null, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData where TData : class { TResponse? responseData = default; try { using (MultipartFormDataContent formData = new MultipartFormDataContent()) { if(fileStream != null) { HttpContent fileStreamContent = new StreamContent(fileStream); fileStreamContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { Name = "\"file\"", FileName = $"\"{fileName}\"" ?? "\"unknown\"" }; fileStreamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType ?? "application/octet-stream"); formData.Add(fileStreamContent); } if (data != null) { HttpContent jsonContent = JsonContent.Create(data, options: _serializerOptions); formData.Add(jsonContent); } HttpResponseMessage response = await _client.PostAsync(uri, formData, cancellationToken: cancellationToken); string str = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task Put(string uri, TData data, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData { TResponse? responseData = default(TResponse); try { string json = JsonSerializer.Serialize(data, _serializerOptions); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, uri); request.Content = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage response = await _client.SendAsync(request, cancellationToken: cancellationToken); if (response.IsSuccessStatusCode) { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task Patch(string uri, TData data, CancellationToken cancellationToken = default) where TResponse : IOmgLolResponseData { TResponse? responseData = default(TResponse); try { HttpResponseMessage response = await _client.PatchAsJsonAsync(uri, data, _serializerOptions, cancellationToken: cancellationToken); string str = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } private async Task Delete(string uri, CancellationToken cancellationToken = default) where T : IOmgLolResponseData { T? responseData = default(T); try { HttpResponseMessage response = await _client.DeleteAsync(uri, cancellationToken: cancellationToken); if (response.IsSuccessStatusCode) { string str = await response.Content.ReadAsStringAsync(); try { OmgLolResponse? responseObj = await response.Content.ReadFromJsonAsync>(_serializerOptions, cancellationToken: cancellationToken); if (responseObj?.Request?.Success ?? false) { responseData = responseObj.Response; } } catch (JsonException ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); Debug.WriteLine(str); } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return responseData; } public async Task> StatuslogLatest() => (await Get("/statuslog/latest"))?.Statuses ?? new List(); public async Task> Statuslog(string address) => (await Get($"/address/{address}/statuses"))?.Statuses ?? new List(); public async Task StatuslogBio(string address) { StatusBioResponseData? responseData = await Get($"/address/{address}/statuses/bio"); return Utilities.MdToHtmlMarkup(responseData?.Bio ?? ""); } public async Task AccountInfo() => await Get("/account/application/info"); public async Task Addresses() => await Get("/account/application/addresses"); public async Task StatusPost(string address, StatusPost statusPost) => await Post($"/address/{address}/statuses", statusPost); public async Task> SomePics() => (await Get("/pics"))?.Pics ?? new List(); public async Task> SomePics(string address) => (await Get($"/address/{address}/pics"))?.Pics ?? new List(); public async Task PutPic(string address, string base64Image) => (await Put($"/address/{address}/pics/upload", new PutPic { Pic = base64Image })); public async Task PutPic(string address, IBrowserFile file) { byte[] bytes; using (var memoryStream = new MemoryStream()) { await file.OpenReadStream().CopyToAsync(memoryStream); bytes = memoryStream.ToArray(); } return await PutPic(address, bytes); } public async Task PutPic(string address, FileResult file) { byte[] bytes; using var memoryStream = new MemoryStream(); using var fileStream = await file.OpenReadAsync(); await fileStream.CopyToAsync(memoryStream); bytes = memoryStream.ToArray(); return await PutPic(address, bytes); } public async Task PutPic(string address, byte[] bytes) => await PutPic(address, Convert.ToBase64String(bytes)); public async Task PostPicDescription(string address, string id, string? description) => (await Post($"/address/{address}/pics/{id}", new PostPic { Description = description })); public async Task DeletePic(string address, string id) => (await Delete($"/address/{address}/pics/{id}")); public async Task PatchStatus(string address, string id, string content, string? emoji) => (await Patch($"/address/{address}/statuses/", new PatchStatus { Id = id, Content = content, Emoji = emoji })); public async Task DeleteStatus(string address, string id) => (await Delete($"/address/{address}/statuses/{id}")); public async Task?> NowGarden() => (await Get($"/now/garden"))?.Garden ?? new List(); public async Task?> Directory() => (await Get($"/directory"))?.Directory ?? new List(); public async Task GetNowPage(string address) => (await Get($"/address/{address}/now"))?.Now; public async Task PostNowPage(string address, string content, bool listed) => await Post($"/address/{address}/now", new NowContentData { Content = content, Listed = listed ? 1 : 0 }); public async Task> Ephemeral() => (await Get($"/ephemeral"))?.Content?.Select(s => (MarkupString)s)?.ToList() ?? new List(); public async Task PostEphemeral(string content) => await Post("/ephemeral", new EphemeralData { Content = content }); public async Task GetProfile(string address) => await Get($"/address/{address}/web"); public async Task PostProfile(string address, string content, bool publish = true) => await Post($"/address/{address}/web", new PostProfile { Content = content, Publish = publish }); public async Task PostProfile(string address, PostProfile data) => await Post($"/address/{address}/web", data); public async Task?> GetThemes() => (await Get($"/theme/list"))?.Themes; public async Task GetThemePreview(string theme) => (MarkupString)((await Get($"/theme/{theme}/preview"))?.Html ?? string.Empty); public async Task PostProfilePic(string address, FileResult image) => await PostBinary($"/address/{address}/pfp", fileResult: image); public async Task OAuth(string code, string client_id, string client_secret, string redirect_uri) { string? token = null; string uri = $"/oauth/?code={code}&client_id={client_id}&client_secret={client_secret}&redirect_uri={redirect_uri}&scope=everything"; try { HttpResponseMessage response = await _client.GetAsync(uri); if (response.IsSuccessStatusCode) { TokenResponseData? responseObj = await response.Content.ReadFromJsonAsync(_serializerOptions); if (responseObj != null && !string.IsNullOrEmpty(responseObj.AccessToken)) { token = responseObj.AccessToken; } } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return token; } public async Task GetHtml(string url) { string? raw = null; try { HttpResponseMessage response = await _client.GetAsync(url); if (response.IsSuccessStatusCode) { raw = await response.Content.ReadAsStringAsync(); } } catch (Exception ex) { Debug.WriteLine(@"\tERROR {0}", ex.Message); } return string.IsNullOrEmpty(raw) ? null : (MarkupString)raw; } } }