Add .ini for configuration
This commit is contained in:
parent
906fe39e39
commit
744373e584
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
/vendor/
|
||||
/.idea/
|
||||
/var/*
|
||||
!/var/.gitignore
|
||||
|
17
README.md
17
README.md
@ -3,10 +3,9 @@
|
||||
This is a simple fileserver written in PHP (7.4+) using [ZeroMQ](https://zeromq.org/).
|
||||
|
||||
There are three executable files:
|
||||
|
||||
- `$ ./server` runs the fileserver
|
||||
- `$ ./command <arg1> <arg2> ...` sends a command to the server
|
||||
- `$ ./query <arg1> <arg2> ...` sends a query to the server and returns the response
|
||||
- `$ bin/server` runs the fileserver
|
||||
- `$ bin/command <arg1> <arg2> ...` sends a command to the server
|
||||
- `$ bin/query <arg1> <arg2> ...` sends a query to the server and returns the response
|
||||
|
||||
## Commands
|
||||
|
||||
@ -15,9 +14,8 @@ There are three executable files:
|
||||
- `DELETE_ALL <namespace>` deletes an entire namespace
|
||||
|
||||
To save a file to the fileserver you can do:
|
||||
`$ ./command SAVE my-project-namespace 1.html "<!DOCTYPE html><html>...</html>"`
|
||||
`$ ./command SAVE my-project-namespace 2.xml "$(cat some/xml/file)"`
|
||||
|
||||
`$ bin/command SAVE my-project-namespace 1.html "<!DOCTYPE html><html>...</html>"`
|
||||
`$ bin/command SAVE my-project-namespace 2.xml "$(cat some/xml/file)"`
|
||||
|
||||
## Queries
|
||||
|
||||
@ -25,5 +23,8 @@ To save a file to the fileserver you can do:
|
||||
- `LOAD <namespace> <name>` returns the file contents if it exists, else `-1`
|
||||
|
||||
To load a file from the fileserver you can do:
|
||||
`$ ./query LOAD my-project-namespace 1.html`
|
||||
`$ bin/query LOAD my-project-namespace 1.html`
|
||||
|
||||
## Configuration
|
||||
|
||||
See `config/config.ini`. It contains an example configuration.
|
||||
|
13
bin/command
Executable file
13
bin/command
Executable file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
array_shift($argv);
|
||||
if (count($argv) === 0) {
|
||||
print('command needs at least one argument' . PHP_EOL);
|
||||
die(1);
|
||||
}
|
||||
|
||||
$ini = parse_ini_file(__DIR__ . '/../config/config.ini', true)['command'];
|
||||
$socket = new ZMQSocket(new ZMQContext, ZMQ::SOCKET_PUSH);
|
||||
$socket->connect($ini['dsn']);
|
||||
$socket->sendmulti($argv);
|
15
bin/query
Executable file
15
bin/query
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
array_shift($argv);
|
||||
if (count($argv) === 0) {
|
||||
print('query needs at least one argument' . PHP_EOL);
|
||||
die(1);
|
||||
}
|
||||
|
||||
$ini = parse_ini_file(__DIR__ . '/../config/config.ini', true)['query'];
|
||||
$socket = new ZMQSocket(new ZMQContext, ZMQ::SOCKET_REQ);
|
||||
$socket->connect($ini['dsn']);
|
||||
$socket->sendmulti($argv);
|
||||
print(implode(PHP_EOL, $socket->recvMulti()));
|
||||
print(PHP_EOL);
|
10
bin/server
Executable file
10
bin/server
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../src/FileServer.php';
|
||||
|
||||
$ini = parse_ini_file(__DIR__ . '/../config/config.ini', true)['server'];
|
||||
$ini['storage_dir'] = str_replace('%ROOT_DIR%', realpath(__DIR__ . '/..'), $ini['storage_dir']);
|
||||
|
||||
$server = new FileServer(new ZMQContext, $ini['storage_dir'], $ini['command_dsn'], $ini['query_dsn']);
|
||||
$server->run();
|
13
command
13
command
@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
array_shift($argv);
|
||||
if (count($argv) === 0) {
|
||||
print('Command needs at least one argument' . PHP_EOL);
|
||||
die(1);
|
||||
}
|
||||
|
||||
$context = new ZMQContext();
|
||||
$socket = new ZMQSocket($context, ZMQ::SOCKET_PUSH);
|
||||
$socket->connect('ipc:///tmp/storage_server_command.ipc');
|
||||
$socket->sendmulti($argv);
|
21
config/config.ini
Normal file
21
config/config.ini
Normal file
@ -0,0 +1,21 @@
|
||||
[server]
|
||||
; %ROOT_DIR% is replaced by the actual directory of the package
|
||||
storage_dir = %ROOT_DIR%/var/storage
|
||||
|
||||
; Allow network-wide connections for queries
|
||||
query_dsn[] = ipc:///tmp/storage_server_query.ipc
|
||||
query_dsn[] = tcp://0.0.0.0:5678
|
||||
|
||||
; Allow local connections for commands
|
||||
command_dsn[] = ipc:///tmp/storage_server_command.ipc
|
||||
command_dsn[] = tcp://127.0.0.1:5679
|
||||
|
||||
|
||||
[command]
|
||||
; Connect through IPC socket
|
||||
dsn = ipc:///tmp/storage_server_command.ipc
|
||||
|
||||
|
||||
[query]
|
||||
; Connect through TCP socket
|
||||
dsn = tcp://localhost:5678
|
15
query
15
query
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
array_shift($argv);
|
||||
if (count($argv) === 0) {
|
||||
print('Query needs at least one argument' . PHP_EOL);
|
||||
die(1);
|
||||
}
|
||||
|
||||
$context = new ZMQContext();
|
||||
$socket = new ZMQSocket($context, ZMQ::SOCKET_REQ);
|
||||
$socket->connect('ipc:///tmp/storage_server_query.ipc');
|
||||
$socket->sendmulti($argv);
|
||||
print(implode(PHP_EOL, $socket->recvMulti()));
|
||||
print(PHP_EOL);
|
10
server
10
server
@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/src/FileServer.php';
|
||||
|
||||
$dir = ($argv[1] ?? __DIR__ . '/var/documents');
|
||||
$commandEndpoints = ['ipc:///tmp/storage_server_command.ipc'];
|
||||
$queryEndpoints = ['ipc:///tmp/storage_server_query.ipc'];
|
||||
(new FileServer($dir, new ZMQContext(), $commandEndpoints, $queryEndpoints))->run();
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
|
||||
class FileServer
|
||||
{
|
||||
private ZMQSocket $commandSocket;
|
||||
@ -8,11 +7,11 @@ class FileServer
|
||||
private ZMQPoll $poll;
|
||||
private string $rootDirectory;
|
||||
|
||||
public function __construct(string $rootDirectory, ZMQContext $context, array $commandDsns, array $queryDsns)
|
||||
public function __construct(ZMQContext $context, string $rootDirectory, array $commandDSNs, array $queryDSNs)
|
||||
{
|
||||
$this->initializeCommandSocket($context, $commandDSNs);
|
||||
$this->initializeQuerySocket($context, $queryDSNs);
|
||||
$this->initializeRootDirectory($rootDirectory);
|
||||
$this->initializeCommandSocket($context, $commandDsns);
|
||||
$this->initializeQuerySocket($context, $queryDsns);
|
||||
$this->initializePoll();
|
||||
}
|
||||
|
||||
@ -22,28 +21,31 @@ class FileServer
|
||||
if (!is_dir($this->rootDirectory)) {
|
||||
mkdir($this->rootDirectory, 0777, true);
|
||||
}
|
||||
if (!is_dir($this->rootDirectory)) {
|
||||
throw new RuntimeException("Unable to create directory '{$this->rootDirectory}'");
|
||||
}
|
||||
}
|
||||
|
||||
private function initializeCommandSocket(ZMQContext $context, array $bindings): void
|
||||
private function initializeCommandSocket(ZMQContext $context, array $commandDSNs): void
|
||||
{
|
||||
if (count($bindings) === 0) {
|
||||
if (count($commandDSNs) === 0) {
|
||||
throw new InvalidArgumentException("At least one binding required");
|
||||
}
|
||||
$this->commandSocket = new ZMQSocket($context, ZMQ::SOCKET_PULL);
|
||||
$this->commandSocket->setSockOpt(ZMQ::SOCKOPT_HWM, 5);
|
||||
foreach ($bindings as $dsn) {
|
||||
foreach ($commandDSNs as $dsn) {
|
||||
$this->commandSocket->bind($dsn);
|
||||
}
|
||||
}
|
||||
|
||||
private function initializeQuerySocket(ZMQContext $context, array $bindings): void
|
||||
private function initializeQuerySocket(ZMQContext $context, array $queryDSNs): void
|
||||
{
|
||||
if (count($bindings) === 0) {
|
||||
if (count($queryDSNs) === 0) {
|
||||
throw new InvalidArgumentException("At least one binding required");
|
||||
}
|
||||
$this->querySocket = new ZMQSocket($context, ZMQ::SOCKET_REP);
|
||||
$this->querySocket->setSockOpt(ZMQ::SOCKOPT_HWM, 5);
|
||||
foreach ($bindings as $dsn) {
|
||||
foreach ($queryDSNs as $dsn) {
|
||||
$this->querySocket->bind($dsn);
|
||||
}
|
||||
}
|
||||
@ -75,7 +77,7 @@ class FileServer
|
||||
case 'LOAD':
|
||||
if (count($arguments) !== 2) {
|
||||
$this->querySocket->send(-1);
|
||||
print("Malformed LOAD query\n");
|
||||
$this->onNotEnoughArguments($query, 2, count($arguments));
|
||||
return;
|
||||
}
|
||||
$this->querySocket->send(@file_get_contents("{$this->rootDirectory}/{$arguments[0]}/{$arguments[1]}") ?: -1);
|
||||
@ -83,7 +85,7 @@ class FileServer
|
||||
case 'CONTAINS':
|
||||
if (count($arguments) !== 2) {
|
||||
$this->querySocket->send(-1);
|
||||
print("Malformed CONTAINS query\n");
|
||||
$this->onNotEnoughArguments($query, 2, count($arguments));
|
||||
return;
|
||||
}
|
||||
$this->querySocket->send(file_exists("{$this->rootDirectory}/{$arguments[0]}/{$arguments[1]}") ? 'Y' : 'N');
|
||||
@ -102,21 +104,22 @@ class FileServer
|
||||
switch ($command) {
|
||||
case 'SAVE':
|
||||
if (count($arguments) !== 3) {
|
||||
print("Malformed SAVE command\n");
|
||||
$this->onNotEnoughArguments($command, 3, count($arguments));
|
||||
return;
|
||||
}
|
||||
$this->saveFile($arguments[0], $arguments[1], $arguments[2]);
|
||||
break;
|
||||
case 'DELETE':
|
||||
if (count($arguments) !== 2) {
|
||||
print("Malformed DELETE command\n");
|
||||
$this->onNotEnoughArguments($command, 2, count($arguments));
|
||||
return;
|
||||
}
|
||||
$this->deleteFile($arguments[0], $arguments[1]);
|
||||
break;
|
||||
case 'DELETE_ALL':
|
||||
if (count($arguments) !== 1) {
|
||||
print("Malformed DELETE_ALL command\n");
|
||||
$this->onNotEnoughArguments($command, 1, count($arguments));
|
||||
return;
|
||||
}
|
||||
$this->deleteAll($arguments[0]);
|
||||
break;
|
||||
@ -126,10 +129,15 @@ class FileServer
|
||||
}
|
||||
}
|
||||
|
||||
private function onNotEnoughArguments(string $input, int $expected, int $actual): void
|
||||
{
|
||||
printf(date('[H:i:s]') . " Error: unexpected amount of arguments for input '%s' (%d/%d)\n", $input, $actual, $expected);
|
||||
}
|
||||
|
||||
private function onUnknownInput(string $input, array $arguments): void
|
||||
{
|
||||
$arguments = array_map(fn($v) => substr($v, 0, 12), $arguments);
|
||||
printf("Unknown input '%s' with args (%s)\n", $input, implode(', ', $arguments));
|
||||
printf(date('[H:i:s]') . " Error: unknown input '%s' with arguments [%s]\n", $input, implode(', ', $arguments));
|
||||
}
|
||||
|
||||
private function saveFile(string &$namespace, string &$name, string &$content): void
|
||||
|
Loading…
Reference in New Issue
Block a user