Compare commits

...

42 Commits

Author SHA1 Message Date
as2252258 536e4c9bc5 eee 2026-07-03 18:29:45 +08:00
as2252258 91be2eba20 eee 2026-07-03 10:42:54 +08:00
as2252258 d7f5f62c1c eee 2026-06-30 22:39:56 +08:00
as2252258 8b8bfa2a60 eee 2026-06-28 15:16:46 +08:00
as2252258 1ecf32bfa6 eee 2026-06-28 15:13:08 +08:00
as2252258 8c0c5b56c8 eee 2026-06-28 15:12:28 +08:00
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
23 changed files with 1856 additions and 1237 deletions
+1
View File
@@ -34,3 +34,4 @@ runtime/
oot
d
composer.lock
.gstack/
+2 -68
View File
@@ -37,13 +37,6 @@ class Kiri
}
/**
* @return Container|null
*/
public static function getContainerContext(): ?Container
{
return static::getContainer();
}
/**
@@ -89,7 +82,7 @@ class Kiri
if (Kiri::getPlatform()->isMac()) {
return;
}
$name = '[' . \config('id', 'system-service') . ']';
$name = '[' . \config('site.id', 'system-service') . ']';
if (!empty($prefix)) {
$name .= '.' . $prefix;
}
@@ -104,7 +97,7 @@ class Kiri
public static function getStoragePath(): string
{
$default = APP_PATH . 'storage' . DIRECTORY_SEPARATOR;
$path = \config('storage', $default);
$path = \config('site.log.path', $default);
if (!is_dir($path)) {
mkdir($path, 0777, true);
}
@@ -131,17 +124,6 @@ class Kiri
}
/**
* @return bool
*/
public static function isDocker(): bool
{
$output = shell_exec('[ -f /.dockerenv ] && echo yes || echo no');
if (trim($output) === 'yes') {
return true;
}
return false;
}
/**
@@ -177,54 +159,6 @@ class Kiri
}
/**
* @return mixed
*/
public static function localhost(): mixed
{
return current(swoole_get_local_ip());
}
/**
* @param array $v1
* @param array $v2
* @return float
*/
#[Pure] public static function distance(array $v1, array $v2): float
{
$maxX = max($v1['x'], $v2['x']);
$minX = min($v1['x'], $v2['x']);
$maxZ = max($v1['z'], $v2['z']);
$minZ = min($v1['z'], $v2['z']);
$dx = abs($maxX - $minX);
$dy = abs($maxZ - $minZ);
$sqrt = sqrt($dx * $dx + $dy * $dy);
if ($sqrt < 0) {
$sqrt = abs($sqrt);
}
return (float)$sqrt;
}
/**
* @param $tmp_name
* @return string
*/
public static function rename($tmp_name): string
{
$hash = md5_file($tmp_name);
$later = '.' . exif_imagetype($tmp_name);
$match = '/(\w{12})(\w{5})(\w{9})(\w{6})/';
$tmp = preg_replace($match, '$1-$2-$3-$4', $hash);
return strtoupper($tmp) . $later;
}
/**
+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 核心框架!我们期待您的反馈与贡献。
+8 -16
View File
@@ -9,7 +9,7 @@
],
"license": "MIT",
"require": {
"php": ">=8.3",
"php": ">=8.5",
"ext-json": "*",
"ext-fileinfo": "*",
"ext-pdo": "*",
@@ -23,33 +23,25 @@
"ext-openssl": "*",
"ext-swoole": "*",
"ext-msgpack": "*",
"symfony/console": "~v5.3.10",
"symfony/console": "^v8.1.1",
"psr/log": "1.*",
"composer-runtime-api": "^2.0",
"psr/http-server-middleware": "1.0.1",
"psr/http-server-middleware": "^1.0.2",
"ext-pcntl": "*",
"ext-sockets": "*",
"nikic/php-parser": "^4.15",
"nikic/php-parser": "^v5.5.0",
"ext-inotify": "*",
"game-worker/kiri-pool": "~v1.0",
"monolog/monolog": "^2.9",
"psr/container": "^2.0",
"ext-libsodium": "*",
"swiftmailer/swiftmailer": "^6.3"
"game-worker/kiri-pool": "^v1.0",
"psr/container": "^2.0"
},
"replace": {
"symfony/polyfill-apcu": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-ctype": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php81": "*"
"symfony/polyfill-ctype": "*"
},
"autoload": {
"psr-4": {
"Kiri\\": "kiri-engine/",
"Kiri\\Actor\\": "kiri-actor/"
"Kiri\\": "kiri-engine/"
},
"files": [
"Kiri.php",
+83 -104
View File
@@ -6,6 +6,7 @@ defined('APP_PATH') or define('APP_PATH', realpath(__DIR__ . '/../../'));
use JetBrains\PhpStorm\Pure;
use Kiri\Abstracts\Kernel;
use Kiri\Application;
use Kiri\Error\StdoutLogger;
use Kiri\Config\ConfigProvider;
use Kiri\Core\ArrayAccess;
use Kiri\Di\Context;
@@ -45,6 +46,22 @@ if (!function_exists('json_validate')) {
}
if (!function_exists('println')) {
/**
* @param string $data
* @return bool
*/
function println(string $data): void
{
$logger = \Kiri::getDi()->get(StdoutLogger::class);
$logger->println($data);
}
}
if (!function_exists('application')) {
/**
@@ -149,8 +166,7 @@ if (!function_exists('isJson')) {
{
if (is_null($string))
return false;
return (str_starts_with($string, '{') && str_ends_with($string, '}'))
|| (str_ends_with($string, '[') && str_starts_with($string, ']'));
return (str_starts_with($string, '{') && str_ends_with($string, '}')) || (str_ends_with($string, '[') && str_starts_with($string, ']'));
}
}
@@ -261,7 +277,8 @@ if (!function_exists('is_enable_file_modification_listening')) {
/**
* @return bool
*/
#[Pure] function is_enable_file_modification_listening(): bool
#[Pure]
function is_enable_file_modification_listening(): bool
{
return env('enable_file_modification_listening', 'off') == 'on';
}
@@ -701,7 +718,9 @@ if (!function_exists('storage')) {
*/
function storage(?string $fileName = '', ?string $path = ''): string
{
if (!str_ends_with($path, '/')) {
$path .= '/';
}
$basePath = rtrim(Kiri::getStoragePath(), '/');
if (!empty($path)) {
$path = ltrim($path, '/');
@@ -763,13 +782,13 @@ if (!function_exists('process_name_set')) {
* @param string|null $prefix
* @throws
*/
function process_name_set(int $pid, string $prefix = NULL): void
function process_name_set(int $pid, ?string $prefix = NULL): void
{
if (Kiri::getPlatform()->isMac()) {
return;
}
$name = \config('id', 'system') . '[' . $pid . ']';
$name = \config('site.id', 'system') . '[' . $pid . ']';
if (!empty($prefix)) {
$name .= '.' . $prefix;
}
@@ -819,7 +838,7 @@ if (!function_exists('config')) {
* @param null $default
* @return mixed
*/
function config($key, $default = NULL): mixed
function config($key, mixed $default = NULL): mixed
{
return make(ConfigProvider::class)->get($key, $default);
}
@@ -867,17 +886,44 @@ if (!function_exists('sweep')) {
/**
* @param string $configPath
* @return array|false|string|null
* @return array
*/
function sweep(string $configPath = APP_PATH . 'config'): bool|array|string|null
function sweep(string $configPath = APP_PATH . 'config'): array
{
$array = [];
foreach (glob($configPath . '/*.php') as $config) {
$array = array_merge(require "$config", $array);
// 检查目录是否存在
if (!is_dir($configPath)) {
throw new InvalidArgumentException("Config directory does not exist: {$configPath}");
}
// 获取所有PHP配置文件
$configFiles = glob($configPath . '/*.php');
foreach ($configFiles as $config) {
// 使用 pathinfo 更安全地获取文件名
$filename = pathinfo($config, PATHINFO_FILENAME);
$key = strtolower($filename);
// 验证文件是否可读
if (!is_readable($config)) {
throw new RuntimeException("Cannot read config file: {$config}");
}
// 使用 include 而不是 require_once,这样不会跳过已加载的文件
// 在配置加载场景中,通常希望每次都重新加载
$configData = require_once $config;
if (!is_array($configData)) {
continue;
}
$array[$key] = $configData;
}
return $array;
}
}
@@ -896,98 +942,6 @@ if (!function_exists('merge')) {
}
if (!function_exists('jTraceEx')) {
/**
* @param $e
* @param null $seen
* @param bool $toHtml
* @return string
*/
function jTraceEx($e, $seen = NULL, bool $toHtml = FALSE): string
{
$starter = $seen ? 'Caused by: ' : '';
$result = [];
if (!$seen)
$seen = [];
$trace = $e->getTrace();
$prev = $e->getPrevious();
$result[] = sprintf('%s%s: %s', $starter, $e::class, $e->getMessage());
$file = $e->getFile();
$line = $e->getLine();
foreach ($trace as $value) {
$result[] = sprintf(' at %s%s%s(%s%s%s)',
count($value) && array_key_exists('class', $value) ? str_replace('\\', '.', $value['class']) : '',
count($value) && array_key_exists('class', $value) && array_key_exists('function', $value) ? '.' : '',
count($value) && array_key_exists('function', $value) ? str_replace('\\', '.', $value['function']) : '(main)',
$line === NULL ? $file : basename($file),
$line === NULL ? '' : ':',
$line === NULL ? '' : $line);
$file = array_key_exists('file', $value) ? $value['file'] : 'Unknown Source';
$line = array_key_exists('file', $value) && array_key_exists('line', $value) && $value['line'] ? $value['line'] : NULL;
}
$result = join($toHtml ? "<br>" : "\n", $result);
if ($prev) {
$result .= ($toHtml ? "<br>" : "\n") . jTraceEx($prev, $seen, $toHtml);
}
return $result;
}
}
if (!function_exists('error')) {
/**
* @param mixed $message
* @param array $method
* @return void
* @throws
*/
function error(mixed $message, array $method = []): void
{
if (is_string($message) && str_contains($message, 'inotify_rm_watch')) {
return;
}
Kiri::getLogger()->failure($message);
}
}
if (!function_exists('trigger_print_error')) {
/**
* @param mixed $message
* @param string $method
* @return bool
* @throws
*/
function trigger_print_error(mixed $message, string $method = 'app'): bool
{
return Kiri::getLogger()->failure($message, $method);
}
}
if (!function_exists('println')) {
/**
* @param mixed $message
* @param string $method
* @return bool
* @throws
*/
function println(mixed $message, string $method = 'app'): bool
{
return Kiri::getLogger()->failure($message, $method);
}
}
if (!function_exists('event')) {
@@ -1017,7 +971,7 @@ if (!function_exists('throwable')) {
if (is_string($throwable)) {
return $throwable;
}
$message = "\033[31m" . $throwable::class . ' ' . $throwable->getMessage() . "\033[0m" . PHP_EOL;
$message = $throwable::class . ' ' . $throwable->getMessage() . PHP_EOL;
$message .= ' File: ' . $throwable->getFile() . PHP_EOL;
$message .= ' Line: ' . $throwable->getLine() . PHP_EOL;
@@ -1053,6 +1007,31 @@ if (!function_exists('throwable')) {
}
if (!function_exists('json_log')) {
function json_log(Throwable $throwable, array $data = []): void
{
$param = [];
$param['time'] = date('Y-m-d H:i:s');
$param['request'] = [
'path' => \request()->getUri()->getPath(),
'headers' => \request()->getHeaders(),
'method' => \request()->getMethod(),
'params' => \request()->getBody()->getContents(),
];
$param['exception'] = [
'message' => $throwable->getMessage(),
'code' => $throwable->getCode(),
'file' => $throwable->getFile(),
'line' => $throwable->getLine(),
'trace' => $throwable->getTrace(),
];
$param['data'] = $data;
file_put_contents(storage('exception-' . date('Y-m-d') . '.log', 'exception'), json_encode($param, JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND);
}
}
if (!function_exists('map')) {
+12 -4
View File
@@ -46,13 +46,21 @@ abstract class BaseApplication extends LocalService
public function __construct(public EventProvider $provider, public ConfigProvider $config, public ContainerInterface $container)
{
$this->mapping($config);
$this->parseStorage($config);
$this->parseEvents($config);
parent::__construct();
}
/**
* @return void
* @throws
*/
public function init(): void
{
$this->parseStorage($this->config);
$this->parseEvents($this->config);
}
/**
* @param ConfigProvider $config
* @return void
@@ -73,7 +81,7 @@ abstract class BaseApplication extends LocalService
*/
public function parseStorage(ConfigProvider $config): void
{
$storage = $config->get('storage', 'storage');
$storage = $config->get('site.log.storage', 'storage');
if (!str_contains($storage, APP_PATH)) {
$storage = APP_PATH . $storage . '/';
}
+16 -80
View File
@@ -1,15 +1,8 @@
<?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;
@@ -18,44 +11,23 @@ use Kiri\Events\EventDispatch;
use Kiri\Events\EventProvider;
use Psr\Container\ContainerInterface;
/**
* Class Component
* @package Kiri\Base
* @property ContainerInterface $container
* @property EventDispatch $dispatch
* @property EventProvider $provider
*/
class Component implements Configure
class Component
{
/**
* BaseAbstract constructor.
*/
public function __construct()
{
}
/**
* @return void
*/
public function init(): void
{
}
/**
* @return string
*/
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @return StdoutLogger
* @throws
*/
public function getLogger(): StdoutLogger
@@ -63,10 +35,22 @@ class Component implements Configure
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();
}
/**
* @param string $name
* @return mixed
* @throws
*/
public function __get(string $name)
@@ -74,56 +58,8 @@ class Component implements Configure
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->{$method}();
} else if (method_exists($this, $name)) {
return $this->{$name};
} else {
}
throw new Exception('Unable getting property ' . get_called_class() . '::' . $name);
}
}
/**
* @param string $name
* @param $value
* @return void
* @throws
*/
public function __set(string $name, $value): void
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
$this->{$method}($value);
} else if (method_exists($this, $name)) {
$this->{$name} = $value;
} else {
throw new Exception('Unable setting property ' . get_called_class() . '::' . $name);
}
}
/**
* @return EventDispatch
*/
public function getDispatch(): EventDispatch
{
return Kiri::getDi()->get(EventDispatch::class);
}
/**
* @return EventProvider
*/
public function getProvider(): EventProvider
{
return Kiri::getDi()->get(EventProvider::class);
}
/**
* @return ContainerInterface
*/
public function getContainer(): ContainerInterface
{
return Kiri::getDi();
}
}
-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\Base
*/
interface Configure
{
}
+4 -6
View File
@@ -7,9 +7,7 @@ use Kiri\Coordinator;
class CoordinatorManager
{
private static array $_waite = [];
private static array $_items = [];
/**
@@ -18,10 +16,10 @@ class CoordinatorManager
*/
public static function utility(string $category): Coordinator
{
if (!((static::$_waite[$category] ?? null) instanceof Coordinator)) {
static::$_waite[$category] = new Coordinator();
if (!((static::$_items[$category] ?? null) instanceof Coordinator)) {
static::$_items[$category] = new Coordinator();
}
return static::$_waite[$category];
return static::$_items[$category];
}
}
+12 -11
View File
@@ -54,12 +54,15 @@ class Application extends BaseApplication
*/
public function init(): void
{
$this->errorHandler->registerShutdownHandler(config('error.shutdown', []));
$this->errorHandler->registerExceptionHandler(config('error.exception', []));
$this->errorHandler->registerErrorHandler(config('error.error', []));
$this->id = config('id', uniqid('id.'));
$this->errorHandler->registerShutdownHandler(config('site.error.shutdown', []));
$this->errorHandler->registerExceptionHandler(config('site.error.exception', []));
$this->errorHandler->registerErrorHandler(config('site.error.error', []));
$this->id = config('site.id', uniqid('id.'));
$this->provider->on(OnBeforeCommandExecute::class, [$this, 'beforeCommandExecute']);
parent::init();
}
@@ -70,13 +73,11 @@ class Application extends BaseApplication
*/
public function beforeCommandExecute(OnBeforeCommandExecute $beforeCommandExecute): void
{
if (!($beforeCommandExecute->command instanceof ServerCommand)) {
$scanner = $this->container->get(Scanner::class);
$scanner->load_directory(APP_PATH . 'app/');
} else if (config('reload.hot', false) === false) {
$scanner = $this->container->get(Scanner::class);
$scanner->load_directory(APP_PATH . 'app/');
if ($beforeCommandExecute->command instanceof ServerCommand) {
return;
}
$scanner = $this->container->get(Scanner::class);
$scanner->scan(APP_PATH . 'app/');
}
@@ -124,7 +125,7 @@ class Application extends BaseApplication
{
$console = $this->container->get(ConsoleApplication::class);
foreach ($command as $value) {
$console->add($this->container->get($value));
$console->addCommand($this->container->get($value));
}
}
+26 -7
View File
@@ -1,15 +1,19 @@
<?php
declare(strict_types=1);
namespace Kiri;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
class Coordinator
{
const string WORKER_START = 'worker:start';
private bool $waite = true;
private bool $wait = false;
private ?Channel $channel = null;
/**
@@ -17,7 +21,17 @@ class Coordinator
*/
public function yield(): void
{
while ($this->waite) {
if (Coroutine::getCid() > 0) {
if ($this->channel instanceof Channel) {
$this->channel->pop();
}
return;
}
if ($this->wait === false) {
return;
}
while ($this->wait === true) {
usleep(1000);
}
}
@@ -26,9 +40,9 @@ class Coordinator
/**
* @return void
*/
public function waite(): void
public function wait(): void
{
$this->waite = true;
Coroutine::getCid() > 0 ? $this->channel = new Channel(1) : $this->wait = true;
}
@@ -37,8 +51,13 @@ class Coordinator
*/
public function done(): void
{
$this->waite = false;
if (Coroutine::getCid() > 0) {
$this->channel?->push(true);
$this->channel->close();
$this->channel = null;
} else {
$this->wait = false;
}
}
}
+1 -1
View File
@@ -185,7 +185,7 @@ class Str
* @return array
* 剩余天,带分秒
*/
public static function timeout($endTime, int $startTime = NULL): array
public static function timeout($endTime, ?int $startTime = NULL): array
{
$endTime = $endTime - (!empty($startTime) ? $startTime : time());
+4 -13
View File
@@ -22,14 +22,9 @@ class Environmental
*/
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;
}
$os = strtolower(PHP_OS);
return str_contains($os, 'mac') || str_contains($os, 'darwin');
}
@@ -38,11 +33,7 @@ class Environmental
*/
#[Pure] public function isLinux(): bool
{
if (!static::isMac()) {
return true;
} else {
return false;
}
return PHP_OS_FAMILY === 'Linux' || strtolower(PHP_OS) === 'linux';
}
}
+6 -2
View File
@@ -89,7 +89,7 @@ class ErrorHandler extends Component implements ErrorInterface
return;
}
$this->getLogger()->failure($lastError['message'] . PHP_EOL);
$this->getLogger()->println(json_encode($lastError,JSON_UNESCAPED_UNICODE));
event(new OnSystemError());
}
@@ -104,7 +104,9 @@ class ErrorHandler extends Component implements ErrorInterface
{
$this->category = 'exception';
$this->getLogger()->failure($exception);
$this->getLogger()->println(throwable($exception));
json_log($exception);
event(new OnSystemError());
}
@@ -117,6 +119,8 @@ class ErrorHandler extends Component implements ErrorInterface
{
$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]);
+17 -14
View File
@@ -9,6 +9,7 @@ use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;
use Throwable;
/**
@@ -48,7 +49,7 @@ class StdoutLogger extends Component
{
parent::__construct();
$this->logger = new Logger(\config('id'));
$this->logger = new Logger(\config('site.id'));
$this->levels = [
'debug' => $this->logger::DEBUG,
'info' => $this->logger::INFO,
@@ -67,30 +68,31 @@ class StdoutLogger extends Component
* @param string $model
* @return bool
*/
public function failure($message, string $model = 'app'): bool
public function logCategory($message, string $model = 'app'): bool
{
if ($message instanceof \Exception) {
$this->errors[$model] = $message->getMessage();
} else {
$this->errors[$model] = $message;
}
return $this->dump($message);
$this->println($message);
return false;
}
/**
* @param $message
* @param Throwable $exception
* @param array $data
* @param mixed|null $result
* @return bool
*/
protected function dump($message): bool
public function json_log(Throwable $exception, array $data = [], mixed $result = null): mixed
{
$message = throwable($message);
if (str_contains($message, 'inotify_rm_watch')) {
return false;
}
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message, FILE_APPEND);
$this->error($message, []);
return false;
json_log($exception, $data);
$this->println($exception->getMessage());
return $result;
}
@@ -118,8 +120,9 @@ class StdoutLogger extends Component
} else if (method_exists($this, $name)) {
$this->{$name}(...$arguments);
}
} catch (\Throwable $exception) {
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $exception->getMessage(), FILE_APPEND);
} catch (Throwable $exception) {
$this->println($exception->getMessage());
$this->json_log($exception);
}
}
+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);
}
}
@@ -7,7 +7,7 @@
*/
declare(strict_types=1);
namespace Kiri\Redis;
namespace Kiri\NoSql;
use Kiri;
use Kiri\Exception\RedisConnectException;
@@ -15,7 +15,7 @@ use Kiri\Pool\Pool;
use function config;
/**
* Class Redis
* Class NoSql
* @package Kiri\Cache
* @mixin \Redis
*/
@@ -103,13 +103,13 @@ class Redis
public function lock($key, int $timeout = 5): bool|int
{
$script = <<<SCRIPT
local _nx = redis.call('setnx',KEYS[1], ARGV[1])
if (_nx ~= 0) then
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;
end
return 0
SCRIPT;
return $this->eval($script, ['{lock}:' . $key, $timeout], 1);
}
@@ -136,6 +136,8 @@ SCRIPT;
/**
* 代理 Redis 方法调用,内置健康检查和连接回收
* 如果连接 ping 失败则关闭连接并移除,不归还池中防止污染
* @param $name
* @param $arguments
* @return mixed
@@ -147,15 +149,27 @@ SCRIPT;
try {
return $client->{$name}(...$arguments);
} catch (\Throwable $throwable) {
return trigger_print_error(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
@@ -197,10 +211,10 @@ SCRIPT;
{
$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));
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('Redis Error: %s, Host %s, Auth %s', $redis->getLastError(), $this->host, $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) {
+37 -19
View File
@@ -14,33 +14,50 @@
</style>
</head>
<body style="background-color: #666;color: #fff;presentation-level: increment;">
<video id="output" width="320" height="240" autoplay></video>
<!--<video id="output" width="320" height="240" autoplay></video>-->
<pre id="format"></pre>
<script type="text/javascript">
let sock, tick, format = document.getElementById('format');
let buffer;
let ms = new MediaSource()
let output = document.getElementById('output')
output.src = URL.createObjectURL(ms)
ms.onsourceopen = () => {
buffer = ms.addSourceBuffer('video/webm; codecs="vorbis,vp8"')
}
// let buffer;
// let ms = new MediaSource()
let unique = '';
// let output = document.getElementById('output')
// output.src = URL.createObjectURL(ms)
// ms.onsourceopen = () => {
// buffer = ms.addSourceBuffer('video/webm; codecs="vorbis,vp8"')
// }
function message(message) {
// let div = document.createElement('div');
// div.innerHTML = message.data;
// div.style.cssText = 'padding:5px 10px;background-color:#222;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;word-break: break-all;word-wrap: break-word;';
// div.style.marginBottom = '10px';
// let count = format.getElementsByTagName('div');
try {
let data = JSON.parse(message.data);
if (data.event === 'user::kick') {
return;
}
if (unique === '') {
unique = message.data;
}
if (data["ack"]) {
sock.send(JSON.stringify({'event': 'ack', 'id': unique, 'data': {'ack': data["ack"]}}));
}
} catch (e) {
if (unique === '') {
unique = message.data;
}
}
let div = document.createElement('div');
div.innerHTML = message.data;
div.style.cssText = 'padding:5px 10px;background-color:#222;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px;word-break: break-all;word-wrap: break-word;';
div.style.marginBottom = '10px';
let count = format.getElementsByTagName('div');
buffer.appendBuffer(new Uint8Array(message.data))
// format.insertBefore(div, count[0]);
format.insertBefore(div, count[0]);
}
function close(even) {
unique = '';
setTimeout(function () {
connect();
sock.onmessage = message;
@@ -50,13 +67,14 @@
}
function connect() {
sock = new WebSocket('wss://center-wss.stupideyes.com/ws?access_token=6648f48a-466ba-6394-70527ef8b-bc47b8');
sock.onopen = function () {
sock = new WebSocket('ws://121.40.147.153:6611/sockets/?auth=dG9rZW49NjYxNTBhMWQwYS0wMWItMDMxYS0wZTRjNTJiNGEtMjkzMTI5JnRpbWU9MTc4MjEyODcwMCZyZWZyZXNoPTJzMTdyR1BMWDRuWElKWExycTdNU1pQNEsyUXQwQ1pId1RsWUM5dzZJTmpLU1dvOThocW5KR0tQVFNCU2E2QTllNWRMTm9DYkRBaVhVQVd1cUU3Q1B5ejZLMTVzamdaTlpJWHhXNVlKeWQ2ODBaTkhZdktHUnd5RklKT1NZTEVBMURSb3JrbTUwRVUrTmpNMjJJL0lsMmpPT3p2MzFFNFZ4WkZwb1pXSmZVV015Q1VZenFtYTg4MDRHZ0Z3anZobDlYdWFkakR3QmhmZFd4QloxSC9HWndDRHdVQjN3elFrL01wUWFOSTB2YTlqZjZzQTRESFI2VlJtYWpxYWFHdkVNV3BGOXllbGVrTXFhcUhyT0tkdUpZRXVpSzEzZkNoRUljblFqdUVzWjdGUDBYVGlkNTUybUlyQnlYQjc0YktxQVRNbklvZlFQcnl3aEVUNGRSZVhhdz09');
// sock = new WebSocket('wss://meet-bottle.zhuangb123.com/socket/?auth=dG9rZW49M2I2ODJhNzg0NS0xMTktMzBiMS1mMDkxOGRhNjktNTg2ZDEyJnRpbWU9MTc1MzA4MTI5MyZyZWZyZXNoPXBDT0VFYk9KOG8xTEVZQytyUkR4VlZIaXR1TmVWcndCY2crRTBua2U1ZkJuUWNJaHl6NUtTV0x2ZExXa1Y5aXlyK3NmRnRwOVRCVU91MnhPSVRPRjROTjhoT0hlODNNVmZjN1NXb2QyeDY0TXEvZTFEUCtySjNzNjZhVlplcXdYV0QzV2VRd0V6YkowZ29oOFFqRHVvZGcyb281OEZkZVp5TjVIcHFyejRZQ0VMbkxydXlCUmpFdjNTWnRsQ3gxMWthNDNxbEwzM1lJYVlaV2t3dEhOMm9VaXllNFpKOHFnU1FueEZ4N0c4RDhabzBhajFFeEJIZTlJUFQ0VUo3UkR0V0g2Y3A3bkY3bXlkVHB4Wnp5NG1kRlgxa3M5eC9iVlJHaVFDRnU4VEFsUVdDdHEzbmJ1TnNYZVd3Q2dXWEd1OEUzMld3THVFRzRCZFRCanA2MGtYUT09');
sock.onopen = function (data) {
if (tick) {
clearInterval(tick)
}
tick = setInterval(function () {
sock.send(JSON.stringify({'route': 'getUserPosition', 'tick': new Date().getTime()}));
sock.send(JSON.stringify({'event': 'tick', 'id': unique, 'data': {'math': Math.ceil(Math.random() * 1000000)}}));
}, 3000)
}
}
+96 -42
View File
@@ -1,51 +1,105 @@
<?php
ini_set('memory_limit','64GB');
use wchat\common\AppConfig;
use wchat\wx\V3\Libs\TransferDetail;
use wchat\wx\V3\Libs\TransferSceneReportInfo;
use wchat\wx\V3\WxV3Transfer;
use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client;
use function Swoole\Coroutine\run;
//ini_set('memory_limit', '64G');
function faker($page = 0)
{
$client = new Client('openapi.stupideyes.com', 443, true);
$client->get('/faker?offset=' . $page);
$client->close();
$msg = 'default';
try {
return json_decode($client->getBody(), true);
if (random_int(1, 10) % 3 === 0) {
return;
}
$msg = 'default2';
} catch (\Exception $e) {
} finally {
var_dump($msg);
}
run(function () {
$offset = 1;
$success = 0;
for ($i = 1; $i <= 10000; $i++) {
$faker = faker($offset);
$offset++;
go(function () use ($faker, $offset, &$success) {
$socket = new Swoole\Coroutine\Http\Client('43.248.128.57', 14101);
$socket->upgrade("/ws?access_token=" . $faker['params']['token']);
if ($socket->connected) {
$success += 1;
while (true) {
$socket->recv();
// $socket->push('hello');
// var_dump($socket->recv());
Coroutine::sleep(0.1);
}
} else {
$success -= 1;
echo 'websocket fail: ' . socket_strerror($socket->errCode) . PHP_EOL;
}
});
Coroutine::sleep(0.1);
var_dump($success);
}
//run(function () {
// $offset = 1;
// $success = 0;
//
// $group = new Coroutine\WaitGroup();
// for ($i = 0; $i < 54500; $i++) {
// $offset++;
//
// $group->add(1);
// Swoole\Coroutine::create(function () use ($offset, &$success) {
// $socket = new Swoole\Coroutine\Http\Client('192.168.0.57', 14101);
// $socket->upgrade("/websocket");
// if ($socket->connected) {
// $success += 1;
// while (true) {
// $socket->recv();
// Coroutine::sleep(0.1);
//
// $socket->push("2");
// }
// } else {
// echo 'websocket fail: ' . socket_strerror($socket->errCode) . PHP_EOL;
// echo $success;
// }
// # echo $offset . PHP_EOL;
// });
// }
// $group->wait();
//});
//
//
//function Index_Odd()
//{
//
//}
});
//class Dispatcher
//{
//
//
// public function dispatch(){
//
// }
//
//
// public static function dispatch1()
// {
//
// }
//
//
//}
//$t = microtime(true);
//var_dump(method_exists('Dispatcher', 'dispatch'));
//var_dump(method_exists('Dispatcher', 'dispatch1'));
//
//var_dump(microtime(true) - $t);
//
//$t = microtime(true);
//
//$r = new ReflectionClass('Dispatcher');
//
//var_dump($r->hasMethod('dispatch'));
//var_dump($r->hasMethod('dispatch1') && $r->getMethod('dispatch1')->isStatic());
//
//var_dump(microtime(true) - $t);
//$transferDetail = new TransferDetail();
//$transferDetail->setTransferAmount(1);
//$transferDetail->setTransferRemark("提现");
//$transferDetail->setTransferSceneId("1005");
//$transferDetail->setOpenid("xxxxx");
//$transferDetail->setNotifyUrl("https");
//$transferDetail->setOutBillNo("");
//$transferDetail->setTransferSceneReportInfos(new TransferSceneReportInfo('', ''), new TransferSceneReportInfo('', ''));
//$transferDetail->setUserName("");
//$transferDetail->setUserRecvPerception("");
//
//$transfer = new WxV3Transfer();
//$transfer->setPayConfig(AppConfig::instance((object)[]));
//$response = $transfer->transfer($transferDetail);