Passed
Pull Request — master (#378)
by Bill
07:55 queued 05:18
created

RedisRoom   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 211
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
eloc 40
c 4
b 1
f 1
dl 0
loc 211
rs 10
wmc 24

14 Methods

Rating   Name   Duplication   Size   Complexity  
A connection() 0 3 1
A addValue() 0 12 2
A prepare() 0 5 1
A checkTable() 0 4 2
A getKey() 0 3 1
A removeValue() 0 12 2
A cleanRooms() 0 4 2
A add() 0 8 3
A getRooms() 0 3 1
A getRedis() 0 3 1
A delete() 0 9 4
A getClients() 0 3 1
A __construct() 0 4 1
A getValue() 0 8 2
1
<?php
2
3
namespace SwooleTW\Http\Websocket\Rooms;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Contracts\Redis\Factory as RedisFactory;
7
8
/**
9
 * Class RedisRoom
10
 */
11
class RedisRoom implements RoomContract
12
{
13
	/**
14
     * The Redis factory implementation.
15
     *
16
     * @var \Illuminate\Contracts\Redis\Factory
17
     */
18
    public $redis;
19
20
	/**
21
	 * @var array
22
	 */
23
	protected $config;
24
25
	/**
26
	 * RedisRoom constructor.
27
	 *
28
	 * @param array $config
29
	 */
30
	public function __construct(array $config, RedisFactory $redis)
31
	{
32
		$this->config = $config;
33
		$this->redis = $redis;
34
	}
35
36
	/**
37
	 * @param \Illuminate\Contracts\Redis\Factory|null $redis
38
	 *
39
	 * @return \Ofcold\HttpSwoole\Websocket\Rooms\RoomContract
0 ignored issues
show
Bug introduced by
The type Ofcold\HttpSwoole\Websocket\Rooms\RoomContract was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
	 */
41
	public function prepare(RedisFactory $redis = null): RoomContract
42
	{
43
		$this->cleanRooms();
44
45
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type SwooleTW\Http\Websocket\Rooms\RedisRoom which is incompatible with the documented return type Ofcold\HttpSwoole\Websocket\Rooms\RoomContract.
Loading history...
46
	}
47
48
	/**
49
	 * Get redis client.
50
	 */
51
	public function getRedis()
52
	{
53
		return $this->connection();
54
	}
55
56
	/**
57
	 * Add multiple socket fds to a room.
58
	 *
59
	 * @param int fd
0 ignored issues
show
Bug introduced by
The type SwooleTW\Http\Websocket\Rooms\fd was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
60
	 * @param array|string rooms
0 ignored issues
show
Bug introduced by
The type SwooleTW\Http\Websocket\Rooms\rooms was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
61
	 */
62
	public function add(int $fd, $rooms)
63
	{
64
		$rooms = is_array($rooms) ? $rooms : [$rooms];
65
66
		$this->addValue($fd, $rooms, RoomContract::DESCRIPTORS_KEY);
67
68
		foreach ($rooms as $room) {
69
			$this->addValue($room, [$fd], RoomContract::ROOMS_KEY);
70
		}
71
	}
72
73
	/**
74
	 * Delete multiple socket fds from a room.
75
	 *
76
	 * @param int fd
77
	 * @param array|string rooms
78
	 */
79
	public function delete(int $fd, $rooms)
80
	{
81
		$rooms = is_array($rooms) ? $rooms : [$rooms];
82
		$rooms = count($rooms) ? $rooms : $this->getRooms($fd);
83
84
		$this->removeValue($fd, $rooms, RoomContract::DESCRIPTORS_KEY);
85
86
		foreach ($rooms as $room) {
87
			$this->removeValue($room, [$fd], RoomContract::ROOMS_KEY);
88
		}
89
	}
90
91
	/**
92
	 * Add value to redis.
93
	 *
94
	 * @param $key
95
	 * @param array $values
96
	 * @param string $table
97
	 *
98
	 * @return $this
99
	 */
100
	public function addValue($key, array $values, string $table)
101
	{
102
		$this->checkTable($table);
103
		$redisKey = $this->getKey($key, $table);
104
105
		$this->connection()->pipeline(function ($pipe) use ($redisKey, $values) {
106
			foreach ($values as $value) {
107
				$pipe->sadd($redisKey, $value);
108
			}
109
		});
110
111
		return $this;
112
	}
113
114
	/**
115
	 * Remove value from reddis.
116
	 *
117
	 * @param $key
118
	 * @param array $values
119
	 * @param string $table
120
	 *
121
	 * @return $this
122
	 */
123
	public function removeValue($key, array $values, string $table)
124
	{
125
		$this->checkTable($table);
126
		$redisKey = $this->getKey($key, $table);
127
128
		$this->connection()->pipeline(function ($pipe) use ($redisKey, $values) {
129
			foreach ($values as $value) {
130
				$pipe->srem($redisKey, $value);
131
			}
132
		});
133
134
		return $this;
135
	}
136
137
	/**
138
	 * Get all sockets by a room key.
139
	 *
140
	 * @param string room
141
	 *
142
	 * @return array
143
	 */
144
	public function getClients(string $room)
145
	{
146
		return $this->getValue($room, RoomContract::ROOMS_KEY) ?? [];
147
	}
148
149
	/**
150
	 * Get all rooms by a fd.
151
	 *
152
	 * @param int fd
153
	 *
154
	 * @return array
155
	 */
156
	public function getRooms(int $fd)
157
	{
158
		return $this->getValue($fd, RoomContract::DESCRIPTORS_KEY) ?? [];
159
	}
160
161
	/**
162
	 * Check table for rooms and descriptors.
163
	 *
164
	 * @param string $table
165
	 */
166
	protected function checkTable(string $table)
167
	{
168
		if (! in_array($table, [RoomContract::ROOMS_KEY, RoomContract::DESCRIPTORS_KEY])) {
169
			throw new \InvalidArgumentException("Invalid table name: `{$table}`.");
170
		}
171
	}
172
173
	/**
174
	 * Get value.
175
	 *
176
	 * @param string $key
177
	 * @param string $table
178
	 *
179
	 * @return array
180
	 */
181
	public function getValue(string $key, string $table)
182
	{
183
		$this->checkTable($table);
184
185
		$result = $this->connection()->smembers($this->getKey($key, $table));
186
187
		// Try to fix occasional non-array returned result
188
		return is_array($result) ? $result : [];
189
	}
190
191
	/**
192
	 * Get key.
193
	 *
194
	 * @param string $key
195
	 * @param string $table
196
	 *
197
	 * @return string
198
	 */
199
	public function getKey(string $key, string $table)
200
	{
201
		return "{$table}:{$key}";
202
	}
203
204
	/**
205
	 * Clean all rooms.
206
	 */
207
	protected function cleanRooms(): void
208
	{
209
		if (count($keys = $this->connection()->keys("*"))) {
210
			$this->connection()->del($keys);
211
		}
212
	}
213
214
	/**
215
	 * Get the Redis connection instance.
216
	 *
217
	 * @return \Illuminate\Redis\Connections\Connection
0 ignored issues
show
Bug introduced by
The type Illuminate\Redis\Connections\Connection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
218
	 */
219
	public function connection()
220
	{
221
		return $this->redis->connection('swoole');
222
	}
223
}
224