3

I have implemented chat in Ionic3 using pubnub. Its working fine for a group chat.the channel used for group chat is "group1-ch". I have added my code here. I am facing some difficulties in developing a one to one chat.

PubnubService

import {Injectable, EventEmitter} from '@angular/core';
declare var PUBNUB;
type OnMessageFn = (message, envelope, channelOrGroup, time, channel) => void;

export enum PubNubEventType {
    MESSAGE,
    CONNECT,
    DISCONNECT,
    RECONNECT,
    PUBLISHED,
    HISTORY,
    PRESENCE
}

export class PubNubEvent {
    constructor(public type: PubNubEventType, channel:string, public value: any) {}
}

@Injectable()
export class PubNubService {

    pubnub:any;

    /**
     * Call this method after platform becomes to be ready
     */
    // init() {
    constructor() {

    }
    connectionuuid(uuid){
     this.pubnub = PUBNUB({

            subscribe_key: '*********************************',
            publish_key:   '*********************************',
            uuid:uuid,
            ssl: true,
            secret_key: '**************************************'

        });
    }

    subscribe(channel:string):EventEmitter<PubNubEvent> {
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.subscribe({
            channel : channel,
            withPresence: true,
            presence : (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.PRESENCE, channel, message));
            },
            message : (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.MESSAGE, channel, message));
            },
            connect: (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.CONNECT, channel, message));
            },
            disconnect: (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.DISCONNECT, channel, message));
            },
            reconnect: (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.RECONNECT, channel, message));
            },
            error: (error) => {
                eventEmitter.error(error);
            }, 
        });
        return eventEmitter;
    }

    publish(channel:string, message:any, store_in_history:boolean = true):EventEmitter<PubNubEvent> {
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.publish({
            channel: channel, 
            message: message, 
            store_in_history: store_in_history, 
            callback : (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.PUBLISHED, channel, message));
            },
            // Executes on a publish error.
            error: (error) => {
                eventEmitter.error(error);
            }
        });
        return eventEmitter;
    }

    individual_chat(channel:string, message:any, store_in_history:boolean = true):EventEmitter<PubNubEvent> {
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.publish({
            channel: channel,        
            message: message, 
            store_in_history: store_in_history, 
            callback : (message) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.PUBLISHED, channel, message));
            },
            // Executes on a publish error.
            error: (error) => {
                eventEmitter.error(error);
            }
        });
        return eventEmitter;
    }

    history(channel: string, count:number = 100, start:number = null, end:number = null, reverse:boolean = true, include_token: boolean = true):EventEmitter<PubNubEvent> {
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.history({
            channel: channel,
            callback: (messages) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.HISTORY, channel, messages));
            },
            error: (error) => {
                eventEmitter.error(error);
            },
            count: count,
            start: start,
            end: end,
            reverse: reverse,
            include_token: include_token
        });
        return eventEmitter;
    }

    here_now(channel: string, count:number = 100, start:number = null, end:number = null, reverse:boolean = true, include_token: boolean = true):EventEmitter<PubNubEvent>{
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.here_now({
        channel: channel,
        callback: (m) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.PRESENCE, channel, m));
            },
            error: (error) => {
                eventEmitter.error(error);
            },
            count: count,
            start: start,
            end: end,
            reverse: reverse,
            include_token: include_token
       });
        return eventEmitter;
    }
    where_now(channel: string, count:number = 100, start:number = null, end:number = null, reverse:boolean = true, include_token: boolean = true):EventEmitter<PubNubEvent>{
        let eventEmitter:EventEmitter<PubNubEvent> = new EventEmitter<PubNubEvent>();
        this.pubnub.where_now({
        uuid: channel,
        callback: (m) => {
                eventEmitter.emit(new PubNubEvent(PubNubEventType.PRESENCE, channel, m));
            },
            error: (error) => {
                eventEmitter.error(error);
            },
            count: count,
            start: start,
            end: end,
            reverse: reverse,
            include_token: include_token
       });
        return eventEmitter;
    }
}

My Requirement

  1. Could anyone please tell me how to create "channel" for one to one chat?
  2. How the receiver knows which channel the sender is using?

Thanks and Regards

Anand Raj

Arj 1411
  • 1,395
  • 3
  • 14
  • 36
  • any help on this scenario? – Arj 1411 Jan 04 '18 at 11:46
  • This is a matter of design patterns with respect to initiating a chat between two users. Start with [Chat Fundamentals](https://www.pubnub.com/docs/web-javascript/chat-fundamentals) and also review other [Design Patterns](https://www.pubnub.com/docs/web-javascript/best-practices-playbook) for more robust app requirements. Also consider [PubNub ChatEngine](https://www.pubnub.com/docs/chat-engine/getting-started) although it does not currently have an Ionic implementation, but there are other framework options. – Craig Conover Jan 04 '18 at 21:05
  • There is an Angular example though: https://github.com/pubnub/chat-engine#angular – Craig Conover Jan 04 '18 at 21:09
  • @CraigConover Hi Craig, thanks for your reply. Suppose I have("Anand") a list of 5 users(A,B,C,D,E) and I want to chat with each users individually. So there must me 5 different channels for that, right? So How the chnnel can be named? If I named channel AnandA for the user A then how the user knows that I am chatting with A through the channel "AnandA"? – Arj 1411 Jan 05 '18 at 05:04

1 Answers1

2

High Level Chat Invite Design Pattern

Let me use more specific names: Anand, Craig, John. Each user should subscribe to an inbound channel which they receive notification about invites:

  • Anand subscribes to inbound.anand
  • Craig subscribes to inbound.craig
  • John subscribes to inbound.john

Now you can always know which channel to send (publish) an invitation to another inbound channel if you know the username you want to contact. You can send a message to invite them to chat and provide the channel as a separate value:

{
    "message": "Hi, this is Anand. I would like to invite you to chat with me.",
    "chat_channel": "abc123",
    "sender_id": "anand"
}

This is just a simple sample message and can be more complex but the point is, you want to send a message to the person you want to invite and provide a channel name (it can be a randomly generated string or something like andand_craig, as long as it is a unique channel name for Anand and Craig using unique usernames).

Your user interface would provide a way for the invited user to click either Accept or Reject buttons to respond to the invite.

  • If Accept is clicked, then the invited user would publish a message back to inbox.anand or to the chat_channel that was provided, which anand would already be subscribed to, and then subscribe to the provided chat_channel, too, to begin chatting with anand.

This is fairly simplified design pattern but should provide some insights into how you can initiate conversations between two people or even a group of people.

For more details on recommended design patterns:

You can also look into using PubNub's ChatEngine framework which has builtin chat features. For Angular, see Simple Angular ChatEngine example.

Community
  • 1
  • 1
Craig Conover
  • 4,710
  • 34
  • 59
  • I have followed your steps. But got stuck at the place of creating dynamic channel. – Arj 1411 Jan 10 '18 at 05:13
  • @Craid, could you please share an example that creates and accept chat requests using dynamic channel? – Arj 1411 Jan 10 '18 at 05:16
  • Creating a dynamic channel just means that your app will come up with a way to name new channels. For example, you could use a UUID generator (PubNub has one in its API). Or you could just use the current user name concatenated with the target username, but be sure this results in a unique channel name, which it should if your usernames are unique. So it is really up to you. Whatever that channel name is that you created, just publish that channel name in your "invitation" message on the target user's inbound channel. – Craig Conover Jan 11 '18 at 05:28
  • 1
    According you your example, take the same users. If Anand wants to chat with Craig created a channel named 'outbound-AnandCraig'. Send the invite to Craig through the channel 'outbound-AnandCraig'. My doubt is in order to receive the chat request receiver should also subscribe for ' 'outbound-AnandCraig' ', right? Second doubt is Is there any parameter in publish/ subscribe API through which we can Identify whether the request is comes for the first time or not? – Arj 1411 Jan 11 '18 at 11:30
  • Close, but no. Send the invite to Craig with the `outbound.anand_craig` (put a delimiter in between the names, you'll thank me later) on `inbox.craig` because Craig is not yet subscribed to the new outbound channel. And outbound is the wrong prefix, I'd call it prchat (for private chat) or something like that because it is a two way channel. And there is no API about what kind of message it is. Each message is just a message to PubNub. You can create custom properties in the JSON message just like `"senderid"::anand"`. Make sense? – Craig Conover Jan 12 '18 at 21:23
  • Anand - did that answer you question sufficiently? If so, please mark this as answered. If not, please let me know what your further doubts are. – Craig Conover Jan 25 '18 at 16:01