Удаленное управление смартфоном с Node.js и Socket.io

в 16:06, , рубрики: javascript, node.js, socket.io, Веб-разработка, Мобильный веб, Презентации

Было бы прикольно использовать свой смартфон в качестве пульта управления, не так ли? На самом деле, выглядит не очень то и сложно. Вам даже не нужно уметь писать крупные приложения, так как имеется браузера, поддерживающий открытие сокетов. В этом коротком уроке мы воспользуемся Node.js и Socket.io, чтобы с помощью телефона управлять презентацией, запущенной на компьютере.

Есть множество крутых библиотек HTML5 для создания презентаций, но не одна из них не предусмотрена для задуманной нами идеи. В связи с этим мы воспользуемся Reveal.js — библиотека будет работать с анимацией и реагировать на нажатие клавиатуры или прикосновение к экрану смартфона.

Мы не будем разрабатывать отдельный интерфейс управления. Вместо этого займемся синхронизацией открытой презентации на обоих устройствах. Это позволит вам не только видеть мобильную версии презентации, но и понимать, какой из слайдов активен в данный момент.

Идея

Наша задумка проста — Reveal.js будет передавать номер текущего слайда через URL в виде хеша (например, example.com/#/1). Затем мы будем рассылать данный хеш на все остальные подключенные устройства, что будет перелистывать на них презентации автоматически. В связи с этим любой сможет испортить все элементарным открытием произвольного слайда, что приведет к перелистыванию на всех устройствах. Во избежание сего установим пароль и будем требовать его ввода для подключения.

Полезно упомянуть то, что у Reveal.js уже есть API, и мы можем использовать его для синхронизации, но техника смены и рассылки хеша проще, так что воспользуемся ею.
Удаленное управление смартфоном с Node.js и Socket.io - 1
Наша презентация

Запуск примера

Вы можете запустить пример на своем компьютере или развернуть у провайдера типа Heroku. Первый вариант проще, но нужно установить node.js и npm. Второй подразумевает установку heroku toolbelt и регистрацию в системе.

Для запуска локально:

  1. Скачайте архив с кодом;
  2. Убедитесь в том, что node.js установлен;.
  3. Разархивируйте скачанный файл;
  4. Откройте терминал и перейдите в папку с извлеченными файлами;
  5. Запустите npm install для установки библиотек;
  6. Запустите приложение командой node app.js;
  7. Откройте http://localhost:8080 и введите пароль (“kittens“ по умолчанию);
  8. Откройте http://<локальный адрес компьютера> на телефоне и введите ту же фразу;
  9. Радуйтесь!

Для запуска в Heroku:

  1. Скачайте архив с кодом;
  2. Разархивируйте его;
  3. Откройте терминал и перейдите в папку;
  4. Создайте репозиторий и первый commit;
  5. Создайте приложение в Heroku;
  6. Запустите git push heroku master;
  7. Откройте приложение по его адресу и введите пароль “kittens” (по умолчанию).

Прочитать больше об этом процесс можно здесь. Если Вы пользуетесь другим провайдером, последние шаги могут отличаться.

Код

Хватит разговаривать, давайте взглянем на код! У нас всего два JavaScript файла – app.js для back-end и script.js для браузера. Вы можете запустить приложение в Node.js 0.10+ или в io.js.

В серверной части мы используем express и socket.io. Его задача — прослушивание событий socket.io и отправка ответов на них. С express.static мы отображаем файлы из публичных папок. В файле public/index.html содержится сама презентация. Она обрабатывается автоматически через express.static, так что в адресе не нужно указывать “/”.
app.js

// This is the server-side file of our mobile remote controller app.
// It initializes socket.io and a new express instance.
// Start it by running 'node app.js' from your terminal.


// Creating an express server

var express = require('express'),
    app = express();

// This is needed if the app is run on heroku and other cloud providers:

var port = process.env.PORT || 8080;

// Initialize a new socket.io object. It is bound to 
// the express app, which allows them to coexist.

var io = require('socket.io').listen(app.listen(port));


// App Configuration

// Make the files in the public folder available to the world
app.use(express.static(__dirname + '/public'));


// This is a secret key that prevents others from opening your presentation
// and controlling it. Change it to something that only you know.

var secret = 'kittens';

// Initialize a new socket.io application

var presentation = io.on('connection', function (socket) {

    // A new client has come online. Check the secret key and 
    // emit a "granted" or "denied" message.

    socket.on('load', function(data){

        socket.emit('access', {
            access: (data.key === secret ? "granted" : "denied")
        });

    });

    // Clients send the 'slide-changed' message whenever they navigate to a new slide.

    socket.on('slide-changed', function(data){

        // Check the secret key again

        if(data.key === secret) {

            // Tell all connected clients to navigate to the new slide
            
            presentation.emit('navigate', {
                hash: data.hash
            });
        }
    });
});

console.log('Your presentation is running on http://localhost:' + port);

А вот и JavaScript для front-end, который слушает событие hashchange и отправляет сообщение socket.io на сервер.
public/assets/js/script.js

$(function() {

    // Apply a CSS filter with our blur class (see our assets/css/styles.css)
    
    var blurredElements = $('.homebanner, div.reveal').addClass('blur');

    // Initialize the Reveal.js library with the default config options
    // See more here https://github.com/hakimel/reveal.js#configuration

    Reveal.initialize({
        history: true		// Every slide will change the URL
    });

    // Connect to the socket

    var socket = io();

    // Variable initialization

    var form = $('form.login'),
        secretTextBox = form.find('input[type=text]');

    var key = "", animationTimeout;

    // When the page is loaded it asks you for a key and sends it to the server

    form.submit(function(e){

        e.preventDefault();

        key = secretTextBox.val().trim();

        // If there is a key, send it to the server-side
        // through the socket.io channel with a 'load' event.

        if(key.length) {
            socket.emit('load', {
                key: key
            });
        }

    });

    // The server will either grant or deny access, depending on the secret key

    socket.on('access', function(data){

        // Check if we have "granted" access.
        // If we do, we can continue with the presentation.

        if(data.access === "granted") {

            // Unblur everything
            blurredElements.removeClass('blurred');

            form.hide();

            var ignore = false;

            $(window).on('hashchange', function(){

                // Notify other clients that we have navigated to a new slide
                // by sending the "slide-changed" message to socket.io

                if(ignore){
                    // You will learn more about "ignore" in a bit
                    return;
                }

                var hash = window.location.hash;

                socket.emit('slide-changed', {
                    hash: hash,
                    key: key
                });
            });

            socket.on('navigate', function(data){
    
                // Another device has changed its slide. Change it in this browser, too:

                window.location.hash = data.hash;

                // The "ignore" variable stops the hash change from
                // triggering our hashchange handler above and sending
                // us into a never-ending cycle.

                ignore = true;

                setInterval(function () {
                    ignore = false;
                },100);

            });

        }
        else {

            // Wrong secret key

            clearTimeout(animationTimeout);

            // Addding the "animation" class triggers the CSS keyframe
            // animation that shakes the text input.

            secretTextBox.addClass('denied animation');
            
            animationTimeout = setTimeout(function(){
                secretTextBox.removeClass('animation');
            }, 1000);

            form.show();
        }

    });

});

It’s Slideshow Time!

Наш пульт в виде смартфона готов! Надеюсь, Вам это пригодится и понравится.

Скачать код
Демо

Автор: alexandfox

Источник

  1. Александр Горбылёв:

    Хотел взять и изучить исходный код, но “403 Forbidden”!! :(
    Это не есть хорошо.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js