From 37eeae6bc2503281d1b806c85aa0e70645fd9966 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Sun, 5 Apr 2009 11:24:55 -0400 Subject: RoundTrip demo --- demo/prose | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'demo/prose') diff --git a/demo/prose b/demo/prose index 80113c3e..45b7be00 100644 --- a/demo/prose +++ b/demo/prose @@ -246,3 +246,13 @@ threads.urp

We specify some client-side code to run on page load using the onload attribute of <body>. The onload code in this example spawns two separate threads running the loop code with different prefixes, update intervals, and starting counters.

Old hands at concurrent programming may be worried at the lack of synchronization in this program. Ur/Web uses cooperative multi-threading, not the more common preemptive multi-threading. Only one thread runs at a time, and only particular function calls can trigger context switches. In this example, sleep is the only such function that appears.

+ +roundTrip.urp + +

So far, we've seen examples of client-side code triggering the execution of server-side code. Such remote calls only happen in response to client-side events. It is often useful to allow a client to trigger events on other clients, and Ur/Web facilitates this with a simple asynchronous message-passing facility. The current example introduces the basics of message-passing with a trivial use case, and the next example shows a more realistic case where several clients can communicate.

+ +

We are going to provide a silly service where a client can send messages to the server, which the server then echoes back to the client. The SQL table channels stores a mapping from client IDs to message channels. The abstract type client holds unique client IDs, which Ur/Web generates automatically as needed. A channel T is a channel to which messages of type T can be sent. Every channel belongs to a single client; anyone can send to a channel, but only the channel's owner can read the messages. Every client is associated with a particular open page on a particular web browser somewhere. Since web browsing sessions are ephemeral, clients and their channels are garbage-collected automatically as the web server loses contact with browsers. When a client is garbage-collected, any database row mentioning it or one of its channels is deleted. It's also possible to include option clients (and likewise for channels) in databases, in which case such columns are merely nulled out when they refer to dead clients.

+ +

The main function begins by retrieving the current client ID, allocating a new channel, and associating that channel with the current client in the database. Next, we allocate a buffer and return the page, which in its onload attribute starts two loops running in parallel. In contrast to in the last example, here we only use spawn with the call to the first loop, since every client-side event handler is implicitly started in a new thread. + +

The first loop, receiver, repeatedly reads messages from the channel and writes them to the buffer. The second loop, sender, periodically sends messages to the channel. Client code can't send messages directly. Instead, we must use server-side functions to do the sending. Clients aren't trusted to pass channels to the server, so our server-side function writeBack instead keys off of the client ID, looking up the corresponding channel in the database.

-- cgit v1.2.3