Compare commits

..

61 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
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
30 changed files with 1921 additions and 1669 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",
+777 -730
View File
File diff suppressed because it is too large Load Diff
-238
View File
@@ -1,238 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use Exception;
use JsonSerializable;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
/**
* @Actor
*/
abstract class Actor implements ActorInterface, JsonSerializable
{
/**
* @var Channel
*/
private Channel $channel;
/**
* @var bool
*/
private bool $isShutdown = false;
/**
* @var int
*/
private int $messageId = -1;
/**
* @var int
*/
private int $coroutineId = -1;
/**
* @var ActorState
*/
private ActorState $state;
/**
* @var float
*/
private float $startTime = 0;
/**
* @var int
*/
private int $refreshInterval = 0;
/**
* @return ActorState
*/
public function getState(): ActorState
{
return $this->state;
}
/**
* @param ActorState $state
*/
public function setState(ActorState $state): void
{
$this->state = $state;
}
/**
* @return float
*/
public function getRunTime(): float
{
return microtime(true) - $this->startTime;
}
/**
* @param string $uniqueId
*/
private function __construct(readonly public string $uniqueId)
{
$this->channel = new Channel(99);
$this->startTime = microtime(true);
}
/**
* @return void
*/
public function init(): void
{
}
/**
* @return bool
*/
public function isShutdown(): bool
{
return $this->isShutdown;
}
/**
* @param $id
* @return static
*/
public static function newActor($id): static
{
$actor = new static($id);
$actor->listen();
return $actor;
}
/**
* @return void
*/
private function listen(): void
{
Coroutine::create(function (Actor $actor) {
$actor->coroutineId = Coroutine::getCid();
$this->run();
}, $this);
}
/**
* @return string
*/
public function getName(): string
{
return $this->uniqueId;
}
/**
* @param mixed $response
* @return bool
*/
public function write(mixed $response): bool
{
return $this->channel->push($response);
}
/**
* @return void
*/
public function shutdown(): void
{
$this->isShutdown = true;
Coroutine::cancel($this->coroutineId);
if ($this->messageId > -1) {
Coroutine::cancel($this->messageId);
}
$this->channel->close();
}
/**
* @return void
*/
public function onUpdate(): void
{
}
/**
* @return void
* @throws Exception
*/
public function run(): void
{
if ($this->refreshInterval < 1) {
throw new Exception('Refresh interval must be greater than 1');
}
$this->setState(ActorState::BUSY);
$this->init();
$this->messageId = Coroutine::create(fn() => $this->loop());
$this->interval();
$this->setState(ActorState::IDLE);
}
/**
* @return void
*/
private function interval(): void
{
if ($this->isShutdown()) {
return;
}
try {
$this->onUpdate();
} catch (\Throwable $exception) {
error($exception);
}
Coroutine::sleep($this->refreshInterval / 1000);
$this->interval();
}
/**
* @return bool
*/
private function loop(): bool
{
if ($this->messageId == -1) {
$this->messageId = Coroutine::getCid();
}
if ($this->channel->errCode == SWOOLE_CHANNEL_CLOSED) {
$this->channel = new Channel(99);
}
$message = $this->channel->pop();
$this->process($message);
if ($this->isShutdown()) {
return true;
}
return $this->loop();
}
}
-15
View File
@@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
interface ActorInterface
{
/**
* @param ActorMessage $message
* @return void
*/
public function process(ActorMessage $message): void;
}
-110
View File
@@ -1,110 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use Swoole\Coroutine;
class ActorManager
{
/** @var array<string, ActorInterface> */
private array $nodes = [];
/**
* @param Actor $actor
* @return void
*/
public function addActor(ActorInterface $actor): void
{
$this->nodes[$actor->uniqueId] = $actor;
Coroutine::create(function (Actor $actor) {
$actor->run();
}, $actor);
}
/**
* @param $name
* @return void
*/
public function closeActor($name): void
{
$node = $this->nodes[$name] ?? null;
if (is_null($node)) {
return;
}
foreach ($node as $actor) {
$actor->shutdown();
}
}
/**
* @param $name
* @param $message
* @return bool
*/
public function write($name, $message): bool
{
$actor = $this->nodes[$name] ?? null;
if (is_null($actor)) {
return false;
}
return $actor->write($message);
}
/**
* @param $name
* @return array
*/
public function lists($name): array
{
$array = [];
foreach ($this->nodes[$name] as $actor) {
$array[] = [
'id' => $actor->getName(),
'state' => $actor->getState()->name,
'runTime' => $actor->getRunTime()
];
}
return $array;
}
/**
* @param string $uniqueId
* @return bool
*/
public function hasActor(string $uniqueId): bool
{
return isset($this->nodes[$uniqueId]) && $this->nodes[$uniqueId] instanceof ActorInterface;
}
/**
* @param array|null $data
* @return void
*/
public static function exec(?array $data): void
{
if (is_null($data)) {
return;
}
}
/**
* @return void
*/
public function clean(): void
{
foreach ($this->nodes as $actor) {
$actor->shutdown();
}
$this->nodes = [];
}
}
-78
View File
@@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
namespace Kiri\Actor;
use JetBrains\PhpStorm\ArrayShape;
class ActorMessage implements \JsonSerializable
{
/**
* @var int
*/
private int $userId;
/**
* @var string
*/
private string $event;
/**
* @var array
*/
private array $body;
/**
* @param int $userId
* @param string $event
* @param array $body
*/
public function __construct(int $userId, string $event, array $body)
{
$this->userId = $userId;
$this->event = $event;
$this->body = $body;
}
/**
* @return int
*/
public function getUserId(): int
{
return $this->userId;
}
/**
* @return string
*/
public function getEvent(): string
{
return $this->event;
}
/**
* @return array
*/
public function getBody(): array
{
return $this->body;
}
/**
* @return array
*/
#[ArrayShape(['userId' => "int", 'event' => "string", 'body' => "array"])]
public function jsonSerialize(): array
{
return [
'userId' => $this->userId,
'event' => $this->event,
'body' => $this->body
];
}
}
-55
View File
@@ -1,55 +0,0 @@
<?php
namespace Kiri\Actor;
use Kiri\Server\Abstracts\BaseProcess;
use Swoole\Coroutine;
use Swoole\Process;
class ActorProcess extends BaseProcess
{
/**
* @var bool
*/
protected bool $enable_coroutine = true;
/**
* @return string
*/
public function getName(): string
{
// TODO: Change the autogenerated stub
return '[' . \config('id', 'system-service') . '].Actor Manager';
}
public function process(?Process $process): void
{
// TODO: Implement process() method.
while ($this->isStop() === false) {
$read = $process->read();
ActorManager::exec(json_decode($read, true));
Coroutine::sleep(1000 / 120);
}
}
/**
* @return $this
*/
public function onSigterm(): static
{
// TODO: Implement onSigterm() method.
Coroutine::create(function () {
$sign = Coroutine::waitSignal(SIGINT | SIGTERM);
if ($sign) {
$this->onShutdown(true);
}
});
return $this;
}
}
-18
View File
@@ -1,18 +0,0 @@
<?php
namespace Kiri\Actor;
enum ActorState
{
case IDLE;
case BUSY;
/**
*
*/
case CREATE;
case MESSAGE;
case SHUTDOWN;
}
+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 . '/';
}
+44 -78
View File
@@ -1,99 +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;
use Kiri\Error\StdoutLogger;
use ReflectionException;
use Kiri\Events\EventDispatch;
use Kiri\Events\EventProvider;
use Psr\Container\ContainerInterface;
/**
* Class Component
* @package Kiri\Base
*/
class Component implements Configure
class Component
{
public function __construct()
{
}
/**
* BaseAbstract constructor.
*/
public function __construct()
{
}
public function init(): void
{
}
#[Pure] public static function className(): string
{
return static::class;
}
/**
* @return void
*/
public function init(): void
{
}
/**
* @throws
*/
public function getLogger(): StdoutLogger
{
return Kiri::getLogger();
}
public function getDispatch(): EventDispatch
{
return Kiri::getDi()->get(EventDispatch::class);
}
/**
* @return string
*/
#[Pure] public static function className(): string
{
return static::class;
}
public function getProvider(): EventProvider
{
return Kiri::getDi()->get(EventProvider::class);
}
public function getContainer(): ContainerInterface
{
return Kiri::getDi();
}
/**
* @return StdoutLogger
* @throws
*/
public function getLogger(): StdoutLogger
{
return Kiri::getLogger();
}
/**
* @param string $name
* @return mixed
* @throws
*/
public function __get(string $name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->{$method}();
} else if (method_exists($this, $name)) {
return $this->{$name};
} else {
throw new Exception('Unable getting property ' . get_called_class() . '::' . $name);
}
}
/**
* @param 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);
}
}
/**
* @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);
}
}
-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];
}
}
-13
View File
@@ -4,24 +4,11 @@ declare(strict_types=1);
namespace Kiri\Abstracts;
use Kiri;
use Psr\Container\ContainerInterface;
/**
* Class Providers
* @package Kiri\Abstracts
* @property-read ContainerInterface $container
*/
abstract class Providers extends Component implements Provider
{
/**
* @return ContainerInterface
*/
public function getContainer(): ContainerInterface
{
return Kiri::getDi();
}
}
+13 -17
View File
@@ -10,17 +10,12 @@ declare(strict_types=1);
namespace Kiri;
use Exception;
use Kiri;
use Kiri\Abstracts\{BaseApplication, Kernel};
use Kiri\Di\Scanner;
use Kiri\Error\ErrorHandler;
use Kiri\Events\{OnAfterCommandExecute, OnBeforeCommandExecute};
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use ReflectionException;
use Symfony\Component\Console\{Application as ConsoleApplication,
Exception\ExceptionInterface,
Input\ArgvInput,
Output\ConsoleOutput,
Output\OutputInterface
@@ -59,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();
}
@@ -75,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/');
}
@@ -129,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 -8
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 = false;
private bool $wait = false;
private ?Channel $channel = null;
/**
@@ -17,19 +21,28 @@ class Coordinator
*/
public function yield(): void
{
if ($this->waite === false) {
if (Coroutine::getCid() > 0) {
if ($this->channel instanceof Channel) {
$this->channel->pop();
}
return;
}
$this->yield();
if ($this->wait === false) {
return;
}
while ($this->wait === true) {
usleep(1000);
}
}
/**
* @return void
*/
public function waite(): void
public function wait(): void
{
$this->waite = true;
Coroutine::getCid() > 0 ? $this->channel = new Channel(1) : $this->wait = true;
}
@@ -38,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';
}
}
+9 -17
View File
@@ -11,17 +11,12 @@ namespace Kiri\Error;
use Closure;
use ErrorException;
use Exception;
use Kiri\Abstracts\Component;
use Psr\Container\ContainerInterface;
use Kiri\Di\Inject\Container;
use ReflectionException;
use Kiri\Events\OnSystemError;
use Throwable;
/**
* Class ErrorHandler
* hahahah
* @package Kiri\Base
* @property-read $asError
*/
@@ -34,13 +29,6 @@ class ErrorHandler extends Component implements ErrorInterface
public string $category = 'app';
/**
* @var ContainerInterface
*/
#[Container(ContainerInterface::class)]
public ContainerInterface $container;
/**
* @param array|Closure|null $callback
* @return void
@@ -51,7 +39,7 @@ class ErrorHandler extends Component implements ErrorInterface
if (empty($callback)) {
$callback = [$this, 'exceptionHandler'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = $this->container->get($callback[0]);
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
set_exception_handler($callback);
}
@@ -67,7 +55,7 @@ class ErrorHandler extends Component implements ErrorInterface
if (empty($callback)) {
$callback = [$this, 'errorHandler'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = $this->container->get($callback[0]);
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
set_error_handler($callback);
}
@@ -83,7 +71,7 @@ class ErrorHandler extends Component implements ErrorInterface
if (empty($callback)) {
$callback = [$this, 'shutdown'];
} else if (is_array($callback) && is_string($callback[0])) {
$callback[0] = $this->container->get($callback[0]);
$callback[0] = \Kiri::getDi()->get($callback[0]);
}
register_shutdown_function($callback);
}
@@ -101,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());
}
@@ -116,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());
}
@@ -129,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]);
+23 -21
View File
@@ -9,7 +9,7 @@ use Monolog\Formatter\LineFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;
use ReflectionException;
use Throwable;
/**
@@ -49,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,
@@ -68,31 +68,32 @@ 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
* @return bool
*/
protected function dump($message): bool
{
$message = throwable($message);
if (str_contains($message, 'inotify_rm_watch')) {
return false;
}
file_put_contents('php://output', '[' . date('Y-m-d H:i:s') . '] ' . $message, FILE_APPEND);
$this->error($message, []);
return false;
}
/**
* @param 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;
}
/**
@@ -119,9 +120,10 @@ 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,17 +7,15 @@
*/
declare(strict_types=1);
namespace Kiri\Redis;
namespace Kiri\NoSql;
use Exception;
use Kiri;
use Kiri\Exception\RedisConnectException;
use Kiri\Pool\Pool;
use RedisException;
use function config;
/**
* Class Redis
* Class NoSql
* @package Kiri\Cache
* @mixin \Redis
*/
@@ -105,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
redis.call('expire',KEYS[1], ARGV[1])
return 1
end
return 0
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);
}
@@ -133,11 +131,13 @@ SCRIPT;
*/
public function destroy(): void
{
$this->pool()->close($this->host);
$this->pool()->close($this->getName());
}
/**
* 代理 Redis 方法调用,内置健康检查和连接回收
* 如果连接 ping 失败则关闭连接并移除,不归还池中防止污染
* @param $name
* @param $arguments
* @return mixed
@@ -149,22 +149,34 @@ 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->host, $client);
$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->host);
return $this->pool()->get($this->getName());
}
@@ -175,13 +187,22 @@ SCRIPT;
protected function pool(): Pool
{
$pool = Kiri::getPool();
if (!$pool->hasChannel($this->host)) {
$pool->created($this->host, $this->pool['max'], [$this, 'connect']);
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
@@ -190,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) {
+24
View File
@@ -1 +1,25 @@
<?php
use Swoole\Timer;
use Swoole\WebSocket\Server;
$client = new Server("0.0.0.0", 9511);
$client->addProcess(new Swoole\Process(function (\Swoole\Process $server) use ($client) {
while (true) {
echo json_encode($client->stats(), JSON_UNESCAPED_UNICODE) . PHP_EOL;
sleep(1);
}
}));
$client->on('open', function (Server $server) {
});
$client->on('message', function (Server $server, $frame) {
});
$client->on('close', function (Server $server, $fd) {
});
$client->start();
+38 -20
View File
@@ -9,38 +9,55 @@
white-space: pre-wrap;
word-wrap: break-word;
overflow-y: scroll;
overflow: hidden;
overflow: hidden;
}
</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)
}
}
+104
View File
@@ -1 +1,105 @@
<?php
use wchat\common\AppConfig;
use wchat\wx\V3\Libs\TransferDetail;
use wchat\wx\V3\Libs\TransferSceneReportInfo;
use wchat\wx\V3\WxV3Transfer;
//ini_set('memory_limit', '64G');
$msg = 'default';
try {
if (random_int(1, 10) % 3 === 0) {
return;
}
$msg = 'default2';
} catch (\Exception $e) {
} finally {
var_dump($msg);
}
//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);