-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PHP/ripple] Added ripple coroutine engine. (#9377)
* [PHP/ripple] Added ripple coroutine engine. * [PHP/ripple] Update dependent version
- Loading branch information
Showing
6 changed files
with
363 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<p align="center"> | ||
<img src="https://raw.githubusercontent.com/cloudtay/ripple/refs/heads/main/assets/images/logo.png" width="420" alt="Logo"> | ||
</p> | ||
<p align="center"> | ||
<a href="#"><img src="https://img.shields.io/badge/PHP-%3E%3D%208.1-blue" alt="Build Status"></a> | ||
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/dt/cloudtay/ripple" alt="Download statistics"> </a> | ||
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/v/cloudtay/ripple" alt="Stable version"> </a> | ||
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/l/cloudtay/ripple" alt="License"></a> | ||
</p> | ||
<p> | ||
Ripple is a modern, high-performance native PHP coroutine engine designed to solve PHP's challenges in high concurrency, complex network communication and data operations. | ||
The engine uses an innovative architecture and efficient programming model to provide powerful and flexible backend support for modern web and web applications. | ||
By using ripple, you will experience the advantages of managing tasks from a global view of the system and efficiently handling network traffic and data. </p> | ||
|
||
## Install | ||
|
||
````bash | ||
composer require cloudtay/ripple | ||
```` | ||
|
||
## Latest documentation | ||
|
||
You can visit `ripple`’s [documentation](https://ripple.cloudtay.com/) to start reading | ||
|
||
We recommend that you start with [Manual Installation](https://ripple.cloudtay.com/docs/install/professional) to better | ||
understand the workflow of ripple | ||
|
||
If you want to quickly deploy and use `ripple` services, you can directly | ||
visit [Quick Deployment](https://ripple.cloudtay.com/docs/install/server) | ||
|
||
## Appendix | ||
|
||
### Applicable component library | ||
|
||
> We allow users to choose applicable component libraries by themselves. All components can be used as described in the | ||
> document without additional configuration. | ||
**🚀 [Guzzle](https://docs.guzzlephp.org/en/stable/)** | ||
PHP is the most widely used HTTP client | ||
|
||
**🔥 [AmPHP](https://amphp.org/)** | ||
Provides rich PHP asynchronous components for users to encapsulate by themselves | ||
|
||
**🚀 [Driver](https://github.com/cloudtay/ripple-driver)** | ||
The official high-performance driver library provides seamless access to your traditional applications. | ||
|
||
**🚀 [Webman-coroutine](https://github.com/workbunny/webman-coroutine)** | ||
The workbunny team's integrated webman coroutine extension provides coroutine support for Webman. | ||
|
||
**🟢[ripple](https://github.com/cloudtay/ripple)** | ||
Provides standard coroutine architecture and tools for rapid development or packaging of traditional applications | ||
|
||
### Event Library Guide | ||
|
||
| Extension Types | Recommended Use | Compatibility | Description | | ||
|:---------------:|:---------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------:| | ||
| `libev` | 🏅️ | 🟢️ | `Ev` is a more efficient event extension that performs consistently in various systems and is recommended to be used | | ||
| `Native` | ️ | 🟢 | Support the use of PHP's built-in select mechanism | | ||
| `event` | | 🌗 | The event characteristics under different systems are not uniform, and their use is not recommended | | ||
|
||
## Special thanks | ||
|
||
<a href="https://www.jetbrains.com/?from=ripple" target="__blank"> | ||
<img src="https://www.jetbrains.com/company/brand/img/jetbrains_logo.png" width="200" alt="jetbrains"> | ||
</a> | ||
|
||
[Jetbrains](https://www.jetbrains.com/?from=ripple) provides free development tools for this project | ||
|
||
### Contact information | ||
|
||
`Email` [email protected] | ||
|
||
`WeChat` jingnigg | ||
|
||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"framework": "ripple", | ||
"tests": [ | ||
{ | ||
"default": { | ||
"json_url": "/json", | ||
"db_url": "/db", | ||
"query_url": "/queries?queries=", | ||
"fortune_url": "/fortunes", | ||
"update_url": "/updates?queries=", | ||
"plaintext_url": "/plaintext", | ||
"port": 8080, | ||
"approach": "Realistic", | ||
"classification": "Fullstack", | ||
"database": "MySQL", | ||
"framework": "ripple", | ||
"language": "PHP", | ||
"flavor": "PHP8.3", | ||
"orm": "Raw", | ||
"platform": "ripple", | ||
"os": "Linux", | ||
"database_os": "Linux", | ||
"display_name": "ripple", | ||
"notes": "", | ||
"versus": "php" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"require": { | ||
"ext-pdo": "*", | ||
"cloudtay/ripple-http": "^1.0", | ||
"cloudtay/ripple": "^1.0" | ||
}, | ||
"minimum-stability": "beta", | ||
"prefer-stable": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php /*** @var array $rows */?><!DOCTYPE html> | ||
<html lang="en"> | ||
<head><title>Fortunes</title></head> | ||
<body> | ||
<table> | ||
<tr> | ||
<th>id</th> | ||
<th>message</th> | ||
</tr> | ||
<?php foreach ($rows as $row): ?> | ||
<tr> | ||
<td><?= \htmlspecialchars($row['id']) ?></td> | ||
<td><?= \htmlspecialchars($row['message']) ?></td> | ||
</tr> | ||
<?php endforeach; ?> | ||
</table> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
FROM php:8.3-cli | ||
|
||
RUN apt-get update -yqq >> /dev/null | ||
RUN apt-get install -y libevent-dev \ | ||
libssl-dev \ | ||
pkg-config \ | ||
build-essential \ | ||
unzip >> /dev/null | ||
|
||
RUN docker-php-ext-install pdo_mysql \ | ||
opcache \ | ||
posix \ | ||
pcntl \ | ||
sockets >> /dev/null | ||
|
||
RUN pecl install event >> /dev/null | ||
|
||
RUN docker-php-ext-enable posix pcntl sockets | ||
RUN docker-php-ext-enable --ini-name zz-event.ini event | ||
|
||
COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer | ||
|
||
# Initialize | ||
WORKDIR /ripple | ||
COPY --link . . | ||
|
||
# Configure | ||
RUN composer install --quiet | ||
|
||
# Start | ||
EXPOSE 8080 | ||
ENTRYPOINT ["php","server.php"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
<?php declare(strict_types=1); | ||
|
||
include __DIR__ . '/vendor/autoload.php'; | ||
|
||
use Ripple\Http\Server; | ||
use Ripple\Worker\Manager; | ||
|
||
use function Co\repeat; | ||
use function Co\wait; | ||
|
||
class Setup | ||
{ | ||
public static PDO $pdo; | ||
public static string $dateFormatted; | ||
|
||
public static PDOStatement $queryWorldWhereID; | ||
public static PDOStatement $updateWorldRandomNumber; | ||
public static PDOStatement $queryFortune; | ||
|
||
public static function dateRefresh(): void | ||
{ | ||
try { | ||
$date = new DateTime('now', new DateTimeZone('GMT')); | ||
} catch (Throwable $e) { | ||
return; | ||
} | ||
Setup::$dateFormatted = $date->format('D, d M Y H:i:s T'); | ||
} | ||
|
||
|
||
/** | ||
* @return int | ||
*/ | ||
public static function randomInt(): int | ||
{ | ||
try { | ||
return \random_int(1, 10000); | ||
} catch (Throwable $e) { | ||
return mt_rand(1, 10000); | ||
} | ||
} | ||
|
||
/** | ||
* @param mixed $value | ||
* | ||
* @return int | ||
*/ | ||
public static function clamp(mixed $value): int | ||
{ | ||
if (!\is_numeric($value) || $value < 1) { | ||
return 1; | ||
} | ||
if ($value > 500) { | ||
return 500; | ||
} | ||
return \intval($value); | ||
} | ||
|
||
/** | ||
* @param string $template | ||
* @param array $data | ||
* | ||
* @return string | ||
*/ | ||
public static function render(string $template, array $data = []): string | ||
{ | ||
foreach ($data as $key => $value) { | ||
$$key = $value; | ||
} | ||
|
||
\ob_start(); | ||
include $template; | ||
return \ob_get_clean(); | ||
} | ||
} | ||
|
||
$manager = new Manager(); | ||
$worker = new class() extends \Ripple\Worker { | ||
/*** @var \Ripple\Http\Server */ | ||
public Server $server; | ||
|
||
/** | ||
* @param \Ripple\Worker\Manager $manager | ||
* | ||
* @return void | ||
*/ | ||
public function register(Manager $manager): void | ||
{ | ||
$this->count = 64; | ||
$this->server = new Server('http://0.0.0.0:8080'); | ||
} | ||
|
||
/** | ||
* @return void | ||
*/ | ||
public function boot(): void | ||
{ | ||
Setup::dateRefresh(); | ||
repeat(static fn () => Setup::dateRefresh(), 1); | ||
|
||
Setup::$pdo = new \PDO( | ||
'mysql:host=tfb-database;port=3306;dbname=hello_world', | ||
'benchmarkdbuser', | ||
'benchmarkdbpass', | ||
[ | ||
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, | ||
\PDO::ATTR_EMULATE_PREPARES => false, | ||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, | ||
] | ||
); | ||
|
||
Setup::$queryWorldWhereID = Setup::$pdo->prepare('SELECT id, randomNumber FROM World WHERE id = ?'); | ||
Setup::$updateWorldRandomNumber = Setup::$pdo->prepare('UPDATE World SET randomNumber = ? WHERE id = ?'); | ||
Setup::$queryFortune = Setup::$pdo->prepare('SELECT * FROM `Fortune`'); | ||
$this->server->onRequest(fn (Server\Request $request) => $this->onRequest($request)); | ||
$this->server->listen(); | ||
} | ||
|
||
/** | ||
* @param \Ripple\Http\Server\Request $request | ||
* | ||
* @return void | ||
*/ | ||
public function onRequest(Server\Request $request): void | ||
{ | ||
switch ($request->SERVER['REQUEST_URI']) { | ||
case '/json': | ||
$request->respondJson( | ||
['message' => 'Hello, World!'], | ||
['Date' => Setup::$dateFormatted] | ||
); | ||
break; | ||
|
||
case '/db': | ||
$statement = Setup::$queryWorldWhereID; | ||
$statement->execute([Setup::randomInt()]); | ||
$request->respondJson($statement->fetch(), ['Date' => Setup::$dateFormatted]); | ||
break; | ||
|
||
case '/queries': | ||
$queries = Setup::clamp($request->GET['queries'] ?? 1); | ||
$results = []; | ||
$statement = Setup::$queryWorldWhereID; | ||
while ($queries--) { | ||
$statement->execute([Setup::randomInt()]); | ||
$results[] = $statement->fetch(); | ||
} | ||
$request->respondJson($results, ['Date' => Setup::$dateFormatted]); | ||
|
||
break; | ||
case '/fortunes': | ||
$rows = Setup::$pdo->query('SELECT * FROM `Fortune`')?->fetchAll(); | ||
$rows[] = ['id' => 0, 'message' => 'Additional fortune added at request time.']; | ||
\usort($rows, function ($a, $b) { | ||
return $a['message'] <=> $b['message']; | ||
}); | ||
|
||
$request->respondHtml( | ||
Setup::render('fortunes.php', ['rows' => $rows]), | ||
[ | ||
'Date' => Setup::$dateFormatted, | ||
'Content-Type' => 'text/html; charset=UTF-8' | ||
] | ||
); | ||
break; | ||
|
||
case '/updates': | ||
$queries = Setup::clamp($request->GET['queries'] ?? 1); | ||
$results = []; | ||
$statement = Setup::$queryWorldWhereID; | ||
$update = Setup::$updateWorldRandomNumber; | ||
while ($queries--) { | ||
$statement->execute([Setup::randomInt()]); | ||
$row = $statement->fetch(); | ||
$row['randomNumber'] = Setup::randomInt(); | ||
$results[] = $row; | ||
$update->execute([$row['randomNumber'], $row['id']]); | ||
} | ||
$request->respondJson($results, ['Date' => Setup::$dateFormatted]); | ||
break; | ||
|
||
case '/plaintext': | ||
$request->respond( | ||
'Hello, World!', | ||
[ | ||
'Content-Type' => 'text/plain; charset=utf-8', | ||
'Date' => Setup::$dateFormatted | ||
] | ||
); | ||
break; | ||
|
||
default: | ||
$request->respond('Not Found', [], 404); | ||
} | ||
} | ||
}; | ||
|
||
$manager->addWorker($worker); | ||
$manager->run(); | ||
wait(); |