Compare commits

..

514 Commits

Author SHA1 Message Date
as2252258 526256302d eee 2024-09-04 10:14:31 +08:00
as2252258 95254ac300 eee 2024-09-04 10:07:59 +08:00
as2252258 fdf7757b6a eee 2024-09-03 15:05:19 +08:00
as2252258 6e4a045c7d eee 2024-09-03 14:47:30 +08:00
as2252258 03d16d8157 eee 2024-08-29 18:06:58 +08:00
as2252258 c8041cc09e eee 2024-08-29 17:01:09 +08:00
as2252258 976f67a838 eee 2024-05-01 02:06:14 +08:00
as2252258 c7e0cd4948 eee 2024-05-01 02:02:58 +08:00
as2252258 3fc1b16f33 eee 2024-04-15 15:39:31 +08:00
as2252258 103b757a05 eee 2024-04-15 15:39:03 +08:00
as2252258 b52270ff25 eee 2024-01-10 17:52:18 +08:00
as2252258 c0aa9acb19 eee 2024-01-10 17:49:50 +08:00
as2252258 89678aab1a eee 2023-12-21 14:03:24 +08:00
as2252258 fa0afbfe18 eee 2023-12-19 14:31:41 +08:00
as2252258 9fe3a0be29 eee 2023-12-13 21:01:59 +08:00
as2252258 c425543491 eee 2023-12-13 19:25:04 +08:00
as2252258 37270e8e65 eee 2023-12-13 19:23:24 +08:00
as2252258 299def8f02 eee 2023-12-13 19:22:39 +08:00
as2252258 d0241e987f eee 2023-12-13 19:19:18 +08:00
as2252258 85ceb901bd eee 2023-12-13 19:18:05 +08:00
as2252258 3ffb60e78f eee 2023-12-13 19:13:53 +08:00
as2252258 bca45371bc eee 2023-12-13 19:13:37 +08:00
as2252258 42be87dc37 eee 2023-12-13 19:04:22 +08:00
as2252258 84c253a9f6 eee 2023-12-12 15:35:38 +08:00
as2252258 827fb257ab eee 2023-12-12 14:10:09 +08:00
as2252258 10f24b60d6 eee 2023-12-12 14:09:11 +08:00
as2252258 279173cee8 eee 2023-12-12 14:08:20 +08:00
as2252258 50a4aad871 eee 2023-12-12 14:08:01 +08:00
as2252258 dc4b2ec8ca eee 2023-12-12 10:56:44 +08:00
as2252258 2add68b33a eee 2023-12-12 10:16:28 +08:00
as2252258 9a5384e3ef eee 2023-12-01 22:57:25 +08:00
as2252258 5adac967a0 eee 2023-12-01 11:35:50 +08:00
as2252258 4211f27d88 eee 2023-12-01 10:19:53 +08:00
as2252258 3c72ca7175 eee 2023-11-30 18:09:06 +08:00
as2252258 5e2862926a eee 2023-11-30 18:06:45 +08:00
as2252258 49b3085ab1 eee 2023-11-30 18:03:48 +08:00
as2252258 b74426a40c eee 2023-11-30 17:54:42 +08:00
as2252258 91e986e613 eee 2023-11-30 17:48:11 +08:00
as2252258 b25987c865 eee 2023-11-30 17:46:50 +08:00
as2252258 aa9d25d4ee eee 2023-11-30 17:30:46 +08:00
as2252258 fa562b9487 eee 2023-11-30 17:10:37 +08:00
as2252258 66ef753b67 eee 2023-11-30 17:02:21 +08:00
as2252258 c29362be7c eee 2023-11-29 15:02:48 +08:00
as2252258 d209804005 eee 2023-11-29 14:57:02 +08:00
as2252258 63b3f5df26 eee 2023-11-29 14:55:05 +08:00
as2252258 93a3a06963 eee 2023-11-29 14:18:09 +08:00
as2252258 5cb7fb73c6 eee 2023-11-29 14:08:37 +08:00
as2252258 6a9114fd9a eee 2023-11-25 17:46:47 +08:00
as2252258 b3fd42d076 eee 2023-11-24 10:46:45 +08:00
as2252258 ea13b67364 eee 2023-11-24 10:23:28 +08:00
as2252258 6b9195476a eee 2023-11-24 10:22:56 +08:00
as2252258 396248e41e eee 2023-11-23 16:33:06 +08:00
as2252258 d30df26cc8 eee 2023-11-23 16:21:57 +08:00
as2252258 5ed5ee5ca9 eee 2023-11-16 23:50:06 +08:00
as2252258 a0354a9d94 eee 2023-11-16 23:01:59 +08:00
as2252258 a7c3acce27 eee 2023-11-16 21:13:41 +08:00
as2252258 646ed19ded eee 2023-11-16 21:13:17 +08:00
as2252258 06e2b8a380 eee 2023-11-16 21:00:34 +08:00
as2252258 6cd9377866 eee 2023-11-10 14:01:37 +08:00
as2252258 781ebe1704 eee 2023-11-10 10:44:26 +08:00
as2252258 345d02e310 eee 2023-11-09 20:31:01 +08:00
as2252258 ce067c67d1 eee 2023-11-09 20:00:06 +08:00
as2252258 9c3c1cfd82 eee 2023-10-24 17:22:32 +08:00
as2252258 9c2a349242 eee 2023-10-18 10:58:25 +08:00
as2252258 575c728bdc eee 2023-10-17 21:27:47 +08:00
as2252258 67cf863c38 eee 2023-10-12 00:15:53 +08:00
as2252258 20a8b32cdf eee 2023-10-11 13:14:37 +08:00
as2252258 837f597342 eee 2023-10-08 23:43:01 +08:00
as2252258 7f129b2107 eee 2023-10-07 20:50:40 +08:00
as2252258 21d79dec0b eee 2023-09-15 16:45:09 +08:00
as2252258 6d98bcb9b2 eee 2023-09-15 16:44:48 +08:00
as2252258 41ac60fd17 eee 2023-09-15 15:58:24 +08:00
as2252258 aecf830211 eee 2023-09-13 16:59:26 +08:00
as2252258 b32a751231 eee 2023-08-29 15:23:39 +08:00
as2252258 26fc76caa0 eee 2023-08-29 01:09:57 +08:00
as2252258 9b4f5d59dc r 2023-08-28 12:01:30 +08:00
as2252258 4a607a5687 qqq 2023-08-25 09:37:59 +08:00
as2252258 28a484ee42 qqq 2023-08-24 16:22:09 +08:00
as2252258 5fdd35c4d5 qqq 2023-08-24 13:49:58 +08:00
as2252258 cf39ea4ad6 qqq 2023-08-24 12:01:34 +08:00
as2252258 07e077cba0 qqq 2023-08-24 11:39:54 +08:00
as2252258 3b51cc83ca qqq 2023-08-24 11:36:56 +08:00
as2252258 0d5bad7186 qqq 2023-08-18 21:44:32 +08:00
as2252258 797cb94716 qqq 2023-08-18 20:57:30 +08:00
as2252258 bfa5e350f8 qqq 2023-08-18 20:56:45 +08:00
as2252258 7f4e4c9757 qqq 2023-08-18 14:37:47 +08:00
as2252258 483dd6bc79 qqq 2023-08-17 15:52:02 +08:00
as2252258 62fb7a2278 qqq 2023-08-17 15:50:08 +08:00
as2252258 1406a76b6b qqq 2023-08-17 15:48:23 +08:00
as2252258 bf822fe449 qqq 2023-08-17 15:41:19 +08:00
as2252258 6ec1b8c202 qqq 2023-08-16 15:01:45 +08:00
as2252258 1cfdbd3e5d qqq 2023-08-16 12:34:11 +08:00
as2252258 4711a999f0 qqq 2023-08-16 12:32:42 +08:00
as2252258 529ae9c40c qqq 2023-08-16 12:32:32 +08:00
as2252258 58797cb20f qqq 2023-08-16 12:30:12 +08:00
as2252258 0360a9664c qqq 2023-08-16 12:00:11 +08:00
as2252258 12f8bc338e qqq 2023-08-16 10:38:59 +08:00
as2252258 a8b326437c qqq 2023-08-16 10:38:24 +08:00
as2252258 4b04a53578 qqq 2023-08-16 10:35:37 +08:00
as2252258 c30f82e468 qqq 2023-08-16 10:32:53 +08:00
as2252258 0aa6f7ac5a qqq 2023-08-16 10:26:48 +08:00
as2252258 b3f22240b0 qqq 2023-08-16 01:01:48 +08:00
as2252258 cd26b26d1d qqq 2023-08-16 00:55:05 +08:00
as2252258 c392460dd7 qqq 2023-08-16 00:45:04 +08:00
as2252258 1690fa4d44 qqq 2023-08-16 00:43:40 +08:00
as2252258 f433cff03d qqq 2023-08-16 00:34:06 +08:00
as2252258 e5e2c2ea74 qqq 2023-08-16 00:16:16 +08:00
as2252258 2c46a752f9 qqq 2023-08-16 00:01:52 +08:00
as2252258 0b29e15af6 qqq 2023-08-15 23:50:34 +08:00
as2252258 08e6f5c29f qqq 2023-08-15 16:06:50 +08:00
as2252258 a81dd74257 qqq 2023-08-14 23:21:05 +08:00
as2252258 db5fa33f61 qqq 2023-08-14 22:59:53 +08:00
as2252258 ee907ce498 qqq 2023-08-14 22:10:38 +08:00
as2252258 676f0ce1e6 qqq 2023-08-14 22:01:43 +08:00
as2252258 4850748c77 qqq 2023-08-14 21:40:02 +08:00
as2252258 5aa6291ae3 qqq 2023-08-14 21:35:23 +08:00
as2252258 baeb3a5521 qqq 2023-08-14 21:11:47 +08:00
as2252258 513690e9a3 qqq 2023-08-14 21:09:45 +08:00
as2252258 754998830c qqq 2023-08-14 14:14:40 +08:00
as2252258 00444a4c0d qqq 2023-08-11 14:02:51 +08:00
as2252258 e61ded6ef5 qqq 2023-08-11 10:10:45 +08:00
as2252258 5ce21ec2f5 qqq 2023-08-11 09:47:33 +08:00
as2252258 94ff383a86 qqq 2023-08-11 09:40:06 +08:00
as2252258 2c21e5c2fe qqq 2023-08-11 00:12:33 +08:00
as2252258 69473a349e qqq 2023-08-03 14:02:07 +08:00
as2252258 f3e90725cc qqq 2023-08-02 14:44:22 +08:00
as2252258 a99c50a116 qqq 2023-08-02 13:03:07 +08:00
as2252258 714745f649 qqq 2023-08-02 12:49:02 +08:00
as2252258 1928ddd350 qqq 2023-08-02 12:48:39 +08:00
as2252258 dcc13945a2 qqq 2023-08-02 12:47:41 +08:00
as2252258 33aec3582e qqq 2023-08-02 12:46:22 +08:00
as2252258 5f9c08984c qqq 2023-08-02 12:45:58 +08:00
as2252258 cee99fc39e qqq 2023-08-02 12:44:23 +08:00
as2252258 2e0efd6044 qqq 2023-08-02 12:42:56 +08:00
as2252258 cb2fd761a3 qqq 2023-08-02 12:40:57 +08:00
as2252258 dfa3ab413b qqq 2023-08-02 12:37:57 +08:00
as2252258 c541ecb96d qqq 2023-08-02 12:37:18 +08:00
as2252258 7da1e91f5e qqq 2023-08-02 12:34:28 +08:00
as2252258 a46e66c022 qqq 2023-08-02 12:33:38 +08:00
as2252258 e86464c3c2 qqq 2023-08-02 12:32:21 +08:00
as2252258 28e519d937 qqq 2023-08-02 12:30:22 +08:00
as2252258 9bd463cbd1 qqq 2023-08-02 10:30:37 +08:00
as2252258 29f821f026 qqq 2023-07-31 23:18:08 +08:00
as2252258 0fbb08ed58 qqq 2023-07-31 23:09:00 +08:00
as2252258 c062a8f6a3 qqq 2023-07-26 17:26:47 +08:00
as2252258 8d4dd1bda9 qqq 2023-07-26 16:45:28 +08:00
as2252258 2004391c9b qqq 2023-07-20 17:12:31 +08:00
as2252258 0b1be47fb6 qqq 2023-07-20 15:01:24 +08:00
as2252258 221183e196 qqq 2023-07-13 09:02:45 +08:00
as2252258 9f218a59a2 qqq 2023-07-10 02:06:01 +08:00
as2252258 a9ad66dc2e qqq 2023-07-10 02:05:44 +08:00
as2252258 6ea25f35a4 qqq 2023-07-10 02:04:49 +08:00
as2252258 d093dd7f57 qqq 2023-07-06 17:21:32 +08:00
as2252258 460818a50a qqq 2023-07-06 16:53:53 +08:00
as2252258 8fa9d7235f qqq 2023-07-06 15:29:32 +08:00
as2252258 95915678c3 qqq 2023-07-06 13:33:50 +08:00
as2252258 c22d7a36a0 qqq 2023-06-27 16:29:10 +08:00
as2252258 f641cb9b82 qqq 2023-05-26 18:26:46 +08:00
as2252258 74ebcbe630 qqq 2023-05-26 11:21:36 +08:00
as2252258 5b27d5c07e qqq 2023-05-26 11:16:45 +08:00
as2252258 37bbb14fdb qqq 2023-05-26 10:39:31 +08:00
as2252258 13cc75765b qqq 2023-05-26 10:30:23 +08:00
as2252258 fff3211e61 qqq 2023-05-26 10:26:13 +08:00
as2252258 a1c0da9688 qqq 2023-05-26 10:16:22 +08:00
as2252258 3c933d8e4f qqq 2023-05-26 10:08:39 +08:00
as2252258 2ddfdc1db4 qqq 2023-05-26 10:06:37 +08:00
as2252258 1f986439b2 qqq 2023-05-26 09:37:56 +08:00
as2252258 d7fd23800b qqq 2023-05-26 09:20:31 +08:00
as2252258 0f1a55462e qqq 2023-05-25 16:59:20 +08:00
as2252258 3016bb54f1 qqq 2023-05-20 22:59:07 +08:00
as2252258 93fa562e2d 变更 2023-04-23 18:34:14 +08:00
as2252258 e7c4ba752b 变更 2023-04-22 02:28:26 +08:00
as2252258 7f7ed83bba 变更 2023-04-21 17:50:33 +08:00
as2252258 e4b28f7679 变更 2023-04-19 21:39:55 +08:00
as2252258 7ff9c2b78e 变更 2023-04-19 15:38:08 +08:00
as2252258 97e1ab470a 变更 2023-04-19 15:35:57 +08:00
as2252258 a0b13362de 变更 2023-04-19 13:15:21 +08:00
as2252258 a3f2168f3a 变更 2023-04-19 12:41:41 +08:00
as2252258 84fa24e194 变更 2023-04-19 12:35:39 +08:00
as2252258 b2066bfad7 变更 2023-04-19 10:51:08 +08:00
as2252258 be6953b83f 变更 2023-04-19 10:39:28 +08:00
as2252258 c9eab465ea 变更 2023-04-19 10:32:55 +08:00
as2252258 e451efad4f 变更 2023-04-19 00:03:18 +08:00
as2252258 50b57d1fac 变更 2023-04-19 00:01:12 +08:00
as2252258 b8cc600ae6 变更 2023-04-18 23:59:29 +08:00
as2252258 af284dbe4b 变更 2023-04-18 23:47:31 +08:00
as2252258 88c2c430c6 变更 2023-04-18 23:24:33 +08:00
as2252258 e3d990077d 变更 2023-04-17 10:19:00 +08:00
as2252258 00b6d28196 变更 2023-04-17 01:39:32 +08:00
as2252258 a0cd1182c1 变更 2023-04-17 01:29:43 +08:00
as2252258 ac2f2654a3 变更 2023-04-17 00:41:30 +08:00
as2252258 3b92bdb3ea 变更 2023-04-17 00:33:52 +08:00
as2252258 6d47eb377d 变更 2023-04-17 00:30:28 +08:00
as2252258 a475e3a396 变更 2023-04-16 17:15:05 +08:00
as2252258 b782fae562 变更 2023-04-16 16:40:45 +08:00
as2252258 289ffee605 变更 2023-04-16 14:41:21 +08:00
as2252258 b29e8eb893 变更 2023-04-16 14:21:55 +08:00
as2252258 5f53ab9d7d 变更 2023-04-16 13:47:32 +08:00
as2252258 3bfa88b4d8 变更 2023-04-16 13:36:36 +08:00
as2252258 ae48aca021 变更 2023-04-16 13:26:19 +08:00
as2252258 e307494a53 变更 2023-04-16 02:51:27 +08:00
as2252258 a660e1c08e 变更 2023-04-16 02:46:54 +08:00
as2252258 656038dc7d 变更 2023-04-16 02:21:25 +08:00
as2252258 641144bd66 变更 2023-04-16 02:18:22 +08:00
as2252258 9389386030 变更 2023-04-16 02:15:51 +08:00
as2252258 4eb7e6142b 变更 2023-04-16 02:05:36 +08:00
as2252258 fef9f27c2d 变更 2023-04-16 02:01:27 +08:00
as2252258 989ec6ed03 变更 2023-04-16 01:56:54 +08:00
as2252258 12f61a5bb5 变更 2023-04-16 01:54:43 +08:00
as2252258 3aab5da74f 变更 2023-04-16 01:50:47 +08:00
as2252258 11c21f01a2 变更 2023-04-16 01:45:34 +08:00
as2252258 46baac8bbd 变更 2023-04-16 01:24:30 +08:00
as2252258 cdd8644419 变更 2023-04-16 00:59:56 +08:00
as2252258 becf0bf249 变更 2023-04-16 00:59:31 +08:00
as2252258 a10d597e7e 变更 2023-04-16 00:15:10 +08:00
as2252258 12ab8b5f88 变更 2023-04-15 23:32:00 +08:00
as2252258 c825fd0d94 变更 2023-04-11 23:49:01 +08:00
as2252258 e62d83b62b 变更 2023-04-11 14:15:14 +08:00
as2252258 1c3ef9b361 变更 2023-04-11 14:00:45 +08:00
as2252258 7a2ffac535 变更 2023-04-11 13:42:33 +08:00
as2252258 87e91ad850 变更 2023-04-07 00:11:29 +08:00
as2252258 21de24af6a 变更 2023-04-07 00:05:01 +08:00
as2252258 df76dcaa54 变更 2023-04-06 23:00:58 +08:00
as2252258 b7bcdc2096 变更 2023-04-06 22:39:32 +08:00
as2252258 99b01b7f78 变更 2023-04-06 22:15:33 +08:00
as2252258 a5b473956d 变更 2023-04-06 17:08:47 +08:00
as2252258 4e7ef150a3 变更 2023-04-05 21:54:01 +08:00
as2252258 00ee4651b9 变更 2023-04-05 19:58:07 +08:00
as2252258 fab3779116 变更 2023-04-05 15:22:01 +08:00
as2252258 b0bebb81ca 变更 2023-04-05 15:05:22 +08:00
as2252258 b4d6c66ed3 变更 2023-04-05 14:59:13 +08:00
as2252258 133e63a96f 变更 2023-04-05 14:53:08 +08:00
as2252258 49ecd46ef3 变更 2023-04-05 14:49:52 +08:00
as2252258 02df2c7432 变更 2023-04-05 14:42:26 +08:00
as2252258 4b09fbdadd 变更 2023-04-05 14:12:57 +08:00
as2252258 2d190b5103 变更 2023-04-05 14:09:46 +08:00
as2252258 eb931b5fd4 变更 2023-04-05 13:55:56 +08:00
as2252258 419dfb6e0b 变更 2023-04-05 13:54:36 +08:00
as2252258 417b8b3927 变更 2023-04-05 12:35:18 +08:00
as2252258 1f145e9d24 变更 2023-04-05 11:40:48 +08:00
as2252258 03b43ba4ac 变更 2023-04-05 11:39:15 +08:00
as2252258 c1c3ab71ba 变更 2023-04-05 11:32:56 +08:00
as2252258 d8863f79a7 变更 2023-04-05 11:17:55 +08:00
as2252258 5d2ffd3aa6 变更 2023-04-05 11:04:54 +08:00
as2252258 ebc46f6323 变更 2023-04-05 10:55:30 +08:00
as2252258 8f925a1e6c 变更 2023-04-05 10:50:17 +08:00
as2252258 cf0376d5e1 变更 2023-04-05 10:24:58 +08:00
as2252258 77dd313b12 变更 2023-04-04 15:21:20 +08:00
as2252258 bc98a865af 变更 2023-04-04 15:15:30 +08:00
as2252258 0c2a419d0b 变更 2023-04-04 13:46:01 +08:00
as2252258 68e225c3b4 变更 2023-04-03 14:03:46 +08:00
as2252258 05c1a159c1 变更 2023-04-03 14:02:56 +08:00
as2252258 ebe679914d 变更 2023-04-03 13:56:46 +08:00
as2252258 fb84e7cebd 变更 2023-04-03 13:55:24 +08:00
as2252258 c9637f2dd3 变更 2023-04-03 13:54:09 +08:00
as2252258 ac588a6f6f 变更 2023-04-03 13:45:59 +08:00
as2252258 7d574e9172 变更 2023-04-03 11:08:11 +08:00
as2252258 709e35f4dc 变更 2023-04-03 00:56:22 +08:00
as2252258 00efca071f 变更 2023-04-03 00:43:25 +08:00
as2252258 d1cd8b0d5c 变更 2023-04-03 00:43:06 +08:00
as2252258 9b331798fb 变更 2023-04-03 00:24:51 +08:00
as2252258 fb851bbfc1 变更 2023-04-03 00:14:29 +08:00
as2252258 dcf4de9900 变更 2023-04-02 23:23:55 +08:00
as2252258 4afa0064e9 变更 2023-04-02 00:58:35 +08:00
as2252258 eb880adf57 变更 2023-04-02 00:50:42 +08:00
as2252258 b4e9e204bc 变更 2023-04-02 00:34:55 +08:00
as2252258 437e52896e 变更 2023-04-02 00:28:17 +08:00
as2252258 8d27725583 变更 2023-04-02 00:16:25 +08:00
as2252258 314bc98044 变更 2023-04-02 00:09:07 +08:00
as2252258 93804a751a 变更 2023-04-02 00:05:19 +08:00
as2252258 779c13f25a 变更 2023-04-01 01:02:14 +08:00
as2252258 a659375e1f 变更 2023-03-31 23:44:16 +08:00
as2252258 0fa38df2c9 变更 2023-03-31 23:36:08 +08:00
as2252258 d7060dd82e 变更 2023-03-31 11:08:21 +08:00
as2252258 fdbf891fad 变更 2023-03-31 10:37:15 +08:00
as2252258 8cfcb18d6a 变更 2023-03-31 10:31:51 +08:00
as2252258 8f1d367484 变更 2023-03-31 10:30:39 +08:00
as2252258 bb41e1052f 变更 2023-03-30 23:10:14 +08:00
as2252258 592015e3ee 变更 2023-03-30 18:24:05 +08:00
as2252258 00f934c0d5 变更 2023-02-13 14:37:07 +08:00
as2252258 86e3ac485c 变更 2023-02-13 14:35:00 +08:00
as2252258 adffcf1852 变更 2023-02-13 14:23:29 +08:00
as2252258 da361fcca2 变更 2023-02-07 17:46:41 +08:00
as2252258 17fd230ebb 变更 2023-02-07 17:19:31 +08:00
as2252258 d83f061a1c 变更 2023-02-07 17:16:10 +08:00
as2252258 4f341594b5 变更 2023-02-07 16:46:13 +08:00
as2252258 a9472ff0a3 变更 2023-01-30 11:03:58 +08:00
as2252258 b7229f32f8 变更 2022-12-13 14:23:06 +08:00
as2252258 4a4bf7b5cb 变更 2022-12-12 17:31:12 +08:00
as2252258 eef386d6c8 变更 2022-10-12 15:03:12 +08:00
as2252258 5bfe8401f5 变更 2022-10-11 18:55:06 +08:00
as2252258 268f8665d0 变更 2022-10-11 18:28:33 +08:00
as2252258 ceefabb8e4 变更 2022-10-11 18:20:47 +08:00
as2252258 81c8f8f50e 变更 2022-10-11 18:00:22 +08:00
as2252258 090f51f624 变更 2022-10-11 17:55:03 +08:00
as2252258 0b179f9739 变更 2022-10-11 17:35:42 +08:00
as2252258 af60e61c5c 变更 2022-10-11 17:33:00 +08:00
as2252258 5d9014acc3 变更 2022-10-11 16:03:56 +08:00
as2252258 9d5ab6e80e 变更 2022-10-11 15:58:20 +08:00
as2252258 52624c4542 变更 2022-10-11 15:51:01 +08:00
as2252258 5d0c019bd5 Merge branch 'master' of github.com:as2252258/kiri-core 2022-10-11 15:37:01 +08:00
as2252258 7824a7cc7a 变更 2022-10-11 15:27:48 +08:00
as2252258 45aa4c5d92 变更 2022-10-11 15:19:48 +08:00
as2252258 6898e544f7 变更 2022-10-11 15:15:04 +08:00
as2252258 3dd5311430 变更 2022-10-11 14:33:33 +08:00
as2252258 8d8033027d 变更 2022-09-29 23:51:17 +08:00
as2252258 d8eae58bfd 变更 2022-09-29 23:49:33 +08:00
as2252258 530f2ea98d 变更 2022-09-29 23:49:07 +08:00
as2252258 6039ca70c5 变更 2022-09-29 23:06:08 +08:00
as2252258 bc2275300d 变更 2022-09-26 11:04:28 +08:00
as2252258 6485b8ca22 变更 2022-09-25 17:22:51 +08:00
as2252258 dbc7cc2dfa 变更 2022-09-25 17:22:25 +08:00
as2252258 d960f518be 变更 2022-09-25 17:16:40 +08:00
as2252258 eda1955956 变更 2022-09-25 17:15:23 +08:00
as2252258 354013fa41 变更 2022-09-25 04:38:27 +08:00
as2252258 f63f480e57 变更 2022-09-24 14:27:42 +08:00
as2252258 c2daafed59 变更 2022-09-24 14:24:02 +08:00
as2252258 64dbdf57c1 变更 2022-09-24 14:22:36 +08:00
as2252258 8e7832912d 变更 2022-09-24 13:39:06 +08:00
as2252258 e0795595e7 变更 2022-09-23 19:00:53 +08:00
as2252258 f5e7fcf51f 变更 2022-09-23 18:59:35 +08:00
as2252258 98fae744c0 变更 2022-09-23 18:55:46 +08:00
as2252258 d909aa4c4e 变更 2022-09-20 18:53:49 +08:00
as2252258 d520b5fbc4 变更 2022-09-20 18:23:19 +08:00
as2252258 2ce699faa7 变更 2022-09-19 18:51:30 +08:00
as2252258 709e40fc28 变更 2022-09-19 18:45:22 +08:00
as2252258 15214aa07e 变更 2022-09-19 18:39:28 +08:00
as2252258 9bf6d000ed 变更 2022-09-19 18:24:12 +08:00
as2252258 9b873479ac 变更 2022-09-08 11:38:00 +08:00
as2252258 e45fbef80a 变更 2022-09-08 11:31:12 +08:00
as2252258 ca24cb9e58 变更 2022-09-07 13:51:11 +08:00
as2252258 92024adb53 变更 2022-09-05 18:56:20 +08:00
as2252258 6a3aa12f1d 变更 2022-09-05 18:53:36 +08:00
as2252258 24322a411a 变更 2022-09-05 18:47:20 +08:00
as2252258 623f0362fd 变更 2022-09-05 18:42:53 +08:00
as2252258 4ea5945101 变更 2022-09-05 18:41:37 +08:00
as2252258 4b5d9b6486 变更 2022-09-05 18:39:03 +08:00
as2252258 7e02cc582c 变更 2022-09-05 18:34:35 +08:00
as2252258 14080f7e30 变更 2022-09-05 18:32:27 +08:00
as2252258 b764ced6fa 变更 2022-09-05 18:28:44 +08:00
as2252258 85d19dcccf 变更 2022-09-05 18:17:31 +08:00
as2252258 ac6c9af6d9 变更 2022-09-05 18:14:07 +08:00
as2252258 6a6f14b7a3 变更 2022-09-05 18:11:26 +08:00
as2252258 6e21c3b5ab 变更 2022-09-05 18:09:01 +08:00
as2252258 843abbeaa6 modify plugin name 2022-07-11 18:53:19 +08:00
as2252258 7e409968be modify plugin name 2022-07-11 18:33:25 +08:00
as2252258 211905278b modify plugin name 2022-07-11 17:51:41 +08:00
as2252258 d80d4af8c5 modify plugin name 2022-07-11 17:35:45 +08:00
as2252258 a03d076299 modify plugin name 2022-07-11 17:28:41 +08:00
as2252258 150cdbbbfa modify plugin name 2022-07-11 17:05:32 +08:00
as2252258 cd509b2663 modify plugin name 2022-07-11 16:54:24 +08:00
as2252258 0705eefd69 modify plugin name 2022-07-11 16:49:32 +08:00
as2252258 d2c42c8553 modify plugin name 2022-07-11 16:34:13 +08:00
as2252258 a55944a285 modify plugin name 2022-07-11 16:33:46 +08:00
as2252258 cba75d419d modify plugin name 2022-07-11 16:21:51 +08:00
as2252258 f77374519e modify plugin name 2022-07-11 16:09:58 +08:00
as2252258 52c6ee7053 modify plugin name 2022-07-11 14:50:33 +08:00
as2252258 3c3e7f900b modify plugin name 2022-07-11 14:49:47 +08:00
as2252258 e39a63523e 变更 2022-07-10 01:19:10 +08:00
as2252258 983722d22f 变更 2022-07-10 00:15:37 +08:00
as2252258 e54ac1ed39 变更 2022-07-09 23:48:01 +08:00
as2252258 912738ae1c modify plugin name 2022-07-08 18:38:19 +08:00
as2252258 d48d0d81c7 modify plugin name 2022-07-08 18:33:51 +08:00
as2252258 838847bd78 modify plugin name 2022-07-08 17:46:42 +08:00
as2252258 d50f99e144 Merge remote-tracking branch 'origin/master' 2022-07-08 17:44:19 +08:00
as2252258 7c26dff45e modify plugin name 2022-07-08 17:43:51 +08:00
as2252258 dfe62ef592 变更 2022-06-30 16:40:48 +08:00
as2252258 d2dd255c90 modify plugin name 2022-06-24 15:07:46 +08:00
as2252258 93ae880902 modify plugin name 2022-06-23 13:44:32 +08:00
as2252258 7077095f7a 变更 2022-06-23 00:32:41 +08:00
as2252258 b2dfedfe63 modify plugin name 2022-06-22 19:05:08 +08:00
as2252258 0b70d9109c modify plugin name 2022-06-22 19:02:30 +08:00
as2252258 f729233ffd modify plugin name 2022-06-22 19:01:44 +08:00
as2252258 8deff8743a modify plugin name 2022-06-22 18:55:30 +08:00
as2252258 71c1d8c9d3 modify plugin name 2022-06-22 18:28:46 +08:00
as2252258 8630d79519 modify plugin name 2022-06-22 16:57:11 +08:00
as2252258 f595f1146e modify plugin name 2022-06-22 16:50:37 +08:00
as2252258 77087baed9 modify plugin name 2022-06-22 16:42:10 +08:00
as2252258 5c91717d84 modify plugin name 2022-06-22 16:39:05 +08:00
as2252258 60003c4527 modify plugin name 2022-06-22 16:37:03 +08:00
as2252258 38f00206eb modify plugin name 2022-06-22 16:29:42 +08:00
as2252258 f139f32c85 modify plugin name 2022-06-22 10:53:59 +08:00
as2252258 f20e695919 modify plugin name 2022-06-20 17:25:02 +08:00
as2252258 4a7d4165f8 modify plugin name 2022-06-17 19:00:56 +08:00
as2252258 b515f04c97 modify plugin name 2022-06-17 15:02:31 +08:00
as2252258 287dc99362 modify plugin name 2022-06-17 14:30:31 +08:00
as2252258 824dd399db modify plugin name 2022-06-17 14:17:22 +08:00
as2252258 4419b7b237 modify plugin name 2022-06-17 14:07:16 +08:00
as2252258 3e609a48ef modify plugin name 2022-06-17 14:04:35 +08:00
as2252258 85277cd277 modify plugin name 2022-06-17 14:04:23 +08:00
as2252258 4927294b9e modify plugin name 2022-06-17 12:14:17 +08:00
as2252258 0535d6fd7f modify plugin name 2022-06-17 12:09:07 +08:00
as2252258 92b5b248a3 modify plugin name 2022-06-17 11:59:19 +08:00
as2252258 0a70a95b63 modify plugin name 2022-06-16 18:49:34 +08:00
as2252258 a79a469547 modify plugin name 2022-06-16 18:47:38 +08:00
as2252258 4daad7d111 modify plugin name 2022-06-16 17:38:23 +08:00
as2252258 10de6b5246 debug alter 2022-06-08 16:20:22 +08:00
as2252258 d1b870a8ca modify plugin name 2022-06-08 16:19:15 +08:00
as2252258 1955e73881 modify plugin name 2022-06-08 16:13:16 +08:00
as2252258 8b7dc42185 modify plugin name 2022-06-08 16:02:32 +08:00
as2252258 751168b2de modify plugin name 2022-06-08 16:00:54 +08:00
as2252258 8681a23919 modify plugin name 2022-06-08 15:50:50 +08:00
as2252258 80fd889ae4 modify plugin name 2022-06-08 14:08:32 +08:00
as2252258 def499c2f6 变更 2022-05-03 06:56:28 +08:00
as2252258 ab2ec0f790 s 2022-03-17 10:43:50 +08:00
as2252258 ffc9b57cad e 2022-03-17 10:42:50 +08:00
as2252258 734db55904 modify plugin name 2022-03-17 10:35:37 +08:00
as2252258 864c8fa84c modify plugin name 2022-03-16 18:08:49 +08:00
as2252258 4f5c63e222 modify plugin name 2022-03-16 18:06:59 +08:00
as2252258 bab0512dd6 modify plugin name 2022-03-04 17:36:12 +08:00
as2252258 4af173deff modify plugin name 2022-03-03 18:30:59 +08:00
as2252258 9cd44aad3d modify plugin name 2022-03-03 17:25:47 +08:00
as2252258 4f5fba5ce4 modify plugin name 2022-03-02 18:30:11 +08:00
as2252258 66dc6de141 modify plugin name 2022-03-02 18:20:49 +08:00
as2252258 c3e914ecf1 modify plugin name 2022-03-02 17:25:12 +08:00
as2252258 7232269ad0 modify plugin name 2022-03-01 18:01:53 +08:00
as2252258 b601c4150b modify plugin name 2022-03-01 17:58:10 +08:00
as2252258 54e1ecd10f modify plugin name 2022-03-01 17:57:22 +08:00
as2252258 9c7d284e17 modify plugin name 2022-03-01 16:13:12 +08:00
as2252258 b1b22bf835 modify plugin name 2022-03-01 15:13:54 +08:00
as2252258 35239ed0dc modify plugin name 2022-03-01 15:08:15 +08:00
as2252258 a89061c90c modify plugin name 2022-03-01 15:05:50 +08:00
as2252258 1570239840 modify plugin name 2022-03-01 14:23:36 +08:00
as2252258 875cbe08db modify plugin name 2022-03-01 14:19:48 +08:00
as2252258 0b9d570871 modify plugin name 2022-03-01 14:08:38 +08:00
as2252258 a465d2f489 modify plugin name 2022-02-28 14:40:13 +08:00
as2252258 6e7fe74130 modify plugin name 2022-02-28 10:31:44 +08:00
as2252258 eab01dee1b modify plugin name 2022-02-28 10:29:20 +08:00
as2252258 7ac19eb76b modify plugin name 2022-02-28 10:24:37 +08:00
as2252258 5ee6a6ab54 modify plugin name 2022-02-28 10:17:08 +08:00
as2252258 1c5279f7c7 modify plugin name 2022-02-28 10:13:27 +08:00
as2252258 aa598cfb4f modify plugin name 2022-02-27 18:35:58 +08:00
as2252258 2b1f5f3804 modify plugin name 2022-02-27 18:34:17 +08:00
as2252258 b7fe54451c modify plugin name 2022-02-27 18:29:57 +08:00
as2252258 e01a1cbb7b modify plugin name 2022-02-27 18:29:31 +08:00
as2252258 66a76c3fb1 modify plugin name 2022-02-27 18:26:57 +08:00
as2252258 69138a56e2 modify plugin name 2022-02-27 18:26:08 +08:00
as2252258 6bc1b9238e modify plugin name 2022-02-27 18:23:05 +08:00
as2252258 215b3ced71 modify plugin name 2022-02-27 18:21:47 +08:00
as2252258 696db2ec66 modify plugin name 2022-02-27 18:19:35 +08:00
as2252258 99250b3e03 modify plugin name 2022-02-27 17:32:38 +08:00
as2252258 adcabf4df6 modify plugin name 2022-02-27 15:31:21 +08:00
as2252258 635372cd83 modify plugin name 2022-02-27 15:29:23 +08:00
as2252258 513f947b28 modify plugin name 2022-02-25 19:00:06 +08:00
as2252258 c032120de0 modify plugin name 2022-02-25 18:59:58 +08:00
as2252258 632fe7569e modify plugin name 2022-02-25 18:58:40 +08:00
as2252258 bbd960899a modify plugin name 2022-02-25 18:37:49 +08:00
as2252258 37784a238a modify plugin name 2022-02-25 18:33:31 +08:00
as2252258 360347325e modify plugin name 2022-02-25 18:33:05 +08:00
as2252258 d67bbd69ca modify plugin name 2022-02-25 18:30:59 +08:00
as2252258 56c4f42b97 modify plugin name 2022-02-25 18:14:22 +08:00
as2252258 c0efa2f913 modify plugin name 2022-02-25 18:11:09 +08:00
as2252258 a71924dd37 modify plugin name 2022-02-25 18:00:55 +08:00
as2252258 ecddacb321 modify plugin name 2022-02-25 17:21:00 +08:00
as2252258 70271e3db4 modify plugin name 2022-02-25 15:54:57 +08:00
as2252258 7fd29e4982 modify plugin name 2022-02-25 15:42:02 +08:00
as2252258 b551e5e22c modify plugin name 2022-02-25 15:39:08 +08:00
as2252258 a0d62fdc01 modify plugin name 2022-02-25 10:25:29 +08:00
as2252258 867f76e058 modify plugin name 2022-02-24 16:58:37 +08:00
as2252258 457ae27528 modify plugin name 2022-02-24 15:24:29 +08:00
as2252258 dbfad195e3 modify plugin name 2022-02-24 13:55:23 +08:00
as2252258 d5293f28b7 modify plugin name 2022-02-24 13:53:03 +08:00
as2252258 f59e2870c0 modify plugin name 2022-02-24 13:51:44 +08:00
as2252258 698b0ad0ff modify plugin name 2022-02-24 11:00:01 +08:00
as2252258 8e4f345091 modify plugin name 2022-02-23 18:48:49 +08:00
as2252258 70a5a5ea59 modify plugin name 2022-02-23 18:20:14 +08:00
as2252258 689f1cc32a modify plugin name 2022-02-23 18:18:44 +08:00
as2252258 09dd2443c7 modify plugin name 2022-02-23 18:12:57 +08:00
as2252258 1cdb8aceac modify plugin name 2022-02-23 18:02:29 +08:00
as2252258 8bb593bf3e modify plugin name 2022-02-23 17:15:53 +08:00
as2252258 3bc08ec6d0 modify plugin name 2022-02-23 17:06:49 +08:00
as2252258 01694d39ae modify plugin name 2022-02-23 17:04:52 +08:00
as2252258 58f1eeb91c modify plugin name 2022-02-23 16:54:34 +08:00
as2252258 a0920dfb92 modify plugin name 2022-02-23 16:36:48 +08:00
as2252258 02c879442c modify plugin name 2022-02-23 16:35:41 +08:00
as2252258 99c824c467 modify plugin name 2022-02-23 16:32:08 +08:00
as2252258 fa66eef192 modify plugin name 2022-02-21 14:18:34 +08:00
as2252258 7564a8229f modify plugin name 2022-02-21 11:10:30 +08:00
as2252258 6dd4a036b0 modify plugin name 2022-02-21 11:02:10 +08:00
as2252258 f479f037f7 modify plugin name 2022-02-18 17:16:46 +08:00
as2252258 c59c564f32 modify plugin name 2022-02-18 15:57:18 +08:00
as2252258 7a331e36ad modify plugin name 2022-02-18 15:17:31 +08:00
as2252258 2e073ddbb2 modify plugin name 2022-02-18 15:16:41 +08:00
as2252258 064ca3f728 modify plugin name 2022-02-18 14:51:31 +08:00
as2252258 634b9223e0 modify plugin name 2022-02-18 14:45:59 +08:00
as2252258 7a6de074b9 modify plugin name 2022-02-18 13:45:30 +08:00
as2252258 eba7dc29b3 modify plugin name 2022-02-18 10:48:43 +08:00
as2252258 4887fb036c modify plugin name 2022-02-17 18:58:43 +08:00
as2252258 a5bb77a0ec modify plugin name 2022-02-17 18:52:03 +08:00
as2252258 59f3322635 modify plugin name 2022-02-17 18:50:14 +08:00
as2252258 2f540211c9 modify plugin name 2022-02-17 18:49:05 +08:00
as2252258 fcbdda6239 modify plugin name 2022-02-17 18:48:26 +08:00
as2252258 dca19bf88b modify plugin name 2022-02-17 18:45:59 +08:00
as2252258 04dabe755e modify plugin name 2022-02-17 18:45:32 +08:00
as2252258 3675a592c4 modify plugin name 2022-02-17 17:44:28 +08:00
as2252258 2d0f214a9f modify plugin name 2022-02-16 10:55:42 +08:00
as2252258 8cd3886494 modify plugin name 2022-02-16 10:38:58 +08:00
as2252258 a75561a415 modify plugin name 2022-02-15 17:19:06 +08:00
as2252258 106e84914d modify plugin name 2022-02-15 12:17:11 +08:00
as2252258 4f54e5bdf8 modify plugin name 2022-02-14 18:04:47 +08:00
as2252258 79ac0bd558 modify plugin name 2022-02-14 17:59:56 +08:00
as2252258 d36a359cc0 modify plugin name 2022-02-14 17:39:51 +08:00
as2252258 a36817e89c modify plugin name 2022-02-14 14:42:56 +08:00
as2252258 5b93689184 modify plugin name 2022-02-14 14:34:56 +08:00
as2252258 fce7551dc3 modify plugin name 2022-02-14 14:32:53 +08:00
as2252258 826dcb58e5 modify plugin name 2022-02-14 14:30:48 +08:00
as2252258 244ed0fded modify plugin name 2022-02-14 14:30:18 +08:00
as2252258 60e891b08c modify plugin name 2022-02-14 14:28:47 +08:00
as2252258 f42614ea5d modify plugin name 2022-02-14 13:34:54 +08:00
as2252258 a70c66cc99 modify plugin name 2022-02-14 10:23:43 +08:00
as2252258 c9a904f065 modify plugin name 2022-02-13 03:20:06 +08:00
as2252258 69a7735144 modify plugin name 2022-02-11 19:00:55 +08:00
as2252258 7b283e1c19 modify plugin name 2022-02-11 11:18:25 +08:00
as2252258 97a5b58d11 modify plugin name 2022-02-10 16:35:03 +08:00
118 changed files with 3473 additions and 10584 deletions
-1
View File
@@ -33,5 +33,4 @@ runtime/
oot
d
composer.lock
+6 -2
View File
@@ -5,14 +5,18 @@ namespace PHPSTORM_META {
// Reflect
use Kiri\Di\Container;
use Psr\Container\ContainerInterface;
use Psr\Container\ContainerInterface as SC;
use Psr\Http\Message\ServerRequestInterface;
override(ContainerInterface::get(0), map('@'));
override(ContainerInterface::get(0), map('@'));
override(SC::get(0), map('@'));
override(Container::get(0), map('@'));
override(Container::make(0), map('@'));
override(Container::create(0), map('@'));
// override(\Hyperf\Utils\Context::get(0), map('@'));
// override(\make(0), map('@'));
override(\make(0), map('@'));
override(\di(0), map('@'));
override(\duplicate(0), map('@'));
override(ServerRequestInterface::getAttribute(0), map('@'));
}
+216 -301
View File
@@ -5,26 +5,19 @@ declare(strict_types=1);
error_reporting(0);
use Database\Collection;
use Database\ModelInterface;
use JetBrains\PhpStorm\Pure;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Annotation;
use Kiri\Application;
use Kiri\Core\Json;
use Kiri\Di\Container;
use Kiri\Environmental;
use Psr\Container\ContainerInterface;
use Kiri\Error\StdoutLogger;
use Swoole\Coroutine;
use Swoole\Process;
use Swoole\WebSocket\Server;
defined('DB_ERROR_BUSY') or define('DB_ERROR_BUSY', 'The database is busy. Please try again later.');
defined('SELECT_IS_NULL') or define('SELECT_IS_NULL', 'Query data does not exist, please check the relevant conditions.');
defined('PARAMS_IS_NULL') or define('PARAMS_IS_NULL', 'Required items cannot be empty, please add.');
defined('CONTROLLER_PATH') or define('CONTROLLER_PATH', realpath(APP_PATH . 'controllers/'));
defined('MODEL_PATH') or define('MODEL_PATH', realpath(APP_PATH . 'models/'));
defined('CONTROLLER_PATH') or define('CONTROLLER_PATH', realpath(APP_PATH . 'app/Controller/'));
defined('MODEL_PATH') or define('MODEL_PATH', realpath(APP_PATH . 'app/Model/'));
defined('COMPONENT_PATH') or define('COMPONENT_PATH', realpath(APP_PATH . 'components/'));
defined('URL_MATCH') or define('URL_MATCH', '/(http[s]?:\/\/)?((?:[\w\-_]+\.)+\w+(?::\d+)?)(?:(\/[a-zA-Z0-9-\/]+)+[\/]?(\?[a-zA-Z]+=.*)?)?/');
/**
@@ -34,331 +27,253 @@ defined('COMPONENT_PATH') or define('COMPONENT_PATH', realpath(APP_PATH . 'compo
class Kiri
{
/** @var Container */
private static Container $container;
/**
* @return Container
*/
public static function getContainer(): Container
{
return Container::instance();
}
/** @var ?Application */
private static ?Application $service = null;
/**
* @return Container|null
*/
public static function getContainerContext(): ?Container
{
return static::getContainer();
}
/**
* @param $service
*
* 初始化服务
*/
public static function init($service)
{
static::$service = $service;
}
/**
* @param string|array $className
* @param array $construct
* @return mixed
* @throws
*/
public static function createObject(string|array $className, array $construct = []): mixed
{
$container = static::getContainer();
if (is_string($className) && class_exists($className)) {
$object = $container->get($className);
return self::configure($object, $construct);
} else if (is_array($className) && isset($className['class'])) {
$class = $className['class'];
unset($className['class']);
return $container->make($class, $construct, $className);
} else if (is_callable($className, TRUE)) {
return call_user_func($className, $construct);
} else {
throw new Exception('Unsupported configuration type: ' . gettype($className));
}
}
/**
* @param Container $container
*/
public static function setContainer(Container $container)
{
$container->setBindings(ContainerInterface::class, $container);
static::$container = $container;
}
/**
* @return \Kiri\Pool\Pool
* @throws
*/
public static function getPool(): \Kiri\Pool\Pool
{
return static::getDi()->get(\Kiri\Pool\Pool::class);
}
/**
* @return Container
*/
public static function getContainer(): Container
{
return static::$container;
}
/**
* @param $prefix
* @return void
*/
public static function setProcessName($prefix): void
{
if (Kiri::getPlatform()->isMac()) {
return;
}
$name = '[' . \config('id', 'system-service') . ']';
if (!empty($prefix)) {
$name .= '.' . $prefix;
}
swoole_set_process_name($name);
}
/**
* @param $alias
* @param array $array
* @throws Exception
*/
public static function set($alias, array $array = [])
{
static::app()->set($alias, $array);
}
/**
* @return string
* @throws
*/
public static function getStoragePath(): string
{
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
$path = \config('storage', $default);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
return $path;
}
/**
* @param string $name
* @return mixed
* @throws Exception
*/
public static function getApp(string $name): mixed
{
return static::app()->get($name);
}
/**
* @return Application|null
*/
public static function app(): ?Application
{
return static::$service;
}
/**
* @return Container
*/
public static function getDi(): Container
{
return static::getContainer();
}
/**
* @return Application|null
*/
public static function getFactory(): ?Application
{
return static::$service;
}
/**
* @return StdoutLogger
* @throws
*/
public static function getLogger(): StdoutLogger
{
return static::getContainer()->get(StdoutLogger::class);
}
/**
* @return Application|null
*/
public static function getApplicationContext(): ?Application
{
return static::$service;
}
/**
* @return bool
*/
public static function isDocker(): bool
{
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
if (trim($output) === 'yes') {
return true;
}
return false;
}
/**
* @return Container|null
*/
public static function getContainerContext(): ?Container
{
return static::$container;
}
/**
* @param $name
* @return bool
*/
public static function has($name): bool
{
return static::$service->has($name);
}
/**
* @param $fileName
* @param $content
* @param null $is_append
* @return int|bool
*/
public static function writeFile($fileName, $content, $is_append = null): int|bool
{
$params = [$fileName, (string)$content];
if ($is_append !== null) {
$params[] = $is_append;
}
return !(Coroutine::getCid() > 0) ? file_put_contents(...$params) : Coroutine::writeFile(...$params);
}
/**
* @return Annotation
* @throws Exception
*/
public static function getAnnotation(): Annotation
{
return static::app()->getAnnotation();
}
/**
* @param $object
* @param $config
* @return mixed
*/
public static function configure($object, $config): mixed
{
foreach ($config as $key => $value) {
if (!property_exists($object, $key)) {
continue;
}
$object->$key = $value;
}
return $object;
}
/**
* @param $className
* @param array $construct
* @return mixed
* @throws Exception
*/
public static function createObject($className, array $construct = []): mixed
{
if (is_string($className) && class_exists($className)) {
return static::$container->get($className, $construct);
} else if (is_array($className) && isset($className['class'])) {
$class = $className['class'];
unset($className['class']);
return static::$container->create($class, $construct, $className);
} else if (is_callable($className, TRUE)) {
return call_user_func($className, $construct);
} else {
throw new Exception('Unsupported configuration type: ' . gettype($className));
}
}
/**
* @return mixed
*/
public static function localhost(): mixed
{
return current(swoole_get_local_ip());
}
/**
* @return string
* @throws Exception
*/
public static function getStoragePath(): string
{
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
$path = Config::get('storage', $default);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
return $path;
}
/**
* @param array $v1
* @param array $v2
* @return float
*/
#[Pure] public static function distance(array $v1, array $v2): float
{
$maxX = max($v1['x'], $v2['x']);
$minX = min($v1['x'], $v2['x']);
$maxZ = max($v1['z'], $v2['z']);
$minZ = min($v1['z'], $v2['z']);
$dx = abs($maxX - $minX);
$dy = abs($maxZ - $minZ);
$sqrt = sqrt($dx * $dx + $dy * $dy);
if ($sqrt < 0) {
$sqrt = abs($sqrt);
}
return (float)$sqrt;
}
/**
* @return Container
*/
public static function getDi(): Container
{
return static::$container;
}
/**
* @param $tmp_name
* @return string
*/
public static function rename($tmp_name): string
{
$hash = md5_file($tmp_name);
$later = '.' . exif_imagetype($tmp_name);
$match = '/(\w{12})(\w{5})(\w{9})(\w{6})/';
$tmp = preg_replace($match, '$1-$2-$3-$4', $hash);
return strtoupper($tmp) . $later;
}
/**
* @return Container
*/
public static function di(): Container
{
return static::$container;
}
/**
* @return Environmental
* @throws
*/
public static function getPlatform(): Environmental
{
return Kiri::createObject(Environmental::class);
}
/**
* @return bool
*/
public static function isDocker(): bool
{
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
if (trim($output) === 'yes') {
return true;
}
return false;
}
const PROCESS = 'process';
const TASK = 'task';
const WORKER = 'worker';
/**
* @return string|null
*/
#[Pure] public static function getEnvironmental(): ?string
{
return env('environmental');
}
/**
* @param $fileName
* @param $content
* @param null $is_append
* @return mixed
*/
public static function writeFile($fileName, $content, $is_append = null): mixed
{
$params = [$fileName, (string)$content];
if ($is_append !== null) {
$params[] = $is_append;
}
return !(Coroutine::getCid() > 0) ? file_put_contents(...$params) : Coroutine::writeFile(...$params);
}
/**
* @return bool
*/
#[Pure] public static function isTask(): bool
{
return static::getEnvironmental() == static::TASK;
}
/**
* @param $object
* @param $config
* @return mixed
*/
public static function configure($object, $config): mixed
{
foreach ($config as $key => $value) {
if (!property_exists($object, $key)) {
continue;
}
$object->$key = $value;
}
return $object;
}
/**
* @return bool
*/
#[Pure] public static function isWorker(): bool
{
return static::getEnvironmental() == static::WORKER;
}
/**
* @return mixed
*/
public static function localhost(): mixed
{
return current(swoole_get_local_ip());
}
/**
* @param array $v1
* @param array $v2
* @return float
*/
#[Pure] public static function distance(array $v1, array $v2): float
{
$maxX = max($v1['x'], $v2['x']);
$minX = min($v1['x'], $v2['x']);
$maxZ = max($v1['z'], $v2['z']);
$minZ = min($v1['z'], $v2['z']);
$dx = abs($maxX - $minX);
$dy = abs($maxZ - $minZ);
$sqrt = sqrt($dx * $dx + $dy * $dy);
if ($sqrt < 0) {
$sqrt = abs($sqrt);
}
return (float)$sqrt;
}
/**
* @param $tmp_name
* @return string
*/
public static function rename($tmp_name): string
{
$hash = md5_file($tmp_name);
$later = '.' . exif_imagetype($tmp_name);
$match = '/(\w{12})(\w{5})(\w{9})(\w{6})/';
$tmp = preg_replace($match, '$1-$2-$3-$4', $hash);
return strtoupper($tmp) . $later;
}
/**
* @return Environmental
* @throws
*/
public static function getPlatform(): Environmental
{
return Kiri::createObject(Environmental::class);
}
/**
* @return mixed
* @throws Exception
*/
public static function reload(): mixed
{
return Kiri::app()->getSwoole()->reload();
}
const PROCESS = 'process';
const TASK = 'task';
const WORKER = 'worker';
/**
* @return string|null
*/
#[Pure] public static function getEnvironmental(): ?string
{
return env('environmental');
}
/**
* @return bool
*/
#[Pure] public static function isTask(): bool
{
return static::getEnvironmental() == static::TASK;
}
/**
* @return bool
*/
#[Pure] public static function isWorker(): bool
{
return static::getEnvironmental() == static::WORKER;
}
/**
* @return bool
*/
#[Pure] public static function isProcess(): bool
{
return static::getEnvironmental() == static::PROCESS;
}
/**
* @return bool
*/
#[Pure] public static function isProcess(): bool
{
return static::getEnvironmental() == static::PROCESS;
}
}
Kiri::setContainer(new Container());
+22 -12
View File
@@ -9,7 +9,7 @@
],
"license": "MIT",
"require": {
"php": ">=8.1",
"php": ">=8.3",
"ext-json": "*",
"ext-fileinfo": "*",
"ext-pdo": "*",
@@ -21,28 +21,38 @@
"ext-xml": "*",
"ext-curl": "*",
"ext-openssl": "*",
"ext-swoole": "*",
"ext-msgpack": "*",
"symfony/console": "~v5.3.10",
"psr/log": "1.*",
"composer-runtime-api": "^2.0",
"psr/container": "^2.0",
"psr/http-server-middleware": "1.0.1",
"game-worker/kiri-event": "~v2.0",
"game-worker/kiri-di": "~v1.0",
"ext-inotify": "*"
"ext-pcntl": "*",
"ext-sockets": "*",
"nikic/php-parser": "^4.15",
"ext-inotify": "*",
"game-worker/kiri-pool": "~v1.0",
"monolog/monolog": "^2.9",
"psr/container": "^2.0",
"ext-libsodium": "*",
"swiftmailer/swiftmailer": "^6.3"
},
"replace": {
"symfony/polyfill-apcu": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-ctype": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php81": "*"
},
"autoload": {
"psr-4": {
"Kiri\\": "kiri-engine/",
"Kiri\\Gateway\\": "kiri-gateway/",
"Kiri\\Websocket\\": "kiri-websocket-server/",
"Gii\\": "kiri-gii/",
"Kiri\\Annotation\\": "kiri-annotation/",
"Kiri\\Server\\": "kiri-server/",
"Kiri\\Task\\": "kiri-task/"
"Kiri\\Actor\\": "kiri-actor/"
},
"files": [
"Kiri.php",
"error.php",
"function.php"
]
}
-31
View File
@@ -1,31 +0,0 @@
<?php
define('SUCCESS', 0);
define('NO_AUTH', 401);
define('ERROR_MESSAGES', [
SUCCESS => 'ok',
NO_AUTH => ''
]);
if (!function_exists('message')) {
/**
* @param $code
* @param $replace
* @param string $default
* @return mixed|string
*/
function message($code, $replace, $default = '')
{
if (!isset(ERROR_MESSAGES[$code])) {
if (!empty($default)) {
return $default;
}
return 'unknown error';
}
return sprintf(ERROR_MESSAGES[$code], $replace);
}
}
+799 -1038
View File
File diff suppressed because it is too large Load Diff
+238
View File
@@ -0,0 +1,238 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use Exception;
use JsonSerializable;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
/**
* @Actor
*/
abstract class Actor implements ActorInterface, JsonSerializable
{
/**
* @var Channel
*/
private Channel $channel;
/**
* @var bool
*/
private bool $isShutdown = false;
/**
* @var int
*/
private int $messageId = -1;
/**
* @var int
*/
private int $coroutineId = -1;
/**
* @var ActorState
*/
private ActorState $state;
/**
* @var float
*/
private float $startTime = 0;
/**
* @var int
*/
private int $refreshInterval = 0;
/**
* @return ActorState
*/
public function getState(): ActorState
{
return $this->state;
}
/**
* @param ActorState $state
*/
public function setState(ActorState $state): void
{
$this->state = $state;
}
/**
* @return float
*/
public function getRunTime(): float
{
return microtime(true) - $this->startTime;
}
/**
* @param string $uniqueId
*/
private function __construct(readonly public string $uniqueId)
{
$this->channel = new Channel(99);
$this->startTime = microtime(true);
}
/**
* @return void
*/
public function init(): void
{
}
/**
* @return bool
*/
public function isShutdown(): bool
{
return $this->isShutdown;
}
/**
* @param $id
* @return static
*/
public static function newActor($id): static
{
$actor = new static($id);
$actor->listen();
return $actor;
}
/**
* @return void
*/
private function listen(): void
{
Coroutine::create(function (Actor $actor) {
$actor->coroutineId = Coroutine::getCid();
$this->run();
}, $this);
}
/**
* @return string
*/
public function getName(): string
{
return $this->uniqueId;
}
/**
* @param mixed $response
* @return bool
*/
public function write(mixed $response): bool
{
return $this->channel->push($response);
}
/**
* @return void
*/
public function shutdown(): void
{
$this->isShutdown = true;
Coroutine::cancel($this->coroutineId);
if ($this->messageId > -1) {
Coroutine::cancel($this->messageId);
}
$this->channel->close();
}
/**
* @return void
*/
public function onUpdate(): void
{
}
/**
* @return void
* @throws Exception
*/
public function run(): void
{
if ($this->refreshInterval < 1) {
throw new Exception('Refresh interval must be greater than 1');
}
$this->setState(ActorState::BUSY);
$this->init();
$this->messageId = Coroutine::create(fn() => $this->loop());
$this->interval();
$this->setState(ActorState::IDLE);
}
/**
* @return void
*/
private function interval(): void
{
if ($this->isShutdown()) {
return;
}
try {
$this->onUpdate();
} catch (\Throwable $exception) {
error($exception);
}
Coroutine::sleep($this->refreshInterval / 1000);
$this->interval();
}
/**
* @return bool
*/
private function loop(): bool
{
if ($this->messageId == -1) {
$this->messageId = Coroutine::getCid();
}
if ($this->channel->errCode == SWOOLE_CHANNEL_CLOSED) {
$this->channel = new Channel(99);
}
$message = $this->channel->pop();
$this->process($message);
if ($this->isShutdown()) {
return true;
}
return $this->loop();
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
interface ActorInterface
{
/**
* @param ActorMessage $message
* @return void
*/
public function process(ActorMessage $message): void;
}
+110
View File
@@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use Swoole\Coroutine;
class ActorManager
{
/** @var array<string, ActorInterface> */
private array $nodes = [];
/**
* @param Actor $actor
* @return void
*/
public function addActor(ActorInterface $actor): void
{
$this->nodes[$actor->uniqueId] = $actor;
Coroutine::create(function (Actor $actor) {
$actor->run();
}, $actor);
}
/**
* @param $name
* @return void
*/
public function closeActor($name): void
{
$node = $this->nodes[$name] ?? null;
if (is_null($node)) {
return;
}
foreach ($node as $actor) {
$actor->shutdown();
}
}
/**
* @param $name
* @param $message
* @return bool
*/
public function write($name, $message): bool
{
$actor = $this->nodes[$name] ?? null;
if (is_null($actor)) {
return false;
}
return $actor->write($message);
}
/**
* @param $name
* @return array
*/
public function lists($name): array
{
$array = [];
foreach ($this->nodes[$name] as $actor) {
$array[] = [
'id' => $actor->getName(),
'state' => $actor->getState()->name,
'runTime' => $actor->getRunTime()
];
}
return $array;
}
/**
* @param string $uniqueId
* @return bool
*/
public function hasActor(string $uniqueId): bool
{
return isset($this->nodes[$uniqueId]) && $this->nodes[$uniqueId] instanceof ActorInterface;
}
/**
* @param array|null $data
* @return void
*/
public static function exec(?array $data): void
{
if (is_null($data)) {
return;
}
}
/**
* @return void
*/
public function clean(): void
{
foreach ($this->nodes as $actor) {
$actor->shutdown();
}
$this->nodes = [];
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use JetBrains\PhpStorm\ArrayShape;
class ActorMessage implements \JsonSerializable
{
/**
* @var int
*/
private int $userId;
/**
* @var string
*/
private string $event;
/**
* @var array
*/
private array $body;
/**
* @param int $userId
* @param string $event
* @param array $body
*/
public function __construct(int $userId, string $event, array $body)
{
$this->userId = $userId;
$this->event = $event;
$this->body = $body;
}
/**
* @return int
*/
public function getUserId(): int
{
return $this->userId;
}
/**
* @return string
*/
public function getEvent(): string
{
return $this->event;
}
/**
* @return array
*/
public function getBody(): array
{
return $this->body;
}
/**
* @return array
*/
#[ArrayShape(['userId' => "int", 'event' => "string", 'body' => "array"])]
public function jsonSerialize(): array
{
return [
'userId' => $this->userId,
'event' => $this->event,
'body' => $this->body
];
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace Kiri\Actor;
use Kiri\Server\Processes\AbstractProcess;
use Swoole\Coroutine;
use Swoole\Process;
class ActorProcess extends AbstractProcess
{
/**
* @var bool
*/
protected bool $enable_coroutine = true;
/**
* @return string
*/
public function getName(): string
{
// TODO: Change the autogenerated stub
return 'Actor Manager';
}
public function process(?Process $process): void
{
// TODO: Implement process() method.
while ($this->isStop() === false) {
$read = $process->read();
ActorManager::exec(json_decode($read, true));
Coroutine::sleep(1000 / 120);
}
}
/**
* @return void
*/
public function onSigterm(): void
{
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace Kiri\Actor;
enum ActorState
{
case IDLE;
case BUSY;
/**
*
*/
case CREATE;
case MESSAGE;
case SHUTDOWN;
}
-86
View File
@@ -1,86 +0,0 @@
<?php
namespace Kiri\Annotation;
use DirectoryIterator;
use Exception;
use ReflectionException;
use Kiri\Abstracts\Component;
/**
* Class Annotation
* @package Annotation
*/
class Annotation extends Component
{
private Loader $_loader;
/**
*
*/
public function init(): void
{
$this->_loader = new Loader();
}
/**
* @return Loader
*/
public function getLoader(): Loader
{
return $this->_loader;
}
/**
* @param Loader $loader
* @return Loader
*/
public function setLoader(Loader $loader): Loader
{
return $this->_loader = $loader;
}
/**
* @param object $class
* @throws ReflectionException
*/
public function injectProperty(object $class)
{
$this->_loader->injectProperty($class::class, $class);
}
/**
* @param string $path
* @param string $namespace
* @param array $exclude
* @return static
* @throws Exception
*/
public function read(string $path, string $namespace = 'App', array $exclude = []): static
{
$this->_loader->_scanDir(new DirectoryIterator($path), $namespace, $exclude);
return $this;
}
/**
* @param string $dir
* @param array $exclude
* @return array
* @throws Exception
*/
public function runtime(string $dir, array $exclude = []): array
{
return $this->_loader->loadByDirectory($dir, $exclude);
}
}
-37
View File
@@ -1,37 +0,0 @@
<?php
namespace Kiri\Annotation;
use Exception;
defined('ASPECT_ERROR') or define('ASPECT_ERROR', 'Aspect annotation must implement ');
/**
* Class Aspect
* @package Annotation
*/
#[\Attribute(\Attribute::TARGET_METHOD)] class Aspect extends Attribute
{
/**
* Aspect constructor.
* @param string $aspect
*/
public function __construct(public string $aspect)
{
}
/**
* @throws Exception
*/
public function execute(mixed $class, mixed $method = ''): bool
{
return true;
}
}
-27
View File
@@ -1,27 +0,0 @@
<?php
namespace Kiri\Annotation;
/**
* Class Attribute
* @package Annotation
*/
abstract class Attribute implements IAnnotation
{
/**
* @param static $class
* @param mixed|string $method
* @return mixed
*/
#[\ReturnTypeWillChange]
public function execute(mixed $class, mixed $method = ''): mixed
{
// TODO: Implement execute() method.
return true;
}
}
-46
View File
@@ -1,46 +0,0 @@
<?php
namespace Kiri\Annotation;
use Exception;
use Kiri\Events\EventProvider;
use Kiri;
/**
* Class Event
* @package Annotation
*/
#[\Attribute(\Attribute::TARGET_METHOD)] class Event extends Attribute
{
/**
* Event constructor.
* @param string $name
* @param array $params
*/
public function __construct(public string $name, public array $params = [])
{
}
/**
* @param mixed $class
* @param mixed|null $method
* @return bool
* @throws Exception
*/
public function execute(mixed $class, mixed $method = null): bool
{
$pro = Kiri::getDi()->get(EventProvider::class);
if (is_string($class)) {
$class = Kiri::getDi()->get($class);
}
$pro->on($this->name, [$class, $method]);
return true;
}
}
-19
View File
@@ -1,19 +0,0 @@
<?php
namespace Kiri\Annotation;
interface IAnnotation
{
/**
* @param mixed $class
* @param mixed $method
* @return mixed
*/
public function execute(mixed $class, mixed $method = ''): mixed;
}
-104
View File
@@ -1,104 +0,0 @@
<?php
namespace Kiri\Annotation;
use Exception;
use Kiri\Core\Str;
use Kiri;
use ReflectionException;
use ReflectionProperty;
/**
* Class Inject
* @package Annotation
*/
#[\Attribute(\Attribute::TARGET_PROPERTY)] class Inject extends Attribute
{
/**
* Inject constructor.
* @param string $value
* @param array $construct
*/
public function __construct(public string $value, public array $construct = [])
{
}
/**
* @param mixed $class
* @param mixed|null $method
* @return bool
* @throws ReflectionException
* @throws Exception
*/
public function execute(mixed $class, mixed $method = null): bool
{
if (!($method = $this->getProperty($class, $method))) {
return false;
}
/** @var ReflectionProperty $class */
$injectValue = static::parseInjectValue();
if ($method->isPrivate() || $method->isProtected()) {
$this->setter($class, $method, $injectValue);
} else {
$class->{$method->getName()} = $injectValue;
}
return true;
}
/**
* @param $class
* @param $method
* @param $injectValue
*/
private function setter($class, $method, $injectValue)
{
$method = 'set' . ucfirst(Str::convertUnderline($method->getName()));
if (!method_exists($class, $method)) {
return;
}
$class->$method($injectValue);
}
/**
* @param $class
* @param $method
* @return ReflectionProperty|bool
*/
private function getProperty($class, $method): ReflectionProperty|bool
{
if ($method instanceof ReflectionProperty && !$method->isStatic()) {
return $method;
}
if (is_object($class)) $class = $class::class;
$method = Kiri::getDi()->getClassReflectionProperty($class, $method);
if (!$method || $method->isStatic()) {
return false;
}
return $method;
}
/**
* @return mixed
* @throws Exception
*/
private function parseInjectValue(): mixed
{
if (!Kiri::app()->has($this->value)) {
if (!empty($this->construct)) {
return Kiri::getDi()->create($this->value, $this->construct);
}
return Kiri::getDi()->get($this->value);
} else {
return Kiri::app()->get($this->value);
}
}
}
-228
View File
@@ -1,228 +0,0 @@
<?php
namespace Kiri\Annotation;
use DirectoryIterator;
use Exception;
use Kiri;
use Kiri\Abstracts\Component;
use ReflectionClass;
use ReflectionException;
use Throwable;
/**
* Class Loader
* @package Annotation
*/
class Loader extends Component
{
private array $_directory = [];
private array $_methods = [];
/**
* @param $path
* @param $namespace
* @throws Exception
*/
public function loader($path, $namespace)
{
$this->_scanDir(new DirectoryIterator($path), $namespace);
}
/**
* @param string $class
* @param object $handler
* @return $this
* @throws ReflectionException
* @throws Exception
*/
public function injectProperty(string $class, object $handler): static
{
$di = Kiri::getDi();
$reflect = $di->getReflect($class);
$di->propertyInject($reflect, $handler);
return $this;
}
/**
* @param string $class
* @param string $method
* @return mixed
*/
public function getMethod(string $class, string $method = ''): array
{
if (!isset($this->_methods[$class])) {
return [];
}
$properties = $this->_methods[$class];
if (!empty($method) && isset($properties[$method])) {
return $properties[$method];
}
return $properties;
}
/**
* @param DirectoryIterator $paths
* @param $namespace
* @param array $exclude
* @throws Exception
*/
public function _scanDir(DirectoryIterator $paths, $namespace, array $exclude = [])
{
foreach ($paths as $path) {
if (function_exists('opcache_invalidate')) {
opcache_invalidate($path->getRealPath(), true);
}
if ($path->isDot() || str_starts_with($path->getFilename(), '.')) {
continue;
}
if ($this->inExclude($exclude, $path->getRealPath())) {
continue;
}
if ($path->isDir()) {
$iterator = new DirectoryIterator($path->getRealPath());
$directory = rtrim($path->getRealPath(), '/');
if (!isset($this->_directory[$directory])) {
$this->_directory[$directory] = [];
}
$this->_scanDir($iterator, $namespace);
} else {
$this->readFile($path, $namespace);
}
}
}
/**
* @param DirectoryIterator $path
* @param $namespace
* @throws Exception
*/
private function readFile(DirectoryIterator $path, $namespace)
{
try {
if ($path->getExtension() !== 'php') {
return;
}
$replace = $this->getReflect($path, $namespace);
if (!$replace || !$replace->getAttributes(Target::class)) {
return;
}
$this->appendFileToDirectory($path->getRealPath(), $replace->getName());
} catch (Throwable $throwable) {
$this->error(jTraceEx($throwable), 'throwable');
}
}
/**
* @param DirectoryIterator $path
* @param string $namespace
* @return ReflectionClass|null
*/
private function getReflect(DirectoryIterator $path, string $namespace): ?ReflectionClass
{
$class = $this->explodeFileName($path, $namespace);
if (!class_exists($class)) {
return null;
}
return Kiri::getDi()->getReflect($class);
}
/**
* @param string $path
* @param array $exclude
* @return array
* @throws Exception
*/
public function loadByDirectory(string $path, array $exclude = []): array
{
try {
$path = '/' . trim($path, '/');
$paths = [];
foreach ($this->_directory as $key => $_path) {
$key = '/' . trim($key, '/');
if (!str_starts_with($key, $path) || $this->inExclude($exclude, $path)) {
continue;
}
unset($this->_directory[$key]);
foreach ($_path as $item) {
$paths[] = $item;
}
}
return $paths;
} catch (Throwable $exception) {
$this->addError($exception, 'throwable');
return [];
}
}
/**
* @param array $exclude
* @param $path
* @return bool
*/
private function inExclude(array $exclude, $path): bool
{
if (empty($exclude)) {
return false;
}
foreach ($exclude as $value) {
if (str_starts_with($path, $value)) {
return true;
}
}
return false;
}
/**
* @param DirectoryIterator $path
* @param string $namespace
* @return string
*/
private function explodeFileName(DirectoryIterator $path, string $namespace): string
{
$replace = str_replace(APP_PATH, '', $path->getRealPath());
$replace = str_replace('.php', '', $replace);
$replace = str_replace(DIRECTORY_SEPARATOR, '\\', $replace);
$explode = explode('\\', $replace);
array_shift($explode);
return $namespace . '\\' . implode('\\', $explode);
}
/**
* @param string $filePath
* @param string $className
*/
public function appendFileToDirectory(string $filePath, string $className)
{
$array = explode('/', $filePath);
unset($array[count($array) - 1]);
$array = '/' . trim(implode('/', $array), '/');
$this->_directory[$array][] = $className;
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
namespace Kiri\Annotation;
use Kiri;
#[\Attribute(\Attribute::TARGET_CLASS)] class Mapping extends Attribute
{
/**
* @param string $class
*/
public function __construct(public string $class)
{
}
/**
* @param mixed $class
* @param mixed|string $method
* @return mixed
*/
public function execute(mixed $class, mixed $method = ''): mixed
{
Kiri::getDi()->mapping($this->class, $class);
return parent::execute($class, $method);
}
}
-34
View File
@@ -1,34 +0,0 @@
<?php
namespace Kiri\Annotation\Route;
use Kiri\Annotation\Attribute;
/**
* Class Document
* @package Annotation\Route
*/
#[\Attribute(\Attribute::TARGET_METHOD)] class Document extends Attribute
{
const INTEGER = 'int';
const STRING = 'string';
const BOOLEAN = 'bool';
const FLOAT = 'float';
const ALIAS = [
self::INTEGER => '整数',
self::STRING => '字符串',
self::BOOLEAN => '布尔值',
self::FLOAT => '浮点',
];
public function __construct(array $request, array $response)
{
}
}
-53
View File
@@ -1,53 +0,0 @@
<?php
namespace Kiri\Annotation\Route;
use Kiri\Annotation\Attribute;
use Kiri\Message\Handler\Abstracts\MiddlewareManager;
use Psr\Http\Server\MiddlewareInterface;
/**
* Class Middleware
* @package Annotation\Route
*/
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Middleware extends Attribute
{
/**
* Interceptor constructor.
* @param string|array $middleware
* @throws
*/
public function __construct(public string|array $middleware)
{
if (is_string($this->middleware)) {
$this->middleware = [$this->middleware];
}
$array = [];
foreach ($this->middleware as $value) {
if (!in_array(MiddlewareInterface::class, class_implements($value))) {
throw new \Exception('The middleware');
}
$array[] = $value;
}
$this->middleware = $array;
}
/**
* @param mixed $class
* @param mixed|null $method
* @return $this
* @throws \ReflectionException
*/
public function execute(mixed $class, mixed $method = null): mixed
{
MiddlewareManager::add($class, $method, $this->middleware);
return parent::execute($class, $method);
}
}
-41
View File
@@ -1,41 +0,0 @@
<?php
namespace Kiri\Annotation\Route;
use Kiri\Annotation\Attribute;
use Kiri\Message\Handler\Router;
use Kiri;
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] class Route extends Attribute
{
/**
* Route constructor.
* @param string $uri
* @param string $method
* @param string $version
*/
public function __construct(public string $uri, public string $method, public string $version = 'v.1.0')
{
$this->uri = '/' . ltrim($this->uri, '/');
$this->method = strtoupper($this->method);
}
/**
* @param mixed $class
* @param mixed|null $method
* @return bool
* @throws \ReflectionException
*/
public function execute(mixed $class, mixed $method = null): bool
{
$di = Kiri::getDi()->get(Router::class);
$di->addRoute($this->method, $this->uri, $class . '@' . $method);
return parent::execute($class, $method);
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
namespace Kiri\Annotation\Route;
use Kiri\Annotation\Attribute;
/**
* Class Socket
* @package Annotation
*/
#[\Attribute(\Attribute::TARGET_METHOD)] class Socket extends Attribute
{
const CLOSE = 'CLOSE';
const MESSAGE = 'MESSAGE';
const HANDSHAKE = 'HANDSHAKE';
/**
* Socket constructor.
* @param string $event
* @param string|null $uri
* @param string $version
*/
public function __construct(string $event, ?string $uri = null, string $version = 'v.1.0')
{
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
namespace Kiri\Annotation;
/**
* Class Target
* @package Annotation
*/
#[\Attribute(\Attribute::TARGET_CLASS)] class Target extends Attribute
{
const WORKER = 'worker';
const ALL = 'any';
const PROCESS = 'process';
const TASK = 'task';
/**
* @param string $only
*/
public function __construct(string $only = Target::ALL)
{
}
}
-12
View File
@@ -1,12 +0,0 @@
<?php
namespace Kiri\Abstracts;
abstract class AbstractServer extends Component
{
public string $name = 'http';
}
+108 -453
View File
@@ -1,453 +1,108 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/10/7 0007
* Time: 2:13
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Database\Connection;
use Exception;
use Kafka\KafkaProvider;
use Kiri;
use Kiri\Annotation\Annotation as SAnnotation;
use Kiri\Async;
use Kiri\Cache\Redis;
use Kiri\Di\LocalService;
use Kiri\Error\{ErrorHandler, Logger};
use Kiri\Exception\{InitException, NotFindClassException};
use Kiri\Message\Handler\Router;
use Kiri\Server\{Server, ServerManager};
use Kiri\Task\AsyncTaskExecute;
use Kiri\Task\OnTaskInterface;
use ReflectionException;
use Swoole\Table;
/**
* Class BaseApplication
* @package Kiri\Base
*/
abstract class BaseApplication extends Component
{
use TraitApplication;
/**
* @var string
*/
public string $storage = APP_PATH . 'storage';
public string $envPath = APP_PATH . '.env';
/**
* Init constructor.
*
*
* @throws
*/
public function __construct()
{
Kiri::init($this);
$config = sweep(APP_PATH . '/config');
$this->moreComponents();
$this->parseInt($config);
$this->parseEvents($config);
$this->initErrorHandler();
$this->enableEnvConfig();
$this->mapping($config['mapping'] ?? []);
parent::__construct();
}
/**
* @param array $mapping
*/
public function mapping(array $mapping)
{
$di = Kiri::getDi();
foreach ($mapping as $interface => $class) {
$di->mapping($interface, $class);
}
}
/**
* @return array
*/
public function enableEnvConfig(): array
{
if (!file_exists($this->envPath)) {
return [];
}
$lines = $this->readLinesFromFile($this->envPath);
foreach ($lines as $line) {
if (!$this->isComment($line) && $this->looksLikeSetter($line)) {
[$key, $value] = explode('=', $line);
putenv(trim($key) . '=' . trim($value));
}
}
return $lines;
}
/**
* Read lines from the file, auto detecting line endings.
*
* @param string $filePath
*
* @return array
*/
protected function readLinesFromFile(string $filePath): array
{
// Read file into an array of lines with auto-detected line endings
$autodetect = ini_get('auto_detect_line_endings');
ini_set('auto_detect_line_endings', '1');
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
ini_set('auto_detect_line_endings', $autodetect);
return $lines;
}
/**
* Determine if the line in the file is a comment, e.g. begins with a #.
*
* @param string $line
*
* @return bool
*/
protected function isComment(string $line): bool
{
$line = ltrim($line);
return isset($line[0]) && $line[0] === '#';
}
/**
* Determine if the given line looks like it's setting a variable.
*
* @param string $line
*
* @return bool
*/
protected function looksLikeSetter(string $line): bool
{
return str_contains($line, '=');
}
/**
* @param $config
*
* @throws
*/
public function parseInt($config)
{
Config::sets($config);
if ($storage = Config::get('storage', 'storage')) {
if (!str_contains($storage, APP_PATH)) {
$storage = APP_PATH . $storage . '/';
}
if (!is_dir($storage)) {
mkdir($storage);
}
if (!is_dir($storage) || !is_writeable($storage)) {
throw new InitException("Directory {$storage} does not have write permission");
}
}
}
/**
* @param $name
* @return mixed
* @throws ReflectionException
* @throws NotFindClassException
* @throws Exception
*/
public function __get($name): mixed
{
if ($this->has($name)) {
return $this->get($name);
}
return parent::__get($name); // TODO: Change the autogenerated stub
}
/**
* @param $config
*
* @throws
*/
public function parseEvents($config)
{
if (!isset($config['events']) || !is_array($config['events'])) {
return;
}
foreach ($config['events'] as $key => $value) {
if (is_string($value)) {
$value = Kiri::createObject($value);
}
$this->addEvent($key, $value);
}
}
/**
* @param OnTaskInterface $execute
* @throws ReflectionException|Exception
*/
public function task(OnTaskInterface $execute): void
{
di(AsyncTaskExecute::class)->execute($execute);
}
/**
* @param $key
* @param $value
* @throws InitException
* @throws Exception
*/
private function addEvent($key, $value): void
{
if ($value instanceof \Closure || is_object($value)) {
$this->getEventProvider()->on($key, $value, 0);
return;
}
if (is_array($value)) {
if (is_object($value[0]) && !($value[0] instanceof \Closure)) {
$this->getEventProvider()->on($key, $value, 0);
return;
}
if (is_string($value[0])) {
$value[0] = Kiri::createObject($value[0]);
$this->getEventProvider()->on($key, $value, 0);
return;
}
foreach ($value as $item) {
if (!is_callable($item, true)) {
throw new InitException("Class does not hav callback.");
}
$this->getEventProvider()->on($key, $item, 0);
}
}
}
/**
* @param $name
* @return mixed
* @throws Exception
*/
public function clone($name): mixed
{
return clone $this->get($name);
}
/**
*
* @throws Exception
*/
public function initErrorHandler()
{
$this->get('error')->register();
}
/**
* @param $name
* @return mixed
* @throws
*/
public function get($name): mixed
{
return di(LocalService::class)->get($name);
}
/**
* @return mixed
*/
public function getLocalIps(): mixed
{
return swoole_get_local_ip();
}
/**
* @return mixed
*/
public function getFirstLocal(): mixed
{
return current($this->getLocalIps());
}
/**
* @return Logger
* @throws
*/
public function getLogger(): Logger
{
return $this->get('logger');
}
/**
* @return \Redis|Redis
* @throws
*/
public function getRedis(): Redis|\Redis
{
return Kiri::getDi()->get(Redis::class);
}
/**
* @param $ip
* @return bool
*/
public function isLocal($ip): bool
{
return $this->getFirstLocal() == $ip;
}
/**
* @return ErrorHandler
* @throws
*/
public function getError(): ErrorHandler
{
return $this->get('error');
}
/**
* @param $name
* @return Table
* @throws
*/
public function getTable($name): Table
{
return $this->get($name);
}
/**
* @return Config
* @throws
*/
public function getConfig(): Config
{
return $this->get('config');
}
/**
* @return Router
* @throws
*/
public function getRouter(): Router
{
return Kiri::getDi()->get(Router::class);
}
/**
* @return Server
* @throws
*/
public function getServer(): Server
{
return Kiri::getDi()->get(Server::class);
}
/**
* @return \Swoole\Http\Server|\Swoole\Server|\Swoole\WebSocket\Server|null
* @throws
*/
public function getSwoole(): \Swoole\Http\Server|\Swoole\Server|\Swoole\WebSocket\Server|null
{
return di(ServerManager::class)->getServer();
}
/**
* @return SAnnotation
* @throws
*/
public function getAnnotation(): SAnnotation
{
return $this->get('Annotation');
}
/**
* @return Async
* @throws
*/
public function getAsync(): Async
{
return $this->get('async');
}
/**
* @param $array
*/
private function setComponents($array): void
{
di(LocalService::class)->setComponents($array);
}
/**
* @param $id
* @param $definition
*/
public function set($id, $definition): void
{
di(LocalService::class)->set($id, $definition);
}
/**
* @param $id
* @return bool
*/
public function has($id): bool
{
return di(LocalService::class)->has($id);
}
/**
* @throws Exception
*/
protected function moreComponents(): void
{
$this->setComponents([
'error' => ['class' => ErrorHandler::class],
'config' => ['class' => Config::class],
'logger' => ['class' => Logger::class],
'Annotation' => ['class' => SAnnotation::class],
'databases' => ['class' => Connection::class],
'async' => ['class' => Async::class],
'kafka-container' => ['class' => KafkaProvider::class],
]);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/10/7 0007
* Time: 2:13
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Database\DatabasesProviders;
use Exception;
use Kiri\Events\EventInterface;
use Kiri\Config\ConfigProvider;
use Kiri\Exception\{InitException};
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Kiri\Events\EventProvider;
use Kiri\Error\StdoutLogger;
/**
* Class BaseApplication
* @package Kiri\Base
* @property DatabasesProviders $connections
*/
abstract class BaseApplication extends LocalService
{
/**
* @var string
*/
public string $storage = APP_PATH . 'storage';
/**
* @param EventProvider $provider
* @param ConfigProvider $config
* @param ContainerInterface $container
* @throws
*/
public function __construct(public EventProvider $provider, public ConfigProvider $config, public ContainerInterface $container)
{
$this->mapping($config);
$this->parseStorage($config);
$this->parseEvents($config);
parent::__construct();
}
/**
* @param ConfigProvider $config
* @return void
*/
public function mapping(ConfigProvider $config): void
{
$this->container->bind(LoggerInterface::class, new StdoutLogger());
foreach ($config->get('mapping', []) as $interface => $class) {
$this->container->set($interface, $class);
}
}
/**
* @param ConfigProvider $config
* @return void
* @throws
*/
public function parseStorage(ConfigProvider $config): void
{
$storage = $config->get('storage', 'storage');
if (!str_contains($storage, APP_PATH)) {
$storage = APP_PATH . $storage . '/';
}
if (!is_dir($storage)) {
mkdir($storage, 0777, true);
}
if (!is_dir($storage) || !is_writeable($storage)) {
throw new InitException("Directory $storage does not have write permission");
}
}
/**
* @param ConfigProvider $config
* @return void
* @throws
*/
public function parseEvents(ConfigProvider $config): void
{
$events = $config->get('events', []);
foreach ($events as $key => $value) {
if (is_string($value)) {
$value = $this->container->get($value);
if (!($value instanceof EventInterface)) {
throw new Exception("Event listen must implement " . EventInterface::class);
}
$value = [$value, 'process'];
}
$this->provider->on($key, $value, 0);
}
}
}
-13
View File
@@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
use Swoole\Coroutine;
abstract class BaseContext
{
protected static array $pool = [];
}
-28
View File
@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
use Kiri\Core\Json;
/**
* Class BaseGoto
* @package Kiri\Abstracts
*/
class BaseGoto extends Component
{
/**
* @param string $message
* @param int $statusCode
* @return mixed
* @throws Exception
*/
public function end(string $message, int $statusCode = 200): mixed
{
throw new Exception(Json::to(12350, $message), $statusCode);
}
}
-10
View File
@@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
abstract class Command extends Component
{
}
+86 -184
View File
@@ -12,216 +12,118 @@ namespace Kiri\Abstracts;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Di\Container;
use Kiri;
use Kiri\Error\StdoutLogger;
use Kiri\Events\EventDispatch;
use Kiri\Events\EventProvider;
use Kiri;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* Class Component
* @package Kiri\Base
* @property ContainerInterface $container
* @property EventDispatch $dispatch
* @property EventProvider $provider
*/
class Component implements Configure
{
/**
* BaseAbstract constructor.
*
* @param array $config
* @throws Exception
*/
public function __construct(array $config = [])
{
if (!empty($config) && is_array($config)) {
Kiri::configure($this, $config);
}
}
/**
* BaseAbstract constructor.
*/
public function __construct()
{
}
/**
* @return Container|ContainerInterface
*/
#[Pure] public function getContainer(): ContainerInterface|Container
{
return Kiri::getDi();
}
/**
* @return void
*/
public function init(): void
{
}
/**
* @return EventProvider
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getEventProvider(): EventProvider
{
return $this->getContainer()->get(EventProvider::class);
}
/**
* @return string
*/
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @return EventDispatch
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function getEventDispatch(): EventDispatch
{
return $this->getContainer()->get(EventDispatch::class);
}
/**
* @throws Exception
*/
public function init()
{
}
/**
* @return StdoutLogger
* @throws
*/
public function getLogger(): StdoutLogger
{
return Kiri::getLogger();
}
/**
* @return string
*/
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @param string $name
* @return mixed
* @throws
*/
public function __get(string $name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->{$method}();
} else if (method_exists($this, $name)) {
return $this->{$name};
} else {
throw new Exception('Unable getting property ' . get_called_class() . '::' . $name);
}
}
/**
* @param $message
* @param string $model
* @return bool
* @throws Exception
*/
public function addError($message, string $model = 'app'): bool
{
if ($message instanceof \Throwable) {
$this->error($message = jTraceEx($message));
} else {
if (!is_string($message)) {
$message = json_encode($message, JSON_UNESCAPED_UNICODE);
}
$this->error($message);
}
Kiri::app()->getLogger()->fail($message, $model);
return FALSE;
}
/**
* @param string $name
* @param $value
* @return void
* @throws
*/
public function __set(string $name, $value): void
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
$this->{$method}($value);
} else if (method_exists($this, $name)) {
$this->{$name} = $value;
} else {
throw new Exception('Unable setting property ' . get_called_class() . '::' . $name);
}
}
/**
* @return Logger
* @throws Exception
*/
protected function logger(): Logger
{
return Kiri::getDi()->get(Logger::class);
}
/**
* @return EventDispatch
*/
public function getDispatch(): EventDispatch
{
return Kiri::getDi()->get(EventDispatch::class);
}
/**
* @param mixed $message
* @param string $method
* @param string $file
* @throws Exception
*/
public function debug(mixed $message, string $method = '', string $file = '')
{
if (!is_string($message)) {
$message = print_r($message, true);
}
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->debug($message, $context);
}
/**
* @return EventProvider
*/
public function getProvider(): EventProvider
{
return Kiri::getDi()->get(EventProvider::class);
}
/**
* @param mixed $message
* @param string $method
* @param string $file
* @throws Exception
*/
public function info(mixed $message, string $method = '', string $file = '')
{
if (!is_string($message)) {
$message = print_r($message, true);
}
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->info($message, $context);
}
/**
* @param mixed $message
* @param string $method
* @param string $file
* @throws Exception
*/
public function success(mixed $message, string $method = '', string $file = '')
{
if (!is_string($message)) {
$message = print_r($message, true);
}
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->notice($message, $context);
}
/**
* @param mixed $message
* @param string $method
* @param string $file
* @throws Exception
*/
public function warning(mixed $message, string $method = '', string $file = '')
{
if (!is_string($message)) {
$message = print_r($message, true);
}
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->critical($message, $context);
}
/**
* @param mixed $message
* @param null $method
* @param null $file
* @throws Exception
*/
public function error(mixed $message, $method = null, $file = null)
{
if ($message instanceof \Throwable) {
$message = $message->getMessage() . " on line " . $message->getLine() . " at file " . $message->getFile();
}
$context = [];
if (is_string($method)) {
$message = (empty($method) ? '' : $method . ': ') . $message;
} else {
if (is_null($method)) {
$method = [];
}
$context = $method;
}
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->error($message, $context);
}
/**
* @return ContainerInterface
*/
public function getContainer(): ContainerInterface
{
return Kiri::getDi();
}
}
-128
View File
@@ -1,128 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/5/24 0024
* Time: 11:50
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Kiri\Exception\ConfigException;
/**
* Class Config
* @package Kiri\Base
*/
class Config extends Component
{
const ERROR_MESSAGE = 'The not find %s in app configs.';
protected static mixed $data = [];
/**
* @return mixed
*/
public static function getData(): mixed
{
return static::$data;
}
/**
* @param $key
* @param $value
* @return mixed
*/
public static function setData($key, $value): mixed
{
return static::$data[$key] = $value;
}
/**
* @param array $configs
*/
public static function sets(array $configs)
{
if (empty($configs)) {
return;
}
static::$data = $configs;
}
/**
* @param $key
* @param bool $try
* @param mixed|null $default
* @return mixed
* @throws ConfigException
*/
public static function get($key, mixed $default = null, bool $try = FALSE): mixed
{
$instance = static::$data;
if (!str_contains($key, '.')) {
return $instance[$key] ?? $default;
}
foreach (explode('.', $key) as $value) {
if (empty($value)) {
continue;
}
if (!isset($instance[$value])) {
if ($try) {
throw new ConfigException(sprintf(self::ERROR_MESSAGE, $key));
}
return $default;
}
if (!is_array($instance[$value])) {
return $instance[$value];
}
$instance = $instance[$value];
}
return empty($instance) ? $default : $instance;
}
/**
* @param $key
* @param $value
* @return mixed
*/
public static function set($key, $value): mixed
{
$explode = explode('.', $key);
$parent = &static::$data;
foreach ($explode as $item) {
if (!isset($parent[$item])) {
$parent[$item] = [];
}
$parent = &$parent[$item];
}
$parent = $value;
unset($parent);
return static::$data;
}
/**
* @param $key
* @param bool $must_not_null
* @return bool
*/
public static function has($key, bool $must_not_null = false): bool
{
if (!isset(static::$data[$key])) {
return false;
}
$config = static::$data[$key];
if ($must_not_null === false) {
return true;
}
return !empty($config);
}
}
@@ -0,0 +1,27 @@
<?php
namespace Kiri\Abstracts;
use Kiri\Coordinator;
class CoordinatorManager
{
private static array $_waite = [];
/**
* @param string $category
* @return Coordinator
*/
public static function utility(string $category): Coordinator
{
if (!((static::$_waite[$category] ?? null) instanceof Coordinator)) {
static::$_waite[$category] = new Coordinator();
}
return static::$_waite[$category];
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
use Kiri\Core\Dtl;
/**
* Interface IListener
* @package Kiri\Abstracts
*/
interface IListener
{
/**
* @param Dtl $dtl
* @return mixed
*/
public function execute(Dtl $dtl): mixed;
}
-111
View File
@@ -1,111 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
class Input
{
private array $_argv = [];
private string $_command = '';
/**
* Input constructor.
* @param $argv
* @throws
*/
public function __construct($argv)
{
$this->_argv = $this->resolve($argv);
}
/**
* @return string
*/
public function getCommandName(): string
{
return $this->_command;
}
/**
* @param $key
* @param null $default
* @return mixed
*/
public function get($key, $default = null): mixed
{
return $this->_argv[$key] ?? $default;
}
/**
* @param $key
* @return bool
*/
public function exists($key): bool
{
return isset($this->_argv[$key]);
}
/**
* @param $key
* @param $value
* @return $this
*/
public function set($key, $value): static
{
$this->_argv[$key] = $value;
return $this;
}
/**
* @return false|string
*/
public function toJson(): bool|string
{
return json_encode($this->_argv, JSON_UNESCAPED_UNICODE);
}
/**
* @param $parameters
* @return array
* @throws Exception
*/
public function resolve($parameters): array
{
$arrays = [];
$parameters = array_slice($parameters, 1);
if (empty($parameters)) {
return $arrays;
}
$this->_command = array_shift($parameters);
foreach ($parameters as $parameter) {
$explode = explode('=', $parameter);
if (count($explode) < 2) {
continue;
}
$arrays[array_shift($explode)] = current($explode);
}
return $arrays;
}
/**
* @return string
*/
public function getCommand(): string
{
return $this->_command;
}
}
-18
View File
@@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
/**
* Class Listener
* @package Kiri\Abstracts
* 监听的名称
*/
abstract class Listener extends Component implements IListener
{
}
+80
View File
@@ -0,0 +1,80 @@
<?php
namespace Kiri\Abstracts;
use Exception;
class LocalService extends Component implements LocalServiceInterface
{
/**
* @var array
*/
protected array $_definition = [];
/**
* @var array
*/
protected array $_components = [];
/**
* @param string $name
* @return bool
*/
public function has(string $name): bool
{
return isset($this->_definition[$name]) || isset($this->_components[$name]);
}
/**
* @param string $name
* @return mixed
* @throws
*/
public function get(string $name): mixed
{
if (isset($this->_components[$name])) return $this->_components[$name];
if (!isset($this->_definition[$name])) {
throw new Exception('Undefined component ' . $name);
}
$definition = $this->_definition[$name];
if (!($definition instanceof \Closure)) {
$this->_components[$name] = \Kiri::createObject($definition);
} else {
$this->_components[$name] = call_user_func($definition);
}
return $this->_components[$name];
}
/**
* @param string $name
* @param array $value
* @return void
*/
public function set(string $name, array $value): void
{
$this->_definition[$name] = $value;
unset($this->_components[$name]);
}
/**
* @param string $name
* @return mixed
* @throws
*/
public function __get(string $name)
{
if (!$this->has($name)) {
return parent::__get($name);
} else {
return $this->get($name);
}
}
}
@@ -0,0 +1,8 @@
<?php
namespace Kiri\Abstracts;
interface LocalServiceInterface
{
}
-229
View File
@@ -1,229 +0,0 @@
<?php
namespace Kiri\Abstracts;
use DirectoryIterator;
use Exception;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Kiri;
use Kiri\Server\Events\OnWorkerStop;
use Psr\Log\LoggerInterface;
use ReflectionException;
/**
*
*/
class Logger implements LoggerInterface
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
private array $_loggers = [];
const LOGGER_LEVELS = [Logger::EMERGENCY, Logger::ALERT, Logger::CRITICAL, Logger::ERROR, Logger::WARNING, Logger::NOTICE, Logger::INFO, Logger::DEBUG];
/**
* @return void
* @throws ReflectionException
*/
public function init()
{
Kiri::getDi()->get(EventProvider::class)->on(OnWorkerStop::class, [$this, 'onAfterRequest']);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*
* 紧急情况
*/
public function emergency($message, array $context = [])
{
// TODO: Implement emergency() method.
$this->log(Logger::EMERGENCY, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*
* 应该警惕的
*/
public function alert($message, array $context = [])
{
// TODO: Implement alert() method.
$this->log(Logger::ALERT, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*
* 关键性的日志
*/
public function critical($message, array $context = [])
{
// TODO: Implement critical() method.
$this->log(Logger::CRITICAL, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function error($message, array $context = [])
{
// TODO: Implement error() method.
$this->log(Logger::ERROR, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function warning($message, array $context = [])
{
// TODO: Implement warning() method.
$this->log(Logger::WARNING, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function notice($message, array $context = [])
{
// TODO: Implement notice() method.
$this->log(Logger::NOTICE, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function info($message, array $context = [])
{
// TODO: Implement info() method.
$this->log(Logger::INFO, $message, $context);
}
/**
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function debug($message, array $context = [])
{
// TODO: Implement debug() method.
$this->log(Logger::DEBUG, $message, $context);
}
/**
* @param mixed $level
* @param string $message
* @param array $context
* @throws ConfigException
*/
public function log($level, $message, array $context = [])
{
// TODO: Implement log() method.
$levels = Config::get('log.level', Logger::LOGGER_LEVELS);
if (!in_array($level, $levels) || str_contains($message, 'Event::rshutdown')) {
return;
}
$_string = '[' . now() . '] production.' . $level . ': ' . $this->_string($message, $context);
file_put_contents('php://output', $_string);
$this->_loggers[] = $_string;
}
/**
* @param OnWorkerStop $param
* @throws Exception
*/
public function onAfterRequest(OnWorkerStop $param)
{
$loggers = implode(PHP_EOL, $this->_loggers);
$this->_loggers = [];
if (!empty($loggers)) {
$filename = storage('log-' . date('Y-m-d') . '.log', 'log/');
file_put_contents($filename, $loggers);
}
}
/**
* @return void
* @throws Exception
*/
public function flush()
{
$this->removeFile(storage());
}
/**
* @param string $dirname
* @return void
*/
private function removeFile(string $dirname)
{
$paths = new DirectoryIterator($dirname);
/** @var DirectoryIterator $path */
foreach ($paths as $path) {
if ($path->isDot() || str_starts_with($path->getFilename(), '.')) {
continue;
}
if ($path->isDir()) {
$directory = rtrim($path->getRealPath(), '/');
$this->removeFile($directory);
}
@unlink($path->getRealPath());
}
}
/**
* @param $message
* @param $context
* @return string
*/
private function _string($message, $context): string
{
if (!empty($context)) {
return $message . ' ' . PHP_EOL . print_r($context, true) . PHP_EOL;
}
return $message . PHP_EOL;
}
}
+1 -3
View File
@@ -4,11 +4,9 @@ declare(strict_types=1);
namespace Kiri\Abstracts;
use Kiri\Application;
interface Provider
{
public function onImport(Application $application);
public function onImport();
}
-1
View File
@@ -11,5 +11,4 @@ namespace Kiri\Abstracts;
abstract class Providers extends Component implements Provider
{
}
@@ -1,32 +0,0 @@
<?php
namespace Kiri\Abstracts;
use Kiri\Annotation\Annotation as SAnnotation;
use Database\Connection;
use Database\DatabasesProviders;
use Kiri\Message\Handler\Router;
use Kiri\Server\Server;
use Kiri\Async;
use Kiri\Error\Logger;
use Kiri\Jwt\JWTAuth;
/**
* Trait TraitApplication
* @package Kiri\Abstracts
* @property Router $router
* @property Server $server
* @property DatabasesProviders $db
* @property Async $async
* @property Logger $logger
* @property JWTAuth $jwt
* @property SAnnotation $annotation
* @property BaseGoto $goto
* @property Connection $databases
*/
trait TraitApplication
{
}
+160 -260
View File
@@ -1,260 +1,160 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/25 0025
* Time: 18:38
*/
declare(strict_types=1);
namespace Kiri;
use Closure;
use Database\DatabasesProviders;
use Exception;
use Kiri;
use Kiri\Abstracts\{BaseApplication, Config, Kernel};
use Kiri\Crontab\CrontabProviders;
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
use Kiri\FileListen\HotReload;
use Kiri\Server\ServerProviders;
use ReflectionException;
use stdClass;
use Swoole\Process;
use Swoole\Timer;
use Symfony\Component\Console\{Application as ConsoleApplication,
Command\Command,
Input\ArgvInput,
Output\ConsoleOutput,
Output\OutputInterface
};
/**
* Class Init
*
* @package Kiri
*
* @property-read Config $config
*/
class Application extends BaseApplication
{
/**
* @var string
*/
public string $id = 'uniqueId';
public string $state = '';
/** @var array<array<Process>> */
private array $_process = [];
/**
*/
public function init()
{
$this->import(ServerProviders::class);
$this->register(Runtime::class);
}
/**
* @throws
*/
public function withDatabase()
{
$this->import(DatabasesProviders::class);
}
/**
* @throws
*/
public function withCrontab()
{
$this->import(CrontabProviders::class);
}
/**
* @param string $class
* @param Process $process
*/
public function addProcess(string $class, Process $process)
{
}
/**
* @return Process[]
*/
public function getProcess(): array
{
return $this->_process;
}
/**
* @param string $class
* @return Process|null
*/
public function getProcessName(string $class): ?Process
{
return $this->_process[$class] ?? null;
}
/**
* @throws
*/
public function withFileChangeListen()
{
$container = Kiri::getDi();
$console = $container->get(ConsoleApplication::class);
$console->add($container->get(HotReload::class));
}
/**
* @param Closure|array $closure
* @return $this
* @throws Exception
*/
public function middleware(Closure|array $closure): static
{
return $this;
}
/**
* @param bool $useTree
* @return $this
* @throws Exception
*/
public function setUseTree(bool $useTree): static
{
return $this;
}
/**
* @param string $service
* @return $this
* @throws
*/
public function import(string $service): static
{
if (!class_exists($service)) {
return $this;
}
$class = Kiri::getDi()->get($service);
if (method_exists($class, 'onImport')) {
$class->onImport($this);
}
return $this;
}
/**
* @param Kernel $kernel
* @return $this
*/
public function commands(Kernel $kernel): static
{
foreach ($kernel->getCommands() as $command) {
$this->register($command);
}
return $this;
}
/**
* @param string $command
* @throws
*/
public function register(string $command)
{
di(ConsoleApplication::class)->add(di($command));
}
/**
* @param array $argv
* @return void
*/
public function execute(array $argv): void
{
ini_set('swoole.enable_preemptive_scheduler', 'On');
ini_set('swoole.enable_library', 'On');
[$input, $output] = $this->argument($argv);
try {
$console = di(ConsoleApplication::class);
$command = $input->getFirstArgument();
if (empty($command)) {
$command = 'sw:server';
}
$command = $console->find($command);
if ($command instanceof Command) {
$this->enableFileChange($command, $input, $output);
}
} catch (\Throwable $exception) {
$output->writeln(jTraceEx($exception));
} finally {
Timer::clearAll();
}
}
/**
* @param $argv
* @return array
*/
private function argument($argv): array
{
return [new ArgvInput($argv), new ConsoleOutput()];
}
/**
* @throws ReflectionException
* @throws Exception
*/
private function enableFileChange(Command $class, $input, $output): void
{
fire(new OnBeforeCommandExecute());
if (!($class instanceof HotReload)) {
$config = Config::get('scanner', []);
if (!empty($config)) {
foreach ($config as $key => $value) {
scan_directory($value, $key);
}
}
scan_directory(MODEL_PATH, 'app\Model');
}
$this->getContainer()->setBindings(OutputInterface::class, $output);
$class->run($input, $output);
fire(new OnAfterCommandExecute());
$output->writeln('ok' . PHP_EOL);
}
/**
* @param $className
* @param null $abstracts
* @return stdClass
* @throws Exception
*/
public function make($className, $abstracts = null): stdClass
{
return make($className, $abstracts);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/25 0025
* Time: 18:38
*/
declare(strict_types=1);
namespace Kiri;
use Exception;
use Kiri;
use Kiri\Abstracts\{BaseApplication, Kernel};
use Kiri\Di\Scanner;
use Kiri\Error\ErrorHandler;
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionException;
use Symfony\Component\Console\{Application as ConsoleApplication,
Exception\ExceptionInterface,
Input\ArgvInput,
Output\ConsoleOutput,
Output\OutputInterface
};
use Kiri\Server\ServerCommand;
use Kiri\Di\Inject\Container;
use function config;
/**
* Class Init
*
* @package Kiri
*/
class Application extends BaseApplication
{
/**
* @var string
*/
public string $id = 'uniqueId';
public string $state = '';
/**
* @var ErrorHandler
*/
#[Container(ErrorHandler::class)]
public ErrorHandler $errorHandler;
/**
* @return void
* @throws
*/
public function init(): void
{
$this->errorHandler->registerShutdownHandler(config('error.shutdown', []));
$this->errorHandler->registerExceptionHandler(config('error.exception', []));
$this->errorHandler->registerErrorHandler(config('error.error', []));
$this->id = config('id', uniqid('id.'));
$this->provider->on(OnBeforeCommandExecute::class, [$this, 'beforeCommandExecute']);
}
/**
* @param OnBeforeCommandExecute $beforeCommandExecute
* @return void
* @throws
*/
public function beforeCommandExecute(OnBeforeCommandExecute $beforeCommandExecute): void
{
if (!($beforeCommandExecute->command instanceof ServerCommand)) {
$scanner = $this->container->get(Scanner::class);
$scanner->load_directory(APP_PATH . 'app/');
} else if (config('reload.hot', false) === false) {
$scanner = $this->container->get(Scanner::class);
$scanner->load_directory(APP_PATH . 'app/');
}
}
/**
* @param string ...$services
* @return $this
* @throws
*/
public function import(string ...$services): static
{
foreach ($services as $service) {
if (!class_exists($service)) {
continue;
}
/** @var Kiri\Abstracts\Provider $class */
$class = $this->container->get($service);
if (method_exists($class, 'onImport')) {
$class->onImport();
}
}
return $this;
}
/**
* @param Kernel $kernel
* @return $this
* @throws
*/
public function commands(Kernel $kernel): static
{
foreach ($kernel->getCommands() as $command) {
$this->command($command);
}
return $this;
}
/**
* @param string ...$command
* @return void
* @throws
*/
public function command(string ...$command): void
{
$console = $this->container->get(ConsoleApplication::class);
foreach ($command as $value) {
$console->add($this->container->get($value));
}
}
/**
* @param array $argv
* @return void
* @throws
*/
public function execute(array $argv): void
{
/** @var ArgvInput $input */
$input = $this->container->bind(ArgvInput::class, new ArgvInput($argv));
/** @var ConsoleOutput $output */
$output = $this->container->bind(OutputInterface::class, new ConsoleOutput());
$console = $this->container->get(ConsoleApplication::class);
$command = $console->find($input->getFirstArgument() ?? 'list');
fire(new OnBeforeCommandExecute($command));
$command->run($input, $output);
fire(new OnAfterCommandExecute($command));
$output->writeln('execute complete.');
}
}
-44
View File
@@ -1,44 +0,0 @@
<?php
namespace Kiri;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Server\ServerManager;
use Kiri\Task\AsyncTaskExecute;
use Kiri;
/**
* Class Async
* @package Kiri
*/
class Async extends Component
{
private static array $_absences = [];
/**
* @param string $name
* @param string $handler
*/
public function addAsync(string $name, string $handler)
{
static::$_absences[$name] = $handler;
}
/**
* @param string $name
* @param array $params
* @throws Exception
*/
public function dispatch(string $name, array $params = [])
{
$context = di(AsyncTaskExecute::class);
$context->execute(static::$_absences[$name], $params);
}
}
-185
View File
@@ -1,185 +0,0 @@
<?php
namespace Kiri\Cache\Base;
use Exception;
use Kiri\Abstracts\Logger;
use Kiri\Events\EventProvider;
use Kiri\Exception\RedisConnectException;
use Kiri;
use Kiri\Pool\StopHeartbeatCheck;
use Kiri\Server\Events\OnWorkerExit;
use RedisException;
use Swoole\Timer;
/**
*
*/
class Redis implements StopHeartbeatCheck
{
const DB_ERROR_MESSAGE = 'The system is busy, please try again later.';
private ?\Redis $pdo = null;
public string $host;
public int $port;
public int $database = 0;
public string $auth = '';
public string $prefix = '';
public int $timeout = 30;
public int $read_timeout = 30;
public array $pool = [];
private int $_timer = -1;
private int $_last = 0;
/**
* @param array $config
*/
public function __construct(array $config)
{
$this->host = $config['host'];
$this->port = $config['port'];
$this->database = $config['databases'];
$this->auth = $config['auth'];
$this->prefix = $config['prefix'];
$this->timeout = $config['timeout'];
$this->read_timeout = $config['read_timeout'];
$this->pool = $config['pool'];
}
public function init()
{
$this->heartbeat_check();
}
/**
* @param Kiri\Server\Events\OnWorkerExit $exit
* @return void
*/
public function onWorkerExit(OnWorkerExit $exit)
{
$this->stopHeartbeatCheck();
}
/**
*
*/
public function heartbeat_check(): void
{
if ($this->_timer === -1) {
$this->_timer = Timer::tick(1000, fn() => $this->waite());
}
}
/**
* @throws Exception
*/
private function waite(): void
{
try {
if ($this->_timer === -1) {
Kiri::getDi()->get(Logger::class)->critical('timer end');
$this->stopHeartbeatCheck();
}
if (time() - $this->_last > intval($this->pool['tick'] ?? 60)) {
$this->stopHeartbeatCheck();
$this->pdo = null;
}
} catch (\Throwable $throwable) {
error($throwable);
}
}
/**
*
*/
public function stopHeartbeatCheck(): void
{
if ($this->_timer > -1) {
Timer::clear($this->_timer);
}
$this->_timer = -1;
}
/**
* @param string $name
* @param array $arguments
* @return mixed
* @throws RedisConnectException|RedisException
*/
public function __call(string $name, array $arguments)
{
if (!method_exists($this, $name)) {
return $this->_pdo()->{$name}(...$arguments);
}
return $this->{$name}(...$arguments);
}
/**
* @return \Redis
* @throws RedisConnectException
* @throws RedisException
*/
public function _pdo(): \Redis
{
if ($this->_timer === -1) {
$this->heartbeat_check();
}
if (!($this->pdo instanceof \Redis) || !$this->pdo->ping('isOk')) {
$this->pdo = $this->newClient();
}
return $this->pdo;
}
/**
* @return \Redis
* @throws RedisConnectException
*/
private function newClient(): \Redis
{
$redis = new \Redis();
if (!$redis->connect($this->host, $this->port, $this->timeout)) {
throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $this->host, $this->port));
}
if (!empty($this->auth) && !$redis->auth($this->auth)) {
throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $this->auth));
}
if ($this->read_timeout < 0) {
$this->read_timeout = 0;
}
$redis->select($this->database);
if ($this->read_timeout > 0) {
$redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->read_timeout);
}
$redis->setOption(\Redis::OPT_PREFIX, $this->prefix);
return $redis;
}
}
-141
View File
@@ -1,141 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/5/2 0002
* Time: 14:51
*/
declare(strict_types=1);
namespace Kiri\Cache;
use JetBrains\PhpStorm\Pure;
use Kiri\Abstracts\Component;
use Swoole\Coroutine\System;
/**
* Class File
* @package Kiri\Cache
*/
class File extends Component implements ICache
{
public string $path;
/**
* @param $key
* @param $val
* @return string|int
*/
public function set($key, $val): string|int
{
if (is_array($val) || is_object($val)) {
$val = swoole_serialize($val);
}
$tmpFile = $this->getCacheKey($key);
if (!$this->exists($tmpFile)) {
touch($tmpFile);
}
return System::writeFile($tmpFile, $val, LOCK_EX);
}
/**
* @param $key
* @param array $hashKeys
* @return array|bool
*/
public function hMGet($key, array $hashKeys): array|bool
{
$hash = $this->get($key);
if (!is_array($hash)) {
return false;
}
$nowHash = [];
foreach ($hashKeys as $hashKey) {
$nowHash[$hashKey] = $hash[$hashKey] ?? null;
}
return $nowHash;
}
/**
* @param $key
* @param array $val
* @return bool|int|string
*/
public function hMSet($key, array $val): bool|int|string
{
$hash = $this->get($key);
if (!is_array($hash)) {
return false;
}
$merge = array_merge($hash, $val);
return $this->set($key, $merge);
}
/**
* @param string $key
* @param string $hashKey
* @return string|int|bool
*/
public function hGet(string $key, string $hashKey): string|int|bool
{
$hash = $this->get($key);
if (!is_array($hash)) {
return false;
}
return $hash[$hashKey] ?? false;
}
/**
* @param $key
* @param $hashKey
* @param $hashValue
* @return bool|int|string
*/
public function hSet($key, $hashKey, $hashValue): bool|int|string
{
$hash = $this->get($key);
if (!is_array($hash)) {
return false;
}
$hash[$hashKey] = $hashValue;
return $this->set($key, $hash);
}
/**
* @param $key
* @return bool
*/
#[Pure] public function exists($key): bool
{
return file_exists($key);
}
/**
* @param $key
* @return mixed|bool
*/
public function get($key): string|bool
{
$tmpFile = $this->getCacheKey($key);
if (!$this->exists($tmpFile)) {
return false;
}
$content = file_get_contents($tmpFile);
return swoole_unserialize($content);
}
/**
* @param $key
* @return string
* @throws
*/
private function getCacheKey($key): string
{
return storage($key, 'cache');
}
}
-65
View File
@@ -1,65 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/11/8 0008
* Time: 16:35
*/
declare(strict_types=1);
namespace Kiri\Cache;
/**
* Interface ICache
* @package Kiri\Cache
*/
interface ICache
{
/**
* @param $key
* @param $val
* @return string|int
*/
public function set($key, $val): string|int;
/**
* @param $key
* @return string|int|bool
*/
public function get($key): string|int|bool;
/**
* @param $key
* @param array $hashKeys
* @return array|bool|null
*/
public function hMGet($key, array $hashKeys): array|bool|null;
/**
* @param $key
* @param array $val
* @return mixed
*/
public function hMSet($key, array $val): mixed;
/**
* @param string $key
* @param string $hashKey
* @return string|int|bool
*/
public function hGet(string $key, string $hashKey): string|int|bool;
/**
* @param $key
* @param $hashKey
* @param $hashValue
* @return mixed
*/
public function hSet($key, $hashKey, $hashValue): mixed;
/**
* @param $key
* @return bool
*/
public function exists($key): bool;
}
-191
View File
@@ -1,191 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/27 0027
* Time: 11:00
*/
declare(strict_types=1);
namespace Kiri\Cache;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Kiri;
use Kiri\Pool\Redis as PoolRedis;
use Kiri\Annotation\Inject;
use Kiri\Server\Events\OnWorkerExit;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Swoole\Timer;
/**
* Class Redis
* @package Kiri\Cache
* @mixin \Redis
*/
class Redis extends Component
{
const REDIS_OPTION_HOST = 'host';
const REDIS_OPTION_PORT = 'port';
const REDIS_OPTION_PREFIX = 'prefix';
const REDIS_OPTION_AUTH = 'auth';
const REDIS_OPTION_DATABASES = 'databases';
const REDIS_OPTION_TIMEOUT = 'timeout';
const REDIS_OPTION_POOL = 'pool';
const REDIS_OPTION_POOL_TICK = 'tick';
const REDIS_OPTION_POOL_MIN = 'min';
const REDIS_OPTION_POOL_MAX = 'max';
/**
* @return void
* @throws ConfigException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception
*/
public function init()
{
$connections = Kiri::getDi()->get(PoolRedis::class);
$config = $this->get_config();
$length = Config::get('cache.redis.pool.max', 10);
$this->getEventProvider()->on(OnWorkerExit::class, [$this, 'destroy'], 0);
$connections->initConnections('Redis:' . $config['host'], true, $length);
}
/**
* @param $name
* @param $arguments
* @return mixed
* @throws
*/
public function __call($name, $arguments): mixed
{
$time = microtime(true);
if (method_exists($this, $name)) {
$data = $this->{$name}(...$arguments);
} else {
$data = $this->proxy($name, $arguments);
}
if (microtime(true) - $time >= 0.02) {
$this->warning('Redis:' . Json::encode([$name, $arguments]) . (microtime(true) - $time));
}
return $data;
}
/**
* @param $key
* @param int $timeout
* @return bool
*/
public function waite($key, int $timeout = 5): bool
{
$time = time();
while (!$this->setNx($key, 1)) {
if (time()- $time >= $timeout) {
return FALSE;
}
usleep(1000);
}
$this->expire($key, $timeout);
return TRUE;
}
/**
* @param $key
* @param int $timeout
* @return bool|int
* @throws Exception
*/
public function lock($key, int $timeout = 5): bool|int
{
$script = <<<SCRIPT
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
if (_nx ~= 0) then
redis.call('expire',KEYS[1], ARGV[1])
return 1
end
return 0
SCRIPT;
return $this->eval($script, ['{lock}:' . $key, $timeout], 1);
}
/**
* @param $key
* @return int
* @throws Exception
*/
public function unlock($key): int
{
return $this->del('{lock}:' . $key);
}
/**
* @throws ConfigException
* @throws Exception
*/
public function release()
{
$connections = Kiri::getDi()->get(PoolRedis::class);
$connections->release($this->get_config(), true);
}
/**
* 销毁连接池
* @throws ConfigException
* @throws Exception
*/
public function destroy()
{
$connections = Kiri::getDi()->get(PoolRedis::class);
$connections->connection_clear($this->get_config(), true);
}
/**
* @param $name
* @param $arguments
* @return mixed
* @throws ConfigException
* @throws Exception
*/
public function proxy($name, $arguments): mixed
{
$connections = Kiri::getDi()->get(PoolRedis::class);
$config = $this->get_config();
$client = $connections->get($config, true);
if (!($client instanceof Base\Redis)) {
throw new Exception('Redis connections more.');
}
$response = $client->{$name}(...$arguments);
$this->release();
return $response;
}
/**
* @return array
* @throws ConfigException
*/
public function get_config(): array
{
return Config::get('cache.redis', null, true);
}
}
+151
View File
@@ -0,0 +1,151 @@
<?php
namespace Kiri\Config;
use Kiri\Core\HashMap;
class ConfigProvider
{
private HashMap $hashMap;
/**
*
*/
public function __construct()
{
$this->hashMap = new HashMap();
$this->load(sweep(APP_PATH . 'config'));
$this->enableEnvConfig(APP_PATH . '.env');
}
/**
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get(string $key, mixed $default = null): mixed
{
$keys = explode('.', $key);
$hashMap = $this->hashMap->get(array_shift($keys));
if (is_null($hashMap)) {
return $default;
}
if (count($keys) < 1 || !is_array($hashMap)) {
return $hashMap;
}
foreach ($keys as $string) {
if (!isset($hashMap[$string])) {
return $default;
}
$hashMap = $hashMap[$string];
}
return $hashMap;
}
/**
* @param string $key
* @param mixed $value
* @return bool
*/
public function modify(string $key, mixed $value): bool
{
$keys = explode('.', $key);
$hashMap = $this->hashMap->get(array_shift($keys));
if (is_null($hashMap)) {
return false;
}
$setting = &$hashMap;
foreach ($keys as $k => $val) {
if (!is_array($val)) {
unset($setting);
return false;
}
$setting = &$setting[$k];
}
$setting = $value;
unset($setting);
return $this->get($key) == $value;
}
/**
* @param array $config
* @return void
*/
private function load(array $config): void
{
foreach ($config as $key => $value) {
$this->hashMap->put($key, $value);
}
}
/**
* @param $envPath
* @return void
*/
private function enableEnvConfig($envPath): void
{
if (!file_exists($envPath)) {
return;
}
$lines = $this->readLinesFromFile($envPath);
foreach ($lines as $line) {
if (!$this->isComment($line) && $this->looksLikeSetter($line)) {
[$key, $value] = explode('=', $line);
putenv(trim($key) . '=' . trim($value));
}
}
}
/**
* Read lines from the file, auto detecting line endings.
*
* @param string $filePath
*
* @return array
*/
protected function readLinesFromFile(string $filePath): array
{
// Read file into an array of lines with auto-detected line endings
return file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
}
/**
* Determine if the line in the file is a comment, e.g. begins with a #.
*
* @param string $line
*
* @return bool
*/
protected function isComment(string $line): bool
{
$line = ltrim($line);
return isset($line[0]) && $line[0] === '#';
}
/**
* Determine if the given line looks like it's setting a variable.
*
* @param string $line
*
* @return bool
*/
protected function looksLikeSetter(string $line): bool
{
return str_contains($line, '=');
}
}
-209
View File
@@ -1,209 +0,0 @@
<?php
namespace Kiri;
use Kiri\Abstracts\BaseContext;
use Swoole\Coroutine;
use Kiri;
/**
* Class Context
* @package Yoc\http
*/
class Context extends BaseContext
{
protected static array $_contents = [];
/**
* @param $id
* @param $context
* @param null $coroutineId
* @return mixed
*/
public static function setContext($id, $context, $coroutineId = null): mixed
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
if (Coroutine::getCid() !== -1) {
return Coroutine::getContext($coroutineId)[$id] = $context;
}
return static::$_contents[$id] = $context;
}
/**
* @param $id
* @param int $value
* @param null $coroutineId
* @return bool|int
*/
public static function increment($id, int $value = 1, $coroutineId = null): bool|int
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
Coroutine::getContext($coroutineId)[$id] = 0;
}
return Coroutine::getContext($coroutineId)[$id] += $value;
}
/**
* @param $id
* @param int $value
* @param null $coroutineId
* @return bool|int
*/
public static function decrement($id, int $value = 1, $coroutineId = null): bool|int
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
Coroutine::getContext($coroutineId)[$id] = 0;
}
return Coroutine::getContext($coroutineId)[$id] -= $value;
}
/**
* @param $id
* @param null $default
* @param null $coroutineId
* @return mixed
*/
public static function getContext($id, $default = null, $coroutineId = null): mixed
{
if (Coroutine::getCid() === -1) {
return static::loadByStatic($id, $default);
}
return static::loadByContext($id, $default, $coroutineId);
}
/**
* @param $id
* @param null $default
* @param null $coroutineId
* @return mixed
*/
private static function loadByContext($id, $default = null, $coroutineId = null): mixed
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
return Coroutine::getContext($coroutineId)[$id] ?? $default;
}
/**
* @param $id
* @param null $default
* @return mixed
*/
private static function loadByStatic($id, $default = null): mixed
{
return static::$_contents[$id] ?? $default;
}
/**
* @param null $coroutineId
* @return mixed
*/
public static function getAllContext($coroutineId = null): mixed
{
if (Coroutine::getCid() === -1) {
return Coroutine::getContext($coroutineId) ?? [];
} else {
return static::$_contents ?? [];
}
}
/**
* @param string $id
* @param null $coroutineId
*/
public static function remove(string $id, $coroutineId = null)
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
if (!static::hasContext($id, $coroutineId)) {
return;
}
if (Coroutine::getCid() === -1) {
unset(static::$_contents[$id]);
} else {
unset(Coroutine::getContext($coroutineId)[$id]);
}
}
/**
* @param $id
* @param null $key
* @param null $coroutineId
* @return bool
*/
public static function hasContext($id, $key = null, $coroutineId = null): bool
{
if (Coroutine::getCid() === -1) {
return static::searchByStatic($id, $key);
}
return static::searchByCoroutine($id, $key, $coroutineId);
}
/**
* @param $id
* @param null $key
* @return bool
*/
private static function searchByStatic($id, $key = null): bool
{
if (!isset(static::$_contents[$id])) {
return false;
}
$value = static::$_contents[$id];
if (!empty($key) && is_array($value)) {
return isset($value[$key]);
}
return true;
}
/**
* @param $id
* @param null $key
* @param null $coroutineId
* @return bool
*/
private static function searchByCoroutine($id, $key = null, $coroutineId = null): bool
{
if (is_null($coroutineId)) {
$coroutineId = Coroutine::getCid();
}
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
return false;
}
$value = Coroutine::getContext($coroutineId)[$id];
if ($key !== null && is_array($value)) {
return isset($value[$key]);
}
return true;
}
/**
* @return bool
*/
public static function inCoroutine(): bool
{
return Coroutine::getCid() !== -1;
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Kiri;
class Coordinator
{
const string WORKER_START = 'worker:start';
private bool $waite = false;
/**
* @return void
*/
public function yield(): void
{
if ($this->waite === false) {
return;
}
$this->yield();
}
/**
* @return void
*/
public function waite(): void
{
$this->waite = true;
}
/**
* @return void
*/
public function done(): void
{
$this->waite = false;
}
}
+73 -75
View File
@@ -10,8 +10,6 @@ declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class ArrayAccess
* @package Kiri\Core
@@ -19,82 +17,82 @@ use Exception;
class ArrayAccess
{
/**
* @param $data
* @return array
* @throws Exception
*/
public static function toArray($data): array
{
if (!is_object($data) && !is_array($data)) {
return [];
}
if (is_object($data)) {
$data = self::objToArray($data);
}
$tmp = [];
if (!is_array($data)) {
return $tmp;
}
foreach ($data as $key => $val) {
if (is_array($val) || is_object($val)) {
$tmp[$key] = self::toArray($val);
} else {
$tmp[$key] = $val;
}
}
return $tmp;
}
/**
* @param $data
* @return array
* @throws
*/
public static function toArray($data): array
{
if (!is_object($data) && !is_array($data)) {
return [];
}
if (is_object($data)) {
$data = self::objToArray($data);
}
$tmp = [];
if (!is_array($data)) {
return $tmp;
}
foreach ($data as $key => $val) {
if (is_array($val) || is_object($val)) {
$tmp[$key] = self::toArray($val);
} else {
$tmp[$key] = $val;
}
}
return $tmp;
}
/**
* @param $data
* @return array
* @throws Exception
*/
public static function objToArray($data): array
{
if (!is_object($data)) {
return $data;
}
if (method_exists($data, 'get')) {
$data = $data->get();
if (is_array($data)) {
return $data;
}
}
if (method_exists($data, 'toArray')) {
$data = $data->toArray();
} else {
$data = get_object_vars((object)$data);
}
return $data;
}
/**
* @param $data
* @return array
* @throws
*/
public static function objToArray($data): array
{
if (!is_object($data)) {
return $data;
}
if (method_exists($data, 'get')) {
$data = $data->get();
if (is_array($data)) {
return $data;
}
}
if (method_exists($data, 'toArray')) {
$data = $data->toArray();
} else {
$data = get_object_vars((object)$data);
}
return $data;
}
/**
* @param array $oldArray
* @param array $newArray
* @return array
*/
public static function merge(array $oldArray, array $newArray): array
{
if (empty($oldArray)) {
return $newArray;
} else if (empty($newArray)) {
return $oldArray;
}
foreach ($newArray as $item => $value) {
if (!isset($oldArray[$item])) {
$oldArray[$item] = $value;
}
if (is_array($value)) {
$oldArray[$item] = self::merge($oldArray[$item], $value);
} else {
$oldArray[$item] = $value;
}
}
return $oldArray;
}
/**
* @param array $oldArray
* @param array $newArray
* @return array
*/
public static function merge(array $oldArray, array $newArray): array
{
if (empty($oldArray)) {
return $newArray;
} else if (empty($newArray)) {
return $oldArray;
}
foreach ($newArray as $item => $value) {
if (!isset($oldArray[$item])) {
$oldArray[$item] = $value;
}
if (is_array($value)) {
$oldArray[$item] = self::merge($oldArray[$item], $value);
} else {
$oldArray[$item] = $value;
}
}
return $oldArray;
}
}
+99 -75
View File
@@ -10,7 +10,6 @@ declare(strict_types=1);
namespace Kiri\Core;
/**
* Class DateFormat
* @package Kiri\Core
@@ -18,87 +17,112 @@ namespace Kiri\Core;
class DateFormat
{
/**
* @param $time
* @return bool|false|int|string
*/
private static function check($time): bool|int|string
{
if ($time === null) {
$time = time();
} else if (is_numeric($time)) {
$length = strlen((string)$time);
if ($length != 10 && $length != 13) {
return false;
}
} else if (is_string($time)) {
$time = strtotime($time);
}
if (date('Y-m-d', $time)) {
return $time;
}
return false;
}
/**
* @return int
*/
public static function DaySecond(): int
{
$time = strtotime(date('Y-m-d', strtotime('+1days')));
return $time - time();
}
/**
* @param null $time
* @return bool|false|int
*
* 获取指定日期当周第一天的时间
*/
public static function getWeekCurrentDay($time = null): bool|int
{
if (!($time = static::check($time))) {
return false;
}
$time = strtotime('-' . (date('N') - 1) . 'days', $time);
return strtotime(date('Y-m-d'), $time);
}
/**
* @param int $time
* @return array
*/
public static function timeFromStrDate(int $time): array
{
$year = date('Y', $time);
$month = date('m', $time);
$day = date('d', $time);
return [$year, $month, $day];
}
/**
* @param null $time
* @return bool|false|int
*
* 获取指定日期当月第一天的时间
*/
public static function getMonthCurrentDay($time = null): bool|int
{
if (!($time = static::check($time))) {
return false;
}
/**
* @param $time
* @return bool|false|int|string
*/
private static function check($time): bool|int|string
{
if ($time === null) {
$time = time();
} else if (is_numeric($time)) {
$length = strlen((string)$time);
if ($length != 10 && $length != 13) {
return false;
}
} else if (is_string($time)) {
$time = strtotime($time);
}
return strtotime(date('Y-m', $time) . '-01');
}
if (date('Y-m-d', $time)) {
return $time;
}
return false;
}
/**
* @param $time
* @return bool|int|string 指定的月份有几天
* 指定的月份有几天
*/
public static function getMonthTotalDay($time): bool|int|string
{
if (!($time = static::check($time))) {
return false;
}
return date('t', $time);
}
/**
* @param null $time
* @return bool|false|int
*
* 获取指定日期当周第一天的时间
*/
public static function getWeekCurrentDay($time = null): bool|int
{
if (!($time = static::check($time))) {
return false;
}
/**
* @param $startTime
* @param null $endTime
* @return string
*/
public static function mtime($startTime, $endTime = null)
{
if ($endTime === null) {
$endTime = microtime(true);
}
return sprintf('%.7f', $endTime - $startTime);
}
$time = strtotime('-' . (date('N') - 1) . 'days', $time);
return strtotime(date('Y-m-d'), $time);
}
/**
* @param null $time
* @return bool|false|int
*
* 获取指定日期当月第一天的时间
*/
public static function getMonthCurrentDay($time = null): bool|int
{
if (!($time = static::check($time))) {
return false;
}
return strtotime(date('Y-m', $time) . '-01');
}
/**
* @param $time
* @return bool|int|string 指定的月份有几天
* 指定的月份有几天
*/
public static function getMonthTotalDay($time): bool|int|string
{
if (!($time = static::check($time))) {
return false;
}
return date('t', $time);
}
/**
* @param $startTime
* @param null $endTime
* @return string
*/
public static function mtime($startTime, $endTime = null): string
{
if ($endTime === null) {
$endTime = microtime(true);
}
return sprintf('%.7f', $endTime - $startTime);
}
}
-58
View File
@@ -1,58 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
use Kiri\Abstracts\Component;
/**
* Class Dtl
* @package Kiri\Core
*/
class Dtl extends Component
{
protected array $params;
/**
* Dtl constructor.
* @param $params
* @throws Exception
*/
public function __construct($params)
{
parent::__construct([]);
$this->params = $params;
}
/**
* @return array
* @throws Exception
*/
public function toArray(): array
{
return $this->params;
}
/**
* @param $name
* @return mixed
* @throws Exception
*/
public function get($name): mixed
{
$array = $this->toArray();
if (!isset($array[$name])) {
return null;
}
return $array[$name];
}
}
+119 -73
View File
@@ -2,6 +2,7 @@
namespace Kiri\Core;
use Exception;
use JetBrains\PhpStorm\Pure;
use ReturnTypeWillChange;
use Traversable;
@@ -9,10 +10,10 @@ use Traversable;
class HashMap implements \ArrayAccess, \IteratorAggregate
{
/**
* @var array
*/
private array $lists = [];
/**
* @var array
*/
private array $lists = [];
/**
@@ -25,87 +26,132 @@ class HashMap implements \ArrayAccess, \IteratorAggregate
/**
* @param string $key
* @param $value
*/
public function put(string $key, $value)
{
$this->lists[$key] = $value;
}
* @return bool
*/
public function hasItem(): bool
{
return count($this->lists) > 0;
}
/**
* @param string $key
* @return mixed
*/
#[Pure] public function get(string $key): mixed
{
if (!$this->has($key)) {
return null;
}
return $this->lists[$key];
}
/**
* @param string $key
* @param $value
*/
public function put(string $key, $value): void
{
$this->lists[$key] = $value;
}
/**
* @param string $key
*/
public function del(string $key)
{
if (!$this->has($key)) {
return;
}
unset($this->lists[$key]);
}
/**
* @param string $key
* @param $value
* @return void
* @throws Exception
*/
public function append(string $key, $value): void
{
if (!$this->has($key)) {
$this->lists[$key] = [];
} else if (!is_array($this->lists[$key])) {
throw new Exception('Source must a array.');
}
$this->lists[$key][] = $value;
}
/**
* @param string $key
* @return bool
*/
public function has(string $key): bool
{
return array_key_exists($key, $this->lists);
}
/**
* @param string $key
* @param mixed|null $default
* @return mixed
*/
#[Pure] public function get(string $key, mixed $default = null): mixed
{
if (!$this->has($key)) {
return $default;
}
return $this->lists[$key];
}
/**
* @param mixed $offset
* @return bool
*/
public function offsetExists(mixed $offset): bool
{
return isset($this->lists[$offset]);
}
/**
* @param string $key
*/
public function del(string $key): void
{
if (!$this->has($key)) {
return;
}
unset($this->lists[$key]);
}
/**
* @param mixed $offset
* @return mixed
*/
#[Pure] public function offsetGet(mixed $offset): mixed
{
return $this->get($offset);
}
/**
* @param string $key
* @return bool
*/
public function has(string $key): bool
{
return array_key_exists($key, $this->lists);
}
/**
* @param mixed $offset
* @param mixed $value
*/
#[ReturnTypeWillChange]
public function offsetSet(mixed $offset, mixed $value)
{
$this->put($offset, $value);
}
/**
* @param mixed $offset
* @return bool
*/
public function offsetExists(mixed $offset): bool
{
return isset($this->lists[$offset]);
}
/**
* @param mixed $offset
*/
#[ReturnTypeWillChange]
public function offsetUnset(mixed $offset)
{
unset($this->lists[$offset]);
}
/**
* @param mixed $offset
* @return mixed
*/
#[Pure] public function offsetGet(mixed $offset): mixed
{
return $this->get($offset);
}
/**
* @param mixed $offset
* @param mixed $value
*/
#[ReturnTypeWillChange]
public function offsetSet(mixed $offset, mixed $value): void
{
$this->put($offset, $value);
}
/**
* @param mixed $offset
*/
#[ReturnTypeWillChange]
public function offsetUnset(mixed $offset): void
{
unset($this->lists[$offset]);
}
/**
* @param HashMap $root
* @param string $leaf
* @return HashMap
*/
public static function Tree(HashMap $root, string $leaf): HashMap
{
if ($root->has($leaf)) {
$hashMap = $root->get($leaf);
} else {
$hashMap = new HashMap();
$root->put($leaf, $hashMap);
}
return $hashMap;
}
}
+291 -185
View File
@@ -6,6 +6,8 @@ namespace Kiri\Core;
use Exception;
use Swift_Message;
use Swift_SmtpTransport;
/**
@@ -15,205 +17,309 @@ use Exception;
class Help
{
/**
* @param array $data
* @return string
*/
public static function toXml(array $data): string
{
$xml = "<xml>";
foreach ($data as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . static::xmlChild($val) . "</" . $key . ">";
} else if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* @param array $data
* @return string
*/
public static function toXml(array $data): string
{
$xml = "<xml>";
foreach ($data as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . static::xmlChild($val) . "</" . $key . ">";
} else if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* @param array $array
* @return string
*/
private static function xmlChild(array $array): string
{
$string = '';
foreach ($array as $key => $value) {
if (is_array($value)) {
$string .= static::xmlChild($value);
} else if (is_numeric($value)) {
$string .= "<" . $key . ">" . $value . "</" . $key . ">";
} else {
$string .= "<" . $key . "><![CDATA[" . $value . "]]></" . $key . ">";
}
}
return $string;
}
/**
* @param array $array
* @return string
*/
private static function xmlChild(array $array): string
{
$string = '';
foreach ($array as $key => $value) {
if (is_array($value)) {
$string .= static::xmlChild($value);
} else if (is_numeric($value)) {
$string .= "<" . $key . ">" . $value . "</" . $key . ">";
} else {
$string .= "<" . $key . "><![CDATA[" . $value . "]]></" . $key . ">";
}
}
return $string;
}
/**
* @param $xml
* @return mixed
* @throws Exception
*/
public static function toArray($xml): mixed
{
if (empty($xml)) {
return [];
} else if (is_array($xml)) {
return $xml;
}
if (!($_xml = Xml::isXml($xml))) {
return static::jsonToArray($xml);
}
return $_xml;
}
/**
* @param $xml
* @return mixed
* @throws
*/
public static function toArray($xml): mixed
{
if (empty($xml)) {
return [];
} else if (is_array($xml)) {
return $xml;
}
if (!($_xml = Xml::isXml($xml))) {
return static::jsonToArray($xml);
}
return $_xml;
}
/**
* @param $xml
* @return mixed
*/
public static function jsonToArray($xml): mixed
{
$_xml = json_decode($xml, true);
if (is_null($_xml)) {
return [];
}
return $_xml;
}
/**
* @param $xml
* @return mixed
*/
public static function jsonToArray($xml): mixed
{
$_xml = json_decode($xml, true);
if (is_null($_xml)) {
return [];
}
return $_xml;
}
/**
* @param $xml
* @return mixed
*/
public static function xmlToArray($xml): mixed
{
if (is_array($xml)) {
return $xml;
}
if (($data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)) !== false) {
return json_decode(json_encode($data), TRUE);
}
if (!is_null($json = json_decode($xml, TRUE))) {
return $json;
}
return $xml;
}
/**
* @param $xml
* @return mixed
*/
public static function xmlToArray($xml): mixed
{
if (is_array($xml)) {
return $xml;
}
if (($data = @simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)) !== false) {
return json_decode(json_encode($data), TRUE);
}
if (!is_null($json = json_decode($xml, TRUE))) {
return $json;
}
return $xml;
}
/**
* @param $parameter
* @return array|false|string
* @throws Exception
*/
public static function toString($parameter): bool|array|string
{
if (!is_string($parameter)) {
$parameter = ArrayAccess::toArray($parameter);
if (is_array($parameter)) {
$parameter = Json::encode($parameter);
}
}
return $parameter;
}
/**
* @param $parameter
* @return array|false|string
* @throws
*/
public static function toString($parameter): bool|array|string
{
if (!is_string($parameter)) {
$parameter = Json::encode(ArrayAccess::toArray($parameter));
}
return $parameter;
}
/**
* @param mixed $json
* @return bool|string
*/
public static function toJson(mixed $json): bool|string
{
if (is_object($json)) {
$json = get_object_vars($json);
}
if (is_array($json)) {
return json_encode($json, JSON_UNESCAPED_UNICODE);
}
$matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';
if (preg_match($matchQuote, $json)) {
$json = self::xmlToArray($json);
} else {
$json = json_decode($json, true);
}
if (!is_array($json)) {
$json = [];
}
return json_encode($json, JSON_UNESCAPED_UNICODE);
}
/**
* @param mixed $json
* @return bool|string
*/
public static function toJson(mixed $json): bool|string
{
if (is_object($json)) {
$json = get_object_vars($json);
}
if (is_array($json)) {
return json_encode($json, JSON_UNESCAPED_UNICODE);
}
$matchQuote = '/(<\?xml.*?\?>)?<([a-zA-Z_]+)>(<([a-zA-Z_]+)><!.*?><\/\4>)+<\/\2>/';
if (preg_match($matchQuote, $json)) {
$json = self::xmlToArray($json);
} else {
$json = json_decode($json, true);
}
if (!is_array($json)) {
$json = [];
}
return json_encode($json, JSON_UNESCAPED_UNICODE);
}
/**
* @param int $length
* @return string
*
* 随机字符串
*/
public static function random($length = 20): string
{
$res = [];
$str = 'abcdefghijklmnopqrstuvwxyz';
$str .= strtoupper($str) . '1234567890';
for ($i = 0; $i < $length; $i++) {
$rand = substr($str, rand(0, strlen($str) - 2), 1);
if (empty($rand)) {
$rand = substr($str, strlen($str) - 3, 1);
}
array_push($res, $rand);
}
/**
* @param int $length
* @return string
*
* 随机字符串
*/
public static function random(int $length = 20): string
{
$res = [];
$str = 'abcdefghijklmnopqrstuvwxyz';
$str .= strtoupper($str) . '1234567890';
for ($i = 0; $i < $length; $i++) {
$rand = substr($str, rand(0, strlen($str) - 2), 1);
if (empty($rand)) {
$rand = substr($str, strlen($str) - 3, 1);
}
$res[] = $rand;
}
return implode($res);
}
return implode($res);
}
/**
* @param array $array
* @param $key
* @param string $type
* @return string
*/
public static function sign(array $array, $key, string $type = 'MD5'): string
{
ksort($array, SORT_ASC);
$string = [];
foreach ($array as $hashKey => $val) {
if (empty($val)) {
continue;
}
$string[] = $hashKey . '=' . $val;
}
$string[] = 'key=' . $key;
$string = implode('&', $string);
if ($type == 'MD5') {
return strtoupper(md5($string));
} else {
return hash('sha256', $string);
}
}
/**
* @param array $array
* @param $key
* @param string $type
* @return string
*/
public static function sign(array $array, $key, string $type = 'MD5'): string
{
ksort($array, SORT_ASC);
$string = [];
foreach ($array as $hashKey => $val) {
if (empty($val)) {
continue;
}
$string[] = $hashKey . '=' . $val;
}
$string[] = 'key=' . $key;
$string = implode('&', $string);
if ($type == 'MD5') {
return strtoupper(md5($string));
} else {
return hash('sha256', $string);
}
}
/**
* @param $email
* @param string $Subject
* @param $messageContent
*/
public static function sendEmail($email, string $Subject, $messageContent)
{
if (!class_exists('\Swift_Mailer')) {
return;
}
$mailer = new \Swift_Mailer((new \Swift_SmtpTransport($email['host'], $email['port']))
->setUsername($email['username'])->setPassword($email['password']));
$message = (new \Swift_Message($Subject))
->setFrom([$email['send']['address'] => $email['send']['nickname']])
->setBody('Here is the message itself');
/**
* @param $email
* @param string $Subject
* @param $messageContent
*/
public static function sendEmail($email, string $Subject, $messageContent): void
{
if (!class_exists('\Swift_Mailer')) {
return;
}
$mailer = new \Swift_Mailer((new Swift_SmtpTransport($email['host'], $email['port']))
->setUsername($email['username'])->setPassword($email['password']));
$message = (new Swift_Message($Subject))
->setFrom([$email['send']['address'] => $email['send']['nickname']])
->setBody('Here is the message itself');
foreach ($email['receive'] as $item) {
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
}
$mailer->send($messageContent);
}
foreach ($email['receive'] as $item) {
$message->setTo([$item['address'], $item['address'] => $item['nickname']]);
}
$mailer->send($messageContent);
}
/**
* @param int $year
* @return int
*/
public static function age(int $year): int
{
return date('Y') - $year;
}
/**
* @param int $year
* @return string
*/
public static function zodiac(int $year): string
{
$zodiac = "-1";
$start = 1901;
$x = ($start - $year) % 12;
if ($x == 1 || $x == -11) {
$zodiac = "";
}
if ($x == 0) {
$zodiac = "";
}
if ($x == 11 || $x == -1) {
$zodiac = "";
}
if ($x == 10 || $x == -2) {
$zodiac = "";
}
if ($x == 9 || $x == -3) {
$zodiac = "";
}
if ($x == 8 || $x == -4) {
$zodiac = "";
}
if ($x == 7 || $x == -5) {
$zodiac = "";
}
if ($x == 6 || $x == -6) {
$zodiac = "";
}
if ($x == 5 || $x == -7) {
$zodiac = "";
}
if ($x == 4 || $x == -8) {
$zodiac = "";
}
if ($x == 3 || $x == -9) {
$zodiac = "";
}
if ($x == 2 || $x == -10) {
$zodiac = "";
}
return $zodiac;
}
/**
* @param int $month
* @param int $day
* @return string
*/
public static function constellation(int $month, int $day): string
{
$star = "-1";
if (($month == 1 && $day >= 20) || ($month == 2 && $day <= 18)) {
$star = "水瓶座";
}
if (($month == 2 && $day >= 19) || ($month == 3 && $day <= 20)) {
$star = "双鱼座";
}
if (($month == 3 && $day >= 21) || ($month == 4 && $day <= 19)) {
$star = "白羊座";
}
if (($month == 4 && $day >= 20) || ($month == 5 && $day <= 20)) {
$star = "金牛座";
}
if (($month == 5 && $day >= 21) || ($month == 6 && $day <= 21)) {
$star = "双子座";
}
if (($month == 6 && $day >= 22) || ($month == 7 && $day <= 22)) {
$star = "巨蟹座";
}
if (($month == 7 && $day >= 23) || ($month == 8 && $day <= 22)) {
$star = "狮子座";
}
if (($month == 8 && $day >= 23) || ($month == 9 && $day <= 22)) {
$star = "处女座";
}
if (($month == 9 && $day >= 23) || ($month == 10 && $day <= 22)) {
$star = "天秤座";
}
if (($month == 10 && $day >= 23) || ($month == 11 && $day <= 21)) {
$star = "天蝎座";
}
if (($month == 11 && $day >= 22) || ($month == 12 && $day <= 21)) {
$star = "射手座";
}
if (($month == 12 && $day >= 22) || ($month == 1 && $day <= 19)) {
$star = "魔蝎座";
}
return $star;
}
}
+110 -87
View File
@@ -22,100 +22,123 @@ class Json
{
/**
* @param $data
* @return false|string
*/
public static function encode($data): bool|string
{
if (empty($data)) {
return false;
}
if (is_array($data)) {
return json_encode($data, JSON_UNESCAPED_UNICODE);
}
return $data;
}
/**
* @param $data
* @return false|string
*/
public static function encode($data): bool|string
{
if (empty($data)) {
return false;
}
if (is_array($data)) {
return json_encode($data, JSON_UNESCAPED_UNICODE);
}
return $data;
}
/**
* @param $data
* @param bool $asArray
* @return mixed
*/
public static function decode($data, bool $asArray = true): mixed
{
if (is_array($data) || is_numeric($data)) {
return $data;
}
if (!is_string($data)) return null;
return json_decode($data, $asArray);
}
/**
* @param $data
* @param bool $asArray
* @return mixed
*/
public static function decode($data, bool $asArray = true): mixed
{
if (is_array($data) || is_numeric($data)) {
return $data;
}
if (!is_string($data)) return null;
return json_decode($data, $asArray);
}
/**
* @param $code
* @param string|array $message
* @param array|int $data
* @param int $count
* @param array $exPageInfo
* @return string|bool
*/
public static function to($code, string|array $message = '', array|int $data = [], int $count = 0, array $exPageInfo = []): string|bool
{
$params['code'] = $code;
if (!is_string($message)) {
$params['message'] = 'System success.';
$params['param'] = $message;
if (!empty($data)) {
$params['exPageInfo'] = $data;
}
} else {
$params['message'] = $message;
$params['param'] = $data;
}
if (!empty($exPageInfo)) {
$params['exPageInfo'] = $exPageInfo;
}
$params['count'] = $count;
if (is_numeric($data) || !is_numeric($count)) {
$params['count'] = $data;
$params['exPageInfo'] = $count;
}
if ((int)$params['count'] == -100) {
$params['count'] = 1;
}
return static::encode($params);
}
/**
* @param string $message
* @param int $code
* @param array|string $data
* @param int $count
* @return string
*/
public static function jsonFail(string $message, int $code = 500, array|string $data = [], int $count = 0): string
{
return json_encode(['code' => $code, 'param' => $data, 'message' => $message, 'count' => $count], JSON_UNESCAPED_UNICODE);
}
/**
* @param Throwable|Error $throwable
* @return bool|string
*/
public static function error(Throwable|Error $throwable): bool|string
{
$array['code'] = $throwable->getCode() == 0 ? 500 : $throwable->getCode();
$array['message'] = $throwable->getMessage();
$array['param'] = [
'file' => $throwable->getFile(),
'line' => $throwable->getLine()
];
return Json::encode($array);
}
/**
* @param string $message
* @param array|string $data
* @param int $count
* @return string
*/
public static function jsonSuccess(array|string $data = [], string $message = "ok", int $count = 0): string
{
return json_encode(['code' => 0, 'param' => $data, 'message' => $message, 'count' => $count], JSON_UNESCAPED_UNICODE);
}
/**
* @param $state
* @param $body
* @return false|int|string
* @throws Exception
*/
public static function output($state, $body): bool|int|string
{
$params['state'] = $state;
$params['body'] = ArrayAccess::toArray($body);
/**
* @param $code
* @param string|array $message
* @param array|int $data
* @param int $count
* @param array $exPageInfo
* @return string|bool
*/
public static function to($code, string|array $message = '', array|int $data = [], int $count = 0, array $exPageInfo = []): string|bool
{
$params['code'] = $code;
if (!is_string($message)) {
$params['message'] = 'System success.';
$params['param'] = $message;
$params['exPageInfo'] = $data;
} else {
$params['message'] = $message;
$params['param'] = $data;
}
if (!empty($exPageInfo)) {
$params['exPageInfo'] = $exPageInfo;
}
$params['count'] = $count;
if (is_numeric($data) || !is_numeric($count)) {
$params['count'] = $data;
$params['exPageInfo'] = $count;
}
if ((int)$params['count'] == -100) {
$params['count'] = 1;
}
return static::encode($params);
}
return static::encode($params);
}
/**
* @param Throwable|Error $throwable
* @return bool|string
*/
public static function error(Throwable|Error $throwable): bool|string
{
$array['code'] = $throwable->getCode() == 0 ? 500 : $throwable->getCode();
$array['message'] = $throwable->getMessage();
$array['param'] = [
'file' => $throwable->getFile(),
'line' => $throwable->getLine()
];
return Json::encode($array);
}
/**
* @param $state
* @param $body
* @return false|int|string
* @throws
*/
public static function output($state, $body): bool|int|string
{
$params['state'] = $state;
$params['body'] = ArrayAccess::toArray($body);
return static::encode($params);
}
}
+14 -19
View File
@@ -14,9 +14,9 @@ use Exception;
class Str
{
const STRING = 'abcdefghijklmnopqrstuvwxyz';
const string STRING = 'abcdefghijklmnopqrstuvwxyz';
const NUMBER = '01234567890';
const string NUMBER = '01234567890';
/**
* @param int $length
@@ -45,7 +45,7 @@ class Str
*/
public static function random(int $length = 20): int|string
{
$number = '';
$number = '';
$default = str_split(self::NUMBER);
if ($length < 1) $length = 1;
for ($i = 0; $i < $length; $i++) {
@@ -107,7 +107,7 @@ class Str
*/
public static function isSerialize($data, $callBack = NULL): bool
{
$false = !empty($data) && swoole_unserialize($data) !== FALSE;
$false = !empty($data) && unserialize($data) !== FALSE;
if ($false && is_callable($callBack, TRUE)) {
return call_user_func($callBack, $data);
}
@@ -151,13 +151,13 @@ class Str
{
$res = [];
$add = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$len = strlen($key) < 0 ? 1 : (strlen($key) + 5 > strlen($add) ? strlen($add) - 5 : strlen($key));
$len = strlen($key) + 5 > strlen($add) ? strlen($add) - 5 : strlen($key);
if ($number < 1) $number = 10;
$array = str_split($str);
asort($array);
$str = implode('', $array);
for ($i = 0; $i < $number; $i++) {
$_tmp = md5($key) . md5($str) . mb_substr($add, $len, $len + 5, 'utf-8');
$_tmp = md5($key) . md5($str) . mb_substr($add, $len, $len + 5, 'utf-8');
$res[] = md5($_tmp);
}
sort($res, SORT_STRING);
@@ -171,17 +171,12 @@ class Str
*/
public static function filename($file, $type): string
{
switch ($type) {
case 'image/png':
return md5_file($file) . '.png';
case 'image/jpeg':
case 'image/jpg':
return md5_file($file) . '.jpg';
case 'image/gif':
return md5_file($file) . '.gif';
break;
}
return md5_file($file);
return match ($type) {
'image/png' => md5_file($file) . '.png',
'image/jpeg', 'image/jpg' => md5_file($file) . '.jpg',
'image/gif' => md5_file($file) . '.gif',
default => md5_file($file),
};
}
/**
@@ -232,8 +227,8 @@ class Str
*/
public static function clear(string $string): array|string|null
{
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
return preg_replace(["/[[:punct:]]/i", '/[' . $char . ']/u', '/[ ]{2,}/'], '', $string);
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔¡¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
return preg_replace(["/[[:punct:]]/i", '/[' . $char . ']/u', '/ {2,}/'], '', $string);
}
+34 -34
View File
@@ -18,40 +18,40 @@ use Exception;
class Xml
{
/**
* @param $data
* @param bool $asArray
* @return array|object
* @throws Exception
*/
public static function toArray($data, bool $asArray = true): object|array
{
$data = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($data === false) {
throw new Exception('Parameter format error.');
}
$array = get_object_vars($data);
if (isset($array[0])) {
$array[$data->getName()] = $array[0];
unset($array[0]);
}
return $array;
}
/**
* @param $data
* @param bool $asArray
* @return array|object
* @throws
*/
public static function toArray($data, bool $asArray = true): object|array
{
$data = \simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($data === false) {
throw new Exception('Parameter format error.');
}
$array = \get_object_vars($data);
if (isset($array[0])) {
$array[$data->getName()] = $array[0];
unset($array[0]);
}
return $array;
}
/**
* @param $str
* @return array|bool|object
* @throws Exception
*/
public static function isXml($str): object|bool|array
{
$xml_parser = xml_parser_create();
if (!xml_parse($xml_parser, $str, true)) {
xml_parser_free($xml_parser);
return false;
} else {
return self::toArray($str);
}
}
/**
* @param $str
* @return array|bool|object
* @throws
*/
public static function isXml($str): object|bool|array
{
$xml_parser = \xml_parser_create();
if (!\xml_parse($xml_parser, $str, true)) {
\xml_parser_free($xml_parser);
return false;
} else {
return self::toArray($str);
}
}
}
+3 -1
View File
@@ -1,11 +1,13 @@
<?php
declare(strict_types=1);
namespace Kiri;
use JetBrains\PhpStorm\Pure;
use Kiri;
/**
* Class Environmental
+93 -115
View File
@@ -9,143 +9,121 @@ declare(strict_types=1);
namespace Kiri\Error;
use Closure;
use ErrorException;
use Exception;
use Kiri\Message\Handler\Formatter\IFormatter;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri\Events\EventDispatch;
use Kiri;
use Kiri\Message\Events\OnAfterRequest;
use Psr\Container\ContainerInterface;
use Kiri\Di\Inject\Container;
use ReflectionException;
use Kiri\Events\OnSystemError;
use Throwable;
/**
* Class ErrorHandler
*
* hahahah
* @package Kiri\Base
* @property-read $asError
*/
class ErrorHandler extends Component implements ErrorInterface
{
/** @var ?IFormatter $message */
private ?IFormatter $message = NULL;
public string $category = 'app';
/**
* 错误处理注册
*/
public function register()
{
set_exception_handler([$this, 'exceptionHandler']);
set_error_handler([$this, 'errorHandler']);
register_shutdown_function([$this, 'shutdown']);
}
/**
* @throws Exception
*/
public function shutdown()
{
$lastError = error_get_last();
if (empty($lastError) || $lastError['type'] !== E_ERROR) {
return;
}
$this->category = 'shutdown';
$messages = explode(PHP_EOL, $lastError['message']);
$message = array_shift($messages);
$this->sendError($message, $lastError['file'], $lastError['line']);
}
/**
* @var string
*/
public string $category = 'app';
/**
* @param \Throwable $exception
*
* @throws Exception
*/
public function exceptionHandler(\Throwable $exception)
{
$this->category = 'exception';
di(EventDispatch::class)->dispatch(new OnAfterRequest());
$this->sendError($exception->getMessage(), $exception->getFile(), $exception->getLine());
}
/**
* @param array|Closure|null $callback
* @return void
* @throws
*/
public function registerExceptionHandler(null|array|Closure $callback): void
{
if (empty($callback)) {
$callback = [$this, 'exceptionHandler'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
set_exception_handler($callback);
}
/**
* @throws Exception
*
* 以异常形式抛出错误,防止执行后续程序
*/
public function errorHandler()
{
$error = func_get_args();
$path = ['file' => $error[2], 'line' => $error[3]];
if ($error[0] === 0) {
$error[0] = 500;
}
$data = Json::to(500, $error[1], $path);
Kiri::app()->error($data, 'error');
di(EventDispatch::class)->dispatch(new OnAfterRequest());
/**
* @param array|Closure|null $callback
* @return void
* @throws
*/
public function registerErrorHandler(null|array|Closure $callback): void
{
if (empty($callback)) {
$callback = [$this, 'errorHandler'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
set_error_handler($callback);
}
throw new \ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
}
/**
* @param array|Closure|null $callback
* @return void
* @throws
*/
public function registerShutdownHandler(null|array|Closure $callback): void
{
if (empty($callback)) {
$callback = [$this, 'shutdown'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
register_shutdown_function($callback);
}
/**
* @param $message
* @param $file
* @param $line
* @param int $code
* @return false|string
* @throws Exception
*/
public function sendError($message, $file, $line, $code = 500): bool|string
{
$path = ['file' => $file, 'line' => $line];
$data = Json::to($code, $this->category . ': ' . $message, $path);
/**
* @return void
* @throws
* @throws
*/
public function shutdown(): void
{
$lastError = error_get_last();
if (empty($lastError) || $lastError['type'] !== E_ERROR) {
return;
}
write($data, $this->category);
$this->getLogger()->failure($lastError['message'] . PHP_EOL);
return $data;
}
event(new OnSystemError());
}
/**
* @return mixed
*/
public function getErrorMessage(): mixed
{
$message = $this->message;
$this->message = NULL;
return $message->getData();
}
/**
* @return bool
*/
public function getAsError(): bool
{
return $this->message !== NULL;
}
/**
* @param Throwable $exception
*
* @throws
*/
public function exceptionHandler(Throwable $exception): void
{
$this->category = 'exception';
/**
* @param $message
* @param string $category
*
* @throws Exception
*/
public function writer($message, string $category = 'app')
{
Kiri::app()->debug($message, $category);
}
$this->getLogger()->failure($exception);
event(new OnSystemError());
}
/**
* @throws
*/
public function errorHandler()
{
$error = func_get_args();
event(new OnSystemError());
throw new ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
}
}
-9
View File
@@ -16,13 +16,4 @@ namespace Kiri\Error;
interface ErrorInterface
{
/**
* @param $message
* @param $file
* @param $line
* @param int $code
* @return mixed
*/
public function sendError($message, $file, $line, $code = 500): mixed;
}
-117
View File
@@ -1,117 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-22
* Time: 14:36
*/
declare(strict_types=1);
namespace Kiri\Error;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri;
use Kiri\Annotation\Inject;
use Psr\Log\LoggerInterface;
use Throwable;
/**
* Class Logger
* @package Kiri\Error
* @mixin \Kiri\Abstracts\Logger
*/
class Logger extends Component
{
private array $logs = [];
/**
* inject logger
*
* @var LoggerInterface
*/
#[Inject(LoggerInterface::class)]
public LoggerInterface $logger;
private array $sources = [];
/**
* @param string $application
* @return string
*/
public function getLastError(string $application = 'app'): string
{
return $this->logs[$application] ?? 'Unknown error.';
}
/**
* @param $message
* @param $method
* @return void
*/
public function fail($message, $method)
{
$this->logs[$method] = $message;
}
/**
* @param string $messages
* @param string $method
* @throws Exception
*/
public function write(string $messages, string $method = 'app')
{
if (empty($messages)) {
return;
}
$to_day = date('Y-m-d');
$fileName = storage('server-' . $to_day . '.log', $dirName = 'log/' . ($method ?? 'app'));
file_put_contents($fileName, '[' . date('Y-m-d H:i:s') . ']:' . PHP_EOL . $messages . PHP_EOL);
}
/**
* @param Throwable $exception
* @return mixed
* @throws Exception
*/
public function exception(Throwable $exception): mixed
{
$code = $exception->getCode() == 0 ? 500 : $exception->getCode();
$logger = Kiri::app()->getLogger();
$logger->write(jTraceEx($exception), 'exception');
return Json::to($code, $exception->getMessage(), [
'file' => $exception->getFile(),
'line' => $exception->getLine()
]);
}
/**
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call(string $name, array $arguments): mixed
{
if (!method_exists($this, $name)) {
return $this->logger->{$name}(...$arguments);
} else {
return $this->{$name}(...$arguments);
}
}
}
-53
View File
@@ -1,53 +0,0 @@
<?php
namespace Kiri\Error;
use Exception;
use Kiri\Message\Aspect\OnAspectInterface;
use Kiri\Message\Aspect\OnJoinPointInterface;
use Kiri\Message\Constrict\RequestInterface;
use Kiri;
use Psr\Log\LoggerInterface;
/**
* Class LoggerAspect
* @package Kiri\Error
*/
class LoggerAspect implements OnAspectInterface
{
/**
* @param OnJoinPointInterface $joinPoint
* @return mixed
* @throws Exception
*/
public function process(OnJoinPointInterface $joinPoint): mixed
{
$time = microtime(true);
$response = $joinPoint->process();
$this->print_runtime($time);
return $response;
}
/**
* @param $startTime
* @throws Exception
*/
private function print_runtime($startTime)
{
$request = Kiri::getDi()->get(RequestInterface::class);
$runTime = round(microtime(true) - $startTime, 6);
$logger = Kiri::getDi()->get(LoggerInterface::class);
$logger->debug(sprintf('run %s use time %6f', $request->getUri()->__toString(), $runTime));
}
}
-97
View File
@@ -1,97 +0,0 @@
<?php
namespace Kiri\Error;
use Exception;
use Kiri\Core\Json;
use Kiri\Exception\ComponentException;
use Kiri;
use Kiri\Server\Abstracts\BaseProcess;
use Kiri\Server\Broadcast\OnBroadcastInterface;
use Psr\Log\LoggerInterface;
use Swoole\Coroutine;
use Swoole\Process;
/**
* Class LoggerProcess
* @package Kiri\Error
*/
class LoggerProcess extends BaseProcess
{
public string $name = 'logger process';
/**
* @param Process $process
* @throws ComponentException
*/
public function process(Process $process): void
{
// TODO: Implement onHandler() method.
$this->message($process);
}
/**
* @param OnBroadcastInterface $message
* @return void
*/
public function onBroadcast(OnBroadcastInterface $message): void
{
$logger = Kiri::getDi()->get(LoggerInterface::class);
$logger->debug($message->data . '::' . static::class);
}
/**
* @param Process $process
* @throws ComponentException
* @throws Exception
*/
public function message(Process $process)
{
if ($this->isStop()) {
return;
}
$message = Json::decode($process->read());
if (!empty($message)) {
Kiri::writeFile($this->getDirName($message), $message[0], FILE_APPEND);
$this->checkLogFile($message[1]);
}
Coroutine\System::sleep(1);
$this->message($process);
}
/**
* @param $message
* @return string
* @throws Exception
*/
private function getDirName($message): string
{
return storage('server-' . date('Y-m-d') . '.log', $message[1]);
}
/**
* @param $dirName
* @throws Exception
*/
private function checkLogFile($dirName)
{
$files = new \DirectoryIterator(storage(null, $dirName));
if ($files->getSize() < 15) {
return;
}
Coroutine\System::exec('find ' . storage(null, $dirName) . '/ -mtime +15 -name "*.log" -exec rm -rf {} \;');
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
declare(strict_types=1);
namespace Kiri\Error;
use Kiri\Abstracts\Component;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;
use ReflectionException;
/**
* @see LoggerInterface
* @method error(string $message, array $context = array())
* @method log($level, $message, array $context = array())
* @method debug($message, array $context = array())
* @method info($message, array $context = array())
* @method notice($message, array $context = array())
* @method warning($message, array $context = array())
* @method critical($message, array $context = array())
* @method alert($message, array $context = array())
* @method emergency($message, array $context = array())
*/
class StdoutLogger extends Component
{
/**
* @var array
*/
private array $errors = [];
/**
* @var Logger
*/
protected Logger $logger;
protected array $levels;
/**
* StdoutLogger construct
*/
public function __construct()
{
parent::__construct();
$this->logger = new Logger(\config('id'));
$this->levels = [
'debug' => $this->logger::DEBUG,
'info' => $this->logger::INFO,
'notice' => $this->logger::NOTICE,
'warning' => $this->logger::WARNING,
'error' => $this->logger::ERROR,
'critical' => $this->logger::CRITICAL,
'alert' => $this->logger::ALERT,
'emergency' => $this->logger::EMERGENCY,
];
}
/**
* @param $message
* @param string $model
* @return bool
*/
public function failure($message, string $model = 'app'): bool
{
if ($message instanceof \Exception) {
$this->errors[$model] = $message->getMessage();
} else {
$this->errors[$model] = $message;
}
return $this->dump($message);
}
/**
* @param $message
* @return bool
*/
protected function dump($message): bool
{
$message = throwable($message);
if (str_contains($message, 'inotify_rm_watch')) {
return false;
}
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message, FILE_APPEND);
$this->error($message, []);
return false;
}
/**
* @param string $message
* @return void
*/
public function println(string $message): void
{
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message . PHP_EOL, FILE_APPEND);
}
/**
* @param string $name
* @param array $arguments
* @return void
* @throws
*/
public function __call(string $name, array $arguments)
{
try {
if (method_exists($this->logger, $name)) {
$this->createHandler($name)->$name(...$arguments);
} else if (method_exists($this, $name)) {
$this->{$name}(...$arguments);
}
} catch (\Throwable $exception) {
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $exception->getMessage(), FILE_APPEND);
}
}
/**
* @param string $name
* @return Logger
*/
protected function createHandler(string $name): Logger
{
if (!$this->logger->isHandling($this->levels[$name])) {
$handler = new RotatingFileHandler(APP_PATH . 'storage/logs/' . $name . '/kiri.log', $this->levels[$name]);
$handler->setFormatter(new LineFormatter("[%datetime%] %channel%.%level_name%: %message% %context%\n", 'Y-m-d H:i:s'));
$this->logger->pushHandler($handler);
}
return $this->logger;
}
/**
* @param string $model
* @return mixed
*/
public function getLastError(string $model = 'app'): mixed
{
return $this->errors[$model] ?? 'Unknown error.';
}
}
-238
View File
@@ -1,238 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri;
use Exception;
use Kiri\Abstracts\Component;
use Kiri;
/**
* Class Event
* @package Kiri
*/
class Event extends Component
{
public bool $isVide = true;
private static array $_events = [];
const PIPE_MESSAGE = 'SERVER:PIPE:MESSAGE';
const TASK_FINISH = 'SERVER:TASK::FINISH';
const EVENT_AFTER_REQUEST = 'SERVER:REQUEST:AFTER:START';
const EVENT_BEFORE_REQUEST = 'SERVER:REQUEST:BEFORE:START';
const RECEIVE_CONNECTION = 'SERVER:RECEIVE:CONNECTION';
const SYSTEM_RESOURCE_RELEASES = 'SYSTEM::RESOURCE::RELEASES';
const SYSTEM_RESOURCE_CLEAN = 'SYSTEM::RESOURCE::CLEAN';
const PROCESS_WORKER_STOP = 'SERVER:PROCESS:WORKER:STOP';
const SERVER_AFTER_RELOAD = 'SERVER:AFTER:RELOAD';
const SERVER_BEFORE_RELOAD = 'SERVER:BEFORE:RELOAD';
const SERVER_CONNECT = 'SERVER:CONNECT';
const SERVER_PACKAGE = 'SERVER:PACKAGE';
const SERVER_RECEIVE = 'SERVER:RECEIVE';
const SERVER_EVENT_START = 'SERVER:EVENT:START';
const SERVER_MANAGER_START = 'SERVER:EVENT:MANAGER:START';
const SERVER_MANAGER_STOP = 'SERVER:EVENT:MANAGER:START';
const SERVER_WORKER_STOP = 'SERVER:EVENT:WORKER:STOP';
const SERVER_WORKER_START = 'SERVER:EVENT:WORKER:START';
const SERVER_AFTER_WORKER_START = 'SERVER:EVENT:AFTER:WORKER:START';
const SERVER_BEFORE_START = 'SERVER:EVENT:BEFORE:START';
const BEFORE_COMMAND_EXECUTE = 'COMMAND:EVENT:BEFORE:EXECUTE';
const AFTER_COMMAND_EXECUTE = 'COMMAND:EVENT:AFTER:EXECUTE';
const SERVER_TASK_START = 'SERVER:EVENT:TASK:START';
const SERVER_WORKER_EXIT = 'SERVER:EVENT:WORKER:EXIT';
const SERVER_WORKER_ERROR = 'SERVER:EVENT:WORKER:ERROR';
const SERVER_SHUTDOWN = 'SERVER:EVENT:SHUTDOWN';
const SERVER_HANDSHAKE = 'on handshake';
const SERVER_MESSAGE = 'on message';
const SERVER_CLIENT_CLOSE = 'SERVER:CLIENT:CLOSE';
const SERVER_ON_START = 'Start';
const SERVER_ON_SHUTDOWN = 'Shutdown';
const SERVER_ON_WORKER_START = 'WorkerStart';
const SERVER_ON_WORKER_STOP = 'WorkerStop';
const SERVER_ON_WORKER_EXIT = 'WorkerExit';
const SERVER_ON_CONNECT = 'Connect';
const SERVER_ON_RECEIVE = 'Receive';
const SERVER_ON_PACKET = 'Packet';
const SERVER_ON_REQUEST = 'request';
const SERVER_ON_CLOSE = 'Close';
const SERVER_ON_TASK = 'Task';
const SERVER_ON_FINISH = 'Finish';
const SERVER_ON_PIPE_MESSAGE = 'OnPipeMessageInterface';
const SERVER_ON_WORKER_ERROR = 'WorkerError';
const SERVER_ON_MANAGER_START = 'ManagerStart';
const SERVER_ON_MANAGER_STOP = 'ManagerStop';
const SERVER_ON_BEFORE_RELOAD = 'BeforeReload';
const SERVER_ON_AFTER_RELOAD = 'AfterReload';
/**
* @param $name
* @param $callback
* @param bool $isAppend
* @throws Exception
*/
public static function on($name, $callback, bool $isAppend = false)
{
if (!isset(static::$_events[$name])) {
static::$_events[$name] = [];
}
if (is_array($callback) && is_string($callback[0])) {
if (!class_exists($callback[0])) {
throw new Exception('Undefined callback class.');
}
$callback[0] = di($callback[0]);
}
if (static::exists($name, $callback)) {
return;
}
if (!empty(static::$_events[$name]) && $isAppend === true) {
array_unshift(static::$_events[$name], [$callback]);
} else {
static::$_events[$name][] = [$callback];
}
}
/**
* @param $name
* @param $callback
*/
public static function of($name, $callback): void
{
if (!isset(static::$_events[$name])) {
return;
}
foreach (static::$_events[$name] as $index => $event) {
[$handler] = $event;
if ($handler !== $callback) {
continue;
}
unset(static::$_events[$name][$index]);
}
}
/**
* @param $name
*/
public static function offName($name): void
{
unset(static::$_events[$name]);
}
/**
* @param $name
* @param null $callback
* @return bool
*/
public static function exists($name, $callback): bool
{
if ($callback instanceof \Closure || !isset(static::$_events[$name])) {
return false;
}
foreach (static::$_events[$name] as $event) {
[$handler] = $event;
if ($handler === $callback) {
return true;
}
}
return false;
}
/**
* @param $name
* @param $handler
* @return mixed
*/
public static function get($name, $handler): mixed
{
if (!static::exists($name, $handler)) {
return null;
}
if (empty($handler)) {
return static::$_events[$name];
}
foreach (static::$_events[$name] as $event) {
[$callback] = $event;
if ($callback === $handler) {
return [$event];
}
}
return null;
}
public static function clean()
{
static::$_events = [];
}
/**
* @param $name
* @param array $params
* @return bool
* @throws Exception
*/
public function dispatch($name, array $params = []): bool
{
return static::trigger($name, $params);
}
/**
* @param $name
* @param null $parameter
* @param false $is_remove
* @return bool
* @throws Exception
*/
public static function trigger($name, $parameter = null, bool $is_remove = false): bool
{
foreach ((static::$_events[$name] ?? []) as $key => $event) {
static::execute($event, $parameter);
if ($event instanceof \Closure) {
unset(static::$_events[$name][$key]);
}
}
if ($is_remove) {
unset(static::$_events[$name]);
}
return true;
}
/**
* @param $event
* @param $parameter
* @return void
* @throws Exception
*/
private static function execute($event, $parameter): void
{
try {
call_user_func($event[0], ...$parameter);
} catch (\Throwable $throwable) {
logger()->addError($throwable, 'throwable');
return;
}
}
}
+6 -4
View File
@@ -2,14 +2,16 @@
namespace Kiri\Events;
use Symfony\Component\Console\Command\Command;
class OnAfterCommandExecute
{
/**
*
*/
public function __construct()
/**
* @param Command $command
*/
public function __construct(public Command $command)
{
}
@@ -2,7 +2,17 @@
namespace Kiri\Events;
use Symfony\Component\Console\Command\Command;
class OnBeforeCommandExecute
{
/**
* @param Command $command
*/
public function __construct(public Command $command)
{
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Kiri\Events;
class OnSystemError
{
}
+1 -1
View File
@@ -21,7 +21,7 @@ class AuthException extends \Exception
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($message = "", $code = 0, Throwable $previous = null)
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
parent::__construct($message, 4001, $previous);
}
-224
View File
@@ -1,224 +0,0 @@
<?php
namespace Kiri\FileListen;
use Exception;
use Kiri;
use Kiri\Abstracts\Config;
use Kiri\Annotation\Inject;
use Kiri\Core\Json;
use Kiri\Error\Logger;
use Kiri\Exception\ConfigException;
use Swoole\Coroutine;
use Swoole\Process;
use Swoole\Timer;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
*
*/
class HotReload extends Command
{
public bool $isReloading = FALSE;
public bool $isReloadingOut = FALSE;
public ?array $dirs = [];
public int $events;
public int $int = -1;
private ?Process $process = NULL;
public Inotify|Scaner $driver;
#[Inject(Logger::class)]
public Logger $logger;
protected mixed $source = NULL;
protected mixed $pipes = [];
protected ?Coroutine\Channel $channel = NULL;
/**
*/
protected function configure()
{
$this->setName('sw:wather')->setDescription('server start');
}
/**
* @throws ConfigException
* @throws Exception
*/
protected function initCore()
{
set_error_handler([$this, 'errorHandler']);
$this->dirs = Config::get('inotify', [APP_PATH . 'app']);
if (!extension_loaded('inotify')) {
$this->driver = Kiri::getDi()->make(Scaner::class, [$this->dirs, $this]);
} else {
$this->driver = Kiri::getDi()->make(Inotify::class, [$this->dirs, $this]);
}
$this->clearOtherService();
$this->setProcessName();
}
/**
* @throws ConfigException
*/
public function setProcessName()
{
swoole_async_set(['enable_coroutine' => FALSE]);
if (Kiri::getPlatform()->isLinux()) {
swoole_set_process_name('[' . Config::get('id', 'sw service.') . '].sw:wather');
}
}
/**
* @throws Exception
*/
public function clearOtherService()
{
if (file_exists(storage('.manager.pid'))) {
$pid = (int)file_get_contents(storage('.manager.pid'));
if ($pid > 0 && Process::kill($pid, 0)) {
Process::kill($pid, 15) && Process::wait(TRUE);
}
}
file_put_contents(storage('.manager.pid'), getmypid());
}
/**
* @throws Exception
*/
public function errorHandler()
{
$error = func_get_args();
$path = ['file' => $error[2], 'line' => $error[3]];
if ($error[0] === 0) {
$error[0] = 500;
}
$data = Json::to(500, $error[1], $path);
$this->logger->error($data, 'error');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws ConfigException
* @throws Exception
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
$this->initCore();
$this->trigger_reload();
Timer::tick(1000, fn() => $this->healthCheck());
Process::signal(SIGTERM, [$this, 'onSignal']);
Process::signal(SIGKILL, [$this, 'onSignal']);
$this->driver->start();
return 0;
}
/**
* @throws Exception
*/
public function healthCheck()
{
$pid = (int)file_get_contents(storage('.swoole.pid'));
if ($this->int == 1) {
return;
}
if (empty($pid)) {
$this->logger->warning('service is shutdown you need reload.');
$this->trigger_reload();
} else if (!Process::kill($pid, 0)) {
$this->logger->warning('service is shutdown you need reload.');
$this->trigger_reload();
}
}
/**
* @param $data
* @throws Exception
*/
public function onSignal($data)
{
if (!$data) {
return;
}
Timer::clearAll();
$this->driver->clear();
$this->stopServer();
while ($ret = Process::wait(TRUE)) {
echo "PID={$ret['pid']}\n";
sleep(1);
}
}
/**
* @throws Exception
*/
protected function stopServer()
{
$pid = file_get_contents(storage('.swoole.pid'));
if (!empty($pid) && Process::kill($pid, 0)) {
Process::kill($pid, SIGTERM);
}
if ($this->process && Process::kill($this->process->pid, 0)) {
Process::kill($this->process->pid) && Process::wait(TRUE);
}
}
/**
* 重启
*
* @throws Exception
*/
public function trigger_reload(string $path = '')
{
$this->logger->warning('change reload');
if (!empty($path) && str_starts_with($path, CONTROLLER_PATH)) {
$pid = file_get_contents(storage('.swoole.pid'));
if (!empty($pid) && Process::kill($pid, 0)) {
Process::kill($pid, SIGUSR1);
}
} else {
$this->int = 1;
$this->stopServer();
$this->process = new Process(function (Process $process) {
$process->exec(PHP_BINARY, [APP_PATH . "kiri.php", "sw:server", "start"]);
});
$this->process->start();
$this->int = -1;
}
}
}
-171
View File
@@ -1,171 +0,0 @@
<?php
namespace Kiri\FileListen;
use Exception;
use Swoole\Event;
use Swoole\Timer;
class Inotify
{
private mixed $inotify;
private mixed $events;
private array $watchFiles = [];
public bool $isReloading = FALSE;
protected int $cid;
const IG_DIR = [APP_PATH . 'commands', APP_PATH . '.git', APP_PATH . '.gitee'];
/**
* @param array $dirs
* @param HotReload $process
*/
public function __construct(protected array $dirs, public HotReload $process)
{
set_error_handler([$this, 'error']);
set_exception_handler([$this, 'error']);
}
/**
* @return void
*/
public function error(): void
{
}
/**
* @throws Exception
*/
public function start()
{
$this->inotify = inotify_init();
$this->events = IN_MODIFY | IN_DELETE | IN_CREATE | IN_MOVE;
foreach ($this->dirs as $dir) {
if (!is_dir($dir)) continue;
$this->watch($dir);
}
$this->process->int = -1;
Event::add($this->inotify, [$this, 'check']);
Event::wait();
}
public function clear()
{
Event::del($this->inotify);
Event::exit();
}
/**
* 开始监听
* @throws Exception
*/
public function check()
{
if (!($events = inotify_read($this->inotify))) {
return;
}
if ($this->isReloading) {
return;
}
$LISTEN_TYPE = [IN_CREATE, IN_DELETE, IN_MODIFY, IN_MOVED_TO, IN_MOVED_FROM];
foreach ($events as $ev) {
if (!in_array($ev['mask'], $LISTEN_TYPE)) {
continue;
}
$search = array_search($ev['wd'], $this->watchFiles);
//非重启类型
if (str_ends_with($ev['name'], '.php')) {
Timer::after(3000, fn() => $this->reload($search));
$this->isReloading = TRUE;
}
}
}
/**
* @throws Exception
*/
public function reload($path)
{
$this->process->trigger_reload($path);
$this->process->int = -1;
$this->clearWatch();
foreach ($this->dirs as $root) {
$this->watch($root);
}
$this->isReloading = FALSE;
}
/**
* @throws Exception
*/
public function clearWatch()
{
foreach ($this->watchFiles as $wd) {
@inotify_rm_watch($this->inotify, $wd);
}
$this->watchFiles = [];
}
/**
* @param $dir
* @return bool
* @throws Exception
*/
public function watch($dir): bool
{
//目录不存在
if (!is_dir($dir)) {
return logger()->addError("[$dir] is not a directory.");
}
//避免重复监听
if (isset($this->watchFiles[$dir])) {
return FALSE;
}
if (in_array($dir, self::IG_DIR)) {
return FALSE;
}
$wd = @inotify_add_watch($this->inotify, $dir, $this->events);
$this->watchFiles[$dir] = $wd;
$files = scandir($dir);
foreach ($files as $f) {
if ($f == '.' || $f == '..') {
continue;
}
$path = $dir . '/' . $f;
//递归目录
if (is_dir($path)) {
$this->watch($path);
} else if (!str_ends_with($f, '.php')) {
continue;
}
//检测文件类型
if (strstr($f, '.') == '.php') {
$wd = @inotify_add_watch($this->inotify, $path, $this->events);
$this->watchFiles[$path] = $wd;
}
}
return TRUE;
}
}
-152
View File
@@ -1,152 +0,0 @@
<?php
namespace Kiri\FileListen;
use Exception;
class Scaner
{
private array $md5Map = [];
public bool $isReloading = FALSE;
/**
* @param array $dirs
* @param HotReload $process
*/
public function __construct(protected array $dirs, public HotReload $process)
{
}
/**
* @throws Exception
*/
public function start(): void
{
$this->loadDirs();
$this->tick();
}
/**
* @param bool $isReload
* @throws Exception
*/
private function loadDirs(bool $isReload = FALSE)
{
foreach ($this->dirs as $value) {
if (is_bool($path = realpath($value))) {
continue;
}
if (!is_dir($path)) continue;
$this->loadByDir($path, $isReload);
}
}
/**
* @param $path
* @param bool $isReload
* @return void
* @throws Exception
*/
private function loadByDir($path, bool $isReload = FALSE): void
{
if (!is_string($path)) {
return;
}
$path = rtrim($path, '/');
foreach (glob(realpath($path) . '/*') as $value) {
if (is_dir($value)) {
$this->loadByDir($value, $isReload);
}
if (is_file($value)) {
if ($this->checkFile($value, $isReload)) {
$this->isReloading = TRUE;
sleep(2);
$this->timerReload($value);
break;
}
}
}
}
/**
* @param $value
* @param $isReload
* @return bool
*/
private function checkFile($value, $isReload): bool
{
$md5 = md5($value);
$mTime = filectime($value);
if (!isset($this->md5Map[$md5])) {
if ($isReload) {
return TRUE;
}
$this->md5Map[$md5] = $mTime;
} else {
if ($this->md5Map[$md5] != $mTime) {
if ($isReload) {
return TRUE;
}
$this->md5Map[$md5] = $mTime;
}
}
return FALSE;
}
/**
* @throws Exception
*/
public function timerReload($path)
{
$this->isReloading = TRUE;
$this->process->trigger_reload($path);
$this->loadDirs();
$this->process->int = -1;
$this->isReloading = FALSE;
$this->process->isReloadingOut = FALSE;
$this->tick();
}
private bool $isStop = FALSE;
public function clear()
{
$this->isStop = TRUE;
}
/**
* @throws Exception
*/
public function tick()
{
if ($this->isReloading || $this->isStop) {
return;
}
$this->loadDirs(TRUE);
sleep(2);
$this->tick();
}
}
-27
View File
@@ -1,27 +0,0 @@
<?php
namespace Kiri;
interface IAspect
{
public function before(): void;
/**
* @param mixed $response
*/
public function after(mixed $response): void;
/**
* @param mixed $handler
* @param array $params
* @return mixed
*/
public function invoke(mixed $handler, array $params = []): mixed;
}
-13
View File
@@ -1,13 +0,0 @@
<?php
namespace Kiri;
interface IProxy
{
public function execute();
}
-24
View File
@@ -1,24 +0,0 @@
<?php
namespace Kiri\Pool;
use JetBrains\PhpStorm\Pure;
trait Alias
{
/**
* @param $cds
* @param false $isMaster
* @return string
*/
#[Pure] public function name($cds, bool $isMaster = false): string
{
if ($isMaster === true) {
return $cds . '_master';
} else {
return $cds . '_slave';
}
}
}
-233
View File
@@ -1,233 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
use Closure;
use Database\Mysql\PDO;
use Exception;
use Kiri;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Context;
use Swoole\Error;
use Throwable;
/**
* Class Connection
* @package Kiri\Pool
*/
class Connection extends Component
{
use Alias;
/**
* @param $cds
* @return bool
*
* db is in transaction
* @throws Exception
*/
public function inTransaction($cds): bool
{
$name = $this->name('Mysql:' . $cds, true);
$connection = Context::getContext($name);
if ($connection instanceof PDO) {
return $connection->inTransaction();
}
return false;
}
/**
* @param $coroutineName
* @throws Exception
*/
public function beginTransaction($coroutineName)
{
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
$connection = Context::getContext($coroutineName);
if ($connection instanceof PDO) {
$connection->beginTransaction();
}
}
/**
* @param $coroutineName
* @throws Exception
*/
public function commit($coroutineName)
{
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
$connection = Context::getContext($coroutineName);
if ($connection instanceof PDO) {
$connection->commit();
}
}
/**
* @param $coroutineName
* @throws Exception
*/
public function rollback($coroutineName)
{
$coroutineName = $this->name('Mysql:' . $coroutineName, true);
$connection = Context::getContext($coroutineName);
if ($connection instanceof PDO) {
$connection->rollBack();
}
}
/**
* @param mixed $config
* @param bool $isMaster
* @return PDO|null
* @throws Exception
*/
public function get(mixed $config, bool $isMaster = false): ?PDO
{
$coroutineName = $this->name('Mysql:' . $config['cds'], $isMaster);
if (($pdo = Context::getContext($coroutineName)) instanceof PDO) {
return $pdo;
}
$minx = Config::get('databases.pool.min', 1);
/** @var PDO $connections */
$connections = $this->getPool()->get($coroutineName, $this->create($coroutineName, $config), $minx);
if (Context::hasContext('begin_' . $coroutineName)) {
$connections->beginTransaction();
}
return Context::setContext($coroutineName, $connections);
}
/**
* @param $coroutineName
* @param $config
* @return Closure
*/
public function create($coroutineName, $config): Closure
{
return static function () use ($coroutineName, $config) {
return Kiri::getDi()->create(PDO::class, [$config]);
};
}
/**
* @param string $name
* @param PDO $PDO
* @return void
* @throws Kiri\Exception\ConfigException
* @throws Exception
*/
public function addItem(string $name, PDO $PDO)
{
$this->getPool()->push($name, $PDO);
}
/**
* @param $name
* @param $isMaster
* @param $max
* @throws Exception
*/
public function initConnections($name, $isMaster, $max)
{
$pool = $this->getPool();
$pool->initConnections($name, $isMaster, $max);
}
/**
* @param $coroutineName
* @param $isMaster
* @param array $config
* @throws Kiri\Exception\ConfigException
* @throws Exception
*/
public function release($coroutineName, $isMaster, array $config)
{
$coroutineName = $this->name('Mysql:' . $coroutineName, $isMaster);
/** @var PDO $client */
if (!($client = Context::getContext($coroutineName)) instanceof PDO) {
$client = call_user_func($this->create($coroutineName, $config));
}
if ($client->inTransaction()) {
return;
}
$this->getPool()->push($coroutineName, $client);
Context::remove($coroutineName);
}
/**
* @param $coroutineName
* @return bool
*/
private function hasClient($coroutineName): bool
{
return Context::hasContext($coroutineName);
}
/**
* batch release
* @throws Exception
*/
public function connection_clear($name, $isMaster)
{
$this->getPool()->clean($this->name($name, $isMaster));
}
/**
* @param string $name
* @param mixed $client
* @return bool
* @throws Exception
*/
public function checkCanUse(string $name, mixed $client): bool
{
try {
if (empty($client) || !($client instanceof PDO)) {
$result = false;
} else {
$result = true;
}
} catch (Error|Throwable $exception) {
$result = $this->addError($exception, 'mysql');
} finally {
return $result;
}
}
/**
* @param $coroutineName
* @param bool $isMaster
* @throws Exception
*/
public function disconnect($coroutineName, bool $isMaster = false)
{
Context::remove($coroutineName);
$coroutineName = $this->name('Mysql:' . $coroutineName, $isMaster);
$this->getPool()->clean($coroutineName);
}
/**
* @return Pool
* @throws Exception
*/
public function getPool(): Pool
{
return Kiri::getDi()->get(Pool::class);
}
}
@@ -1,28 +0,0 @@
<?php
namespace Kiri\Pool\Helper;
interface QueueInterface
{
public function isEmpty(): bool;
public function push(mixed $data, float $timeout = -1): bool;
public function pop(float $timeout = -1): mixed;
public function stats(): array;
public function close(): bool;
public function length(): int;
public function isFull(): bool;
}
-101
View File
@@ -1,101 +0,0 @@
<?php
namespace Kiri\Pool\Helper;
use JetBrains\PhpStorm\Pure;
/**
*
*/
class SplQueue implements QueueInterface
{
private \SplQueue $channel;
public int $errCode = 0;
/**
* @param int $max
*/
#[Pure] public function __construct(public int $max)
{
$this->channel = new \SplQueue();
}
/**
* @return bool
*/
public function isEmpty(): bool
{
// TODO: Implement isEmpty() method.
return $this->channel->count() < 1;
}
/**
* @param mixed $data
* @param float $timeout
* @return bool
*/
public function push(mixed $data, float $timeout = -1): bool
{
// TODO: Implement push() method.
$this->channel->enqueue($data);
return true;
}
/**
* @param float $timeout
* @return mixed
*/
public function pop(float $timeout = -1): mixed
{
// TODO: Implement pop() method.
return $this->channel->dequeue();
}
/**
* @return array
*/
public function stats(): array
{
// TODO: Implement stats() method.
return [];
}
/**
* @return bool
*/
public function close(): bool
{
// TODO: Implement close() method.
return false;
}
/**
* @return int
*/
public function length(): int
{
// TODO: Implement length() method.
return $this->channel->count();
}
/**
* @return bool
*/
public function isFull(): bool
{
// TODO: Implement isFull() method.
return $this->channel->count() >= $this->max;
}
}
-248
View File
@@ -1,248 +0,0 @@
<?php
namespace Kiri\Pool;
use Exception;
use Kiri\Context;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Exception\ConfigException;
use Kiri\Pool\Helper\SplQueue;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
/**
* Class Pool
* @package Kiri\Pool
*/
class Pool extends Component
{
/** @var Channel[] */
private static array $_connections = [];
public int $max = 60;
use Alias;
/**
* @param $channel
* @param $retain_number
* @throws Exception
*/
public function flush($channel, $retain_number)
{
$this->pop($channel, $retain_number);
}
/**
* @param Channel|SplQueue $channel
* @param $retain_number
*/
protected function pop(Channel|SplQueue $channel, $retain_number): void
{
while ($channel->length() > $retain_number) {
if (Context::inCoroutine()) {
$connection = $channel->pop();
if ($connection instanceof StopHeartbeatCheck) {
$connection->stopHeartbeatCheck();
}
}
}
}
/**
* @param $name
* @param false $isMaster
* @param int $max
* @throws ConfigException
*/
public function initConnections($name, bool $isMaster = false, int $max = 60)
{
$name = $this->name($name, $isMaster);
if (isset(static::$_connections[$name])) {
$value = static::$_connections[$name];
if ($value instanceof Channel || $value instanceof SplQueue) {
return;
}
}
$this->newChannel($name, $max);
$this->max = $max;
}
/**
* @param $name
* @return Channel|SplQueue
* @throws ConfigException
* @throws Exception
*/
private function getChannel($name): Channel|SplQueue
{
if (!isset(static::$_connections[$name])) {
$this->newChannel($name);
}
if (static::$_connections[$name]->errCode == SWOOLE_CHANNEL_CLOSED) {
throw new Exception('Channel is Close.');
}
return static::$_connections[$name];
}
/**
* @throws ConfigException
*/
private function newChannel($name, $max = null)
{
if ($max == null) {
$max = Config::get('databases.pool.max', 10);
}
if (Coroutine::getCid() === -1) {
static::$_connections[$name] = new SplQueue($max);
} else {
static::$_connections[$name] = new Channel($max);
}
}
/**
* @param $name
* @param $callback
* @param $minx
* @return array
* @throws ConfigException
* @throws Exception
*/
public function get($name, $callback, $minx): mixed
{
$channel = $this->getChannel($name);
if (!$channel->isEmpty()) {
return $this->maxIdleQuantity($channel, $minx);
}
return $callback();
}
/**
* @param $channel
* @param $minx
* @return mixed
* @throws Exception
*/
protected function maxIdleQuantity($channel, $minx): mixed
{
$connection = $channel->pop();
if ($channel->length() > $minx) {
$this->pop($channel, $minx);
}
return $connection;
}
/**
* @param $name
* @return bool
* @throws ConfigException
*/
public function isNull($name): bool
{
return $this->getChannel($name)->isEmpty();
}
/**
* @param string $name
* @param mixed $client
* @return bool
* 检查连接可靠性
*/
public function checkCanUse(string $name, mixed $client): bool
{
return true;
}
/**
* @param string $name
* @return bool
*/
public function hasItem(string $name): bool
{
if (isset(static::$_connections[$name])) {
return !static::$_connections[$name]->isEmpty();
}
return false;
}
/**
* @param string $name
* @return mixed
*/
public function size(string $name): mixed
{
if (!isset(static::$_connections[$name])) {
return 0;
}
return static::$_connections[$name]->length();
}
/**
* @param string $name
* @param mixed $client
* @throws ConfigException
*/
public function push(string $name, mixed $client)
{
$channel = $this->getChannel($name);
if (!$channel->isFull()) {
$channel->push($client);
}
unset($client);
}
/**
* @param string $name
* @throws Exception
*/
public function clean(string $name)
{
if (!isset(static::$_connections[$name])) {
return;
}
while (static::$_connections[$name]->length() > 0) {
if (static::$_connections[$name] instanceof Channel)
{
if (!Context::inCoroutine())
{
break;
}
}
$client = static::$_connections[$name]->pop();
if ($client instanceof StopHeartbeatCheck) {
$client->stopHeartbeatCheck();
}
}
static::$_connections[$name] = null;
unset(static::$_connections[$name]);
}
/**
* @return Channel[]
*/
protected function getChannels(): array
{
return static::$_connections;
}
}
-122
View File
@@ -1,122 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
use Closure;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Context;
use Kiri\Exception\ConfigException;
use Kiri;
/**
* Class RedisClient
* @package Kiri\Pool
*/
class Redis extends Component
{
use Alias;
/**
* @param mixed $config
* @param bool $isMaster
* @return mixed
* @throws Exception
*/
public function get(mixed $config, bool $isMaster = false): mixed
{
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
if (Context::hasContext($coroutineName)) {
return Context::getContext($coroutineName);
}
$pool = $config['pool'] ?? ['min' => 1, 'max' => 100];
$clients = $this->getPool()->get($coroutineName, $this->create($coroutineName, $config), $pool['min'] ?? 1);
return Context::setContext($coroutineName, $clients);
}
/**
* @param string $name
* @param mixed $config
* @return Closure
*/
public function create(string $name, mixed $config): Closure
{
return static function () use ($name, $config) {
return Kiri::getDi()->create(\Kiri\Cache\Base\Redis::class, [$config]);
};
}
/**
* @param array $config
* @param bool $isMaster
* @throws ConfigException
* @throws Exception
*/
public function release(array $config, bool $isMaster = false)
{
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
if (!Context::hasContext($coroutineName)) {
return;
}
$this->getPool()->push($coroutineName, Context::getContext($coroutineName));
Context::remove($coroutineName);
}
/**
* @param array $config
* @param bool $isMaster
* @throws Exception
*/
public function destroy(array $config, bool $isMaster = false)
{
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
$this->getPool()->clean($coroutineName);
Context::remove($coroutineName);
}
/**
* @param array $config
* @param bool $isMaster
* @throws Exception
*/
public function connection_clear(array $config, bool $isMaster = false)
{
$coroutineName = $this->name('Redis:' . $config['host'], $isMaster);
$this->getPool()->clean($coroutineName);
}
/**
* @return Pool
* @throws Exception
*/
public function getPool(): Pool
{
return Kiri::getDi()->get(Pool::class);
}
/**
* @param $name
* @param $isMaster
* @param $max
* @throws Exception
*/
public function initConnections($name, $isMaster, $max)
{
$this->getPool()->initConnections($name, $isMaster, $max);
}
}
-11
View File
@@ -1,11 +0,0 @@
<?php
namespace Kiri\Pool;
interface StopHeartbeatCheck
{
public function stopHeartbeatCheck();
}
-27
View File
@@ -1,27 +0,0 @@
<?php
namespace Kiri;
class Proxy
{
/**
* Proxy constructor.
* @param IProxy $IProxy
*/
public function __construct(public IProxy $IProxy)
{
}
/**
* @return mixed
*/
public function execute(): mixed
{
return $this->IProxy->execute();
}
}
+217
View File
@@ -0,0 +1,217 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/27 0027
* Time: 11:00
*/
declare(strict_types=1);
namespace Kiri\Redis;
use Exception;
use Kiri;
use Kiri\Exception\RedisConnectException;
use Kiri\Pool\Pool;
use RedisException;
use wchat\common\Result;
use function config;
/**
* Class Redis
* @package Kiri\Cache
* @mixin \Redis
*/
class Redis
{
public string $host = '';
public int $port = 6379;
public string $prefix = '';
public string $auth = '';
public int $databases = 0;
public int $timeout = 30;
/**
* @var int
*/
public int $read_timeout = -1;
/**
* @var array|int[]
*/
public array $pool = ['min' => 1, 'max' => 100];
/**
* 初始化
*/
public function __construct()
{
Kiri::configure($this, config('redis', []));
}
/**
* @return void
* @throws
*/
public function init(): void
{
}
/**
* @param $name
* @param $arguments
* @return mixed
* @throws
*/
public function __call($name, $arguments): mixed
{
if (method_exists($this, $name)) {
return $this->{$name}(...$arguments);
} else {
return $this->proxy($name, $arguments);
}
}
/**
* @param $key
* @param int $timeout
* @return bool
* @throws
*/
public function waite($key, int $timeout = 5): bool
{
$time = time();
while (!$this->setNx($key, '1')) {
if (time() - $time >= $timeout) {
return FALSE;
}
usleep(1000);
}
$this->expire($key, $timeout);
return TRUE;
}
/**
* @param $key
* @param int $timeout
* @return bool|int
* @throws
*/
public function lock($key, int $timeout = 5): bool|int
{
$script = <<<SCRIPT
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
if (_nx ~= 0) then
redis.call('expire',KEYS[1], ARGV[1])
return 1
end
return 0
SCRIPT;
return $this->eval($script, ['{lock}:' . $key, $timeout], 1);
}
/**
* @param $key
* @return int
* @throws
*/
public function unlock($key): int
{
return $this->del('{lock}:' . $key);
}
/**
* @return void
* @throws
*/
public function destroy(): void
{
$this->pool()->close($this->getName());
}
/**
* @param $name
* @param $arguments
* @return mixed
* @throws
*/
public function proxy($name, $arguments): mixed
{
$client = $this->getClient();
try {
return $client->{$name}(...$arguments);
} catch (\Throwable $throwable) {
return trigger_print_error(throwable($throwable));
} finally {
if ($client->ping('h') == 'h') {
$this->pool()->push($this->getName(), $client);
}
}
}
/**
* @return \Redis
* @throws
*/
private function getClient(): \Redis
{
return $this->pool()->get($this->getName());
}
/**
* @return Pool
* @throws
*/
protected function pool(): Pool
{
$pool = Kiri::getPool();
if (!$pool->hasChannel($this->getName())) {
$pool->created($this->getName(), $this->pool['max'], [$this, 'connect']);
}
return $pool;
}
/**
* @return string
*/
private function getName(): string
{
return 'redis.' . $this->host;
}
/**
* @return \Redis
* @throws
*/
protected function connect(): \Redis
{
$redis = new \Redis();
if (!$redis->connect($this->host, $this->port, $this->timeout)) {
throw new RedisConnectException(sprintf('The Redis Connect %s::%d Fail.', $this->host, $this->port));
}
if (!empty($this->auth) && !$redis->auth($this->auth)) {
throw new RedisConnectException(sprintf('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $this->auth));
}
$redis->select($this->databases);
if ($this->read_timeout > 0) {
$redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->read_timeout);
}
if (!empty($this->prefix)) {
$redis->setOption(\Redis::OPT_PREFIX, $this->prefix);
}
return $redis;
}
}
-101
View File
@@ -1,101 +0,0 @@
<?php
namespace Kiri;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Abstracts\Input;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Kiri;
/**
* Class Runtime
* @package Kiri
*/
class Runtime extends Command
{
public string $command = 'runtime:builder';
public string $description = 'create app file cache';
const CACHE_NAME = '.runtime.cache';
const CONFIG_NAME = '.config.cache';
protected function configure()
{
$this->setName('runtime:builder');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws Exception
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
// TODO: Implement onHandler() method.
$annotation = Kiri::app()->getAnnotation();
$runtime = storage(static::CACHE_NAME);
$config = storage(static::CONFIG_NAME);
Kiri::writeFile($config, $this->configEach());
Kiri::writeFile($runtime, serialize($annotation->getLoader()));
return 1;
}
/**
* @return string
* @throws Exception
*/
public function configEach(): string
{
$array = [];
foreach (Config::getData() as $key => $datum) {
if ($datum instanceof \Closure) {
continue;
}
if (is_array($datum)) {
$array[$key] = $this->arrayEach($datum);
} else {
$array[$key] = $datum;
}
}
return serialize($array);
}
/**
* @param array $value
* @return array
*/
private function arrayEach(array $value): array
{
$array = [];
foreach ($value as $key => $item) {
if ($item instanceof \Closure) {
continue;
}
if (is_array($item)) {
$array[$key] = $this->arrayEach($item);
} else {
$array[$key] = $item;
}
}
return $array;
}
}
-10
View File
@@ -1,10 +0,0 @@
<?php
namespace Kiri;
interface ToArray
{
public function toArray();
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace Kiri;
use Swoole\Coroutine;
class Waite
{
/**
* @param float $time
* @return void
*/
public static function sleep(float $time): void
{
if (!class_exists(Coroutine::class) || Coroutine::getCid() > -1) {
usleep($time * 1000);
} else {
Coroutine::sleep($time / 1000);
}
}
}
-14
View File
@@ -1,14 +0,0 @@
<?php
namespace Kiri\Gateway;
class Collector
{
public function get()
{
}
}
-23
View File
@@ -1,23 +0,0 @@
<?php
namespace Kiri\Gateway;
use Swoole\Http\Request;
use Swoole\Http\Response;
class GatewayServer
{
/**
* @param Request $request
* @param Response $response
*/
public function onRequest(Request $request, Response $response)
{
}
}
-35
View File
@@ -1,35 +0,0 @@
<?php
namespace Kiri\Gateway;
class HashMap
{
const HTTP = 1;
const TCP = 2;
const UDP = 2;
public string $domain;
public string $path;
public string $scheme;
public string $method;
public string $proxy_host;
public string $proxy_port;
public int $type = self::HTTP;
}
-342
View File
@@ -1,342 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: 向林
* Date: 2016/8/9 0009
* Time: 17:43
*/
declare(strict_types=1);
namespace Gii;
use Database\Connection;
use Database\Db;
use Exception;
use Kiri\Cache\Redis;
use Kiri;
use Symfony\Component\Console\Input\InputInterface;
/**
* Class gii
*
* @package Inter\utility
*/
class Gii
{
private ?string $tableName = NULL;
/** @var null|Connection */
private ?Connection $db;
private InputInterface $input;
public string $modelPath = APP_PATH . 'app/Model/';
public string $modelNamespace = 'App\\Model\\';
public string $controllerPath = APP_PATH . 'app/Http/Controller/';
public string $controllerNamespace = 'App\\Controller\\';
public static array $createSqls = [];
public array $keyword = [
'ADD', 'ALL', 'ALTER', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'BEFORE', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'CONDITION', 'CONNECTION', 'CONSTRAINT', 'CONTINUE', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'DUAL', 'EACH', 'ELSE', 'ELSEIF', 'ENCLOSED', 'ESCAPED', 'EXISTS', 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FLOAT', 'FLOAT4', 'FLOAT8', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'GOTO', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', 'INT1', 'INT2', 'INT3', 'INT4', 'INT8', 'INTEGER', 'INTERVAL', 'INTO', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LABEL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINEAR', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'MODIFIES', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PROCEDURE', 'PURGE', 'RAID0', 'RANGE', 'READ', 'READS', 'REAL', 'REFERENCES', 'REGEXP', 'RELEASE', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SCHEMA', 'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE', 'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SPATIAL', 'SPECIFIC', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'TABLE', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRIGGER', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'X509', 'XOR', 'YEAR_MONTH', 'ZEROFILL'
];
/**
* @param Connection|null $db
*
* @param InputInterface $input
* @return array
* @throws Exception
*/
public function run(?Connection $db, InputInterface $input): array
{
return $this->gen($input, $db);
}
/**
* @param InputInterface $input
* @param $db
* @return array
* @throws Exception
*/
public function gen(InputInterface $input, $db): array
{
$this->input = $input;
$this->db = $db;
$make = $this->input->getOption('make');
if (empty($make)) {
throw new Exception('构建类型不能为空~');
}
switch (strtolower($make)) {
case 'task':
$task = new GiiTask();
$task->setInput($this->input);
return $task->generate();
case 'middleware':
$task = new GiiMiddleware();
$task->setInput($this->input);
return $task->generate();
case 'rpc-client':
$task = new GiiRpcClient();
$task->setInput($this->input);
return $task->generate();
case 'rpc-service':
$task = new GiiRpcService();
$task->setInput($this->input);
return $task->generate();
case 'json-rpc':
$task = new GiiJsonRpc();
$task->setInput($this->input);
return $task->create();
default:
return $this->getModel($make, $input);
}
}
/**
* @param $make
* @param $input
* @return array
* @throws Exception
*/
private function getModel($make, $input): array
{
return $this->makeByDatabases($make, $input);
}
/**
* @param $make
* @param InputInterface $input
* @return array
* @throws Exception
*/
private function makeByDatabases($make, InputInterface $input): array
{
if ($input->hasOption('name')) {
$this->tableName = $input->getOption('name');
}
return match ($make) {
'controller' => $this->getTable(1, 0),
'model' => $this->getTable(0, 1),
default => [],
};
}
/**
* @param $controller
* @param $model
* @return array
*
* @throws Exception
*/
private function getTable($controller, $model): array
{
$tables = $this->getFields($this->getTables());
if (empty($tables)) {
return [];
}
$fileList = [];
foreach ($tables as $key => $val) {
$data = $this->createModelFile($key, $val);
if ($controller == 1) {
$fileList[] = $this->generateController($data);
}
if ($model == 1) {
$fileList[] = $this->generateModel($data);
}
}
return $fileList;
}
/**
* @param array $data
* @return string
* @throws Exception
*/
private function generateModel(array $data): string
{
$controller = new GiiModel($data['classFileName'], $data['tableName'], $data['visible'], $data['res'], $data['fields']);
$controller->setConnection($this->db);
$controller->setModelPath($this->modelPath);
$controller->setModelNamespace($this->modelNamespace);
$controller->setInput($this->input);
// $controller->setModule($this->input->getArgument('module'));
$controller->setControllerPath($this->controllerPath);
$controller->setControllerNamespace($this->controllerNamespace);
return $controller->generate();
}
/**
* @param array $data
* @return string
* @throws Exception
*/
private function generateController(array $data): string
{
$controller = new GiiController($data['classFileName'], $data['fields']);
$controller->setConnection($this->db);
$controller->setModelPath($this->modelPath);
$controller->setInput($this->input);
$controller->setModelNamespace($this->modelNamespace);
$controller->setControllerPath($this->controllerPath);
$controller->setModule($this->input->getArgument('module'));
$controller->setControllerNamespace($this->controllerNamespace);
return $controller->generate();
}
/**
* @return array|string|null
* @throws Exception
*/
private function getTables(): array|string|null
{
if (empty($this->tableName)) {
return $this->showAll();
}
$res = $this->tableName;
if (is_string($res)) {
$res = explode(',', $this->tableName);
}
if (empty($res)) {
return [];
}
return $res;
}
/**
* @return array
* @throws Exception
*/
private function showAll(): array
{
$res = [];
$_tables = Db::findAllBySql('show tables from `' . $this->db->database . '`', [], $this->db);
if (empty($_tables)) {
return $res;
}
foreach ($_tables as $key => $val) {
$res[] = array_shift($val);
}
return $res;
}
/**
* @param $table
* @return bool|int|null
* @throws Exception
*/
private function getIndex($table): bool|int|null
{
$data = Db::findAllBySql('SHOW INDEX FROM ' . $table, [], $this->db);
return empty($data) ? NULL : $data[0];
}
/**
* @param $tables
*
* @return array
* @throws
*/
private function getFields($tables): array
{
$res = [];
if (!is_array($tables)) {
$tables = [$tables];
}
foreach ($tables as $key => $val) {
if (empty($val)) continue;
$_tmp = Db::findAllBySql('SHOW FULL FIELDS FROM `' . $this->db->database . '`.' . $val, [], $this->db);
if (empty($_tmp)) {
continue;
}
$res[$val] = $_tmp;
}
return $res;
}
/**
* @param $tableName
* @param $tables
*
* @return array
* @throws Exception
*/
public function createModelFile($tableName, $tables): array
{
$res = $visible = $fields = $keys = [];
foreach ($tables as $_key => $_val) {
$keys = $tableName;
if ($_val['Extra'] == 'auto_increment' || $_val['Key'] == 'PRI') {
$keys = $tableName;
}
if (!isset($keys) && !($index = $this->getIndex($tableName))) {
$keys = $index['Column_name'];
}
if (in_array(strtoupper($_val['Field']), $this->keyword)) {
throw new Exception('You can not use keyword "' . $_val['Field'] . '" as field at table "' . $tableName . '"');
}
array_push($visible, $this->createVisible($_val['Field']));
array_push($fields, $_val);
$res[] = $this->createSetFunc($_val['Field'], $_val['Comment']);
}
$classFileName = $this->getClassName($tableName);
return [
'classFileName' => $classFileName,
'tableName' => $keys,
'visible' => $visible,
'fields' => $fields,
'res' => $res,
];
}
/**
* @param $field
* @return string
* 创建变量注释
*/
private function createVisible($field): string
{
return '
* @property $' . $field;
}
/**
* @param $field
* @param $comment
* @return string
* 暂时不知道干嘛用的
*/
private function createSetFunc($field, $comment): string
{
return '
' . str_pad('\'' . $field . '\'', 20, ' ', STR_PAD_RIGHT) . '=> \'' . (empty($comment) ? ucfirst($field) : $comment) . '\',';
}
/**
* @param $tableName
* @return string
* 构建类名称
*/
private function getClassName($tableName): string
{
$res = [];
$tableName = str_replace($this->db->tablePrefix,'', $tableName);
foreach (explode('_', $tableName) as $n => $val) {
$res[] = ucfirst($val);
}
return implode('', $res);
}
}
-411
View File
@@ -1,411 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Database\Connection;
use Exception;
use Kiri\Core\Json;
use ReflectionClass;
use ReflectionException;
use Symfony\Component\Console\Input\InputInterface;
/**
* Class GiiBase
* @package Gii
*/
abstract class GiiBase
{
public array $fileList = [];
protected InputInterface $input;
public string $modelPath = APP_PATH . 'app/Model/';
public string $modelNamespace = 'App\Model\\';
public string $controllerPath = APP_PATH . 'app/Http/Controller/';
public string $controllerNamespace = 'App\\Controller\\';
public ?string $module = null;
public array $rules = [];
public array $type = [
'int' => ['tinyint', 'smallint', 'mediumint', 'int', 'bigint'],
'string' => ['char', 'varchar', 'tinytext', 'text', 'mediumtext', 'longtext', 'enum'],
'date' => ['date'],
'time' => ['time'],
'year' => ['year'],
'datetime' => ['datetime'],
'timestamp' => ['timestamp'],
'float' => ['float', 'double', 'decimal',],
];
public ?string $tableName = NULL;
public ?Connection $db = null;
/**
* @param string $modelPath
*/
public function setModelPath(string $modelPath): void
{
$this->modelPath = $modelPath;
}
/**
* @param string $modelNamespace
*/
public function setModelNamespace(string $modelNamespace): void
{
$this->modelNamespace = $modelNamespace;
}
/**
* @param string $controllerPath
*/
public function setControllerPath(string $controllerPath): void
{
$this->controllerPath = $controllerPath;
}
/**
* @param $module
*/
public function setModule($module)
{
$this->module = $module;
}
/**
* @param string $controllerNamespace
*/
public function setControllerNamespace(string $controllerNamespace): void
{
$this->controllerNamespace = $controllerNamespace;
}
/**
* @param InputInterface $input
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
}
/**
* @param ReflectionClass $object
* @param $className
*
* @return string
*/
public function getUseContent(ReflectionClass $object, $className): string
{
if (empty($object)) {
return '';
}
$file = $this->getFilePath($className);
if (!file_exists($file)) {
return '';
}
$content = file_get_contents($file);
$explode = explode(PHP_EOL, $content);
$exists = array_slice($explode, 0, $object->getStartLine());
$_tmp = [];
foreach ($exists as $key => $val) {
if (trim($val) == '/**') {
break;
}
$_tmp[] = $val;
}
return trim(implode(PHP_EOL, $_tmp));
}
/**
* @param string $fileName
* @param ReflectionClass $class
* @return string
*/
protected function getImports(string $fileName, ReflectionClass $class): string
{
$startLine = 1;
$array = [];
$fileOpen = fopen($fileName, 'r');
while (($content = fgets($fileOpen)) !== false) {
if (str_starts_with($content, 'use ')) {
$array[] = $content;
}
if ($startLine == $class->getStartLine()) {
break;
}
++$startLine;
}
return implode($array);
}
/**
* @param ReflectionClass $class
* @return string
* @throws ReflectionException
*/
protected function getClassProperty(ReflectionClass $class): string
{
$html = '';
$rc = $class->getParentClass()->getConstants();
foreach ($class->getConstants() as $key => $val) {
if (isset($rc[$key])) {
continue;
}
if (is_numeric($val)) {
$html .= '
const ' . $key . ' = ' . $val . ';' . "\n";
} else {
$html .= '
const ' . $key . ' = \'' . $val . '\';' . "\n";
}
}
foreach ($class->getDefaultProperties() as $key => $val) {
$property = $class->getProperty($key);
if ($key == 'primary' || $key == 'table' || $key == 'connection' || $key == 'rules') {
continue;
}
if ($property->class != $class->getName()) continue;
if (is_array($val)) {
$val = '[\'' . implode('\', \'', $val) . '\']';
} else if (!is_numeric($val)) {
$val = '\'' . $val . '\'';
}
if ($property->isProtected()) {
$debug = 'protected';
} else if ($property->isPrivate()) {
$debug = 'private';
} else {
$debug = 'public';
}
if ($property->hasType()) {
$type = ' ' . $property->getType() . ' $' . $key . ' = ' . $val . ';' . "\n";
} else {
$type = ' $' . $key . ' = ' . $val . ';' . "\n";
}
if ($property->isStatic()) {
$html .= '
' . $debug . ' static' . $type;
} else {
$html .= '
' . $debug . $type;
}
}
return $html;
}
/**
* @param ReflectionClass $class
* @param array $filters
* @return string
* @throws Exception
*/
protected function getClassMethods(ReflectionClass $class, array $filters = []): string
{
$methods = $class->getMethods();
$classFileName = str_replace(APP_PATH, '', $class->getFileName());
$content = [];
if (!empty($methods)) foreach ($methods as $key => $val) {
if ($val->class != $class->getName()) continue;
if (in_array($val->name, $filters)) continue;
$over = "
" . $val->getDocComment() . "\n";
$attributes = $val->getAttributes();
if (!empty($attributes)) {
foreach ($attributes as $attribute) {
$explode = explode('\\', $attribute->getName());
$_array = [];
foreach ($attribute->getArguments() as $_key => $argument) {
$argument = $this->resolveArray($argument);
if (is_numeric($_key)) {
$_array[] = $argument;
} else {
$_array[] = $_key . ': ' . $argument . '';
}
}
if (empty($_array)) {
$end = " #[" . end($explode) . "]
";
} else {
$end = " #[" . end($explode) . "(" . implode(',', $_array) . ")]
";
}
if (str_contains($over, $end)) {
$over = str_replace($end, '', $over);
}
$over .= $end;
}
}
$func = $this->getFuncLineContent($class, $classFileName, $val->name) . "\n";
$content[] = $over . $func;
}
return implode(PHP_EOL, $content);
}
/**
* @param $argument
* @return string
*/
private function resolveArray($argument): string
{
if (is_array($argument)) {
$__array = [];
foreach ($argument as $key => $value) {
if (is_string($value)) {
if (str_contains($value, '\\') && class_exists($value)) {
$explode_class = explode('\\', $value);
$__array[] = end($explode_class) . '::class';
} else {
$__array[] = '\'' . $value . '\'';
}
} else {
$value = str_replace('{', '[', Json::encode($value));
$value = str_replace('}', ']', Json::encode($value));
$value = str_replace(':', '=>', Json::encode($value));
$value = preg_replace('/"\d+"\=\>/', '', $value);
$__array[] = $value;
}
}
$argument = '[' . implode(', ', $__array) . ']';
} else {
$argument = '\'' . $argument . '\'';
}
return $argument;
}
/**
* @param $fields
* @return mixed 返回表主键
* 返回表主键
*/
public function getPrimaryKey($fields): mixed
{
$condition = ['PRI', 'UNI'];
foreach ($fields as $field) {
if ($field['Extra'] == 'auto_increment') {
return $field['Field'];
}
if (in_array($field['Key'], $condition)) {
return $field['Field'];
}
}
return null;
}
/**
* @param $className
* @return string
*/
private function getFilePath($className): string
{
if (strpos($className, '\\')) {
$className = str_replace('\\', '/', $className);
}
if (strpos($className, '\\')) {
$className = str_replace('\\', '/', $className);
}
return APP_PATH . $className;
}
/**
* @param ReflectionClass $object
* @param $className
* @param $method
* @return string
* @throws Exception
*/
public function getFuncLineContent(ReflectionClass $object, $className, $method): string
{
$fun = $object->getMethod($method);
$content = file_get_contents($this->getFilePath($className));
$explode = explode(PHP_EOL, $content);
$exists = array_slice($explode, $fun->getStartLine() - 1, $fun->getEndLine() - $fun->getStartLine() + 1);
return implode(PHP_EOL, $exists);
}
/**
* @return array
*/
protected function getModelPath(): array
{
$dbName = $this->db->id;
if (empty($dbName) || $dbName == 'db') {
$dbName = '';
}
$modelPath = [
'namespace' => $this->modelNamespace,
'path' => $this->modelPath,
];
if (!is_dir($modelPath['path'])) {
mkdir($modelPath['path']);
}
if (!empty($dbName)) {
$modelPath['namespace'] = $this->modelNamespace . ucfirst($dbName);
$modelPath['path'] = $this->modelPath . ucfirst($dbName);
}
if (!is_dir($modelPath['path'])) {
mkdir($modelPath['path']);
}
return $modelPath;
}
/**
* @param $db
*/
public function setConnection($db)
{
$this->db = $db;
}
/**
* @param $val
* @return string
*/
protected function checkIsRequired($val): string
{
return strtolower($val['Null']) == 'no' && $val['Default'] === NULL ? 'true' : 'false';
}
/**
* @return array
*/
public function getFileLists(): array
{
return $this->fileList;
}
}
-76
View File
@@ -1,76 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Exception\ConfigException;
use Kiri;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class Command
* @package Http
*/
class GiiCommand extends Command
{
public string $command = 'sw:gii';
public string $description = './snowflake sw:gii make=model|controller|task|interceptor|limits|middleware name=xxxx';
/**
*
*/
protected function configure()
{
$this->setName('sw:gii')
->addOption('make','m', InputArgument::OPTIONAL)
->addOption('name','t', InputArgument::OPTIONAL)
->addOption('databases','d', InputArgument::OPTIONAL)
->setDescription('./snowflake sw:gii make=model|controller|task|interceptor|limits|middleware name=xxxx');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws ConfigException
* @throws Exception
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
/** @var Gii $gii */
$gii = Kiri::app()->get('gii');
$connections = Kiri::app()->get('db');
if (($db = $input->getOption('databases')) != null) {
$gii->run($connections->get($db), $input);
return 1;
}
$action = $input->getOption('make');
if (!in_array($action, ['model', 'controller'])) {
$gii->run(null, $input);
return 1;
}
$array = [];
foreach (Config::get('databases.connections') as $key => $connection) {
$array[$key] = $gii->run($connections->get($key), $input);
}
$output->writeln(json_encode($array, JSON_UNESCAPED_UNICODE));
return 1;
}
}
-536
View File
@@ -1,536 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Exception;
use ReflectionException;
use Kiri;
/**
* Class GiiController
* @package Gii
*/
class GiiController extends GiiBase
{
public string $className = '';
public array $fields = [];
/**
* GiiController constructor.
* @param $className
* @param $fields
*/
public function __construct($className, $fields)
{
$this->className = $className;
$this->fields = $fields;
}
/**
* @return string|bool
* @throws ReflectionException
* @throws Exception
*/
public function generate(): string|bool
{
$path = $this->getControllerPath();
$modelPath = $this->getModelPath();
$managerName = $this->className;
$namespace = rtrim($path['namespace'], '\\');
$model_namespace = rtrim($modelPath['namespace'], '\\');
$class = '';
$controller = str_replace('\\\\', '\\', "$namespace\\{$managerName}Controller");
$html = "<?php
namespace {$namespace};
";
if (file_exists($path['path'] . '/' . $managerName . 'Controller.php')) {
try {
$class = new \ReflectionClass($controller);
$import = $this->getImports($path['path'] . '/' . $managerName . 'Controller.php', $class);
} catch (\Throwable $Exception) {
exit(logger()->addError($Exception, 'throwable'));
}
} else {
$import = "use Kiri;
use Exception;
use Kiri\Annotation\Target;
use Kiri\Annotation\Route\Middleware;
use Kiri\Annotation\Route\Route;
use Kiri\Core\Str;
use Kiri\Core\Json;
use Kiri\Message\Context\Request;
use Kiri\Message\Context\Response;
use Kiri\Message\Controller;
use JetBrains\PhpStorm\ArrayShape;
use {$model_namespace}\\{$managerName};
";
}
if (!empty($import)) {
$html .= $import;
}
$controllerName = $managerName;
$historyModel = "use {$model_namespace}\\{$managerName};";
if (!str_contains($html, $historyModel)) {
$html .= $historyModel;
}
$html .= "
/**
* Class {$controllerName}Controller
*
* @package controller
*/
#[Target] class {$controllerName}Controller extends Controller
{
";
$funcNames = [];
if (is_object($class)) {
$html .= $this->getClassProperty($class);
$html .= $this->getClassMethods($class);
}
$default = ['loadParam', 'actionAdd', 'actionUpdate', 'actionDetail', 'actionDelete', 'actionBatchDelete', 'actionList'];
foreach ($default as $key => $val) {
if (str_contains($html, ' function ' . $val . '(')) {
continue;
}
$html .= $this->{'controllerMethod' . str_replace('action', '', $val)}($this->fields, $managerName, $managerName, $path) . "\n";
}
$html .= '
}';
$file = $path['path'] . '/' . $controllerName . 'Controller.php';
if (file_exists($file)) {
unlink($file);
}
Kiri::writeFile($file, $html);
return $controllerName . 'Controller.php';
}
/**
* @return array
*/
private function getControllerPath(): array
{
$dbName = $this->db->id;
if (empty($dbName) || $dbName == 'db') {
$dbName = '';
}
$module = empty($this->module) ? '' : $this->module;
$modelPath['namespace'] = $this->controllerNamespace . $module;
$modelPath['path'] = $this->controllerPath . $module;
if (!is_dir($modelPath['path'])) {
mkdir($modelPath['path']);
}
if (!empty($dbName)) {
$modelPath['namespace'] = $this->controllerNamespace . ucfirst($dbName);
$modelPath['path'] = $this->controllerPath . ucfirst($dbName);
}
$modelPath['namespace'] = rtrim($modelPath['namespace'], '\\');
$modelPath['path'] = rtrim($modelPath['path'], '\\');
if (!is_dir($modelPath['path'])) {
mkdir($modelPath['path']);
}
return $modelPath;
}
/**
* @param $fields
* @param $className
* @param null $object
* @param $path
* @return string
* 新增
*/
public function controllerMethodAdd($fields, $className, $object, $path): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/add", method: "POST")]
#[Middleware(middleware: [])]
public function actionAdd(): string
{
$model = new ' . $className . '();
$model->attributes = $this->loadParam();
if (!$model->save()) {
return JSON::to(500, $model->getLastError());
}
return JSON::to(0, $model->toArray());
}';
}
/**
* @param $fields
* @param $className
* @param null $object
* @return string
* 通用
*/
public function controllerMethodLoadParam($fields, $className, $object = NULL): string
{
return '
/**
* @return array
* @throws Exception
*/
#[ArrayShape([])]
private function loadParam(): array
{
return [' . $this->getData($fields) . '
];
}';
}
/**
* @param $fields
* @param $className
* @param null $object
* @param array $path
* @return string
* 构建更新
*/
public function controllerMethodUpdate($fields, $className, $object = NULL, $path = []): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/update", method: "POST")]
#[Middleware(middleware: [])]
public function actionUpdate(): string
{
$model = ' . $className . '::findOne($this->request->post(\'id\', 0));
if (empty($model)) {
return JSON::to(500, SELECT_IS_NULL);
}
$model->attributes = $this->loadParam();
if (!$model->save()) {
return JSON::to(500, $model->getLastError());
}
return JSON::to(0, $model->toArray());
}';
}
/**
* @param $fields
* @param $className
* @param null $object
* @param array $path
* @return string
* 构建更新
*/
public function controllerMethodBatchDelete($fields, $className, $object = NULL, $path = []): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/batch-delete", method: "POST")]
#[Middleware(middleware: [])]
public function actionBatchDelete(): string
{
$_key = $this->request->array(\'ids\');
if (empty($_key)) {
return JSON::to(500, PARAMS_IS_NULL);
}
$model = ' . $className . '::find()->whereIn(\'id\', $_key);
if (!$model->delete()) {
return JSON::to(500, DB_ERROR_BUSY);
}
return JSON::to(0, $_key);
}';
}
/**
* @param $fields
* @param $className
* @param $managerName
* @param array $path
* @return string
* 构建详情
*/
public function controllerMethodDetail($fields, $className, $managerName, $path = []): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/detail", method: "POST")]
#[Middleware(middleware: [])]
public function actionDetail(): string
{
$model = ' . $managerName . '::findOne($this->request->query(\'id\'));
if (empty($model)) {
return JSON::to(404, SELECT_IS_NULL);
}
return JSON::to(0, $model->toArray());
}';
}
/**
* @param $fields
* @param $className
* @param $managerName
* @param $path
* @return string
* 构建删除操作
*/
public function controllerMethodDelete($fields, $className, $managerName, $path): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/delete", method: "POST")]
#[Middleware(middleware: [])]
public function actionDelete(): string
{
$_key = $this->request->int(\'id\', true);
$model = ' . $managerName . '::findOne($_key);
if (empty($model)) {
return JSON::to(500, SELECT_IS_NULL);
}
if (!$model->delete()) {
return JSON::to(500, $model->getLastError());
}
return JSON::to(0, $model);
}';
}
/**
* @param $fields
* @param $className
* @param $managerName
* @param array $path
* @return string
* 构建查询列表
*/
public function controllerMethodList($fields, $className, $managerName, $path = []): string
{
$_path = str_replace(CONTROLLER_PATH, '', $path['path']);
$_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className);
$_path = ltrim($_path,'/');
return '
/**
* @return string
* @throws Exception
*/
#[Route(uri: "' . $_path . '/list", method: "POST")]
#[Middleware(middleware: [])]
public function actionList(): string
{
//分页处理
$count = $this->request->query(\'count\', -1);
$order = $this->request->query(\'order\', \'id\');
if (!empty($order)) {
$order .= !$this->request->query(\'isDesc\', 0) ? \' asc\' : \' desc\';
} else {
$order = \'id desc\';
}
//列表输出
$model = ' . $managerName . '::find()->where($this->request->gets())->orderBy($order);
$keyword = $this->request->query(\'keyword\', null);
if (!empty($keyword)) {
$model->like(\'keyword\', $keyword);
}
if ((int) $count === 1) {
$count = $model->count();
}
if ($count != -100) {
$model->limit($this->request->offset() ,$this->request->size());
}
$data = $model->all()->toArray();
return JSON::to(0, $data, $count);
}
';
}
private function getData($fields): string
{
$html = '';
$length = $this->getMaxLength($fields);
foreach ($fields as $key => $val) {
preg_match('/\((\d+)(,(\d+))*\)/', $val['Type'], $number);
$type = strtolower(preg_replace('/\(\d+(,\d+)*\)/', '', $val['Type']));
$first = preg_replace('/\s+\w+/', '', $type);
if ($val['Field'] == 'id') continue;
if ($type == 'timestamp') continue;
$_field = [];
$_field['required'] = $this->checkIsRequired($val);
foreach ($this->type as $_key => $value) {
if (!in_array(strtolower($first), $value)) continue;
$comment = '//' . $val['Comment'];
$_field['type'] = $_key;
if ($type == 'date' || $type == 'datetime' || $type == 'time') {
$_tps = match ($type) {
'date' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d\'))',
'time' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'H:i:s\'))',
default => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d H:i:s\'))',
};
$html .= '
\'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment;
} else {
$tmp = 'null';
if (isset($number[0])) {
if (strpos(',', $number[0])) {
$tmp = '[' . $number[1] . ',' . $number[3] . ']';
$_field['min'] = $number[1];
$_field['max'] = $number[3];
} else {
$tmp = '[0,' . $number[1] . ']';
$_field['min'] = 0;
$_field['max'] = $number[1];
}
}
if ($key == 'string') {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . $tmp . ')';
} else if ($type == 'int') {
if ($number[0] == 10) {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())';
} else {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
}
} else if ($type == 'float') {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . ($number[3] ?? '2') . ')';
} else if ($key == 'email') {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
} else if ($key == 'timestamp') {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())';
} else {
$_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')';
}
$html .= '
\'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment;
}
}
$this->rules[$val['Field']] = $_field;
}
return $html;
}
/**
* @param $fields
* @return int
*/
private function getMaxLength($fields): int
{
$length = 0;
foreach ($fields as $key => $val) {
if (mb_strlen($val['Field'] . ' >=') > $length) $length = mb_strlen($val['Field'] . ' >=');
}
return $length;
}
/**
* @param $fields
* @return string
*/
private function getWhere($fields): string
{
$html = '';
$length = $this->getMaxLength($fields);
foreach ($fields as $key => $val) {
preg_match('/\d+/', $val['Type'], $number);
$type = strtolower(preg_replace('/\(\d+\)/', '', $val['Type']));
$first = preg_replace('/\s+\w+/', '', $type);
if ($type == 'timestamp') continue;
if ($type == 'json') continue;
foreach ($this->type as $_key => $value) {
if (!in_array(strtolower($first), $value)) continue;
$comment = '//' . $val['Comment'];
if ($type == 'date' || $type == 'datetime' || $type == 'time') {
$_tps = '$this->request->query(\'' . $val['Field'] . '\', null)';
$html .= '
$pWhere[\'' . str_pad($val['Field'] . ' <=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
$html .= '
$pWhere[\'' . str_pad($val['Field'] . ' >=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
} else {
$_tps = '$this->request->query(\'' . $val['Field'] . '\', null)';
$html .= '
$pWhere[\'' . str_pad($val['Field'] . '\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment;
}
}
}
return $html;
}
}
-113
View File
@@ -1,113 +0,0 @@
<?php
namespace Gii;
class GiiJsonRpc extends GiiBase
{
/**
* @return array
*/
public function create(): array
{
return [
$this->createInterface($this->input->getArgument('name')),
$this->createProducers($this->input->getArgument('name')),
$this->createConsumer($this->input->getArgument('name')),
];
}
private function createInterface($name): string
{
$html = '<?php
namespace Rpc;
interface ' . ucfirst($name) . 'RpcInterface
{
}';
$name = ucfirst($name) . 'RpcInterface.php';
if (!is_dir(APP_PATH . '/rpc/')) {
mkdir(APP_PATH . '/rpc/');
}
file_put_contents(APP_PATH . '/rpc/' . $name, $html);
return $name;
}
private function createProducers($name): string
{
$html = '<?php
namespace Rpc\Producers;
use Kiri\Annotation\Target;
use Kiri\Annotation\Mapping;
use Rpc\\' . ucfirst($name) . 'RpcInterface;
use Exception;
use Kiri\Rpc\JsonRpcConsumers;
#[Target]
#[Mapping(' . ucfirst($name) . 'RpcInterface::class)]
class ' . ucfirst($name) . 'RpcService extends JsonRpcConsumers implements ' . ucfirst($name) . 'RpcInterface
{
protected string $name = \'' . $name . '\';
}';
$name = ucfirst($name) . 'RpcService.php';
if (!is_dir(APP_PATH . '/rpc/Producers/')) {
mkdir(APP_PATH . '/rpc/Producers/');
}
file_put_contents(APP_PATH . '/rpc/Producers/' . $name, $html);
return $name;
}
private function createConsumer($name): string
{
$html = '<?php
namespace Rpc\Consumers;
use Kiri\Annotation\Target;
use Kiri\Rpc\Annotation\JsonRpc;
use Kiri\Message\Handler\Controller;
use Rpc\\' . ucfirst($name) . 'RpcInterface;
#[Target]
#[JsonRpc(service: \'' . $name . '\', version: \'2.0\')]
class ' . ucfirst($name) . 'RpcConsumer extends Controller implements ' . ucfirst($name) . 'RpcInterface
{
}';
$name = ucfirst($name) . 'RpcConsumer.php';
if (!is_dir(APP_PATH . '/rpc/Consumers/')) {
mkdir(APP_PATH . '/rpc/Consumers/');
}
file_put_contents(APP_PATH . '/rpc/Consumers/' . $name, $html);
return $name;
}
}
-72
View File
@@ -1,72 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Exception;
use Kiri;
/**
* Class GiiMiddleware
* @package Gii
*/
class GiiMiddleware extends GiiBase
{
/**
* @return array
* @throws Exception
*/
public function generate(): array
{
$managerName = $this->input->getArgument('name');
if (empty($managerName)) {
throw new Exception('文件名称不能为空~');
}
$html = '<?php
namespace App\Middleware;
use Closure;
use Psr\Http\Server\MiddlewareInterface;
use Kiri\Server\Constrict\RequestInterface;
';
$managerName = ucfirst($managerName);
$html .= '
/**
* Class ' . $managerName . 'Middleware
* @package App\Middleware
*/
class ' . $managerName . 'Middleware implements Middleware
{
/**
* @param Request $request
* @param Closure $closure
* @return mixed
*/
public function handler(RequestInterface $request, Closure $closure)
{
return $closure($request);
}
}';
$file = APP_PATH . 'app/Http/Middleware/' . $managerName . 'Middleware.php';
if (file_exists($file)) {
throw new Exception('File exists.');
}
Kiri::writeFile($file, $html);
return [$managerName . 'Middleware.php'];
}
}
-426
View File
@@ -1,426 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Database\Db;
use Database\Model;
use Exception;
use ReflectionException;
use Kiri;
/**
* Class GiiModel
* @package Gii
*/
class GiiModel extends GiiBase
{
public ?string $classFileName;
public ?array $visible;
public ?array $res;
public ?array $fields;
/**
* GiiModel constructor.
* @param string $classFileName
* @param string $tableName
* @param array $visible
* @param array $res
* @param array $fields
*/
public function __construct(string $classFileName, string $tableName, array $visible, array $res, array $fields)
{
$this->classFileName = $classFileName;
$this->tableName = $tableName;
$this->visible = $visible;
$this->res = $res;
$this->fields = $fields;
}
/**
* @throws ReflectionException
* @throws Exception
*/
public function generate(): string
{
$class = '';
$modelPath = $this->getModelPath();
$managerName = $this->classFileName;
$namespace = rtrim($modelPath['namespace'], '\\');
if (file_exists($modelPath['path'] . '/' . $managerName . '.php')) {
try {
$className = str_replace('\\\\', '\\', "{$modelPath['namespace']}\\{$managerName}");
$class = Kiri::getDi()->getReflect($className);
$html = '<?php
namespace ' . $namespace . ';
';
$imports = $this->getImports($modelPath['path'] . '/' . $managerName . '.php', $class);
if (!empty($imports)) {
$html .= $imports . PHP_EOL;
}
if (!str_contains($imports, 'Database\Annotation\Set')) {
$html .= 'use Database\Annotation\Set;' . PHP_EOL;
}
if (!str_contains($imports, 'Database\Annotation\Get')) {
$html .= 'use Database\Annotation\Get;' . PHP_EOL;
}
} catch (\Throwable $e) {
logger()->addError($e, 'throwable');
}
}
if (empty($html)) {
$html = '<?php
namespace ' . $namespace . ';
use Exception;
use Kiri\Annotation\Target;
use Kiri\Core\Json;
use Database\Connection;
use Database\Annotation\Get;
use Database\Annotation\Set;
use Database\Relation;
use Database\Model;
' . PHP_EOL;
}
$createSql = $this->setCreateSql($this->tableName);
if (!str_contains($html, $createSql)) {
$html .= '
' . $this->setCreateSql($this->tableName);
}
$html .= '
/**
* Class ' . $managerName . '
* @package Inter\mysql
*' . implode('', $this->visible) . '
*/
#[Target] class ' . $managerName . ' extends Model
{
';
if (!empty($class)) {
$html .= $this->getClassProperty($class);
}
$primary = $this->createPrimary($this->fields);
if (!empty($primary)) {
$html .= $primary . "\n";
}
$html .= $this->createTableName($this->tableName) . "\n";
$html .= $this->createDatabaseSource();
$html .= $this->createRules($this->fields);
if (is_object($class)) {
$html .= $this->getClassMethods($class, ['rules', 'tableName', 'attributes', 'getDb']);
} else {
$other = $this->generate_json_function($html, $this->fields);
if (!empty($other)) {
$html .= implode($other);
}
}
$html .= '
}';
$file = rtrim($modelPath['path'], '/') . '/' . $managerName . '.php';
if (file_exists($file)) {
unlink($file);
}
Kiri::writeFile($file, $html);
return $managerName . '.php';
}
/**
* @param $html
* @param $fields
* @return array
*/
private function generate_json_function($html, $fields): array
{
$strings = [];
foreach ($fields as $field) {
if ($field['Type'] === 'json') {
$function = '
/**
* @param $value
* @return int|bool|string
* @throws Exception
*/
#[Set(\'' . $field['Field'] . '\')]
public function set' . ucfirst($field['Field']) . 'Attribute($value): int|bool|string
{
if ( !is_string($value) ) {
return JSON::encode($value);
}
return $value;
}
';
$get_function = '
/**
* @param $value
* @return array|null|bool
*/
#[Get(\'' . $field['Field'] . '\')]
public function get' . ucfirst($field['Field']) . 'Attribute($value): array|null|bool
{
$value = stripcslashes($value);
if ( is_string($value) ) {
return JSON::decode($value, true);
}
return $value;
}
';
if (!str_contains($html, 'set' . ucfirst($field['Field']) . 'Attribute')) {
$strings[] = $function;
}
if (!str_contains($html, 'get' . ucfirst($field['Field']) . 'Attribute')) {
$strings[] = $get_function;
}
}
}
return $strings;
}
/**
* @param $field
* @return string
* 创建表名称
*/
private function createTableName($field): string
{
$prefixed = $this->db->tablePrefix;
if (!empty($prefixed)) {
if (str_starts_with($field, $prefixed)) {
$field = str_replace($prefixed, '', $field);
}
}
return '
/**
* @inheritdoc
*/
protected string $table = \'' . $field . '\';
';
}
/**
* @param $fields
* @return string
* 创建效验规则
*/
private function createRules($fields): string
{
$data = [];
foreach ($fields as $key => $val) {
if ($val['Extra'] == 'auto_increment') continue;
$type = preg_replace('/\(.*?\)|\s+\w+/', '', $val['Type']);
foreach ($this->type as $_key => $_val) {
if (in_array($type, $_val)) {
$type = lcfirst(str_replace('get', '', $_key));
break;
}
}
$data[$type][] = $val;
}
$_field_one = '';
$required = $this->getRequired($fields);
if (!empty($required)) {
$_field_one .= $required;
}
foreach ($data as $key => $val) {
$field = '[\'' . implode('\', \'', array_column($val, 'Field')) . '\']';
if (count($val) == 1) {
$field = '\'' . current($val)['Field'] . '\'';
}
$_field_one .= '
[' . $field . ', \'' . $key . '\'],';
}
foreach ($data as $key => $val) {
$length = $this->getLength($val);
if (!empty($length)) {
$_field_one .= $length . ',';
}
}
$required = $this->getUnique($fields);
if (!empty($required)) {
$_field_one .= $required;
}
return '
/**
* @return array
*/
public function rules(): array
{
return [' . $_field_one . '
];
}
';
}
/**
* @param $val
* @return string
*/
public function getLength($val): string
{
$data = [];
foreach ($val as $key => $_val) {
$preg = preg_match('/(\w+)\((.*?)\)/', $_val['Type'], $results);
if ($preg && isset($results[2])) {
$results[] = $_val['Field'];
$data[$results[2]][] = $results;
}
}
if (empty($data)) return '';
$string = [];
foreach ($data as $key => $_val) {
if (in_array($_val[0][1], $this->type['float'])) {
$e_x = explode(',', $key);
$key = '\'round\' => ' . $e_x[1] . ', \'maxLength\' => ' . ((int)$e_x[0] + 1);
} else if (is_string($key) && str_contains($key, ',')) {
} else {
$key = '\'maxLength\' => ' . $key;
}
if (count($_val) == 1) {
$_tmp = '
[\'' . $_val[0][3] . '\', ' . ($_val[0][1] == 'enum' ? '\'enum\' => [' . $key .']' : $key) . ']';
} else {
$_tmp = '
[[\'' . implode('\', \'', array_column($_val, 3)) . '\'], ' . $key . ']';
}
$string[] = $_tmp;
}
return implode(',', $string);
}
/**
* @param $fields
* @return string
*/
public function getUnique($fields): string
{
$data = [];
foreach ($fields as $_val) {
if ($_val['Extra'] == 'auto_increment') continue;
if (str_contains($_val['Type'], 'unique')) {
$data[] = $_val['Field'];
}
}
if (empty($data)) {
return '';
}
return '
[[\'' . implode('\', \'', $data) . '\'], \'unique\'],';
}
/**
* @param $val
* @return string
*/
public function getRequired($val): string
{
$data = [];
foreach ($val as $_key => $_val) {
if ($_val['Extra'] == 'auto_increment') continue;
if ($_val['Key'] == 'PRI' || $_val['Key'] == 'UNI' || $this->checkIsRequired($_val) === 'true') {
array_push($data, $_val['Field']);
}
}
if (empty($data)) {
return '';
}
return '
[[\'' . implode('\', \'', $data) . '\'], \'required\'],';
}
/**
* 用来生成文档的
* 格式
* @param $fields
* @return null|string
* array(
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释',
* )
*/
private function createPrimary($fields): ?string
{
$field = $this->getPrimaryKey($fields);
if (empty($field)) {
return null;
}
return '
/**
* @var string|null
*/
protected ?string $primary = \'' . $field . '\';';
}
/**
* @return string
*/
private function createDatabaseSource(): string
{
return '
/**
* @var string
*/
protected string $connection = \'' . $this->db->id . '\';
';
}
/**
* @param $table
* @return string
* @throws Exception
*/
private function setCreateSql($table): string
{
if (isset(Gii::$createSqls[$table])) {
return Gii::$createSqls[$table];
}
$text = Db::showCreateSql($table, $this->db)['Create Table'] ?? '';
$_tmp = [];
foreach (explode(PHP_EOL, $text) as $val) {
$_tmp[] = '// ' . $val;
}
return Gii::$createSqls[$table] = implode(PHP_EOL, $_tmp);
}
}
-34
View File
@@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Exception;
use Kiri\Abstracts\Providers;
use Kiri\Application;
use Kiri;
/**
* Class DatabasesProviders
* @package Database
*/
class GiiProviders extends Providers
{
/**
* @param Application $application
* @throws Exception
*/
public function onImport(Application $application)
{
$application->set('gii', ['class' => Gii::class]);
$container = Kiri::getDi();
$console = $container->get(\Symfony\Component\Console\Application::class);
$console->add($container->get(GiiCommand::class));
}
}
-99
View File
@@ -1,99 +0,0 @@
<?php
namespace Gii;
use Exception;
use Kiri;
/**
* Class GiiRpcClient
* @package Gii
*/
class GiiRpcClient extends GiiBase
{
/**
* @return array
* @throws Exception
*/
public function generate(): array
{
$managerName = $this->input->getArgument('name', null);
if (empty($managerName)) {
throw new Exception('文件名称不能为空~');
}
$service = $this->input->getArgument('service', strtolower($managerName));
$port = $this->input->getArgument('port', 443);
$mode = $this->input->getArgument('mode', 'SWOOLE_SOCK_TCP');
$html = '<?php
namespace App\Client\Rpc;
use Kiri\Annotation\Rpc\Consumer;
use Kiri\Annotation\Rpc\RpcClient;
use Kiri\Annotation\Target;
use Exception;
use Rpc\Client;
use Kiri\Core\Json;
use Kiri;
';
$managerName = ucfirst($managerName);
$html .= '
/**
* Class ' . $managerName . 'Consumer
* @package App\Client\Rpc
*/
#[Target]
#[RpcClient(cmd: \'' . $service . '\', port: ' . $port . ', timeout: 1, mode: ' . $mode . ')]
class ' . $managerName . 'Consumer extends \Rpc\Consumer
{
public array $node = [\'host\' => \'127.0.0.1\', \'port\' => 5377];
/**
* @return Client
* @throws Exception
*/
public function initClient(): Client
{
// TODO: Implement initClient() method.
return $this->client = $this->rpc->getClient(\'' . $service . '\');
}
/**
* @param string $event
* @param array $params
* @throws Exception
*/
#[Consumer(\'default\')]
public function push(string $event, array $params)
{
}
}';
if (!is_dir(APP_PATH . 'app/Client/Rpc/')) {
mkdir(APP_PATH . 'app/Client/Rpc/', 0777, true);
}
$file = APP_PATH . 'app/Client/Rpc/' . $managerName . 'Middleware.php';
if (file_exists($file)) {
throw new Exception('File exists.');
}
Kiri::writeFile($file, $html);
return [$managerName . 'Middleware.php'];
}
}

Some files were not shown because too many files have changed in this diff Show More