44
55use Swoole \Coroutine \Client ;
66use Utopia \Proxy \Adapter ;
7+ use Utopia \Proxy \ConnectionResult ;
78use Utopia \Proxy \Protocol ;
89use Utopia \Proxy \Resolver ;
910use Utopia \Proxy \Sockmap \Loader as Sockmap ;
@@ -40,9 +41,14 @@ class TCP extends Adapter
4041 /** @var array<int, Client> */
4142 protected array $ connections = [];
4243
44+ /** @var array<int, string> */
45+ protected array $ initialData = [];
46+
4347 /** @var array<int, int> client fd => backend fd, for sockmap pairs handed to the kernel */
4448 protected array $ sockmapPairs = [];
4549
50+ protected ?\Closure $ initialDataTransformer = null ;
51+
4652 protected float $ timeout = 30.0 ;
4753
4854 protected float $ connectTimeout = 5.0 ;
@@ -66,6 +72,25 @@ public function __construct(
6672 parent ::__construct ($ resolver );
6773 }
6874
75+ /**
76+ * Transform the first client packet before it is forwarded to the backend.
77+ *
78+ * The callback receives the raw initial packet and route result. This lets
79+ * protocol-aware callers route by one identifier while forwarding a backend
80+ * specific startup packet.
81+ */
82+ public function onInitialData (callable $ callback ): static
83+ {
84+ $ this ->initialDataTransformer = $ callback (...);
85+
86+ return $ this ;
87+ }
88+
89+ public function getInitialData (int $ fd , string $ default ): string
90+ {
91+ return $ this ->initialData [$ fd ] ?? $ default ;
92+ }
93+
6994 public function setTimeout (float $ timeout ): static
7095 {
7196 $ this ->timeout = $ timeout ;
@@ -181,6 +206,7 @@ public function getConnection(string $data, int $fd): Client
181206
182207 $ result = $ this ->route ($ data );
183208 [$ host , $ port ] = self ::parseEndpoint ($ result ->endpoint , $ this ->port );
209+ $ initialData = $ this ->transformInitialData ($ data , $ result );
184210
185211 $ client = new Client (SWOOLE_SOCK_TCP );
186212 $ client ->set ([
@@ -196,10 +222,25 @@ public function getConnection(string $data, int $fd): Client
196222
197223 $ this ->applySocketOptions ($ client );
198224 $ this ->connections [$ fd ] = $ client ;
225+ $ this ->initialData [$ fd ] = $ initialData ;
199226
200227 return $ client ;
201228 }
202229
230+ protected function transformInitialData (string $ data , ConnectionResult $ result ): string
231+ {
232+ if ($ this ->initialDataTransformer === null ) {
233+ return $ data ;
234+ }
235+
236+ $ transformed = ($ this ->initialDataTransformer )($ data , $ result );
237+ if (!\is_string ($ transformed )) {
238+ throw new \Exception ('Initial data transformer must return string ' );
239+ }
240+
241+ return $ transformed ;
242+ }
243+
203244 /**
204245 * Hand the (client fd, backend fd) pair to the kernel via sockmap.
205246 *
@@ -270,6 +311,7 @@ public function closeConnection(int $fd): void
270311 }
271312
272313 unset($ this ->connections [$ fd ]);
314+ unset($ this ->initialData [$ fd ]);
273315 $ client ->close ();
274316 }
275317
0 commit comments