Skip to content

Commit f897d20

Browse files
authored
[PHP/ripple] Added ripple coroutine engine. (#9377)
* [PHP/ripple] Added ripple coroutine engine. * [PHP/ripple] Update dependent version
1 parent a7b33c3 commit f897d20

File tree

6 files changed

+363
-0
lines changed

6 files changed

+363
-0
lines changed

frameworks/PHP/ripple/README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<p align="center">
2+
<img src="https://raw.githubusercontent.com/cloudtay/ripple/refs/heads/main/assets/images/logo.png" width="420" alt="Logo">
3+
</p>
4+
<p align="center">
5+
<a href="#"><img src="https://img.shields.io/badge/PHP-%3E%3D%208.1-blue" alt="Build Status"></a>
6+
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/dt/cloudtay/ripple" alt="Download statistics"> </a>
7+
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/v/cloudtay/ripple" alt="Stable version"> </a>
8+
<a href="https://packagist.org/packages/cloudtay/ripple"><img src="https://img.shields.io/packagist/l/cloudtay/ripple" alt="License"></a>
9+
</p>
10+
<p>
11+
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.
12+
The engine uses an innovative architecture and efficient programming model to provide powerful and flexible backend support for modern web and web applications.
13+
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>
14+
15+
## Install
16+
17+
````bash
18+
composer require cloudtay/ripple
19+
````
20+
21+
## Latest documentation
22+
23+
You can visit `ripple`’s [documentation](https://ripple.cloudtay.com/) to start reading
24+
25+
We recommend that you start with [Manual Installation](https://ripple.cloudtay.com/docs/install/professional) to better
26+
understand the workflow of ripple
27+
28+
If you want to quickly deploy and use `ripple` services, you can directly
29+
visit [Quick Deployment](https://ripple.cloudtay.com/docs/install/server)
30+
31+
## Appendix
32+
33+
### Applicable component library
34+
35+
> We allow users to choose applicable component libraries by themselves. All components can be used as described in the
36+
> document without additional configuration.
37+
38+
**🚀 [Guzzle](https://docs.guzzlephp.org/en/stable/)**
39+
PHP is the most widely used HTTP client
40+
41+
**🔥 [AmPHP](https://amphp.org/)**
42+
Provides rich PHP asynchronous components for users to encapsulate by themselves
43+
44+
**🚀 [Driver](https://github.com/cloudtay/ripple-driver)**
45+
The official high-performance driver library provides seamless access to your traditional applications.
46+
47+
**🚀 [Webman-coroutine](https://github.com/workbunny/webman-coroutine)**
48+
The workbunny team's integrated webman coroutine extension provides coroutine support for Webman.
49+
50+
**🟢[ripple](https://github.com/cloudtay/ripple)**
51+
Provides standard coroutine architecture and tools for rapid development or packaging of traditional applications
52+
53+
### Event Library Guide
54+
55+
| Extension Types | Recommended Use | Compatibility | Description |
56+
|:---------------:|:---------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------:|
57+
| `libev` | 🏅️ | 🟢️ | `Ev` is a more efficient event extension that performs consistently in various systems and is recommended to be used |
58+
| `Native` || 🟢 | Support the use of PHP's built-in select mechanism |
59+
| `event` | | 🌗 | The event characteristics under different systems are not uniform, and their use is not recommended |
60+
61+
## Special thanks
62+
63+
<a href="https://www.jetbrains.com/?from=ripple" target="__blank">
64+
<img src="https://www.jetbrains.com/company/brand/img/jetbrains_logo.png" width="200" alt="jetbrains">
65+
</a>
66+
67+
[Jetbrains](https://www.jetbrains.com/?from=ripple) provides free development tools for this project
68+
69+
### Contact information
70+
71+
72+
73+
`WeChat` jingnigg
74+
75+
---
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"framework": "ripple",
3+
"tests": [
4+
{
5+
"default": {
6+
"json_url": "/json",
7+
"db_url": "/db",
8+
"query_url": "/queries?queries=",
9+
"fortune_url": "/fortunes",
10+
"update_url": "/updates?queries=",
11+
"plaintext_url": "/plaintext",
12+
"port": 8080,
13+
"approach": "Realistic",
14+
"classification": "Fullstack",
15+
"database": "MySQL",
16+
"framework": "ripple",
17+
"language": "PHP",
18+
"flavor": "PHP8.3",
19+
"orm": "Raw",
20+
"platform": "ripple",
21+
"os": "Linux",
22+
"database_os": "Linux",
23+
"display_name": "ripple",
24+
"notes": "",
25+
"versus": "php"
26+
}
27+
}
28+
]
29+
}

frameworks/PHP/ripple/composer.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"require": {
3+
"ext-pdo": "*",
4+
"cloudtay/ripple-http": "^1.0",
5+
"cloudtay/ripple": "^1.0"
6+
},
7+
"minimum-stability": "beta",
8+
"prefer-stable": true
9+
}

frameworks/PHP/ripple/fortunes.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php /*** @var array $rows */?><!DOCTYPE html>
2+
<html lang="en">
3+
<head><title>Fortunes</title></head>
4+
<body>
5+
<table>
6+
<tr>
7+
<th>id</th>
8+
<th>message</th>
9+
</tr>
10+
<?php foreach ($rows as $row): ?>
11+
<tr>
12+
<td><?= \htmlspecialchars($row['id']) ?></td>
13+
<td><?= \htmlspecialchars($row['message']) ?></td>
14+
</tr>
15+
<?php endforeach; ?>
16+
</table>
17+
</body>
18+
</html>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
FROM php:8.3-cli
2+
3+
RUN apt-get update -yqq >> /dev/null
4+
RUN apt-get install -y libevent-dev \
5+
libssl-dev \
6+
pkg-config \
7+
build-essential \
8+
unzip >> /dev/null
9+
10+
RUN docker-php-ext-install pdo_mysql \
11+
opcache \
12+
posix \
13+
pcntl \
14+
sockets >> /dev/null
15+
16+
RUN pecl install event >> /dev/null
17+
18+
RUN docker-php-ext-enable posix pcntl sockets
19+
RUN docker-php-ext-enable --ini-name zz-event.ini event
20+
21+
COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer
22+
23+
# Initialize
24+
WORKDIR /ripple
25+
COPY --link . .
26+
27+
# Configure
28+
RUN composer install --quiet
29+
30+
# Start
31+
EXPOSE 8080
32+
ENTRYPOINT ["php","server.php"]

frameworks/PHP/ripple/server.php

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
<?php declare(strict_types=1);
2+
3+
include __DIR__ . '/vendor/autoload.php';
4+
5+
use Ripple\Http\Server;
6+
use Ripple\Worker\Manager;
7+
8+
use function Co\repeat;
9+
use function Co\wait;
10+
11+
class Setup
12+
{
13+
public static PDO $pdo;
14+
public static string $dateFormatted;
15+
16+
public static PDOStatement $queryWorldWhereID;
17+
public static PDOStatement $updateWorldRandomNumber;
18+
public static PDOStatement $queryFortune;
19+
20+
public static function dateRefresh(): void
21+
{
22+
try {
23+
$date = new DateTime('now', new DateTimeZone('GMT'));
24+
} catch (Throwable $e) {
25+
return;
26+
}
27+
Setup::$dateFormatted = $date->format('D, d M Y H:i:s T');
28+
}
29+
30+
31+
/**
32+
* @return int
33+
*/
34+
public static function randomInt(): int
35+
{
36+
try {
37+
return \random_int(1, 10000);
38+
} catch (Throwable $e) {
39+
return mt_rand(1, 10000);
40+
}
41+
}
42+
43+
/**
44+
* @param mixed $value
45+
*
46+
* @return int
47+
*/
48+
public static function clamp(mixed $value): int
49+
{
50+
if (!\is_numeric($value) || $value < 1) {
51+
return 1;
52+
}
53+
if ($value > 500) {
54+
return 500;
55+
}
56+
return \intval($value);
57+
}
58+
59+
/**
60+
* @param string $template
61+
* @param array $data
62+
*
63+
* @return string
64+
*/
65+
public static function render(string $template, array $data = []): string
66+
{
67+
foreach ($data as $key => $value) {
68+
$$key = $value;
69+
}
70+
71+
\ob_start();
72+
include $template;
73+
return \ob_get_clean();
74+
}
75+
}
76+
77+
$manager = new Manager();
78+
$worker = new class() extends \Ripple\Worker {
79+
/*** @var \Ripple\Http\Server */
80+
public Server $server;
81+
82+
/**
83+
* @param \Ripple\Worker\Manager $manager
84+
*
85+
* @return void
86+
*/
87+
public function register(Manager $manager): void
88+
{
89+
$this->count = 64;
90+
$this->server = new Server('http://0.0.0.0:8080');
91+
}
92+
93+
/**
94+
* @return void
95+
*/
96+
public function boot(): void
97+
{
98+
Setup::dateRefresh();
99+
repeat(static fn () => Setup::dateRefresh(), 1);
100+
101+
Setup::$pdo = new \PDO(
102+
'mysql:host=tfb-database;port=3306;dbname=hello_world',
103+
'benchmarkdbuser',
104+
'benchmarkdbpass',
105+
[
106+
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
107+
\PDO::ATTR_EMULATE_PREPARES => false,
108+
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
109+
]
110+
);
111+
112+
Setup::$queryWorldWhereID = Setup::$pdo->prepare('SELECT id, randomNumber FROM World WHERE id = ?');
113+
Setup::$updateWorldRandomNumber = Setup::$pdo->prepare('UPDATE World SET randomNumber = ? WHERE id = ?');
114+
Setup::$queryFortune = Setup::$pdo->prepare('SELECT * FROM `Fortune`');
115+
$this->server->onRequest(fn (Server\Request $request) => $this->onRequest($request));
116+
$this->server->listen();
117+
}
118+
119+
/**
120+
* @param \Ripple\Http\Server\Request $request
121+
*
122+
* @return void
123+
*/
124+
public function onRequest(Server\Request $request): void
125+
{
126+
switch ($request->SERVER['REQUEST_URI']) {
127+
case '/json':
128+
$request->respondJson(
129+
['message' => 'Hello, World!'],
130+
['Date' => Setup::$dateFormatted]
131+
);
132+
break;
133+
134+
case '/db':
135+
$statement = Setup::$queryWorldWhereID;
136+
$statement->execute([Setup::randomInt()]);
137+
$request->respondJson($statement->fetch(), ['Date' => Setup::$dateFormatted]);
138+
break;
139+
140+
case '/queries':
141+
$queries = Setup::clamp($request->GET['queries'] ?? 1);
142+
$results = [];
143+
$statement = Setup::$queryWorldWhereID;
144+
while ($queries--) {
145+
$statement->execute([Setup::randomInt()]);
146+
$results[] = $statement->fetch();
147+
}
148+
$request->respondJson($results, ['Date' => Setup::$dateFormatted]);
149+
150+
break;
151+
case '/fortunes':
152+
$rows = Setup::$pdo->query('SELECT * FROM `Fortune`')?->fetchAll();
153+
$rows[] = ['id' => 0, 'message' => 'Additional fortune added at request time.'];
154+
\usort($rows, function ($a, $b) {
155+
return $a['message'] <=> $b['message'];
156+
});
157+
158+
$request->respondHtml(
159+
Setup::render('fortunes.php', ['rows' => $rows]),
160+
[
161+
'Date' => Setup::$dateFormatted,
162+
'Content-Type' => 'text/html; charset=UTF-8'
163+
]
164+
);
165+
break;
166+
167+
case '/updates':
168+
$queries = Setup::clamp($request->GET['queries'] ?? 1);
169+
$results = [];
170+
$statement = Setup::$queryWorldWhereID;
171+
$update = Setup::$updateWorldRandomNumber;
172+
while ($queries--) {
173+
$statement->execute([Setup::randomInt()]);
174+
$row = $statement->fetch();
175+
$row['randomNumber'] = Setup::randomInt();
176+
$results[] = $row;
177+
$update->execute([$row['randomNumber'], $row['id']]);
178+
}
179+
$request->respondJson($results, ['Date' => Setup::$dateFormatted]);
180+
break;
181+
182+
case '/plaintext':
183+
$request->respond(
184+
'Hello, World!',
185+
[
186+
'Content-Type' => 'text/plain; charset=utf-8',
187+
'Date' => Setup::$dateFormatted
188+
]
189+
);
190+
break;
191+
192+
default:
193+
$request->respond('Not Found', [], 404);
194+
}
195+
}
196+
};
197+
198+
$manager->addWorker($worker);
199+
$manager->run();
200+
wait();

0 commit comments

Comments
 (0)