ваше сообщение коммита
This commit is contained in:
85
frontend/src/services/dleV2Service.js
Normal file
85
frontend/src/services/dleV2Service.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
/**
|
||||
* Сервис для работы с DLE v2 (Digital Legal Entity)
|
||||
* Современный подход с единым контрактом
|
||||
*/
|
||||
class DLEV2Service {
|
||||
/**
|
||||
* Создает новое DLE v2
|
||||
* @param {Object} dleParams - Параметры DLE
|
||||
* @returns {Promise<Object>} - Результат создания
|
||||
*/
|
||||
async createDLE(dleParams) {
|
||||
try {
|
||||
const response = await axios.post('/api/dle-v2', dleParams);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при создании DLE v2:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает список всех DLE v2
|
||||
* @returns {Promise<Array>} - Список DLE v2
|
||||
*/
|
||||
async getAllDLEs() {
|
||||
try {
|
||||
const response = await axios.get('/api/dle-v2');
|
||||
return response.data.data || [];
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении списка DLE v2:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает настройки по умолчанию для DLE v2
|
||||
* @returns {Promise<Object>} - Настройки по умолчанию
|
||||
*/
|
||||
async getDefaults() {
|
||||
try {
|
||||
const response = await axios.get('/api/dle-v2/defaults');
|
||||
return response.data.data;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении настроек по умолчанию DLE v2:', error);
|
||||
return {
|
||||
votingDelay: 1,
|
||||
votingPeriod: 45818,
|
||||
proposalThreshold: '100000',
|
||||
quorumPercentage: 4,
|
||||
minTimelockDelay: 2
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет DLE v2 по адресу
|
||||
* @param {string} dleAddress - Адрес DLE
|
||||
* @returns {Promise<Object>} - Результат удаления
|
||||
*/
|
||||
async deleteDLE(dleAddress) {
|
||||
try {
|
||||
const response = await axios.delete(`/api/dle-v2/${dleAddress}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении DLE v2:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new DLEV2Service();
|
||||
@@ -49,6 +49,7 @@ export async function connectWithWallet() {
|
||||
const origin = window.location.origin;
|
||||
const statement = 'Sign in with Ethereum to the app.';
|
||||
|
||||
const issuedAt = new Date().toISOString();
|
||||
const siweMessage = new SiweMessage({
|
||||
domain,
|
||||
address,
|
||||
@@ -57,11 +58,23 @@ export async function connectWithWallet() {
|
||||
version: '1',
|
||||
chainId: 1,
|
||||
nonce,
|
||||
issuedAt,
|
||||
resources: [`${origin}/api/auth/verify`],
|
||||
});
|
||||
|
||||
const message = siweMessage.prepareMessage();
|
||||
console.log('SIWE message:', message);
|
||||
console.log('SIWE message details:', {
|
||||
domain,
|
||||
address,
|
||||
statement,
|
||||
uri: origin,
|
||||
version: '1',
|
||||
chainId: 1,
|
||||
nonce,
|
||||
issuedAt,
|
||||
resources: [`${origin}/api/auth/verify`],
|
||||
});
|
||||
|
||||
// Запрашиваем подпись
|
||||
console.log('Requesting signature...');
|
||||
@@ -75,9 +88,10 @@ export async function connectWithWallet() {
|
||||
// Отправляем подпись на сервер для верификации
|
||||
console.log('Sending verification request...');
|
||||
const verificationResponse = await axios.post('/auth/verify', {
|
||||
message,
|
||||
signature,
|
||||
address,
|
||||
nonce,
|
||||
issuedAt,
|
||||
});
|
||||
|
||||
console.log('Verification response:', verificationResponse.data);
|
||||
|
||||
192
frontend/src/services/websocketService.js
Normal file
192
frontend/src/services/websocketService.js
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* WebSocket сервис для реального времени обновлений
|
||||
*/
|
||||
|
||||
class WebSocketService {
|
||||
constructor() {
|
||||
this.ws = null;
|
||||
this.isConnected = false;
|
||||
this.reconnectAttempts = 0;
|
||||
this.maxReconnectAttempts = 5;
|
||||
this.reconnectDelay = 1000; // 1 секунда
|
||||
this.listeners = new Map();
|
||||
this.userId = null;
|
||||
}
|
||||
|
||||
// Подключение к WebSocket серверу
|
||||
connect(userId = null) {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
console.log('🔌 [WebSocket] Уже подключен');
|
||||
return;
|
||||
}
|
||||
|
||||
this.userId = userId;
|
||||
|
||||
try {
|
||||
// Определяем WebSocket URL
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
// В Docker окружении backend работает на порту 8000
|
||||
const backendHost = window.location.hostname + ':8000';
|
||||
const wsUrl = `${protocol}//${backendHost}/ws`;
|
||||
|
||||
console.log('🔌 [WebSocket] Подключение к:', wsUrl);
|
||||
|
||||
this.ws = new WebSocket(wsUrl);
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log('✅ [WebSocket] Подключение установлено');
|
||||
this.isConnected = true;
|
||||
this.reconnectAttempts = 0;
|
||||
|
||||
// Аутентификация пользователя
|
||||
if (this.userId) {
|
||||
this.send({
|
||||
type: 'auth',
|
||||
userId: this.userId
|
||||
});
|
||||
}
|
||||
|
||||
this.emit('connected');
|
||||
};
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('📨 [WebSocket] Получено сообщение:', data);
|
||||
this.handleMessage(data);
|
||||
} catch (error) {
|
||||
console.error('❌ [WebSocket] Ошибка парсинга сообщения:', error);
|
||||
}
|
||||
};
|
||||
|
||||
this.ws.onclose = (event) => {
|
||||
console.log('🔌 [WebSocket] Соединение закрыто:', event.code, event.reason);
|
||||
this.isConnected = false;
|
||||
this.emit('disconnected', event);
|
||||
|
||||
// Попытка переподключения
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
this.reconnectAttempts++;
|
||||
console.log(`🔄 [WebSocket] Попытка переподключения ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
|
||||
|
||||
setTimeout(() => {
|
||||
this.connect(this.userId);
|
||||
}, this.reconnectDelay * this.reconnectAttempts);
|
||||
} else {
|
||||
console.error('❌ [WebSocket] Превышено максимальное количество попыток переподключения');
|
||||
this.emit('reconnect-failed');
|
||||
}
|
||||
};
|
||||
|
||||
this.ws.onerror = (error) => {
|
||||
console.error('❌ [WebSocket] Ошибка соединения:', error);
|
||||
this.emit('error', error);
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ [WebSocket] Ошибка создания соединения:', error);
|
||||
this.emit('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Отправка сообщения
|
||||
send(data) {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(data));
|
||||
} else {
|
||||
console.warn('⚠️ [WebSocket] Соединение не установлено, сообщение не отправлено:', data);
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка входящих сообщений
|
||||
handleMessage(data) {
|
||||
switch (data.type) {
|
||||
case 'auth-success':
|
||||
console.log('✅ [WebSocket] Аутентификация успешна для пользователя:', data.userId);
|
||||
this.emit('auth-success', data);
|
||||
break;
|
||||
|
||||
case 'chat-message':
|
||||
console.log('💬 [WebSocket] Новое сообщение чата:', data.message);
|
||||
this.emit('chat-message', data.message);
|
||||
break;
|
||||
|
||||
case 'conversation-updated':
|
||||
console.log('📝 [WebSocket] Обновление диалога:', data.conversationId);
|
||||
this.emit('conversation-updated', data.conversationId);
|
||||
break;
|
||||
|
||||
case 'messages-updated':
|
||||
console.log('📨 [WebSocket] Обновление сообщений');
|
||||
this.emit('messages-updated');
|
||||
break;
|
||||
|
||||
case 'contacts-updated':
|
||||
console.log('👥 [WebSocket] Обновление контактов');
|
||||
this.emit('contacts-updated');
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ [WebSocket] Неизвестный тип сообщения:', data.type);
|
||||
this.emit('unknown-message', data);
|
||||
}
|
||||
}
|
||||
|
||||
// Подписка на события
|
||||
on(event, callback) {
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
this.listeners.get(event).push(callback);
|
||||
}
|
||||
|
||||
// Отписка от событий
|
||||
off(event, callback) {
|
||||
if (this.listeners.has(event)) {
|
||||
const callbacks = this.listeners.get(event);
|
||||
const index = callbacks.indexOf(callback);
|
||||
if (index > -1) {
|
||||
callbacks.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Эмиссия событий
|
||||
emit(event, data) {
|
||||
if (this.listeners.has(event)) {
|
||||
this.listeners.get(event).forEach(callback => {
|
||||
try {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error(`❌ [WebSocket] Ошибка в обработчике события ${event}:`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Отключение
|
||||
disconnect() {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
this.isConnected = false;
|
||||
this.listeners.clear();
|
||||
console.log('🔌 [WebSocket] Отключен');
|
||||
}
|
||||
|
||||
// Получение статуса соединения
|
||||
getStatus() {
|
||||
return {
|
||||
isConnected: this.isConnected,
|
||||
readyState: this.ws ? this.ws.readyState : null,
|
||||
reconnectAttempts: this.reconnectAttempts,
|
||||
userId: this.userId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Создаем единственный экземпляр
|
||||
const websocketService = new WebSocketService();
|
||||
|
||||
export default websocketService;
|
||||
Reference in New Issue
Block a user