Triangle WS Framework
triangle/ws — это WebSocket-фреймворк на основе Triangle Engine для разработки real-time приложений.
Установка
composer create-project triangle/ws my-ws-app
cd my-ws-app
Структура проекта
my-ws-app/
├── app/
│ ├── controller/ # WebSocket контроллеры
│ ├── middleware/ # Middleware
│ └── model/ # Модели
├── config/ # Конфигурация
├── process/ # Дополнительные процессы
└── master # Скрипт запуска
Запуск
# Разработка
php master start
# Production
php master start -d
# Остановка
php master stop
Конфигурация
Сервер
config/server.php:
return [
'listen' => 'websocket://0.0.0.0:2345',
'processes' => 4,
'name' => 'Triangle-WS',
];
Создание WebSocket контроллера
<?php
namespace App\Controller;
use Triangle\Engine\Request;
use Triangle\Ws\Connection;
class ChatController
{
public function onMessage(Connection $connection, Request $request)
{
$data = json_decode($request->rawBody(), true);
// Отправка сообщения всем подключенным клиентам
foreach (Connection::getAll() as $conn) {
$conn->send(json_encode([
'type' => 'message',
'data' => $data['message'],
]));
}
}
public function onConnect(Connection $connection)
{
$connection->send(json_encode([
'type' => 'connected',
'message' => 'Welcome!',
]));
}
public function onClose(Connection $connection)
{
// Обработка отключения
}
}
Маршрутизация WebSocket
Определите маршруты в config/route.php:
use Triangle\Router\Route;
return [
Route::ws('/chat', [\App\Controller\ChatController::class, 'onMessage']),
];
Работа с подключениями
Получение всех подключений
use Triangle\Ws\Connection;
$allConnections = Connection::getAll();
// Отправка всем
foreach ($allConnections as $connection) {
$connection->send($message);
}
Работа с конкретным подключением
// Отправка данных
$connection->send(json_encode(['message' => 'Hello']));
// Закрытие подключения
$connection->close();
// Получение информации
$connectionId = $connection->id;
$remoteAddress = $connection->getRemoteAddress();
Пример: Чат-приложение
Контроллер
<?php
namespace App\Controller;
use App\Model\Message;
use Triangle\Engine\Request;
use Triangle\Ws\Connection;
class ChatController
{
public function onMessage(Connection $connection, Request $request)
{
$data = json_decode($request->rawBody(), true);
// Сохранение сообщения в БД
$message = Message::create([
'user_id' => $connection->session->get('user_id'),
'text' => $data['message'],
]);
// Отправка всем подключенным
foreach (Connection::getAll() as $conn) {
$conn->send(json_encode([
'type' => 'new_message',
'message' => $message->toArray(),
]));
}
}
public function onConnect(Connection $connection)
{
// Отправка истории сообщений
$messages = Message::latest()->limit(50)->get();
$connection->send(json_encode([
'type' => 'history',
'messages' => $messages->toArray(),
]));
}
}
Клиентская часть (JavaScript)
const ws = new WebSocket('ws://localhost:2345/chat');
ws.onopen = function() {
console.log('Connected');
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
switch(data.type) {
case 'new_message':
addMessageToChat(data.message);
break;
case 'history':
loadHistory(data.messages);
break;
}
};
ws.onclose = function() {
console.log('Disconnected');
};
function sendMessage(message) {
ws.send(JSON.stringify({
message: message
}));
}
Middleware для WebSocket
<?php
namespace App\Middleware;
use Triangle\Engine\Request;
use Triangle\Middleware\MiddlewareInterface;
use Triangle\Ws\Connection;
class AuthMiddleware implements MiddlewareInterface
{
public function process(Request $request, callable $next)
{
$connection = $request->connection;
if (!$connection->session->get('user_id')) {
$connection->close();
return;
}
return $next($request);
}
}
Группировка подключений
use Triangle\Ws\Connection;
// Добавление в группу
Connection::joinGroup($connection, 'room:123');
// Отправка группе
Connection::sendToGroup('room:123', $message);
// Удаление из группы
Connection::leaveGroup($connection, 'room:123');
Процессы
Для дополнительных процессов создайте файлы в process/:
<?php
namespace App\Process;
use Triangle\Engine\Process;
class Monitor extends Process
{
public function onWorkerStart()
{
// Инициализация процесса
}
public function onWorkerStop()
{
// Очистка при остановке
}
}
Зарегистрируйте в config/process.php:
return [
\App\Process\Monitor::class,
];