mirror of
https://github.com/kevachat/npsapp.git
synced 2025-01-14 09:07:59 +00:00
replace nps-php with async cboden/ratchet socket server
This commit is contained in:
parent
eed6fd1d9f
commit
0033b1f3a3
@ -9,6 +9,6 @@ To read messages, use KevaChat [webapp](https://github.com/kevachat/webapp), [ge
|
||||
## Components
|
||||
|
||||
* [kevachat/kevacoin-php](https://github.com/kevachat/kevacoin-php) - KevaCoin library for PHP 8
|
||||
* [yggverse/nps-php](https://github.com/YGGverse/nps-php) - PHP 8 / Composer Library for NPS Protocol
|
||||
* [gregwar/captcha](https://github.com/Gregwar/Captcha) - Captcha library to prevent spam abuses
|
||||
* [ixnode/php-cli-image](https://github.com/ixnode/php-cli-image) - Library converts captcha to ASCII format
|
||||
* [cboden/ratchet](https://github.com/ratchetphp/Ratchet) - Asynchronous Socket server
|
||||
* [gregwar/captcha](https://github.com/Gregwar/Captcha) - Captcha library to prevent spam abuse
|
||||
* [ixnode/php-cli-image](https://github.com/ixnode/php-cli-image) - Library converts captcha to ASCII/CLI format
|
@ -19,6 +19,6 @@
|
||||
"kevachat/kevacoin": "^1.10",
|
||||
"gregwar/captcha": "^1.2",
|
||||
"ixnode/php-cli-image": "^0.1.2",
|
||||
"yggverse/nps": "^1.3"
|
||||
"cboden/ratchet": "^0.4.4"
|
||||
}
|
||||
}
|
||||
|
@ -20,93 +20,101 @@
|
||||
"server":
|
||||
{
|
||||
"host":"127.0.0.1",
|
||||
"port":1915,
|
||||
"size":3072,
|
||||
"line":1024
|
||||
"port":1915
|
||||
},
|
||||
"session":
|
||||
"captcha":
|
||||
{
|
||||
"timeout":3600,
|
||||
"captcha":
|
||||
"length":3,
|
||||
"chars":"1234567890",
|
||||
"dimensions":
|
||||
{
|
||||
"length":3,
|
||||
"chars":"1234567890",
|
||||
"dimensions":
|
||||
{
|
||||
"width":100,
|
||||
"height":40
|
||||
},
|
||||
"background":
|
||||
{
|
||||
"r":0,
|
||||
"g":0,
|
||||
"b":0
|
||||
},
|
||||
"ascii":
|
||||
{
|
||||
"width": 50
|
||||
}
|
||||
"width":100,
|
||||
"height":40
|
||||
},
|
||||
"background":
|
||||
{
|
||||
"r":0,
|
||||
"g":0,
|
||||
"b":0
|
||||
},
|
||||
"ascii":
|
||||
{
|
||||
"width": 50
|
||||
}
|
||||
},
|
||||
"action":
|
||||
"event":
|
||||
{
|
||||
"start":
|
||||
"init":
|
||||
{
|
||||
"debug":
|
||||
{
|
||||
"enabled":true,
|
||||
"template":"[{time}] server started at {host}:{port} balance: {keva}"
|
||||
"template":"[{time}] [init] listen on {host}:{port} balance: {keva}"
|
||||
}
|
||||
},
|
||||
"welcome":
|
||||
"open":
|
||||
{
|
||||
"message":
|
||||
"response":
|
||||
[
|
||||
"\u001b[34m\u001b[1mWelcome to KevaChat!\u001b[0m",
|
||||
"\u001b[34mEnter captcha to confirm you are human:\u001b[0m"
|
||||
"\u001b[34mEnter captcha to confirm you are human\u001b[0m"
|
||||
],
|
||||
"debug":
|
||||
{
|
||||
"enabled":true,
|
||||
"template":"[{time}] [welcome] {host}:{port} captcha: {code}"
|
||||
"template":"[{time}] [open] {host}#{crid} captcha: {code}"
|
||||
}
|
||||
},
|
||||
"pending":
|
||||
"message":
|
||||
{
|
||||
"message":
|
||||
"response":
|
||||
{
|
||||
"success":
|
||||
[
|
||||
"\u001b[34mLooks good, now enter your message:\u001b[0m"
|
||||
],
|
||||
"failure":
|
||||
[
|
||||
"\u001b[31mSomething went wrong, try again later!\u001b[0m"
|
||||
]
|
||||
"captcha":
|
||||
{
|
||||
"success":
|
||||
[
|
||||
"\u001b[34mGood, now enter your message!\u001b[0m"
|
||||
],
|
||||
"failure":
|
||||
[
|
||||
"\u001b[31mIncorrect captcha code, try again later!\u001b[0m"
|
||||
]
|
||||
},
|
||||
"submit":
|
||||
{
|
||||
"success":
|
||||
[
|
||||
"\u001b[32mThanks, your message successfully sent!\u001b[0m"
|
||||
],
|
||||
"failure":
|
||||
{
|
||||
"internal":
|
||||
[
|
||||
"\u001b[31mSomething went wrong, please make your feedback!\u001b[0m"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"debug":
|
||||
{
|
||||
"enabled":true,
|
||||
"template":"[{time}] [pending] {host}:{port} captcha: {code} sent: {sent}"
|
||||
"template":"[{time}] [message] {host}#{crid} captcha: {code} size: {size} bytes \n\r{sent}."
|
||||
}
|
||||
},
|
||||
"handler":
|
||||
"close":
|
||||
{
|
||||
"message":
|
||||
{
|
||||
"success":
|
||||
[
|
||||
"\u001b[32mThanks, your message successfully sent!\u001b[0m"
|
||||
],
|
||||
"failure":
|
||||
[
|
||||
"\u001b[31mSomething went wrong, please make your feedback!\u001b[0m"
|
||||
]
|
||||
},
|
||||
"debug":
|
||||
{
|
||||
"enabled":true,
|
||||
"template":"[{time}] [handler] {host}:{port} captcha: {code} sent: {sent} length: {size} bytes {data}"
|
||||
"template":"[{time}] [close] {host}#{crid}"
|
||||
}
|
||||
},
|
||||
"error":
|
||||
{
|
||||
"debug":
|
||||
{
|
||||
"enabled":true,
|
||||
"template":"[{time}] [error] {host}#{crid} {info}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
262
src/Server/Ratchet.php
Normal file
262
src/Server/Ratchet.php
Normal file
@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace Kevachat\Npsapp\Server;
|
||||
|
||||
use \Ratchet\MessageComponentInterface;
|
||||
|
||||
class Ratchet implements MessageComponentInterface
|
||||
{
|
||||
private \Kevachat\Kevacoin\Client $_kevacoin;
|
||||
|
||||
private object $_config;
|
||||
|
||||
public function __construct(
|
||||
object $config
|
||||
) {
|
||||
// Init config
|
||||
$this->_config = $config;
|
||||
|
||||
// Init KevaCoin
|
||||
$this->_kevacoin = new \Kevachat\Kevacoin\Client(
|
||||
$this->_config->kevacoin->server->protocol,
|
||||
$this->_config->kevacoin->server->host,
|
||||
$this->_config->kevacoin->server->port,
|
||||
$this->_config->kevacoin->server->username,
|
||||
$this->_config->kevacoin->server->password
|
||||
);
|
||||
|
||||
// Validate funds
|
||||
if ((float) $this->_kevacoin->getBalance($this->_config->kevacoin->wallet->account) <= 0)
|
||||
{
|
||||
throw new \Exception(); // @TODO
|
||||
}
|
||||
|
||||
// Dump event on enabled
|
||||
if ($this->_config->nps->event->init->debug->enabled)
|
||||
{
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{port}',
|
||||
'{keva}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $this->_config->nps->server->host,
|
||||
(string) $this->_config->nps->server->port,
|
||||
(float) $this->_kevacoin->getBalance(
|
||||
$this->_config->kevacoin->wallet->account
|
||||
)
|
||||
],
|
||||
$this->_config->nps->event->init->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onOpen(
|
||||
\Ratchet\ConnectionInterface $connection
|
||||
) {
|
||||
// Init config namespace
|
||||
$config = $this->_config->nps;
|
||||
|
||||
// Build captcha
|
||||
$captcha = new \Gregwar\Captcha\CaptchaBuilder(
|
||||
null,
|
||||
new \Gregwar\Captcha\PhraseBuilder(
|
||||
$config->captcha->length,
|
||||
$config->captcha->chars
|
||||
)
|
||||
);
|
||||
|
||||
$captcha->setBackgroundColor(
|
||||
$config->captcha->background->r,
|
||||
$config->captcha->background->g,
|
||||
$config->captcha->background->b
|
||||
);
|
||||
|
||||
$captcha->build(
|
||||
$config->captcha->dimensions->width,
|
||||
$config->captcha->dimensions->height
|
||||
);
|
||||
|
||||
// Convert captcha image to ASCII response
|
||||
$image = new \Ixnode\PhpCliImage\CliImage(
|
||||
$captcha->get(),
|
||||
$config->captcha->ascii->width
|
||||
);
|
||||
|
||||
// Send response
|
||||
$connection->send(
|
||||
sprintf(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$config->event->open->response
|
||||
) . PHP_EOL . $image->getAsciiString() . PHP_EOL
|
||||
)
|
||||
);
|
||||
|
||||
// Keep captcha phrase in connection
|
||||
$connection->captcha = $captcha->getPhrase();
|
||||
|
||||
// Init connection confirmed
|
||||
$connection->confirmed = false;
|
||||
|
||||
// Debug open event on enabled
|
||||
if ($config->event->open->debug->enabled)
|
||||
{
|
||||
// Print debug from template
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{crid}',
|
||||
'{code}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $connection->remoteAddress,
|
||||
(string) $connection->resourceId,
|
||||
(string) $connection->captcha
|
||||
],
|
||||
$config->event->open->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onMessage(
|
||||
\Ratchet\ConnectionInterface $connection,
|
||||
$request
|
||||
) {
|
||||
// Init config namespace
|
||||
$config = $this->_config->nps->event->message;
|
||||
|
||||
// Captcha request first for unconfirmed connections
|
||||
if (!$connection->confirmed)
|
||||
{
|
||||
// Request match captcha
|
||||
if ($request == $connection->captcha)
|
||||
{
|
||||
$connection->confirmed = true;
|
||||
|
||||
$connection->send(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$config->response->captcha->success
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
// Captcha request invalid
|
||||
else
|
||||
{
|
||||
$connection->confirmed = false;
|
||||
|
||||
$connection->send(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$config->response->captcha->failure
|
||||
) . PHP_EOL
|
||||
);
|
||||
|
||||
// Drop connection or do something else..
|
||||
$connection->close();
|
||||
}
|
||||
}
|
||||
|
||||
// @TODO compose request to KevaCoin, return transaction ID
|
||||
else
|
||||
{
|
||||
// Save massage to kevacoin
|
||||
/*
|
||||
$connection->send(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$config->response->captcha->failure
|
||||
) . PHP_EOL
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
// Debug message event on enabled
|
||||
if ($config->debug->enabled)
|
||||
{
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{crid}',
|
||||
'{code}',
|
||||
'{sent}',
|
||||
'{size}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $connection->remoteAddress,
|
||||
(string) $connection->resourceId,
|
||||
(string) $connection->captcha,
|
||||
(string) str_replace('%', '%%', $request),
|
||||
(string) mb_strlen($request)
|
||||
],
|
||||
$config->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onClose(
|
||||
\Ratchet\ConnectionInterface $connection
|
||||
) {
|
||||
if ($this->_config->nps->event->close->debug->enabled)
|
||||
{
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{crid}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $connection->remoteAddress,
|
||||
(string) $connection->resourceId
|
||||
],
|
||||
$this->_config->nps->event->close->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function onError(
|
||||
\Ratchet\ConnectionInterface $connection,
|
||||
\Exception $exception
|
||||
) {
|
||||
if ($this->_config->nps->event->close->debug->enabled)
|
||||
{
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{crid}',
|
||||
'{info}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $connection->remoteAddress,
|
||||
(string) $connection->resourceId,
|
||||
(string) str_replace('%', '%%', $exception->getMessage())
|
||||
],
|
||||
$this->_config->nps->event->error->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
$connection->close();
|
||||
}
|
||||
}
|
30
src/app.php
Normal file
30
src/app.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
// Load dependencies
|
||||
require_once __DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..'.
|
||||
DIRECTORY_SEPARATOR . 'vendor' .
|
||||
DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
|
||||
// Init config
|
||||
$config = json_decode(
|
||||
file_get_contents(
|
||||
__DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..'.
|
||||
DIRECTORY_SEPARATOR . 'config'.
|
||||
DIRECTORY_SEPARATOR . (
|
||||
isset($argv[1]) ? $argv[1] : 'example.json'
|
||||
)
|
||||
)
|
||||
); if (!$config) throw new \Exception();
|
||||
|
||||
// Start server
|
||||
$server = \Ratchet\Server\IoServer::factory(
|
||||
new \Kevachat\Npsapp\Server\Ratchet(
|
||||
$config
|
||||
),
|
||||
$config->nps->server->port,
|
||||
$config->nps->server->host
|
||||
);
|
||||
|
||||
$server->run();
|
310
src/server.php
310
src/server.php
@ -1,310 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Load dependencies
|
||||
require_once __DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..'.
|
||||
DIRECTORY_SEPARATOR . 'vendor' .
|
||||
DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
|
||||
// Init config
|
||||
$config = json_decode(
|
||||
file_get_contents(
|
||||
__DIR__ .
|
||||
DIRECTORY_SEPARATOR . '..'.
|
||||
DIRECTORY_SEPARATOR . 'config'.
|
||||
DIRECTORY_SEPARATOR . (
|
||||
isset($argv[1]) ? $argv[1] : 'example.json'
|
||||
)
|
||||
)
|
||||
); if (!$config) exit;
|
||||
|
||||
// Init KevaCoin
|
||||
$kevacoin = new \Kevachat\Kevacoin\Client(
|
||||
$config->kevacoin->server->protocol,
|
||||
$config->kevacoin->server->host,
|
||||
$config->kevacoin->server->port,
|
||||
$config->kevacoin->server->username,
|
||||
$config->kevacoin->server->password
|
||||
);
|
||||
|
||||
if ((float) $kevacoin->getBalance($config->kevacoin->wallet->account) <= 0) exit;
|
||||
|
||||
// Init session
|
||||
$session = [];
|
||||
|
||||
// Init server
|
||||
$server = new \Yggverse\Nps\Server(
|
||||
$config->nps->server->host,
|
||||
$config->nps->server->port,
|
||||
$config->nps->server->size,
|
||||
$config->nps->server->line
|
||||
);
|
||||
|
||||
// Init welcome function
|
||||
$server->setWelcome(
|
||||
function (
|
||||
string $connect
|
||||
): ?string
|
||||
{
|
||||
global $config,
|
||||
$session;
|
||||
|
||||
// Cleanup expired sessions
|
||||
foreach ($session as $key => $value)
|
||||
{
|
||||
if ($value['time'] + $config->nps->session->timeout < time())
|
||||
{
|
||||
unset(
|
||||
$session[$key]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Build connection URL #72811
|
||||
$url = sprintf(
|
||||
'nex://%s',
|
||||
$connect
|
||||
);
|
||||
|
||||
// Init new session
|
||||
$session[$connect] =
|
||||
[
|
||||
'time' => time(),
|
||||
'host' => parse_url(
|
||||
$url,
|
||||
PHP_URL_HOST
|
||||
),
|
||||
'port' => parse_url(
|
||||
$url,
|
||||
PHP_URL_PORT
|
||||
),
|
||||
'code' => null
|
||||
];
|
||||
|
||||
// Build captcha
|
||||
$captcha = new \Gregwar\Captcha\CaptchaBuilder(
|
||||
null,
|
||||
new \Gregwar\Captcha\PhraseBuilder(
|
||||
$config->nps->session->captcha->length,
|
||||
$config->nps->session->captcha->chars
|
||||
)
|
||||
);
|
||||
|
||||
$captcha->setBackgroundColor(
|
||||
$config->nps->session->captcha->background->r,
|
||||
$config->nps->session->captcha->background->g,
|
||||
$config->nps->session->captcha->background->b
|
||||
);
|
||||
|
||||
$captcha->build(
|
||||
$config->nps->session->captcha->dimensions->width,
|
||||
$config->nps->session->captcha->dimensions->height
|
||||
);
|
||||
|
||||
// Set captcha value to the session code
|
||||
$session[$connect]['code'] = $captcha->getPhrase();
|
||||
|
||||
// Create ASCII confirmation code
|
||||
$image = new \Ixnode\PhpCliImage\CliImage(
|
||||
$captcha->get(),
|
||||
$config->nps->session->captcha->ascii->width
|
||||
);
|
||||
|
||||
// Debug request on enabled
|
||||
if ($config->nps->action->welcome->debug->enabled)
|
||||
{
|
||||
// Print debug from template
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{port}',
|
||||
'{code}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $session[$connect]['host'],
|
||||
(string) $session[$connect]['port'],
|
||||
(string) $session[$connect]['code']
|
||||
],
|
||||
$config->nps->action->welcome->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
implode(
|
||||
PHP_EOL,
|
||||
$config->nps->action->welcome->message
|
||||
) . PHP_EOL . $image->getAsciiString() . PHP_EOL
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Init pending function
|
||||
$server->setPending(
|
||||
function (
|
||||
string $request,
|
||||
string $connect
|
||||
): ?string
|
||||
{
|
||||
global $config,
|
||||
$session;
|
||||
|
||||
// Filter request
|
||||
$request = trim(
|
||||
$request
|
||||
);
|
||||
|
||||
// Debug request on enabled
|
||||
if ($config->nps->action->pending->debug->enabled)
|
||||
{
|
||||
// Print debug from template
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{port}',
|
||||
'{sent}',
|
||||
'{code}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $session[$connect]['host'],
|
||||
(string) $session[$connect]['port'],
|
||||
(string) $request,
|
||||
(string) $session[$connect]['code']
|
||||
],
|
||||
$config->nps->action->pending->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
// Session valid
|
||||
if ($session[$connect]['code'] == $request)
|
||||
{
|
||||
// Return success message
|
||||
return implode(
|
||||
PHP_EOL,
|
||||
$config->nps->action->pending->message->success
|
||||
) . PHP_EOL;
|
||||
}
|
||||
|
||||
// @TODO disconnect, stop handler
|
||||
|
||||
// Cleanup session
|
||||
unset($session[$connect]);
|
||||
|
||||
// Return failure message
|
||||
return implode(
|
||||
PHP_EOL,
|
||||
$config->nps->action->pending->message->failure
|
||||
) . PHP_EOL;
|
||||
}
|
||||
);
|
||||
|
||||
// Init handler function
|
||||
$server->setHandler(
|
||||
function (
|
||||
bool $success,
|
||||
string $content,
|
||||
string $request,
|
||||
string $connect
|
||||
): ?string
|
||||
{
|
||||
global $config,
|
||||
$session;
|
||||
|
||||
// Filter request
|
||||
$request = trim(
|
||||
$request
|
||||
);
|
||||
|
||||
// Filter content
|
||||
$content = trim(
|
||||
$content
|
||||
);
|
||||
|
||||
// Build response
|
||||
if ($session[$connect]['code'] == $request)
|
||||
{
|
||||
// @TODO save content in blockchain with kevacoin-php
|
||||
|
||||
$response = implode(
|
||||
PHP_EOL,
|
||||
$config->nps->action->handler->message->success
|
||||
) . PHP_EOL;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$response = implode(
|
||||
PHP_EOL,
|
||||
$config->nps->action->handler->message->failure
|
||||
) . PHP_EOL;
|
||||
}
|
||||
|
||||
// Debug request on enabled
|
||||
if ($config->nps->action->handler->debug->enabled)
|
||||
{
|
||||
// Print debug from template
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{port}',
|
||||
'{code}',
|
||||
'{sent}',
|
||||
'{size}',
|
||||
'{data}'
|
||||
],
|
||||
[
|
||||
(string) date('c'),
|
||||
(string) $session[$connect]['host'],
|
||||
(string) $session[$connect]['port'],
|
||||
(string) $session[$connect]['code'],
|
||||
(string) str_replace('%', '%%', $request),
|
||||
(string) mb_strlen($content),
|
||||
(string) PHP_EOL . $content,
|
||||
],
|
||||
$config->nps->action->handler->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
// Cleanup session
|
||||
unset($session[$connect]);
|
||||
|
||||
// Result
|
||||
return $response;
|
||||
}
|
||||
);
|
||||
|
||||
// Start server
|
||||
if ($config->nps->action->start->debug->enabled)
|
||||
{
|
||||
print(
|
||||
str_ireplace(
|
||||
[
|
||||
'{time}',
|
||||
'{host}',
|
||||
'{port}',
|
||||
'{keva}'
|
||||
],
|
||||
[
|
||||
date('c'),
|
||||
$config->nps->server->host,
|
||||
$config->nps->server->port,
|
||||
$kevacoin->getBalance(
|
||||
$config->kevacoin->wallet->account
|
||||
)
|
||||
],
|
||||
$config->nps->action->start->debug->template
|
||||
) . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
$server->start();
|
Loading…
Reference in New Issue
Block a user