Skip to content

Commit 97dbce8

Browse files
committed
Restructure objects, data flow, and tests
1 parent 1684d5b commit 97dbce8

File tree

7 files changed

+183
-143
lines changed

7 files changed

+183
-143
lines changed

run.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
$envConfig['HOST_ADDR'] . ':' . $envConfig['HOST_PORT']
1717
);
1818

19-
$server->init(null, true); // Standalone without an event loop or ReactPHP server
19+
//$server->init(null, true); // Standalone without an event loop or ReactPHP server
20+
$server->init(); // Standalone ReactPHP server
2021
$server->setLogger(true);
2122
$server->start();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace VerifierServer\Endpoints;
4+
5+
use React\Http\Message\Response;
6+
use Psr\Http\Message\ServerRequestInterface;
7+
use VerifierServer\PersistentState;
8+
9+
interface EndpointInterface
10+
{
11+
12+
/**
13+
* Handles the incoming HTTP request and generates the appropriate response.
14+
*
15+
* @param string $method The HTTP method of the request (e.g., 'GET', 'POST').
16+
* @param ServerRequestInterface|string $request The request payload, typically used for 'POST' requests.
17+
* @param string &$response The variable to store the generated response.
18+
* @param array &$content_type The variable to store the content type of the response.
19+
* @param string &$body The variable to store the body of the response.
20+
* @param bool $bypass_token Whether to bypass the token check.
21+
*/
22+
public function handle(string $method, ServerRequestInterface|string $request, int|string &$response, array &$content_type, string &$body, bool $bypass_token = false): void;
23+
}

src/VerifierServer/Endpoints/VerifiedEndpoint.php

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
use Psr\Http\Message\ServerRequestInterface;
77
use VerifierServer\PersistentState;
88

9-
class VerifiedEndpoint {
10-
public function __construct(private PersistentState $state)
9+
class VerifiedEndpoint implements EndpointInterface
10+
{
11+
public function __construct(private PersistentState &$state)
1112
{}
1213

1314
/**
@@ -19,15 +20,15 @@ public function __construct(private PersistentState $state)
1920
* @param array &$content_type The variable to store the content type of the response.
2021
* @param string &$body The variable to store the body of the response.
2122
*/
22-
public function handleRequest(string $method, ServerRequestInterface|string $request, int|string &$response, array &$content_type, string &$body): void
23+
public function handle(string $method, ServerRequestInterface|string $request, int|string &$response, array &$content_type, string &$body, bool $bypass_token = false): void
2324
{
2425
switch ($method) {
2526
case 'GET':
26-
$this->handleGet($response, $content_type, $body);
27+
$this->get($response, $content_type, $body);
2728
break;
2829
case 'POST':
2930
case 'DELETE':
30-
$this->handlePost($request, $response, $content_type, $body);
31+
$this->post($request, $response, $content_type, $body, $bypass_token);
3132
break;
3233
default:
3334
$response = Response::STATUS_METHOD_NOT_ALLOWED;
@@ -47,7 +48,7 @@ public function handleRequest(string $method, ServerRequestInterface|string $req
4748
* This method sets the HTTP status code to 200 OK and the Content-Type to application/json.
4849
* It then appends the JSON-encoded verification list to the response.
4950
*/
50-
private function handleGet(int|string &$response, array &$content_type, string &$body): void
51+
private function get(int|string &$response, array &$content_type, string &$body): void
5152
{
5253
$response = Response::STATUS_OK;
5354
$content_type = ['Content-Type' => 'application/json'];
@@ -70,7 +71,7 @@ private function handleGet(int|string &$response, array &$content_type, string &
7071
* 5. Retrieves the verification list from the state.
7172
* 6. Based on the method type, either deletes an entry from the list or handles the default case.
7273
*/
73-
private function handlePost(ServerRequestInterface|string $request, int|string &$response, array &$content_type, string &$body): void
74+
private function post(ServerRequestInterface|string $request, int|string &$response, array &$content_type, string &$body, bool $bypass_token = false): void
7475
{
7576
if ($request instanceof ServerRequestInterface) {
7677
$formData = $request->getHeaders();
@@ -98,7 +99,7 @@ private function handlePost(ServerRequestInterface|string $request, int|string &
9899
? trim(is_array($formData['token']) ? $formData['token'][0] : $formData['token'])
99100
: '';
100101

101-
if ($this->state->getToken() === 'changeme' || $token !== $this->state->getToken()) {
102+
if (!$bypass_token && ($this->state->getToken() === 'changeme' || $token !== $this->state->getToken())) {
102103
$response = Response::STATUS_UNAUTHORIZED;
103104
$content_type = ['Content-Type' => 'text/plain'];
104105
$body = 'Unauthorized';
@@ -111,7 +112,7 @@ private function handlePost(ServerRequestInterface|string $request, int|string &
111112
case 'delete':
112113
$existingIndex = array_search($ckey, array_column($list, 'ss13'));
113114
if ($existingIndex === false) $existingIndex = array_search($discord, array_column($list, 'discord'));
114-
$this->handleDelete(
115+
$this->delete(
115116
$existingIndex,
116117
$list,
117118
$response,
@@ -120,7 +121,7 @@ private function handlePost(ServerRequestInterface|string $request, int|string &
120121
);
121122
break;
122123
default:
123-
$this->handleDefault(
124+
$this->__post(
124125
$list,
125126
$ckey,
126127
$discord,
@@ -132,31 +133,6 @@ private function handlePost(ServerRequestInterface|string $request, int|string &
132133
}
133134
}
134135

135-
/**
136-
* Handles the deletion of an item from the list.
137-
*
138-
* @param int|string|false $existingIndex The index of the item to delete, or false if the item does not exist.
139-
* @param array &$list The list from which the item will be deleted.
140-
* @param string &$response The HTTP response message to be returned.
141-
* @param array &$content_type The variable to store the content type of the response.
142-
* @param string &$body The variable to store the body of the response.
143-
*/
144-
private function handleDelete(int|string|false $existingIndex, array &$list, int|string &$response, array &$content_type, string &$body): void
145-
{
146-
if ($existingIndex === false) {
147-
$response = Response::STATUS_NOT_FOUND;
148-
$content_type = ['Content-Type' => 'text/plain'];
149-
$body = 'Not Found';
150-
return;
151-
}
152-
$splice = array_splice($list, $existingIndex, 1);
153-
PersistentState::writeJson($this->state->getJsonPath(), $list);
154-
$this->state->setVerifyList($list);
155-
$response = Response::STATUS_OK;
156-
$content_type = ['Content-Type' => 'application/json'];
157-
$body = json_encode($splice);
158-
}
159-
160136
/**
161137
* Handles the default verification process.
162138
*
@@ -172,7 +148,7 @@ private function handleDelete(int|string|false $existingIndex, array &$list, int
172148
* @param array &$content_type The variable to store the content type of the response.
173149
* @param string &$body The variable to store the body of the response.
174150
*/
175-
public function handleDefault(array &$list, string $ckey, string $discord, int|string &$response, array &$content_type, string &$body): void
151+
private function __post(array &$list, string $ckey, string $discord, int|string &$response, array &$content_type, string &$body): void
176152
{
177153
$existingCkeyIndex = array_search($ckey, array_column($list, 'ss13'));
178154
$existingDiscordIndex = array_search($discord, array_column($list, 'discord'));
@@ -194,4 +170,29 @@ public function handleDefault(array &$list, string $ckey, string $discord, int|s
194170
$content_type = ['Content-Type' => 'application/json'];
195171
$body = json_encode($list);
196172
}
173+
174+
/**
175+
* Handles the deletion of an item from the list.
176+
*
177+
* @param int|string|false $existingIndex The index of the item to delete, or false if the item does not exist.
178+
* @param array &$list The list from which the item will be deleted.
179+
* @param string &$response The HTTP response message to be returned.
180+
* @param array &$content_type The variable to store the content type of the response.
181+
* @param string &$body The variable to store the body of the response.
182+
*/
183+
private function delete(int|string|false $existingIndex, array &$list, int|string &$response, array &$content_type, string &$body): void
184+
{
185+
if ($existingIndex === false) {
186+
$response = Response::STATUS_NOT_FOUND;
187+
$content_type = ['Content-Type' => 'text/plain'];
188+
$body = 'Not Found';
189+
return;
190+
}
191+
$splice = array_splice($list, $existingIndex, 1);
192+
PersistentState::writeJson($this->state->getJsonPath(), $list);
193+
$this->state->setVerifyList($list);
194+
$response = Response::STATUS_OK;
195+
$content_type = ['Content-Type' => 'application/json'];
196+
$body = json_encode($splice);
197+
}
197198
}

src/VerifierServer/PersistentState.php

Lines changed: 49 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,7 @@ public function __construct(
1313
private string $storageType = 'filesystem',
1414
private string $json_path = 'json/verify.json'
1515
) {
16-
$this->civToken = $civToken;
17-
$this->storageType = $storageType;
18-
1916
if ($this->storageType !== 'filesystem') {
20-
$env = self::loadEnvConfig();
21-
$dsn = $env['DB_DSN'];
22-
$username = $env['DB_USERNAME'];
23-
$password = $env['DB_PASSWORD'];
24-
$options = isset($env['DB_OPTIONS']) ? json_decode($env['DB_OPTIONS'], true) : [];
25-
$this->pdo = new \PDO($dsn, $username, $password, $options);
2617
$this->initializeDatabase();
2718
}
2819
}
@@ -47,6 +38,13 @@ public function __construct(
4738
*/
4839
private function initializeDatabase(): void
4940
{
41+
$env = self::loadEnvConfig();
42+
$this->pdo = new \PDO(
43+
$env['DB_DSN'],
44+
$env['DB_USERNAME'],
45+
$env['DB_PASSWORD'],
46+
isset($env['DB_OPTIONS']) ? json_decode($env['DB_OPTIONS'], true) : null
47+
);
5048
if (strpos($this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME), 'mysql') !== false) {
5149
if ($this->pdo->exec("CREATE TABLE IF NOT EXISTS verify_list (
5250
id INT AUTO_INCREMENT PRIMARY KEY,
@@ -80,9 +78,9 @@ private function initializeDatabase(): void
8078
*
8179
* @throws \PDOException If there is an error executing the query or fetching the data from the database.
8280
*/
83-
public function getVerifyList(): array
81+
public function getVerifyList(bool $getLocalCache = false): array
8482
{
85-
if ($this->storageType === 'filesystem') {
83+
if ($this->storageType === 'filesystem' || $getLocalCache) {
8684
return isset($this->verifyList)
8785
? $this->verifyList
8886
: $this->verifyList = self::loadVerifyFile($this->getJsonPath());
@@ -97,7 +95,7 @@ public function getVerifyList(): array
9795
$errorInfo = $this->pdo->errorInfo();
9896
throw new \PDOException("Failed to fetch data: " . implode(", ", $errorInfo));
9997
}
100-
return $result;
98+
return $this->verifyList = $result;
10199
}
102100

103101
/**
@@ -109,29 +107,26 @@ public function getVerifyList(): array
109107
*
110108
* @param array $list The list of verification items to be set. Each item in the list should be an associative array
111109
* with keys 'ss13', 'discord', and 'create_time'.
110+
* @param bool $write Whether to write the list to the database. Default is true.
112111
*
113112
* @throws \PDOException If there is an error deleting from the verify_list table, preparing the insert statement,
114113
* or executing the insert statement.
115114
*/
116-
public function setVerifyList(array $list): void
115+
public function setVerifyList(array $list, bool $write = true): void
117116
{
118-
if ($this->storageType === 'filesystem') {
119-
$this->verifyList = $list;
120-
return;
121-
}
122-
if ($this->pdo->exec("DELETE FROM verify_list") === false) {
123-
$errorInfo = $this->pdo->errorInfo();
124-
throw new \PDOException("Failed to delete from verify_list: " . implode(", ", $errorInfo));
125-
}
126-
$stmt = $this->pdo->prepare("INSERT INTO verify_list (ss13, discord, create_time) VALUES (:ss13, :discord, :create_time)");
127-
if ($stmt === false) {
128-
throw new \PDOException("Failed to prepare statement.");
129-
}
130-
foreach ($list as $item) {
131-
if (!$stmt->execute($item)) {
117+
if ($write && $this->storageType !== 'filesystem') {
118+
if ($this->pdo->exec("DELETE FROM verify_list") === false) {
119+
throw new \PDOException("Failed to delete from verify_list: " . implode(", ", $this->pdo->errorInfo()));
120+
}
121+
$stmt = $this->pdo->prepare("INSERT INTO verify_list (ss13, discord, create_time) VALUES (:ss13, :discord, :create_time)");
122+
if ($stmt === false) {
123+
throw new \PDOException("Failed to prepare statement.");
124+
}
125+
foreach ($list as $item) if (!$stmt->execute($item)) {
132126
throw new \PDOException("Failed to execute statement.");
133127
}
134128
}
129+
$this->verifyList = $list;
135130
}
136131

137132
/**
@@ -145,27 +140,13 @@ public function getToken(): string
145140
}
146141

147142
/**
148-
* Loads the verification data from the "verify.json" file.
149-
* If the file does not exist, it creates an empty JSON array file.
150-
* If the file cannot be read, it throws an exception.
143+
* Retrieves the JSON path associated with the persistent state.
151144
*
152-
* @return array|null The decoded JSON data as an associative array, or an empty array if the file is empty or invalid.
153-
* @throws \Exception If the file cannot be read.
145+
* @return string The file path to the JSON data.
154146
*/
155-
public static function loadVerifyFile(string $json_path): ?array
147+
public function getJsonPath(): string
156148
{
157-
$directory = dirname($json_path);
158-
if (!is_dir($directory)) {
159-
mkdir($directory, 0777, true);
160-
}
161-
if (!file_exists($json_path)) {
162-
file_put_contents($json_path, "[]");
163-
}
164-
$data = file_get_contents($json_path);
165-
if ($data === false) {
166-
throw new \Exception("Failed to read {$json_path}");
167-
}
168-
return json_decode($data, true) ?: [];
149+
return getcwd() . '/' . $this->json_path;
169150
}
170151

171152
/**
@@ -232,23 +213,37 @@ public static function loadEnvConfig(): array
232213
}
233214

234215
/**
235-
* Writes the given data to a file in JSON format.
216+
* Loads the verification data from the "verify.json" file.
217+
* If the file does not exist, it creates an empty JSON array file.
218+
* If the file cannot be read, it throws an exception.
236219
*
237-
* @param string $file The path to the file where the JSON data will be written.
238-
* @param mixed $data The data to be encoded as JSON and written to the file.
220+
* @return array|null The decoded JSON data as an associative array, or an empty array if the file is empty or invalid.
221+
* @throws \Exception If the file cannot be read.
239222
*/
240-
public static function writeJson(string $file, $data): void
223+
public static function loadVerifyFile(string $json_path): ?array
241224
{
242-
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
225+
$directory = dirname($json_path);
226+
if (!is_dir($directory)) {
227+
mkdir($directory, 0777, true);
228+
}
229+
if (!file_exists($json_path)) {
230+
file_put_contents($json_path, "[]");
231+
}
232+
$data = file_get_contents($json_path);
233+
if ($data === false) {
234+
throw new \Exception("Failed to read {$json_path}");
235+
}
236+
return json_decode($data, true) ?: [];
243237
}
244238

245239
/**
246-
* Retrieves the JSON path associated with the persistent state.
240+
* Writes the given data to a file in JSON format.
247241
*
248-
* @return string The file path to the JSON data.
242+
* @param string $file The path to the file where the JSON data will be written.
243+
* @param mixed $data The data to be encoded as JSON and written to the file.
249244
*/
250-
public function getJsonPath(): string
245+
public static function writeJson(string $file, array $data): void
251246
{
252-
return getcwd() . $this->json_path;
247+
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
253248
}
254249
}

0 commit comments

Comments
 (0)