从 PubNub 获取未读消息并呈现通知

Posted

技术标签:

【中文标题】从 PubNub 获取未读消息并呈现通知【英文标题】:Fetch unread messages from PubNub and render notifications 【发布时间】:2021-12-07 19:15:20 【问题描述】:

我正在尝试从 PubNub 获取未读消息。流程是这样的:

    设置授权 获取频道元数据 获取未读消息等...

我没有运气按顺序运行这些功能。那一个是在前一个完成之后执行的。

async function setGrant()
     await pubnub.grant(
        
            channels: [userId.toString() + '.*'],
            ttl: 55,
            read: true,
            write: true,
            update: true,
            get: true,
        ,(status) => 
         return new Promise(function (resolve) 
             resolve(status)
     );
    );


 async function getMetadata() 
     await pubnub.objects.getAllChannelMetadata(
        
            include: 
                customFields: true
            
        ).then((res: any) => 
        return new Promise(function (resolve) 
            resolve(setChannelMetadata(res.data));
        );
    );



 async function getUnreadedMessages() 
     await pubnub.messageCounts(
        channels: channels,
        channelTimetokens: tokens,
    ).then((res: any) => 
        console.log(res);
        return new Promise(function (resolve) 
            resolve(setUnreadMessage(res));
        );
    );



async function setChannelsAndTokens()
    channelMetadata.forEach((value, index) => 
        tokens.push(value.custom.lastToken);
        channels.push(value.id)
    );

    return new Promise(function (resolve) 
        getUnreadedMessages()
        resolve("Chanells and tokens set!");
    )


function getUnreadMessagesProccess() 
    return setGrant().then(getMetadata).then(setChannelsAndTokens).then(getUnreadedMessages)

编辑:

看起来这也是渲染的问题。当我收到getUnreadedMessages() 然后我正在编辑对象客户端:

clients.forEach((value, index) => 
       if (res.channels[value.id + '-' + userId + '-chat']) 
           value.unreadMessages = res["channels"][value.id + '-' + userId + '-chat'];
         else 
            value.unreadMessages = 0;
        
      console.log("UNREAD MESSAGE", value.unreadMessages, value.username);
);

基于此,我正在设置 showIcon:

<ClientItem
   client=item.item
   isAdmin=isAdmin
   navigation=navigation
   fromAdminTab=fromAdminTab
   showIcon=item.item.unreadMessages>0
/>

但是这个图标显示不正确。

客户列表:

 import Colors from '@helper/Colors';
    import  useSelector  from '@redux/index';
    import  HealthierLifeOption  from '@redux/types';
    import React,  useEffect, useState  from 'react';
    import  View, Text, FlatList, ActivityIndicator  from 'react-native';
    import ClientItem from './ClientItem';
    import usePubNub from "pubnub-react";
    
    export type Client = 
        id: number;
        username: string;
        individualPlanPaid: boolean;
        healthierLifeOption?: HealthierLifeOption;
        company?: 
          id: number;
          companyName: string;
        ;
        mentor?: 
          id: number;
          username: string;
        ;
    
    
    type Props = 
        navigation: any;
        clients: Client[];
        isAdmin?: boolean;
        isLoading: boolean;
        onEndReached: Function;
        fromAdminTab?: boolean
    
    
    const ClientList = ( navigation, clients, onEndReached, isLoading, isAdmin = false, fromAdminTab= false : Props) => 
        const resultCount = useSelector(state => state.user.menteesResultCount);
        const [hasMoreResults, setHasMoreResults] = useState(true);
        const userId = useSelector(state => state.user.id);
        const pubnub = usePubNub();
    
        useEffect(() => 
    
            getUnreadMessagesProccess
          setHasMoreResults(resultCount !== clients?.length);
    
        , [resultCount, clients]);
    
    
        async function setGrant() 
            return new Promise( async resolve => 
                await pubnub.grant(
                    channels: [
                        '100-68-chat',
                        '101-68-chat',
                        '22-2-chat',
                        '22-96-chat',
                        '73-68-chat',
                        '78-68-chat',
                        '79-68-chat',
                        '81-68-chat',
                        '90-68-chat',
                        '92-68-chat',
                        '93-68-chat',
                        '98-68-chat',
                        '99-68-chat' ],
                    ttl: 55,
                    read: true,
                    write: true,
                    update: true,
                    get: true,
                , response => resolve(response));
            );
        
    
        async function getMetadata() 
            const options = include: customFields: true;
            return await pubnub.objects.getAllChannelMetadata(options);
        
    
        function setChannelsAndTokens(channelMetadata, channels, tokens) 
    
            channelMetadata.data.forEach((value, index) => 
                tokens.push(value.custom.lastToken);
                channels.push(value.id.toString())
            );
        
    
        async function getUnreadedMessages(channels, tokens) 
            return new Promise(async resolve => 
                pubnub.messageCounts(
                    channels: null,
                    channelTimetokens: tokens,
                ).then(res => 
                    clients.forEach((value, index) => 
                        if (res.channels[value.id + '-' + userId + '-chat']) 
                            value.unreadMessages = res["channels"][value.id + '-' + userId + '-chat'];
                         else 
                            value.unreadMessages = 0;
                        
                        console.log("UNREAD MESSAGE", value.unreadMessages, value.username);
                    );
                    resolve()
                )
                    .catch(error => resolve(error));
            );
        
    
        async function getUnreadMessagesProccess() 
            const tokens = ['1000'];
            const channels = ['1234567'];
            const userId = 1234567;
    
            const auth = await setGrant(userId);
            log([statusCode: auth.statusCode]);
    
            const channelMetadata = await getMetadata();
            log([channelMetadata,channels,tokens]);
    
            setChannelsAndTokens(channelMetadata, channels, tokens);
            const unread = await getUnreadedMessages(channels, tokens);
            log([unread]);
    
            return unread;
        
    
    
        return (
            <View>
                <FlatList
                    keyExtractor=item => item.id.toString()
                    data=clients
                    onEndReached=() => hasMoreResults ? onEndReached() : null
                    onEndReachedThreshold=0.4
                    renderItem=item => (
                        <ClientItem
                            client=item.item
                            isAdmin=isAdmin
                            navigation=navigation
                            fromAdminTab=fromAdminTab
                            showIcon=parseInt(item.item.unreadMessages) > 0 
                        />
                    )
                    ListFooterComponent=isLoading
                      ? () => (
                          <View style= padding: 20 >
                            <ActivityIndicator animating size="large" color=Colors.border_gray />
                          </View>
                        )
                      : null
                    
                />
            </View>
        );
    
    export default ClientList;

客户项目:

import React, useEffect, useState from 'react';
    import  Text, View, Image, TouchableOpacity  from 'react-native';
    import Images from '@helper/Images';
    import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
    import Colors from '@helper/Colors';
    import styles from '../styles';
    import ClientModal from './ClientModal/ClientModal';
    import  Client  from './ClientList';
    import  HealthierLifeOption  from '@redux/types';
    
    type Props = 
        client: Client;
        navigation: any;
        isAdmin?: boolean;
        fromAdminTab?: boolean;
        showIcon?: boolean
    
    
    const ClientItem = ( client, navigation, isAdmin = false, fromAdminTab= false, showIcon= false : Props) => 
        const [showModal, setShowModal] = useState(false);
    
        console.log(showIcon); // its not passed correclty
    
        let clientIcon = Images.icon.logoIconOrange 
    
        const handleContinueButton = () => 
            if(!fromAdminTab) 
                navigation.navigate('ChatFromClientsList',  selectedId: client.id, showBackButton: true );
            else 
                setShowModal(!showModal)
            
        ;
    
        return (
            <View style=styles.client_item_container>
            

<TouchableOpacity style=styles.client_content_container onPress=handleContinueButton
                >
                <View style=styles.image_container>
                    <Image
                        style=styles.client_profile_img
                        source=clientIcon
                        resizeMode="contain"
                        resizeMethod="resize"
                    />
                </View>
                <View style=styles.title_container>
                    <Text style=styles.title > client.username  </Text>
                </View>
                <View style=styles.dot_container>
                showIcon  &&  <FontAwesome5
                    name="comment-dots"
                    size=20
                    color=Colors.red

                />  
                </View>
                <View style=styles.hamburger_container >
                    <FontAwesome5
                        name="bars"
                        size=30
                        color=Colors.black
                        onPress=() => setShowModal(!showModal)
                    />
                </View>
                <View>
                    <ClientModal
                        isVisible=showModal
                        onCollapse=(value: boolean) => setShowModal(value)
                        closeModal=(value: boolean) => setShowModal(value)
                        client=client
                        navigation=navigation
                        isAdmin=isAdmin
                    />
                </View>
            </TouchableOpacity>
        </View>
    );
;
export default ClientItem;

我不确定是因为从 Pubnub 获取数据还是因为渲染或我在 foreach 中处理数据的方式。

【问题讨论】:

【参考方案1】:

上一个完成后运行函数

在经验编码风格中使用asyncawait。这有助于组织代码。使代码易于阅读。这也有助于操作顺序。

我们所做的是在每个函数的awaitpromise 前面添加一个return。这允许我们在每个函数执行完成后分配结果变量,同时在编写代码时保留执行顺序。

? 注意:当 SDK 初始化为 secretKey 时,无需授予自己访问资源的权限。只需使用任何方法,就好像您已经拥有权限一样。 SDK 将使用您的密钥自动签署所有请求。

按下代码 sn-p 下方的 Run code snippet 按钮进行测试。

(async ()=>
'use strict';

const publishKey   = "pub-c-51f1008b-7ddf-42b7-aec9-2d0153b0e766";
const subscribeKey = "sub-c-1597b696-05af-11e6-a6dc-02ee2ddab7fe";
const secretKey    = "sec-c-YTVjYjUzMWMtM2MxZC00YzdiLWE0ZjAtNWRmMWVmYmNkZGNl";
const myUUID       = "myUniqueUUID"

const pubnub = new PubNub(
    publishKey   : publishKey,
    subscribeKey : subscribeKey,
    secretKey    : secretKey,
    uuid         : myUUID,
);

const unread = await getUnreadMessagesProccess();

async function getUnreadMessagesProccess() 
    const tokens = ['1000'];      // placeholder change me
    const channels = ['1234567']; // placeholder change me
    const userId = 1234567;       // placeholder change me

    const auth = await setGrant(userId);
    log([statusCode: auth.statusCode]);

    const channelMetadata = await getMetadata();
    log([channelMetadata,channels,tokens]);

    setChannelsAndTokens(channelMetadata, channels, tokens);
    const unread = await getUnreadedMessages(channels, tokens);
    log([unread]);

    return unread;


async function setGrant(userId) 
    return new Promise( async resolve => 
        await pubnub.grant(
            channels: [userId.toString() + '.*'],
            ttl: 55,
            read: true,
            write: true,
            update: true,
            get: true,
        , response => resolve(response));
    );


async function getMetadata() 
    const options = include: customFields: true;
    return await pubnub.objects.getAllChannelMetadata(options);


function setChannelsAndTokens(channelMetadata, channels, tokens) 
    channelMetadata.data.forEach((value, index) => 
        tokens.push(value.custom.lastToken);
        channels.push(value.id)
    );


async function getUnreadedMessages(channels, tokens) 
    try 
        return await pubnub.messageCounts(
            channels: channels,
            channelTimetokens: tokens,
        );
    
    catch(error) 
        return error;
    


async function getUnreadedMessagesAlternative(channels, tokens) 
    return new Promise(async resolve => 
        pubnub.messageCounts(
            channels: channels,
            channelTimetokens: tokens,
        ).then(result => resolve(result))
          .catch(error => resolve(error));
    );


function log(data) 
    // console.log(data);
    document.querySelector("#out").innerhtml += 
      `<div>$JSON.stringify(data)</div>`;


)();
<div id="out"></div>
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.33.0.js"></script>

【讨论】:

您好,感谢您的解决方案。但是,如果例如调用 pubnub.messageCounts 失败,我将无法获取我的数据。如何处理? 嗨@user2994290 好问题。我将在今天晚些时候更新答案。我将发布我最喜欢的 try/catch with async/await 方法。同时这里有一些描述各种选项的帖子:***.com/a/40886720/524733 和 itnext.io/error-handling-with-async-await-in-js-26c3f20bc06a @user2994290 已添加!我发现有两个例子很有用。检查上面代码 sn-p 中的 getUnreadedMessagesgetUnreadedMessagesAlternative 方法。两者的工作方式几乎相同。 感谢您的帮助,对我来说很遗憾,它不起作用。我只是更新我的问题。 嗨@user2994290 看起来原来的问题已经改变了。最初发布的问题是关于asyncawait 编码模式以确保排序。您发布的新问题是用于 GUI 调试。我们上面提供的答案向您展示了如何修复函数排序。但是我们的代码使用占位符名称。您已将代码按原样放入无法运行的应用程序中。您需要将这些占位符值更改为使用您的真实频道名称。另外一个很好的资源可能是与 support@pubnub.com 联系以进行进一步的详细调试。

以上是关于从 PubNub 获取未读消息并呈现通知的主要内容,如果未能解决你的问题,请参考以下文章

如何将未读消息的iOS推送通知分组为一个

获取聊天记录中的消息以显示在 Messenger Pubnub 中

Laravel 消息通知

Laravel 消息通知

Socket,长连接,消息推送,消息提醒,未读消息提醒,消息通知,未读消息通知

在 quickblox 中未收到未读消息计数