/
Server.fsx
119 lines (94 loc) · 3.67 KB
/
Server.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#r "..\\bin\\FSharp.AgentExtensions.dll"
open FSharp.Control
open System.IO
open System.Net
open System.Text
open System.Threading
// ----------------------------------------------------------------------------
// Simple agent
let simpleAgent = Agent<_>.Start(fun agent -> async {
while true do
let! msg = agent.Receive()
printfn "Received: %s" msg })
simpleAgent.Post("Hello world!")
// ----------------------------------------------------------------------------
// Agent implementing a chat room
type ChatMessage =
| GetContent of AsyncReplyChannel<string>
| SendMessage of string
let agent = Agent<_>.Start(fun agent ->
let rec loop messages = async {
// Pick next message from the mailbox
let! msg = agent.Receive()
match msg with
| SendMessage msg ->
// Add message to the list & continue
return! loop (msg :: messages)
| GetContent reply ->
// Generate HTML with messages
let sb = new StringBuilder()
sb.Append("<ul>\n") |> ignore
for msg in messages do
sb.AppendFormat(" <li>{0}</li>\n", msg) |> ignore
sb.Append("</ul>") |> ignore
// Send it back as the reply
reply.Reply(sb.ToString())
return! loop messages }
loop [] )
agent.Post(SendMessage "Welcome to F# chat implemented using agents!")
agent.Post(SendMessage "This is my second message to this chat room...")
agent.PostAndReply(GetContent)
// ----------------------------------------------------------------------------
// Encapsulated agent
type ChatRoom() =
let agent = Agent<_>.Start(fun agent ->
let rec loop messages = async {
let! msg = agent.Receive()
match msg with
| SendMessage msg ->
// Add message to the list & continue
return! loop (msg :: messages)
| GetContent reply ->
// Generate HTML with messages
let sb = new StringBuilder()
sb.Append("<ul>\n") |> ignore
for msg in messages do
sb.AppendFormat(" <li>{0}</li>\n", msg) |> ignore
sb.Append("</ul>") |> ignore
// Send it back as the reply
reply.Reply(sb.ToString())
return! loop messages }
loop [] )
member x.SendMessage(msg) = agent.Post(SendMessage msg)
member x.AsyncGetContent(?timeout) = agent.PostAndAsyncReply(GetContent, ?timeout=timeout)
member x.GetContent() = agent.PostAndReply(GetContent)
let room = new ChatRoom()
room.SendMessage("Welcome to F# chat implemented using agents!")
room.SendMessage("This is my second message to this chat room...")
room.GetContent()
// ----------------------------------------------------------------------------
// Exposing the chat agent using a simple HTTP server
let root = @"C:\Tomas\Projects\Demos\FSharp.Agents\Demo.ChatServer\"
let cts = new CancellationTokenSource()
HttpListener.Start
("http://localhost:8082/", (fun (request, response) -> async {
match request.Url.LocalPath with
| "/post" ->
// Send message to the chat room
room.SendMessage(request.InputString)
response.Reply("OK")
| "/chat" ->
// Get messages from the chat room (asynchronously!)
let! text = room.AsyncGetContent()
response.Reply(text)
| s ->
// Handle an ordinary file request
let file =
root + (if s = "/" then "chat.html" else s.ToLower())
if File.Exists(file) then
let typ = contentTypes.[Path.GetExtension(file)]
response.Reply(typ, File.ReadAllBytes(file))
else
response.Reply(sprintf "File not found: %s" file) }),
cts.Token)
cts.Cancel()