从 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】:上一个完成后运行函数
在经验编码风格中使用async
和await
。这有助于组织代码。使代码易于阅读。这也有助于操作顺序。
我们所做的是在每个函数的await
和promise
前面添加一个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 中的getUnreadedMessages
和 getUnreadedMessagesAlternative
方法。两者的工作方式几乎相同。
感谢您的帮助,对我来说很遗憾,它不起作用。我只是更新我的问题。
嗨@user2994290 看起来原来的问题已经改变了。最初发布的问题是关于async
和await
编码模式以确保排序。您发布的新问题是用于 GUI 调试。我们上面提供的答案向您展示了如何修复函数排序。但是我们的代码使用占位符名称。您已将代码按原样放入无法运行的应用程序中。您需要将这些占位符值更改为使用您的真实频道名称。另外一个很好的资源可能是与 support@pubnub.com 联系以进行进一步的详细调试。以上是关于从 PubNub 获取未读消息并呈现通知的主要内容,如果未能解决你的问题,请参考以下文章
获取聊天记录中的消息以显示在 Messenger Pubnub 中