Building a chat app that uses a node.js server in IOS

10,521

Solution 1

Of cuz you could create chat application using Socket.io with iOS/Android and HTML!

There are 2 ways for you to do it!

i) Implement your own socket communication with Socket.io, (this is diffucult, because you need to write most of the network implementation by yourself!)

Socket.io will interface as stream, that you need to connect from your iOS!

You could refer the iOS dev guide on how to implement the stream!

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/UsingSocketsandSocketStreams.html

There is an active thread that discuss about this too!

iPhone Objective-C socket communication with Socket.IO

ii) Use existing library or wrapper that people make for iOS, you could find the link below!

This library mainly done the networking part, and you just need to implement your app logics!

iOS

https://github.com/pkyeck/socket.IO-objc

Android

https://github.com/nkzawa/socket.io-client.java

It would be good for you to start with the library first and then try to make your own implementation! :))

Solution 2

I suggest following:

  1. Develop HTML5 application with node.js and NOSQL database (CouchDb in my example) on the server
  2. Do not use socket.io for your first playground, because its complex. You must first understand the websockets very well.

Do not burden yourself with pre-prepared frameworks and tons of code. You need a clear, simple code in order to make modifications you need later. You need full control and understanding of the code you have.

I attached working sample (thanks to Ales Smodis). For the sample bellow to work, you need to install 2 node.js packets:

npm install websocket
npm install nano 

And you need to create databse and insert at least 1 user into CouchDb database:

curl -X PUT http://localhost:5984/chatroom
curl -X PUT -H 'Content-Type: application/json' --data '{"username":"john","password":"john"}' http://localhost:5984/chatroom/john

$(document).ready(function () {

    var connection,
        username = 'Tester',
        password = 'Tester',
        historyCounter = 0,
        members = {},
        // displays
        jqLogin = $('#login'),
        jqChatroom = $('#chatroom'),
        // login display components
        jqWaiting = $('#waiting'),
        jqNickname = $('#nickname'),
        jqPassword = $('#password'),
        // chat display components
        jqHistory = $('#history'),
        jqMembers = $('#members'),
        jqLine = $('#line');

    function addLine(nick, line) {
        var jq = $('<p><span class="nick"></span><span class="line"></span></p>'),
            jqNick = jq.find('.nick'),
            jqLine = jq.find('.line'),
            i, lines;
        jqNick.text(nick ? nick + ': ' : '*** ');
        jqLine.text(line);
        jqHistory.append(jq);
        historyCounter++;
        for (lines = jqHistory.children(), i = 0; historyCounter > 100; i++, historyCounter--) {
            $(lines[i]).remove();
        }
    }

    function addMsg(msgObj) {
        var msgHandler = states[activeState].messageHandlers[msgObj.type] || function () { addLine(null, 'Neveljaven paket tipa ' + msgObj.type); };
        msgHandler(msgObj);
    }

    function clearMembers() {
        var nickname;
        for (nickname in members) {
            members[nickname].remove();
            delete members[nickname];
        }
        jqMembers.empty(); // just in case
    }

    function addMember(nickname) {
        var jq = $('<li></li>');
        jq.text(nickname);
        jqMembers.append(jq);
        members[nickname] = jq;
    }

    function removeMember(nickname) {
        if (nickname in members) {
            members[nickname].remove();
            delete members[nickname];
        }
    }

    function connect () {
        connection = new WebSocket('ws://127.0.0.1:8080');

        connection.onopen = function () {
            states[activeState].onopen();
        };

        connection.onmessage = function (message) {
            try {
                addMsg(JSON.parse(message.data));
            }
            catch (e) {
                addLine(null, 'Exception while handling a server message: ' + e.toString());
            }
        };

        connection.onclose = function () {
            states[activeState].onclose();
        };
    }

    function loginKeypress(event) {
        if (13 !== event.keyCode) return;
        username = jqNickname.val();
        password = jqPassword.val();
        if (!username) jqNickname[0].focus();
        else if (!password) jqPassword[0].focus();
        else {
            jqWaiting.css('display', '');
            jqNickname.unbind('keydown', loginKeypress);
            jqPassword.unbind('keydown', loginKeypress);
            connect();
        }
    }

    function inputKeypress(event) {
        var line;
        if (13 === event.keyCode) {
            line = jqLine.val();
            if (line.length === 0) return;
            jqLine.val('');
            connection.send(JSON.stringify({ 'type': 'line', 'line': line }));
        }
    }

    var states = {
            'login': {
                'start': function () {
                    jqChatroom.css('display', 'none');
                    jqWaiting.css('display', 'none');
                    jqLogin.css('display', '');
                    jqNickname.val('');
                    jqPassword.val('');
                    jqNickname[0].focus();
                    activeState = 'login';
                    jqNickname.bind('keydown', loginKeypress);
                    jqPassword.bind('keydown', loginKeypress);
                },
                'onopen': function () {
                    connection.send(JSON.stringify({ 'type': 'login', 'username': username, 'password': password }));
                },
                'messageHandlers': {
                    'state': function (msgObj) {
                        var i, history, users;
                        states.chat.start();
                        history = msgObj.history;
                        jqHistory.empty();
                        historyCounter = 0;
                        for (i = 0; i < history.length; i++) addMsg(history[i]);
                        users = msgObj.users;
                        clearMembers();
                        for (i = 0; i < users.length; i++) addMember(users[i]);
                    }
                },
                'unhandledMessage': function (msgObj) {
                    connection.close(4000, 'Unhandled message type');
                },
                'onclose': function () {
                    states.login.start();
                }
            },

            'chat': {
                'start': function () {
                    jqLogin.css('display', 'none');
                    jqWaiting.css('display', 'none');
                    jqChatroom.css('display', '');
                    jqHistory.empty();
                    historyCounter = 0;
                    activeState = 'chat';
                    jqLine.bind('keydown', inputKeypress);
                },
                'onopen': function () {
                    connection.close(4001, 'Connection opened while chatting');
                },
                'messageHandlers': {
                    'line': function (msgObj) {
                        addLine(msgObj.nick, msgObj.line);
                    },
                    'join': function (msgObj) {
                        addLine(null, 'Priklopil: ' + msgObj.nick);
                        addMember(msgObj.nick);
                    },
                    'leave': function (msgObj) {
                        addLine(null, 'Odklopil: ' + msgObj.nick);
                        removeMember(msgObj.nick);
                    }
                },
                'unhandledMessage': function (msgObj) {
                    connection.close(4000, 'Unhandled message type');
                },
                'onclose': function () {
                    addLine(null, 'Connection closed');
                    jqLine.unbind('keydown', inputKeypress);
                }
            }
        },
        activeState = 'login';

    states.login.start();
});
// node.js code
var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs'),
    nano = require('nano')('http://localhost:5984'),
    chatroomDb = nano.use('chatroom'),
    websocket = require('websocket'),
    chatHistory = [],
    activeUsers = {};

var filesDir = path.join(process.cwd(), 'web');

var mimeTypes = {
    '.html': 'text/html',
    '.css': 'text/css',
    '.js': 'text/javascript'
};

var getContentType = function (extension) {
    var mimeType = mimeTypes[extension];
    return mimeType ? mimeType : 'application/octet-stream';
};

var server = http.createServer(function (request, response) {
    var relativePath = url.parse(request.url).pathname,
        absolutePath = path.join(filesDir, relativePath);
    var handler = function (err, stats) {
        if (stats) {
            if (stats.isDirectory()) {
                absolutePath = path.join(absolutePath, 'index.html');
                fs.stat(absolutePath, handler);
                return;
            }
            if (stats.isFile()) {
                response.writeHead(200, getContentType(path.extname(absolutePath)));
                var stream = fs.createReadStream(absolutePath);
                stream.pipe(response);
                return;
            }
        }
        response.writeHead(404, {'Content-Type': 'text/plain'});
        response.write('Not found\r\n');
        response.end();
    };
    console.log('HTTP request for ' + relativePath);
    fs.stat(absolutePath, handler);
});
server.listen(8080, function () {});

wsServer = new websocket.server({
    'httpServer': server
});

function addLine (type, nick, line) {
    var msg = { 'type': type, 'nick': nick, 'line': line },
        jsonMsg = JSON.stringify(msg),
        username;
    chatHistory.push(msg);
    while (chatHistory.length > 100) chatHistory.shift();
    for (username in activeUsers) {
        activeUsers[username].sendMessage(jsonMsg);
    }
}

wsServer.on('request', function (request) {
    console.log('New websocket connection from ' + request.origin);
    // TODO: verify that request.origin is our web site

    var connection = request.accept(null, request.origin);

    var username = null;

    connection.on('message', function (message) {
        if (message.type !== 'utf8') {
            console.log('Refusing a non-utf8 message');
            return;
        }
        console.log('Processing message: ' + message.utf8Data);
        try {
            var m = JSON.parse(message.utf8Data);
            switch (m.type) {

                case 'login':
                    chatroomDb.get(m.username, function (err, body) {
                        if (err || (body.password !== m.password)) {
                            connection.close();
                            return;
                        }
                        username = m.username;
                        addLine('join', username, null);
                        activeUsers[username] = {
                            'sendMessage': function (jsonMsg) {
                                connection.sendUTF(jsonMsg);
                            }
                        };
                        var users = [], u;
                        for (u in activeUsers) users.push(u);
                        connection.sendUTF(JSON.stringify({ 'type': 'state', 'history': chatHistory, 'users': users }));
                    });
                    break;

                case 'line':
                    if (!username) {
                        connection.close();
                        break;
                    }
                    addLine('line', username, m.line);
                    break;
            }
        }
        catch (e) {
            console.log(e);
        }
    });

    connection.on('close', function (connection) {
        console.log('Connection closed');
        if (username) {
            delete activeUsers[username];
            addLine('leave', username, null);
        }
    });
});

console.log('Server running');
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Chatroom</title>
      <style>
        html, body {
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    margin: 0;
}

#heading {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 30px;
    margin: 0;
    padding: 0;
    line-height: 30px;
    text-align: center;
    font-size: 20px;
    background-color: green;
}

#outer {
    position: absolute;
    top: 30px;
    bottom: 0;
    left: 0;
    right: 0;
    margin: 20px;
    min-height: 400px;
    min-width: 400px;
    background-color: lime;
}

#inner {
    height: 100%;
    background-color: #ffc0cb;
}

#chat {
    position: absolute;
    top: 0;
    left: 0;
    right: 200px;
    bottom: 0;
    background-color: #ffd700;
}

#members {
    position: absolute;
    top: 0;
    right: 10px;
    width: 180px;
    bottom: 0;
    background-color: #ff00ff;
    list-style-type: none;
    padding: 10px;
    padding: 0;
    border: none;
}

#history {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 2em;
    right: 0;
    background-color: #00ffff;
    padding: 10px;
}

#input {
    position: absolute;
    height: 2em;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #90ee90;
    line-height: 2em;
}

#line {
    width: 100%;
    margin: 0;
    border: none;
    padding: 0;
}

#history > p {
    margin: 2px;
}

.nick {
    white-space: pre;
    display: table-cell;
}

.line {
    display: table-cell;
}

#login {
    height: 100%;
    display: table;
    margin: 0 auto;
}
#login > .svg {
    vertical-align: middle;
    display: table-cell;
}
#login-wrapper1 {
    display: table;
    height: 100%;
    width: 100%;
}
#login-wrapper2 {
    display: table-cell;
    vertical-align: middle;
}
#login-table {
    margin: 0 auto;
}
#login-table .label {
    text-align: right;
}

#waiting {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    opacity: 0.3;
}

       </style> 
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
        <script src="client.js"></script>
    </head>
    <body>
        <div id="login">
            <div class="svg">

                <svg
                    xmlns="http://www.w3.org/2000/svg"
                    xmlns:xlink="http://www.w3.org/1999/xlink"
                    viewBox="0 0 400 400"
                    width="400"
                    height="400">
                    <defs>
                        <path id="curved-text" d="M0,0 c 50 -50 150 -50 200 0" />
                    </defs>
                    <g>
                        <text
                            transform="translate(-100,40)"
                            font-weight="bold"
                            font-variant="small-caps"
                            font-family="Arial sans-serif"
                            font-size="30"
                            fill="none"
                            stroke="orange"
                            text-anchor="middle">
                            <textPath xlink:href="#curved-text" startOffset="50%">Chatroom</textPath>
                        </text>
                        <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="5s" fill="remove" additive="sum" repeatCount="indefinite" />
                        <animateMotion dur="10s" repeatCount="indefinite" path="M100,200 a100,100 0 1 1 200,0 a100,100 0 1 1 -200,0" />
                    </g>
                    <foreignObject
                        x="0"
                        y="0"
                        width="400"
                        height="400"
                        style="height:400px;">

                        <div xmlns="http://www.w3.org/1999/xhtml" id="login-wrapper1">
                            <div id="login-wrapper2">
                                <table id="login-table">
                                    <tbody>
                                        <tr>
                                            <td class="label">Vzdevek:</td><td><input type="text" id="nickname" /></td>
                                        </tr>
                                        <tr>
                                            <td class="label">Geslo:</td><td><input type="password" id="password" /></td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>

                    </foreignObject>
                </svg>

            </div>
        </div>

        <div id="chatroom" style="display:none;">
            <h1 id="heading">Chatroom</h1>

            <div id="outer">
                <div id="inner">
                    <div id="chat">
                        <div id="history">
                            <p><span class="nick">Matej: </span><span class="line">Hi</span></p>
                            <p><span class="nick">Borut: </span><span class="line">How are you?</span></p>
                            <p><span class="nick">Martina: </span><span class="line">Ok, thanks!</span></p>
                        </div>
                        <div id="input"><input id="line" type="text"></div>
                    </div>
                    <ul id="members">
                        <li>Matej</li>
                        <li>Borut</li>
                        <li>Martina</li>
                    </ul>
                </div>
            </div>
        </div>

        <div id="waiting" style="display:none;"></div>

    </body>
</html>
Share:
10,521
btmanikandan
Author by

btmanikandan

Updated on June 14, 2022

Comments

  • btmanikandan
    btmanikandan almost 2 years

    I am trying to build an iPhone(native) chat app that uses node.js on socket.io.

    What is the best way to create chat application on IOS

    Is there is any way to create chat application with the node.js server in IOS

    Could anyone give me suggestion?

    Thanks for you suggestion