Browse Source

- First raw import of the daemon in Movim

- Adapt RPC to be called with the linker
- Create the MovimWebsocket javascript class to handle the websocket connection
pull/16/head
Jaussoin Timothée 11 years ago
parent
commit
cc8e6c1a6d
  1. 2
      app/assets/js/movim_base.js
  2. 91
      app/assets/js/movim_websocket.js
  3. 3
      app/views/page.tpl
  4. 5
      bootstrap.php
  5. 12
      composer.json
  6. 20
      daemon.php
  7. 100
      linker.php
  8. 134
      src/Movim/Daemon/Behaviour.php
  9. 20
      system/RPC.php
  10. 2
      system/controllers/AjaxController.php
  11. 2
      system/controllers/BaseController.php

2
app/assets/js/movim_base.js

@ -23,7 +23,7 @@ function movim_onload()
{
for(var i = 0; i < onloaders.length; i++) {
if(typeof(onloaders[i]) === "function")
onloaders[i]();
onloaders[i]();
}
}

91
app/assets/js/movim_websocket.js

@ -0,0 +1,91 @@
/**
* Movim Websocket
*
* This file define the websocket behaviour and handle its connection
*/
WebSocket.prototype.link = function(body) {
this.send(JSON.stringify({'func' : 'link'}));
};
WebSocket.prototype.register = function() {
this.send(JSON.stringify({'func' : 'register', 'sid' : localStorage.movimSession}));
};
/**
* @brief Definition of the MovimWebsocket object
* @param string error
*/
function MovimWebsocket() {
var connection;
}
MovimWebsocket.prototype.init = function() {
this.connection = new WebSocket('ws://localhost:8080');
this.connection.onopen = function(e) {
console.log("Connection established!");
if(localStorage.movimSession === undefined) {
this.send(JSON.stringify({'func' : 'ask'}));
} else {
this.register();
}
// And we launch the Javascript
movim_onload();
};
this.connection.onmessage = function(e) {
console.log(e.data);
var obj = JSON.parse(e.data);
if(obj.id) {
localStorage.movimSession = obj.id;
this.register();
}
websocket.handle(e.data);
};
};
MovimWebsocket.prototype.send = function(widget, func, params) {
this.connection.send(
JSON.stringify(
{'func' : 'message', 'body' :
{
'widget' : widget,
'func' : func,
'params' : params
}
}
)
);
};
MovimWebsocket.prototype.handle = function(json) {
var funcalls = eval(json);
if(funcalls != null) {
for(h = 0; h < funcalls.length; h++) {
var funcall = funcalls[h];
if(funcall.func != null && eval("typeof " + funcall.func) == "function") {
var funcs = funcall.func.split('.');
try {
if(funcs.length == 1)
window[funcs[0]](funcall.params);
else if(funcs.length == 2)
window[funcs[0]][funcs[1]](funcall.params);
}
catch(err) {
console.log("Error caught: " + err.toString() + " - " +funcall.func);
}
}
}
}
}
// And we start it
var websocket = new MovimWebsocket;
websocket.init();

3
app/views/page.tpl

@ -86,9 +86,6 @@
© <a href="http://www.movim.eu">Movim</a> • 2008 - 2014 • Under <a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License</a>
</footer>
</div>
<script type="text/javascript">
movim_onload();
</script>
<?php
$this->displayFooterDebug();
?>

5
bootstrap.php

@ -146,8 +146,9 @@ class Bootstrap {
}
$uri = str_replace('jajax.php', '', $uri);
return $uri;
return 'http://localhost/0.9/';
//return $uri;
}
private function loadSystem() {

12
composer.json

@ -1,4 +1,10 @@
{
"autoload": {
"psr-0": {
"Movim": "src"
}
},
"require": {
"monolog/monolog": "1.8.*",
"libchart/libchart": "dev-default",
@ -6,6 +12,10 @@
"michelf/php-markdown": "1.4.*@dev",
"movim/modl": "dev-master",
"movim/sasl2": "dev-master",
"movim/moxl": "dev-master"
"movim/moxl": "dev-master",
"cboden/ratchet": "0.3.*",
"devristo/phpws": "dev-master",
"react/child-process": "0.5.*@dev"
}
}

20
daemon.php

@ -0,0 +1,20 @@
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Movim\Daemon\Behaviour;
require dirname(__FILE__) . '/vendor/autoload.php';
$server = new Behaviour;
$server = IoServer::factory(
new HttpServer(
new WsServer(
$server
)
),
8080
);
$server->run();

100
linker.php

@ -0,0 +1,100 @@
<?php
require __DIR__ . '/vendor/autoload.php';
define('DOCUMENT_ROOT', dirname(__FILE__));
require_once(DOCUMENT_ROOT.'/bootstrap.php');
$bootstrap = new Bootstrap();
$booted = $bootstrap->boot();
set_time_limit(200);
$polling = true;
$loop = React\EventLoop\Factory::create();
$logger = new \Zend\Log\Logger();
$writer = new \Zend\Log\Writer\Syslog(array('application' => 'movim'));
$logger->addWriter($writer);
$client_xmpp = new \Devristo\Phpws\Client\WebSocket("ws://movim.eu:5290/", $loop, $logger);
$client_local = new \Devristo\Phpws\Client\WebSocket("ws://127.0.0.1:8080/", $loop, $logger);
// CLIENT 1
$client_xmpp->on("request", function($headers) use ($logger){
$logger->notice("XMPP : Request object created!");
});
$client_xmpp->on("handshake", function() use ($logger) {
$logger->notice("XMPP : Handshake received!");
});
$client_xmpp->on("connect", function($headers = false) use ($client_xmpp, $logger) {
$logger->notice("XMPP : Connected");
});
$client_xmpp->on("disconnect", function($headers = false) use ($client_xmpp) {
$logger->notice("XMPP : Disconnected");
$client_local->close();
});
$client_xmpp->on("message", function($message) use ($client_local, $logger){
$logger->notice("XMPP : Got message");
$obj = new \StdClass;
$obj->func = 'message';
$obj->body = $message->getData();
$client_local->send(json_encode($obj));
});
// CLIENT 2
$client_local->on("request", function($headers) use ($logger){
$logger->notice("LOOP : Request object created!");
});
$client_local->on("handshake", function() use ($logger) {
$logger->notice("LOOP : Handshake received!");
});
$client_local->on("connect", function($headers = false) use ($client_local, $logger) {
$logger->notice("LOOP : Connected!");
$obj = new \StdClass;
$obj->func = 'register_linker';
$obj->sid = getenv('sid');
$client_local->send(json_encode($obj));
});
$client_local->on("disconnect", function($headers = false) use ($client_local) {
$logger->notice("LOOP : Disconnected");
$client_xmpp->close();
});
$client_local->on("message", function($message) use ($client_local, $client_xmpp, $logger){
if($message->getData() != '') {
$rpc = new RPC();
$rpc->handle_json($message->getData());
$logger->notice("LOOP : Got message");
$obj = new \StdClass;
$obj->func = 'message';
$obj->body = RPC::commit();
RPC::clear();
$client_local->send(json_encode($obj));
}
//$client_xmpp->send($message->getData());
});
$client_local->open();
$client_xmpp->open();
$loop->run();

134
src/Movim/Daemon/Behaviour.php

@ -0,0 +1,134 @@
<?php
namespace Movim\Daemon;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Behaviour implements MessageComponentInterface {
protected $sessions = array(); // Store the sessions
public function __construct() {
echo "Movim daemon launched\n";
}
public function onOpen(ConnectionInterface $conn) {
echo "{$conn->resourceId} connected\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$msg = json_decode($msg);
switch ($msg->func) {
// The browser ask for a new session
case 'ask':
$id = $this->generateId();
$obj = new \StdClass;
$obj->id = $id;
$from->send(json_encode($obj));
break;
// A browser websocket ask to be linked to an existent session
case 'register':
$from->sid = $msg->sid;
if(!array_key_exists($from->sid, $this->sessions)) {
$this->sessions[$from->sid] = array();
}
$this->sessions[$from->sid][$from->resourceId] = $from;
// If a linker doesn't exist for the current session
if(!array_key_exists('linker', $this->sessions[$from->sid])) {
$from->send(json_encode('session linked'));
$loop = \React\EventLoop\Factory::create();
$process = new \React\ChildProcess\Process('php linker.php', null, array('sid' => $from->sid));
$process->start($loop);
}
$session_size = count($this->sessions[$from->sid]);
echo "{$from->sid} : {$from->resourceId} registered - session size {$session_size}\n";
break;
// A linker ask to be linked to a session
case 'register_linker':
if(array_key_exists($msg->sid, $this->sessions) &&
!array_key_exists('linker', $this->sessions[$msg->sid])) {
$from->sid = $msg->sid;
$this->sessions[$from->sid]['linker'] = $from;
}
$session_size = count($this->sessions[$from->sid]);
echo "{$from->sid} : {$from->resourceId} linker registered - session size {$session_size}\n";
break;
// A message is received !
case 'message':
// Forbid any incoming messages if the session is not linked to XMPP
if(!array_key_exists('linker', $this->sessions[$from->sid])) {
$from->send(json_encode('linker not connected'));
return;
}
$msg->body = (string)json_encode($msg->body);
// A message from the linker to the clients
if($from === $this->sessions[$from->sid]['linker']) {
echo "{$from->sid} : {$msg->body} got from the linker\n";
foreach($this->sessions[$from->sid] as $key => $client) {
if($from !== $client) {
//The sender is not the receiver, send to each client connected
if(isset($msg->body)) {
$client->send($msg->body);
}
}
}
// A message from the browser to the linker
} else {
echo "{$from->sid} : {$msg->body} sent to the linker\n";
$this->sessions[$from->sid]['linker']->send((string)$msg->body);
}
break;
default:
$from->send('no function specified');
break;
}
}
public function onClose(ConnectionInterface $conn) {
$session_size = count($this->sessions[$conn->sid]);
// The connection is closed, remove it, as we can no longer send it messages
if($conn === $this->sessions[$conn->sid]['linker']) {
foreach($this->sessions[$conn->sid] as $key => $client) {
$client->close();
}
unset($this->sessions[$conn->sid]);
} else {
unset($this->sessions[$conn->sid][$conn->resourceId]);
}
echo "{$conn->resourceId} disconnected - session size {$session_size}\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
private function generateId() {
// Generating the session cookie's hash.
$hash_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$hash = "";
for($i = 0; $i < 16; $i++) {
$r = mt_rand(0, strlen($hash_chars) - 1);
$hash.= $hash_chars[$r];
}
return $hash;
}
}

20
system/RPC.php

@ -74,17 +74,27 @@ class RPC
self::$funcalls = array('ping');
}
header('Content-Type: application/json');
printf('%s', json_encode(self::$funcalls));
//header('Content-Type: application/json');
//printf('%s', json_encode(self::$funcalls));
return self::$funcalls;
}
public static function clear()
{
self::$funcalls = array();
}
/**
* Handles incoming requests.
*/
public function handle_json()
public function handle_json($content = false)
{
$json = file_get_contents('php://input');
if($content && $content != '') {
$json = $content;
} else {
$json = file_get_contents('php://input');
}
$request = json_decode($json);
if(isset($_GET['do']) && $_GET['do'] == 'poll') {

2
system/controllers/AjaxController.php

@ -44,7 +44,7 @@ class AjaxController extends BaseController
$buffer .= "function " . $funcdef['object'] . '_'
. $funcdef['funcname'] . "(${parlist}) {";
$buffer .= "movim_ajaxSend('".$funcdef['object']."', '".$funcdef['funcname']."', [${parlist}]);}\n";
$buffer .= "websocket.send('".$funcdef['object']."', '".$funcdef['funcname']."', [${parlist}]);}\n";
}
return $buffer . "</script>\n";

2
system/controllers/BaseController.php

@ -14,7 +14,7 @@ class BaseController {
$this->page->addScript('movim_base.js');
$this->page->addScript('movim_tpl.js');
$this->page->addScript('movim_rpc.js');
$this->page->addScript('movim_lazy.js');
$this->page->addScript('movim_websocket.js');
}

Loading…
Cancel
Save