#r @"../bin/FSharpx.Extras.dll"
#r @"../bin/FSharpx.Async.dll"
#r @"../bin/FSharp.Control.AsyncSeq.dll"
open FSharp.Control
open FSharpx.IO
open FSharpx.Net
open System
open System.Net
open System.Threading
let root = "http://msdn.microsoft.com"
let proxy = "http://localhost:8082/"
// ----------------------------------------------------------------------------
// Simple web proxy implemented using 'HttpListener'. This version downloads
// the entire web page as a string and then writes it to the response stream.
let cts1 = new CancellationTokenSource()
HttpListener.Start(proxy, (fun (req, resp) -> async {
// Download the web page
let url = root + req.Url.PathAndQuery
let wc = new WebClient()
let! html = wc.AsyncDownloadString(Uri(url))
// Replace URLs and send to the response stream
let html = html.Replace(root, proxy)
do! resp.AsyncReply(html) }), cancellationToken = cts1.Token)
// Now go to: http://localhost:8082/en-us/fsharp
cts1.Cancel()
// ----------------------------------------------------------------------------
// Better version of a proxy - this time, we read data from the input stream
// in chunks and write them to the response stream as they arive.
let cts2 = new CancellationTokenSource()
HttpListener.Start(proxy, (fun (req, resp) -> async {
// Initialize the download
let url = root + req.Url.PathAndQuery
let targetReq = HttpWebRequest.Create(url)
use! targetResp = targetReq.AsyncGetResponse()
use stream = targetResp.GetResponseStream()
// Copy data until we read the entire input
let count = ref 1
let buffer = Array.zeroCreate 4096
while !count > 0 do
let! read = stream.AsyncRead(buffer, 0, buffer.Length)
do! resp.OutputStream.AsyncWrite(buffer, 0, read)
count := read
resp.Close() }), cancellationToken = cts2.Token)
cts2.Cancel()
// ----------------------------------------------------------------------------
// Proxy that copies data in chunks can be easily implemented using
// asynchronous sequences. We read all data as asynchronous sequence and
// write them to the output (Even simpler version could use 'AsyncWriteSeq'
// to write all input buffers to the output stream).
let cts3 = new CancellationTokenSource()
HttpListener.Start(proxy, (fun (req, resp) -> async {
// Initialize the download
let url = root + req.Url.PathAndQuery
let targetReq = HttpWebRequest.Create(url)
use! targetResp = targetReq.AsyncGetResponse()
use stream = targetResp.GetResponseStream()
// Iterate over chunks read as an asynchronous sequence
// and write them to the output stream
for buffer in stream.AsyncReadSeq(4096) do
do! resp.OutputStream.AsyncWrite(buffer, 0, buffer.Length)
resp.Close() }), cancellationToken = cts3.Token)
cts3.Cancel()
// ----------------------------------------------------------------------------
// A more sophisticated version of proxy that caches web
// pages using a simple agent.
type CacheMessage =
| TryGet of string * AsyncReplyChannel<option<byte[]>>
| Add of string * byte[]
// Creates an agent that handles 'CacheMessage' and implements the cache
let cache = MailboxProcessor.Start(fun agent -> async {
let pages = new System.Collections.Generic.Dictionary<_, _>()
while true do
let! msg = agent.Receive()
match msg with
| TryGet(url, repl) ->
// Try to get a value from the dictionary
match pages.TryGetValue(url) with
| true, data -> repl.Reply(Some(data))
| _ -> repl.Reply(None)
| Add(url, data) ->
// Add byte array to the cache
pages.[url] <- data })
let cts4 = new CancellationTokenSource()
HttpListener.Start(proxy, (fun (req, resp) -> async {
// Generate URL and check data from the cache
let url = root + req.Url.PathAndQuery
let! cached = cache.PostAndAsyncReply(fun repl -> TryGet(url, repl))
match cached with
| Some data ->
// Reply using data from the cache
do! resp.OutputStream.AsyncWrite(data)
resp.Close()
| None ->
// Initialize the download
let targetReq = HttpWebRequest.Create(url)
use! targetResp = targetReq.AsyncGetResponse()
use stream = targetResp.GetResponseStream()
// Create a cached asynchronous sequence
// (that reads the stream only once)
let cachedData = stream.AsyncReadSeq(4096) |> AsyncSeq.cache
// Start workflow that reads all data in memory (for caching)
let! allBytes =
cachedData
|> AsyncSeq.fold (fun st data -> data::st) []
|> Async.StartChild
// Write all data from the async sequence to the output
for buffer in cachedData do
do! resp.OutputStream.AsyncWrite(buffer, 0, buffer.Length)
resp.Close()
// Get all data accumulated in background and save
// them to the cache (for later use)
let! allData = allBytes
let data = allData |> List.rev |> Array.concat
cache.Post(Add(url, data)) }), cts4.Token)
cts4.Cancel()
Multiple items
namespace Microsoft.FSharp
--------------------
namespace FSharp
namespace Microsoft.FSharp.Control
namespace System
namespace System.Net
namespace System.Threading
val root: string
val proxy: string
val cts1: CancellationTokenSource
Multiple items
type CancellationTokenSource =
interface IDisposable
new: unit -> unit + 2 overloads
member Cancel: unit -> unit + 1 overload
member CancelAfter: millisecondsDelay: int -> unit + 1 overload
member Dispose: unit -> unit
member TryReset: unit -> bool
static member CreateLinkedTokenSource: token: CancellationToken -> CancellationTokenSource + 2 overloads
member IsCancellationRequested: bool
member Token: CancellationToken
<summary>Signals to a <see cref="T:System.Threading.CancellationToken" /> that it should be canceled.</summary>
--------------------
CancellationTokenSource() : CancellationTokenSource
CancellationTokenSource(millisecondsDelay: int) : CancellationTokenSource
CancellationTokenSource(delay: TimeSpan) : CancellationTokenSource
Multiple items
type HttpListener =
interface IDisposable
new: unit -> unit
member Abort: unit -> unit
member BeginGetContext: callback: AsyncCallback * state: obj -> IAsyncResult
member Close: unit -> unit
member EndGetContext: asyncResult: IAsyncResult -> HttpListenerContext
member GetContext: unit -> HttpListenerContext
member GetContextAsync: unit -> Task<HttpListenerContext>
member Start: unit -> unit
member Stop: unit -> unit
...
<summary>Provides a simple, programmatically controlled HTTP protocol listener. This class cannot be inherited.</summary>
--------------------
HttpListener() : HttpListener
val async: AsyncBuilder
type WebClient =
inherit Component
new: unit -> unit
member CancelAsync: unit -> unit
member DownloadData: address: string -> byte array + 1 overload
member DownloadDataAsync: address: Uri -> unit + 1 overload
member DownloadDataTaskAsync: address: string -> Task<byte array> + 1 overload
member DownloadFile: address: string * fileName: string -> unit + 1 overload
member DownloadFileAsync: address: Uri * fileName: string -> unit + 1 overload
member DownloadFileTaskAsync: address: string * fileName: string -> Task + 1 overload
member DownloadString: address: string -> string + 1 overload
...
<summary>Provides common methods for sending data to and receiving data from a resource identified by a URI.</summary>
Multiple items
type Uri =
interface ISerializable
new: uriString: string -> unit + 6 overloads
member Equals: comparand: obj -> bool
member GetComponents: components: UriComponents * format: UriFormat -> string
member GetHashCode: unit -> int
member GetLeftPart: part: UriPartial -> string
member IsBaseOf: uri: Uri -> bool
member IsWellFormedOriginalString: unit -> bool
member MakeRelative: toUri: Uri -> string
member MakeRelativeUri: uri: Uri -> Uri
...
<summary>Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.</summary>
--------------------
Uri(uriString: string) : Uri
Uri(uriString: string, creationOptions: inref<UriCreationOptions>) : Uri
Uri(uriString: string, uriKind: UriKind) : Uri
Uri(baseUri: Uri, relativeUri: string) : Uri
Uri(baseUri: Uri, relativeUri: Uri) : Uri
property CancellationTokenSource.Token: CancellationToken with get
<summary>Gets the <see cref="T:System.Threading.CancellationToken" /> associated with this <see cref="T:System.Threading.CancellationTokenSource" />.</summary>
<exception cref="T:System.ObjectDisposedException">The token source has been disposed.</exception>
<returns>The <see cref="T:System.Threading.CancellationToken" /> associated with this <see cref="T:System.Threading.CancellationTokenSource" />.</returns>
CancellationTokenSource.Cancel() : unit
CancellationTokenSource.Cancel(throwOnFirstException: bool) : unit
val cts2: CancellationTokenSource
type HttpWebRequest =
inherit WebRequest
interface ISerializable
member Abort: unit -> unit
member AddRange: range: int -> unit + 7 overloads
member BeginGetRequestStream: callback: AsyncCallback * state: obj -> IAsyncResult
member BeginGetResponse: callback: AsyncCallback * state: obj -> IAsyncResult
member EndGetRequestStream: asyncResult: IAsyncResult -> Stream + 1 overload
member EndGetResponse: asyncResult: IAsyncResult -> WebResponse
member GetRequestStream: unit -> Stream + 1 overload
member GetResponse: unit -> WebResponse
...
<summary>Provides an HTTP-specific implementation of the <see cref="T:System.Net.WebRequest" /> class.</summary>
Multiple items
val ref: value: 'T -> 'T ref
--------------------
type 'T ref = Ref<'T>
type Array =
interface ICollection
interface IEnumerable
interface IList
interface IStructuralComparable
interface IStructuralEquatable
interface ICloneable
member Clone: unit -> obj
member CopyTo: array: Array * index: int -> unit + 1 overload
member GetEnumerator: unit -> IEnumerator
member GetLength: dimension: int -> int
...
<summary>Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the base class for all arrays in the common language runtime.</summary>
val zeroCreate: count: int -> 'T array
val cts3: CancellationTokenSource
type CacheMessage =
| TryGet of string * AsyncReplyChannel<byte array option>
| Add of string * byte array
union case CacheMessage.TryGet: string * AsyncReplyChannel<byte array option> -> CacheMessage
Multiple items
val string: value: 'T -> string
--------------------
type string = String
type AsyncReplyChannel<'Reply> =
member Reply: value: 'Reply -> unit
type 'T option = Option<'T>
Multiple items
val byte: value: 'T -> byte (requires member op_Explicit)
--------------------
type byte = Byte
--------------------
type byte<'Measure> =
byte
union case CacheMessage.Add: string * byte array -> CacheMessage
val cache: MailboxProcessor<CacheMessage>
Multiple items
type MailboxProcessor<'Msg> =
interface IDisposable
new: body: (MailboxProcessor<'Msg> -> Async<unit>) * ?cancellationToken: CancellationToken -> MailboxProcessor<'Msg>
member Dispose: unit -> unit
member Post: message: 'Msg -> unit
member PostAndAsyncReply: buildMessage: (AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout: int -> Async<'Reply>
member PostAndReply: buildMessage: (AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout: int -> 'Reply
member PostAndTryAsyncReply: buildMessage: (AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout: int -> Async<'Reply option>
member Receive: ?timeout: int -> Async<'Msg>
member Scan: scanner: ('Msg -> Async<'T> option) * ?timeout: int -> Async<'T>
member TryPostAndReply: buildMessage: (AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout: int -> 'Reply option
...
--------------------
new: body: (MailboxProcessor<'Msg> -> Async<unit>) * ?cancellationToken: CancellationToken -> MailboxProcessor<'Msg>
static member MailboxProcessor.Start: body: (MailboxProcessor<'Msg> -> Async<unit>) * ?cancellationToken: CancellationToken -> MailboxProcessor<'Msg>
val agent: MailboxProcessor<CacheMessage>
val pages: Collections.Generic.Dictionary<string,byte array>
namespace System.Collections
namespace System.Collections.Generic
Multiple items
type Dictionary<'TKey,'TValue> =
interface ICollection<KeyValuePair<'TKey,'TValue>>
interface IEnumerable<KeyValuePair<'TKey,'TValue>>
interface IEnumerable
interface IDictionary<'TKey,'TValue>
interface IReadOnlyCollection<KeyValuePair<'TKey,'TValue>>
interface IReadOnlyDictionary<'TKey,'TValue>
interface ICollection
interface IDictionary
interface IDeserializationCallback
interface ISerializable
...
<summary>Represents a collection of keys and values.</summary>
<typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
<typeparam name="TValue">The type of the values in the dictionary.</typeparam>
--------------------
Collections.Generic.Dictionary() : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(dictionary: Collections.Generic.IDictionary<'TKey,'TValue>) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(collection: Collections.Generic.IEnumerable<Collections.Generic.KeyValuePair<'TKey,'TValue>>) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(comparer: Collections.Generic.IEqualityComparer<'TKey>) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(capacity: int) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(dictionary: Collections.Generic.IDictionary<'TKey,'TValue>, comparer: Collections.Generic.IEqualityComparer<'TKey>) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(collection: Collections.Generic.IEnumerable<Collections.Generic.KeyValuePair<'TKey,'TValue>>, comparer: Collections.Generic.IEqualityComparer<'TKey>) : Collections.Generic.Dictionary<'TKey,'TValue>
Collections.Generic.Dictionary(capacity: int, comparer: Collections.Generic.IEqualityComparer<'TKey>) : Collections.Generic.Dictionary<'TKey,'TValue>
val msg: CacheMessage
member MailboxProcessor.Receive: ?timeout: int -> Async<'Msg>
val url: string
val repl: AsyncReplyChannel<byte array option>
Collections.Generic.Dictionary.TryGetValue(key: string, value: byref<byte array>) : bool
val data: byte array
member AsyncReplyChannel.Reply: value: 'Reply -> unit
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val cts4: CancellationTokenSource
member MailboxProcessor.PostAndAsyncReply: buildMessage: (AsyncReplyChannel<'Reply> -> 'Msg) * ?timeout: int -> Async<'Reply>
Multiple items
type Async =
static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool>
static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload
static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool>
static member CancelDefaultToken: unit -> unit
static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>>
static member Choice: computations: Async<'T option> seq -> Async<'T option>
static member FromBeginEnd: beginAction: (AsyncCallback * obj -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads
static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
...
--------------------
type Async<'T>
static member Async.StartChild: computation: Async<'T> * ?millisecondsTimeout: int -> Async<Async<'T>>
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| op_Nil
| op_ColonColon of Head: 'T * Tail: 'T list
interface IReadOnlyList<'T>
interface IReadOnlyCollection<'T>
interface IEnumerable
interface IEnumerable<'T>
member GetReverseIndex: rank: int * offset: int -> int
member GetSlice: startIndex: int option * endIndex: int option -> 'T list
static member Cons: head: 'T * tail: 'T list -> 'T list
member Head: 'T
member IsEmpty: bool
member Item: index: int -> 'T with get
...
val rev: list: 'T list -> 'T list
val concat: arrays: 'T array seq -> 'T array
member MailboxProcessor.Post: message: 'Msg -> unit