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..4ad9b92c 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 @@ -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/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 50428413..6f361aeb 100644 --- a/NOnion/NOnion.fsproj +++ b/NOnion/NOnion.fsproj @@ -19,9 +19,8 @@ - + - @@ -91,6 +90,7 @@ + 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 8450be42..4f58619d 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 @@ -130,7 +131,7 @@ type TorGuard do! client.ConnectAsync(ipEndpoint.Address, ipEndpoint.Port) |> Async.AwaitTask - |> FSharpUtil.WithTimeout + |> AsyncUtil.WithTimeout Constants.GuardConnectionTimeout } @@ -158,7 +159,7 @@ type TorGuard false ) |> Async.AwaitTask - |> FSharpUtil.WithTimeout Constants.CircuitOperationTimeout + |> AsyncUtil.WithTimeout Constants.CircuitOperationTimeout do! ExceptionUtil.RunGuardJobWithExceptionHandling( @@ -533,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 7d6c10e0..8823bd79 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 @@ -249,7 +250,7 @@ type TorServiceHost introEncPubKey do! - FSharpUtil.Retry + AsyncUtil.Retry connectToRendezvousJob maxRendezvousConnectRetryCount diff --git a/NOnion/Utility/AsyncUtil.fs b/NOnion/Utility/AsyncUtil.fs new file mode 100644 index 00000000..71afd8f6 --- /dev/null +++ b/NOnion/Utility/AsyncUtil.fs @@ -0,0 +1,47 @@ +namespace NOnion.Utility + +open System + +open Fsdk + +open NOnion + +module AsyncUtil = + let WithTimeout (timeSpan: TimeSpan) (job: Async<'R>) : Async<'R> = + async { + let! result = FSharpUtil.WithTimeout timeSpan job + + match result with + | Some value -> return value + | None -> return raise <| TimeoutErrorException() + } + + let Retry<'TEx when 'TEx :> Exception> + (jobToRetry: Async) + (maxRetryCount: int) + = + 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 + | Some value -> value + | None -> failwith <| sprintf "error unwrapping Option: %s" msg 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 diff --git a/NOnion/Utility/FSharpUtil.fs b/NOnion/Utility/FSharpUtil.fs deleted file mode 100644 index f4a67a17..00000000 --- a/NOnion/Utility/FSharpUtil.fs +++ /dev/null @@ -1,102 +0,0 @@ -namespace NOnion.Utility - -open System -open System.Runtime.ExceptionServices - -open FSharpx.Collections - -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 ]) - - 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" - } - - let Retry<'E1, 'E2 when 'E1 :> Exception and 'E2 :> Exception> - (jobToRetry: Async) - (maxRetryCount: int) - = - let rec retryLoop(tryNumber: int) = - async { - try - do! jobToRetry - with - | :? 'E1 - | :? 'E2 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 - - let UnwrapOption<'T> (opt: Option<'T>) (msg: string) : 'T = - match opt with - | Some value -> value - | None -> failwith <| sprintf "error unwrapping Option: %s" msg 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