Created
August 30, 2024 07:42
-
-
Save sappho192/6ca7c067d4eb4a7fdda1197de23fc813 to your computer and use it in GitHub Desktop.
C# client toward Cloudflare worker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Npgsql; | |
using NpgsqlTypes; | |
var connString = "Host=database.example.com:5432;Username=postgres;Password=PASSWORD;Database=DATABASE_NAME"; | |
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString); | |
var dataSource = dataSourceBuilder.Build(); | |
var conn = await dataSource.OpenConnectionAsync(); | |
// Insert some data | |
await using (var cmd = new NpgsqlCommand( | |
"INSERT INTO sentences.raw VALUES (@input_sentence,@input_language,@output_sentence,@output_language,@timestamp,@comment)", | |
conn)) | |
{ | |
// Specify the id as null to let the database generate the default value | |
cmd.Parameters.Add(new NpgsqlParameter("input_sentence", NpgsqlDbType.Text) { Value = "안녕하세요." }); | |
cmd.Parameters.Add(new NpgsqlParameter("input_language", NpgsqlDbType.Text) { Value = "" }); | |
cmd.Parameters.Add(new NpgsqlParameter("output_sentence", NpgsqlDbType.Text) { Value = "" }); | |
cmd.Parameters.Add(new NpgsqlParameter("output_language", NpgsqlDbType.Text) { Value = "" }); | |
cmd.Parameters.Add(new NpgsqlParameter("timestamp", NpgsqlDbType.Timestamp) { Value = DateTime.UtcNow }); | |
cmd.Parameters.Add(new NpgsqlParameter("comment", NpgsqlDbType.Text) { Value = "테스트 데이터" }); | |
await cmd.ExecuteNonQueryAsync(); | |
} | |
// Retrieve all rows | |
await using (var cmd = new NpgsqlCommand("SELECT * FROM schema_name.table_name", conn)) | |
await using (var reader = await cmd.ExecuteReaderAsync()) | |
{ | |
while (await reader.ReadAsync()) | |
Console.WriteLine(reader.GetString(0)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Net.Http; | |
using System.Threading.Tasks; | |
namespace test | |
{ | |
public class Program | |
{ | |
public static async Task Main(string[] args) | |
{ | |
var httpClient = new HttpClient(); | |
var cloudflareClient = new CloudflareWorkerHttpClient(httpClient); | |
try | |
{ | |
var request = new HttpRequestMessage(HttpMethod.Get, "https://example.worker.dev"); | |
var response = await cloudflareClient.SendAsync(request); | |
if (response.IsSuccessStatusCode) | |
{ | |
// Process successful response | |
Console.WriteLine(await response.Content.ReadAsStringAsync()); | |
} | |
else | |
{ | |
// Handle error | |
Console.WriteLine($"Error: {response.StatusCode}"); | |
Console.WriteLine(await response.Content.ReadAsStringAsync()); | |
} | |
} | |
catch (CloudflareWorkerException ex) | |
{ | |
Console.WriteLine($"Cloudflare Worker Error: Code {ex.ErrorCode}"); | |
Console.WriteLine($"Error Message: {ex.ErrorMessage}"); | |
// from https://developers.cloudflare.com/workers/observability/errors/#_top | |
switch (ex.ErrorCode) | |
{ | |
case 1101: | |
Console.WriteLine("Worker threw a JavaScript exception."); | |
break; | |
case 1102: | |
Console.WriteLine("Worker exceeded CPU time limit."); | |
break; | |
case 1103: | |
Console.WriteLine("The owner of this worker needs to contact Cloudflare Support"); | |
break; | |
case 1015: | |
Console.WriteLine("Worker hit the burst rate limit."); | |
break; | |
case 1019: | |
Console.WriteLine("Worker hit loop limit."); | |
break; | |
case 1021: | |
Console.WriteLine("Worker has requested a host it cannot access."); | |
break; | |
case 1022: | |
Console.WriteLine("Cloudflare has failed to route the request to the Worker."); | |
break; | |
case 1024: | |
Console.WriteLine("Worker cannot make a subrequest to a Cloudflare-owned IP address."); | |
break; | |
case 1027: | |
Console.WriteLine("Worker exceeded free tier daily request limit."); | |
break; | |
case 1042: | |
Console.WriteLine("Worker tried to fetch from another Worker on the same zone, which is unsupported."); | |
break; | |
default: | |
Console.WriteLine("Unknown Cloudflare Worker error"); | |
break; | |
} | |
} | |
} | |
} | |
public class CloudflareWorkerException : Exception | |
{ | |
public int ErrorCode { get; } | |
public string ErrorMessage { get; } | |
public CloudflareWorkerException(int errorCode, string errorMessage) | |
: base($"Cloudflare Worker Error {errorCode}: {errorMessage}") | |
{ | |
ErrorCode = errorCode; | |
ErrorMessage = errorMessage; | |
} | |
} | |
public class CloudflareWorkerHttpClient | |
{ | |
private readonly HttpClient _httpClient; | |
public CloudflareWorkerHttpClient(HttpClient httpClient) | |
{ | |
_httpClient = httpClient; | |
} | |
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request) | |
{ | |
var response = await _httpClient.SendAsync(request); | |
if (!response.IsSuccessStatusCode && IsCloudflareWorkerError(response)) | |
{ | |
throw new CloudflareWorkerException( | |
GetErrorCodeFromResponse(response).GetAwaiter().GetResult(), | |
GetErrorMessageFromResponse(response).GetAwaiter().GetResult()); | |
} | |
return response; | |
} | |
private bool IsCloudflareWorkerError(HttpResponseMessage response) | |
{ | |
// Check if the response contains Cloudflare-specific headers | |
return response.Headers.Contains("CF-RAY") && | |
response.Content.Headers.ContentType.MediaType == "text/html"; | |
} | |
private async Task<int> GetErrorCodeFromResponse(HttpResponseMessage response) | |
{ | |
// Parse the HTML content to extract the error code | |
var htmlContent = await response.Content.ReadAsStringAsync(); | |
var errorCodeMatch = System.Text.RegularExpressions.Regex.Match(htmlContent, @"<title>Error (\d+)</title>"); | |
if (errorCodeMatch.Success && int.TryParse(errorCodeMatch.Groups[1].Value, out var errorCode)) | |
{ | |
return errorCode; | |
} | |
throw new Exception("Unable to parse error code from Cloudflare Worker response"); | |
} | |
private async Task<string> GetErrorMessageFromResponse(HttpResponseMessage response) | |
{ | |
// Parse the HTML content to extract the error message | |
var htmlContent = await response.Content.ReadAsStringAsync(); | |
var errorMessageMatch = System.Text.RegularExpressions.Regex.Match(htmlContent, @"<p class=""error-message"">(.*)</p>"); | |
if (errorMessageMatch.Success) | |
{ | |
return errorMessageMatch.Groups[1].Value.Trim(); | |
} | |
throw new Exception("Unable to parse error message from Cloudflare Worker response"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment