Monthly Archives: July 2012

Scroll desktop’s Web pages remotely with our smartphone, using Node.js and WebSockets

Why this script? OK. It was a crazy idea. It started with one “Is it possible? Yes, let’s code it” in my mind. Let start. I want to scroll one web page in the TV’s web browser (or PC’s browser) using my smartphone lying on my couch. I’ve got a wireless mouse so I don’t really need it, but scroll the TV browser with the smartphone sounds cool, isn’t it?

The idea is the following one:

  • One QR code in our web page (added dinamically with JavaScrip with Google’s Chart API ). Write urls with the smartphone is hard and QR has a good hype, so we will add a QR code at the bottom of the web page with the link to the node.js server.
  • One socket.io server built with a node.js server for the real time communications. This node.js server will serve also a jQuery Mobile application with four buttons (with express and jade):
  • The server will register the WebSocket and send the real time commands to the browser (with one easy-to-hack security token).
  • The browser will handle the socket.io actions and controls the scroll of the web page.

The code is probably crowded by bugs and security problems, but it works and it was enough in my experiment :) :

The node.js server:

var io = require('socket.io').listen(8080);

var app = require('express').createServer();
app.set('view engine', 'jade');

app.set('view options', {
    layout:false
});

app.get('/panel/:key', function (req, res) {
    var key = req.params.key;
    console.log(key);
    res.render('mobile.jade', {key:key});
});

app.get('/action/:key/:y/:action', function (req, res) {
    var key = req.params.key;
    var y = req.params.y;
    var action = req.params.action;
    sockets[key].emit('scrollTo', {y:y, action:action});
    res.send('OK');
});

app.listen(8000);

var sockets = {};
io.sockets.on('connection', function (socket) {
    socket.on('setKey', function (key) {
        sockets[key] = socket;
    });
});

The jade template with the jquery mobile application:

!!! 5
html
    head
        meta(charset="utf-8")
        meta(name="viewport", content="width=device-width, initial-scale=1")
        title title
        link(rel='stylesheet', href='http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css')
        script(src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js')
        script(src='http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js')
        script(type='text/javascript')
            $(document).bind('pageinit', function() {
                $('#toTop').tap(function() {
                    $.get('/action/#{key}/0/go', function() {});
                });
                $('#toBotton').tap(function() {
                    $.get('/action/#{key}/max/go', function() {});
                });
                $('#toUp').tap(function() {
                    $.get('/action/#{key}/100/rew', function() {});
                });
                $('#toDown').tap(function() {
                    $.get('/action/#{key}/100/ffd', function() {});
                });
            });
    body
        #page1(data-role="page")
            #header(data-theme="a", data-role="header")
                h3 Header
            #content(data-role="content")
                a(data-role="button", data-transition="fade", data-theme="a", href="#", id="toTop", data-icon="minus", data-iconpos="left") Top
                a(data-role="button", data-transition="fade", href="#", id="toUp", data-icon="arrow-u", data-iconpos="left") Up
                a(data-role="button", data-transition="fade", href="#", id="toDown", data-icon="arrow-d", data-iconpos="left") Down
                a(data-r

Our Html client page

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>jQuery Smooth Scroll - Design Woop</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>
    Lorem ipsum ….. put a big lorem ipsum here to make possible the scroll
</p>
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</body>
</html>

And finally our client magic with the QR code and the functions to handle the node.js actions

var key = "secret";
function getDocHeight() {
    var D = document;
    return Math.max(
            Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
            Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
            Math.max(D.body.clientHeight, D.documentElement.clientHeight)
    );
}
var socket = io.connect('http://localhost:8080');
var y = 0;

socket.emit('setKey', key);
socket.on('scrollTo', function (data) {
    if (data.y == 'max') {
        y = getDocHeight();
    } else {
        if (data.action == 'ffd') {
            y += parseInt(data.y);
        } else if (data.action == 'go') {
            y = parseInt(data.y);
        } else {
            y -= parseInt(data.y);
        }
    }
    window.scrollTo(0, y);

});
document.write('<img src="https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=http://192.168.2.3:8000/panel/' + key + '&choe=UTF-8" alt=""/>');

You can see the code in github too. We also can see the script in action here:

We can also add more features to our application but that’s enought for this experiment. What do you think?

Building a simple Dependency Injection Container with PHP

If you are looking for a small Dependency Injection Container with PHP maybe you need have look to Pimple.

Pimple is a small Dependency Injection Container for PHP 5.3 that consists of just one file and one class (about 50 lines of code).

Now, keeping with my aim of reinvent the wheel, we will create a simple Dependency Injection Container basically to understand how does it work. Let’s start.

First of all: Do we really need a Dependency Injection Container (DIC)? If you are asking yourself this question, maybe you need to have look to Fabien Poetencier’s article.

We are going to work with a teorical problem like this:

Imagine we are going to build a service that uses one external REST API. We define your application with three classes:

  • App. The main application.
  • Proxy The part of the application that speaks with the external API
  • Curl. One curl wrapper to perform our http connections to the REST API

Our first approach can be:

<?php
class App
{
    private $proxy;

    public function __construct()
    {
        echo "App::__construct\n";
        $this->proxy = new Proxy();
    }

    public function hello()
    {
        return $this->proxy->hello();
    }
}

class Proxy
{
    private $curl;

    public function __construct()
    {
        $this->curl = new Curl();
    }

    public function hello()
    {
        echo "Proxy::__construct\n";
        return $this->curl->doGet();
    }
}

class Curl
{
    public function doGet()
    {
        echo "Curl::doGet\n";
        return "Hello";
    }
}

$app = new App();
echo $app->hello();

If we execute the script:

php example1.php 

App::__construct
Proxy::__construct
Curl::doGet
Hello

It works but we have one problem. Our application is strongly coupled. As we can see App creates a new instance of Proxy within the constructor and Proxy creates a new instance of Curl. That’s a problem especially if we want to use TDD. What happens if we want to mock Curl requests to test the application without using the real external service?. Dependency injection can help us here. We can change our application to:

<?php
class App
{
    private $proxy;

    public function __construct(Proxy $proxy)
    {
        echo "App::__construct\n";
        $this->proxy = $proxy;
    }

    public function hello()
    {
        return $this->proxy->hello();
    }
}

class Proxy
{
    private $curl;

    public function __construct(Curl $curl)
    {
        $this->curl = $curl;
    }

    public function hello()
    {
        echo "Proxy::__construct\n";
        return $this->curl->doGet();
    }
}

class Curl
{
    public function doGet()
    {
        echo "Curl::doGet\n";
        return "Hello";
    }
}


$app = new App(new Proxy(new Curl()));
echo $app->hello();

The outcome is exactly the same but now we can easily use mocks and use different configurations depending on the environment. Maybe your testing development does not have access to the real REST server.

Now our application isn’t coupled but as we can see our Dependency Injection becomes a mess. That’s one problem with DI. It’s pretty straightforward to inject simple things but when we have dependencies over a set of classes that’s becomes a difficult task. Because of that we can use Dependency Injection Containers.

If we choose Pimple as Dependency Injection Container we can refactor our application to:

<?php
class App
{
    private $proxy;

    public function __construct(Pimple $container)
    {
        echo "App::__construct\n";
        $this->proxy = $container['Proxy'];
    }

    public function hello()
    {
        return $this->proxy->hello();
    }
}

class Proxy
{
    private $curl;

    public function __construct(Pimple $container)
    {
        $this->curl = $container['Curl'];
    }

    public function hello()
    {
        echo "Proxy::__construct\n";
        return $this->curl->doGet();
    }
}

class Curl
{
    public function doGet()
    {
        echo "Curl::doGet\n";
        return "Hello";
    }
}

require_once 'Pimple.php';

$container = new Pimple();
$container['Curl'] = function ($c) {return new Curl();};
$container['Proxy'] = function ($c) {return new Proxy($c);};

$app = new App($container);
echo $app->hello();

But what is my problem with Pimple? Basically my problem is that my IDE cannot autocomplete correctly $container is an instance of Pimple not the “real” instance. OK It instantiated on demand the classes but it’s done at runtime and the IDE don’t know about that. We can solve it using an extra PHPDoc to give hints to the IDE but we also can use a different approach. Instead of using Pimple we can use this script:

<?php
class App
{
    private $proxy;

    public function __construct(Container $container)
    {
        echo "App::__construct\n";
        $this->proxy = $container->getProxy();
    }

    public function hello()
    {
        echo "App::hello\n";
        return $this->proxy->hello();
    }
}

class Proxy
{
    private $curl;

    public function __construct(Container $container)
    {
        echo "Proxy::__construct\n";
        $this->curl = $container->getCurl();
    }

    public function hello()
    {
        return $this->curl->doGet();
    }
}

class Curl
{
    public function doGet()
    {
        echo "Curl::doGet\n";
        return "Hello";
    }
}

class Container
{
    public function getProxy()
    {
        return new Proxy($this);
    }

    public function getCurl()
    {
        return new Curl();
    }
}

$app = new App(new Container());
echo $app->hello();

The idea is the same than Pimple but now we have created our custom Dependency Injection Container without extending any library and now our IDE will autocomplete the fucntion names without problems. If we want to share objects instead creating new ones each time we call the factory function of the container we can change a little bit our Container (the same way than Pimple::share) with a simple singleton pattern:

class Container
{
    static $proxy;
    public function shareProxy()
    {
        if (NULL === self::$proxy) self::$proxy = new Proxy($this);
        return self::$proxy;
    }

    public function getCurl()
    {
        return new Curl();
    }
}

And that’s all. What do you think?

Follow

Get every new post delivered to your Inbox.

Join 989 other followers