Как обновлять чаты через WebSoket в реальном времени?
После многочисленных тестов было выявлено, что после подачи axios не проходит ни единой команды. Запрос проходит успешно, так как проходит на основной сервер,тот в свою очередь проводит все нужные операции. Но вот в чем проблема, веб сокет ни в какую не хочет работать после отправки своего запроса, так как посление сообщения что вижу я это:
console.log('Сокет готов к отправке данных');
и действительно, не обманул,он готов и даже отправляет, но только на сервер и больше ничего не хочет делать
Вот код самой страницы чата
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { StyleSheet, FlatList, Text, View, Alert, SafeAreaView, TextInput, TouchableOpacity } from 'react-native';
import { GetToken, GetUserId, GetUserName } from '../../../JwtTokens/JwtStorege';
import { useWebSocket } from '@/WebSoket/WSConnection';
export default function ChatWithUser({ route, navigation }) {
const socket = useWebSocket();
const { title } = route.params;
const [messages, setMessages] = useState([]);
const [UserId, setUserId] = useState(null);
const [NameUser, setNameUser] = useState(null);
const [messageText, setMessageText] = useState('');
const flatListRef = useRef(null); // Создание рефа для FlatList
useEffect(() => {
navigation.setOptions({ title });
}, [navigation, title]);
useEffect(() => {
const fetchUserId = async () => {
const name = await GetUserName();
const id = await GetUserId();
setUserId(id);
setNameUser(name);
};
fetchUserId();
}, []);
const handleMessage = useCallback(async (event) => {
try {
const response = JSON.parse(event.data);
if (response.success) {
if (response.type === 'NewMessage') {
// Добавляем новое сообщение в состояние
const newMessage = {
_id: response.data._id, // Убедитесь, что _id уникален
sender: response.data.sender,
text: response.data.text,
time: response.data.time,
data: response.data.data,
};
setMessages((prevMessages) => [...prevMessages, newMessage]);
} else {
// Обработка других типов сообщений
const newMessages = response.data.map((msg) => ({
_id: msg._id,
sender: msg.sender,
text: msg.text,
time: msg.time,
data: msg.data,
}));
setMessages((prevMessages) => [...prevMessages, ...newMessages]);
}
} else {
Alert.alert('Ошибка', response.message);
}
} catch (error) {
console.error('Ошибка при обработке сообщения:', error, event.data);
}
}, []);
useEffect(() => {
if (messages.length > 0) {
flatListRef.current.scrollToEnd({ animated: true });
}
}, [messages]);
useEffect(() => {
if (socket && NameUser) {
socket.send(JSON.stringify({ type: 'registerС', userId: NameUser }));
}
}, [socket, NameUser]);
useEffect(() => {
if (socket) {
socket.addEventListener('message', handleMessage);
return () => {
socket.removeEventListener('message', handleMessage);
};
}
}, [socket, handleMessage]);
const fetchMessages = async () => {
const JwtToken = await GetToken();
const UserId = await GetUserId();
if (JwtToken && UserId) {
const message = {
type: 'AllMesseges',
JwtToken: JwtToken,
UserId: UserId,
AponentName: title,
};
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(message));
}
}
};
useEffect(() => {
fetchMessages();
}, [socket, title]);
const renderMessage = ({ item, index }) => {
if (!UserId) return null;
const isMyMessage = item.sender === UserId;
const previousMessage = messages[index - 1];
const showDateHeader = !previousMessage || previousMessage.data !== item.data;
return (
<>
{showDateHeader && (
<View style={styles.dateHeader}>
<Text style={styles.dateText}>{new Date(item.data).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long'
})}</Text>
</View>
)}
<View style={[styles.messageContainer, isMyMessage ? styles.myMessage : styles.partnerMessage]}>
<Text style={styles.messageText}>{item.text}</Text>
<Text style={styles.messageTime}>{item.time.slice(0, 5)}</Text>
</View>
</>
);
};
const sendMessage = async () => {
const JwtToken = await GetToken();
const UserId = await GetUserId();
if (messageText.trim() === '') return;
const currentDate = new Date().toLocaleDateString('en-CA');
const currentTime = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
if (JwtToken && UserId) {
const message = {
type: 'NewMessage',
JwtToken: JwtToken,
text: messageText,
sender: UserId,
recipient: title, // имя оппонента
DataTime: currentTime,
Data: currentDate,
};
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(message));
// Создаем новый объект сообщения для добавления в состояние
const newMessage = {
_id: Math.floor(Math.random() * 1000).toString(), // Убедитесь, что это значение уникально
sender: UserId,
text: messageText,
time: currentTime,
data: currentDate,
};
// Обновляем состояние сообщений
setMessages((prevMessages) => [...prevMessages, newMessage]);
setMessageText('');
flatListRef.current.scrollToEnd({ animated: true });
}
}
};
return (
<SafeAreaView style={styles.container}>
<FlatList
ref={flatListRef} // Присоединяем реф
data={messages.sort((a, b) => new Date(a.data + ' ' + a.time) - new Date(b.data + ' ' + b.time))}
keyExtractor={(item) => item._id.toString()}
renderItem={renderMessage}
style={styles.chatContainer}
/>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
value={messageText}
onChangeText={setMessageText}
placeholder="Введите ваше сообщение..."
onSubmitEditing={sendMessage}
/>
<TouchableOpacity style={styles.sendButton} onPress={sendMessage}>
<Text style={styles.sendButtonText}>Отправить</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
chatContainer: {
flex: 1,
backgroundColor: '#fff',
},
messageContainer: {
marginVertical: 5,
maxWidth: '70%',
padding: 10,
borderRadius: 10,
},
myMessage: {
alignSelf: 'flex-end',
backgroundColor: '#DCF8C6',
},
partnerMessage: {
alignSelf: 'flex-start',
backgroundColor: '#E4E6EB',
},
messageText: {
fontSize: 16,
color: '#000',
},
messageTime: {
fontSize: 12,
color: '#555',
marginTop: 5,
textAlign: 'right',
},
inputContainer: {
flexDirection: 'row',
padding: 10,
borderTopWidth: 1,
borderColor: '#ccc',
},
input: {
flex: 1,
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 10,
padding: 10,
marginRight: 10,
},
sendButton: {
backgroundColor: '#007BFF',
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
padding: 10,
},
sendButtonText: {
color: '#fff',
},
dateHeader: {
alignSelf: 'center',
marginVertical: 10,
},
dateText: {
fontSize: 14,
color: '#666',
},
});
И WebSoket-сервер. Он разделен у меня на модули:
Основной, где дополнительно открывается путь к пользователю
import express from 'express';
import http from 'http';
import { WebSocketServer } from 'ws';
import axios from 'axios';
import dotenv from 'dotenv';
import messageHandlers from './processingMessages/GeneralProc.js';
dotenv.config({ path: "./Config.env" });
const app = express();
const PORT = 3000;
const server = http.createServer(app);
const wss = new WebSocketServer({ server });
const usersSockets = new Map(); // Сохраняем WebSocket для каждого пользователя
wss.on('connection', (ws) => {
console.log('Новое WebSocket-соединение установлено');
ws.on('message', async (message) => {
try {
const data = JSON.parse(message.toString());
// Регистрация соединения пользователя
if (data.type === 'registerС') {
usersSockets.set(data.userId, ws);
console.log(`Пользователь ${data.userId} подключен`);
return;
}
// Обработка сообщения
const handler = messageHandlers[data.type];
if (handler) {
handler(ws, data, usersSockets); // Передаем usersSockets для доступа к другим соединениям
} else {
ws.send(JSON.stringify({ success: false, message: 'Тип запроса не найден' }));
}
} catch (error) {
console.error('Ошибка при обработке данных:', error.message);
ws.send(JSON.stringify({ success: false, message: 'Ошибка при обработке данных' }));
}
});
ws.on('close', () => {
for (let [userId, socket] of usersSockets.entries()) {
if (socket === ws) {
usersSockets.delete(userId);
console.log(`Пользователь ${userId} отключен`);
break;
}
}
});
});
// Запуск сервера
server.listen(PORT, (err) => {
if (err) {
console.error('Ошибка при запуске сервера:', err);
} else {
console.log(`Сервер запущен на http://localhost:${PORT}`);
}
});
export default server;
Часть кода сервера где обрабатываются новые сообщения
import axios from 'axios';
async function Sentmess(ws, { DataTime, JwtToken, recipient, sender, text, Data }, usersSockets) {
try {
const recipientSocket = usersSockets.get(recipient);
if (recipientSocket) {
console.log('Recipient socket найден:', recipientSocket);
// Проверяем текущее состояние сокета
console.log('Состояние recipientSocket:', recipientSocket.readyState);
const response = await axios.post(process.env.URL_CKECK_SENTMESSEGE, { DataTime, JwtToken, recipient, sender, text, Data });
// Если состояние сокета открытое, продолжаем отправку
if (recipientSocket.readyState === WebSocket.OPEN) {
console.log('Сокет готов к отправке данных');
try {
// Выполняем запрос к вашему API
console.log('Ответ от axios:', response.data);
// Отправляем сообщение оппоненту
recipientSocket.send(JSON.stringify({
success: true,
type: 'NewMessage',
data: {
_id: response.data._id, // Уникальный ID сообщения
sender,
text,
time: DataTime,
data: Data,
},
}));
} catch (error) {
console.log(error)
}
} else {
console.log("Сокет оппонента не открыт, состояние:", recipientSocket.readyState);
}
} else {
console.log('Recipient socket не найден');
}
console.log("Почти конец!")
// Отправляем ответ обратно отправителю
ws.send(JSON.stringify({
success: true,
message: "Ваше сообщение отправлено",
...response?.data, // Ответ API (если был)
}));
} catch (err) {
console.error('Ошибка при отправке запроса:', err.message);
ws.send(JSON.stringify({ success: false, message: 'Не удалось отправить сообщение' }));
}
}
export default Sentmess;