( ′∀`)σ≡σ☆))Д′)レ(゚∀゚;)ヘ=З=З=Зε≡(ノ´_ゝ`)ノ
<?php
// CubicleSoft PHP WebSocketServer class with libev support.
// (C) 2021 CubicleSoft. All Rights Reserved.
if (!class_exists("WebSocketServer", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/websocket_server.php";
class LibEvWebSocketServer extends WebSocketServer
{
protected $ev_watchers, $ev_read_ready, $ev_write_ready;
public static function IsSupported()
{
$os = php_uname("s");
$windows = (strtoupper(substr($os, 0, 3)) == "WIN");
return (extension_loaded("ev") && !$windows);
}
public function Reset()
{
parent::Reset();
$this->ev_watchers = array();
}
public function Internal_LibEvHandleEvent($watcher, $revents)
{
if (($revents & Ev::READ) || ($revents & Ev::ERROR)) $this->ev_read_ready[$watcher->data] = $watcher->fd;
if ($revents & Ev::WRITE) $this->ev_write_ready[$watcher->data] = $watcher->fd;
}
public function Start($host, $port)
{
$result = parent::Start($host, $port);
if (!$result["success"]) return $result;
$this->ev_watchers["ws_s"] = new EvIo($this->fp, Ev::READ, array($this, "Internal_LibEvHandleEvent"), "ws_s");
return $result;
}
public function Stop()
{
parent::Stop();
foreach ($this->ev_watchers as $key => $watcher)
{
$watcher->stop();
}
$this->ev_watchers = array();
}
protected function InitNewClient($fp)
{
$client = parent::InitNewClient($fp);
$this->ev_watchers["ws_c_" . $client->id] = new EvIo($client->fp, Ev::READ, array($this, "Internal_LibEvHandleEvent"), "ws_c_" . $client->id);
return $client;
}
public function UpdateStreamsAndTimeout($prefix, &$timeout, &$readfps, &$writefps)
{
if ($this->fp !== false) $readfps[$prefix . "ws_s"] = $this->fp;
if ($timeout === false || $timeout > $this->defaultkeepalive) $timeout = $this->defaultkeepalive;
foreach ($this->clients as $id => $client)
{
if ($client->writedata === "") $readfps[$prefix . "ws_c_" . $id] = $client->fp;
if ($client->writedata !== "" || ($client->websocket !== false && $client->websocket->NeedsWrite())) $writefps[$prefix . "ws_c_" . $id] = $client->fp;
}
}
public function Internal_LibEvTimeout($watcher, $revents)
{
Ev::stop(Ev::BREAK_ALL);
}
public function Wait($timeout = false, $readfps = array(), $writefps = array(), $exceptfps = NULL)
{
if ($timeout === false || $timeout > $this->defaultkeepalive) $timeout = $this->defaultkeepalive;
$result = array("success" => true, "clients" => array(), "removed" => array(), "readfps" => array(), "writefps" => array(), "exceptfps" => array(), "accepted" => array(), "read" => array(), "write" => array());
if (!count($this->ev_watchers) && !count($readfps) && !count($writefps)) return $result;
$this->ev_read_ready = array();
$this->ev_write_ready = array();
// Temporarily attach other read/write handles.
$tempwatchers = array();
foreach ($readfps as $key => $fp)
{
$tempwatchers[] = new EvIo($fp, Ev::READ, array($this, "Internal_LibEvHandleEvent"), $key);
}
foreach ($writefps as $key => $fp)
{
$tempwatchers[] = new EvIo($fp, Ev::WRITE, array($this, "Internal_LibEvHandleEvent"), $key);
}
$tempwatchers[] = new EvTimer($timeout, 0, array($this, "Internal_LibEvTimeout"));
// Wait for one or more events to fire.
Ev::run(Ev::RUN_ONCE);
// Remove temporary watchers.
foreach ($tempwatchers as $watcher) $watcher->stop();
// Return handles that were being waited on.
$result["readfps"] = $this->ev_read_ready;
$result["writefps"] = $this->ev_write_ready;
$result["exceptfps"] = (is_array($exceptfps) ? array() : $exceptfps);
$this->ProcessWaitResult($result);
// Post-process clients.
foreach ($result["clients"] as $id => $client)
{
$this->UpdateClientState($id);
}
return $result;
}
public function UpdateClientState($id)
{
if (isset($this->clients[$id]))
{
$client = $this->clients[$id];
$events = 0;
if ($client->writedata === "") $events = Ev::READ;
if ($client->writedata !== "" || ($client->websocket !== false && $client->websocket->NeedsWrite())) $events |= Ev::WRITE;
$this->ev_watchers["ws_c_" . $id]->set($client->fp, $events);
}
}
public function RemoveClient($id)
{
parent::RemoveClient($id);
if (isset($this->ev_watchers["ws_c_" . $id]))
{
$this->ev_watchers["ws_c_" . $id]->stop();
unset($this->ev_watchers["ws_c_" . $id]);
}
}
}
?>