<?php
use Swoole\Http\Response;
use Swoole\Http\Request;
use Swoole\WebSocket\Server;

//$server = new swoole_websocket_server("0.0.0.0", 9501);
$server = new Server("0.0.0.0", 9501, SWOOLE_BASE);
//$server->addlistener('0.0.0.0', 9502, SWOOLE_SOCK_UDP);
$server->set([
    // 'worker_num' => 4,
    // 'task_worker_num' => 4,
    'websocket_compression' => true,
]);

function user_handshake(Request $request, Response $response)
{
    //自定定握手规则，没有设置则用系统内置的（只支持version:13的）
    if (!isset($request->header['sec-websocket-key']))
    {
        //'Bad protocol implementation: it is not RFC6455.'
        $response->end();
        return false;
    }
    if (0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $request->header['sec-websocket-key'])
        || 16 !== strlen(base64_decode($request->header['sec-websocket-key']))
    )
    {
        //Header Sec-WebSocket-Key is illegal;
        $response->end();
        return false;
    }

    $key = base64_encode(sha1($request->header['sec-websocket-key']
        . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
        true));
    $headers = array(
        'Upgrade'               => 'websocket',
        'Connection'            => 'Upgrade',
        'Sec-WebSocket-Accept'  => $key,
        'Sec-WebSocket-Version' => '13',
        'KeepAlive'             => 'off',
    );
    foreach ($headers as $key => $val)
    {
        $response->header($key, $val);
    }
    $response->status(101);
    $response->end();
    global $server;
    $fd = $request->fd;
    $server->defer(function () use ($fd, $server)
    {
        $server->push($fd, "hello, welcome\n");
    });
    return true;
}

//$server->on('handshake', 'user_handshake');
$server->on('open', function (Server $_server, Request $request) {
    echo "server#{$_server->worker_pid}: handshake success with fd#{$request->fd}\n";
    var_dump($_server->exist($request->fd), $_server->getClientInfo($request->fd));
    $fd = $request->fd;
//    $_server->tick(2000, function($id) use ($fd, $_server) {
//        $_send = str_repeat('B', rand(100, 5000));
//        $ret = $_server->push($fd, $_send);
//        if (!$ret)
//        {
//            var_dump($id);
//            var_dump($_server->clearTimer($id));
//        }
//    });
});

$server->on('message', function (Server $_server, $frame) {
    //var_dump($frame->data);
    echo "received " . strlen($frame->data) . " bytes\n";
    if ($frame->data == "close") {
        $_server->close($frame->fd);
    } elseif ($frame->data == "task") {
        $_server->task(['go' => 'die']);
    } else {
        //echo "receive from {$frame->fd}:{$frame->data}, opcode:{$frame->opcode}, finish:{$frame->finish}\n";
        // for ($i = 0; $i < 100; $i++)
        {
//            $_send = ''
            $_send = base64_encode(random_bytes(rand(100, 1024)));
//            $_send = str_repeat('B', rand(100, 800));
            $_server->push($frame->fd, $_send, SWOOLE_WEBSOCKET_OPCODE_TEXT, SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS);
            // echo "#$i\tserver sent " . strlen($_send) . " byte \n";
        }
    }
});

$server->on('close', function ($_server, $fd) {
    echo "client {$fd} closed\n";
});

$server->on('task', function ($_server, $worker_id, $task_id, $data)
{
    var_dump($worker_id, $task_id, $data);
    return "hello world\n";
});

$server->on('finish', function ($_server, $task_id, $result)
{
    var_dump($task_id, $result);
});

$server->on('packet', function ($_server, $data, $client) {
    echo "#".posix_getpid()."\tPacket {$data}\n";
    var_dump($client);
});

$server->on('request', function (Request $request, Response $response) {
    $response->end(<<<HTML
<h1>Swoole WebSocket Server</h1>
<script>
var wsServer = 'ws://127.0.0.1:9501';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
	console.log("Connected to WebSocket server.");
};

websocket.onclose = function (evt) {
	console.log("Disconnected");
};

websocket.onmessage = function (evt) {
	console.log('Retrieved data from server: ' + evt.data);
};

websocket.onerror = function (evt, e) {
	console.log('Error occured: ' + evt.data);
};
</script>
HTML
    );
});

$server->start();
