diff --git a/README.md b/README.md index d2e19d0..4947432 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ KevaChat is distributed chat platform for open, uncensored and privacy respectab * [x] Multiple host support * [x] Room list * [x] Room threads -* [ ] Post publication -* [ ] Post replies +* [x] Post publication +* [x] Post replies * [ ] Rooms publication * [x] Media viewer * [ ] Users auth diff --git a/composer.json b/composer.json index 23d6047..03fada1 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "require": { "yggverse/titan-ii": "^1.0", "kevachat/kevacoin": "^1.6", - "clitor-is-protocol/kevacoin": "^1.0" + "clitor-is-protocol/kevacoin": "^1.0", + "yggverse/cache": "^0.3.1" } } diff --git a/example/config.json b/example/config.json index 7471854..bb300fe 100644 --- a/example/config.json +++ b/example/config.json @@ -24,7 +24,8 @@ { "host":"127.0.0.1", "port":11211, - "timeout":3600 + "timeout":3600, + "namespace":"geminiapp" } }, "kevachat": diff --git a/src/controller/room.php b/src/controller/room.php index e8f2155..e10bb8c 100644 --- a/src/controller/room.php +++ b/src/controller/room.php @@ -5,11 +5,25 @@ namespace Kevachat\Geminiapp\Controller; class Room { private $_config; + private $_memory; + + private $_session; private \Kevachat\Kevacoin\Client $_kevacoin; - public function __construct($config) + public function __construct(\Yggverse\Cache\Memory $memory, $config) { + // Init memory + $this->_memory = $memory; + + // Init session + $this->_session = rand(); + + $this->_memory->set( + $this->_session, + time() + ); + // Init config $this->_config = $config; @@ -170,8 +184,9 @@ class Room // post $this->_link( // @TODO sprintf( - '/room/%s/post', - $namespace + '/room/%s/%d/post', + $namespace, + $this->_session ) ), @@ -192,6 +207,69 @@ class Room ); } + public function post(string $namespace, ?string $txid, int $session, string $message): bool + { + // Validate funds available yet + if (1 > $this->_kevacoin->getBalance()) + { + return false; + } + + // Validate session exists + if (!$this->_memory->get($session)) + { + return false; + } + + // Validate value format allowed in settings + if (!preg_match((string) $this->_config->kevachat->post->value->regex, $message)) + { + return false; + } + + // Prepare message + $message = trim( + strip_tags( + urldecode( + $message + ) + ) + ); + + // Append mention if provided + if ($txid) + { + $message = $txid . PHP_EOL . $message; + } + + // Validate final message length + if (mb_strlen($message) < 1 || mb_strlen($message) > 3072) + { + return false; + } + + // Send message + if (!$this->_kevacoin->kevaPut( + $namespace, + sprintf( + '%s@anon', + time() + ), + $message + )) + { + return false; + } + + // Cleanup memory + $this->_memory->delete( + $session + ); + + // Success + return true; + } + private function _post(string $namespace, string $key, array $posts = [], ?string $field = null, ?int &$time = 0): ?string { // Check record exists @@ -316,9 +394,10 @@ class Room // Reply link $links[] = $this->_link( sprintf( - '/room/%s/%s/reply', + '/room/%s/%s/%d/reply', $namespace, $record['txid'], + $this->_session ), _('Reply'), true diff --git a/src/server.php b/src/server.php index 299d901..03442b9 100644 --- a/src/server.php +++ b/src/server.php @@ -52,6 +52,14 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) ) ); + // Init memory + $memory = new \Yggverse\Cache\Memory( + $config->memcached->server->host, + $config->memcached->server->port, + $config->memcached->server->namespace, + $config->memcached->server->timeout + ); + // Init server $server = new \Yggverse\TitanII\Server(); @@ -66,6 +74,7 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) $server->setHandler( function (\Yggverse\TitanII\Request $request): \Yggverse\TitanII\Response { + global $memory; global $config; $response = new \Yggverse\TitanII\Response(); @@ -89,6 +98,7 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) include_once __DIR__ . '/controller/room.php'; $room = new \Kevachat\Geminiapp\Controller\Room( + $memory, $config ); @@ -104,6 +114,7 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) // Dynamical requests default: + // room|raw request if (preg_match('/^\/([A-z]+)\/(N[A-z0-9]{33})$/', $request->getPath(), $matches)) { if (!empty($matches[1]) && !empty($matches[2])) @@ -115,6 +126,7 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) include_once __DIR__ . '/controller/room.php'; $room = new \Kevachat\Geminiapp\Controller\Room( + $memory, $config ); @@ -154,6 +166,104 @@ foreach ((array) scandir(__DIR__ . '/../host') as $host) } } } + + // New publication request + else if (preg_match('/^\/room\/(N[A-z0-9]{33})\/([\d]+)\/post$/', $request->getPath(), $matches)) + { + if (!empty($matches[1])) + { + // Request post message + if (empty($request->getQuery())) + { + $response->setMeta( + 'text/plain' + ); + + $response->setCode( + 10 + ); + + return $response; + } + + // Message sent, save to blockchain + else + { + include_once __DIR__ . '/controller/room.php'; + + $room = new \Kevachat\Geminiapp\Controller\Room( + $memory, + $config + ); + + // Success, redirect to this room page + if ($room->post($matches[1], null, $matches[2], $request->getQuery())) + { + $response->setCode( + 30 + ); + + $response->setMeta( + sprintf( + '/room/%s', + $matches[1] + ) + ); + + return $response; + } + } + } + } + + // New post reply request + else if (preg_match('/^\/room\/(N[A-z0-9]{33})\/([A-z0-9]{64})\/([\d]+)\/reply$/', $request->getPath(), $matches)) + { + if (!empty($matches[1]) && !empty($matches[2]) && !empty($matches[3])) + { + // Request post message + if (empty($request->getQuery())) + { + $response->setMeta( + 'text/plain' + ); + + $response->setCode( + 10 + ); + + return $response; + } + + // Message sent, save to blockchain + else + { + include_once __DIR__ . '/controller/room.php'; + + $room = new \Kevachat\Geminiapp\Controller\Room( + $memory, + $config + ); + + // Success, redirect to this room page + if ($room->post($matches[1], $matches[2], $matches[3], $request->getQuery())) + { + $response->setCode( + 30 + ); + + $response->setMeta( + sprintf( + '/room/%s', + $matches[1] + ) + ); + + return $response; + } + } + } + } } // Set default response