Compare commits

..

774 Commits

Author SHA1 Message Date
as2252258 76351fbe66 eee 2026-06-24 20:11:12 +08:00
as2252258 8479106b9f eee 2026-06-12 23:57:25 +08:00
as2252258 ca8cc081bc Merge remote-tracking branch 'origin/master' 2026-04-17 14:11:05 +08:00
as2252258 a31c24ddf3 eee 2026-04-17 14:10:48 +08:00
as2252258 826503f4e6 add println function
Signed-off-by: 向林 <as2252258@163.com>
2026-01-08 08:26:08 +00:00
as2252258 eeb348c053 eee 2026-01-02 04:51:16 +08:00
as2252258 168954e4c4 update composer.json.
xx

Signed-off-by: 向林 <as2252258@163.com>
2025-12-31 06:59:26 +00:00
as2252258 6a27fa3b74 eee 2025-12-31 01:50:09 +08:00
as2252258 79d4f47a67 eee 2025-12-31 01:16:00 +08:00
as2252258 e6786666b7 eee 2025-12-31 00:50:04 +08:00
as2252258 b5c18fc074 eee 2025-12-31 00:43:25 +08:00
as2252258 86b9c46755 eee 2025-12-31 00:40:05 +08:00
as2252258 baea90e9e5 eee 2025-12-31 00:19:31 +08:00
as2252258 87e7535f27 eee 2025-12-23 20:24:00 +08:00
as2252258 cc073f13c2 update composer.json.
xxx

Signed-off-by: 向林 <as2252258@163.com>
2025-12-23 02:26:34 +00:00
as2252258 3afb1bd514 eee 2025-12-22 23:42:04 +08:00
as2252258 0e7d429bfc Merge remote-tracking branch 'origin/master' 2025-12-22 23:06:51 +08:00
as2252258 526aa9a63d eee 2025-12-22 23:06:36 +08:00
as2252258 48db719890 !1 Add README.md
Merge pull request !1 from gitee-agent/N/A
2025-12-22 14:31:18 +00:00
gitee-bot daa8311eb9 Add README.md 2025-12-22 13:38:31 +00:00
as2252258 a065e5da49 eee 2025-12-19 17:09:36 +08:00
as2252258 8ae2af7dd6 eee 2025-12-18 23:29:55 +08:00
as2252258 6f0376ac44 eee 2025-12-18 22:56:20 +08:00
as2252258 08a4d6af4e eee 2025-12-18 22:56:08 +08:00
as2252258 9899578d52 eee 2025-12-18 22:53:28 +08:00
as2252258 f97df5cfe5 eee 2025-12-18 22:35:21 +08:00
as2252258 34f8f6f523 eee 2025-12-18 21:30:00 +08:00
as2252258 f6f94aff32 eee 2025-12-18 15:39:47 +08:00
as2252258 377a9c17c3 eee 2025-12-18 15:03:43 +08:00
as2252258 174d2f1659 eee 2025-12-16 20:20:09 +08:00
as2252258 d6c8380c64 eee 2025-12-01 06:39:05 +08:00
as2252258 2e54326aba eee 2025-07-16 09:17:03 +08:00
as2252258 59632ac4a3 eee 2025-07-16 09:09:56 +08:00
as2252258 da5a6a6b83 eee 2025-07-14 18:12:17 +08:00
as2252258 d758d21f08 eee 2025-07-11 17:44:34 +08:00
as2252258 c59212da78 eee 2025-07-11 17:32:17 +08:00
as2252258 9ce0cb96bf eee 2025-07-11 16:27:14 +08:00
as2252258 c7b5d5fb59 eee 2025-01-18 20:45:37 +08:00
as2252258 daa89f3794 eee 2024-11-28 14:35:20 +08:00
as2252258 60670f7f97 eee 2024-11-18 11:24:08 +08:00
as2252258 3a0c5f6d70 eee 2024-11-15 14:30:18 +08:00
as2252258 ef312c2aa4 eee 2024-11-15 14:24:19 +08:00
as2252258 a0eb46cf4e eee 2024-09-23 16:16:01 +08:00
as2252258 fbd3799081 eee 2024-09-12 09:06:02 +08:00
as2252258 97a3335217 eee 2024-09-11 15:22:25 +08:00
as2252258 1790d01730 eee 2024-09-11 11:10:15 +08:00
as2252258 8a4b62b2d8 eee 2024-09-11 11:09:26 +08:00
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
as2252258 ca274a3910 Revert "改名"
This reverts commit fdf58326
2022-02-10 11:37:54 +08:00
as2252258 4d6f7d1d13 Revert "改名"
This reverts commit fdf58326
2022-02-03 14:54:38 +08:00
as2252258 8296cda1f2 Revert "改名"
This reverts commit fdf58326
2022-01-25 15:50:17 +08:00
as2252258 3bb14c5acb Revert "改名"
This reverts commit fdf58326
2022-01-25 15:49:48 +08:00
as2252258 b5bfff66dd 1 2022-01-25 02:00:42 +08:00
as2252258 adb2269df0 Revert "改名"
This reverts commit fdf58326
2022-01-20 19:05:57 +08:00
as2252258 b557f15a98 Revert "改名"
This reverts commit fdf58326
2022-01-20 19:04:16 +08:00
as2252258 862acf1db1 Revert "改名"
This reverts commit fdf58326
2022-01-18 16:01:02 +08:00
as2252258 a2272edc76 Revert "改名"
This reverts commit fdf58326
2022-01-18 10:29:32 +08:00
as2252258 555d653288 Revert "改名"
This reverts commit fdf58326
2022-01-18 10:18:13 +08:00
as2252258 45cf88e52c Revert "改名"
This reverts commit fdf58326
2022-01-17 19:04:26 +08:00
as2252258 a8f840bfb2 Revert "改名"
This reverts commit fdf58326
2022-01-17 18:48:57 +08:00
as2252258 d8222366b1 Revert "改名"
This reverts commit fdf58326
2022-01-17 18:45:00 +08:00
as2252258 fbe13eaa7e Revert "改名"
This reverts commit fdf58326
2022-01-17 14:04:37 +08:00
as2252258 466df3387f Revert "改名"
This reverts commit fdf58326
2022-01-17 10:59:55 +08:00
as2252258 fa76b5170a Revert "改名"
This reverts commit fdf58326
2022-01-15 10:23:57 +08:00
as2252258 b0c66c9c6a Revert "改名"
This reverts commit fdf58326
2022-01-14 16:50:01 +08:00
as2252258 2ffdf83645 Revert "改名"
This reverts commit fdf58326
2022-01-14 16:05:12 +08:00
as2252258 c3a3551ba3 Revert "改名"
This reverts commit fdf58326
2022-01-14 15:52:38 +08:00
as2252258 829c063700 Revert "改名"
This reverts commit fdf58326
2022-01-14 14:54:13 +08:00
as2252258 eaf251ac53 Revert "改名"
This reverts commit fdf58326
2022-01-14 14:45:03 +08:00
as2252258 776cc80495 Revert "改名"
This reverts commit fdf58326
2022-01-14 14:43:04 +08:00
as2252258 103cc96103 Revert "改名"
This reverts commit fdf58326
2022-01-14 14:19:52 +08:00
as2252258 f2da99efce Revert "改名"
This reverts commit fdf58326
2022-01-14 14:18:29 +08:00
as2252258 49d0ba7b3c Revert "改名"
This reverts commit fdf58326
2022-01-14 11:43:02 +08:00
as2252258 a6ed92206e Revert "改名"
This reverts commit fdf58326
2022-01-14 11:41:30 +08:00
as2252258 bb9b9dbcd2 Revert "改名"
This reverts commit fdf58326
2022-01-14 11:40:20 +08:00
as2252258 9782147a47 Revert "改名"
This reverts commit fdf58326
2022-01-14 11:39:52 +08:00
as2252258 7598bdbd63 Revert "改名"
This reverts commit fdf58326
2022-01-14 11:38:28 +08:00
as2252258 a569bd6897 Revert "改名"
This reverts commit fdf58326
2022-01-14 11:29:16 +08:00
as2252258 ffeef3ff4b Revert "改名"
This reverts commit fdf58326
2022-01-13 18:48:13 +08:00
as2252258 7f6a0c01e0 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:41:16 +08:00
as2252258 32f9ebc2a2 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:39:39 +08:00
as2252258 f35ffe6ff1 Revert "改名"
This reverts commit fdf58326
2022-01-13 18:33:04 +08:00
as2252258 9a76ee0184 Revert "改名"
This reverts commit fdf58326
2022-01-13 10:15:04 +08:00
as2252258 249f9b1c6f Revert "改名"
This reverts commit fdf58326
2022-01-12 18:52:13 +08:00
as2252258 1df2d43b8b Revert "改名"
This reverts commit fdf58326
2022-01-12 18:50:48 +08:00
as2252258 2daac841a3 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:49:57 +08:00
as2252258 28cd946219 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:30:28 +08:00
as2252258 70015f7ab8 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:29:49 +08:00
as2252258 a467056c86 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:28:51 +08:00
as2252258 a2a3f0fc40 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:27:49 +08:00
as2252258 cfbebeb951 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:26:54 +08:00
as2252258 94851c3f51 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:22:53 +08:00
as2252258 1896dc90b4 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:14:15 +08:00
as2252258 6168adb401 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:12:56 +08:00
as2252258 5e742e7196 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:09:49 +08:00
as2252258 4605fc9162 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:08:28 +08:00
as2252258 54f19fb058 Revert "改名"
This reverts commit fdf58326
2022-01-12 18:05:49 +08:00
as2252258 a9165b601a Revert "改名"
This reverts commit fdf58326
2022-01-12 18:03:09 +08:00
as2252258 5b35c4de4a Revert "改名"
This reverts commit fdf58326
2022-01-12 18:02:45 +08:00
as2252258 8b6aff5c7b Revert "改名"
This reverts commit fdf58326
2022-01-12 18:01:55 +08:00
as2252258 1d3b45e2c3 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:58:01 +08:00
as2252258 f2ad97c7f0 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:55:25 +08:00
as2252258 19b3f0f1e9 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:54:18 +08:00
as2252258 ebd643772d Revert "改名"
This reverts commit fdf58326
2022-01-12 17:53:27 +08:00
as2252258 08d9551245 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:52:18 +08:00
as2252258 59eec80939 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:46:16 +08:00
as2252258 241385b575 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:39:11 +08:00
as2252258 73ce2b8a50 Revert "改名"
This reverts commit fdf58326
2022-01-12 17:38:25 +08:00
as2252258 6f80b2fe6a Revert "改名"
This reverts commit fdf58326
2022-01-12 17:17:47 +08:00
as2252258 8955891c2f Revert "改名"
This reverts commit fdf58326
2022-01-12 16:01:55 +08:00
as2252258 035138a779 Revert "改名"
This reverts commit fdf58326
2022-01-12 16:00:11 +08:00
as2252258 c6e6c8d68d Revert "改名"
This reverts commit fdf58326
2022-01-12 15:47:28 +08:00
as2252258 6a30fdfa8d Revert "改名"
This reverts commit fdf58326
2022-01-12 15:08:22 +08:00
as2252258 367e1cd122 Revert "改名"
This reverts commit fdf58326
2022-01-12 15:07:40 +08:00
as2252258 667d311d73 Revert "改名"
This reverts commit fdf58326
2022-01-12 14:52:01 +08:00
as2252258 375f396467 Revert "改名"
This reverts commit fdf58326
2022-01-12 14:43:28 +08:00
as2252258 7b1cc1bd7b Revert "改名"
This reverts commit fdf58326
2022-01-12 14:10:33 +08:00
as2252258 1ae1d78ddf Revert "改名"
This reverts commit fdf58326
2022-01-12 11:52:59 +08:00
as2252258 00212d133d Revert "改名"
This reverts commit fdf58326
2022-01-12 11:39:17 +08:00
as2252258 7fbe9fbf44 Revert "改名"
This reverts commit fdf58326
2022-01-12 11:20:34 +08:00
as2252258 de1aff9efd Revert "改名"
This reverts commit fdf58326
2022-01-11 16:17:25 +08:00
as2252258 cef09a11ef Revert "改名"
This reverts commit fdf58326
2022-01-11 16:16:05 +08:00
as2252258 7122018a2a Revert "改名"
This reverts commit fdf58326
2022-01-11 15:53:31 +08:00
as2252258 f8763953c5 Revert "改名"
This reverts commit fdf58326
2022-01-11 15:48:12 +08:00
as2252258 22560d77d6 Revert "改名"
This reverts commit fdf58326
2022-01-10 11:39:56 +08:00
as2252258 483c898f51 1 2022-01-10 02:13:11 +08:00
as2252258 1fa651c587 1 2022-01-10 02:10:37 +08:00
as2252258 f7ca56a9b0 1 2022-01-09 17:56:47 +08:00
as2252258 4fa5c23c10 1 2022-01-09 16:07:58 +08:00
as2252258 f46af653f2 1 2022-01-09 14:33:33 +08:00
as2252258 5e02a79bf0 e 2022-01-09 03:50:38 +08:00
as2252258 08dc3e262b 1 2022-01-09 03:46:42 +08:00
as2252258 8c5e52940f 1 2022-01-09 02:44:09 +08:00
as2252258 4dbcacdd1f Revert "改名"
This reverts commit fdf58326
2022-01-08 19:11:23 +08:00
as2252258 97cd1a0ebf Revert "改名"
This reverts commit fdf58326
2022-01-08 18:49:08 +08:00
as2252258 7165a67294 Revert "改名"
This reverts commit fdf58326
2022-01-08 18:10:52 +08:00
as2252258 4bc7451424 Revert "改名"
This reverts commit fdf58326
2022-01-08 18:10:41 +08:00
as2252258 d7d0f685dc Revert "改名"
This reverts commit fdf58326
2022-01-08 10:07:19 +08:00
as2252258 8ee7d30d6a Revert "改名"
This reverts commit fdf58326
2022-01-07 19:01:00 +08:00
as2252258 224009e7e6 Revert "改名"
This reverts commit fdf58326
2022-01-07 19:00:45 +08:00
as2252258 b4551ae2fd Revert "改名"
This reverts commit fdf58326
2022-01-07 18:16:30 +08:00
as2252258 5ca94925e3 Revert "改名"
This reverts commit fdf58326
2022-01-07 18:05:17 +08:00
as2252258 0afa8fc400 Revert "改名"
This reverts commit fdf58326
2022-01-07 17:59:37 +08:00
as2252258 842220e4de Revert "改名"
This reverts commit fdf58326
2022-01-07 17:57:27 +08:00
as2252258 c9726e5778 Revert "改名"
This reverts commit fdf58326
2022-01-07 14:38:36 +08:00
as2252258 f867f4be9e Revert "改名"
This reverts commit fdf58326
2022-01-06 19:05:15 +08:00
as2252258 45319c3733 Revert "改名"
This reverts commit fdf58326
2022-01-04 17:27:37 +08:00
as2252258 06c9459f14 Revert "改名"
This reverts commit fdf58326
2022-01-04 16:25:03 +08:00
as2252258 5fd2abcb69 Revert "改名"
This reverts commit fdf58326
2022-01-04 16:22:37 +08:00
as2252258 58a3d91df3 Merge remote-tracking branch 'origin/master' 2022-01-04 16:05:08 +08:00
as2252258 c61842402a Revert "改名"
This reverts commit fdf58326
2022-01-04 16:04:22 +08:00
as2252258 623bae9e97 1 2022-01-04 00:07:26 +08:00
as2252258 12610c218c 1 2022-01-04 00:07:14 +08:00
as2252258 c3ca24884e Revert "改名"
This reverts commit fdf58326
2021-12-31 16:47:17 +08:00
as2252258 02c14874a2 Revert "改名"
This reverts commit fdf58326
2021-12-31 16:46:13 +08:00
as2252258 6eff48e22f Revert "改名"
This reverts commit fdf58326
2021-12-30 18:10:51 +08:00
as2252258 6c46a54d4b Revert "改名"
This reverts commit fdf58326
2021-12-28 17:54:51 +08:00
as2252258 03287cfd65 Revert "改名"
This reverts commit fdf58326
2021-12-28 14:16:45 +08:00
as2252258 93ce4c16b6 Revert "改名"
This reverts commit fdf58326
2021-12-27 15:24:29 +08:00
as2252258 4b92edd40f 1 2021-12-24 01:19:43 +08:00
as2252258 a76c81df8e 改名 2021-12-23 18:36:14 +08:00
as2252258 aa59caad07 改名 2021-12-23 18:22:27 +08:00
as2252258 6fd8a5dd34 1 2021-12-22 03:29:27 +08:00
as2252258 9ca53a73ce 1 2021-12-22 03:29:14 +08:00
as2252258 d904e78864 1 2021-12-18 03:27:14 +08:00
as2252258 0d64ef7ac4 1 2021-12-17 04:57:46 +08:00
as2252258 154d9d74d6 1 2021-12-17 04:43:20 +08:00
as2252258 2c61abff01 1 2021-12-17 04:41:00 +08:00
as2252258 b4ce762cf3 1 2021-12-17 04:26:54 +08:00
as2252258 4b3c2234af 1 2021-12-17 04:24:40 +08:00
as2252258 7ee78a9642 1 2021-12-17 04:24:01 +08:00
as2252258 f9838f781d 1 2021-12-17 04:23:12 +08:00
as2252258 848416af4f 1 2021-12-17 04:22:13 +08:00
as2252258 0216e761be 1 2021-12-17 04:17:53 +08:00
as2252258 acf6631c5c 1 2021-12-17 04:15:59 +08:00
as2252258 64e4307a57 1 2021-12-12 06:37:52 +08:00
as2252258 ab672127e6 1 2021-12-12 02:46:30 +08:00
as2252258 6e5b545a1e 1 2021-12-12 02:45:39 +08:00
as2252258 8229395e6d 1 2021-12-12 02:41:31 +08:00
as2252258 d5d2b04321 1 2021-12-11 17:56:35 +08:00
as2252258 ce9c184c83 1 2021-12-11 17:40:16 +08:00
as2252258 620de34559 1 2021-12-11 17:38:53 +08:00
as2252258 b01c71ea5e 1 2021-12-11 17:38:15 +08:00
as2252258 90e1f7eb29 1 2021-12-11 17:35:44 +08:00
as2252258 f3ad09ef66 1 2021-12-11 17:34:05 +08:00
as2252258 dfccb8816c 1 2021-12-11 17:32:28 +08:00
as2252258 1670ff3fef 1 2021-12-11 05:33:46 +08:00
as2252258 8870a7ca27 1 2021-12-11 05:33:00 +08:00
as2252258 ebb7ac9673 改名 2021-12-09 17:01:18 +08:00
as2252258 5aad8d2001 改名 2021-12-08 11:45:19 +08:00
as2252258 80713788c9 改名 2021-12-08 11:39:57 +08:00
as2252258 9f36acbbca 改名 2021-12-08 11:32:32 +08:00
as2252258 044d213a69 改名 2021-12-07 16:44:12 +08:00
as2252258 e5fe525f82 改名 2021-12-07 16:02:07 +08:00
as2252258 39e4e52908 改名 2021-12-07 16:00:52 +08:00
as2252258 f62014ff34 改名 2021-12-07 15:59:13 +08:00
as2252258 7935e6a6a3 改名 2021-12-07 15:53:56 +08:00
as2252258 d2acd50352 改名 2021-12-06 18:07:33 +08:00
as2252258 d02337ec22 改名 2021-12-06 17:58:11 +08:00
as2252258 57f12b6701 改名 2021-12-06 17:22:26 +08:00
as2252258 d500fd21ce 改名 2021-12-06 16:14:48 +08:00
as2252258 30d7b8684e 改名 2021-12-06 16:13:52 +08:00
as2252258 d8eb4d4e45 改名 2021-12-06 16:03:39 +08:00
as2252258 7004c5c0f8 改名 2021-12-06 15:54:31 +08:00
as2252258 81e55ecdf1 改名 2021-12-06 15:52:05 +08:00
as2252258 20adc186d4 改名 2021-12-06 15:51:29 +08:00
as2252258 8c16d9f4b3 改名 2021-12-06 15:48:57 +08:00
as2252258 b3e06a680a 改名 2021-12-06 15:47:12 +08:00
as2252258 3176443e5c 改名 2021-12-06 15:39:35 +08:00
as2252258 83962fa3ba 改名 2021-12-06 14:49:47 +08:00
as2252258 5475f2cd51 改名 2021-12-06 14:45:12 +08:00
as2252258 30212c0b86 改名 2021-12-06 14:44:18 +08:00
as2252258 4731463897 改名 2021-12-06 14:43:46 +08:00
as2252258 87e901f5b1 改名 2021-12-06 14:42:54 +08:00
as2252258 66f87b6da4 改名 2021-12-06 14:41:05 +08:00
as2252258 0007242b70 改名 2021-12-06 14:40:18 +08:00
as2252258 8653e6914b 改名 2021-12-06 14:39:03 +08:00
as2252258 816fec8ef4 改名 2021-12-06 14:38:17 +08:00
as2252258 b0ef09fd35 改名 2021-12-06 14:38:06 +08:00
as2252258 f7a2d6f30e 改名 2021-12-06 14:32:04 +08:00
as2252258 2950ba8fd5 改名 2021-12-06 14:24:41 +08:00
as2252258 2de5c82a73 改名 2021-12-06 14:22:08 +08:00
as2252258 758c4e7d5b 改名 2021-12-06 14:12:03 +08:00
as2252258 33f045aec7 改名 2021-12-06 13:49:01 +08:00
as2252258 35189de442 改名 2021-12-06 11:44:01 +08:00
as2252258 34e7fc0392 改名 2021-12-03 18:40:27 +08:00
as2252258 a3ce9f52ba 改名 2021-12-03 18:22:26 +08:00
as2252258 6e7da1b0ed 改名 2021-12-03 17:40:21 +08:00
as2252258 a6e0b5c1a2 改名 2021-12-03 16:24:44 +08:00
as2252258 13ab14f965 改名 2021-12-03 15:42:05 +08:00
as2252258 6729094f63 改名 2021-12-03 15:35:16 +08:00
as2252258 e1aeb17a5a 改名 2021-12-03 14:46:38 +08:00
as2252258 b9e20051ef 改名 2021-12-02 14:06:57 +08:00
as2252258 4ab6332176 改名 2021-12-01 19:05:10 +08:00
as2252258 abe2dad521 改名 2021-12-01 19:05:00 +08:00
as2252258 b0f70a13da 改名 2021-12-01 15:16:08 +08:00
as2252258 1e8aca91dd 改名 2021-12-01 14:08:09 +08:00
as2252258 b4ac5c4758 改名 2021-11-30 19:04:29 +08:00
as2252258 d161477957 改名 2021-11-30 19:04:16 +08:00
as2252258 a26b99dd1e 改名 2021-11-30 18:33:22 +08:00
as2252258 86e4a92ab0 改名 2021-11-30 18:31:41 +08:00
as2252258 ea425bb82d 改名 2021-11-30 18:30:15 +08:00
as2252258 ad0154d319 改名 2021-11-30 18:29:10 +08:00
as2252258 edb70d2b9b 改名 2021-11-30 18:26:23 +08:00
as2252258 9f3355cab4 改名 2021-11-30 18:23:56 +08:00
as2252258 4107b5bb07 改名 2021-11-30 15:48:18 +08:00
as2252258 048960c572 改名 2021-11-30 15:14:42 +08:00
as2252258 b826e1f594 改名 2021-11-30 15:10:01 +08:00
as2252258 e5b57cbcdb 改名 2021-11-30 14:59:51 +08:00
as2252258 2870a64792 改名 2021-11-30 14:32:56 +08:00
as2252258 4d1587bc8d 改名 2021-11-29 14:35:09 +08:00
as2252258 24b69507b2 改名 2021-11-29 11:44:03 +08:00
as2252258 8b45c90a04 1 2021-11-28 19:37:07 +08:00
as2252258 95ae1fe999 1 2021-11-27 17:58:17 +08:00
as2252258 9668830ee2 1 2021-11-27 17:45:39 +08:00
as2252258 f26539c41f 1 2021-11-27 17:43:29 +08:00
as2252258 3ead688d5f Merge remote-tracking branch 'origin/master' 2021-11-26 11:28:37 +08:00
as2252258 157c233ed6 改名 2021-11-26 11:27:55 +08:00
as2252258 40b4c2a4c9 1 2021-11-24 23:46:26 +08:00
as2252258 a7db58d7e4 改名 2021-11-24 17:07:35 +08:00
as2252258 87e4bfdbec 改名 2021-11-24 17:07:13 +08:00
123 changed files with 5101 additions and 12172 deletions
+9 -9
View File
@@ -1,9 +1,9 @@
### 該問題是如何引起的?
### 重現步驟
### 報錯信息
### 該問題是如何引起的?
### 重現步驟
### 報錯信息
+12 -12
View File
@@ -1,12 +1,12 @@
### 該Pull Request關聯的Issue
### 修改描述
### 測試用例
### 修復效果的截屏
### 該Pull Request關聯的Issue
### 修改描述
### 測試用例
### 修復效果的截屏
+37 -37
View File
@@ -1,37 +1,37 @@
# Created by .ignore support plugin (hsz.mobi)
### Yii template
assets/*
!assets/.gitignore
protected/runtime/*
!protected/runtime/.gitignore
protected/data/*.db
themes/classic/views/
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
db/
async-queue/
composer.lock
*.log
commands/result
config/setting.php
tests/
vendor/
runtime/
*.xml
*.lock
oot
d
composer.lock
# Created by .ignore support plugin (hsz.mobi)
### Yii template
assets/*
!assets/.gitignore
protected/runtime/*
!protected/runtime/.gitignore
protected/data/*.db
themes/classic/views/
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
db/
async-queue/
composer.lock
*.log
commands/result
config/setting.php
tests/
vendor/
runtime/
*.xml
*.lock
oot
d
composer.lock
.gstack/
+22 -15
View File
@@ -1,15 +1,22 @@
<?php
namespace PHPSTORM_META {
// Reflect
use Kiri\Di\Container;
override(Container::get(0), map('@'));
override(Container::create(0), map('@'));
// override(\Hyperf\Utils\Context::get(0), map('@'));
// override(\make(0), map('@'));
override(\di(0), map('@'));
override(\duplicate(0), map('@'));
}
<?php
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(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(\di(0), map('@'));
override(\duplicate(0), map('@'));
override(ServerRequestInterface::getAttribute(0), map('@'));
}
+213
View File
@@ -0,0 +1,213 @@
<?php
declare(strict_types=1);
error_reporting(0);
use JetBrains\PhpStorm\Pure;
use Kiri\Di\Container;
use Kiri\Environmental;
use Kiri\Error\StdoutLogger;
use Swoole\Coroutine;
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 . '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]+=.*)?)?/');
/**
* Class Kiri
* @package Kiri
*/
class Kiri
{
/**
* @return Container
*/
public static function getContainer(): Container
{
return Container::instance();
}
/**
* @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));
}
}
/**
* @return \Kiri\Pool\Pool
* @throws
*/
public static function getPool(): \Kiri\Pool\Pool
{
return static::getDi()->get(\Kiri\Pool\Pool::class);
}
/**
* @param $prefix
* @return void
*/
public static function setProcessName($prefix): void
{
if (Kiri::getPlatform()->isMac()) {
return;
}
$name = '[' . \config('site.id', 'system-service') . ']';
if (!empty($prefix)) {
$name .= '.' . $prefix;
}
swoole_set_process_name($name);
}
/**
* @return string
* @throws
*/
public static function getStoragePath(): string
{
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
$path = \config('site.log.path', $default);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
return $path;
}
/**
* @return Container
*/
public static function getDi(): Container
{
return static::getContainer();
}
/**
* @return StdoutLogger
* @throws
*/
public static function getLogger(): StdoutLogger
{
return static::getContainer()->get(StdoutLogger::class);
}
/**
* @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);
}
/**
* @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 Environmental
* @throws
*/
public static function getPlatform(): Environmental
{
return Kiri::createObject(Environmental::class);
}
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;
}
}
+21 -21
View File
@@ -1,21 +1,21 @@
MIT License
Copyright (c) 2020 向林
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2020 向林
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+135
View File
@@ -0,0 +1,135 @@
# Kiri Core Framework Documentation
## Project Introduction
Kiri is a high-performance PHP-based core framework designed to provide developers with a simple and efficient development experience. The framework includes a variety of practical utility classes, exception handling mechanisms, configuration management, and a dependency injection container, making it suitable for building various types of applications.
### Key Features
- **Dependency Injection Container**: Provides powerful dependency management via `Kiri\Di\Container`.
- **Configuration Management**: Supports reading configuration from files and environment variables.
- **Exception Handling**: Offers a unified exception handling interface with support for registering custom exception handlers.
- **Logging**: Built-in `StdoutLogger` supporting multiple log levels.
- **Utility Classes**:
- `Str`: String operations such as encryption and random string generation.
- `Json`: JSON encoding/decoding and response construction.
- `Help`: Auxiliary functions including XML conversion, random number generation, and email sending.
- `DateFormat`: Date and time formatting tools.
- **Networking**: Supports local IP retrieval and Socket programming.
- **NoSQL Support**: Provides client wrappers for Redis and MongoDB with connection pool management.
## Installation
### System Requirements
- PHP 7.4 or higher
- Composer (for dependency management)
### Installation Steps
1. Ensure Composer is installed.
2. Run the following command to install dependencies:
```bash
composer install
```
## Usage Guide
### Initialize the Framework
```php
use Kiri\Kiri;
use Kiri\Application;
// Initialize the container
Kiri::setContainer(new Container());
// Create an application instance
$app = new Application(
new EventProvider(),
new ConfigProvider(),
Kiri::getContainer()
);
// Initialize the application
$app->init();
```
### Configuration Management
Configuration files can be loaded and accessed via the `ConfigProvider` class:
```php
$config = new ConfigProvider();
$databaseHost = $config->get('database.host');
```
### Dependency Injection
Use the container to inject dependencies:
```php
$service = Kiri::getContainer()->get(MyService::class);
```
### Logging
Use the built-in logger to output messages:
```php
Kiri::getLogger()->info('This is an info message.');
```
### Exception Handling
Register a custom exception handler:
```php
$errorHandler = new ErrorHandler();
$errorHandler->registerExceptionHandler(function (Throwable $e) {
echo "Unhandled exception: " . $e->getMessage();
});
```
### Database Connections
#### Redis
```php
$redis = new Redis();
$redis->connect();
$redis->set('key', 'value');
echo $redis->get('key');
```
#### MongoDB
```php
$mongo = new MongoDB();
$collection = $mongo->getCollection('users');
$result = $collection->find([]);
```
### Utility Class Examples
#### String Operations
```php
echo Str::rand(10); // Generate a random string
```
#### JSON Response
```php
echo Json::jsonSuccess(['data' => 'example'], 'Operation successful');
```
#### Date Formatting
```php
echo DateFormat::DaySecond(); // Get the number of seconds in a day
```
## Contribution Guidelines
Contributions are welcome! Please follow these steps:
1. Fork the project repository.
2. Create a new branch (`git checkout -b feature/new-feature`)
3. Commit your changes (`git commit -am 'Add new feature'`)
4. Push to the branch (`git push origin feature/new-feature`)
5. Create a Pull Request
## License
This project is licensed under the MIT License. For details, see the [LICENSE](LICENSE) file.
## Contact
If you have any questions or suggestions, please open an Issue or contact the project maintainers.
---
Thank you for choosing Kiri Core Framework! We look forward to your feedback and contributions.
+133
View File
@@ -0,0 +1,133 @@
# Kiri 核心框架文档
## 项目介绍
Kiri 是一个基于 PHP 的高性能核心框架,旨在为开发者提供简洁、高效的开发体验。该框架内置了多种实用工具类、异常处理机制、配置管理、容器依赖注入等功能,适用于构建各种类型的应用程序。
### 主要特性
- **依赖注入容器**:通过 `Kiri\Di\Container` 提供强大的依赖管理功能。
- **配置管理**:支持从文件和环境变量中读取配置。
- **异常处理**:提供统一的异常处理接口,支持注册自定义异常处理器。
- **日志记录**:内置 `StdoutLogger` 支持多种日志级别输出。
- **实用工具类**
- `Str`:字符串操作,如加密、随机字符串生成等。
- `Json`JSON 编码/解码及响应构造。
- `Help`:提供 XML 转换、随机数生成、邮件发送等辅助功能。
- `DateFormat`:日期和时间格式化工具。
- **网络功能**:支持本地 IP 获取、Socket 编程。
- **NoSQL 支持**:提供 Redis 和 MongoDB 的客户端封装,支持连接池管理。
## 安装
### 系统要求
- PHP 7.4 或更高版本
- Composer(用于依赖管理)
### 安装步骤
1. 确保已安装 Composer。
2. 执行以下命令安装依赖:
```bash
composer install
```
## 使用说明
### 初始化框架
```php
use Kiri\Kiri;
use Kiri\Application;
// 初始化容器
Kiri::setContainer(new Container());
// 创建应用实例
$app = new Application(
new EventProvider(),
new ConfigProvider(),
Kiri::getContainer()
);
// 初始化应用
$app->init();
```
### 配置管理
配置文件可通过 `ConfigProvider` 类进行加载和访问:
```php
$config = new ConfigProvider();
$databaseHost = $config->get('database.host');
```
### 依赖注入
使用容器进行依赖注入:
```php
$service = Kiri::getContainer()->get(MyService::class);
```
### 日志记录
使用内置日志记录器输出信息:
```php
Kiri::getLogger()->info('This is an info message.');
```
### 异常处理
注册自定义异常处理器:
```php
$errorHandler = new ErrorHandler();
$errorHandler->registerExceptionHandler(function (Throwable $e) {
echo "Unhandled exception: " . $e->getMessage();
});
```
### 数据库连接
#### Redis
```php
$redis = new Redis();
$redis->connect();
$redis->set('key', 'value');
echo $redis->get('key');
```
#### MongoDB
```php
$mongo = new MongoDB();
$collection = $mongo->getCollection('users');
$result = $collection->find([]);
```
### 工具类使用示例
#### 字符串处理
```php
echo Str::rand(10); // 生成随机字符串
```
#### JSON 响应
```php
echo Json::jsonSuccess(['data' => 'example'], 'Operation successful');
```
#### 日期格式化
```php
echo DateFormat::DaySecond(); // 获取一天的秒数
```
## 贡献指南
欢迎贡献代码!请遵循以下步骤:
1. Fork 项目仓库。
2. 创建新分支 (`git checkout -b feature/new-feature`)
3. 提交更改 (`git commit -am 'Add new feature'`)
4. 推送分支 (`git push origin feature/new-feature`)
5. 创建 Pull Request
## 许可证
该项目采用 MIT 许可证。详细信息请参阅 [LICENSE](LICENSE) 文件。
## 联系方式
如有问题或建议,请提交 Issue 或联系项目维护者。
---
感谢您选择 Kiri 核心框架!我们期待您的反馈与贡献。
+23 -23
View File
@@ -1,23 +1,23 @@
<?php
function version($oldVersion, $newVersion): bool
{
$first = explode('.', $oldVersion);
$end = explode('.', $newVersion);
while (count($first) > 0) {
$shift = (int)array_shift($first);
$endShift = (int)array_shift($end);
if ($endShift == $shift) {
continue;
}
if ($endShift < $shift) {
return true;
} else {
return false;
}
}
return false;
}
var_dump(version('1.4.4','1.4.3'));
<?php
function version($oldVersion, $newVersion): bool
{
$first = explode('.', $oldVersion);
$end = explode('.', $newVersion);
while (count($first) > 0) {
$shift = (int)array_shift($first);
$endShift = (int)array_shift($end);
if ($endShift == $shift) {
continue;
}
if ($endShift < $shift) {
return TRUE;
} else {
return FALSE;
}
}
return FALSE;
}
var_dump(version('1.4.4', '1.4.3'));
+22 -12
View File
@@ -9,7 +9,7 @@
],
"license": "MIT",
"require": {
"php": ">=8.0",
"php": ">=8.5",
"ext-json": "*",
"ext-fileinfo": "*",
"ext-pdo": "*",
@@ -21,25 +21,35 @@
"ext-xml": "*",
"ext-curl": "*",
"ext-openssl": "*",
"symfony/console": "^v5.3",
"ext-swoole": "*",
"ext-msgpack": "*",
"symfony/console": "^v8.0",
"psr/log": "1.*",
"ext-sockets": "*",
"ext-pcntl": "*",
"ext-posix": "*",
"composer-runtime-api": "^2.0",
"swiftmailer/swiftmailer": "^6.0",
"psr/http-server-middleware": "^1.0.2",
"ext-pcntl": "*",
"ext-sockets": "*",
"nikic/php-parser": "^v5.5.0",
"ext-inotify": "*",
"game-worker/kiri-pool": "^v1.0",
"psr/container": "^2.0",
"psr/http-server-middleware": "^1.0",
"game-worker/kiri-event": "v1.0"
"swiftmailer/swiftmailer": "^v6.3.0"
},
"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/",
"Gii\\": "kiri-gii/",
"Annotation\\": "kiri-note/"
"Kiri\\": "kiri-engine/"
},
"files": [
"error.php",
"Kiri.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);
}
}
+1052 -1155
View File
File diff suppressed because it is too large Load Diff
+94 -449
View File
@@ -10,462 +10,107 @@ declare(strict_types=1);
namespace Kiri\Abstracts;
use Annotation\Annotation as SAnnotation;
use Database\Connection;
use Database\DatabasesProviders;
use Exception;
use Http\Handler\Router;
use Kiri\Events\OnBeforeCommandExecute;
use Server\Server;
use Kafka\KafkaProvider;
use Kiri\Async;
use Kiri\Cache\Redis;
use Kiri\Di\LocalService;
use Kiri\Error\ErrorHandler;
use Kiri\Error\Logger;
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\Exception\InitException;
use Kiri\Exception\NotFindClassException;
use Kiri\Jwt\Jwt;
use Kiri\Kiri;
use ReflectionException;
use Server\ServerManager;
use Server\Contract\OnTaskInterface;
use Swoole\Table;
use Kiri\Error\StdoutLogger;
/**
* Class BaseApplication
* @package Kiri\Kiri\Base
* @package Kiri\Base
* @property DatabasesProviders $connections
*/
abstract class BaseApplication extends Component
abstract class BaseApplication extends LocalService
{
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
*/
public function task(OnTaskInterface $execute): void
{
di(ServerManager::class)->task($execute);
}
/**
* @param $key
* @param $value
* @throws InitException
* @throws Exception
*/
private function addEvent($key, $value): void
{
$eventProvider = di(EventProvider::class);
if ($value instanceof \Closure || is_object($value)) {
$eventProvider->on($key, $value, 0);
return;
}
if (is_array($value)) {
if (is_object($value[0]) && !($value[0] instanceof \Closure)) {
$eventProvider->on($key, $value, 0);
return;
}
if (is_string($value[0])) {
$value[0] = Kiri::createObject($value[0]);
$eventProvider->on($key, $value, 0);
return;
}
foreach ($value as $item) {
if (!is_callable($item, true)) {
throw new InitException("Class does not hav callback.");
}
$eventProvider->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 Jwt
* @throws
*/
public function getJwt(): Jwt
{
return $this->get('jwt');
}
/**
* @return Server
* @throws
*/
public function getServer(): Server
{
return $this->get('server');
}
/**
* @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],
'jwt' => ['class' => Jwt::class],
'async' => ['class' => Async::class],
'kafka-container' => ['class' => KafkaProvider::class],
]);
}
/**
* @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);
parent::__construct();
}
/**
* @return void
* @throws
*/
public function init(): void
{
$this->parseStorage($this->config);
$this->parseEvents($this->config);
}
/**
* @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('site.log.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);
}
}
-243
View File
@@ -1,243 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/3/30 0030
* Time: 14:10
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Kiri;
use Swoole\Coroutine;
/**
* Class BaseObject
* @package Kiri\Kiri\Base
*/
class BaseObject implements Configure
{
/**
* BaseAbstract constructor.
*
* @param array $config
* @throws Exception
*/
public function __construct(array $config = [])
{
if (!empty($config) && is_array($config)) {
Kiri::configure($this, $config);
}
}
/**
* @throws Exception
*/
public function init()
{
}
/**
* @param array|callable $callback
* @param object $scope
*/
public function async_create(array|callable $callback, object $scope)
{
Coroutine::create($callback, $scope);
}
/**
* @return string
*/
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @param $name
* @param $value
*
* @throws Exception
*/
public function __set($name, $value)
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
$this->{$method}($value);
} else {
throw new Exception('The set name ' . $name . ' not find in class ' . static::class);
}
}
/**
* @param $name
*
* @return mixed
* @throws Exception
*/
public function __get($name): mixed
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method();
} else {
throw new Exception('The get name ' . $name . ' not find in class ' . static::class);
}
}
/**
* @param $message
* @param string $model
* @return bool
* @throws Exception
*/
public function addError($message, string $model = 'app'): bool
{
if ($message instanceof \Throwable) {
$this->error(jTraceEx($message));
} else {
if (!is_string($message)) {
$message = json_encode($message, JSON_UNESCAPED_UNICODE);
}
$this->error($message);
}
return FALSE;
}
/**
* @return Logger
* @throws Exception
*/
private function logger(): Logger
{
return Kiri::getDi()->get(Logger::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);
}
$message = "\033[35m" . $message . "\033[0m";
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->debug($message, $context);
}
/**
* @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);
}
$message = "\033[34m" . $message . "\033[0m";
$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);
}
$message = "\033[36m" . $message . "\033[0m";
$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);
}
$message = "\033[33m" . $message . "\033[0m";
$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();
}
$content = (empty($method) ? '' : $method . ': ') . $message;
$message = "\033[41;37m" . $content . "\033[0m";
if (!empty($file)) {
$message .= PHP_EOL . "\03341;37m[" . $file . "\033[0m";
}
$context = [];
if (!empty($method)) $context['method'] = $method;
if (!empty($file)) $context['file'] = $file;
$this->logger()->error($message, $context);
}
}
-10
View File
@@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Abstracts;
abstract class Command extends Component
{
}
+46 -36
View File
@@ -1,55 +1,65 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/3/30 0030
* Time: 14:28
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Exception\ComponentException;
use Kiri\Kiri;
use Kiri;
use Kiri\Error\StdoutLogger;
use Kiri\Events\EventDispatch;
use Kiri\Events\EventProvider;
use Psr\Container\ContainerInterface;
/**
* Class Component
* @package Kiri\Kiri\Base
*/
class Component extends BaseObject
class Component
{
/**
* @param $name
* @param $value
* @throws Exception
*/
public function __set($name, $value)
public function __construct()
{
if (property_exists($this, $name)) {
$this->$name = $value;
} else {
parent::__set($name, $value);
}
}
public function init(): void
{
}
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @param $name
* @return mixed
* @throws Exception
* @throws
*/
public function __get($name): mixed
public function getLogger(): StdoutLogger
{
if (property_exists($this, $name)) {
return $this->$name ?? null;
} else {
return parent::__get($name);
}
return Kiri::getLogger();
}
public function getDispatch(): EventDispatch
{
return Kiri::getDi()->get(EventDispatch::class);
}
public function getProvider(): EventProvider
{
return Kiri::getDi()->get(EventProvider::class);
}
public function getContainer(): ContainerInterface
{
return Kiri::getDi();
}
/**
* @throws
*/
public function __get(string $name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->{$method}();
}
throw new Exception('Unable getting property ' . get_called_class() . '::' . $name);
}
}
-124
View File
@@ -1,124 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/5/24 0024
* Time: 11:50
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
use Exception;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
/**
* Class Config
* @package Kiri\Kiri\Base
*/
class Config extends Component
{
const ERROR_MESSAGE = 'The not find %s in app configs.';
protected mixed $data = [];
/**
* @return mixed
*/
public function getData(): mixed
{
return $this->data;
}
/**
* @param $key
* @param $value
* @return mixed
*/
public function setData($key, $value): mixed
{
return $this->data[$key] = $value;
}
/**
* @param array $configs
* @throws Exception
*/
public static function sets(array $configs)
{
$config = Kiri::app()->getConfig();
if (empty($configs)) {
return;
}
$config->data = $configs;
}
/**
* @param $key
* @param bool $try
* @param mixed|null $default
* @return mixed
* @throws
*/
public static function get($key, mixed $default = null, bool $try = FALSE): mixed
{
$instance = Kiri::app()->getConfig()->getData();
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
* @throws Exception
*/
public static function set($key, $value): mixed
{
$config = Kiri::app()->getConfig();
return $config->setData($key, $value);
}
/**
* @param $key
* @param bool $must_not_null
* @return bool
* @throws Exception
*/
public static function has($key, bool $must_not_null = false): bool
{
$config = Kiri::app()->getConfig();
if (!isset($config->data[$key])) {
return false;
}
$config = $config->data[$key];
if ($must_not_null === false) {
return true;
}
return !empty($config);
}
}
-18
View File
@@ -1,18 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/3/30 0030
* Time: 14:11
*/
declare(strict_types=1);
namespace Kiri\Abstracts;
/**
* Interface Configure
* @package Kiri\Kiri\Base
*/
interface Configure
{
}
@@ -0,0 +1,25 @@
<?php
namespace Kiri\Abstracts;
use Kiri\Coordinator;
class CoordinatorManager
{
private static array $_items = [];
/**
* @param string $category
* @return Coordinator
*/
public static function utility(string $category): Coordinator
{
if (!((static::$_items[$category] ?? null) instanceof Coordinator)) {
static::$_items[$category] = new Coordinator();
}
return static::$_items[$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
{
}
-201
View File
@@ -1,201 +0,0 @@
<?php
namespace Kiri\Abstracts;
use Annotation\Inject;
use Exception;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Psr\Log\LoggerInterface;
use Server\Events\OnWorkerStop;
/**
*
*/
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';
/**
* @var EventProvider
*/
#[Inject(EventProvider::class)]
public EventProvider $eventProvider;
private array $_loggers = [];
const LOGGER_LEVELS = [Logger::EMERGENCY, Logger::ALERT, Logger::CRITICAL, Logger::ERROR, Logger::WARNING, Logger::NOTICE, Logger::INFO, Logger::DEBUG];
/**
* 监听事件
*/
public function init()
{
$this->eventProvider->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)) {
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', 'logs/');
file_put_contents($filename, $loggers);
}
}
/**
* @param $message
* @param $context
* @return string
*/
private function _string($message, $context): string
{
if (!empty($context)) {
return $message . ' ' . 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,37 +0,0 @@
<?php
namespace Kiri\Abstracts;
use Annotation\Annotation as SAnnotation;
use Database\Connection;
use Database\DatabasesProviders;
use Http\Handler\Client\Client;
use Http\Handler\Client\Curl;
use Http\Handler\Router;
use Server\Server;
use Kiri\Crontab\Producer;
use Kiri\Async;
use Kiri\Error\Logger;
use Kiri\Jwt\Jwt;
/**
* Trait TraitApplication
* @package Kiri\Abstracts
* @property Router $router
* @property Server $server
* @property DatabasesProviders $db
* @property Async $async
* @property Logger $logger
* @property Jwt $jwt
* @property SAnnotation $annotation
* @property BaseGoto $goto
* @property Client $client
* @property Connection $databases
* @property Curl $curl
*/
trait TraitApplication
{
}
+111 -211
View File
@@ -10,247 +10,147 @@ declare(strict_types=1);
namespace Kiri;
use Closure;
use Database\DatabasesProviders;
use Exception;
use Kiri\Abstracts\BaseApplication;
use Kiri\Abstracts\Config;
use Kiri\Abstracts\Kernel;
use Kiri\Crontab\CrontabProviders;
use Kiri\Events\OnAfterCommandExecute;
use Kiri\Events\OnBeforeCommandExecute;
use Kiri\Exception\NotFindClassException;
use Kiri\FileListen\HotReload;
use ReflectionException;
use Server\ServerProviders;
use stdClass;
use Swoole\Process;
use Swoole\Timer;
use Symfony\Component\Console\Application as ConsoleApplication;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Kiri;
use Kiri\Abstracts\{BaseApplication, Kernel};
use Kiri\Di\Scanner;
use Kiri\Error\ErrorHandler;
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
use Symfony\Component\Console\{Application as ConsoleApplication,
Input\ArgvInput,
Output\ConsoleOutput,
Output\OutputInterface
};
use Kiri\Server\ServerCommand;
use Kiri\Di\Inject\Container;
use function config;
/**
* Class Init
*
* @package Kiri
*
* @property-read Config $config
*/
class Application extends BaseApplication
{
/**
* @var string
*/
public string $id = 'uniqueId';
/**
* @var string
*/
public string $id = 'uniqueId';
public string $state = '';
public string $state = '';
/** @var array<array<Process>> */
private array $_process = [];
/**
* @var ErrorHandler
*/
#[Container(ErrorHandler::class)]
public ErrorHandler $errorHandler;
/**
*/
public function init()
{
$this->import(ServerProviders::class);
/**
* @return void
* @throws
*/
public function init(): void
{
$this->errorHandler->registerShutdownHandler(config('site.error.shutdown', []));
$this->errorHandler->registerExceptionHandler(config('site.error.exception', []));
$this->errorHandler->registerErrorHandler(config('site.error.error', []));
$this->register(Runtime::class);
}
$this->id = config('site.id', uniqid('id.'));
$this->provider->on(OnBeforeCommandExecute::class, [$this, 'beforeCommandExecute']);
parent::init();
}
/**
* @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;
/**
* @param OnBeforeCommandExecute $beforeCommandExecute
* @return void
* @throws
*/
public function beforeCommandExecute(OnBeforeCommandExecute $beforeCommandExecute): void
{
if ($beforeCommandExecute->command instanceof ServerCommand) {
return;
}
$class = Kiri::getDi()->get($service);
if (method_exists($class, 'onImport')) {
$class->onImport($this);
}
return $this;
}
$scanner = $this->container->get(Scanner::class);
$scanner->scan(APP_PATH . 'app/');
}
/**
* @param Kernel $kernel
* @return $this
*/
public function commands(Kernel $kernel): static
{
foreach ($kernel->getCommands() as $command) {
$this->register($command);
}
return $this;
}
/**
* @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 string $command
* @throws
*/
public function register(string $command)
{
di(ConsoleApplication::class)->add(di($command));
}
/**
* @param Kernel $kernel
* @return $this
* @throws
*/
public function commands(Kernel $kernel): static
{
foreach ($kernel->getCommands() as $command) {
$this->command($command);
}
return $this;
}
/**
* @param array $argv
* @return void
*/
public function execute(array $argv): void
{
/** @var InputInterface $input */
[$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 string ...$command
* @return void
* @throws
*/
public function command(string ...$command): void
{
$console = $this->container->get(ConsoleApplication::class);
foreach ($command as $value) {
$console->addCommand($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));
/**
* @param $argv
* @return array
*/
private function argument($argv): array
{
return [new ArgvInput($argv), new ConsoleOutput()];
}
/** @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));
/**
* @throws NotFindClassException
* @throws ReflectionException
* @throws Exception
*/
private function enableFileChange(Command $class, $input, $output): void
{
fire(new OnBeforeCommandExecute());
if (!($class instanceof HotReload)) {
scan_directory(directory('app'), 'App');
}
$class->run($input, $output);
fire(new OnAfterCommandExecute());
$output->writeln('ok' . PHP_EOL);
}
$output->writeln('execute complete.');
}
/**
* @param $className
* @param null $abstracts
* @return stdClass
* @throws Exception
*/
public function make($className, $abstracts = null): stdClass
{
return make($className, $abstracts);
}
}
-43
View File
@@ -1,43 +0,0 @@
<?php
namespace Kiri;
use Exception;
use Kiri\Abstracts\Component;
use Server\ServerManager;
/**
* 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(ServerManager::class);
$context->task(static::$_absences[$name], $params);
}
}
-152
View File
@@ -1,152 +0,0 @@
<?php
namespace Kiri\Cache\Base;
use Kiri\Abstracts\Logger;
use Kiri\Exception\RedisConnectException;
use Kiri\Kiri;
use Kiri\Pool\StopHeartbeatCheck;
use RedisException;
use Kiri\Context;
use Swoole\Timer;
/**
*
*/
class Redis implements StopHeartbeatCheck
{
const DB_ERROR_MESSAGE = 'The system is busy, please try again later.';
private ?\Redis $pdo = null;
private int $_transaction = 0;
private int $_timer = -1;
private int $_last = 0;
/**
* @param string $host
* @param int $port
* @param int $database
* @param string $auth
* @param string $prefix
* @param int $timeout
* @param int $read_timeout
*/
public function __construct(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 function init()
{
$this->heartbeat_check();
}
/**
*
*/
public function heartbeat_check(): void
{
if (env('state', 'start') == 'exit') {
return;
}
if ($this->_timer === -1 && Context::inCoroutine()) {
$this->_timer = Timer::tick(1000, function () {
try {
if (env('state', 'start') == 'exit') {
Kiri::getDi()->get(Logger::class)->critical('timer end');
$this->stopHeartbeatCheck();
}
if (time() - $this->_last > 10 * 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\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\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;
}
-160
View File
@@ -1,160 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/27 0027
* Time: 11:00
*/
declare(strict_types=1);
namespace Kiri\Cache;
use Annotation\Inject;
use Exception;
use Server\Events\OnWorkerExit;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
use Kiri\Pool\Redis as PoolRedis;
/**
* Class Redis
* @package Kiri\Kiri\Cache
* @mixin \Redis
*/
class Redis extends Component
{
/**
* @var EventProvider
*/
#[Inject(EventProvider::class)]
public EventProvider $eventProvider;
/**
* @throws ConfigException
* @throws Exception
*/
public function init()
{
$connections = Kiri::getDi()->get(PoolRedis::class);
$config = $this->get_config();
$length = Config::get('connections.pool.max', 10);
$this->eventProvider->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|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, '=');
}
}
-189
View File
@@ -1,189 +0,0 @@
<?php
namespace Kiri;
use Kiri\Abstracts\BaseContext;
use Swoole\Coroutine;
/**
* 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 (Coroutine::getCid() === -1) {
return static::$_contents[$id] = $context;
}
return Coroutine::getContext($coroutineId)[$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 (!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 (!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
{
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 (!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;
}
if (!empty($key) && !isset(static::$_contents[$id][$key])) {
return false;
}
return true;
}
/**
* @param $id
* @param null $key
* @param null $coroutineId
* @return bool
*/
private static function searchByCoroutine($id, $key = null, $coroutineId = null): bool
{
if (!isset(Coroutine::getContext($coroutineId)[$id])) {
return false;
}
if ($key !== null) {
return isset((Coroutine::getContext($coroutineId)[$id] ?? [])[$key]);
}
return true;
}
/**
* @return bool
*/
public static function inCoroutine(): bool
{
return Coroutine::getCid() !== -1;
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Kiri;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
class Coordinator
{
const string WORKER_START = 'worker:start';
private bool $wait = true;
private ?Channel $channel = null;
/**
* @return void
*/
public function yield(): void
{
if (Coroutine::getCid() > 0) {
$this->channel = new Channel(1);
$this->channel->pop();
} else {
while ($this->wait) {
usleep(1000);
}
}
}
/**
* @return void
*/
public function wait(): void
{
$this->wait = true;
$this->channel = null;
}
/**
* @return void
*/
public function done(): void
{
$this->wait = false;
$this->channel?->push(true);
}
}
+98 -100
View File
@@ -1,100 +1,98 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/4 0004
* Time: 14:57
*/
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class ArrayAccess
* @package Kiri\Core
*/
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 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 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;
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/4 0004
* Time: 14:57
*/
declare(strict_types=1);
namespace Kiri\Core;
/**
* Class ArrayAccess
* @package Kiri\Core
*/
class ArrayAccess
{
/**
* @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
*/
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;
}
}
+128 -106
View File
@@ -1,106 +1,128 @@
<?php
/**
* Created by PhpStorm.
* User: dell
* Date: 2019/1/14 0014
* Time: 13:50
*/
declare(strict_types=1);
namespace Kiri\Core;
/**
* Class DateFormat
* @package Kiri\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(floatval($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;
}
/**
* @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 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;
}
$time = date('t', $time);
return $time;
}
/**
* @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);
}
}
<?php
/**
* Created by PhpStorm.
* User: dell
* Date: 2019/1/14 0014
* Time: 13:50
*/
declare(strict_types=1);
namespace Kiri\Core;
/**
* Class DateFormat
* @package Kiri\Core
*/
class DateFormat
{
/**
* @return int
*/
public static function DaySecond(): int
{
$time = strtotime(date('Y-m-d', strtotime('+1days')));
return $time - 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 $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;
}
/**
* @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 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);
}
}
-60
View File
@@ -1,60 +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
*/
public function __construct($params)
{
parent::__construct([]);
$this->params = $params;
}
/**
* @return array
* @throws Exception
*/
public function toArray(): array
{
if (!is_array($this->params)) {
return ArrayAccess::toArray($this->params);
}
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];
}
}
+157
View File
@@ -0,0 +1,157 @@
<?php
namespace Kiri\Core;
use Exception;
use JetBrains\PhpStorm\Pure;
use ReturnTypeWillChange;
use Traversable;
class HashMap implements \ArrayAccess, \IteratorAggregate
{
/**
* @var array
*/
private array $lists = [];
/**
* @return Traversable
*/
public function getIterator(): Traversable
{
return new \ArrayIterator($this->lists);
}
/**
* @return bool
*/
public function hasItem(): bool
{
return count($this->lists) > 0;
}
/**
* @param string $key
* @param $value
*/
public function put(string $key, $value): void
{
$this->lists[$key] = $value;
}
/**
* @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
* @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 string $key
*/
public function del(string $key): void
{
if (!$this->has($key)) {
return;
}
unset($this->lists[$key]);
}
/**
* @param string $key
* @return bool
*/
public function has(string $key): bool
{
return array_key_exists($key, $this->lists);
}
/**
* @param mixed $offset
* @return bool
*/
public function offsetExists(mixed $offset): bool
{
return isset($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;
}
}
+325 -215
View File
@@ -1,215 +1,325 @@
<?php
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class Help
* @package Kiri\Kiri\Core
*/
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 $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
*/
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 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 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);
}
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 $email
* @param string $Subject
* @param $messageContent
*/
public static function sendEmail($email, string $Subject, $messageContent)
{
$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);
}
}
<?php
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
use Swift_Message;
use Swift_SmtpTransport;
/**
* Class Help
* @package Kiri\Core
*/
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 $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
*/
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 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
*/
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 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);
}
/**
* @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): 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);
}
/**
* @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;
}
}
+144 -122
View File
@@ -1,122 +1,144 @@
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 01:04
*/
declare(strict_types=1);
namespace Kiri\Core;
use Error;
use Exception;
use Throwable;
/**
* Class JSON
* @package Kiri\Kiri\Core
*/
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
* @param bool $asArray
* @return mixed
*/
public static function decode($data, $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 $message
* @param array $data
* @param int $count
* @param array $exPageInfo
* @return mixed
* @throws
*/
public static function to($code, $message = '', $data = [], $count = 0, $exPageInfo = []): mixed
{
$params['code'] = $code;
if (!is_string($message)) {
$params['param'] = $message;
if (!empty($data)) {
$params['exPageInfo'] = $data;
}
$params['message'] = 'System success.';
} 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 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 Exception
*/
public static function output($state, $body): bool|int|string
{
$params['state'] = $state;
$params['body'] = ArrayAccess::toArray($body);
return static::encode($params);
}
}
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 01:04
*/
declare(strict_types=1);
namespace Kiri\Core;
use Error;
use Exception;
use Throwable;
/**
* Class JSON
* @package Kiri\Core
*/
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
* @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 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 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 $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);
}
/**
* @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);
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
namespace Kiri\Core;
class Network
{
/**
* @return string
*/
public static function local(): string
{
return current(swoole_get_local_ip());
}
}
+31 -31
View File
@@ -1,31 +1,31 @@
<?php
namespace Kiri\Core;
class Number
{
/**
* @param int $userId
* @return string
*/
public static function order(int $userId): string
{
$explode = current(explode(' ', str_replace('0.', '', microtime())));
return 'No.' . sprintf('%010d', $userId) . '.' . date('Ymd.His') . '.' . $explode;
}
/**
* @param int $userId
* @return string
*/
public static function create(int $userId): string
{
return static::order($userId);
}
}
<?php
namespace Kiri\Core;
class Number
{
/**
* @param int $userId
* @return string
*/
public static function order(int $userId): string
{
$explode = current(explode(' ', str_replace('0.', '', microtime())));
return 'No.' . sprintf('%010d', $userId) . '.' . date('Ymd.His') . '.' . $explode;
}
/**
* @param int $userId
* @return string
*/
public static function create(int $userId): string
{
return static::order($userId);
}
}
+172 -172
View File
@@ -1,172 +1,172 @@
<?php
declare(strict_types=1);
namespace Kiri\Core;
/**
* Class Reader
* @package Kiri\Kiri\Core
*/
class Reader
{
/**
* @param $filepath
* @param int $page
* @param int $size
* @return array and int
*/
public static function readerServerLogPagination($filepath, int $page = 1, int $size = 20): array
{
$count = 0;
$strings = [];
$offset = ($page - 1) * $size;
if (!file_exists($filepath)) {
return [0, []];
}
//只读方式打开文件
$fp = fopen($filepath, "r");
//开始循环读取$buffer_size
while (!feof($fp)) {
//读文件到缓冲区
$buffer = fgets($fp);
$count++;
if ($count > $offset && count($strings) < $size) {
$strings[] = [
'id' => $count,
'content' => $buffer
];
}
}
//关闭文件
fclose($fp);
unset($fp);
return ['total' => $count, 'list' => $strings];
}
/**
* @param $filename
* @param $start
* @param $lines
* @return array
*/
public static function read_backward_line($filename, $start, $lines): array
{
$lines++;
$offset = -1;
$read = '';
$fp = @fopen($filename, "r");
$tmpStart = 0;
while ($lines && fseek($fp, $offset, SEEK_END) >= 0) {
$c = fgetc($fp);
if ($c == "\n" || $c == "\r") {
if (++$tmpStart >= $start)
$lines--;
}
if ($tmpStart >= $start)
$read .= $c;
$offset--;
}
$read = trim($read);
$contents = [];
$read = array_reverse(explode("\n", strrev($read)));
foreach ($read as $key => $value) {
if (empty($value)) {
unset($read[$key]);
} else {
$contents[] = ['content' => $value, 'id' => $key + $start];
}
}
$response['total'] = self::read_count_by_file($filename);
$response['list'] = $contents;
return $response;
}
/**
* @param $filepath
* @return int
*/
private static function read_count_by_file($filepath): int
{
$count = 0;
//只读方式打开文件
$fp = fopen($filepath, "r");
//开始循环读取$buffer_size
while (fgets($fp)) {
$count++;
}
//关闭文件
fclose($fp);
unset($fp);
return $count;
}
/**
* @param $filepath
* @param int $page
* @param int $size
* @return array
*/
public static function folderPagination($filepath, int $page = 1, int $size = 20): array
{
$count = 0;
$strings = [];
$offset = ($page - 1) * $size;
if (!is_dir($filepath)) {
return [0, []];
}
foreach (glob($filepath . '/*') as $key => $value) {
$count++;
if ($key < $offset || count($strings) >= $size) {
continue;
}
$explode = explode(DIRECTORY_SEPARATOR, $value);
$addTime = fileatime($value);
$changeTime = filectime($value);
$modifyTime = filemtime($value);
$strings[] = [
'id' => $count,
'path' => $value,
'isDir' => (int)is_dir($value),
'name' => end($explode),
'atime' => [
'format' => date('Y-m-d H:i:s', $addTime),
'microtime' => $addTime
],
'ctime' => [
'format' => date('Y-m-d H:i:s', $changeTime),
'microtime' => $changeTime
],
'mtime' => [
'format' => date('Y-m-d H:i:s', $modifyTime),
'microtime' => $modifyTime
],
];
}
array_multisort($strings, array_column($strings, 'isDir'), SORT_DESC);
return ['total' => $count, 'list' => $strings];
}
}
<?php
declare(strict_types=1);
namespace Kiri\Core;
/**
* Class Reader
* @package Kiri\Core
*/
class Reader
{
/**
* @param $filepath
* @param int $page
* @param int $size
* @return array and int
*/
public static function readerServerLogPagination($filepath, int $page = 1, int $size = 20): array
{
$count = 0;
$strings = [];
$offset = ($page - 1) * $size;
if (!file_exists($filepath)) {
return [0, []];
}
//只读方式打开文件
$fp = fopen($filepath, "r");
//开始循环读取$buffer_size
while (!feof($fp)) {
//读文件到缓冲区
$buffer = fgets($fp);
$count++;
if ($count > $offset && count($strings) < $size) {
$strings[] = [
'id' => $count,
'content' => $buffer
];
}
}
//关闭文件
fclose($fp);
unset($fp);
return ['total' => $count, 'list' => $strings];
}
/**
* @param $filename
* @param $start
* @param $lines
* @return array
*/
public static function read_backward_line($filename, $start, $lines): array
{
$lines++;
$offset = -1;
$read = '';
$fp = @fopen($filename, "r");
$tmpStart = 0;
while ($lines && fseek($fp, $offset, SEEK_END) >= 0) {
$c = fgetc($fp);
if ($c == "\n" || $c == "\r") {
if (++$tmpStart >= $start)
$lines--;
}
if ($tmpStart >= $start)
$read .= $c;
$offset--;
}
$read = trim($read);
$contents = [];
$read = array_reverse(explode("\n", strrev($read)));
foreach ($read as $key => $value) {
if (empty($value)) {
unset($read[$key]);
} else {
$contents[] = ['content' => $value, 'id' => $key + $start];
}
}
$response['total'] = self::read_count_by_file($filename);
$response['list'] = $contents;
return $response;
}
/**
* @param $filepath
* @return int
*/
private static function read_count_by_file($filepath): int
{
$count = 0;
//只读方式打开文件
$fp = fopen($filepath, "r");
//开始循环读取$buffer_size
while (fgets($fp)) {
$count++;
}
//关闭文件
fclose($fp);
unset($fp);
return $count;
}
/**
* @param $filepath
* @param int $page
* @param int $size
* @return array
*/
public static function folderPagination($filepath, int $page = 1, int $size = 20): array
{
$count = 0;
$strings = [];
$offset = ($page - 1) * $size;
if (!is_dir($filepath)) {
return [0, []];
}
foreach (glob($filepath . '/*') as $key => $value) {
$count++;
if ($key < $offset || count($strings) >= $size) {
continue;
}
$explode = explode(DIRECTORY_SEPARATOR, $value);
$addTime = fileatime($value);
$changeTime = filectime($value);
$modifyTime = filemtime($value);
$strings[] = [
'id' => $count,
'path' => $value,
'isDir' => (int)is_dir($value),
'name' => end($explode),
'atime' => [
'format' => date('Y-m-d H:i:s', $addTime),
'microtime' => $addTime
],
'ctime' => [
'format' => date('Y-m-d H:i:s', $changeTime),
'microtime' => $changeTime
],
'mtime' => [
'format' => date('Y-m-d H:i:s', $modifyTime),
'microtime' => $modifyTime
],
];
}
array_multisort($strings, array_column($strings, 'isDir'), SORT_DESC);
return ['total' => $count, 'list' => $strings];
}
}
+278 -277
View File
@@ -1,277 +1,278 @@
<?php
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class Str
* @package Kiri\Kiri\Core
*/
class Str
{
const STRING = 'abcdefghijklmnopqrstuvwxyz';
const NUMBER = '01234567890';
/**
* @param int $length
*
* @return string
* 获取随机字符串
*/
public static function rand(int $length = 20): string
{
$string = '';
if ($length < 1) $length = 20;
$default = self::STRING . strtoupper(self::STRING) . self::NUMBER;
$default = str_split($default);
$string .= str_repeat($default[array_rand($default)], $length);
return (string)$string;
}
/**
* @param int $length
*
* @return int|string 获取随机数字
* 获取随机数字
*/
public static function random(int $length = 20): int|string
{
$number = '';
$default = str_split(self::NUMBER);
if ($length < 1) $length = 1;
$number .= str_repeat($default[array_rand($default)], $length);
return $number;
}
/**
* @param $string
* @param $sullen
* @param bool $strip_tags
* @param string $append
*
* @return string
*/
public static function cut_str_utf8($string, $sullen, bool $strip_tags = true, string $append = '...'): string
{
if ($strip_tags) {
$string = strip_tags($string);
}//去掉签标
$pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
preg_match_all($pa, $string, $t_string);
$str = "";
for ($i = 0; $i < count($t_string[0]); $i++) {
$str .= $t_string[0][$i];
//转为gbk,一个汉字长度为2
if (strlen(@iconv('utf-8', 'gbk', $str)) >= $sullen) {
if ($i != count($t_string[0]) - 1) $str .= $append;
break;
}
}
return $str;
}
/**
* @param $data
*
* @param null $callback
* @return bool
* 判断是否为json字符串
*/
public static function isJson($data, $callback = null): bool
{
$json = !is_null(json_decode($data)) && !is_numeric($data);
if ($json && is_callable($callback, true)) {
return call_user_func($callback, $data);
}
return $json;
}
/**
* @param $data
*
* @param null $callBack
* @return bool
* 判断是否序列化字符串
*/
public static function isSerialize($data, $callBack = null): bool
{
$false = !empty($data) && swoole_unserialize($data) !== false;
if ($false && is_callable($callBack, true)) {
return call_user_func($callBack, $data);
}
return $false;
}
/**
* @param $string
* @param int $length
*
* @param string $append
* @return string
*/
public static function cut($string, int $length = 20, string $append = '...'): string
{
if (empty($string)) {
return '';
}
if ($length < 1) {
$length = 1;
}
$array = str_split($string);
if (count($array) <= $length) {
return implode('', $array);
}
$string = implode('', array_slice($array, 0, $length));
if (!empty($append)) {
$string .= $append;
}
return $string;
}
/**
* @param $str
* @param int $number
* @param string $key
*
* @return string
*/
public static function encrypt($str, int $number = 10, string $key = 'xshucai.com'): string
{
$res = [];
$add = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$len = strlen($key) < 0 ? 1 : (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');
$res[] = md5($_tmp);
}
sort($res, SORT_STRING);
return hash('sha384', implode('', $res));
}
/**
* @param $file
* @param $type
* @return string
*/
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);
}
/**
* @param $endTime
* @param int|null $startTime
* @return array
* 剩余天,带分秒
*/
public static function timeout($endTime, int $startTime = null): array
{
$endTime = $endTime - (!empty($startTime) ? $startTime : time());
$day = intval($endTime / (3600 * 24));
$hours = intval(($endTime - ($day * (3600 * 24))) / 3600);
$minute = intval(($endTime - ($day * (3600 * 24) + $hours * 3600)) / 60);
$scrod = intval(($endTime - ($day * (3600 * 24) + $hours * 3600 + $minute * 60)));
return [$day, $hours, $minute, $scrod];
}
/**
* @return false|int
*/
public static function get_sy_time(): bool|int
{
$time = strtotime('+1days', strtotime(date('Y-m-d')));
return $time - time();
}
/**
* @param string $string
* @return string
*/
public static function encode(string $string): string
{
return addslashes($string);
}
/**
* @param string $string
* @return string|string[]|null
* 清除标点符号
*/
public static function clear(string $string): array|string|null
{
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
return preg_replace(array("/[[:punct:]]/i", '/[' . $char . ']/u', '/[ ]{2,}/'), '', $string);
}
/**
* @param int $user
* @param array $param
* @param null $requestTime
*
* @return string
* @throws Exception
*/
public static function token(int $user, array $param = [], $requestTime = NULL): string
{
$str = '';
if (!$requestTime) {
$requestTime = microtime(true);
}
$_user = str_split(md5($user . md5((string)$user)));
ksort($_user);
foreach ($_user as $key => $val) {
$str .= md5(sha1($key . $val . 'www.xshucai.com'));
}
if (is_array($param)) {
foreach ($param as $key => $val) {
$str .= md5($str . sha1($key . md5($val)));
}
}
$str .= sha1(base64_encode((string)$requestTime));
$md5 = md5($str . $user);
return preg_replace('/(\w{10})(\w{3})(\w{4})(\w{9})(\w{6})/', '$1-$2-$3-$4-$5', $md5);
}
/**
* @param string $str
* @param bool $unfairest
* @return string
*/
public static function convertUnderline(string $str, bool $unfairest = true): string
{
$str = ucwords(str_replace('_', ' ', $str));
$str = str_replace(' ', '', lcfirst($str));
return $unfairest ? ucfirst($str) : $str;
}
}
<?php
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class Str
* @package Kiri\Core
*/
class Str
{
const string STRING = 'abcdefghijklmnopqrstuvwxyz';
const string NUMBER = '01234567890';
/**
* @param int $length
*
* @return string
* 获取随机字符串
*/
public static function rand(int $length = 20): string
{
$string = '';
if ($length < 1) $length = 20;
$default = self::STRING . strtoupper(self::STRING) . self::NUMBER;
$default = str_split($default);
for ($i = 0; $i < $length; $i++) {
shuffle($default);
$string .= $default[array_rand($default)];
}
return $string;
}
/**
* @param int $length
*
* @return int|string 获取随机数字
* 获取随机数字
*/
public static function random(int $length = 20): int|string
{
$number = '';
$default = str_split(self::NUMBER);
if ($length < 1) $length = 1;
for ($i = 0; $i < $length; $i++) {
shuffle($default);
$number .= $default[array_rand($default)];
}
return $number;
}
/**
* @param $string
* @param $sullen
* @param bool $strip_tags
* @param string $append
*
* @return string
*/
public static function cut_str_utf8($string, $sullen, bool $strip_tags = TRUE, string $append = '...'): string
{
if ($strip_tags) {
$string = strip_tags($string);
}//去掉签标
$pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
preg_match_all($pa, $string, $t_string);
$str = "";
for ($i = 0; $i < count($t_string[0]); $i++) {
$str .= $t_string[0][$i];
//转为gbk,一个汉字长度为2
if (strlen(@iconv('utf-8', 'gbk', $str)) >= $sullen) {
if ($i != count($t_string[0]) - 1) $str .= $append;
break;
}
}
return $str;
}
/**
* @param $data
*
* @param null $callback
* @return bool
* 判断是否为json字符串
*/
public static function isJson($data, $callback = NULL): bool
{
$json = !is_null(json_decode($data)) && !is_numeric($data);
if ($json && is_callable($callback, TRUE)) {
return call_user_func($callback, $data);
}
return $json;
}
/**
* @param $data
*
* @param null $callBack
* @return bool
* 判断是否序列化字符串
*/
public static function isSerialize($data, $callBack = NULL): bool
{
$false = !empty($data) && unserialize($data) !== FALSE;
if ($false && is_callable($callBack, TRUE)) {
return call_user_func($callBack, $data);
}
return $false;
}
/**
* @param $string
* @param int $length
*
* @param string $append
* @return string
*/
public static function cut($string, int $length = 20, string $append = '...'): string
{
if (empty($string)) {
return '';
}
if ($length < 1) {
$length = 1;
}
$array = str_split($string);
if (count($array) <= $length) {
return implode('', $array);
}
$string = implode('', array_slice($array, 0, $length));
if (!empty($append)) {
$string .= $append;
}
return $string;
}
/**
* @param $str
* @param int $number
* @param string $key
*
* @return string
*/
public static function encrypt($str, int $number = 10, string $key = 'xshucai.com'): string
{
$res = [];
$add = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$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');
$res[] = md5($_tmp);
}
sort($res, SORT_STRING);
return hash('sha384', implode('', $res));
}
/**
* @param $file
* @param $type
* @return string
*/
public static function filename($file, $type): string
{
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),
};
}
/**
* @param $endTime
* @param int|null $startTime
* @return array
* 剩余天,带分秒
*/
public static function timeout($endTime, ?int $startTime = NULL): array
{
$endTime = $endTime - (!empty($startTime) ? $startTime : time());
$day = intval($endTime / (3600 * 24));
$hours = intval(($endTime - ($day * (3600 * 24))) / 3600);
$minute = intval(($endTime - ($day * (3600 * 24) + $hours * 3600)) / 60);
$scrod = intval(($endTime - ($day * (3600 * 24) + $hours * 3600 + $minute * 60)));
return [$day, $hours, $minute, $scrod];
}
/**
* @return false|int
*/
public static function get_sy_time(): bool|int
{
$time = strtotime('+1days', strtotime(date('Y-m-d')));
return $time - time();
}
/**
* @param string $string
* @return string
*/
public static function encode(string $string): string
{
return addslashes($string);
}
/**
* @param string $string
* @return string|string[]|null
* 清除标点符号
*/
public static function clear(string $string): array|string|null
{
$char = '。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔¡¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()';
return preg_replace(["/[[:punct:]]/i", '/[' . $char . ']/u', '/ {2,}/'], '', $string);
}
/**
* @param int $user
* @param array $param
* @param null $requestTime
*
* @return string
* @throws Exception
*/
public static function token(int $user, array $param = [], $requestTime = NULL): string
{
$str = '';
if (!$requestTime) {
$requestTime = microtime(TRUE);
}
$_user = str_split(md5($user . md5((string)$user)));
ksort($_user);
foreach ($_user as $key => $val) {
$str .= md5(sha1($key . $val . 'www.xshucai.com'));
}
if (is_array($param)) {
foreach ($param as $key => $val) {
$str .= md5($str . sha1($key . md5($val)));
}
}
$str .= sha1(base64_encode((string)$requestTime));
$md5 = md5($str . $user);
return preg_replace('/(\w{10})(\w{3})(\w{4})(\w{9})(\w{6})/', '$1-$2-$3-$4-$5', $md5);
}
/**
* @param string $str
* @param bool $unfairest
* @return string
*/
public static function convertUnderline(string $str, bool $unfairest = TRUE): string
{
$str = ucwords(str_replace('_', ' ', $str));
$str = str_replace(' ', '', lcfirst($str));
return $unfairest ? ucfirst($str) : $str;
}
}
+57 -57
View File
@@ -1,57 +1,57 @@
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 01:03
*/
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class Xml
* @package Kiri\Kiri\Core
*/
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 $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);
}
}
}
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 01:03
*/
declare(strict_types=1);
namespace Kiri\Core;
use Exception;
/**
* Class Xml
* @package Kiri\Core
*/
class Xml
{
/**
* @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
*/
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);
}
}
}
-438
View File
@@ -1,438 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:27
*/
declare(strict_types=1);
namespace Kiri\Di;
use Annotation\Inject;
use Closure;
use Exception;
use Kiri\Abstracts\BaseObject;
use Kiri\Abstracts\Logger;
use Kiri\Kiri;
use Psr\Log\LoggerInterface;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionProperty;
/**
* Class Container
* @package Kiri\Di
*/
class Container extends BaseObject implements ContainerInterface
{
/**
* @var array
*
* instance class by className
*/
private array $_singletons = [];
/**
* @var ReflectionMethod[]
*
* class new instance construct parameter
*/
private array $_constructs = [];
/**
* @var array
*
* implements \ReflectClass
*/
private array $_reflection = [];
/** @var array */
private array $_parameters = [];
/** @var array|string[] */
private array $_interfaces = [
LoggerInterface::class => Logger::class
];
/**
* @param $class
* @param array $constrict
* @param array $config
*
* @return mixed
* @throws
*/
public function get($class, array $constrict = [], array $config = []): mixed
{
if ($this->isInterface($class)) {
$class = $this->_interfaces[$class];
}
if (!isset($this->_singletons[$class])) {
$this->_singletons[$class] = $this->resolve($class, $constrict, $config);
}
return $this->_singletons[$class];
}
/**
* @param string $interface
* @param string $class
*/
public function mapping(string $interface, string $class)
{
$this->_interfaces[$interface] = $class;
}
/**
* @param $class
* @return bool
* @throws ReflectionException
*/
public function isInterface($class): bool
{
$reflect = $this->getReflect($class);
if ($reflect->isInterface()) {
return true;
}
return false;
}
/**
* @param string $interface
* @param $object
*/
public function setBindings(string $interface, $object)
{
if (is_string($object)) {
$this->_interfaces[$interface] = $object;
} else {
$className = get_class($object);
$this->_interfaces[$interface] = $className;
$this->_singletons[$className] = $object;
}
}
/**
* @param $class
* @param array $constrict
* @param array $config
* @return object
* @throws
*/
public function create($class, array $constrict = [], array $config = []): object
{
return $this->resolve($class, $constrict, $config);
}
/**
* @param $class
* @param $constrict
* @param $config
*
* @return object
* @throws Exception
*/
private function resolve($class, $constrict, $config): object
{
$reflect = $this->resolveDependencies($class);
if (!$reflect->isInstantiable()) {
throw new ReflectionException('Class ' . $class . ' cannot be instantiated');
}
$object = $this->newInstance($reflect, $constrict);
$this->propertyInject($reflect, $object);
return $this->onAfterInit($object, $config);
}
/**
* @param ReflectionClass $reflect
* @param $dependencies
* @return object
* @throws ReflectionException
*/
private function newInstance(ReflectionClass $reflect, $dependencies): object
{
if (!isset($this->_constructs[$reflect->getName()])) {
return $reflect->newInstance();
}
$construct = $this->_constructs[$reflect->getName()];
if ($construct->getNumberOfParameters() < 1) {
return $reflect->newInstance();
}
$parameters = $this->mergeParam($this->resolveMethodParameters($construct), $dependencies);
return $reflect->newInstanceArgs($parameters);
}
/**
* @param ReflectionClass $reflect
* @param $object
* @return mixed
* @throws Exception
*/
public function propertyInject(ReflectionClass $reflect, $object): mixed
{
foreach (NoteManager::getPropertyNote($reflect) as $property => $inject) {
/** @var Inject $inject */
$inject->execute($object, $property);
}
return $object;
}
/**
* @param $className
* @param $method
* @return array
* @throws ReflectionException
*/
public function getMethodAttribute($className, $method = null): array
{
$methods = NoteManager::getMethodNote($this->getReflect($className));
if (!empty($method)) {
return $methods[$method] ?? [];
}
return $methods;
}
/**
* @param string $class
* @param string|null $property
* @return ReflectionProperty|ReflectionProperty[]|null
* @throws ReflectionException
*/
public function getClassReflectionProperty(string $class, string $property = null): ReflectionProperty|null|array
{
$lists = NoteManager::getProperty($this->getReflect($class));
if (empty($lists)) {
return null;
}
if (!empty($property)) {
return $lists[$property] ?? null;
}
return $lists;
}
/**
* @param $object
* @param $config
* @return mixed
*/
private function onAfterInit($object, $config): mixed
{
Kiri::configure($object, $config);
if (method_exists($object, 'init') && is_callable([$object, 'init'])) {
call_user_func([$object, 'init']);
}
return $object;
}
/**
* @param $class
* @return ReflectionClass
* @throws ReflectionException
*/
private function resolveDependencies($class): ReflectionClass
{
if (isset($this->_reflection[$class])) {
return $this->_reflection[$class];
}
$reflect = new ReflectionClass($class);
if ($reflect->isAbstract() || $reflect->isTrait() || $reflect->isInterface()) {
return $this->_reflection[$class] = $reflect;
}
$construct = NoteManager::resolveTarget($reflect);
if (!empty($construct) && $construct->getNumberOfParameters() > 0) {
$this->_constructs[$class] = $construct;
}
return $this->_reflection[$class] = $reflect;
}
/**
* @param ReflectionClass|string $class
* @return ReflectionMethod[]
* @throws ReflectionException
*/
public function getReflectMethods(ReflectionClass|string $class): array
{
if (is_string($class)) {
$class = $this->getReflect($class);
}
return NoteManager::getMethods($class);
}
/**
* @param ReflectionClass|string $class
* @param string $method
* @return ReflectionMethod|null
* @throws ReflectionException
*/
public function getReflectMethod(ReflectionClass|string $class, string $method): ?ReflectionMethod
{
return $this->getReflectMethods($class)[$method] ?? null;
}
/**
* @param string $className
* @param string $method
* @return array|null
* @throws ReflectionException
*/
public function getMethodParameters(string $className, string $method): ?array
{
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$method])) {
return $this->_parameters[$className][$method];
}
$reflectMethod = $this->getReflectMethod($this->getReflect($className), $method);
if (!($reflectMethod instanceof ReflectionMethod)) {
throw new ReflectionException("Class does not have a function $className::$method");
}
$className = $reflectMethod->getDeclaringClass()->getName();
if (isset($this->_parameters[$className]) && isset($this->_parameters[$className][$reflectMethod->getName()])) {
return $this->_parameters[$className][$reflectMethod->getName()];
}
return $this->setParameters($className, $reflectMethod->getName(), $this->resolveMethodParameters($reflectMethod));
}
/**
* @param $class
* @param $method
* @param $parameters
* @return mixed
*/
private function setParameters($class, $method, $parameters): mixed
{
if (!isset($this->_parameters[$class])) {
$this->_parameters[$class] = [];
}
if (!isset($this->_parameters[$class][$method])) {
$this->_parameters[$class][$method] = [];
}
return $this->_parameters[$class][$method] = $parameters;
}
/**
* @param Closure $reflectionMethod
* @return array
* @throws ReflectionException
*/
public function getFunctionParameters(Closure $reflectionMethod): array
{
return $this->resolveMethodParameters(new ReflectionFunction($reflectionMethod));
}
/**
* @param ReflectionMethod|ReflectionFunction $reflectionMethod
* @return array
* @throws ReflectionException
*/
private function resolveMethodParameters(ReflectionMethod|ReflectionFunction $reflectionMethod): array
{
if ($reflectionMethod->getNumberOfParameters() < 1) {
return [];
}
$params = [];
foreach ($reflectionMethod->getParameters() as $key => $parameter) {
if ($parameter->isDefaultValueAvailable()) {
$params[$key] = $parameter->getDefaultValue();
} else if ($parameter->getType() === null) {
$params[$key] = $parameter->getType();
} else {
$type = $parameter->getType()->getName();
if (is_string($type) && class_exists($type) || isset($this->_interfaces[$type])) {
$type = Kiri::getDi()->get($type);
}
$params[$key] = match ($parameter->getType()) {
'string' => '',
'int', 'float' => 0,
'', null, 'object', 'mixed' => NULL,
'bool' => false,
default => $type
};
}
}
return $params;
}
/**
* @param $class
* @return ReflectionClass|null
* @throws ReflectionException
*/
public function getReflect($class): ?ReflectionClass
{
if (!isset($this->_reflection[$class])) {
return $this->resolveDependencies($class);
}
return $this->_reflection[$class];
}
/**
* @param $class
*/
public function unset($class)
{
if (is_array($class) && isset($class['class'])) {
$class = $class['class'];
} else if (is_object($class)) {
$class = $class::class;
}
unset(
$this->_reflection[$class], $this->_singletons[$class], $this->_constructs[$class]
);
}
/**
* @return $this
*/
public function flush(): static
{
$this->_reflection = [];
$this->_singletons = [];
$this->_constructs = [];
return $this;
}
/**
* @param $old
* @param $newParam
*
* @return mixed
*/
private function mergeParam($old, $newParam): array
{
if (empty($old)) {
return $newParam;
} else if (empty($newParam)) {
return $old;
}
foreach ($newParam as $key => $val) {
$old[$key] = $val;
}
return $old;
}
}
-12
View File
@@ -1,12 +0,0 @@
<?php
namespace Kiri\Di;
/**
* @mixin Container
*/
interface ContainerInterface
{
}
-88
View File
@@ -1,88 +0,0 @@
<?php
namespace Kiri\Di;
use Kiri\Abstracts\Component;
use Kiri\Kiri;
/**
* 服务定位器
*/
class LocalService extends Component
{
private array $_components = [];
private array $_definition = [];
/**
* @param $name
* @param $define
*/
public function set($name, $define)
{
unset($this->_components[$name]);
$this->_definition[$name] = $define;
if (is_object($define) || $define instanceof \Closure) {
$this->_components[$name] = $define;
}
}
/**
* @throws \Exception
*/
public function get(string $name, $throwException = true)
{
if (isset($this->_components[$name])) {
return $this->_components[$name];
}
if (isset($this->_definition[$name])) {
$definition = $this->_definition[$name];
if (is_object($definition) && !$definition instanceof \Closure) {
return $this->_components[$name] = $definition;
}
return $this->_components[$name] = Kiri::createObject($definition);
} else if ($throwException) {
throw new \Exception("Unknown component ID: $name");
}
return null;
}
/**
* @param array $components
*/
public function setComponents(array $components)
{
foreach ($components as $name => $component) {
$this->set($name, $component);
}
}
/**
* @param $id
* @return bool
*/
public function has($id): bool
{
return isset($this->_components[$id]) || isset($this->_definition[$id]);
}
/**
* @param $id
*/
public function remove($id): void
{
unset($this->_components[$id], $this->_definition[$id]);
}
}
-289
View File
@@ -1,289 +0,0 @@
<?php
namespace Kiri\Di;
use JetBrains\PhpStorm\Pure;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionProperty;
class NoteManager
{
private static array $_classTarget = [];
private static array $_classMethodNote = [];
private static array $_classMethod = [];
private static array $_classPropertyNote = [];
private static array $_classProperty = [];
private static array $_mapping = [];
/**
* @param ReflectionClass $class
*/
public static function setTargetNote(ReflectionClass $class)
{
$className = $class->getName();
if (!isset(static::$_classTarget[$className])) {
static::$_classTarget[$className] = [];
}
foreach ($class->getAttributes() as $attribute) {
if (!class_exists($attribute->getName())) {
continue;
}
$instance = $attribute->newInstance();
static::$_classTarget[$className][] = $instance;
self::setMappingClass($attribute, $className);
}
}
/**
* @param ReflectionAttribute $attribute
* @param string $class
*/
public static function setMappingClass(ReflectionAttribute $attribute, string $class)
{
if (!isset(static::$_mapping[$attribute->getName()])) {
static::$_mapping[$attribute->getName()] = [];
}
if (!isset(static::$_mapping[$attribute->getName()][$class])) {
static::$_mapping[$attribute->getName()][$class] = [];
}
}
/**
* @param ReflectionAttribute $attribute
* @param string $class
* @param string $method
* @param mixed $instance
*/
public static function setMappingMethod(ReflectionAttribute $attribute, string $class, string $method, mixed $instance)
{
self::setMappingClass($attribute, $class);
if (!isset(static::$_mapping[$attribute->getName()][$class]['method'])) {
static::$_mapping[$attribute->getName()][$class]['method'] = [];
}
static::$_mapping[$attribute->getName()][$class]['method'][] = [$method => $instance];
}
/**
* @param ReflectionAttribute $attribute
* @param string $class
* @param string $property
* @param $instance
*/
public static function setMappingProperty(ReflectionAttribute $attribute, string $class, string $property, $instance)
{
self::setMappingClass($attribute, $class);
$mapping = static::$_mapping[$attribute->getName()][$class];
if (!isset($mapping['property'])) {
$mapping['property'] = [];
}
$mapping['property'][] = [$property => $instance];
static::$_mapping[$attribute->getName()][$class] = $mapping;
}
/**
* @param mixed $class
* @return array
*/
public static function getTargetNote(mixed $class): array
{
if (!is_string($class)) {
$class = $class::class;
}
return static::$_classTarget[$class] ?? [];
}
/**
* @param ReflectionClass $class
*/
public static function setMethodNote(ReflectionClass $class)
{
$className = $class->getName();
static::$_classMethodNote[$className] = static::$_classMethod[$className] = [];
foreach ($class->getMethods() as $ReflectionMethod) {
static::$_classMethod[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
static::$_classMethodNote[$className][$ReflectionMethod->getName()] = [];
foreach ($ReflectionMethod->getAttributes() as $attribute) {
if (!class_exists($attribute->getName())) {
continue;
}
$instance = $attribute->newInstance();
static::$_classMethodNote[$className][$ReflectionMethod->getName()][] = $instance;
self::setMappingMethod($attribute, $className, $ReflectionMethod->getName(), $instance);
}
}
}
/**
* @param string $class
* @param string $method
* @return bool
*/
public static function hasMethod(string $class, string $method): bool
{
return isset(static::$_classMethod[$class]) && isset(static::$_classMethod[$class][$method]);
}
/**
* @param ReflectionClass $class
* @return array
*/
#[Pure] public static function getMethodNote(ReflectionClass $class): array
{
return static::$_classMethodNote[$class->getName()] ?? [];
}
/**
* @param \ReflectionClass $reflect
* @return \ReflectionMethod|null
*/
public static function resolveTarget(ReflectionClass $reflect): ?\ReflectionMethod
{
NoteManager::setPropertyNote($reflect);
NoteManager::setTargetNote($reflect);
NoteManager::setMethodNote($reflect);
return $reflect->getConstructor();
}
/**
* @param ReflectionClass $class
*/
public static function setPropertyNote(ReflectionClass $class)
{
$className = $class->getName();
static::$_classProperty[$className] = static::$_classPropertyNote[$className] = [];
foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PUBLIC |
ReflectionProperty::IS_PROTECTED) as $ReflectionMethod) {
static::$_classProperty[$className][$ReflectionMethod->getName()] = $ReflectionMethod;
foreach ($ReflectionMethod->getAttributes() as $attribute) {
if (!class_exists($attribute->getName())) {
continue;
}
$instance = $attribute->newInstance();
static::$_classPropertyNote[$className][$ReflectionMethod->getName()] = $instance;
self::setMappingProperty($attribute, $className, $ReflectionMethod->getName(), $instance);
}
}
}
/**
* @param string $attribute
* @param string|null $class
* @return array[]
*/
public static function getAttributeTrees(string $attribute, string $class = null): array
{
$mapping = static::$_mapping[$attribute] ?? [];
if (empty($mapping) || empty($class)) {
return $mapping;
}
return $mapping[$class] ?? [];
}
/**
* @param string $attribute
* @param string $class
* @param string|null $method
* @return array
*/
public static function getSpecify_annotation(string $attribute, string $class, string $method = null): mixed
{
$class = self::getAttributeTrees($attribute, $class);
if (empty($class) || !isset($class['method'])){
return null;
}
if (empty($method)) {
return $class['method'];
}
foreach ($class['method'] as $value) {
$key = key($value);
if ($method == $key) {
return $value[$key];
}
}
return null;
}
/**
* @param string $attribute
* @param string $class
* @param string $method
* @return mixed
*/
public static function getPropertyByAnnotation(string $attribute, string $class, string $method): mixed
{
$class = self::getAttributeTrees($attribute, $class);
if (empty($class) || !isset($class['property'])) {
return [];
}
foreach ($class['property'] as $value) {
$key = key($value);
if ($method == $key) {
return $value[$key];
}
}
return null;
}
/**
* @param ReflectionClass|string $class
* @return array
* @throws \ReflectionException
*/
public static function getMethods(ReflectionClass|string $class): array
{
if (is_string($class)) {
$class = self::getReflect($class);
}
return static::$_classMethod[$class->getName()] ?? [];
}
/**
* @param ReflectionClass $class
* @return ReflectionProperty[]
*/
#[Pure] public static function getProperty(ReflectionClass $class): array
{
return static::$_classProperty[$class->getName()] ?? [];
}
/**
* @param ReflectionClass $class
* @return array
*/
#[Pure] public static function getPropertyNote(ReflectionClass $class): array
{
return static::$_classPropertyNote[$class->getName()] ?? [];
}
}
+39 -46
View File
@@ -1,46 +1,39 @@
<?php
namespace Kiri;
use JetBrains\PhpStorm\Pure;
/**
* Class Environmental
* @package Kiri
*/
class Environmental
{
/**
* @return bool
*/
public function isMac(): bool
{
$output = strtolower(PHP_OS | PHP_OS_FAMILY);
if (str_contains('mac', $output)) {
return true;
} else if (str_contains('darwin', $output)) {
return true;
} else {
return false;
}
}
/**
* @return bool
*/
#[Pure] public function isLinux(): bool
{
if (!static::isMac()) {
return true;
} else {
return false;
}
}
}
<?php
declare(strict_types=1);
namespace Kiri;
use JetBrains\PhpStorm\Pure;
/**
* Class Environmental
* @package Kiri
*/
class Environmental
{
/**
* @return bool
*/
public function isMac(): bool
{
$os = strtolower(PHP_OS);
return str_contains($os, 'mac') || str_contains($os, 'darwin');
}
/**
* @return bool
*/
#[Pure] public function isLinux(): bool
{
return PHP_OS_FAMILY === 'Linux' || strtolower(PHP_OS) === 'linux';
}
}
+128 -158
View File
@@ -1,158 +1,128 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/26 0026
* Time: 10:00
*/
declare(strict_types=1);
namespace Kiri\Error;
use Exception;
use Http\Handler\Formatter\IFormatter;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri\Events\EventDispatch;
use Kiri\Kiri;
use Http\Events\OnAfterRequest;
/**
* Class ErrorHandler
*
* @package Kiri\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()
{
// ini_set('display_errors', '1');
set_exception_handler([$this, 'exceptionHandler']);
if (defined('HHVM_VERSION')) {
set_error_handler([$this, 'errorHandler']);
} else {
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']);
}
/**
* @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());
}
/**
* @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());
throw new \ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
}
/**
* @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];
var_dump(func_get_args());
$data = Json::to($code, $this->category . ': ' . $message, $path);
write($data, $this->category);
return $data;
}
/**
* @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 $message
* @param string $category
*
* @throws Exception
*/
public function writer($message, string $category = 'app')
{
Kiri::app()->debug($message, $category);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/26 0026
* Time: 10:00
*/
declare(strict_types=1);
namespace Kiri\Error;
use Closure;
use ErrorException;
use Kiri\Abstracts\Component;
use Kiri\Events\OnSystemError;
use Throwable;
/**
* Class ErrorHandler
* @package Kiri\Base
* @property-read $asError
*/
class ErrorHandler extends Component implements ErrorInterface
{
/**
* @var string
*/
public string $category = 'app';
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @return void
* @throws
* @throws
*/
public function shutdown(): void
{
$lastError = error_get_last();
if (empty($lastError) || $lastError['type'] !== E_ERROR) {
return;
}
$this->getLogger()->println(json_encode($lastError,JSON_UNESCAPED_UNICODE));
event(new OnSystemError());
}
/**
* @param Throwable $exception
*
* @throws
*/
public function exceptionHandler(Throwable $exception): void
{
$this->category = 'exception';
$this->getLogger()->println(throwable($exception));
json_log($exception);
event(new OnSystemError());
}
/**
* @throws
*/
public function errorHandler()
{
$error = func_get_args();
$this->getLogger()->println(json_encode($error,JSON_UNESCAPED_UNICODE));
event(new OnSystemError());
throw new ErrorException($error[1], $error[0], 1, $error[2], $error[3]);
}
}
+19 -28
View File
@@ -1,28 +1,19 @@
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 10:25
*/
declare(strict_types=1);
namespace Kiri\Error;
/**
* Interface ErrorInterface
* @package Kiri\Kiri\Error
*/
interface ErrorInterface
{
/**
* @param $message
* @param $file
* @param $line
* @param int $code
* @return mixed
*/
public function sendError($message, $file, $line, $code = 500): mixed;
}
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-20
* Time: 10:25
*/
declare(strict_types=1);
namespace Kiri\Error;
/**
* Interface ErrorInterface
* @package Kiri\Error
*/
interface ErrorInterface
{
}
-111
View File
@@ -1,111 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019-03-22
* Time: 14:36
*/
declare(strict_types=1);
namespace Kiri\Error;
use Annotation\Inject;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Core\Json;
use Kiri\Events\EventProvider;
use Kiri\Kiri;
use Psr\Log\LoggerInterface;
use Throwable;
/**
* Class Logger
* @package Kiri\Kiri\Error
* @mixin \Kiri\Abstracts\Logger
*/
class Logger extends Component
{
private array $logs = [];
/** @var EventProvider */
#[Inject(EventProvider::class)]
public EventProvider $eventProvider;
/**
* 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 'Unknown error.';
}
/**
* @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);
}
}
}
-52
View File
@@ -1,52 +0,0 @@
<?php
namespace Kiri\Error;
use Exception;
use Http\Aspect\OnAspectInterface;
use Http\Aspect\OnJoinPointInterface;
use Http\Constrict\RequestInterface;
use Kiri\Kiri;
/**
* 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);
echo sprintf('run %s use time %6f', $request->getUri()->__toString(), $runTime);
echo PHP_EOL;
}
}
-83
View File
@@ -1,83 +0,0 @@
<?php
namespace Kiri\Error;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Core\Json;
use Kiri\Exception\ComponentException;
use Kiri\Kiri;
use Swoole\Coroutine;
use Swoole\Process;
use Server\Abstracts\BaseProcess;
/**
* 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 Process $process
* @throws ComponentException
* @throws Exception
*/
public function message(Process $process)
{
$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 {} \;');
}
}
+154
View File
@@ -0,0 +1,154 @@
<?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 Throwable;
/**
* @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('site.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 logCategory($message, string $model = 'app'): bool
{
if ($message instanceof \Exception) {
$this->errors[$model] = $message->getMessage();
} else {
$this->errors[$model] = $message;
}
$this->println($message);
return false;
}
/**
* @param Throwable $exception
* @param array $data
* @param mixed|null $result
* @return bool
*/
public function json_log(Throwable $exception, array $data = [], mixed $result = null): mixed
{
json_log($exception, $data);
$this->println($exception->getMessage());
return $result;
}
/**
* @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) {
$this->println($exception->getMessage());
$this->json_log($exception);
}
}
/**
* @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.';
}
}
-239
View File
@@ -1,239 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri;
use Exception;
use Kiri\Abstracts\BaseObject;
use Swoole\Coroutine;
/**
* Class Event
* @package Kiri
*/
class Event extends BaseObject
{
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;
}
}
}
+18 -16
View File
@@ -1,16 +1,18 @@
<?php
namespace Kiri\Events;
class OnAfterCommandExecute
{
/**
*
*/
public function __construct()
{
}
}
<?php
namespace Kiri\Events;
use Symfony\Component\Console\Command\Command;
class OnAfterCommandExecute
{
/**
* @param Command $command
*/
public function __construct(public Command $command)
{
}
}
+18 -8
View File
@@ -1,8 +1,18 @@
<?php
namespace Kiri\Events;
class OnBeforeCommandExecute
{
}
<?php
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
{
}
+29 -29
View File
@@ -1,29 +1,29 @@
<?php
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class AuthException
* @package Kiri\Exception
*/
class AuthException extends \Exception
{
/**
* AuthException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, 4001, $previous);
}
}
<?php
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class AuthException
* @package Kiri\Exception
*/
class AuthException extends \Exception
{
/**
* AuthException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
parent::__construct($message, 4001, $previous);
}
}
+35 -35
View File
@@ -1,35 +1,35 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/25 0025
* Time: 18:34
*/
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class ComponentException
* @package Kiri\Kiri\Exception
*/
class ComponentException extends \Exception
{
/**
* ComponentException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = NULL)
{
parent::__construct($message, 5000, $previous);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/25 0025
* Time: 18:34
*/
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class ComponentException
* @package Kiri\Exception
*/
class ComponentException extends \Exception
{
/**
* ComponentException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = NULL)
{
parent::__construct($message, 5000, $previous);
}
}
+15 -15
View File
@@ -1,15 +1,15 @@
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class ConfigException
* @package Kiri\Exception
*/
class ConfigException extends \Exception
{
}
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class ConfigException
* @package Kiri\Exception
*/
class ConfigException extends \Exception
{
}
+14 -14
View File
@@ -1,14 +1,14 @@
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class InitException
* @package Kiri\Exception
*/
class InitException extends \Exception
{
}
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class InitException
* @package Kiri\Exception
*/
class InitException extends \Exception
{
}
+36 -36
View File
@@ -1,36 +1,36 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:32
*/
declare(strict_types=1);
namespace Kiri\Exception;
use JetBrains\PhpStorm\Pure;
use Throwable;
/**
* Class NotFindClassException
* @package Kiri\Kiri\Exception
*/
class NotFindClassException extends \Exception
{
/**
* NotFindClassException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
#[Pure] public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
$message = "No class named `$message` was found, please check if the class name is correct";
parent::__construct($message, 404, $previous);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:32
*/
declare(strict_types=1);
namespace Kiri\Exception;
use JetBrains\PhpStorm\Pure;
use Throwable;
/**
* Class NotFindClassException
* @package Kiri\Exception
*/
class NotFindClassException extends \Exception
{
/**
* NotFindClassException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
#[Pure] public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
$message = "No class named `$message` was found, please check if the class name is correct";
parent::__construct($message, 404, $previous);
}
}
@@ -1,35 +1,35 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:32
*/
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class NotFindClassException
* @package Kiri\Kiri\Exception
*/
class NotFindPropertyException extends \Exception
{
/**
* NotFindClassException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
$message = "No class named `$message` was found, please check if the class name is correct";
parent::__construct($message, 404, $previous);
}
}
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/24 0024
* Time: 17:32
*/
declare(strict_types=1);
namespace Kiri\Exception;
use Throwable;
/**
* Class NotFindClassException
* @package Kiri\Exception
*/
class NotFindPropertyException extends \Exception
{
/**
* NotFindClassException constructor.
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
{
$message = "No class named `$message` was found, please check if the class name is correct";
parent::__construct($message, 404, $previous);
}
}
+15 -15
View File
@@ -1,15 +1,15 @@
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class RedisConnectException
* @package Kiri\Exception
*/
class RedisConnectException extends \Exception
{
}
<?php
declare(strict_types=1);
namespace Kiri\Exception;
/**
* Class RedisConnectException
* @package Kiri\Exception
*/
class RedisConnectException extends \Exception
{
}
-154
View File
@@ -1,154 +0,0 @@
<?php
namespace Kiri\FileListen;
use Annotation\Inject;
use Exception;
use Kiri\Abstracts\Config;
use Kiri\Error\Logger;
use Kiri\Exception\ConfigException;
use Kiri\Kiri;
use Swoole\Coroutine;
use Swoole\Process;
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');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
* @throws ConfigException
* @throws Exception
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
// TODO: Implement onHandler() method.
set_error_handler([$this, 'onErrorHandler']);
$this->dirs = Config::get('inotify', [APP_PATH . 'app']);
swoole_async_set(['enable_coroutine' => false]);
if (!extension_loaded('inotify')) {
$this->driver = Kiri::getDi()->get(Scaner::class, [$this->dirs, $this]);
} else {
$this->driver = Kiri::getDi()->get(Inotify::class, [$this->dirs, $this]);
}
if (Kiri::getPlatform()->isLinux()) {
swoole_set_process_name('[' . Config::get('id', 'sw service.') . '].sw:wather');
}
$this->trigger_reload();
var_dump(getmypid());
Process::signal(SIGTERM, [$this, 'onSignal']);
Process::signal(SIGKILL, [$this, 'onSignal']);
$this->driver->start();
return 0;
}
/**
* @param $data
* @throws Exception
*/
public function onSignal($data)
{
if (!$data) {
return;
}
$this->driver->clear();
$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);
}
while ($ret = Process::wait(true)) {
echo "PID={$ret['pid']}\n";
sleep(1);
}
}
/**
* @param $code
* @param $message
* @param $file
* @param $line
* @throws Exception
*/
public function onErrorHandler($code, $message, $file, $line)
{
if (str_contains($message, 'The file descriptor is not an inotify instance')) {
return;
}
debug('Error:' . $message . ' at ' . $file . ':' . $line);
}
/**
* 重启
*
* @throws Exception
*/
public function trigger_reload()
{
$this->logger->warning('change reload');
$pid = $this->process?->pid;
$process = new Process(function (Process $process) {
$process->exec(PHP_BINARY, [APP_PATH . "kiri.php", "sw:server", "restart"]);
});
$process->start();
if ($pid && Process::kill($pid, 0)) {
Process::kill($pid) && Process::wait(true);
}
$this->process = null;
$this->process = $process;
}
}
-158
View File
@@ -1,158 +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 = [];
protected 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)
{
}
/**
* @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);
}
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;
}
//非重启类型
if (str_ends_with($ev['name'], '.php')) {
Timer::after(3000, fn()=>$this->reload());
$this->isReloading = TRUE;
}
}
}
/**
* @throws Exception
*/
public function reload()
{
$this->process->trigger_reload();
$this->clearWatch();
foreach ($this->dirs as $root) {
$this->watch($root);
}
$this->process->int = -1;
$this->isReloading = FALSE;
}
/**
* @throws Exception
*/
public function clearWatch()
{
foreach ($this->watchFiles as $wd) {
try {
inotify_rm_watch($this->inotify, $wd);
} catch (\Throwable $exception) {
logger()->addError($exception, 'throwable');
}
}
$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;
}
}
-147
View File
@@ -1,147 +0,0 @@
<?php
namespace Kiri\FileListen;
use Exception;
class Scaner
{
private array $md5Map = [];
/**
* @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->timerReload();
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()
{
if ($this->process->isReloading) {
return;
}
$this->process->isReloading = true;
$this->process->trigger_reload();
$this->process->int = -1;
$this->loadDirs();
$this->process->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->process->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();
}
-57
View File
@@ -1,57 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Jwt;
use Annotation\Inject;
use Exception;
use Http\Message\ServerRequest;
use Kiri\Kiri;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Server\Constrict\ResponseInterface;
/**
* Class CoreMiddleware
* @package Kiri\Kiri\Route
* 跨域中间件
*/
class JWTAuthMiddleware implements MiddlewareInterface
{
/** @var int */
public int $zOrder = 0;
#[Inject(ResponseInterface::class)]
public ResponseInterface $response;
/**
* @param ServerRequest $request
* @param RequestHandlerInterface $handler
* @return \Psr\Http\Message\ResponseInterface
* @throws Exception
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): \Psr\Http\Message\ResponseInterface
{
$authorization = $request->getHeaderLine('Authorization');
if (empty($authorization)) {
return $this->response->json(['code' => 401, 'JWT voucher cannot be empty.']);
}
if (!str_starts_with($authorization, 'Bearer ')) {
return $this->response->json(['code' => 401, 'JWT Voucher Format Error.']);
}
$authorization = str_replace('Bearer ', '', $authorization);
$jwt = Kiri::app()->getJwt();
if (!$jwt->validator($authorization)) {
return $this->response->json(['code' => 401, 'JWT Validator fail.']);
}
return $handler->handle($request);
}
}
-27
View File
@@ -1,27 +0,0 @@
<?php
namespace Kiri\Jwt;
use JetBrains\PhpStorm\Pure;
use Throwable;
/**
*
*/
class JWTAuthTokenException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
#[Pure] public function __construct($message = "", $code = 4001, Throwable $previous = null)
{
parent::__construct($message, 4001, $previous);
}
}
-201
View File
@@ -1,201 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Jwt;
use Annotation\Inject;
use Exception;
use Http\Constrict\RequestInterface;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Exception\ConfigException;
/**
* Class Jwt
* @package Kiri\Jwt
*/
class Jwt extends Component
{
use JwtHelper;
#[Inject(RequestInterface::class)]
private RequestInterface $request;
/**
* @param RequestInterface $request
*/
public function setRequest(RequestInterface $request): void
{
$this->request = $request;
}
/**
* @throws ConfigException
* @throws Exception
* 'jwt' => [
* 'scene' => 'application',
* 'timeout' => 7200,
* 'encrypt' => '',
* 'iv' => '',
* 'key' => '',
* ]
*/
public function init()
{
$this->request = di(RequestInterface::class);
$this->public = Config::get('ssl.public', $this->public);
$this->private = Config::get('ssl.private', $this->private);
$this->timeout = Config::get('jwt.timeout', 7200);
$jwt = Config::get('jwt', []);
if ($jwt) {
$this->setScene($jwt['scene'] ?? 'application');
$this->setKey($jwt['key'] ?? get_called_class());
$length = openssl_cipher_iv_length($this->encrypt);
if ($length > 0) {
$defaultIv = openssl_random_pseudo_bytes($length);
$this->setIv($jwt['iv'] ?? $defaultIv);
}
}
}
/**
* @param int $unionId
*
* @return string
* @throws Exception
*/
public function create(int $unionId): string
{
$this->user = $unionId;
$this->config['time'] = time();
$this->data = $this->request->getHeaders();
if (!isset($this->data['source'])) {
$this->data['source'] = 'browser';
}
return $this->createEncrypt($unionId);
}
/**
* @return string
*/
private function jwtHeader(): string
{
$string = openssl_encrypt(
json_encode(['type' => 'openssl', 'encrypt' => $this->encrypt]),
$this->encrypt,
$this->key,
0,
$this->iv
);
return str_replace('=', '', $string);
}
/**
* @param $unionId
* @return string
* @throws Exception
*/
private function jwtBody($unionId): string
{
$json = json_encode(['unionId' => $unionId, 'createTime' => time(), 'expire_at' => time() + $this->timeout]);
openssl_private_encrypt($json, $encode, $this->private);
return base64_encode($encode);
}
/**
* @param $unionId
* @return string
* @throws Exception
*/
private function createEncrypt($unionId): string
{
$params[] = $this->jwtHeader();
$params[] = $this->jwtBody($unionId);
$params[] = hash('sha256', $params[0] . $params[1]);
return implode('.', $params);
}
/**
* @param $token
* @return string|int
* @throws JWTAuthTokenException
*/
public function getUnionId($token): string|int
{
$unpack = $this->unpack($token);
if (!$this->_validator($unpack)) {
throw new JWTAuthTokenException('JWT certificate has expired.');
}
return $unpack['unionId'];
}
/**
* @param $token
* @return bool
* @throws JWTAuthTokenException
*/
public function validator($token): bool
{
return $this->_validator($this->unpack($token));
}
/**
* @param $unpack
* @return bool
*/
private function _validator($unpack): bool
{
if ($unpack['expire_at'] < time()) {
return false;
}
return true;
}
/**
* @param $token
* @return string
* @throws JWTAuthTokenException
* @throws Exception
*/
public function refresh($token): string
{
return $this->create($this->unpack($token)['unionId']);
}
/**
* @param string $token
* @return mixed
* @throws JWTAuthTokenException
*/
private function unpack(string $token): array
{
if (count($explode = explode('.', $token)) != 3) {
throw new JWTAuthTokenException('JWT Voucher Format Error.');
}
if (hash('sha256', $explode[0] . $explode[1]) != $explode[2]) {
throw new JWTAuthTokenException('JWT Sign Validator Fail.');
}
if (!openssl_public_decrypt(base64_decode($explode[1]), $decode, $this->public)) {
throw new JWTAuthTokenException('JWT Voucher Unpack Error.');
}
return Json::decode($decode, true);
}
}
-134
View File
@@ -1,134 +0,0 @@
<?php
namespace Kiri\Jwt;
trait JwtHelper
{
/** @var int $user */
private int $user;
private array $data;
private array $source = ['browser', 'android', 'iphone', 'pc', 'mingame'];
private array $config = ['token' => ''];
private ?int $timeout = 7200;
private string $key = 'www.xshucai.com';
private string $secret = '';
private string $scene = 'default';
private string $encrypt = 'aes-128-ecb';
private string $iv = '';
private ?string $public = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6BuML3gtLGde7QKNuNST
UCB9gdHC7XIpOc7Wx2I64Esj3UxWHTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6Xad
jqfjEWpTy4WwGYsOfH0tFl3wAmse0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5t
WhTMEnpTFDYoDR0KXlLXltQMudBBUHFaVwP0wKJ/cGX7R1Mrv35K4MXwQFOuGZkP
hsp2rO9x5LjtSKIXbexy7WhUu6QMjD/XzgsXr9UF+ExYmBGXRVWgNFLMkiaCZ2Uz
WlQhpQrA5/wKd76dCzjvqw9M32OiZl2lCKT73cV8GUvt7BNsM1SiPhqfY7nhO6y3
cwIDAQAB
-----END PUBLIC KEY-----';
private ?string $private = '-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA6BuML3gtLGde7QKNuNSTUCB9gdHC7XIpOc7Wx2I64Esj3UxW
HTgp3URj0ge8zpy7A3FfBdppR7d1nwoD6XadjqfjEWpTy4WwGYsOfH0tFl3wAmse
0lebF4NFsS9pzrikQT6c9qsVm88pCjvg4i5tWhTMEnpTFDYoDR0KXlLXltQMudBB
UHFaVwP0wKJ/cGX7R1Mrv35K4MXwQFOuGZkPhsp2rO9x5LjtSKIXbexy7WhUu6QM
jD/XzgsXr9UF+ExYmBGXRVWgNFLMkiaCZ2UzWlQhpQrA5/wKd76dCzjvqw9M32Oi
Zl2lCKT73cV8GUvt7BNsM1SiPhqfY7nhO6y3cwIDAQABAoIBADPihJHP8XktmmCs
43Vfv5Z3zNaKR2LA1Eph3E0xviuJYHkFqXJarbESqqW2qRQeoQeB/lXWnxYzAo4M
tRcpNss+6FlqRVUHi3gKR7C4Yq3PTemcfIVUpAy7gYa8LJDTYZRcJMZXNDtiMbBh
9kFZU4SBhaTTx2KLQKS9yyWOqzbBvyLXN+1+Wy477M9+MXXTKw79dO+pML6cR0yl
pNfVR5FX5L/GB5vOtQB/Aqg/CKT8NC5MzWPnKY+TPCCHZyoZuB9dLDuWOlqsN4QX
Y4B8fFca5yRwzHra5aGoqdaT/zGctt+I6V/f/KNQCo36f9LPxeXg1+FHvvtTj5WZ
N8CGPzECgYEA9R7lRMXzrHE4rK0DhxQXIFbIKKtxrimqZQdbwOUeYYD2R6CDSItK
z88RSYElmd6wiS7fYIaheXNqJ8Yu6SQFBF/yshBwjQVl9NJG94LJlgx1XnVZEju6
OZjMUOhHXBymtXnLo16pDRl8odc4MFLRH25/vLtwChUr+Qoyt54GzFUCgYEA8mjL
jdh94JAmcdnDXsKgjNOGyNWGDVvWoFmy8lEQsMXY1JJnEd3YfDM2prmv3vaoiXzi
YkSETl6ZUtJqh78MnHCBY1vI6EAcKQAF/kvP2TataRCXNcGNQwn2mtq+B+heTta6
Di8jjAdmdUAYHbmOQryBudiRYG7JEF038elzvKcCgYEAq81ByFguGBkrLev94vkz
1Fi+5bJ0dSuC4Fit+J8eEhz/gOiB26C1iL2LUkeQgS5R8XTG37K9DpDUQJhpXMMA
OTa+tgtLt6um8FdJokUq4V5ODSyWh28RcTklSzfifC8gsWVyU0kPl7zbW9uq6EPD
ixI5uaBuQMLiFSUOsx+xiBkCgYEAtqXHWeVZUy7KCNavomK7XeCzmfdovgAIw2FS
t8nk7YzlR6XYC1pAl7Ru5Ujb/v+TFaUHXkuJ9RLKK+Fna0jEU8thcl/iDTzg+vON
kIHG5j+Qga2CgXqI2Y5URXGz5XlsNbMNFUrnWcbpqEbW5O6/BgHLLSDEyQgwbygN
0zS3g9kCgYEAhssb7kOljdIul4lY5MXc67Zf1dp6S2bucLOxsG6cRW07b3pBz7QF
5aPE7ZwnkzTnA4HuGGauKj+qKGAR7ve55XClAq/XipiVFrjwV/t3LC6j5DoqTJYR
mlAZUEjsoaT9vjvjGTxl3uCm0TX5KTgtSJIt2kA1tYVjQef+/iZTHxY=
-----END RSA PRIVATE KEY-----';
/**
* @param string $publicKey
*/
public function setPublic(string $publicKey)
{
$this->public = $publicKey;
}
/**
* @param int $timeout
*/
public function setTimeout(int $timeout)
{
$this->timeout = $timeout;
}
public function setScene(string $scene)
{
$this->scene = $scene;
}
/**
* @param string $timeout
*/
public function setKey(string $timeout)
{
$this->key = $timeout;
}
/**
* @param string $privateKey
*/
public function setPrivate(string $privateKey)
{
$this->private = $privateKey;
}
/**
* @param string $privateKey
*/
public function setIv(string $privateKey)
{
$this->iv = $privateKey;
}
/**
* @param string $privateKey
*/
public function setEncrypt(string $privateKey)
{
$this->encrypt = $privateKey;
}
}
-624
View File
@@ -1,624 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri;
use Annotation\Annotation;
use Database\Collection;
use Database\ModelInterface;
use Exception;
use JetBrains\PhpStorm\Pure;
use Kiri\Abstracts\Config;
use Kiri\Core\Json;
use Kiri\Di\Container;
use Kiri\Di\ContainerInterface;
use ReflectionException;
use Server\ServerManager;
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', APP_PATH . 'app/Controllers/');
defined('CRONTAB_PATH') or define('CRONTAB_PATH', APP_PATH . 'app/Crontab/');
defined('CLIENT_PATH') or define('CLIENT_PATH', APP_PATH . 'app/Client/');
defined('TASK_PATH') or define('TASK_PATH', APP_PATH . 'app/Async/');
defined('LISTENER_PATH') or define('LISTENER_PATH', APP_PATH . 'app/Listener/');
defined('KAFKA_PATH') or define('KAFKA_PATH', APP_PATH . 'app/Kafka/');
defined('RPC_CLIENT_PATH') or define('RPC_CLIENT_PATH', APP_PATH . 'app/Client/Rpc/');
defined('MODEL_PATH') or define('MODEL_PATH', APP_PATH . 'app/Model/');
/**
* Class Kiri
* @package Kiri
*/
class Kiri
{
/** @var Container */
private static Container $container;
/** @var ?Application */
private static ?Application $service = null;
/**
* @param $service
*
* 初始化服务
*/
public static function init($service)
{
static::$service = $service;
}
/**
* @param Container $container
*/
public static function setContainer(Container $container)
{
$container->setBindings(ContainerInterface::class, $container);
static::$container = $container;
}
/**
* @param $alias
* @param array $array
* @throws Exception
*/
public static function set($alias, array $array = [])
{
static::app()->set($alias, $array);
}
/**
* @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 Application|null
*/
public static function getFactory(): ?Application
{
return static::$service;
}
/**
* @return Application|null
*/
public static function getApplicationContext(): ?Application
{
return static::$service;
}
/**
* @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 $port
* @return bool
* @throws Exception
*/
public static function port_already($port): bool
{
if (empty($port)) {
return false;
}
if (Kiri::getPlatform()->isLinux()) {
exec('netstat -tunlp | grep ' . $port, $output);
} else {
exec('lsof -i :' . $port . ' | grep -i "LISTEN"', $output);
}
return !empty($output);
}
/**
* @return Annotation
* @throws Exception
*/
public static function getAnnotation(): Annotation
{
return static::app()->getAnnotation();
}
/**
* @param $service
* @return string
*/
#[Pure] public static function listen($service): string
{
return sprintf('Check listen %s::%d -> ok', $service['host'], $service['port']);
}
/**
* @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 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;
}
/**
* @return bool
*/
public static function inCoroutine(): bool
{
return Coroutine::getCid() > 0;
}
/**
* @return Container
*/
public static function getDi(): Container
{
return static::$container;
}
/**
* @param $workerId
* @return mixed
* @throws Exception
*/
public static function setManagerId($workerId): mixed
{
if (empty($workerId) || static::isDocker()) {
return $workerId;
}
$tmpFile = storage($workerId . '.sock', 'pid/manager');
return self::writeFile($tmpFile, $workerId);
}
/**
* @param $workerId
* @return mixed
* @throws Exception
*/
public static function setProcessId($workerId): mixed
{
if (empty($workerId) || static::isDocker()) {
return $workerId;
}
$tmpFile = storage($workerId . '.sock', 'pid/process');
return self::writeFile($tmpFile, $workerId);
}
/**
* @return bool
*/
public static function isDocker(): bool
{
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
if (trim($output) === 'yes') {
return true;
}
return false;
}
/**
* @param $workerId
* @return mixed
* @throws Exception
*/
public static function setWorkerId($workerId): mixed
{
if (empty($workerId) || static::isDocker()) {
return $workerId;
}
$tmpFile = storage($workerId . '.sock', 'pid/worker');
return self::writeFile($tmpFile, $workerId);
}
/**
* @param $workerId
* @return mixed
* @throws Exception
*/
public static function setTaskId($workerId): mixed
{
if (empty($workerId) || static::isDocker()) {
return $workerId;
}
$tmpFile = storage($workerId . '.sock', 'pid/task');
return self::writeFile($tmpFile, $workerId);
}
/**
* @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 !self::inCoroutine() ? file_put_contents(...$params) : Coroutine::writeFile(...$params);
}
/**
* @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 $workerId
* @param bool $isWorker
* @throws Exception
*/
public static function clearProcessId($workerId, bool $isWorker = false)
{
clearstatcache();
$directory = $isWorker === true ? 'pid/worker' : 'pid/task';
if (!file_exists($file = storage($workerId, $directory))) {
return;
}
shell_exec('rm -rf ' . $file);
}
/**
* @param string|null $taskPid
* @throws Exception
*/
public static function clearTaskPid(string $taskPid = null)
{
if (empty($taskPid)) {
exec('rm -rf ' . storage(null, 'pid/task'));
} else {
static::clearProcessId($taskPid);
}
}
/**
* @param $taskPid
* @throws Exception
*/
public static function clearWorkerPid($taskPid = null)
{
if (empty($taskPid)) {
exec('rm -rf ' . storage(null, 'pid/worker'));
} else {
static::clearProcessId($taskPid, true);
}
}
/**
* @return Server|null
* @throws
*/
public static function getWebSocket(): ?\Swoole\Server
{
$server = static::app()->getSwoole();
if (!($server instanceof \Swoole\Server)) {
return null;
}
return $server;
}
/**
* @return false|string
* @throws Exception
*/
public static function getMasterPid(): bool|string
{
$pid = Kiri::app()->getSwoole()->setting['pid_file'];
return file_get_contents($pid);
}
/**
* @param int $fd
* @param $data
* @return mixed
* @throws Exception
*/
public static function push(int $fd, $data): mixed
{
$server = static::getWebSocket();
if (empty($server) || !$server->isEstablished($fd)) {
return false;
}
if (!is_string($data)) {
$data = Json::encode($data);
}
return $server->push($fd, $data);
}
/**
* @return mixed
*/
public static function localhost(): mixed
{
return current(swoole_get_local_ip());
}
/**
* @param string $class
* @param array $params
* @throws ReflectionException
* @throws Exception
*/
public static function async(string $class, array $params = [])
{
$manager = di(ServerManager::class);
$manager->task(new $class(...$params));
}
/**
* @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 $process
* @throws Exception
*/
public static function shutdown($process): void
{
static::app()->getSwoole()->shutdown();
if ($process instanceof Process) {
$process->exit(0);
}
}
/**
* @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();
}
private static array $_autoload = [];
const PROCESS = 'process';
const TASK = 'task';
const WORKER = 'worker';
/**
* @param string $event
* @param null $data
* @return false|string
* @throws Exception
*/
public static function param(string $event, $data = NULL): bool|string
{
if (is_object($data)) {
if ($data instanceof ModelInterface || $data instanceof Collection) {
$data = $data->getAttributes();
} else {
$data = get_object_vars($data);
}
}
if (!is_array($data)) $data = ['data' => $data];
return json_encode(array_merge(['callback' => $event], $data));
}
/**
* @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;
}
/**
* @param $class
* @param $file
*/
public static function setAutoload($class, $file)
{
if (isset(static::$_autoload[$class])) {
return;
}
static::$_autoload[$class] = $file;
include_once "Kiri.php";
}
/**
* @param $className
*/
public static function autoload($className)
{
if (!isset(static::$_autoload[$className])) {
return;
}
$file = static::$_autoload[$className];
require_once "Kiri.php";
}
}
//spl_autoload_register([Kiri::class, 'autoload'], true, true);
Kiri::setContainer(new Container());
+417
View File
@@ -0,0 +1,417 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2024/12/19
* Time: 14:00
*/
declare(strict_types=1);
namespace Kiri\NoSql;
use Kiri;
use Kiri\Exception\RedisConnectException;
use Kiri\Pool\Pool;
use MongoDB\Client;
use MongoDB\Database;
use MongoDB\Collection;
use function config;
/**
* Class MongoDB
* @package Kiri\NoSql
* @mixin Client
* @mixin Database
* @mixin Collection
*/
class MongoDB
{
public string $host = 'localhost';
public int $port = 27017;
public string $database = '';
public string $username = '';
public string $password = '';
public string $authSource = 'admin';
public int $timeout = 30;
public array $options = [];
/**
* @var array|int[]
*/
public array $pool = ['min' => 1, 'max' => 100];
/**
* 初始化
*/
public function __construct()
{
Kiri::configure($this, config('mongodb', []));
}
/**
* @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 string|null $database
* @return Database
* @throws
*/
public function getDatabase(?string $database = null): Database
{
$dbName = $database ?? $this->database;
if (empty($dbName)) {
throw new RedisConnectException('MongoDB database name is required.');
}
return $this->getClient()->selectDatabase($dbName);
}
/**
* 获取集合实例
* @param string $collection
* @param string|null $database
* @return Collection
* @throws
*/
public function getCollection(string $collection, ?string $database = null): Collection
{
return $this->getDatabase($database)->selectCollection($collection);
}
/**
* 代理方法调用到 MongoDB Client,内置连接健康检查和回收
* 异常时关闭连接并回退计数器,防止断连对象污染连接池
* @param $name
* @param $arguments
* @return mixed
* @throws
*/
public function proxy($name, $arguments): mixed
{
$client = $this->getClient();
try {
// 如果方法存在于 Client,直接调用
if (method_exists($client, $name)) {
return $client->{$name}(...$arguments);
}
// 如果方法存在于 Database,通过默认数据库调用
$database = $this->getDatabase();
if (method_exists($database, $name)) {
$result = $database->{$name}(...$arguments);
$this->returnClient($client);
return $result;
}
throw new \BadMethodCallException("Method {$name} does not exist on MongoDB Client or Database.");
} catch (\Throwable $throwable) {
\Kiri::getLogger()->json_log($throwable);
$this->closeClient($client);
return false;
}
$this->returnClient($client);
}
/**
* 归还连接
* @param Client $client
* @return void
*/
private function returnClient(Client $client): void
{
try {
$this->pool()->push($this->getName(), $client);
} catch (\Throwable) {
$this->closeClient($client);
}
}
/**
* 关闭连接并回退计数器
* @param Client $client
* @return void
*/
private function closeClient(Client $client): void
{
try {
$client->close();
} catch (\Throwable) {
}
$this->pool()->abandon($this->getName());
}
/**
* 执行 MongoDB 命令
* @param array|object $command
* @param array $options
* @param string|null $database
* @return array|object
* @throws
*/
public function command(array|object $command, array $options = [], ?string $database = null): array|object
{
$db = $this->getDatabase($database);
return $db->command($command, $options);
}
/**
* 插入文档
* @param string $collection
* @param array|object $document
* @param array $options
* @param string|null $database
* @return \MongoDB\InsertOneResult|\MongoDB\InsertManyResult
* @throws
*/
public function insert(string $collection, array|object $document, array $options = [], ?string $database = null)
{
$coll = $this->getCollection($collection, $database);
if (is_array($document) && isset($document[0]) && is_array($document[0])) {
// 批量插入
return $coll->insertMany($document, $options);
}
// 单条插入
return $coll->insertOne($document, $options);
}
/**
* 查找文档
* @param string $collection
* @param array $filter
* @param array $options
* @param string|null $database
* @return \MongoDB\Driver\Cursor
* @throws
*/
public function find(string $collection, array $filter = [], array $options = [], ?string $database = null)
{
$coll = $this->getCollection($collection, $database);
return $coll->find($filter, $options);
}
/**
* 查找单个文档
* @param string $collection
* @param array $filter
* @param array $options
* @param string|null $database
* @return array|object|null
* @throws
*/
public function findOne(string $collection, array $filter = [], array $options = [], ?string $database = null): array|object|null
{
$coll = $this->getCollection($collection, $database);
return $coll->findOne($filter, $options);
}
/**
* 更新文档
* @param string $collection
* @param array $filter
* @param array $update
* @param array $options
* @param string|null $database
* @return \MongoDB\UpdateResult
* @throws
*/
public function update(string $collection, array $filter, array $update, array $options = [], ?string $database = null)
{
$coll = $this->getCollection($collection, $database);
if (isset($options['multi']) && $options['multi']) {
unset($options['multi']);
return $coll->updateMany($filter, $update, $options);
}
return $coll->updateOne($filter, $update, $options);
}
/**
* 删除文档
* @param string $collection
* @param array $filter
* @param array $options
* @param string|null $database
* @return \MongoDB\DeleteResult
* @throws
*/
public function delete(string $collection, array $filter, array $options = [], ?string $database = null)
{
$coll = $this->getCollection($collection, $database);
if (isset($options['limit']) && $options['limit'] == 1) {
unset($options['limit']);
return $coll->deleteOne($filter, $options);
}
return $coll->deleteMany($filter, $options);
}
/**
* 统计文档数量
* @param string $collection
* @param array $filter
* @param array $options
* @param string|null $database
* @return int
* @throws
*/
public function count(string $collection, array $filter = [], array $options = [], ?string $database = null): int
{
$coll = $this->getCollection($collection, $database);
return $coll->countDocuments($filter, $options);
}
/**
* @return void
* @throws
*/
public function destroy(): void
{
$this->pool()->close($this->getName());
}
/**
* 获取 MongoDB 客户端
* @return Client
* @throws
*/
private function getClient(): Client
{
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 'mongodb.' . $this->host . '.' . $this->database;
}
/**
* 创建 MongoDB 连接
* @return Client
* @throws
*/
protected function connect(): Client
{
$uri = $this->buildUri();
$clientOptions = $this->buildClientOptions();
try {
$client = new Client($uri, $clientOptions);
// 测试连接
$client->selectDatabase($this->database)->command(['ping' => 1]);
return $client;
} catch (\Throwable $e) {
\Kiri::getLogger()->json_log($e);
throw new RedisConnectException(sprintf('MongoDB Connect %s Fail: %s', $uri, $e->getMessage()));
}
}
/**
* 构建 MongoDB 连接 URI
* @return string
*/
private function buildUri(): string
{
$auth = '';
if (!empty($this->username) && !empty($this->password)) {
$auth = $this->username . ':' . urlencode($this->password) . '@';
}
// 支持多种 host 格式:host:port 或 host1,host2:port
$hosts = $this->host;
if (!str_contains($hosts, ',') && !str_contains($hosts, ':')) {
$hosts = $hosts . ':' . $this->port;
}
$uri = 'mongodb://' . $auth . $hosts;
// 添加数据库和认证源
$query = [];
if (!empty($this->database)) {
$query[] = 'database=' . $this->database;
}
if (!empty($this->authSource)) {
$query[] = 'authSource=' . $this->authSource;
}
if (!empty($query)) {
$uri .= '/?' . implode('&', $query);
}
return $uri;
}
/**
* 构建客户端选项
* @return array
*/
private function buildClientOptions(): array
{
return array_merge([
'connectTimeoutMS' => $this->timeout * 1000,
'serverSelectionTimeoutMS' => $this->timeout * 1000,
'socketTimeoutMS' => $this->timeout * 1000,
], $this->options);
}
}
+228
View File
@@ -0,0 +1,228 @@
<?php
/**
* Created by PhpStorm.
* User: whwyy
* Date: 2018/4/27 0027
* Time: 11:00
*/
declare(strict_types=1);
namespace Kiri\NoSql;
use Kiri;
use Kiri\Exception\RedisConnectException;
use Kiri\Pool\Pool;
use function config;
/**
* Class NoSql
* @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());
}
/**
* 代理 Redis 方法调用,内置健康检查和连接回收
* 如果连接 ping 失败则关闭连接并移除,不归还池中防止污染
* @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 $this->getLogger()->json_log($throwable, [], false);
} finally {
if ($client->ping('h') == 'h') {
$this->pool()->push($this->getName(), $client);
} else {
$client->close();
$this->pool()->abandon($this->getName());
}
}
}
/**
* @return Kiri\Error\StdoutLogger
*/
protected function getLogger(): Kiri\Error\StdoutLogger
{
return Kiri::getLogger();
}
/**
* @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 NoSql Connect %s::%d Fail.', $this->host, $this->port));
}
if (!empty($this->auth) && !$redis->auth($this->auth)) {
throw new RedisConnectException(sprintf('NoSql 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;
}
}
-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';
}
}
}
-219
View File
@@ -1,219 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Pool;
use Closure;
use Database\Mysql\PDO;
use Exception;
use Kiri\Abstracts\Component;
use Kiri\Abstracts\Config;
use Kiri\Context;
use Kiri\Kiri;
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['database'], $config['cds'], $config['username'], $config['password'], $config['charset'] ?? 'utf8mb4'
]);
};
}
/**
* @param $name
* @param $isMaster
* @param $max
* @throws Exception
*/
public function initConnections($name, $isMaster, $max)
{
$this->getPool()->initConnections($name, $isMaster, $max);
}
/**
* @param $coroutineName
* @param $isMaster
* @throws Exception
*/
public function release($coroutineName, $isMaster)
{
$coroutineName = $this->name('Mysql:' . $coroutineName, $isMaster);
/** @var PDO $client */
if (!($client = Context::getContext($coroutineName)) instanceof PDO) {
return;
}
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;
}
}
-249
View File
@@ -1,249 +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 $channel
* @param $retain_number
* @throws Exception
*/
protected function pop(Channel $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;
}
}
-126
View File
@@ -1,126 +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\Kiri;
/**
* Class RedisClient
* @package Kiri\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['host'], (int)$config['port'], $config['databases'] ?? 0,
$config['auth'], $config['prefix'] ?? '', $config['timeout'] ?? 30,
$config['read_timeout'] ?? 30
]);
};
}
/**
* @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();
}
}
-101
View File
@@ -1,101 +0,0 @@
<?php
namespace Kiri;
use Exception;
use Kiri\Abstracts\Input;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* 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 = [];
$configs = Kiri::app()->getConfig();
foreach ($configs->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);
}
}
}
-343
View File
@@ -1,343 +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\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->getArgument('action');
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
{
$redis = Kiri::getDi()->get(Redis::class);
if ($input->hasArgument('name')) {
$this->tableName = $input->getArgument('name');
$redis->del('column:' . $this->tableName);
}
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 = [];
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\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')
->addArgument('action', InputArgument::REQUIRED)
->addArgument('name', InputArgument::OPTIONAL)
->addArgument('databases', 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->getArgument('databases')) != null) {
$gii->run($connections->get($db), $input);
return 1;
}
$action = $input->getArgument('action');
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;
}
}
-539
View File
@@ -1,539 +0,0 @@
<?php
declare(strict_types=1);
namespace Gii;
use Exception;
use ReflectionException;
use Kiri\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'], '\\');
$prefix = str_replace('_', '', $this->db->tablePrefix);
$managerName = str_replace(ucfirst($prefix), '', $managerName);
$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 Annotation\Target;
use Annotation\Route\Middleware;
use Annotation\Route\Route;
use Kiri\Core\Str;
use Kiri\Core\Json;
use Http\Context\Request;
use Http\Context\Response;
use Http\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 Annotation\Target;
use 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 Annotation\Target;
use Kiri\Rpc\Annotation\JsonRpc;
use Http\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;
}
}

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