Twilio对话API实时聊天

发布于 2025-02-09 04:47:54 字数 269 浏览 1 评论 0原文

基本上,我只想使用Twilio对话API进行简单的聊天集成。有了文档,我已经设置了一台服务器,我创建了一个对话,并通过上述API端点添加了2个参与者。对我来说,这也很明显,如何创建有关文档的信息。我想知道如果参与者A发送消息,我如何刷新参与者B更新聊天消息。

我需要配置某种Websockets还是对话API不需要的?我将如何通知参与者B并实时显示新消息?

而且,如果我需要Websockets,为什么我应该需要Twilio对话API?

basically I just want a simple chat integration by using twilio conversations api. With the docs I already set up a server and I created a conversation and added 2 participants to the conversation itself by the mentioned api endpoints. Its also obvious to me how to create a message looking at the docs. Im wondering how I can refresh update the chat message for participant B if participant a is sending a message.

Do I need to configure some kind of websockets or is this not needed for the conversations api? How would i notify the participant b and display the new message in real time?

And if I need websockets, why should I need twilio conversations api then?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦行七里 2025-02-16 04:47:54

我们如何实施?

  1. 客户端服务器如何与Twilio连接
    [带有twilio服务器艺术的客户端服务器] [1]
  2. 步骤您必须遵循
  • 步骤1:在nodejs中生成Twilio访问令牌以及如何使用
- generateToken.js

//require twilio package
const twilio = require('twilio');

//destructure keys from package
const { AccessToken } = twilio.jwt;
const { ChatGrant } = AccessToken;

function generateTwilioAccessToken(identity) {
  // Your Twilio Account SID, API Key SID, and API Key Secret
  const accountSid = process.env.TWILIO_ACCOUNT_SID;
  const apiKeySid = process.env.TWILIO_API_SID;
  const apiKeySecret = process.env.TWILIO_API_SECRET;

  // Create a new access token
  const accessToken = new AccessToken(accountSid, apiKeySid, apiKeySecret, {
    identity,
  });

  // Add a Chat Grant to the token (assuming you have a Conversations Service SID)
  accessToken.addGrant(
    new ChatGrant({
      serviceSid: process.env.TWILIO_CONVERSATIONS_SERVICE_SID,
    })
  );

  // Return the access token as a JWT
  return accessToken.toJwt();
}

module.exports = { generateTwilioAccessToken };
- api.js

// Example how you can use this function using your endpoint
async getTwilioToken(req) {
    try {
   // get userId as query from frontend
      const { userId } = req.query;
   
  // check does user exists
      const userData = await Users.findOne({ where: { id: userId } });

  // if exist then gerate token with unique identity as its id
      let twilioAccessToken;
      if (userData) {
        // generate twilio access token
        twilioAccessToken = generateTwilioAccessToken(userData.dataValues.id);
      }
      return {
        status: HttpStatusCode.success.SUCCESS,
        message: 'Twilio token',
        data: twilioAccessToken,
      };
    } catch (error) {
      throw error;
    }
  }
  • 步骤2:如何使用令牌在Twilio服务器(React JS)
- twilioClient.js

import { Client as ConversationsClient } from '@twilio/conversations';
import { FETCH_TWILIO_ACCESS_TOKEN } from 'services';
// chat Error message in nothing but your toaster function.
import { chatErrorMsg } from './helper';
import axios from 'axios';

export const initializeTwilioConversations = async (userId) => {
  try {
    // Fetch a new Twilio access token first
    const fetchTwilioToken = async () => {
      try {
        const response = await axios.get(
          `${FETCH_TWILIO_ACCESS_TOKEN}?userId=${userId}`,
        );
        if (response?.data?.statusCode === 200) {
          return response?.data?.data;
        }
      } catch (error) {
        chatErrorMsg('Error fetching Twilio access token');
      }
    };

 // This token contain user unqiue id i.e. id.
    const token = await fetchTwilioToken();
    if (!token) {
      chatErrorMsg('Error fetching Twilio access token');
    }

    // Initialize the ConversationsClient with the retrieved token
    let conversationsClientInstance = new ConversationsClient(token);
    return conversationsClientInstance;
  } catch (error) {
    chatErrorMsg('Error initializing Twilio Conversations');
  }
};
  • 步骤3:如何初始化用户并获取其实例
Chat.js

// Defines few state first
const [connectionState, setConnectionState] = useState({
    loading: true,
    connectionStatus: null,
  });
const [conversationsClient, setConversationsClient] = useState(null);
const [conversationsList, setConversationsList] = useState([]);
const [messages, setMessages] = useState([]);


// initialize conversation
  const conversationInitialization = useCallback(async () => {
    try {
      // Initialize the Conversations Client with the access token and gets the Client Instance
      const client = await initializeTwilioConversations(loggedInUserId);

      // Listen for connection state changes :
   // Here, we get the connection status from twilio server and store in state
      client.on('connectionStateChanged', async (state) => {
        if (state === 'connecting') {
          setConnectionState((state) => ({
            ...state,
            connectionStatus: 'Connecting to chat...',
          }));
        }
        if (state === 'connected') {
          const conversations = await client.getSubscribedConversations();
          setConnectionState({
            loading: false,
            connectionStatus: 'You are connected',
          });
          setConversationsList(conversations?.items);
        }
        if (state === 'disconnecting') {
          setConnectionState((state) => ({
            loading: false,
            connectionStatus: 'Disconnecting from chat...',
          }));
        }
        if (state === 'denied') {
          setConnectionState((state) => ({
            loading: false,
            connectionStatus: 'Failed to connect',
          }));
        }
      });

// Event Triggers : When any user joined conversation , any message came for this user these events triggers and we can perform our operations on that.

      client.on('conversationJoined', (conversation) => {
        setConversationsList((prev) => [...prev, conversation]);
      });

      client.on('messageAdded', (message) => {
        setMessages((prevMessages) => [...prevMessages, message]);
      });

      client.on('conversationLeft', (thisConversation) => {
        // eslint-disable-next-line no-console
        console.log('conversation left', thisConversation);
      });

      client.on('tokenAboutToExpire', async () => {
        // Fetch a new token when the existing token is about to expire
        await initializeTwilioConversations();
      });

      setConversationsClient(client);
    } catch (error) {
      chatErrorMsg('Error initializing Twilio Conversations');
    }
  }, []);


  useEffect(() => {
    conversationInitialization();
    return () => {
      // Cleanup function to remove event listeners when the component unmounts
      if (conversationsClient) {
        conversationsClient.removeAllListeners();
      }
    };
   
  }, []);
  • 步骤4:创建与之对话特定用户
helper.js

// Function to initialize the participant if not subscribed
//By chance if user unable to register after loggedIn we can register it from here also.
const initializeParticipantIfNotSubscribed = async (
  client,
  participantIdentities
) => {
  const identities = Array.isArray(participantIdentities)
    ? participantIdentities
    : [participantIdentities];
  let delayValue = 0;
  // Check if any of the participants are not subscribed and initialize if needed
  for (const participantIdentity of identities) {
    const subscribedUsers = await client.getSubscribedUsers();
    const isParticipantSubscribed = subscribedUsers.some(
      (user) => user?.state?.identity === participantIdentity
    );

    if (!isParticipantSubscribed) {
      await initializeTwilioConversations(participantIdentity);
    }
    delayValue = delayValue + 1000;
  }
  await delay(delayValue);
};


// Function to create or join a conversation
export const createOrJoinConversation = async (
  client,
  participantIdentities,
  friendlyName,
  uniqueName,
  attributes = {}
) => {
  try {
// get list of conversation in which user is part of.
    const conversations = await client.getSubscribedConversations();
    const existingConversation = conversations?.items.find(
      (conv) => conv?.friendlyName === friendlyName
    );

    if (existingConversation) {
      return existingConversation; // Return the existing conversation
    }

    // Check if participant is subscribed and initialize if not
    await initializeParticipantIfNotSubscribed(client, participantIdentities);

    // Create a new conversation
    const newConversation = await client.createConversation({
      friendlyName: friendlyName,
      uniqueName: uniqueName,
      attributes: {
        ...attributes,
      },
    });

    // Join the current user to the new conversation
    await newConversation.join();

    // Add participants to the conversation (handle both single and multiple participants)
    const participantsToAdd = Array.isArray(participantIdentities)
      ? participantIdentities
      : [participantIdentities];

    for (const participantIdentity of participantsToAdd) {
      try {
        // Attempt to add the participant to the conversation
        await newConversation.add(participantIdentity);
      } catch (participantError) {
        // Handle errors when adding a participant
        chatErrorMsg(`Error adding participant ${participantIdentity}`);
      }
    }

    return newConversation;
  } catch (error) {
    chatErrorMsg(`Error creating or joining conversation`);
    return null;
  }
};
  • 如何使用此功能
const onSelectMember = async (member) => {
    const senderId = loggedInUserId;
    const receiverId = member?.userId;
    const friendlyName = `one-to-one-${senderId}--${receiverId}`;
    const uniqueName = `${senderId}--${receiverId}`;
    const participantIdentity = member?.userId;
    const attributes = {
      senderId: senderId,
      receiverId: receiverId,
      conversationType: 'ONE_TO_ONE',
    };

    await createOrJoinConversation(
      conversationsClient,
      participantIdentity,
      friendlyName,
      uniqueName,
      attributes
    );
  };

先决条件:

  1. react :用于设计UI。
  2. nodejs :用于您的项目中使用的后端API。

使用的软件包:

  1. twilio
  2. twilio condersation

How can we implement?

  1. How client server connects with twilio
    [Client server with twilio server artitecture ][1]
  2. Steps you have to follow
  • Step 1 : Generate Twilio Access Token in Nodejs and how to use it
- generateToken.js

//require twilio package
const twilio = require('twilio');

//destructure keys from package
const { AccessToken } = twilio.jwt;
const { ChatGrant } = AccessToken;

function generateTwilioAccessToken(identity) {
  // Your Twilio Account SID, API Key SID, and API Key Secret
  const accountSid = process.env.TWILIO_ACCOUNT_SID;
  const apiKeySid = process.env.TWILIO_API_SID;
  const apiKeySecret = process.env.TWILIO_API_SECRET;

  // Create a new access token
  const accessToken = new AccessToken(accountSid, apiKeySid, apiKeySecret, {
    identity,
  });

  // Add a Chat Grant to the token (assuming you have a Conversations Service SID)
  accessToken.addGrant(
    new ChatGrant({
      serviceSid: process.env.TWILIO_CONVERSATIONS_SERVICE_SID,
    })
  );

  // Return the access token as a JWT
  return accessToken.toJwt();
}

module.exports = { generateTwilioAccessToken };
- api.js

// Example how you can use this function using your endpoint
async getTwilioToken(req) {
    try {
   // get userId as query from frontend
      const { userId } = req.query;
   
  // check does user exists
      const userData = await Users.findOne({ where: { id: userId } });

  // if exist then gerate token with unique identity as its id
      let twilioAccessToken;
      if (userData) {
        // generate twilio access token
        twilioAccessToken = generateTwilioAccessToken(userData.dataValues.id);
      }
      return {
        status: HttpStatusCode.success.SUCCESS,
        message: 'Twilio token',
        data: twilioAccessToken,
      };
    } catch (error) {
      throw error;
    }
  }
  • Step 2: How to Use the Token to Initialize/Register Users on the Twilio Server (React JS)
- twilioClient.js

import { Client as ConversationsClient } from '@twilio/conversations';
import { FETCH_TWILIO_ACCESS_TOKEN } from 'services';
// chat Error message in nothing but your toaster function.
import { chatErrorMsg } from './helper';
import axios from 'axios';

export const initializeTwilioConversations = async (userId) => {
  try {
    // Fetch a new Twilio access token first
    const fetchTwilioToken = async () => {
      try {
        const response = await axios.get(
          `${FETCH_TWILIO_ACCESS_TOKEN}?userId=${userId}`,
        );
        if (response?.data?.statusCode === 200) {
          return response?.data?.data;
        }
      } catch (error) {
        chatErrorMsg('Error fetching Twilio access token');
      }
    };

 // This token contain user unqiue id i.e. id.
    const token = await fetchTwilioToken();
    if (!token) {
      chatErrorMsg('Error fetching Twilio access token');
    }

    // Initialize the ConversationsClient with the retrieved token
    let conversationsClientInstance = new ConversationsClient(token);
    return conversationsClientInstance;
  } catch (error) {
    chatErrorMsg('Error initializing Twilio Conversations');
  }
};
  • Step 3: How to initialize User and get Its Instance
Chat.js

// Defines few state first
const [connectionState, setConnectionState] = useState({
    loading: true,
    connectionStatus: null,
  });
const [conversationsClient, setConversationsClient] = useState(null);
const [conversationsList, setConversationsList] = useState([]);
const [messages, setMessages] = useState([]);


// initialize conversation
  const conversationInitialization = useCallback(async () => {
    try {
      // Initialize the Conversations Client with the access token and gets the Client Instance
      const client = await initializeTwilioConversations(loggedInUserId);

      // Listen for connection state changes :
   // Here, we get the connection status from twilio server and store in state
      client.on('connectionStateChanged', async (state) => {
        if (state === 'connecting') {
          setConnectionState((state) => ({
            ...state,
            connectionStatus: 'Connecting to chat...',
          }));
        }
        if (state === 'connected') {
          const conversations = await client.getSubscribedConversations();
          setConnectionState({
            loading: false,
            connectionStatus: 'You are connected',
          });
          setConversationsList(conversations?.items);
        }
        if (state === 'disconnecting') {
          setConnectionState((state) => ({
            loading: false,
            connectionStatus: 'Disconnecting from chat...',
          }));
        }
        if (state === 'denied') {
          setConnectionState((state) => ({
            loading: false,
            connectionStatus: 'Failed to connect',
          }));
        }
      });

// Event Triggers : When any user joined conversation , any message came for this user these events triggers and we can perform our operations on that.

      client.on('conversationJoined', (conversation) => {
        setConversationsList((prev) => [...prev, conversation]);
      });

      client.on('messageAdded', (message) => {
        setMessages((prevMessages) => [...prevMessages, message]);
      });

      client.on('conversationLeft', (thisConversation) => {
        // eslint-disable-next-line no-console
        console.log('conversation left', thisConversation);
      });

      client.on('tokenAboutToExpire', async () => {
        // Fetch a new token when the existing token is about to expire
        await initializeTwilioConversations();
      });

      setConversationsClient(client);
    } catch (error) {
      chatErrorMsg('Error initializing Twilio Conversations');
    }
  }, []);


  useEffect(() => {
    conversationInitialization();
    return () => {
      // Cleanup function to remove event listeners when the component unmounts
      if (conversationsClient) {
        conversationsClient.removeAllListeners();
      }
    };
   
  }, []);
  • Step 4: Creating a Conversation with a Specific User
helper.js

// Function to initialize the participant if not subscribed
//By chance if user unable to register after loggedIn we can register it from here also.
const initializeParticipantIfNotSubscribed = async (
  client,
  participantIdentities
) => {
  const identities = Array.isArray(participantIdentities)
    ? participantIdentities
    : [participantIdentities];
  let delayValue = 0;
  // Check if any of the participants are not subscribed and initialize if needed
  for (const participantIdentity of identities) {
    const subscribedUsers = await client.getSubscribedUsers();
    const isParticipantSubscribed = subscribedUsers.some(
      (user) => user?.state?.identity === participantIdentity
    );

    if (!isParticipantSubscribed) {
      await initializeTwilioConversations(participantIdentity);
    }
    delayValue = delayValue + 1000;
  }
  await delay(delayValue);
};


// Function to create or join a conversation
export const createOrJoinConversation = async (
  client,
  participantIdentities,
  friendlyName,
  uniqueName,
  attributes = {}
) => {
  try {
// get list of conversation in which user is part of.
    const conversations = await client.getSubscribedConversations();
    const existingConversation = conversations?.items.find(
      (conv) => conv?.friendlyName === friendlyName
    );

    if (existingConversation) {
      return existingConversation; // Return the existing conversation
    }

    // Check if participant is subscribed and initialize if not
    await initializeParticipantIfNotSubscribed(client, participantIdentities);

    // Create a new conversation
    const newConversation = await client.createConversation({
      friendlyName: friendlyName,
      uniqueName: uniqueName,
      attributes: {
        ...attributes,
      },
    });

    // Join the current user to the new conversation
    await newConversation.join();

    // Add participants to the conversation (handle both single and multiple participants)
    const participantsToAdd = Array.isArray(participantIdentities)
      ? participantIdentities
      : [participantIdentities];

    for (const participantIdentity of participantsToAdd) {
      try {
        // Attempt to add the participant to the conversation
        await newConversation.add(participantIdentity);
      } catch (participantError) {
        // Handle errors when adding a participant
        chatErrorMsg(`Error adding participant ${participantIdentity}`);
      }
    }

    return newConversation;
  } catch (error) {
    chatErrorMsg(`Error creating or joining conversation`);
    return null;
  }
};
  • How can you use this function
const onSelectMember = async (member) => {
    const senderId = loggedInUserId;
    const receiverId = member?.userId;
    const friendlyName = `one-to-one-${senderId}--${receiverId}`;
    const uniqueName = `${senderId}--${receiverId}`;
    const participantIdentity = member?.userId;
    const attributes = {
      senderId: senderId,
      receiverId: receiverId,
      conversationType: 'ONE_TO_ONE',
    };

    await createOrJoinConversation(
      conversationsClient,
      participantIdentity,
      friendlyName,
      uniqueName,
      attributes
    );
  };

Prerequisites:

  1. React: For designing the UI.
  2. Nodejs: For backend APIs used in your projects.

Packages Used:

  1. Twilio
  2. Twilio-Conversation
极度宠爱 2025-02-16 04:47:54

Twilio对话提供 client side sdks 您可以用来显示对话和对话和对话和对话和对话给您的聊天用户的消息。请查看 javaScript对话quickStart QuickStart 您如何查看如何查看您如何可以使用它为您的用户建立聊天。

Twilio Conversations provides client side SDKs that you can use to display conversations and messages to your chat users. Check out the JavaScript Conversations Quickstart to see how you can use it to build chat for your users.

情绪少女 2025-02-16 04:47:54

如果您有一个聊天应用程序(这不是实时的,就像您建议使用的那样),那么,在Swift中,如果您实现了Twilio的TchconversationDelegate协议,则可以从那里轻松地在屏幕上更新元素(并将其转换为真实 - 时间聊天)。当添加新消息的是:该功能处理事件的函数(例如 - 将其称为“ WebSocket事件”)是:

func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, messageAdded message: TCHMessage){
    // do stuff here with the message argument, which contains the new message. Namely, message.body is the actual text of the message.
}

此函数与Twilio的Websockets连接到另一端的用户的聊天对话。这就是Twilio对话API的工作方式,如果您正在制作聊天应用程序,我建议您使用它。在此之前,有可编程的聊天,现在已弃用,我不再建议了。

If you have a chat app (which is not real time, like you are suggesting you have), then, in Swift, if you implement Twilio's TCHConversationDelegate protocol, you can easily update elements on the screen from there (and turn it into a real-time chat). The function from the protocol - for example - that handles the event (let's call it a "websocket event") when a new message is added is:

func conversationsClient(_ client: TwilioConversationsClient, conversation: TCHConversation, messageAdded message: TCHMessage){
    // do stuff here with the message argument, which contains the new message. Namely, message.body is the actual text of the message.
}

This function is wired with Twilio's websockets directly to the chat of the user at the other end of the conversation. This is how Twilio Conversations API works, and I suggest you use it, if you are making a chat app. Before that, there was Programmable Chat, which is now deprecated and I don't suggest it any more.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文