Bi-directional example, which can only be asynchronous. Send some chat messages, and print any
chat messages that are sent from the server.
327503
public CountDownLatch routeChat() {
    info("*** RouteChat");
    final CountDownLatch finishLatch = new CountDownLatch(1);
    StreamObserver<RouteNote> requestObserver =
        asyncStub.routeChat(new StreamObserver<RouteNote>() {
          @Override
          public void onNext(RouteNote note) {
            info("Got message \"{0}\" at {1}, {2}", note.getMessage(), note.getLocation()
                .getLatitude(), note.getLocation().getLongitude());
            if (testHelper != null) {
              testHelper.onMessage(note);
            }
          }

          @Override
          public void onError(Throwable t) {
            warning("RouteChat Failed: {0}", Status.fromThrowable(t));
            if (testHelper != null) {
              testHelper.onRpcError(t);
            }
            finishLatch.countDown();
          }

          @Override
          public void onCompleted() {
            info("Finished RouteChat");
            finishLatch.countDown();
          }
        });

    try {
      RouteNote[] requests =
          {newNote("First message", 0, 0), newNote("Second message", 0, 1),
              newNote("Third message", 1, 0), newNote("Fourth message", 1, 1)};

      for (RouteNote request : requests) {
        info("Sending message \"{0}\" at {1}, {2}", request.getMessage(), request.getLocation()
            .getLatitude(), request.getLocation().getLongitude());
        requestObserver.onNext(request);
      }
    } catch (RuntimeException e) {
      // Cancel RPC
      requestObserver.onError(e);
      throw e;
    }
    // Mark the end of requests
    requestObserver.onCompleted();

    // return the latch while receiving happens asynchronously
    return finishLatch;
  }
949121
def send_persisted_messages(self, websocket):
        
        for channel in self._subscription.channels:
            message = self._connection.get(channel)
            if message:
                websocket.send(message)
300447
async def send_message(self, *args, **kwargs):
        
        message = await self._client.send_message(
            self._input_chat, *args, **kwargs)

        self._outgoing.add(message.id)
        self._last_outgoing = message.id
        return message
648290
def on_message(self, message):
        
        log.debug('Got websocket message %s', message)
        if message == 'websocket client ready':
            if self.connected:
                # TBD: Add ability to run commands in this branch
                log.debug('Websocket already connected, returning')
                return

            self.connected = True

            evt_processor = event_processor.SaltInfo(self)
            client = salt.netapi.NetapiClient(self.application.opts)
            client.run({
                'fun': 'grains.items',
                'tgt': '*',
                'token': self.token,
                'mode': 'client',
                'asynchronous': 'local_async',
                'client': 'local'
                })
            while True:
                try:
                    event = yield self.application.event_listener.get_event(self)
                    evt_processor.process(event, self.token, self.application.opts)
                    # self.write_message('data: {0}\n\n'.format(salt.utils.json.dumps(event, _json_module=_json)))
                except Exception as err:
                    log.debug('Error! Ending server side websocket connection. Reason = %s', err)
                    break

            self.close()
        else:
            # TBD: Add logic to run salt commands here
            pass
1114617
async def run(self):
        """"""

        # Once everything is ready, we can add an event handler.
        #
        # Events are an abstraction over Telegram's "Updates" and
        # are much easier to use.
        self.add_event_handler(self.message_handler, events.NewMessage)

        # Enter a while loop to chat as long as the user wants
        while True:
            # Retrieve the top dialogs. You can set the limit to None to
            # retrieve all of them if you wish, but beware that may take
            # a long time if you have hundreds of them.
            dialog_count = 15

            # Entities represent the user, chat or channel
            # corresponding to the dialog on the same index.
            dialogs = await self.get_dialogs(limit=dialog_count)

            i = None
            while i is None:
                print_title('Dialogs window')

                # Display them so the user can choose
                for i, dialog in enumerate(dialogs, start=1):
                    sprint('{}. {}'.format(i, get_display_name(dialog.entity)))

                # Let the user decide who they want to talk to
                print()
                print('> Who do you want to send messages to?')
                print('> Available commands:')
                print('  !q: Quits the dialogs window and exits.')
                print('  !l: Logs out, terminating this session.')
                print()
                i = await async_input('Enter dialog ID or a command: ')
                if i == '!q':
                    return
                if i == '!l':
                    # Logging out will cause the user to need to reenter the
                    # code next time they want to use the library, and will
                    # also delete the *.session file off the filesystem.
                    #
                    # This is not the same as simply calling .disconnect(),
                    # which simply shuts down everything gracefully.
                    await self.log_out()
                    return

                try:
                    i = int(i if i else 0) - 1
                    # Ensure it is inside the bounds, otherwise retry
                    if not 0 <= i < dialog_count:
                        i = None
                except ValueError:
                    i = None

            # Retrieve the selected user (or chat, or channel)
            entity = dialogs[i].entity

            # Show some information
            print_title('Chat with "{}"'.format(get_display_name(entity)))
            print('Available commands:')
            print('  !q:  Quits the current chat.')
            print('  !Q:  Quits the current chat and exits.')
            print('  !h:  prints the latest messages (message History).')
            print('  !up  <path>: Uploads and sends the Photo from path.')
            print('  !uf  <path>: Uploads and sends the File from path.')
            print('  !d   <msg-id>: Deletes a message by its id')
            print('  !dm  <msg-id>: Downloads the given message Media (if any).')
            print('  !dp: Downloads the current dialog Profile picture.')
            print('  !i:  Prints information about this chat..')
            print()

            # And start a while loop to chat
            while True:
                msg = await async_input('Enter a message: ')
                # Quit
                if msg == '!q':
                    break
                elif msg == '!Q':
                    return

                # History
                elif msg == '!h':
                    # First retrieve the messages and some information
                    messages = await self.get_messages(entity, limit=10)

                    # Iterate over all (in reverse order so the latest appear
                    # the last in the console) and print them with format:
                    # "[hh:mm] Sender: Message"
                    for msg in reversed(messages):
                        # Note how we access .sender here. Since we made an
                        # API call using the self client, it will always have
                        # information about the sender. This is different to
                        # events, where Telegram may not always send the user.
                        name = get_display_name(msg.sender)

                        # Format the message content
                        if getattr(msg, 'media', None):
                            self.found_media[msg.id] = msg
                            content = '<{}> {}'.format(
                                type(msg.media).__name__, msg.message)

                        elif hasattr(msg, 'message'):
                            content = msg.message
                        elif hasattr(msg, 'action'):
                            content = str(msg.action)
                        else:
                            # Unknown message, simply print its class name
                            content = type(msg).__name__

                        # And print it to the user
                        sprint('[{}:{}] (ID={}) {}: {}'.format(
                            msg.date.hour, msg.date.minute, msg.id, name, content))

                # Send photo
                elif msg.startswith('!up '):
                    # Slice the message to get the path
                    path = msg[len('!up '):]
                    await self.send_photo(path=path, entity=entity)

                # Send file (document)
                elif msg.startswith('!uf '):
                    # Slice the message to get the path
                    path = msg[len('!uf '):]
                    await self.send_document(path=path, entity=entity)

                # Delete messages
                elif msg.startswith('!d '):
                    # Slice the message to get message ID
                    msg = msg[len('!d '):]
                    deleted_msg = await self.delete_messages(entity, msg)
                    print('Deleted {}'.format(deleted_msg))

                # Download media
                elif msg.startswith('!dm '):
                    # Slice the message to get message ID
                    await self.download_media_by_id(msg[len('!dm '):])

                # Download profile photo
                elif msg == '!dp':
                    print('Downloading profile picture to usermedia/...')
                    os.makedirs('usermedia', exist_ok=True)
                    output = await self.download_profile_photo(entity,
                                                               'usermedia')
                    if output:
                        print('Profile picture downloaded to', output)
                    else:
                        print('No profile picture found for this user!')

                elif msg == '!i':
                    attributes = list(entity.to_dict().items())
                    pad = max(len(x) for x, _ in attributes)
                    for name, val in attributes:
                        print("{:<{width}} : {}".format(name, val, width=pad))

                # Send chat message (if any)
                elif msg:
                    await self.send_message(entity, msg, link_preview=False)
914616
def onBinaryMessage(self, msg, fromClient):
		data = bytearray()
		data.extend(msg)

		

		try:
			self.queue.put_nowait(data)
		except asyncio.QueueFull:
			pass
481619
function(msg) {
        if (onSendLogging)
          asyncLogger("Send", msg);

        switch (protocol) {
          case 'websocket':
            if (socketState === socketStateType.OPEN) {
              socket.emit(msg);
            } else {
              pushSendDataQueue.push(msg);
            }
            break;

          case 'queue':
            if (socketState === socketStateType.OPEN) {
              activemq.sendMessage({
                destination: params.queueSend,
                message: msg
              });
            } else {
              pushSendDataQueue.push(msg);
            }
            break;
        }
      }
844337
public Chat createChat(EntityJid userJID, String thread, ChatMessageListener listener) {
        if (thread == null) {
            thread = nextID();
        }
        Chat chat = threadChats.get(thread);
        if (chat != null) {
            throw new IllegalArgumentException("ThreadID is already used");
        }
        chat = createChat(userJID, thread, true);
        chat.addMessageListener(listener);
        return chat;
    }
1360875
async def on_message(message):
    

    # Simplify message info
    server = message.server
    author = message.author
    channel = message.channel
    content = message.content

    data = datatools.get_data()

    if not data["discord"]["servers"][server.id][_data.modulename]["activated"]:
        return

    # Only reply to server messages and don't reply to myself
    if server is not None and author != channel.server.me:
        # Commands section
        prefix = data["discord"]["servers"][server.id]["prefix"]
        if content.startswith(prefix):
            # Parse message
            package = content.split(" ")
            command = package[0][len(prefix):]
            args = package[1:]
            arg = ' '.join(args)

            # Commands
            if command == 'hex':
                await client.send_typing(channel)

                # Parse message
                hex_strs = api_hexconvert.convert_hex_value(arg)
                # Create embed UI
                if len(hex_strs) > 0:
                    for hex_str in hex_strs:
                        image_url = convert_hex_to_url(hex_str)
                        embed = ui_embed.success(channel, image_url, hex_str)
                        await embed.send()
                else:
                    embed = ui_embed.fail_api(channel)
                    await embed.send()
        else:
            # Parse message
            hex_strs = api_hexconvert.convert_hex_value(content)
            # Create embed UI
            if len(hex_strs) > 0:
                for hex_str in hex_strs:
                    await client.send_typing(channel)
                    image_url = convert_hex_to_url(hex_str)
                    embed = ui_embed.success(channel, image_url, hex_str)
                    await embed.send()
274912
async def on_message(message):
    

    # Simplify message info
    server = message.server
    author = message.author
    channel = message.channel
    content = message.content

    data = datatools.get_data()

    # Only reply to server messages and don't reply to myself
    if server is not None and author != channel.server.me:
        # Commands section
        prefix = data["discord"]["servers"][server.id]["prefix"]
        if content.startswith(prefix):
            # Parse message
            package = content.split(" ")
            command = package[0][len(prefix):]
            args = package[1:]
            arg = ' '.join(args)

            # Commands
            if command == 'help':
                if args:
                    # Parse message
                    datapacks = api_help.get_help_datapacks(arg, prefix)
                    # Create embed UI
                    if datapacks:
                        await client.send_typing(channel)
                        embed = ui_embed.success(channel, arg, datapacks)
                        try:
                            await embed.send()
                        except discord.errors.HTTPException:
                            embed = ui_embed.http_exception(channel, arg)
                            await embed.send()
                else:
                    # Parse message
                    datapacks = api_help.get_help_commands(prefix)
                    # Create embed UI
                    if datapacks:
                        await client.send_typing(channel)
                        embed = ui_embed.success(channel, arg, datapacks)
                        try:
                            await embed.send()
                        except discord.errors.HTTPException:
                            embed = ui_embed.http_exception(channel, arg)
                            await embed.send()
416783
def _receive(self):
        
        # preamble - not readall(1) to allow breaking before messages,
        # empty input
        preamble = self._read(1)
        if not preamble:
            return None
        elif ord(preamble) != SBP_PREAMBLE:
            if self._verbose:
                print("Host Side Unhandled byte: 0x%02x" % ord(preamble))
            return None
        # hdr
        hdr = self._readall(5)
        msg_crc = crc16(hdr)
        msg_type, sender, msg_len = struct.unpack("<HHB", hdr)
        # data
        data = self._readall(msg_len)
        msg_crc = crc16(data, msg_crc)
        # crc
        crc = self._readall(2)
        crc, = struct.unpack("<H", crc)
        if crc != msg_crc:
            if self._verbose:
                print("crc mismatch: 0x%04X 0x%04X" % (msg_crc, crc))
            return None
        msg = SBP(msg_type, sender, msg_len, data, crc)
        try:
            msg = self._dispatch(msg)
        except Exception as exc:
            warnings.warn("SBP dispatch error: %s" % (exc,))
        return msg
778229
def from_message(bot, message):
        
        chat = message["chat"]
        return Chat(bot, chat["id"], chat["type"], message)
1370428
def socket_send(
        sock,
        msg,
        debug=False):
    
    if IS_PY2:
        sock.send(msg)
    else:
        sock.send(msg.encode())
61928
function(params, callback) {
                var sendMessageParams = {
                        chatMessageVOType: chatMessageVOTypes.GET_HISTORY,
                        typeCode: params.typeCode,
                        content: {},
                        subjectId: params.threadId
                    },
                    whereClause = {},
                    offset = (parseInt(params.offset) > 0) ? parseInt(params.offset) : 0,
                    count = (parseInt(params.count) > 0) ? parseInt(params.count) : config.getHistoryCount,
                    order = (typeof params.order != 'undefined') ? (params.order).toLowerCase() : 'desc',
                    cacheResult = {},
                    serverResult = {},
                    cacheFirstMessage,
                    cacheLastMessage,
                    messages,
                    returnCache,
                    dynamicHistoryCount = (params.dynamicHistoryCount && typeof params.dynamicHistoryCount === 'boolean')
                        ? params.dynamicHistoryCount
                        : false,
                    sendingQueue = (params.queues && typeof params.queues.sending === 'boolean')
                        ? params.queues.sending
                        : true,
                    failedQueue = (params.queues && typeof params.queues.failed === 'boolean')
                        ? params.queues.failed
                        : true,
                    uploadingQueue = (params.queues && typeof params.queues.uploading === 'boolean')
                        ? params.queues.uploading
                        : true,
                    sendingQueueMessages = [],
                    failedQueueMessages = [],
                    uploadingQueueMessages = [];

                if (sendingQueue) {
                    getChatSendQueue(parseInt(params.threadId), function(sendQueueMessages) {
                        for (var i = 0; i < sendQueueMessages.length; i++) {
                            var decryptedEnqueuedMessage = Utility.jsonParser(chatDecrypt(sendQueueMessages[i].message, cacheSecret));
                            sendQueueMessages[i] = formatDataToMakeMessage(sendQueueMessages[i].threadId, {
                                uniqueId: decryptedEnqueuedMessage.uniqueId,
                                ownerId: userInfo.id,
                                message: decryptedEnqueuedMessage.content,
                                metadata: decryptedEnqueuedMessage.metadata,
                                systemMetadata: decryptedEnqueuedMessage.systemMetadata,
                                replyInfo: decryptedEnqueuedMessage.replyInfo,
                                forwardInfo: decryptedEnqueuedMessage.forwardInfo
                            });
                        }

                        sendingQueueMessages = sendQueueMessages;
                    });
                }

                if (uploadingQueue) {
                    getChatUploadQueue(parseInt(params.threadId), function(uploadQueueMessages) {
                        uploadingQueueMessages = uploadQueueMessages;
                    });
                }

                getChatWaitQueue(parseInt(params.threadId), failedQueue, function(waitQueueMessages) {
                    for (var i = 0; i < waitQueueMessages.length; i++) {
                        var decryptedEnqueuedMessage = Utility.jsonParser(chatDecrypt(waitQueueMessages[i].message, cacheSecret));
                        waitQueueMessages[i] = formatDataToMakeMessage(waitQueueMessages[i].threadId,
                            {
                                uniqueId: decryptedEnqueuedMessage.uniqueId,
                                ownerId: userInfo.id,
                                message: decryptedEnqueuedMessage.content,
                                metadata: decryptedEnqueuedMessage.metadata,
                                systemMetadata: decryptedEnqueuedMessage.systemMetadata,
                                replyInfo: decryptedEnqueuedMessage.replyInfo,
                                forwardInfo: decryptedEnqueuedMessage.forwardInfo
                            });
                    }

                    failedQueueMessages = waitQueueMessages;

                    if (dynamicHistoryCount) {
                        var tempCount = count - (sendingQueueMessages.length + failedQueueMessages.length + uploadingQueueMessages.length);
                        sendMessageParams.content.count = (tempCount > 0) ? tempCount : 0;
                    }
                    else {
                        sendMessageParams.content.count = count;
                    }

                    sendMessageParams.content.offset = offset;
                    sendMessageParams.content.order = order;

                    if (parseInt(params.id) > 0) {
                        sendMessageParams.content.id = whereClause.id = params.id;
                    }

                    if (Array.isArray(params.uniqueIds)) {
                        sendMessageParams.content.uniqueIds = params.uniqueIds;
                    }

                    if (parseInt(params.fromTimeFull) > 0 && params.fromTimeFull.toString().length == 19) {
                        sendMessageParams.content.fromTime = whereClause.fromTime = parseInt(params.fromTimeFull.toString()
                            .substring(0, 13));
                        sendMessageParams.content.fromTimeNanos = whereClause.fromTimeNanos = parseInt(params.fromTimeFull.toString()
                            .substring(10, 19));
                    }
                    else {
                        if (parseInt(params.fromTime) > 0 && arseInt(params.fromTime) < 9999999999999) {
                            sendMessageParams.content.fromTime = whereClause.fromTime = parseInt(params.fromTime);
                        }

                        if (parseInt(params.fromTimeNanos) > 0 && parseInt(params.fromTimeNanos) < 999999999) {
                            sendMessageParams.content.fromTimeNanos = whereClause.fromTimeNanos = parseInt(params.fromTimeNanos);
                        }
                    }

                    if (parseInt(params.toTimeFull) > 0 && params.toTimeFull.toString().length == 19) {
                        sendMessageParams.content.toTime = whereClause.toTime = parseInt(params.toTimeFull.toString()
                            .substring(0, 13));
                        sendMessageParams.content.toTimeNanos = whereClause.toTimeNanos = parseInt(params.toTimeFull.toString()
                            .substring(10, 19));
                    }
                    else {
                        if (parseInt(params.toTime) > 0 && parseInt(params.toTime) < 9999999999999) {
                            sendMessageParams.content.toTime = whereClause.toTime = parseInt(params.toTime);
                        }

                        if (parseInt(params.toTimeNanos) > 0 && parseInt(params.toTimeNanos) < 999999999) {
                            sendMessageParams.content.toTimeNanos = whereClause.toTimeNanos = parseInt(params.toTimeNanos);
                        }
                    }

                    if (typeof params.query != 'undefined') {
                        sendMessageParams.content.query = whereClause.query = params.query;
                    }

                    if (typeof params.metadataCriteria == 'object' && params.metadataCriteria.hasOwnProperty('field')) {
                        sendMessageParams.content.metadataCriteria = whereClause.metadataCriteria = params.metadataCriteria;
                    }

                    /**
                     * Get Thread Messages from cache
                     *
                     * Because we are not applying metadataCriteria search
                     * on cached data, if this attribute has been set, we
                     * should not return any results from cache
                     */
                    if (canUseCache && !whereClause.hasOwnProperty('metadataCriteria')) {
                        if (db) {
                            var table = db.messages,
                                collection;
                            returnCache = true;

                            if (whereClause.hasOwnProperty('id') && whereClause.id > 0) {
                                collection = table.where('id')
                                    .equals(params.id)
                                    .and(function(message) {
                                        return message.owner == userInfo.id;
                                    })
                                    .reverse();
                            }
                            else {
                                collection = table.where('[threadId+owner+time]')
                                    .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                        [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000])
                                    .reverse();
                            }

                            collection.toArray()
                                .then(function(resultMessages) {
                                    messages = resultMessages.sort(Utility.dynamicSort('time', !(order === 'asc')));

                                    if (whereClause.hasOwnProperty('fromTime')) {
                                        var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                            ? (Math.floor(whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                            : whereClause.fromTime * 1000000;
                                        messages = messages.filter(function(message) {
                                            return message.time >= fromTime;
                                        });
                                    }

                                    if (whereClause.hasOwnProperty('toTime')) {
                                        var toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                            ? ((Math.floor(whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                            : (whereClause.toTime + 1) * 1000000;
                                        messages = messages.filter(function(message) {
                                            return message.time <= toTime;
                                        });
                                    }

                                    if (whereClause.hasOwnProperty('query') && typeof whereClause.query == 'string') {
                                        messages = messages.filter(function(message) {
                                            var reg = new RegExp(whereClause.query);
                                            return reg.test(chatDecrypt(message.message, cacheSecret, message.salt));
                                        });
                                    }

                                    /**
                                     * We should check to see if message[offset-1] has
                                     * GAP on cache or not? if yes, we should not return
                                     * any value from cache, because there is a gap between
                                     */
                                    if (offset > 0) {
                                        if (typeof messages[offset - 1] == 'object' && messages[offset - 1].hasGap) {
                                            returnCache = false;
                                        }
                                    }

                                    if (returnCache) {
                                        messages = messages.slice(offset, offset + count);

                                        if (messages.length == 0) {
                                            returnCache = false;
                                        }

                                        cacheFirstMessage = messages[0];
                                        cacheLastMessage = messages[messages.length - 1];

                                        if (returnCache) {
                                            collection.count()
                                                .then(function(contentCount) {
                                                    var cacheData = [];

                                                    for (var i = 0; i < messages.length; i++) {
                                                        /**
                                                         * If any of messages between first and last message of cache response
                                                         * has a GAP before them, we shouldn't return cache's result and
                                                         * wait for server's response to hit in
                                                         */
                                                        if (i != 0 && i != messages.length - 1 && messages[i].hasGap) {
                                                            returnCache = false;
                                                            break;
                                                        }

                                                        try {
                                                            var tempData = {},
                                                                salt = messages[i].salt;

                                                            var tempMessage = formatDataToMakeMessage(messages[i].threadId, JSON.parse(chatDecrypt(messages[i].data, cacheSecret, messages[i].salt)));
                                                            cacheData.push(tempMessage);

                                                            cacheResult[tempMessage.id] = {
                                                                index: i,
                                                                messageId: tempMessage.id,
                                                                threadId: tempMessage.threadId,
                                                                data: Utility.MD5(JSON.stringify([
                                                                    tempMessage.id,
                                                                    tempMessage.message,
                                                                    tempMessage.edited,
                                                                    tempMessage.delivered,
                                                                    tempMessage.seen,
                                                                    tempMessage.metadata,
                                                                    tempMessage.systemMetadata]))
                                                            };
                                                        }
                                                        catch (error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        }
                                                    }

                                                    /**
                                                     * If there is a GAP between messages of cache result
                                                     * WE should not return data from cache, cause it is not valid!
                                                     * Therefore we wait for server's response and edit cache afterwards
                                                     */
                                                    if (returnCache) {
                                                        var returnData = {
                                                            hasError: false,
                                                            cache: true,
                                                            errorCode: 0,
                                                            errorMessage: '',
                                                            result: {
                                                                history: cacheData,
                                                                contentCount: contentCount,
                                                                hasNext: (offset + count < contentCount && messages.length > 0),
                                                                nextOffset: offset + messages.length
                                                            }
                                                        };

                                                        if (sendingQueue) {
                                                            returnData.result.sending = sendingQueueMessages;
                                                        }
                                                        if (uploadingQueue) {
                                                            returnData.result.uploading = uploadingQueueMessages;
                                                        }
                                                        if (failedQueue) {
                                                            returnData.result.failed = failedQueueMessages;
                                                        }

                                                        callback && callback(returnData);
                                                        callback = undefined;
                                                    }
                                                })
                                                .catch(function(error) {
                                                    fireEvent('error', {
                                                        code: error.code,
                                                        message: error.message,
                                                        error: error
                                                    });
                                                });
                                        }
                                    }
                                })
                                .catch(function(error) {
                                    fireEvent('error', {
                                        code: error.code,
                                        message: error.message,
                                        error: error
                                    });
                                });
                        }
                        else {
                            fireEvent('error', {
                                code: 6601,
                                message: CHAT_ERRORS[6601],
                                error: null
                            });
                        }
                    }

                    /**
                     * Get Thread Messages From Server
                     */
                    return sendMessage(sendMessageParams, {
                        onResult: function(result) {
                            var returnData = {
                                    hasError: result.hasError,
                                    cache: false,
                                    errorMessage: result.errorMessage,
                                    errorCode: result.errorCode
                                },
                                resultMessagesId = [];

                            if (!returnData.hasError) {
                                var messageContent = result.result,
                                    messageLength = messageContent.length;

                                var history = reformatThreadHistory(params.threadId, messageContent);

                                if (messageLength > 0) {
                                    /**
                                     * Calculating First and Last Messages of result
                                     */
                                    var lastMessage = history[messageContent.length - 1],
                                        firstMessage = history[0];

                                    /**
                                     * Sending Delivery for Last Message of Thread
                                     */
                                    if (lastMessage.id > 0) {
                                        deliver({
                                            messageId: lastMessage.id,
                                            ownerId: lastMessage.participant.id
                                        });
                                    }
                                }

                                /**
                                 * Add Thread Messages into cache database
                                 * and remove deleted messages from cache database
                                 */
                                if (canUseCache) {
                                    if (db) {

                                        /**
                                         * Cache Synchronization
                                         *
                                         * If there are some results in cache
                                         * Database, we have to check if they need
                                         * to be deleted or not?
                                         *
                                         * To do so, first of all we should make
                                         * sure that metadataCriteria has not been
                                         * set, cuz we are not applying it on the
                                         * cache results, besides the results from
                                         * cache should not be empty, otherwise
                                         * there is no need to sync cache
                                         */
                                        if (Object.keys(cacheResult).length > 0 && !whereClause.hasOwnProperty('metadataCriteria')) {

                                            /**
                                             * Check if a condition has been
                                             * applied on query or not, if there is
                                             * none, the only limitations on
                                             * results are count and offset
                                             *
                                             * whereClause == []
                                             */
                                            if (!whereClause || Object.keys(whereClause).length == 0) {

                                                /**
                                                 * There is no condition applied on
                                                 * query and result is [], so there
                                                 * are no messages in this thread
                                                 * after this offset, and we should
                                                 * delete those messages from cache
                                                 * too
                                                 *
                                                 * result   []
                                                 */
                                                if (messageLength == 0) {

                                                    /**
                                                     * Order is ASC, so if the server result is empty we
                                                     * should delete everything from cache which has bigger
                                                     * time than first item of cache results for this query
                                                     */
                                                    if (order == 'asc') {
                                                        var finalMessageTime = cacheFirstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], true, false)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }

                                                    /**
                                                     * Order is DESC, so if the
                                                     * server result is empty we
                                                     * should delete everything
                                                     * from cache which has smaller
                                                     * time than first item of
                                                     * cache results for this query
                                                     */
                                                    else {
                                                        var finalMessageTime = cacheFirstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, true)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }
                                                }

                                                /**
                                                 * Result is not Empty or doesn't
                                                 * have just one single record, so
                                                 * we should remove everything
                                                 * which are between firstMessage
                                                 * and lastMessage of this result
                                                 * from cache database and insert
                                                 * the new result into cache, so
                                                 * the deleted ones would be
                                                 * deleted
                                                 *
                                                 * result   [..., n-1, n, n+1, ...]
                                                 */
                                                else {

                                                    /**
                                                     * We should check for last message's previouseId if it
                                                     * is undefined, so it is the first message of thread and
                                                     * we should delete everything before it from cache
                                                     */
                                                    if (firstMessage.previousId == undefined || lastMessage.previousId == undefined) {
                                                        var finalMessageTime = (lastMessage.previousId == undefined)
                                                            ? lastMessage.time
                                                            : firstMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, false)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }

                                                    /**
                                                     * Offset has been set as 0 so this result is either the
                                                     * very beginning part of thread or the very last
                                                     * Depending on the sort order
                                                     *
                                                     * offset == 0
                                                     */
                                                    if (offset == 0) {

                                                        /**
                                                         * Results are sorted ASC, and the offset is 0 so
                                                         * the first Message of this result is first
                                                         * Message of thread, everything in cache
                                                         * database which has smaller time than this
                                                         * one should be removed
                                                         *
                                                         * order    ASC
                                                         * result   [0, 1, 2, ...]
                                                         */
                                                        if (order === 'asc') {
                                                            var finalMessageTime = firstMessage.time;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), 0],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime], true, false)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * Results are sorted DESC and the offset is 0 so
                                                         * the last Message of this result is the last
                                                         * Message of the thread, everything in cache
                                                         * database which has bigger time than this
                                                         * one should be removed from cache
                                                         *
                                                         * order    DESC
                                                         * result   [..., n-2, n-1, n]
                                                         */
                                                        else {
                                                            var finalMessageTime = firstMessage.time;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), finalMessageTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], false, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }
                                                    }

                                                    /**
                                                     * Server result is not Empty, so we should remove
                                                     * everything which are between firstMessage and lastMessage
                                                     * of this result from cache database and insert the new
                                                     * result into cache, so the deleted ones would be deleted
                                                     *
                                                     * result   [..., n-1, n, n+1, ...]
                                                     */
                                                    var boundryStartMessageTime = (firstMessage.time < lastMessage.time)
                                                            ? firstMessage.time
                                                            : lastMessage.time,
                                                        boundryEndMessageTime = (firstMessage.time > lastMessage.time)
                                                            ? firstMessage.time
                                                            : lastMessage.time;

                                                    db.messages.where('[threadId+owner+time]')
                                                        .between([parseInt(params.threadId), parseInt(userInfo.id), boundryStartMessageTime],
                                                            [parseInt(params.threadId), parseInt(userInfo.id), boundryEndMessageTime], true, true)
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }
                                            }

                                            /**
                                             * whereClasue is not empty and we
                                             * should check for every single one of
                                             * the conditions to update the cache
                                             * properly
                                             *
                                             * whereClause != []
                                             */
                                            else {

                                                /**
                                                 * When user ordered a message with
                                                 * exact ID and server returns []
                                                 * but there is something in cache
                                                 * database, we should delete that
                                                 * row from cache, because it has
                                                 * been deleted
                                                 */
                                                if (whereClause.hasOwnProperty('id') && whereClause.id > 0) {
                                                    db.messages.where('id')
                                                        .equals(whereClause.id)
                                                        .and(function(message) {
                                                            return message.owner == userInfo.id;
                                                        })
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * When user sets a query to search
                                                 * on messages we should delete all
                                                 * the results came from cache and
                                                 * insert new results instead,
                                                 * because those messages would be
                                                 * either removed or updated
                                                 */
                                                if (whereClause.hasOwnProperty('query') && typeof whereClause.query == 'string') {
                                                    db.messages.where('[threadId+owner+time]')
                                                        .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                                            [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000])
                                                        .and(function(message) {
                                                            var reg = new RegExp(whereClause.query);
                                                            return reg.test(chatDecrypt(message.message, cacheSecret, message.salt));
                                                        })
                                                        .delete()
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * Users sets fromTime or toTime or
                                                 * both of them
                                                 */
                                                if (whereClause.hasOwnProperty('fromTime') || whereClause.hasOwnProperty('toTime')) {

                                                    /**
                                                     * Server response is Empty []
                                                     */
                                                    if (messageLength == 0) {

                                                        /**
                                                         * User set both fromTime and toTime, so we have a
                                                         * boundary restriction in this case. if server
                                                         * result is empty, we should delete all messages from cache
                                                         * which are between fromTime and toTime. if
                                                         * there are any messages on server in this
                                                         * boundary, we should delete all messages
                                                         * which are between time of first and last
                                                         * message of the server result, from cache and
                                                         * insert new result into cache.
                                                         */
                                                        if (whereClause.hasOwnProperty('fromTime') && whereClause.hasOwnProperty('toTime')) {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                                                    ? ((whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                                                    : whereClause.fromTime * 1000000,
                                                                toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                                                    ? (((whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                                                    : (whereClause.toTime + 1) * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), fromTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), toTime], true, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * User only set fromTime
                                                         */
                                                        else if (whereClause.hasOwnProperty('fromTime')) {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var fromTime = (whereClause.hasOwnProperty('fromTimeNanos'))
                                                                ? ((whereClause.fromTime / 1000) * 1000000000) + whereClause.fromTimeNanos
                                                                : whereClause.fromTime * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), fromTime],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), maxIntegerValue * 1000], true, false)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }

                                                        /**
                                                         * User only set toTime
                                                         */
                                                        else {

                                                            /**
                                                             * Server response is Empty []
                                                             */
                                                            var toTime = (whereClause.hasOwnProperty('toTimeNanos'))
                                                                ? (((whereClause.toTime / 1000) + 1) * 1000000000) + whereClause.toTimeNanos
                                                                : (whereClause.toTime + 1) * 1000000;

                                                            db.messages.where('[threadId+owner+time]')
                                                                .between([parseInt(params.threadId), parseInt(userInfo.id), minIntegerValue],
                                                                    [parseInt(params.threadId), parseInt(userInfo.id), toTime], true, true)
                                                                .delete()
                                                                .catch(function(error) {
                                                                    fireEvent('error', {
                                                                        code: error.code,
                                                                        message: error.message,
                                                                        error: error
                                                                    });
                                                                });
                                                        }
                                                    }

                                                    /**
                                                     * Server response is not Empty
                                                     * [..., n-1, n, n+1, ...]
                                                     */
                                                    else {

                                                        /**
                                                         * Server response is not Empty
                                                         * [..., n-1, n, n+1, ...]
                                                         */
                                                        var boundryStartMessageTime = (firstMessage.time < lastMessage.time)
                                                                ? firstMessage.time
                                                                : lastMessage.time,
                                                            boundryEndMessageTime = (firstMessage.time > lastMessage.time)
                                                                ? firstMessage.time
                                                                : lastMessage.time;

                                                        db.messages.where('[threadId+owner+time]')
                                                            .between([parseInt(params.threadId), parseInt(userInfo.id), boundryStartMessageTime],
                                                                [parseInt(params.threadId), parseInt(userInfo.id), boundryEndMessageTime], true, true)
                                                            .delete()
                                                            .catch(function(error) {
                                                                fireEvent('error', {
                                                                    code: error.code,
                                                                    message: error.message,
                                                                    error: error
                                                                });
                                                            });
                                                    }
                                                }
                                            }
                                        }

                                        /**
                                         * Insert new messages into cache database
                                         * after deleting old messages from cache
                                         */
                                        var cacheData = [];

                                        for (var i = 0; i < history.length; i++) {
                                            serverResult[history[i].id] = {
                                                index: i,
                                                data: Utility.MD5(JSON.stringify([
                                                    history[i].id,
                                                    history[i].message,
                                                    history[i].edited,
                                                    history[i].delivered,
                                                    history[i].seen,
                                                    history[i].metadata,
                                                    history[i].systemMetadata]))
                                            };
                                            try {
                                                var tempData = {},
                                                    salt = Utility.generateUUID();
                                                tempData.id = parseInt(history[i].id);
                                                tempData.owner = parseInt(userInfo.id);
                                                tempData.threadId = parseInt(history[i].threadId);
                                                tempData.time = history[i].time;
                                                tempData.message = Utility.crypt(history[i].message, cacheSecret, salt);
                                                tempData.data = Utility.crypt(JSON.stringify(unsetNotSeenDuration(history[i])), cacheSecret, salt);
                                                tempData.salt = salt;
                                                tempData.sendStatus = 'sent';
                                                tempData.hasGap = false;

                                                cacheData.push(tempData);
                                                resultMessagesId.push(history[i].id);
                                            }
                                            catch (error) {
                                                fireEvent('error', {
                                                    code: error.code,
                                                    message: error.message,
                                                    error: error
                                                });
                                            }
                                        }

                                        db.messages.bulkPut(cacheData)
                                            .then(function() {
                                                if (lastMessage.id > 0 && lastMessage.previousId > 0) {
                                                    /**
                                                     * Check to see if there is a Gap in cache before
                                                     * lastMessage or not?
                                                     * To do this, we should check existence of message
                                                     * with the ID of lastMessage's previousId field
                                                     */
                                                    db.messages
                                                        .where('[owner+id]')
                                                        .between([userInfo.id, lastMessage.previousId], [userInfo.id, lastMessage.previousId], true, true)
                                                        .toArray()
                                                        .then(function(messages) {
                                                            if (messages.length == 0) {
                                                                /**
                                                                 * Previous Message of last message is not in cache database
                                                                 * so there is a GAP in cache database for this thread before
                                                                 * the last message.
                                                                 * We should insert this GAP in messageGaps database
                                                                 */
                                                                db.messageGaps
                                                                    .put({
                                                                        id: parseInt(lastMessage.id),
                                                                        owner: parseInt(userInfo.id),
                                                                        waitsFor: parseInt(lastMessage.previousId),
                                                                        threadId: parseInt(lastMessage.threadId),
                                                                        time: lastMessage.time
                                                                    })
                                                                    .then(function() {
                                                                        db.messages
                                                                            .update([userInfo.id, lastMessage.id], {hasGap: true})
                                                                            .catch(function(error) {
                                                                                fireEvent('error', {
                                                                                    code: error.code,
                                                                                    message: error.message,
                                                                                    error: error
                                                                                });
                                                                            });
                                                                    })
                                                                    .catch(function(error) {
                                                                        fireEvent('error', {
                                                                            code: error.code,
                                                                            message: error.message,
                                                                            error: error
                                                                        });
                                                                    });
                                                            }
                                                        })
                                                        .catch(function(error) {
                                                            fireEvent('error', {
                                                                code: error.code,
                                                                message: error.message,
                                                                error: error
                                                            });
                                                        });
                                                }

                                                /**
                                                 * Some new messages have been added into cache,
                                                 * We should check to see if any GAPs have been
                                                 * filled with these messages or not?
                                                 */
                                                db.messageGaps
                                                    .where('waitsFor')
                                                    .anyOf(resultMessagesId)
                                                    .and(function(messages) {
                                                        return messages.owner == userInfo.id;
                                                    })
                                                    .delete()
                                                    .catch(function(error) {
                                                        fireEvent('error', {
                                                            code: error.code,
                                                            message: error.message,
                                                            error: error
                                                        });
                                                    });
                                            })
                                            .catch(function(error) {
                                                fireEvent('error', {
                                                    code: error.code,
                                                    message: error.message,
                                                    error: error
                                                });
                                            });
                                    }
                                    else {
                                        fireEvent('error', {
                                            code: 6601,
                                            message: CHAT_ERRORS[6601],
                                            error: null
                                        });
                                    }
                                }

                                var resultData = {
                                    history: history,
                                    contentCount: result.contentCount,
                                    hasNext: (sendMessageParams.content.offset + sendMessageParams.content.count < result.contentCount && messageLength > 0),
                                    nextOffset: sendMessageParams.content.offset + messageLength
                                };

                                returnData.result = resultData;

                                if (sendingQueue) {
                                    returnData.result.sending = sendingQueueMessages;
                                }
                                if (uploadingQueue) {
                                    returnData.result.uploading = uploadingQueueMessages;
                                }
                                if (failedQueue) {
                                    returnData.result.failed = failedQueueMessages;
                                }

                                /**
                                 * Check Differences between Cache and Server response
                                 */
                                if (returnCache) {
                                    /**
                                     * If there are some messages in cache but they
                                     * are not in server's response, we can assume
                                     * that they have been removed from server, so
                                     * we should call MESSAGE_DELETE event for them
                                     */
                                    for (var key in cacheResult) {
                                        if (!serverResult.hasOwnProperty(key)) {
                                            fireEvent('messageEvents', {
                                                type: 'MESSAGE_DELETE',
                                                result: {
                                                    message: {
                                                        id: cacheResult[key].messageId,
                                                        threadId: cacheResult[key].threadId
                                                    }
                                                }
                                            });
                                        }
                                    }

                                    for (var key in serverResult) {
                                        if (cacheResult.hasOwnProperty(key)) {
                                            /**
                                             * Check digest of cache and server response, if
                                             * they are not the same, we should emit
                                             */
                                            if (cacheResult[key].data != serverResult[key].data) {

                                                /**
                                                 * This message is already on cache, but it's
                                                 * content has been changed, so we emit a
                                                 * message edit event to inform client
                                                 */
                                                fireEvent('messageEvents', {
                                                    type: 'MESSAGE_EDIT',
                                                    result: {
                                                        message: history[serverResult[key].index]
                                                    }
                                                });
                                            }
                                        }
                                        else {
                                            /**
                                             * This Message has not found on cache but it has
                                             * came from server, so we emit it as a new message
                                             */
                                            fireEvent('messageEvents', {
                                                type: 'MESSAGE_NEW',
                                                result: {
                                                    message: history[serverResult[key].index]
                                                }
                                            });
                                        }
                                    }
                                }
                                else {
                                    callback && callback(returnData);
                                    callback = undefined;
                                }
                            }
                        }
                    });
                });
            }
629342
def sendMessage(self, message, thread_id=None, thread_type=ThreadType.USER):
        
        return self.send(
            Message(text=message), thread_id=thread_id, thread_type=thread_type
        )
145160
def on_message(self, handler, msg):
        
        if self.remote_debugging:
            #: Forward to other clients
            for h in self.handlers:
                if h != handler:
                    h.write_message(msg, True)
        else:
            print(msg)
865495
function(params, callbacks, recursiveCallback) {
                /**
                 * + ChatMessage        {object}
                 *    - token           {string}
                 *    - tokenIssuer     {string}
                 *    - type            {int}
                 *    - typeCode        {string}
                 *    - messageType     {int}
                 *    - subjectId       {long}
                 *    - uniqueId        {string}
                 *    - content         {string}
                 *    - time            {long}
                 *    - medadata        {string}
                 *    - systemMedadata  {string}
                 *    - repliedTo       {long}
                 */

                var asyncPriority = (params.asyncPriority > 0)
                    ? params.asyncPriority
                    : msgPriority;

                var messageVO = {
                    type: params.chatMessageVOType,
                    token: token,
                    tokenIssuer: 1
                };

                var threadId = params.subjectId;

                if (params.typeCode) {
                    messageVO.typeCode = params.typeCode;
                }
                else if (generalTypeCode) {
                    messageVO.typeCode = generalTypeCode;
                }

                if (params.messageType) {
                    messageVO.messageType = params.messageType;
                }

                if (params.subjectId) {
                    messageVO.subjectId = params.subjectId;
                }

                if (params.content) {
                    if (typeof params.content == 'object') {
                        messageVO.content = JSON.stringify(params.content);
                    }
                    else {
                        messageVO.content = params.content;
                    }
                }

                if (params.metadata) {
                    messageVO.metadata = params.metadata;
                }

                if (params.systemMetadata) {
                    messageVO.systemMetadata = params.systemMetadata;
                }

                if (params.repliedTo) {
                    messageVO.repliedTo = params.repliedTo;
                }

                var uniqueId;

                if (typeof params.uniqueId != 'undefined') {
                    uniqueId = params.uniqueId;
                }
                else if (params.chatMessageVOType !== chatMessageVOTypes.PING) {
                    uniqueId = Utility.generateUUID();
                }

                if (Array.isArray(uniqueId)) {
                    messageVO.uniqueId = JSON.stringify(uniqueId);
                }
                else {
                    messageVO.uniqueId = uniqueId;
                }

                if (typeof callbacks == 'object') {
                    if (callbacks.onSeen || callbacks.onDeliver || callbacks.onSent) {
                        if (!threadCallbacks[threadId]) {
                            threadCallbacks[threadId] = {};
                        }

                        threadCallbacks[threadId][uniqueId] = {};

                        sendMessageCallbacks[uniqueId] = {};

                        if (callbacks.onSent) {
                            sendMessageCallbacks[uniqueId].onSent = callbacks.onSent;
                            threadCallbacks[threadId][uniqueId].onSent = false;
                            threadCallbacks[threadId][uniqueId].uniqueId = uniqueId;
                        }

                        if (callbacks.onSeen) {
                            sendMessageCallbacks[uniqueId].onSeen = callbacks.onSeen;
                            threadCallbacks[threadId][uniqueId].onSeen = false;
                        }

                        if (callbacks.onDeliver) {
                            sendMessageCallbacks[uniqueId].onDeliver = callbacks.onDeliver;
                            threadCallbacks[threadId][uniqueId].onDeliver = false;
                        }

                    }
                    else if (callbacks.onResult) {
                        messagesCallbacks[uniqueId] = callbacks.onResult;
                    }
                }
                else if (typeof callbacks == 'function') {
                    messagesCallbacks[uniqueId] = callbacks;
                }

                /**
                 * Message to send through async SDK
                 *
                 * + MessageWrapperVO  {object}
                 *    - type           {int}       Type of ASYNC message based on content
                 *    + content        {string}
                 *       -peerName     {string}    Name of receiver Peer
                 *       -receivers[]  {long}      Array of receiver peer ids (if you use this, peerName will be ignored)
                 *       -priority     {int}       Priority of message 1-10, lower has more priority
                 *       -messageId    {long}      Id of message on your side, not required
                 *       -ttl          {long}      Time to live for message in milliseconds
                 *       -content      {string}    Chat Message goes here after stringifying
                 *    - trackId        {long}      Tracker id of message that you receive from DIRANA previously (if you are replying a sync message)
                 */

                var data = {
                    type: (parseInt(params.pushMsgType) > 0)
                        ? params.pushMsgType
                        : 3,
                    content: {
                        peerName: serverName,
                        priority: asyncPriority,
                        content: JSON.stringify(messageVO),
                        ttl: (params.messageTtl > 0)
                            ? params.messageTtl
                            : messageTtl
                    }
                };

                asyncClient.send(data, function(res) {
                    if (res.hasError && callbacks) {
                        if (typeof callbacks == 'function') {
                            callbacks(res);
                        }
                        else if (typeof callbacks == 'object' && typeof callbacks.onResult == 'function') {
                            callbacks.onResult(res);
                        }

                        if (messagesCallbacks[uniqueId]) {
                            delete messagesCallbacks[uniqueId];
                        }
                    }
                });

                sendPingTimeout && clearTimeout(sendPingTimeout);
                sendPingTimeout = setTimeout(function() {
                    ping();
                }, chatPingMessageInterval);

                recursiveCallback && recursiveCallback();

                return {
                    uniqueId: uniqueId,
                    threadId: threadId,
                    participant: userInfo,
                    content: params.content
                };
            }