1010use React \Socket \ConnectionInterface ;
1111use React \Socket \Connector ;
1212use React \Socket \ConnectorInterface ;
13- use InvalidArgumentException ;
1413
1514class Factory
1615{
@@ -38,18 +37,39 @@ public function __construct(LoopInterface $loop = null, ConnectorInterface $conn
3837 /**
3938 * Create Redis client connected to address of given redis instance
4039 *
41- * @param string $target Redis server URI to connect to
42- * @return \React\Promise\PromiseInterface<Client> resolves with Client or rejects with \Exception
40+ * @param string $uri Redis server URI to connect to
41+ * @return \React\Promise\PromiseInterface<Client,\Exception> Promise that will
42+ * be fulfilled with `Client` on success or rejects with `\Exception` on error.
4343 */
44- public function createClient ($ target )
44+ public function createClient ($ uri )
4545 {
46- try {
47- $ parts = $ this ->parseUrl ($ target );
48- } catch (InvalidArgumentException $ e ) {
49- return \React \Promise \reject ($ e );
46+ // support `redis+unix://` scheme for Unix domain socket (UDS) paths
47+ if (preg_match ('/^(redis\+unix:\/\/(?:[^:]*:[^@]*@)?)(.+?)?$/ ' , $ uri , $ match )) {
48+ $ parts = parse_url ($ match [1 ] . 'localhost/ ' . $ match [2 ]);
49+ } else {
50+ if (strpos ($ uri , ':// ' ) === false ) {
51+ $ uri = 'redis:// ' . $ uri ;
52+ }
53+
54+ $ parts = parse_url ($ uri );
55+ }
56+
57+ if ($ parts === false || !isset ($ parts ['scheme ' ], $ parts ['host ' ]) || !in_array ($ parts ['scheme ' ], array ('redis ' , 'rediss ' , 'redis+unix ' ))) {
58+ return \React \Promise \reject (new \InvalidArgumentException ('Given URL can not be parsed ' ));
5059 }
5160
52- $ connecting = $ this ->connector ->connect ($ parts ['authority ' ]);
61+ $ args = array ();
62+ parse_str (isset ($ parts ['query ' ]) ? $ parts ['query ' ] : '' , $ args );
63+
64+ $ authority = $ parts ['host ' ] . ': ' . (isset ($ parts ['port ' ]) ? $ parts ['port ' ] : 6379 );
65+ if ($ parts ['scheme ' ] === 'rediss ' ) {
66+ $ authority = 'tls:// ' . $ authority ;
67+ } elseif ($ parts ['scheme ' ] === 'redis+unix ' ) {
68+ $ authority = 'unix:// ' . substr ($ parts ['path ' ], 1 );
69+ unset($ parts ['path ' ]);
70+ }
71+ $ connecting = $ this ->connector ->connect ($ authority );
72+
5373 $ deferred = new Deferred (function ($ _ , $ reject ) use ($ connecting ) {
5474 // connection cancelled, start with rejecting attempt, then clean up
5575 $ reject (new \RuntimeException ('Connection to Redis server cancelled ' ));
@@ -72,9 +92,12 @@ public function createClient($target)
7292 );
7393 });
7494
75- if (isset ($ parts ['auth ' ])) {
76- $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ parts ) {
77- return $ client ->auth ($ parts ['auth ' ])->then (
95+ // use `?password=secret` query or `user:secret@host` password form URL
96+ $ pass = isset ($ args ['password ' ]) ? $ args ['password ' ] : (isset ($ parts ['pass ' ]) ? rawurldecode ($ parts ['pass ' ]) : null );
97+ if (isset ($ args ['password ' ]) || isset ($ parts ['pass ' ])) {
98+ $ pass = isset ($ args ['password ' ]) ? $ args ['password ' ] : rawurldecode ($ parts ['pass ' ]);
99+ $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ pass ) {
100+ return $ client ->auth ($ pass )->then (
78101 function () use ($ client ) {
79102 return $ client ;
80103 },
@@ -91,9 +114,11 @@ function ($error) use ($client) {
91114 });
92115 }
93116
94- if (isset ($ parts ['db ' ])) {
95- $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ parts ) {
96- return $ client ->select ($ parts ['db ' ])->then (
117+ // use `?db=1` query or `/1` path (skip first slash)
118+ if (isset ($ args ['db ' ]) || (isset ($ parts ['path ' ]) && $ parts ['path ' ] !== '/ ' )) {
119+ $ db = isset ($ args ['db ' ]) ? $ args ['db ' ] : substr ($ parts ['path ' ], 1 );
120+ $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ db ) {
121+ return $ client ->select ($ db )->then (
97122 function () use ($ client ) {
98123 return $ client ;
99124 },
@@ -113,7 +138,7 @@ function ($error) use ($client) {
113138 $ promise ->then (array ($ deferred , 'resolve ' ), array ($ deferred , 'reject ' ));
114139
115140 // use timeout from explicit ?timeout=x parameter or default to PHP's default_socket_timeout (60)
116- $ timeout = isset ($ parts ['timeout ' ]) ? $ parts ['timeout ' ] : (int ) ini_get ("default_socket_timeout " );
141+ $ timeout = isset ($ args ['timeout ' ]) ? ( float ) $ args ['timeout ' ] : (int ) ini_get ("default_socket_timeout " );
117142 if ($ timeout < 0 ) {
118143 return $ deferred ->promise ();
119144 }
@@ -138,63 +163,4 @@ public function createLazyClient($target)
138163 {
139164 return new LazyClient ($ target , $ this , $ this ->loop );
140165 }
141-
142- /**
143- * @param string $target
144- * @return array with keys authority, auth and db
145- * @throws InvalidArgumentException
146- */
147- private function parseUrl ($ target )
148- {
149- $ ret = array ();
150- // support `redis+unix://` scheme for Unix domain socket (UDS) paths
151- if (preg_match ('/^redis\+unix:\/\/([^:]*:[^@]*@)?(.+?)(\?.*)?$/ ' , $ target , $ match )) {
152- $ ret ['authority ' ] = 'unix:// ' . $ match [2 ];
153- $ target = 'redis:// ' . (isset ($ match [1 ]) ? $ match [1 ] : '' ) . 'localhost ' . (isset ($ match [3 ]) ? $ match [3 ] : '' );
154- }
155-
156- if (strpos ($ target , ':// ' ) === false ) {
157- $ target = 'redis:// ' . $ target ;
158- }
159-
160- $ parts = parse_url ($ target );
161- if ($ parts === false || !isset ($ parts ['scheme ' ], $ parts ['host ' ]) || !in_array ($ parts ['scheme ' ], array ('redis ' , 'rediss ' ))) {
162- throw new InvalidArgumentException ('Given URL can not be parsed ' );
163- }
164-
165- if (isset ($ parts ['pass ' ])) {
166- $ ret ['auth ' ] = rawurldecode ($ parts ['pass ' ]);
167- }
168-
169- if (isset ($ parts ['path ' ]) && $ parts ['path ' ] !== '' ) {
170- // skip first slash
171- $ ret ['db ' ] = substr ($ parts ['path ' ], 1 );
172- }
173-
174- if (!isset ($ ret ['authority ' ])) {
175- $ ret ['authority ' ] =
176- ($ parts ['scheme ' ] === 'rediss ' ? 'tls:// ' : '' ) .
177- $ parts ['host ' ] . ': ' .
178- (isset ($ parts ['port ' ]) ? $ parts ['port ' ] : 6379 );
179- }
180-
181- if (isset ($ parts ['query ' ])) {
182- $ args = array ();
183- parse_str ($ parts ['query ' ], $ args );
184-
185- if (isset ($ args ['password ' ])) {
186- $ ret ['auth ' ] = $ args ['password ' ];
187- }
188-
189- if (isset ($ args ['db ' ])) {
190- $ ret ['db ' ] = $ args ['db ' ];
191- }
192-
193- if (isset ($ args ['timeout ' ])) {
194- $ ret ['timeout ' ] = (float ) $ args ['timeout ' ];
195- }
196- }
197-
198- return $ ret ;
199- }
200166}
0 commit comments