Coldfusion Websockets Пользователь вводит Функциональность

Я играю с веб-сокетами Coldfusion 10 и создал простой чат для тестирования. Я видел несколько чатов, в которых текст «пользователь печатает...», который появляется, когда другой пользователь печатает. Кто-нибудь знает, как это реализовать эффективно?


person Guest    schedule 27.05.2013    source источник


Ответы (2)


Создайте еще один канал «уведомление» и опубликуйте в нем «Пользователь печатает», когда пользователь делает «keyDown», и «пустая строка», когда «keyUp».

Подпишитесь на этот канал вместе с вашим чатом. целью этого канала на стороне получателя должен быть внутренний HTML-код, который может быть заполнен сообщением «Пользователь печатает».

Псевдокод:

<cfwebsocket name="notificationSocket" 
             onmessage="notifyHandler"
             subscribeto="notificationChannel" >

<cfwebsocket name="ChatSocket" 
             onmessage="chatHandler"
             subscribeto="chatChannel" >

<!-- Conversation displayer -->
<div id="messageBoard"></div>

<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea"></div>
<input name="submit" onClick="publishMessage()"></textarea>

<script>

    /*chat Functions*/
    var publishMessage = function(){
        var msg = document.getElementById('chatInput').value;
        mycfwebsocketobject.publish("chatChannel", msg );
    };

    var chatHandler = function(msgObj){
        document.getElementById('messageBoard').innerHTML += ColdFusion.JSON.encode(msgObj);
    };


    /*notifying Functions*/
    var notifyHandler = function(noteObj){
        document.getElementById('notifyArea').innerHTML = ColdFusion.JSON.encode(noteObj);
    };    

    var sayTyping = function(){
        mycfwebsocketobject.publish("notificationchannel","User is Typing..." );
    };
    var sayStopped = function(){
        mycfwebsocketobject.publish("notificationchannel","" );
    };

</script>

Еще одним улучшением будет наличие div уже с текстом «пользователь вводит», и ваш канал транслирует текст как «показать» и «не показать». По сути, это имя класса, данное для отображения и скрытия. Меньше трафика.

Подход 2: Использование одного и того же канала

<cfwebsocket name="ChatSocket" 
             onmessage="chatHandler"
             subscribeto="chatChannel" >

<!-- Conversation displayer -->
<div id="messageBoard"></div>

<!-- your text message input area -->
<textarea onKeyDown="sayTyping()" onKeyUp="sayStopped()" id="chatInput"></textarea>
<div id="notifyArea" class="no">User is typing...</div>
<input name="submit" onClick="publishMessage()"></textarea>

<script>

    /*chat Functions*/
    var publishMessage = function(){
        var msg = document.getElementById('chatInput').value;
        mycfwebsocketobject.publish("chatChannel", msg );
    };

    var chatHandler = function(msgObj){
        var msg = ColdFusion.JSON.encode(msgObj);
        if (msg == '@userTyping@-yes'){
            notifyHandler('yes');
        }
        else if (msg == '@userTyping@-no'){
            notifyHandler('no');
        }
        else {
            document.getElementById('messageBoard').innerHTML += msg;
        }
    };


    /*notifying Functions*/
    var notifyHandler = function(action){

        document.getElementById('notifyArea').className = action;

        /*call the notify handler with off to stop showing the user is typing message
        after a certain interval of time. This is to avoid someone believing that 
        partner is still typing even when the connection is lost*/

        if(action == 'on'){
            setTimeout(function(){notifyHandler('no')},250);
        }
    };    

    var sayTyping = function(){
        mycfwebsocketobject.publish("chatChannel","@userTyping@-yes" );
    };
    var sayStopped = function(){
        mycfwebsocketobject.publish("chatChannel","@userTyping@-no" );
    };

</script>
<style>
.yes { display:block;}
.no { display:none;}
</style>

Всегда можно обмануть этот код, набрав сообщение «@userTyping@-yes» или «@userTyping@-no». Но, как я уже сказал, это всего лишь POC. Кроме того, для упомянутого вами тайм-аута keyUp все равно позаботится об этом. Но вы также можете вызвать notifyHandler() с помощью setTimeout(), как показано выше.

person Sanjeev    schedule 29.05.2013
comment
Спасибо за пример. Единственная проблема заключается в том, что я использую веб-сокет для живого справочного чата, поэтому разговоры будут вестись один на один, а не транслироваться всем на канале. Нужно ли мне создавать уникальный подканал для уведомленияSocket для каждого инициированного чата? Кроме того, должен ли быть тайм-аут, чтобы он не обновлял каждую нажатую клавишу? - person Guest; 30.05.2013
comment
В этом случае вы можете использовать тот же канал и адаптировать свою логику, чтобы различать, является ли входящее сообщение «уведомлением» или сообщением чата. - person Sanjeev; 31.05.2013
comment
Таким образом, лучший способ иметь чат один на один, например, чат помощи в реальном времени, - это иметь один канал и фильтровать по идентификатору? - person Guest; 01.06.2013
comment
Вы можете сделать это или лучше всего использовать идентификатор сеанса пользователя для фильтрации. прочитайте эту фантастическую статью из блога BenNadel - bennadel.com/blog/. Это больше похоже на пошаговое руководство. - person Sanjeev; 01.06.2013

В комментариях есть вопрос о том, как фильтровать сообщения один на один. Вот пример кода для достижения этого.

Вместо использования атрибута subscribeTo используйте функцию js для подписки пользователя и передачи некоторых значений заголовка. Затем эти заголовки можно использовать в качестве фильтров в вызове публикации с помощью selector.

Пример:

<cfwebsocket name="ChatSocket" onOpen="openHandler" onMessage="msgHandler" onError="errHandler">

<script>
    function openHandler(){
        //Subscribe to the channel, pass in headers for filtering later
        ChatSocket.subscribe('chatChannel',{name: '#Session.Auth.FirstName#', UserID: '#Session.Auth.UserID#', AccountID: '#Session.Auth.AccountID#' });
    }

    function publish(txt, userID){
        var msg = {
            AccountID: "#Session.Auth.AccountID#",
            publisher: '#Session.Auth.UserID#', 
            id: userID,
            message: converthtml(txt)
        };
        //When including headers, the "selector" is where you will filter who it goes to.
        var headers = {
            AccountID: "#Session.Auth.AccountID#",
            publisher: '#Session.Auth.UserID#', 
            id: userID,
            selector: "UserID eq '"+userID+"' and AccountID eq '#Session.Auth.AccountID#'"
        };
        ChatSocket.publish('chatChannel',msg, headers);

    }

    function msgHandler(message){
        console.log(message);
    }

    function errHandler(err){
        console.log(err);
    }
</script>
person Sean B.    schedule 04.12.2013