B4J Tutorial [WebApp] Chatroom - Threads, Sessions and Server events

SS-2014-04-16_14.40.15.png


Online example: http://basic4ppc.com:51042/chat/index.html

This example demonstrates several important concepts of the web app framework.

Multiple pages

The chatroom is made of two pages. The login page and the chat page.
The WebSocket is broken when the browser navigates to a different page (or refreshes the current page). The http session allows us to pass data from one page to another. In this example the user name is stored in the login page and then retrieved in the chat page:
B4X:
'login
ws.Session.SetAttribute("name", name)
WebUtils.RedirectTo(ws, "chat.html")

'chat page
If ws.Session.HasAttribute("name") = False Then
   'name not found. Go to the login page. This will happen if the user goes to the chat page directly.
   WebUtils.RedirectTo(ws, "index.html")
Else
   name = ws.Session.GetAttribute("name")
   ws.Session.RemoveAttribute("name") 'remove the attribute
   'the user will be redirected to the login page next time.

   CallSubDelayed3(ChatShared, "NewConnection", Me, name)
   txt.RunMethod("select", Null)
End If

Threads

Each WebSocket class instance runs in a different thread (in release mode). This allows many users to be connected at the same time.
CallSubDelayed was modified in B4J v2.00 to be executed on the target object thread. This allows us to safely call subs in other modules or instances.
In this example we have a code module named ChatShared. This module holds references to all the active connections and whenever there is a new message it uses CallSubDelayed to notify each of the instances about the new message:
B4X:
'ChatShared code module
'notify each of the connected users about the new message
For Each c As Chat In connections.Values
   CallSubDelayed2(c, "NewMessage", msg)
Next

'Chat WebSocket class
Sub NewMessage(Msg As String)
   ChatTxt.RunMethod("append", Array As Object(Msg))
   ws.RunFunction("scrollDown", Null)
   ws.Flush
End Sub

The code in code modules will run in the main thread if we call it with CallSubDelayed.
In this example we call WebUtils methods directly as these methods do not rely on any shared data.

Server events

One of the great features of WebSockets is the simple support for server events. Unlike ajax based solutions, the clients don't need to poll the server with endless requests. At any given time the server can send messages to the client.
There is one extra step with server events. You must call ws.Flush at the end of the event. Flush is called internally in the case of client events.
 

Attachments

  • Chatroom.zip
    6.8 KB · Views: 1,831
Last edited:

LucaMs

Expert
Licensed User
Longtime User
What should I change in this web app Chat to play a sound on new msg?

I found the example I'm attaching, but I am a completely "newbie" (and probably I want to continue to be a newbie :D) with java scripts, ajax & C.

I suppose I have to modify Chat.html (and ChatShared.NewMessage to call a function of Chat.html).

(please, start a new thread for this question :): can PHP, JavaScript, Ajax... "coexist"? Uhm... maybe not, they must be elaborated by the server... mah!)


Thaaank you
 

Attachments

  • notify.zip
    93.6 KB · Views: 555

LucaMs

Expert
Licensed User
Longtime User
I have tried so:
B4X:
    <script>
    function scrollDown() {
     $("#chattxt").animate({
            scrollTop: $('#chattxt').prop("scrollHeight")
        }, 300);
        $('#chatAudio')[0].play();
    }
    $( document ).ready(function() {
        b4j_connect("/main");
    });
    </script>

adding one code line: $('#chatAudio')[0].play();

and:
B4X:
$(function(){
$('<audio id="chatAudio"><source src="notify.ogg" type="audio/ogg"><source src="notify.mp3" type="audio/mpeg"><source src="notify.wav" type="audio/wav"></audio>').appendTo('body');
});

before </head>.

it is not enough :(

(audio files in www folder)
 

LucaMs

Expert
Licensed User
Longtime User
@Roycefer the index.html I attached in #43 seems to be "simple" (not to me, but to you :D).

I guess I should extrapolate a few lines of code.

B4X:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>9lessons Javascript Notification Sound</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
    $("#chatData").focus();

THIS ONE ---> $('<audio id="chatAudio"><source src="notify.ogg" type="audio/ogg"><source src="notify.mp3" type="audio/mpeg"><source src="notify.wav" type="audio/wav"></audio>').appendTo('body');


  $("#trig").on("click",function(){
    var a = $("#chatData").val().trim();
    if(a.length > 0){
    $("#chatData").val('');
    $("#chatData").focus();
     $("<li></li>").html('<img src="small.jpg"/><span>'+a+'</span>').appendTo("#chatMessages");
      $("#chat").animate({"scrollTop": $('#chat')[0].scrollHeight}, "slow");

AND THIS --->      $('#chatAudio')[0].play();

    }
  });
});
</script>
<style type="text/css">
* { padding:0px; margin:0px; }
body{font-family:arial;font-size:13px}
#chatBox {width:400px; border:1px solid #000;margin:5px;}
#chatBox > h3 { background-color:#6d84b4; padding:3px; color:#fff; }
#chat { max-height:220px; overflow-y:auto; max-width:400px; }
#chat > ul > li { padding:3px;clear:both;padding:4px;margin:10px 0px 5px 0px;overflow:auto }
#chatMessages{list-style:none}

#chatMessages > li > img { width:35px;float:left }
#chatMessages > li > span { width:300px;float:left;margin-left:5px}
#chatData { padding:5px; margin:5px; border-radius:5px; border:1px solid #999;width:300px }
#trig { padding: 4px;border: solid 1px #333;background-color: #133783;color:#fff;font-weight:bold }
</style>

</head>
<body>
 
    <div style='margin:0 auto;width:800px;'>
        <div style='margin:20px'>
    <h1>Javascript Notification Sound</h1>
    <h3>Turn the volume up and try this demo <a href='http://9lessons.info'>9lessons.info</a></h3>
    </div>

 
    <div id='chatBox' style='margin-top:20px'>
        <h3>9lessons Demo Chat</h3>
        <div id='chat'>
            <ul id='chatMessages'>
                <li>
                    <img src="small.jpg"/>
                    <span>Hello Friends</span>
                </li>
                <li>
                    <img src="small.jpg"/>
                    <span>How are you?</span>
                </li>
            </ul>
        </div>
        <input type="text" id="chatData" placeholder="Message" />
        <input type="button" value=" Send " id="trig" />
    </div>


    </div>
  <iframe src="http://demos.9lessons.info/counter.html" frameborder="0" scrolling="no" height="0"></iframe>
</body>
</html>

but then?
 

Roycefer

Well-Known Member
Licensed User
Longtime User
https://github.com/admsev/jquery-play-sound has the jquery.playSound.js file. If you host the file on your site, just add
B4X:
<script src="jquery.playSound.js"></script>
in your <head> section.

Then you can put something like this in your main <script> section and call it as you would a normal function:
B4X:
function playNotification()
{
    $.playSound("notify");
}

The advantage of using jQuery is that it is typically very good at cross-browser compatibility. Directly playing audio files is problematic as different browsers require different syntax.
 

LucaMs

Expert
Licensed User
Longtime User
It works, but the html page shows this message:
upload_2015-10-1_2-11-3.png


To show this content a plugin is required

Probably my previous tests did not work because I should have used "/" before the name of audio files. More tests :):(:D
 

LucaMs

Expert
Licensed User
Longtime User
Now it works:
B4X:
<script type="text/javascript">
$(function(){ 
  $('<audio id="chatAudio"><source src="notify.ogg" type="audio/ogg"><source src="notify.mp3" type="audio/mpeg"><source src="notify.wav" type="audio/wav"></audio>').appendTo('body');
});
</script>

B4X:
function PlaySound() {
  $('#chatAudio')[0].play();
}
 
Top