1+ <?php
2+
3+ /*
4+ * Copyright (c) 2023 VennV
5+ *
6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7+ * of this software and associated documentation files (the "Software"), to deal
8+ * in the Software without restriction, including without limitation the rights
9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in all
14+ * copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+ declare (strict_types = 1 );
26+
27+ namespace vennv \vapm ;
28+
29+ use Fiber ;
30+ use Throwable ;
31+
32+ final class GreenThread implements GreenThreadInterface
33+ {
34+
35+ /**
36+ * @var array<int, string|int>
37+ */
38+ private static array $ names = [];
39+
40+ /**
41+ * @var array<int, Fiber>
42+ */
43+ private static array $ fibers = [];
44+
45+ /**
46+ * @var array<int, array<int, mixed>>
47+ */
48+ private static array $ params = [];
49+
50+ /**
51+ * @var array<string|int, mixed>
52+ */
53+ private static array $ outputs = [];
54+
55+ /**
56+ * @var array<string|int, StatusThread>
57+ */
58+ private static array $ status = [];
59+
60+ /**
61+ * @param string|int $name
62+ * @param callable $callback
63+ * @param array<int, mixed> $params
64+ */
65+ public static function register (string |int $ name , callable $ callback , array $ params ): void
66+ {
67+ if (isset (self ::$ outputs [$ name ]))
68+ {
69+ unset(self ::$ outputs [$ name ]);
70+ }
71+
72+ self ::$ names [] = $ name ;
73+ self ::$ fibers [] = new Fiber ($ callback );
74+ self ::$ params [] = $ params ;
75+ self ::$ status [$ name ] = new StatusThread ();
76+ }
77+
78+ /**
79+ * @throws Throwable
80+ */
81+ public static function run (): void
82+ {
83+ foreach (self ::$ fibers as $ i => $ fiber )
84+ {
85+ if (!self ::$ status [self ::$ names [$ i ]]->canWakeUp ())
86+ {
87+ continue ;
88+ }
89+
90+ $ name = self ::$ names [$ i ];
91+
92+ try
93+ {
94+ if (!$ fiber ->isStarted ())
95+ {
96+ $ fiber ->start (...self ::$ params [$ i ]);
97+ }
98+ elseif ($ fiber ->isTerminated ())
99+ {
100+ self ::$ outputs [$ name ] = $ fiber ->getReturn ();
101+ unset(self ::$ fibers [$ i ]);
102+ }
103+ elseif ($ fiber ->isSuspended ())
104+ {
105+ $ fiber ->resume ();
106+ }
107+ }
108+ catch (Throwable $ e )
109+ {
110+ self ::$ outputs [$ name ] = $ e ;
111+ }
112+ }
113+ }
114+
115+ public static function clear (): void
116+ {
117+ self ::$ names = [];
118+ self ::$ fibers = [];
119+ self ::$ params = [];
120+ }
121+
122+ /**
123+ * @return array<int, string|int>
124+ */
125+ public static function getNames (): array
126+ {
127+ return self ::$ names ;
128+ }
129+
130+ /**
131+ * @return array<int, Fiber>
132+ */
133+ public static function getFibers (): array
134+ {
135+ return self ::$ fibers ;
136+ }
137+
138+ /**
139+ * @return array<int, array<int, mixed>>
140+ */
141+ public static function getParams (): array
142+ {
143+ return self ::$ params ;
144+ }
145+
146+ /**
147+ * @return array<string|int, mixed>
148+ */
149+ public static function getOutputs (): array
150+ {
151+ return self ::$ outputs ;
152+ }
153+
154+ /**
155+ * @param string|int $name
156+ * @return mixed
157+ */
158+ public static function getOutput (string |int $ name ): mixed
159+ {
160+ return self ::$ outputs [$ name ];
161+ }
162+
163+ /**
164+ * @throws Throwable
165+ */
166+ public static function sleep (string $ name , int $ seconds ): void
167+ {
168+ self ::$ status [$ name ]->sleep ($ seconds );
169+
170+ $ fiberCurrent = Fiber::getCurrent ();
171+
172+ if ($ fiberCurrent !== null )
173+ {
174+ $ fiberCurrent ::suspend ();
175+ }
176+ }
177+
178+ public static function getStatus (string |int $ name ): StatusThread |null
179+ {
180+ return self ::$ status [$ name ] ?? null ;
181+ }
182+
183+ }
0 commit comments