MFlow  Create and maintain dynamic Web applications as easy and fast as console applications
Thou shall not write request handlers
 This release: 11/06/2014. (@agocorona) <>< . issues & bugs .  Mflow Source code,     source code of this site

New push mode, to present data in real time: Basic chat example

The new asynchronous widgets can display server information at the moment that they appear. And thanks to Software Transactional Memory (or MVars) this may be immediately.

The new primitive, push, like autoRefresh,  is a modifier of a widget behavior. In this case push  will execute the widget and present the output again and again using ajax internally. 

This is an example of a basic chat. All users inputs go to a mutable variable. this mutable variable (TVar) is watched by each user push widget, that wait for a new input, and simultaneously refresh all the user windows with every new message. As is now, the message must be different than the previous to be updated. (see the documentation about STM variables work)

Since there is a single push widget spawned per session and all browser tabs share the session, the chat will not work among two windows of the same browser, because the messages will appear alternatively in one and the other browser tab. but you can test it with two different browsers, for example, explorer and chrome. The single push widget per session is a design limitation in order to prevent the spawn of excessive server processes.

The content of the text box will be appended to the push widget above it

 Note that the push process do not push just data but a widget content. A push widget can have links and form fields that may  interact back with the server creating a page flow. This functionality is not evident in this example, hbiwever since the rendering of the widget is

p <<  line ++> noWidget

that is, a paragraph with the last input line and a dumb (invisible) widget that perform no action.

Since push widgets are asynchronous, the communication must be trough mutable variables with the rest of the widgets of the page.

Note also that the input box is configured with autoRefresh in order to prevent navigation or the refresh of the page with every form input.

Running example

(in the light red box):

Basic Chat as a push example


Source code:

{-# OPTIONS   -XCPP #-}
module PushSample (pushSample) where

import Control.Concurrent.STM
import System.IO.Unsafe

-- #define ALONE -- to execute it alone, uncomment this
#ifdef ALONE
import MFlow.Wai.Blaze.Html.All
main= runNavigation "" $ transientNav pushSample
import MFlow.Wai.Blaze.Html.All hiding(retry, page)
import Menu

lastLine = unsafePerformIO $ newTVarIO $ "The content will be appended here"
pushSample=  do
  last <- liftIO $ newTVarIO ""
  page  $ h2 << "Basic Chat as a push example"
       ++> hr
       ++> pageFlow "push" (push Append 1000 (disp last ) <** input )
       **> br
       ++> br
       ++> wlink () << b << "exit"

  -- the widget being pushed:
  disp last = do
      setTimeouts 100 0  -- after 100 seconds of inactivity , kill itself, but restart if needed
      line <- tget last
      p <<  line ++> noWidget

  input = autoRefresh  $ do
      line <- getString Nothing <** submitButton "Enter"
      tput lastLine line

  tput tv x = atomic $ writeTVar  tv  x

  tget last = atomic $ do
      msg <- readTVar lastLine
      lastmsg <- readTVar last
      case lastmsg == msg of
         False ->  do
            writeTVar last msg
            return msg
         True -> retry

atomic= liftIO . atomically

comments powered by Disqus