-
Notifications
You must be signed in to change notification settings - Fork 115
/
websocket_server_libev.php
156 lines (115 loc) · 4.39 KB
/
websocket_server_libev.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?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]);
}
}
}
?>