From df99b5c168aeec30f5a42a2d11b19b378e736df5 Mon Sep 17 00:00:00 2001 From: webwarrior Date: Mon, 9 Jan 2023 11:17:30 +0100 Subject: [PATCH 1/4] Utility: made Retry func take 1 type parameter Changed Retry function to take 1 type parameter instead of 2 as handling 2 types of exceptions is not needed anymore because SocketException is wrapped in NOnionException. --- NOnion/Services/TorServiceHost.fs | 2 +- NOnion/Utility/FSharpUtil.fs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/NOnion/Services/TorServiceHost.fs b/NOnion/Services/TorServiceHost.fs index 7d6c10e0..daf8c6fc 100644 --- a/NOnion/Services/TorServiceHost.fs +++ b/NOnion/Services/TorServiceHost.fs @@ -249,7 +249,7 @@ type TorServiceHost introEncPubKey do! - FSharpUtil.Retry + FSharpUtil.Retry connectToRendezvousJob maxRendezvousConnectRetryCount diff --git a/NOnion/Utility/FSharpUtil.fs b/NOnion/Utility/FSharpUtil.fs index f4a67a17..6cf7d801 100644 --- a/NOnion/Utility/FSharpUtil.fs +++ b/NOnion/Utility/FSharpUtil.fs @@ -65,7 +65,7 @@ module FSharpUtil = return failwith "unreachable" } - let Retry<'E1, 'E2 when 'E1 :> Exception and 'E2 :> Exception> + let Retry<'TEx when 'TEx :> Exception> (jobToRetry: Async) (maxRetryCount: int) = @@ -74,8 +74,7 @@ module FSharpUtil = try do! jobToRetry with - | :? 'E1 - | :? 'E2 as ex -> + | :? 'TEx as ex -> if tryNumber < maxRetryCount then return! retryLoop(tryNumber + 1) else From 92e546611407fdfac44c7124f6dae201ab2a914c Mon Sep 17 00:00:00 2001 From: webwarrior Date: Mon, 16 Jan 2023 11:17:23 +0100 Subject: [PATCH 2/4] Network,Services,Utility: use Fsdk Added fsdk package. Reuse functions from Fsdk. --- NOnion/NOnion.fsproj | 1 + NOnion/Network/TorGuard.fs | 1 + NOnion/Services/TorServiceHost.fs | 1 + NOnion/Utility/FSharpUtil.fs | 102 ++++++++---------------------- NOnion/Utility/MailboxUtil.fs | 2 + NOnion/Utility/ResultUtil.fs | 2 + 6 files changed, 32 insertions(+), 77 deletions(-) diff --git a/NOnion/NOnion.fsproj b/NOnion/NOnion.fsproj index 50428413..75278f37 100644 --- a/NOnion/NOnion.fsproj +++ b/NOnion/NOnion.fsproj @@ -91,6 +91,7 @@ + diff --git a/NOnion/Network/TorGuard.fs b/NOnion/Network/TorGuard.fs index 8450be42..46248673 100644 --- a/NOnion/Network/TorGuard.fs +++ b/NOnion/Network/TorGuard.fs @@ -11,6 +11,7 @@ open System.Threading open Org.BouncyCastle.Security open Org.BouncyCastle.X509 +open Fsdk open NOnion open NOnion.Cells diff --git a/NOnion/Services/TorServiceHost.fs b/NOnion/Services/TorServiceHost.fs index daf8c6fc..989019b1 100644 --- a/NOnion/Services/TorServiceHost.fs +++ b/NOnion/Services/TorServiceHost.fs @@ -15,6 +15,7 @@ open Org.BouncyCastle.Crypto.Parameters open Org.BouncyCastle.Crypto.Generators open Org.BouncyCastle.Crypto.Signers open Org.BouncyCastle.Security +open Fsdk open NOnion open NOnion.Cells.Relay diff --git a/NOnion/Utility/FSharpUtil.fs b/NOnion/Utility/FSharpUtil.fs index 6cf7d801..6c556a28 100644 --- a/NOnion/Utility/FSharpUtil.fs +++ b/NOnion/Utility/FSharpUtil.fs @@ -4,96 +4,44 @@ open System open System.Runtime.ExceptionServices open FSharpx.Collections +open Fsdk open NOnion module FSharpUtil = - //Implementation copied from https://github.com/nblockchain/geewallet/blob/master/src/GWallet.Backend/FSharpUtil.fs - let ReRaise(ex: Exception) : Exception = - (ExceptionDispatchInfo.Capture ex).Throw() - failwith "Should be unreachable" - ex - - let rec public FindException<'T when 'T :> Exception> - (ex: Exception) - : Option<'T> = - let rec findExInSeq(sq: seq) = - match Seq.tryHeadTail sq with - | Some(head, tail) -> - match FindException head with - | Some ex -> Some ex - | None -> findExInSeq <| tail - | None -> None - - if isNull ex then - None - else - match ex with - | :? 'T as specificEx -> Some specificEx - | :? AggregateException as aggEx -> - findExInSeq aggEx.InnerExceptions - | _ -> FindException<'T> ex.InnerException - - type private Either<'Val, 'Err when 'Err :> Exception> = - | FailureResult of 'Err - | SuccessfulValue of 'Val - let WithTimeout (timeSpan: TimeSpan) (job: Async<'R>) : Async<'R> = async { - let read = - async { - let! value = job - return value |> SuccessfulValue |> Some - } - - let delay = - async { - let total = int timeSpan.TotalMilliseconds - do! Async.Sleep total - return FailureResult <| TimeoutException() |> Some - } - - let! dummyOption = Async.Choice([ read; delay ]) + let! result = FSharpUtil.WithTimeout timeSpan job - match dummyOption with - | Some theResult -> - match theResult with - | SuccessfulValue r -> return r - | FailureResult _ -> return raise <| TimeoutErrorException() - | None -> - // none of the jobs passed to Async.Choice returns None - return failwith "unreachable" + match result with + | Some value -> return value + | None -> return raise <| TimeoutErrorException() } let Retry<'TEx when 'TEx :> Exception> (jobToRetry: Async) (maxRetryCount: int) = - let rec retryLoop(tryNumber: int) = - async { - try - do! jobToRetry - with - | :? 'TEx as ex -> - if tryNumber < maxRetryCount then - return! retryLoop(tryNumber + 1) - else - sprintf - "Maximum retry count reached, ex = %s" - (ex.ToString()) - |> TorLogger.Log - - return raise <| ReRaise ex - | ex -> - sprintf - "Unexpected exception happened in the retry loop, ex = %s" - (ex.ToString()) - |> TorLogger.Log - - return raise <| ReRaise ex - } - - retryLoop 0 + async { + try + do! + FSharpUtil.Retry<_, 'TEx> + (fun () -> jobToRetry) + maxRetryCount + with + | :? 'TEx as ex -> + sprintf "Maximum retry count reached, ex = %s" (ex.ToString()) + |> TorLogger.Log + + return raise <| FSharpUtil.ReRaise ex + | ex -> + sprintf + "Unexpected exception happened in the retry loop, ex = %s" + (ex.ToString()) + |> TorLogger.Log + + return raise <| FSharpUtil.ReRaise ex + } let UnwrapOption<'T> (opt: Option<'T>) (msg: string) : 'T = match opt with diff --git a/NOnion/Utility/MailboxUtil.fs b/NOnion/Utility/MailboxUtil.fs index 6024f954..515fbb4a 100644 --- a/NOnion/Utility/MailboxUtil.fs +++ b/NOnion/Utility/MailboxUtil.fs @@ -2,6 +2,8 @@ open System.Net.Sockets +open Fsdk + open NOnion module internal MailboxResultUtil = diff --git a/NOnion/Utility/ResultUtil.fs b/NOnion/Utility/ResultUtil.fs index e997ec7c..28dcfe7b 100644 --- a/NOnion/Utility/ResultUtil.fs +++ b/NOnion/Utility/ResultUtil.fs @@ -1,5 +1,7 @@ namespace NOnion.Utility +open Fsdk + //FIXME: for some reason FSharpUtil is in NOnion namespace instead of NOnion.Utility open NOnion From 67a8ec0ee9595ebe3de8db5c9a2cca51edad5065 Mon Sep 17 00:00:00 2001 From: webwarrior Date: Wed, 18 Jan 2023 10:39:41 +0100 Subject: [PATCH 3/4] Http,Network,Services.Utitlity: rename FSharpUtil Renamed FSharpUtil module to AsyncUtil. --- NOnion/Directory/KeyCertificatesDocument.fs | 2 +- NOnion/Directory/TorDirectory.fs | 2 +- NOnion/Http/TorHttpClient.fs | 4 ++-- NOnion/NOnion.fsproj | 2 +- NOnion/Network/TorCircuit.fs | 12 ++++++------ NOnion/Network/TorGuard.fs | 6 +++--- NOnion/Network/TorStream.fs | 6 +++--- NOnion/Services/TorServiceHost.fs | 2 +- NOnion/Utility/{FSharpUtil.fs => AsyncUtil.fs} | 4 +--- 9 files changed, 19 insertions(+), 21 deletions(-) rename NOnion/Utility/{FSharpUtil.fs => AsyncUtil.fs} (94%) diff --git a/NOnion/Directory/KeyCertificatesDocument.fs b/NOnion/Directory/KeyCertificatesDocument.fs index ebb12b9a..c3014c8d 100644 --- a/NOnion/Directory/KeyCertificatesDocument.fs +++ b/NOnion/Directory/KeyCertificatesDocument.fs @@ -6,7 +6,7 @@ open System.Text open Org.BouncyCastle.Asn1 open NOnion.Crypto.DirectoryCipher -open NOnion.Utility.FSharpUtil +open NOnion.Utility.AsyncUtil open NOnion.Utility.PemUtility type KeyCertificateEntry = diff --git a/NOnion/Directory/TorDirectory.fs b/NOnion/Directory/TorDirectory.fs index 7e03a77a..675a0cb7 100644 --- a/NOnion/Directory/TorDirectory.fs +++ b/NOnion/Directory/TorDirectory.fs @@ -13,7 +13,7 @@ open NOnion.Crypto open NOnion.Network open NOnion.Http open NOnion.Utility -open NOnion.Utility.FSharpUtil +open NOnion.Utility.AsyncUtil type RouterType = | Normal diff --git a/NOnion/Http/TorHttpClient.fs b/NOnion/Http/TorHttpClient.fs index 6b3ea42d..2a6d748b 100644 --- a/NOnion/Http/TorHttpClient.fs +++ b/NOnion/Http/TorHttpClient.fs @@ -42,7 +42,7 @@ type TorHttpClient(stream: Stream, host: string) = do! ReceiveAll memStream - |> FSharpUtil.WithTimeout Constants.HttpGetResponseTimeout + |> AsyncUtil.WithTimeout Constants.HttpGetResponseTimeout let httpResponse = memStream.ToArray() @@ -135,7 +135,7 @@ type TorHttpClient(stream: Stream, host: string) = do! ReceiveAll memStream - |> FSharpUtil.WithTimeout Constants.HttpPostResponseTimeout + |> AsyncUtil.WithTimeout Constants.HttpPostResponseTimeout let httpResponse = memStream.ToArray() diff --git a/NOnion/NOnion.fsproj b/NOnion/NOnion.fsproj index 75278f37..39ecf5b1 100644 --- a/NOnion/NOnion.fsproj +++ b/NOnion/NOnion.fsproj @@ -19,9 +19,9 @@ + - diff --git a/NOnion/Network/TorCircuit.fs b/NOnion/Network/TorCircuit.fs index 39edec50..22ddda11 100644 --- a/NOnion/Network/TorCircuit.fs +++ b/NOnion/Network/TorCircuit.fs @@ -1118,7 +1118,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout } member __.Extend(nodeDetail: CircuitNodeDetail) = @@ -1135,7 +1135,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout } member __.RegisterAsIntroductionPoint @@ -1161,7 +1161,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout } member __.RegisterAsRendezvousPoint(cookie: array) = @@ -1182,7 +1182,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout } member self.ExtendAsync nodeDetail = @@ -1208,7 +1208,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout } member __.WaitingForRendezvousJoin @@ -1236,7 +1236,7 @@ and TorCircuit completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitRendezvousTimeout + |> AsyncUtil.WithTimeout Constants.CircuitRendezvousTimeout } diff --git a/NOnion/Network/TorGuard.fs b/NOnion/Network/TorGuard.fs index 46248673..4f58619d 100644 --- a/NOnion/Network/TorGuard.fs +++ b/NOnion/Network/TorGuard.fs @@ -131,7 +131,7 @@ type TorGuard do! client.ConnectAsync(ipEndpoint.Address, ipEndpoint.Port) |> Async.AwaitTask - |> FSharpUtil.WithTimeout + |> AsyncUtil.WithTimeout Constants.GuardConnectionTimeout } @@ -159,7 +159,7 @@ type TorGuard false ) |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout do! ExceptionUtil.RunGuardJobWithExceptionHandling( @@ -534,7 +534,7 @@ type TorGuard TorLogger.Log "TorGuard: finished handshake process" //TODO: do security checks on handshake data } - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout member internal __.RegisterCircuit(circuit: ITorCircuit) : uint16 = let rec createCircuitId(retry: int) = diff --git a/NOnion/Network/TorStream.fs b/NOnion/Network/TorStream.fs index 4fc2ec27..488aed87 100644 --- a/NOnion/Network/TorStream.fs +++ b/NOnion/Network/TorStream.fs @@ -479,7 +479,7 @@ type TorStream(circuit: TorCircuit) = completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.StreamCreationTimeout + |> AsyncUtil.WithTimeout Constants.StreamCreationTimeout } member self.ConnectToDirectory() = @@ -499,7 +499,7 @@ type TorStream(circuit: TorCircuit) = completionTaskResult |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.StreamCreationTimeout + |> AsyncUtil.WithTimeout Constants.StreamCreationTimeout } member self.ConnectToDirectoryAsync() = @@ -523,7 +523,7 @@ type TorStream(circuit: TorCircuit) = completionTaskRes |> UnwrapResult |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.StreamCreationTimeout + |> AsyncUtil.WithTimeout Constants.StreamCreationTimeout } member self.ConnectToOutsideAsync(address, port) = diff --git a/NOnion/Services/TorServiceHost.fs b/NOnion/Services/TorServiceHost.fs index 989019b1..8823bd79 100644 --- a/NOnion/Services/TorServiceHost.fs +++ b/NOnion/Services/TorServiceHost.fs @@ -250,7 +250,7 @@ type TorServiceHost introEncPubKey do! - FSharpUtil.Retry + AsyncUtil.Retry connectToRendezvousJob maxRendezvousConnectRetryCount diff --git a/NOnion/Utility/FSharpUtil.fs b/NOnion/Utility/AsyncUtil.fs similarity index 94% rename from NOnion/Utility/FSharpUtil.fs rename to NOnion/Utility/AsyncUtil.fs index 6c556a28..71afd8f6 100644 --- a/NOnion/Utility/FSharpUtil.fs +++ b/NOnion/Utility/AsyncUtil.fs @@ -1,14 +1,12 @@ namespace NOnion.Utility open System -open System.Runtime.ExceptionServices -open FSharpx.Collections open Fsdk open NOnion -module FSharpUtil = +module AsyncUtil = let WithTimeout (timeSpan: TimeSpan) (job: Async<'R>) : Async<'R> = async { let! result = FSharpUtil.WithTimeout timeSpan job From 071774f9a87c0b388e73091d456f6e5b459d1fca Mon Sep 17 00:00:00 2001 From: webwarrior Date: Tue, 30 May 2023 11:48:47 +0200 Subject: [PATCH 4/4] Utility,Directory: use resources func from Fsdk Use ExtractEmbeddedResourceFileContents function from Fsdk. Remove local copy of that function. --- NOnion/Directory/TorDirectory.fs | 3 +- NOnion/NOnion.fsproj | 3 +- NOnion/Utility/EmbeddedResourceUtility.fs | 40 ----------------------- 3 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 NOnion/Utility/EmbeddedResourceUtility.fs diff --git a/NOnion/Directory/TorDirectory.fs b/NOnion/Directory/TorDirectory.fs index 675a0cb7..4ad9b92c 100644 --- a/NOnion/Directory/TorDirectory.fs +++ b/NOnion/Directory/TorDirectory.fs @@ -48,7 +48,8 @@ type TorDirectory = static member private GetTrustedAuthorities() = let authDirText = - EmbeddedResourceUtility + Fsdk + .Misc .ExtractEmbeddedResourceFileContents("auth_dirs.inc") .Replace("\r\n", "\n") diff --git a/NOnion/NOnion.fsproj b/NOnion/NOnion.fsproj index 39ecf5b1..6f361aeb 100644 --- a/NOnion/NOnion.fsproj +++ b/NOnion/NOnion.fsproj @@ -20,7 +20,6 @@ - @@ -91,7 +90,7 @@ - + diff --git a/NOnion/Utility/EmbeddedResourceUtility.fs b/NOnion/Utility/EmbeddedResourceUtility.fs deleted file mode 100644 index e4defe8e..00000000 --- a/NOnion/Utility/EmbeddedResourceUtility.fs +++ /dev/null @@ -1,40 +0,0 @@ -namespace NOnion.Utility - -open System -open System.IO -open System.Reflection - -module EmbeddedResourceUtility = - - // Code from https://github.com/nblockchain/geewallet/blob/428cb77d21dba20fc38c7ea032003c5861aac950/src/GWallet.Backend/Config.fs#L156 - let ExtractEmbeddedResourceFileContents(resourceName: string) : string = - let assembly = Assembly.GetExecutingAssembly() - let ress = String.Join(";", assembly.GetManifestResourceNames()) - - let fullNameOpt = - assembly.GetManifestResourceNames() - |> Seq.filter(fun aResourceName -> - aResourceName = resourceName - || aResourceName.EndsWith("." + resourceName) - ) - |> Seq.tryExactlyOne - - match fullNameOpt with - | Some fullName -> - use stream = assembly.GetManifestResourceStream fullName - - if isNull stream then - failwithf - "Embedded resource %s (%s) not found in assembly %s" - resourceName - fullName - assembly.FullName - - use reader = new StreamReader(stream) - reader.ReadToEnd() - | None -> - failwithf - "Embedded resource %s not found at all in assembly %s (resource names: %s)" - resourceName - assembly.FullName - ress