PixeltooSocket

Современная Socket.IO библиотека для Flutter, созданная с нуля для обеспечения надежного real-time соединения с серверами Socket.IO.

Особенности

  • ✅ Полная совместимость с Socket.IO v4
  • 🚀 Умная эскалация транспортов с автоматическим переключением
  • 📋 Настраиваемый порядок транспортов (WebSocket ↔ Polling)
  • Rate Limiting для защиты от спама запросов
  • 🔄 Автоматическое переподключение
  • 📈 Статистика производительности транспортов
  • ⏱️ Поддержка событий с подтверждением (acknowledgments)
  • 🎯 Настраиваемые опции подключения
  • 📝 Подробное логирование
  • 🎛️ Типобезопасные события
  • 🔐 Поддержка HTTP заголовков и query параметров
  • 🏠 Система комнат (rooms)
  • 🧪 Обработка ошибок и таймаутов

Установка

Добавьте в pubspec.yaml:

dependencies:
  pixeltoo_socket: ^0.1.0

Быстрый старт

import 'package:pixeltoo_socket/pixeltoo_socket.dart';

void main() async {
  // Создание клиента
  final socket = io('http://localhost:3000');

  // Подписка на события
  socket.on('connect', (data) {
    print('Подключен!');
    socket.emit('hello', 'Привет от Flutter!');
  });

  socket.on('message', (data) {
    print('Получено: $data');
  });

  // Подключение происходит автоматически
  // Или можно подключиться вручную:
  // await socket.connect();
}

Основное API

Создание клиента

// Простое подключение
final socket = io('http://localhost:3000');

// С настройками
final socket = io('http://localhost:3000', 
  timeout: 10000,
  autoConnect: false,
  reconnectionAttempts: 3,
  enableLogging: true,
  headers: {'Authorization': 'Bearer token'},
  query: {'userId': '123'},
);

Управление подключением

// Подключение
await socket.connect();

// Отключение
socket.disconnect();

// Проверка состояния
if (socket.isConnected) {
  print('Подключен');
}

// Получение текущего состояния
print(socket.state); // SocketIOConnectionState

События

// Подписка на событие
socket.on('message', (data) {
  print('Сообщение: $data');
});

// Подписка на событие (один раз)
socket.once('welcome', (data) {
  print('Добро пожаловать: $data');
});

// Отписка от события
socket.off('message');

// Отписка конкретного обработчика
void handler(data) => print(data);
socket.on('test', handler);
socket.off('test', handler);

// Очистка всех обработчиков
socket.clearAllHandlers();

Отправка событий

// Простая отправка
socket.emit('message', 'Привет!');

// Отправка объекта
socket.emit('user_data', {
  'name': 'Иван',
  'age': 25,
});

// Отправка с подтверждением
try {
  final response = await socket.emitWithAck('get_data', {'id': 123});
  print('Ответ: $response');
} catch (e) {
  print('Таймаут или ошибка: $e');
}

Системные события

socket.on('connect', (data) {
  print('Подключен к серверу');
});

socket.on('disconnect', (data) {
  print('Отключен от сервера');
});

socket.on('error', (error) {
  print('Ошибка: $error');
});

🚀 Новые возможности v0.1.0

Умная эскалация транспортов

Автоматическое переключение между WebSocket и Polling на основе производительности:

final socket = io('http://localhost:3000',
  transportType: SocketIOTransportType.auto,
  transportOrder: ["websocket", "polling"], // Порядок попыток
  enableTransportEscalation: true,
  transportEscalationInterval: 10000, // Проверка каждые 10 секунд
);

// Получение текущего транспорта
print('Текущий транспорт: ${socket.currentTransportType}');

// Статистика производительности
final stats = socket.getTransportStats();
stats.forEach((transport, data) {
  print('$transport: ${data['errorRate']}% ошибок, ${data['averageLatency']}ms задержка');
});

Rate Limiting

Защита от спама запросов с настраиваемыми лимитами:

final socket = io('http://localhost:3000',
  rateLimitInterval: 100,        // Минимум 100ms между запросами
  maxRequestsPerMinute: 300,     // Максимум 300 запросов в минуту
);

// Библиотека автоматически контролирует частоту запросов
for (int i = 0; i < 100; i++) {
  socket.emit('message', 'Сообщение $i'); // Автоматический rate limiting
}

Настраиваемый порядок транспортов

Выбор приоритета транспортов в зависимости от условий:

// Приоритет Polling (для нестабильных сетей)
final socket = io('http://localhost:3000',
  transportOrder: ["polling", "websocket"],
);

// Приоритет WebSocket (для быстрых сетей)
final socket = io('http://localhost:3000',
  transportOrder: ["websocket", "polling"],
);

// Только один транспорт
final socket = io('http://localhost:3000',
  transportType: SocketIOTransportType.polling, // Только polling
);

Настройки подключения

SocketIOOptions

const options = SocketIOOptions(
  url: 'http://localhost:3000',           // URL сервера
  transportType: SocketIOTransportType.auto, // Тип транспорта
  transportOrder: ["websocket", "polling"], // Порядок транспортов
  timeout: 20000,                         // Таймаут подключения (мс)
  autoConnect: true,                      // Автоподключение
  reconnectionDelay: 1000,                // Задержка переподключения (мс)
  reconnectionAttempts: 5,                // Количество попыток
  rateLimitInterval: 100,                 // Минимальный интервал между запросами (мс)
  maxRequestsPerMinute: 300,              // Максимум запросов в минуту
  transportEscalationInterval: 10000,     // Интервал проверки эскалации (мс)
  enableTransportEscalation: true,        // Включить эскалацию транспортов
  headers: {'Custom-Header': 'value'},    // HTTP заголовки
  query: {'token': 'abc123'},             // Query параметры
  enableLogging: false,                   // Включить логи
);

final socket = SocketIOClient(options);

Состояния подключения

enum SocketIOConnectionState {
  disconnected,  // Отключен
  connecting,    // Подключается
  connected,     // Подключен
  reconnecting,  // Переподключается
  error,         // Ошибка
}

Обработка ошибок

socket.on('error', (error) {
  if (error is TimeoutException) {
    print('Таймаут подключения');
  } else if (error is SocketException) {
    print('Сетевая ошибка: ${error.message}');
  } else {
    print('Неизвестная ошибка: $error');
  }
});

Примеры использования

Чат приложение

class ChatService {
  late SocketIOClient socket;
  
  void connect() {
    socket = io('http://localhost:3000');
    
    socket.on('connect', (_) {
      print('Подключен к чату');
    });
    
    socket.on('new_message', (data) {
      final message = Message.fromJson(data);
      _handleNewMessage(message);
    });
    
    socket.on('user_joined', (data) {
      print('${data['username']} присоединился');
    });
  }
  
  void sendMessage(String text) {
    socket.emit('send_message', {
      'text': text,
      'timestamp': DateTime.now().toIso8601String(),
    });
  }
  
  void dispose() {
    socket.dispose();
  }
}

Real-time уведомления

class NotificationService {
  late SocketIOClient socket;
  
  void initialize(String userId) {
    socket = io('http://localhost:3000', 
      query: {'userId': userId},
    );
    
    socket.on('notification', (data) {
      _showNotification(data['title'], data['body']);
    });
    
    socket.on('badge_update', (data) {
      _updateBadgeCount(data['count']);
    });
  }
}

Тестирование

Запуск тестов:

flutter test

Совместимость

  • Flutter: >=1.17.0
  • Dart: ^3.10.3
  • Socket.IO Server: v4.x

Лицензия

MIT License

Поддержка

Если у вас есть вопросы или предложения, создайте issue в репозитории.

Libraries

pixeltoo_socket