Use WoofWare.Myriad entirely to generate the REST API (#9)
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/all-checks-complete Pipeline was successful

Co-authored-by: Smaug123 <patrick+github@patrickstevens.co.uk>
Reviewed-on: #9
This commit is contained in:
2024-01-30 00:17:45 +00:00
parent 58fdb23719
commit e96ae78665
15 changed files with 306 additions and 119 deletions

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open System open System
open PureGym open PureGym
@@ -50,7 +51,7 @@ module Authenticate =
let run (creds : UsernamePin) = let run (creds : UsernamePin) =
task { task {
let! cred = AuthToken.get creds let! cred = AuthToken.get creds CancellationToken.None
Console.WriteLine cred.AccessToken Console.WriteLine cred.AccessToken
match cred.ExpiryTime with match cred.ExpiryTime with

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -48,7 +49,7 @@ module Fullness =
let run (args : FullnessArgs) = let run (args : FullnessArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! id = GymSelector.canonicalId client args.Gym let! id = GymSelector.canonicalId client args.Gym
let! attendance = client.GetGymAttendance id let! attendance = client.GetGymAttendance id

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -44,7 +45,7 @@ module LookupGym =
let run (args : LookupGymArgs) = let run (args : LookupGymArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! s = client.GetGym 19 let! s = client.GetGym 19
System.Console.WriteLine (string<Gym> s) System.Console.WriteLine (string<Gym> s)
return 0 return 0

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
@@ -31,7 +32,7 @@ module MemberActivity =
let run (args : MemberActivityArgs) = let run (args : MemberActivityArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetMemberActivity () let! activity = client.GetMemberActivity ()
let activity = activity.ToMemberActivity () let activity = activity.ToMemberActivity ()
System.Console.WriteLine (string<MemberActivityThisMonth> activity) System.Console.WriteLine (string<MemberActivityThisMonth> activity)

View File

@@ -1,5 +1,6 @@
namespace PureGym.App namespace PureGym.App
open System.Threading
open Argu open Argu
open PureGym open PureGym
open System open System
@@ -41,7 +42,7 @@ module Sessions =
let run (args : SessionsArgs) = let run (args : SessionsArgs) =
task { task {
let! client = Api.make args.Creds let! client = Api.makeWithoutRefresh CancellationToken.None args.Creds
let! activity = client.GetSessions (args.FromDate, args.ToDate) let! activity = client.GetSessions (args.FromDate, args.ToDate)
System.Console.WriteLine (string<Sessions> activity) System.Console.WriteLine (string<Sessions> activity)

View File

@@ -2,26 +2,42 @@ namespace PureGym
open System open System
open System.Net.Http open System.Net.Http
open System.Threading
open System.Threading.Tasks open System.Threading.Tasks
/// Methods for interacting with the PureGym REST API. /// Methods for interacting with the PureGym REST API.
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module Api = module Api =
/// Create a REST client, authenticated as the specified user.
let make (auth : Auth) : IPureGymApi Task = /// Create a REST client, authenticated as the specified user. Creds will be refreshed if possible as long as
/// the returned disposable is not disposed.
let make (auth : Auth) : (IPureGymApi * IDisposable) Task =
let cache, getToken =
match auth with
| Auth.Token t ->
{ new IDisposable with
member _.Dispose () = ()
},
fun () -> t
| Auth.User cred ->
let cache = new Cache<_> (AuthToken.get cred, _.ExpiryTime)
cache :> _, (fun () -> Async.RunSynchronously (cache.GetCurrentValue ()))
task {
let client = new HttpClient ()
return PureGymApi.make (getToken >> _.AccessToken >> sprintf "Bearer %s") client, cache
}
/// Create a REST client, authenticated as the specified user. Do not refresh creds.
let makeWithoutRefresh (ct : CancellationToken) (auth : Auth) : IPureGymApi Task =
task { task {
let! token = let! token =
match auth with match auth with
| Auth.Token t -> Task.FromResult<_> t | Auth.Token t -> Task.FromResult<_> t
| Auth.User cred -> AuthToken.get cred | Auth.User cred -> AuthToken.get cred ct
let client = new HttpClient () let client = new HttpClient ()
client.BaseAddress <- Uri "https://capi.puregym.com/api/"
client.DefaultRequestHeaders.Authorization <- return PureGymApi.make (fun () -> $"Bearer %s{token.AccessToken}") client
Headers.AuthenticationHeaderValue ("Bearer", token.AccessToken)
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
return PureGymApi.make client
} }

View File

@@ -5,6 +5,7 @@ open System.Collections.Generic
open System.Net.Http open System.Net.Http
open System.Text.Json open System.Text.Json
open System.Text.Json.Serialization open System.Text.Json.Serialization
open System.Threading
open System.Threading.Tasks open System.Threading.Tasks
// System.Text.Json does not support internal F# records as of .NET 8, presumably because it can't find the constructor. // System.Text.Json does not support internal F# records as of .NET 8, presumably because it can't find the constructor.
@@ -72,8 +73,9 @@ module AuthToken =
let private options = JsonSerializerOptions (IncludeFields = true) let private options = JsonSerializerOptions (IncludeFields = true)
/// Get an AuthToken for the given user email address with the given eight-digit PureGym PIN. /// Get an AuthToken for the given user email address with the given eight-digit PureGym PIN.
let get (creds : UsernamePin) : Task<AuthToken> = let get (creds : UsernamePin) (ct : CancellationToken) : Task<AuthToken> =
task { async {
let! ct = Async.CancellationToken
use client = new HttpClient () use client = new HttpClient ()
client.BaseAddress <- Uri "https://auth.puregym.com" client.BaseAddress <- Uri "https://auth.puregym.com"
client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0") client.DefaultRequestHeaders.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
@@ -89,14 +91,21 @@ module AuthToken =
|> List.map KeyValuePair |> List.map KeyValuePair
use content = new FormUrlEncodedContent (request) use content = new FormUrlEncodedContent (request)
let! response = client.PostAsync (Uri "https://auth.puregym.com/connect/token", content)
let! response =
Async.AwaitTask (
client.PostAsync (Uri "https://auth.puregym.com/connect/token", content, cancellationToken = ct)
)
if response.IsSuccessStatusCode then if response.IsSuccessStatusCode then
let! content = response.Content.ReadAsStreamAsync () let! content = Async.AwaitTask (response.Content.ReadAsStreamAsync ct)
let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options)
// let! response = JsonSerializer.DeserializeAsync<AuthResponseRaw> (content, options) let! response =
Async.AwaitTask (JsonSerializer.DeserializeAsync<AuthResponseRaw>(content, options, ct).AsTask ())
return AuthToken.Parse response return AuthToken.Parse response
else else
let! content = response.Content.ReadAsStringAsync () let! content = Async.AwaitTask (response.Content.ReadAsStringAsync ct)
return failwithf $"bad status code: %+A{response.StatusCode}\n%s{content}" return failwithf $"bad status code: %+A{response.StatusCode}\n%s{content}"
} }
|> fun a -> Async.StartAsTask (a, cancellationToken = ct)

85
PureGym/Cache.fs Normal file
View File

@@ -0,0 +1,85 @@
namespace PureGym
open System
open System.Threading
open System.Threading.Tasks
type private CacheMessage<'a> =
| TriggerUpdate
| UpdateStored of 'a Task
| Get of AsyncReplyChannel<'a>
| Quit of AsyncReplyChannel<unit>
type internal Cache<'a> (obtainNew : CancellationToken -> 'a Task, expiry : 'a -> DateTime option) =
let cts = new CancellationTokenSource ()
let initialValue = obtainNew cts.Token
let rec handle (value : 'a Task) (mailbox : MailboxProcessor<CacheMessage<'a>>) : Async<unit> =
async {
let! message = mailbox.Receive ()
match message with
| Quit channel ->
channel.Reply ()
return ()
| CacheMessage.UpdateStored newValue -> return! handle newValue mailbox
| CacheMessage.TriggerUpdate ->
async {
let! a = Async.AwaitTask (obtainNew cts.Token)
let expiry = expiry a
match expiry with
| None -> return ()
| Some expiry ->
// a bit sloppy but :shrug:
do! Async.Sleep ((expiry - DateTime.Now) - TimeSpan.FromMinutes 1.0)
try
mailbox.Post CacheMessage.TriggerUpdate
with _ ->
// Post during shutdown sequence: drop it on the floor
()
return ()
}
|> fun a -> Async.Start (a, cancellationToken = cts.Token)
return! handle value mailbox
| CacheMessage.Get reply ->
let! valueAwaited = Async.AwaitTask value
reply.Reply valueAwaited
return! handle value mailbox
}
let mailbox = new MailboxProcessor<_> (handle initialValue)
do
mailbox.Start ()
mailbox.Post CacheMessage.TriggerUpdate
let isDisposing = ref 0
let hasDisposed = TaskCompletionSource<unit> ()
member this.GetCurrentValue () =
try
mailbox.PostAndAsyncReply CacheMessage.Get
with
// TODO I think this is the right exception...
| :? InvalidOperationException ->
raise (ObjectDisposedException (nameof (Cache)))
interface IDisposable with
member _.Dispose () =
if Interlocked.Increment isDisposing = 1 then
mailbox.PostAndReply CacheMessage.Quit
(mailbox :> IDisposable).Dispose ()
// We can't terminate the CTS until the mailbox has processed all client requests.
// Otherwise we terminate the mailbox's state Task before it has finished querying that
// task on behalf of clients.
cts.Cancel ()
cts.Dispose ()
hasDisposed.SetResult ()
else
hasDisposed.Task.Result

View File

@@ -9,7 +9,11 @@ open RestEase
/// The PureGym REST API. You probably want to instantiate one of these with `Api.make`. /// The PureGym REST API. You probably want to instantiate one of these with `Api.make`.
[<WoofWare.Myriad.Plugins.HttpClient>] [<WoofWare.Myriad.Plugins.HttpClient>]
[<Header("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")>] [<Header("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")>]
[<BaseAddress "https://capi.puregym.com/api/">]
type IPureGymApi = type IPureGymApi =
[<Header "Authorization">]
abstract AuthHeader : string
/// Get the complete list of all gyms known to PureGym. /// Get the complete list of all gyms known to PureGym.
[<Get "v1/gyms/">] [<Get "v1/gyms/">]
abstract GetGyms : ?ct : CancellationToken -> Task<Gym list> abstract GetGyms : ?ct : CancellationToken -> Task<Gym list>

View File

@@ -4,6 +4,8 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace PureGym namespace PureGym
open System open System
@@ -16,23 +18,19 @@ open RestEase
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module PureGymApi = module PureGymApi =
/// Create a REST client. /// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
let make (client : System.Net.Http.HttpClient) : IPureGymApi = let make (authHeader : unit -> string) (client : System.Net.Http.HttpClient) : IPureGymApi =
{ new IPureGymApi with { new IPureGymApi with
member _.GetGyms (ct : CancellationToken option) = member _.AuthHeader : string = authHeader ()
member this.GetGyms (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ("v1/gyms/", System.UriKind.Relative) System.Uri ("v1/gyms/", System.UriKind.Relative)
) )
@@ -43,32 +41,28 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return node.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq return jsonNode.AsArray () |> Seq.map (fun elt -> Gym.jsonParse elt) |> List.ofSeq
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMember (ct : CancellationToken option) = member this.GetMember (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ("v1/member", System.UriKind.Relative) System.Uri ("v1/member", System.UriKind.Relative)
) )
@@ -79,32 +73,28 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Member.jsonParse node return Member.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGymAttendance (gymId : int, ct : CancellationToken option) = member this.GetGymAttendance (gymId : int, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ( System.Uri (
"v1/gyms/{gym_id}/attendance" "v1/gyms/{gym_id}/attendance"
@@ -119,32 +109,28 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return GymAttendance.jsonParse node return GymAttendance.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetGym (gymId : int, ct : CancellationToken option) = member this.GetGym (gymId : int, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ( System.Uri (
"v1/gyms/{gym_id}" "v1/gyms/{gym_id}"
@@ -159,32 +145,28 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Gym.jsonParse node return Gym.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetMemberActivity (ct : CancellationToken option) = member this.GetMemberActivity (ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ("v1/member/activity", System.UriKind.Relative) System.Uri ("v1/member/activity", System.UriKind.Relative)
) )
@@ -195,32 +177,28 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return MemberActivityDto.jsonParse node return MemberActivityDto.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
member _.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) = member this.GetSessions (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
async { async {
let! ct = Async.CancellationToken let! ct = Async.CancellationToken
let uri = let uri =
System.Uri ( System.Uri (
(match client.BaseAddress with (match client.BaseAddress with
| null -> | null -> System.Uri "https://capi.puregym.com/api/"
raise (
System.ArgumentNullException (
nameof (client.BaseAddress),
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
)
)
| v -> v), | v -> v),
System.Uri ( System.Uri (
("v2/gymSessions/member" ("v2/gymSessions/member"
@@ -238,15 +216,17 @@ module PureGymApi =
RequestUri = uri RequestUri = uri
) )
do httpMessage.Headers.Add ("Authorization", this.AuthHeader.ToString ())
do httpMessage.Headers.Add ("User-Agent", "PureGym/1523 CFNetwork/1312 Darwin/21.0.0")
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
let response = response.EnsureSuccessStatusCode () let response = response.EnsureSuccessStatusCode ()
let! stream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
let! node = let! jsonNode =
System.Text.Json.Nodes.JsonNode.ParseAsync (stream, cancellationToken = ct) System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|> Async.AwaitTask |> Async.AwaitTask
return Sessions.jsonParse node return Sessions.jsonParse jsonNode
} }
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct)) |> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
} }

View File

@@ -3,6 +3,8 @@
// Changes to this file will be lost when the code is regenerated. // Changes to this file will be lost when the code is regenerated.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace PureGym namespace PureGym
/// Module containing JSON parsing methods for the GymOpeningHours type /// Module containing JSON parsing methods for the GymOpeningHours type
@@ -253,9 +255,41 @@ module Gym =
.AsValue() .AsValue()
.GetValue<string> () .GetValue<string> ()
let Location = GymLocation.jsonParse node.["location"] let Location =
let AccessOptions = GymAccessOptions.jsonParse node.["accessOptions"] GymLocation.jsonParse (
let GymOpeningHours = GymOpeningHours.jsonParse node.["gymOpeningHours"] match node.["location"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("location")
)
)
| v -> v
)
let AccessOptions =
GymAccessOptions.jsonParse (
match node.["accessOptions"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("accessOptions")
)
)
| v -> v
)
let GymOpeningHours =
GymOpeningHours.jsonParse (
match node.["gymOpeningHours"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("gymOpeningHours")
)
)
| v -> v
)
let EmailAddress = let EmailAddress =
(match node.["emailAddress"] with (match node.["emailAddress"] with
@@ -281,7 +315,17 @@ module Gym =
.AsValue() .AsValue()
.GetValue<string> () .GetValue<string> ()
let Address = GymAddress.jsonParse node.["address"] let Address =
GymAddress.jsonParse (
match node.["address"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("address")
)
)
| v -> v
)
let Status = let Status =
(match node.["status"] with (match node.["status"] with
@@ -856,7 +900,17 @@ namespace PureGym
module Visit = module Visit =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : Visit =
let Gym = VisitGym.jsonParse node.["Gym"] let Gym =
VisitGym.jsonParse (
match node.["Gym"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Gym")
)
)
| v -> v
)
let Duration = let Duration =
(match node.["Duration"] with (match node.["Duration"] with
@@ -909,8 +963,29 @@ namespace PureGym
module SessionsSummary = module SessionsSummary =
/// Parse from a JSON node. /// Parse from a JSON node.
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary = let jsonParse (node : System.Text.Json.Nodes.JsonNode) : SessionsSummary =
let ThisWeek = SessionsAggregate.jsonParse node.["ThisWeek"] let ThisWeek =
let Total = SessionsAggregate.jsonParse node.["Total"] SessionsAggregate.jsonParse (
match node.["ThisWeek"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("ThisWeek")
)
)
| v -> v
)
let Total =
SessionsAggregate.jsonParse (
match node.["Total"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Total")
)
)
| v -> v
)
{ {
Total = Total Total = Total
@@ -937,7 +1012,17 @@ module Sessions =
|> Seq.map (fun elt -> Visit.jsonParse elt) |> Seq.map (fun elt -> Visit.jsonParse elt)
|> List.ofSeq |> List.ofSeq
let Summary = SessionsSummary.jsonParse node.["Summary"] let Summary =
SessionsSummary.jsonParse (
match node.["Summary"] with
| null ->
raise (
System.Collections.Generic.KeyNotFoundException (
sprintf "Required key '%s' not found on JSON object" ("Summary")
)
)
| v -> v
)
{ {
Summary = Summary Summary = Summary

View File

@@ -6,20 +6,21 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn> <WarnOn>FS3559</WarnOn>
<WoofWareMyriadPluginVersion>1.1.13</WoofWareMyriadPluginVersion> <WoofWareMyriadPluginVersion>1.4.8</WoofWareMyriadPluginVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="String.fs" /> <Compile Include="String.fs" />
<Compile Include="Auth.fs" /> <Compile Include="Auth.fs" />
<Compile Include="Dto.fs" /> <Compile Include="Dto.fs" />
<Compile Include="GeneratedDto.fs"> <!--1--> <Compile Include="GeneratedDto.fs">
<MyriadFile>Dto.fs</MyriadFile> <!--2--> <MyriadFile>Dto.fs</MyriadFile>
</Compile> </Compile>
<Compile Include="Client.fs" /> <Compile Include="Client.fs" />
<Compile Include="GeneratedClient.fs"> <Compile Include="GeneratedClient.fs">
<MyriadFile>Client.fs</MyriadFile> <!--2--> <MyriadFile>Client.fs</MyriadFile>
</Compile> </Compile>
<Compile Include="Cache.fs" />
<Compile Include="Api.fs" /> <Compile Include="Api.fs" />
<Compile Include="GymSelector.fs" /> <Compile Include="GymSelector.fs" />
<EmbeddedResource Include="SurfaceBaseline.txt" /> <EmbeddedResource Include="SurfaceBaseline.txt" />
@@ -35,8 +36,7 @@
<PackageReference Update="FSharp.Core" Version="6.0.1" /> <PackageReference Update="FSharp.Core" Version="6.0.1" />
<PackageReference Include="System.Text.Json" Version="8.0.0" /> <PackageReference Include="System.Text.Json" Version="8.0.0" />
<PackageReference Include="Fastenshtein" Version="1.0.0.8" /> <PackageReference Include="Fastenshtein" Version="1.0.0.8" />
<PackageReference Include="Myriad.Core" Version="0.8.3" /> <PackageReference Include="Myriad.Sdk" Version="0.8.3" PrivateAssets="all" />
<PackageReference Include="Myriad.Sdk" Version="0.8.3" />
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" /> <PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" />
</ItemGroup> </ItemGroup>

View File

@@ -1,3 +1,6 @@
PureGym.Api inherit obj
PureGym.Api.make [static method]: PureGym.Auth -> (PureGym.IPureGymApi * IDisposable) System.Threading.Tasks.Task
PureGym.Api.makeWithoutRefresh [static method]: System.Threading.CancellationToken -> PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task
PureGym.Auth inherit obj, implements PureGym.Auth System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Auth System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases PureGym.Auth inherit obj, implements PureGym.Auth System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Auth System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 2 cases
PureGym.Auth+Tags inherit obj PureGym.Auth+Tags inherit obj
PureGym.Auth+Tags.Token [static field]: int = 1 PureGym.Auth+Tags.Token [static field]: int = 1
@@ -33,10 +36,8 @@ PureGym.AuthToken.ExpiryTime [property]: [read-only] System.DateTime option
PureGym.AuthToken.get_AccessToken [method]: unit -> string PureGym.AuthToken.get_AccessToken [method]: unit -> string
PureGym.AuthToken.get_ExpiryTime [method]: unit -> System.DateTime option PureGym.AuthToken.get_ExpiryTime [method]: unit -> System.DateTime option
PureGym.AuthTokenModule inherit obj PureGym.AuthTokenModule inherit obj
PureGym.AuthTokenModule.get [static method]: PureGym.UsernamePin -> PureGym.AuthToken System.Threading.Tasks.Task PureGym.AuthTokenModule.get [static method]: PureGym.UsernamePin -> System.Threading.CancellationToken -> PureGym.AuthToken System.Threading.Tasks.Task
PureGym.AuthTokenModule.ofBearerToken [static method]: string -> PureGym.AuthToken PureGym.AuthTokenModule.ofBearerToken [static method]: string -> PureGym.AuthToken
PureGym.Api inherit obj
PureGym.Api.make [static method]: PureGym.Auth -> PureGym.IPureGymApi System.Threading.Tasks.Task
PureGym.Gym inherit obj, implements PureGym.Gym System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Gym System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.Gym inherit obj, implements PureGym.Gym System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Gym System.IComparable, System.IComparable, System.Collections.IStructuralComparable
PureGym.Gym..ctor [constructor]: (string, int, int, PureGym.GymAddress, string, string, PureGym.GymOpeningHours, PureGym.GymAccessOptions, PureGym.GymLocation, string, string) PureGym.Gym..ctor [constructor]: (string, int, int, PureGym.GymAddress, string, string, PureGym.GymOpeningHours, PureGym.GymAccessOptions, PureGym.GymLocation, string, string)
PureGym.Gym.AccessOptions [property]: [read-only] PureGym.GymAccessOptions PureGym.Gym.AccessOptions [property]: [read-only] PureGym.GymAccessOptions
@@ -150,7 +151,9 @@ PureGym.GymSelector.NewName [static method]: string -> PureGym.GymSelector
PureGym.GymSelector.Tag [property]: [read-only] int PureGym.GymSelector.Tag [property]: [read-only] int
PureGym.GymSelectorModule inherit obj PureGym.GymSelectorModule inherit obj
PureGym.GymSelectorModule.canonicalId [static method]: PureGym.IPureGymApi -> PureGym.GymSelector -> int System.Threading.Tasks.Task PureGym.GymSelectorModule.canonicalId [static method]: PureGym.IPureGymApi -> PureGym.GymSelector -> int System.Threading.Tasks.Task
PureGym.IPureGymApi - interface with 6 member(s) PureGym.IPureGymApi - interface with 8 member(s)
PureGym.IPureGymApi.AuthHeader [property]: [read-only] string
PureGym.IPureGymApi.get_AuthHeader [method]: unit -> string
PureGym.IPureGymApi.GetGym [method]: (int, System.Threading.CancellationToken option) -> PureGym.Gym System.Threading.Tasks.Task PureGym.IPureGymApi.GetGym [method]: (int, System.Threading.CancellationToken option) -> PureGym.Gym System.Threading.Tasks.Task
PureGym.IPureGymApi.GetGymAttendance [method]: (int, System.Threading.CancellationToken option) -> PureGym.GymAttendance System.Threading.Tasks.Task PureGym.IPureGymApi.GetGymAttendance [method]: (int, System.Threading.CancellationToken option) -> PureGym.GymAttendance System.Threading.Tasks.Task
PureGym.IPureGymApi.GetGyms [method]: System.Threading.CancellationToken option -> PureGym.Gym list System.Threading.Tasks.Task PureGym.IPureGymApi.GetGyms [method]: System.Threading.CancellationToken option -> PureGym.Gym list System.Threading.Tasks.Task
@@ -223,7 +226,7 @@ PureGym.MemberActivityThisMonth.TotalVisits [property]: [read-only] int
PureGym.MemberModule inherit obj PureGym.MemberModule inherit obj
PureGym.MemberModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Member PureGym.MemberModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Member
PureGym.PureGymApiModule inherit obj PureGym.PureGymApiModule inherit obj
PureGym.PureGymApiModule.make [static method]: System.Net.Http.HttpClient -> PureGym.IPureGymApi PureGym.PureGymApiModule.make [static method]: (unit -> string) -> System.Net.Http.HttpClient -> PureGym.IPureGymApi
PureGym.Sessions inherit obj, implements PureGym.Sessions System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Sessions System.IComparable, System.IComparable, System.Collections.IStructuralComparable PureGym.Sessions inherit obj, implements PureGym.Sessions System.IEquatable, System.Collections.IStructuralEquatable, PureGym.Sessions System.IComparable, System.IComparable, System.Collections.IStructuralComparable
PureGym.Sessions..ctor [constructor]: (PureGym.SessionsSummary, PureGym.Visit list) PureGym.Sessions..ctor [constructor]: (PureGym.SessionsSummary, PureGym.Visit list)
PureGym.Sessions.get_Summary [method]: unit -> PureGym.SessionsSummary PureGym.Sessions.get_Summary [method]: unit -> PureGym.SessionsSummary
@@ -277,4 +280,4 @@ PureGym.VisitGym.Status [property]: [read-only] string
PureGym.VisitGymModule inherit obj PureGym.VisitGymModule inherit obj
PureGym.VisitGymModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.VisitGym PureGym.VisitGymModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.VisitGym
PureGym.VisitModule inherit obj PureGym.VisitModule inherit obj
PureGym.VisitModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Visit PureGym.VisitModule.jsonParse [static method]: System.Text.Json.Nodes.JsonNode -> PureGym.Visit

View File

@@ -1,5 +1,5 @@
{ {
"version": "3.0", "version": "4.0",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/main$" "^refs/heads/main$"
], ],

View File

@@ -438,7 +438,7 @@
}) })
(fetchNuGet { (fetchNuGet {
pname = "WoofWare.Myriad.Plugins"; pname = "WoofWare.Myriad.Plugins";
version = "1.1.13"; version = "1.4.8";
sha256 = "sha256-TjR+3spu9vXb2kOoXM9p6yzjpt2rja1Tu7cAOmIMhog= "; sha256 = "sha256-HdqiXz4pSQ+pPkj82RsWR7zn3JePQm5/IFl4dlR2O5Y=";
}) })
] ]