Nejde mi poslat zprávu do WebSocket topicu přes ZeroMQ (ipublikuj/websockets-zmq)
- crassus
- Backer | 78
Ahoj,
implementoval jsem si do projektu knihovnu ipublikuj/websockets-wamp a ipublikuj/websockets-zmq. JS klienti mi fungují, ale nedokážu vložit do topicu zprávu ze serveru pomocí té ZeroMQ fronty.
Žádnou chybu to nepíše.
Po zavolání: php web/index.php ipub:websockets:start
naběhne WebSocket server i ZMQ. Poté pošlu request presenteru, tam se
ještě zavolá
$this->pusher->push($data, 'RaspberryPi:', ['id' => '1']);
,
ale poté už se nespustí actionPush() uvnitř RaspberryPiController.php.
Nevíte prosím někdo čím by to mohlo být?
ApiPresenter.php
public function actionAdvert()
{
$data = [
'type' => 'system',
'content' => 'This is example advertising.',
];
$this->pusher->push($data, 'RaspberryPi:', ['id' => '1']);
$this->terminate();
}
RaspberryPiController.php
public function actionPush(array $data, ITopic $topic)
{
\Tracy\Debugger::log("nezavola se");
$now = new \DateTime();
$message = new \stdClass();
$message->type = $data['type'];
$message->time = $now->format(DATE_ISO8601);
$message->content = $data['content'];
$topic->broadcast(Json::encode($message));
}
Případně jak mám správně nastavit SSL certifikát v configu, abych mohl použit WSS protokol?
webSockets:
server:
httpHost: localhost
port: 8080
address: 0.0.0.0
secured:
enable: true
sslSettings:
local_cert : 'C:\Apache24\conf\server.crt'
local_pk : 'C:\Apache24\conf\server.key'
allow_self_signed : true
verify_peer : false
routes:
'/raspberrypi/<id>' : 'RaspberryPi:'
mapping:
*: App\Controllers\*Controller
Když se zkouším připojit s klientem na WSS protokol, píše to:
Could not establish connection: Connection from tcp://127.0.0.1:61992 failed during TLS handshake:
Unable to complete TLS handshake: SSL operation failed with code 1.
OpenSSL Error messages: error:14094416:SSL
routines:ssl3_read_bytes:sslv3 alert certificate unknown
Editoval crassus (27. 5. 2019 11:52)
- crassus
- Backer | 78
Rozjel jsem si na lokálu demo: https://github.com/ipublikuj/demo, ve kterém mi také funguje vše kromě té fronty ZeroMQ a WSS protokolu.
Editoval crassus (27. 5. 2019 11:56)
- akadlec
- Člen | 1326
WSS není tak super easy rozchodit, resp. když jsem to zkoušel během vývoje tak byl problém se SSL handshake na straně reactu :/ řeší se to pomocí proxy (popisoval sem v mailul, nevím zda dorazil)
V apache např takto:
ProxyPass „/sockets/“ „ws://yourdomain.com:9787“
Tedy volá se spojení z klienta na wss://yourdomain.com/sockets a apache to přeroutuje na ws://yourdomain.com:9787
Ad zmq pokud to nic neconsumuje tak možná že nesedly porty :/ každopádně na consumerovi jsou eventy https://github.com/…/en/index.md#… tak je zkus logovat jestli tam něco přijde
zmq je supereasy fronta. Jedině co ještě může dělat problém je obsazenost portu. Ve zkratce to jede tak že se otevře TCP kanál na vybraný port kde poslouchá consumer a pusher/producer se připojí jen pro komunikaci, pošle data a pak se odpojí.
- akadlec
- Člen | 1326
a malé OT, vidím tam DATE_ISO8601
což je imo špatně: https://www.php.net/…nterface.php#…
- crassus
- Backer | 78
akadlec napsal(a):
a malé OT, vidím tam
DATE_ISO8601
což je imo špatně: https://www.php.net/…nterface.php#…
Ta actionPush() uvnitr kontroleru se vubec nezavola. Eventy to nevyhazuje. Zkusil jsem i jine porty a taky bohuzel nic :(
- crassus
- Backer | 78
akadlec napsal(a):
WSS není tak super easy rozchodit, resp. když jsem to zkoušel během vývoje tak byl problém se SSL handshake na straně reactu :/ řeší se to pomocí proxy (popisoval sem v mailul, nevím zda dorazil)
V apache např takto:
ProxyPass „/sockets/“ „ws://yourdomain.com:9787“
Tedy volá se spojení z klienta na wss://yourdomain.com/sockets a apache to přeroutuje na ws://yourdomain.com:9787
Ad zmq pokud to nic neconsumuje tak možná že nesedly porty :/ každopádně na consumerovi jsou eventy https://github.com/…/en/index.md#… tak je zkus logovat jestli tam něco přijde
zmq je supereasy fronta. Jedině co ještě může dělat problém je obsazenost portu. Ve zkratce to jede tak že se otevře TCP kanál na vybraný port kde poslouchá consumer a pusher/producer se připojí jen pro komunikaci, pošle data a pak se odpojí.
Povolil jsem v Apache moduly:
mod_proxy.so
mod_proxy_wstunnel.so
A do httpd-vhosts.conf jsem pridal:
ProxyPass /sockets/ ws://127.0.0.1:8080
Na klientovi pak volam:
IPub.WebSockets.WAMP.initialize('wss://127.0.0.1:8080/sockets/');
A bohuzel handshake nekonci 101, ale request je porad pending a pak vytimeoutuje :(
Editoval crassus (31. 5. 2019 21:27)
- crassus
- Backer | 78
akadlec napsal(a):
Jinak pokud nejede demo, tak mě ještě napadá že mohli něco změnit v nějakém reactphp balíku :/
Demo po pullnutí jen tak nefungovalo, tak jsem poopravoval chyby: http://leteckaposta.cz/127858839
Staci zavolat composer install a nabehne to, ale bohuzel ani v tom demu se nespousti actionPush().
- crassus
- Backer | 78
akadlec napsal(a):
Ad zmq, pokud to neodpaluje eventy tak ten consumer vubec nic nedostane. Buď poslouchá na jiném portu než posílá consumer a nebo je ten port obsazeny. Jaký port si tam nakonfil?
webSocketsZMQ: host: '127.0.0.1' port: 5555 persistent: true protocol: 'tcp'
Zkousel jsem 5555, 5554 i treba 9787 a porad nic. Vam ta ZeroMQ fronta funguje? Vsiml jsem si totiz ze ta abstraktni metoda doPush() uvnitr IPub\WebSocketsWAMP\PushMessages\Pusher nikde neni implementovana.
- crassus
- Backer | 78
akadlec napsal(a):
nemůžeš volat stejný port
IPub.WebSockets.WAMP.initialize('wss://127.0.0.1:8080/sockets/');
Pokud děláš proxy tak voláš jiný port a proxypass ti to přeroutuje takžeIPub.WebSockets.WAMP.initialize('wss://127.0.0.1/sockets/');
Díky :)
teď už to vypisuje:
autobahn.js:1293 WebSocket connection to ‚wss://127.0.0.1/sockets/‘ failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
Používám certifikát Internet Widgits Pty Ltd. Na localhostu díky tomu můžu fungovat s https.
Ale kvůli těm WebSocketům budu muset použít jiný certifikát?
- crassus
- Backer | 78
akadlec napsal(a):
nemůžeš volat stejný port
IPub.WebSockets.WAMP.initialize('wss://127.0.0.1:8080/sockets/');
Pokud děláš proxy tak voláš jiný port a proxypass ti to přeroutuje takžeIPub.WebSockets.WAMP.initialize('wss://127.0.0.1/sockets/');
Ted jsem jeste zkusil navstivit https://127.0.0.1/sockets/, potvrdil jsem ze chci prejit na stranku, a pak jsem znovu spustil klienta, ktery mi ted pise:
autobahn.js:1293: WebSocket connection to ‚wss://127.0.0.1/sockets/‘ failed: Error during WebSocket handshake: Unexpected response code: 500
- akadlec
- Člen | 1326
ZMQ jako takovou jsem momentálně implementoval mezi serverem a klientem.
Extension pro WAMP momentálně na jednom projektu přidávám.
Pusher
extenduje pusher z WAMP rozšíření a metoda
doPush
se volá pomocí public push
jako tomu je
tady: https://github.com/…resenter.php#…
- akadlec
- Člen | 1326
@crassus v configu WS serveru vůbec nenastavuj SSL tohle:
secured:
enable: true
sslSettings:
local_cert : 'C:\Apache24\conf\server.crt'
local_pk : 'C:\Apache24\conf\server.key'
allow_self_signed : true
verify_peer : false
dej pryč. WS server ti poběží bez SSL, o SSL se ti postará právě ta proxy a certifikáty to bude mít takové co máš pro ten vhost
- akadlec
- Člen | 1326
@crassus hele tak jsem tu zmq zkusil a normálně mě to běhá. V „presenteru“ mám:
$this->socketsPusher->push($this->getClientsMessage($thing, $channel), 'IOServerExchange:Thing:', [
'thing' => $thing->getPlainId(),
]);
a controleru pr WS pak
public function actionPush(
array $data,
IOServerModuleEntities\Things\IThing $thing,
WebSocketsWAMP\Entities\Topics\ITopic $topic
) : void {
if (!$this->entityManagerHelpers->checkEntityManager()) {
throw new WebSockets\Exceptions\TerminateException('EntityManager is closed.');
}
try {
$topic->broadcast(Utils\Json::encode($data));
} catch (Utils\JsonException $ex) {
$this->logger->logException($ex, [
'type' => 'controller',
'controller' => 'thing',
'action' => 'encode_payload',
'thing' => [
'id' => $thing->getPlainId(),
],
]);
}
}
- crassus
- Backer | 78
akadlec napsal(a):
@crassus v configu WS serveru vůbec nenastavuj SSL tohle:
secured: enable: true sslSettings: local_cert : 'C:\Apache24\conf\server.crt' local_pk : 'C:\Apache24\conf\server.key' allow_self_signed : true verify_peer : false
dej pryč. WS server ti poběží bez SSL, o SSL se ti postará právě ta proxy a certifikáty to bude mít takové co máš pro ten vhost
Dal jsem celou konfiguraci pryc, ale pise to porad: WebSocket connection to ‚wss://127.0.0.1/sockets/‘ failed: Error during WebSocket handshake: Unexpected response code: 500
Asi budu mit tim padem spatne napsany ten ProxyPass.
- crassus
- Backer | 78
akadlec napsal(a):
Ještě mě napadá že to může dělat ta SSL konfigurace. Protože tu zmq extension není nutné vůbec konfigurovat. A druhý tip co by to mohlo dělat ze zakázaní portu na kterém se to snaží naslouchat.
Port blokovany neni: https://jpeg.cz/…/screen2.jpg
Az potud se mi kod jeste provede: https://jpeg.cz/…7/screen.jpg
Jako instanci toho pushera pouzivate IPub\WebSocketsZMQ\Pusher\Pusher nebo IPub\WebSocketsWAMP\PushMessages\IPusher?
Pak jsem si vsiml ze nazev topicu uvadite jako: ‚IOServerExchange:Thing:‘ , co to znamena ze za nazev kontroleru uvedu jeste :Thing ?
- crassus
- Backer | 78
Tady jeste posilam cely ten kontroler:
<?php
namespace App\Controllers;
use IPub\WebSockets\Application\Controller\Controller;
use IPub\WebSockets\Entities\Clients\IClient;
use IPub\WebSocketsWAMP\Entities\Topics\ITopic;
use Nette\Utils\Json;
class RaspberryPiController extends Controller
{
public function actionSubscribe(IClient $client, ITopic $topic, int $id)
{
$topic->broadcast($client->getId() .' joined: ' . ' id: ' . $id);
}
public function actionUnsubscribe(IClient $client, ITopic $topic, int $id)
{
$topic->broadcast($client->getId() .' left: ' . ' id:' . $id);
}
public function actionPublish($event, IClient $client, ITopic $topic, int $id)
{
$topic->broadcast($client->getId() .' is saying: '. $event . ' , topic: ' . $topic->getId() . ' id: ' . $id);
}
public function actionPush(array $data, ITopic $topic)
{
\Tracy\Debugger::log("nezavola se");
//$now = new \DateTime();
$message = new \stdClass();
$message->type = $data['type'];
//$message->time = $now->format(DATE_ISO8601);
$message->content = $data['content'];
$topic->broadcast(Json::encode($message));
}
}
Vsechny actions krome actionPush funguji.
- akadlec
- Člen | 1326
Pokud se to nespojí a háže to ssl chyby, tak asi bude špatně nakonfený proxy pass. Chce to mít i instalované apache pluginy
Jako pusher je instance ze zmq:
IPub\WebSocketsZMQ\Pusher\Pusher
. V pusheru
IOServerExchange:Thing:
je nepodstatné, já takto mám jen
udělaný router. Nicméně i pokud by byla routa špatně a server nedokázal
routu najít, tak i tak musí být odpáleny ty události viz výše.
- crassus
- Backer | 78
akadlec napsal(a):
Zkus update knihoven, vydal jsem nové verze a aktuálně mě fungujou. Ale zaměřil bych se primárně na to odstranění SSL, a promazání cache.
Tak ProxyPass jsem nakonec rozjel, stačilo vložit do httpd.conf toto:
ProxyPassReverse /myws ws://127.0.0.1:8080
V javascriptu pak mám:
IPub.WebSockets.WAMP.initialize('wss://127.0.0.1/myws');
Jedná se o zabezpečený protokol, když takhle použiji ten ProxyPass? Není to pak už jedno zda použiji ws nebo wss s ProxyPass?
Každopádně ZeroMQ jsem stále nevyřešil.
Editoval crassus (29. 5. 2019 15:38)
- crassus
- Backer | 78
Když spustím tento script z příkazové řádky:
$context = new ZMQContext();
$socket = new ZMQSocket($context, ZMQ::SOCKET_PUSH);
$socket->connect("tcp://127.0.0.1:5555");
$socket->send("ahoj tady pusher");
tak consumer zprávu příjme. Když úplně ten stejný kód vložím do action v presenteru a spustím action, tak se zpráva neodešle a aktuálně připojené klienty to odpojí.
Kdybyste kdokoliv věděl co s tím, budu rád když mi poradíte. Proč to z příkazové řádky jede a z requestů přes jdoucích přes Apache nikoliv?
Editoval crassus (29. 5. 2019 15:39)
- pista5
- Člen | 72
Ahoj, též se mi nedaří odeslat zprávu.
Po odeslani se mi vypise chyba: ZMQ socket failed to ack message
Neporadil by mi prosim nekdo, kde hledat problem?
INFO: ZMQ transport listening on 127.0.0.1:5555
DEBUG: Starting IPub\WebSockets
DEBUG: Launching WebSockets WS Server on: 0.0.0.0:8080
DEBUG: INSERT CLIENT 182
DEBUG: GET CLIENT 182
INFO: New connection! (182)
DEBUG: GET CLIENT 182
DEBUG: INSERT TOPIC reminder/1
DEBUG: GET TOPIC reminder/1
DEBUG: GET TOPIC reminder/1
DEBUG: INSERT TOPIC reminder/1
INFO: Connection 182 has subscribed to reminder/1
ERROR! ZMQ socket failed to ack message
- pista5
- Člen | 72
akadlec napsal(a):
tak můžeš kouknout do kódu, hodit si tam dumpy/logy a uvidíš co je špatně
Jasne, na chybu jsem jiz prisel, posunul se dal, ale zde si nevim rady… v logu vypada vse OK, ale v prohlizeci se nic nestane
INFO: ZMQ transport listening on 127.0.0.1:5555
DEBUG: Starting IPub\WebSockets
DEBUG: Launching WebSockets WS Server on: 0.0.0.0:8080
DEBUG: INSERT CLIENT 188
DEBUG: GET CLIENT 188
INFO: New connection! (188)
DEBUG: GET CLIENT 188
DEBUG: INSERT TOPIC phone/1
DEBUG: GET TOPIC phone/1
DEBUG: GET TOPIC phone/1
DEBUG: INSERT TOPIC phone/1
INFO: Connection 188 has subscribed to phone/1
DEBUG: INSERT TOPIC /phone/1
DEBUG: GET TOPIC /phone/1
INFO: Message was pushed to /phone/1 topic
Udelal jsem si dump zde
public function actionPush(array $data, IPub\WebSocketsWAMP\Entities\Topics\ITopic $topic)
{
Debugger::log($topic->getIterator(), 'WS2');
$topic->broadcast(json_encode($data));
}
a $topic je pouze prazdny SplObjectStorage
public function broadcast($message, array $exclude = [], array $eligible = []): void
{
if (!is_string($message) && !$message instanceof WebSocketsApplication\Responses\IResponse) {
throw new Exceptions\InvalidArgumentException(sprintf('Provided message for broadcasting have to be string or instance of "%s"', WebSocketsApplication\Responses\IResponse::class));
}
$useEligible = (bool) count($eligible);
Debugger::log($this->subscribers, 'X');
/** @var WebSocketsEntities\Clients\IClient $client */
foreach ($this->subscribers as $client) {
Debugger::log($client, 'X');
if (in_array($client->getId(), $exclude, true)) {
continue;
}
if ($useEligible && !in_array($client->getParameter('subscribedTopics'), $eligible, true)) {
continue;
}
$client->send(Utils\Json::encode([Application\Application::MSG_EVENT, $this->id, (string) $message]));
}
}
a funkce broadcast ma prazdnou promennou $this->subscribers
Vubec nechapu, kde je problem, ze tam neni prihlaseny uzivatel k topicu, kdyz v prvnim logu vidim, ze prihlaseni probehlo uspesne? :(
- pista5
- Člen | 72
dakur napsal(a):
Zkus si ten kód prokrokovat, pak uvidíš, co se ve které chvíli děje. Je to poměrně jistý způsob odhalení problému, když člověk už fakt neví.
To samozrejme delam, viz kod vyse :))
Ale nechapu, proc neobdrzim v IPub\WebSocketsWAMP\Entities\Topics\ITopic $topic seznam uzivatelu, ktere se tam predtim ulozili. A zde nevim, co bych krokoval…
Jedna funkce zapise uzivatele jako odberetele u topicu a pri zavolani jine funkce se tam nepreda instance $topic s temito uzivateli… moje znalosti nesahaji tak daleko, abych tusil, co se deje mezi tim… kde se uchovava data a proc se mi to nepreda do fukce