Created
May 6, 2024 05:35
-
-
Save Darkle/e2ea7ca35617bcea0340eb256ea9a476 to your computer and use it in GitHub Desktop.
This file contains 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
#!/usr/bin/env -S dotnet fsi | |
#r "nuget: FsHttp, 14.5.0" | |
#r "nuget: FSharp.Json, 0.4.1" | |
#r "nuget: Serilog, 3.1.1" | |
open System | |
open System.Net.Http.Headers | |
open System.Net | |
open FsHttp | |
open FSharp.Json | |
open Serilog | |
// Omitting the stuff that we don't actually use | |
type RedditFeedRootJson = | |
{ data: | |
{| after: string option | |
children: | |
{| data: | |
{| id: string | |
title: string | |
permalink: string | |
subreddit: string | |
score: int64 | |
created_utc: float | |
url: string | |
thumbnail: string | |
is_self: bool | |
media: {| oembed: {| ``type``: string option |} option |} option | |
post_hint: string option | |
is_video: bool |} |}[] |} } | |
type HttpStatusAndHeaders = | |
{ headers: HttpResponseHeaders | |
statusCode: HttpStatusCode } | |
[<Serializable>] | |
exception TooManyRequestsError of HttpStatusAndHeaders | |
[<Serializable>] | |
exception Non200ResponseError of HttpStatusAndHeaders | |
let isNon200HttpResponse (code: HttpStatusCode) = int (code) < 200 || int (code) >= 300 | |
let ridoVersion = 0.1 | |
let fetchFeedData (redditFeedToGet: string, oauthBearerToken) = | |
task { | |
try | |
let! resp = | |
http { | |
GET "https://oauth.reddit.com/r/aww/.json" | |
config_timeoutInSeconds 30 | |
// dotnet doesn't like colons in the user agent | |
UserAgent $"dotnet RIDO v{ridoVersion} (by github.com/Darkle/RIDO)" | |
AuthorizationBearer oauthBearerToken | |
} | |
|> Request.sendAsync | |
if HttpStatusCode.TooManyRequests.Equals(resp.statusCode) then | |
raise ( | |
TooManyRequestsError( | |
{ headers = resp.headers | |
statusCode = resp.statusCode } | |
) | |
) | |
else if isNon200HttpResponse (resp.statusCode) then | |
raise ( | |
Non200ResponseError( | |
{ headers = resp.headers | |
statusCode = resp.statusCode } | |
) | |
) | |
let! data = resp |> Response.toTextAsync | |
// Using FSharp.Json here as it will auto convert null values to optionals | |
return data |> Json.deserialize<RedditFeedRootJson> |> Ok | |
with e -> | |
return Error(e) | |
} | |
let getResetHeader (headers: HttpResponseHeaders) = | |
// TODO | |
() | |
let foo (feedUrl, oauthBearerToken) = | |
task { | |
let! fetchFeedResult = fetchFeedData (feedUrl, oauthBearerToken) | |
match fetchFeedResult with | |
| Error err -> | |
match err with | |
| :? TooManyRequestsError as response -> | |
Log.Information("service: {service}. error: {error}", "feed-updates", err) | |
let secondsTillRateLimitReset = getResetHeader (response.Data0.headers) | |
//... do backoff here | |
| _ -> | |
Log.Error( | |
"service: {service}. message: Error fetching data for: {feedUrl}. error: {@error}", | |
"feed-updates", | |
feedUrl, | |
err | |
) | |
| Ok feedData -> | |
Log.Information("service: {service}. Successfully fetched data for: {feedUrl}", "feed-updates", feedUrl) | |
//... do other stuff | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment