middleware/Communication/WSServer.cs
author bastiena
Thu, 24 May 2012 10:30:05 +0200
changeset 33 2d9b15f99b4e
parent 29 fcf435874395
child 37 37ebedd84755
permissions -rw-r--r--
Front IDILL : search by curves added search by type added notifications added timeline improved

/*
* This file is part of the TraKERS\Middleware package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/*
 * Projet : TraKERS
 * Module : MIDDLEWARE
 * Sous-Module : Communication
 * Classe : WSServer
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Reçoit des notifications du module sous-module Tracking.
 * Traduit les notifications sous forme de strings et les envoie au Front IDILL via WebSocket.
 * Forme des messages :
 * - Notification de main dans le champ de recherche : Point3D converti en String indiquant la position de la main dans l'espace.
 * - Notification de gesture/mode : String.
 * - Paramètres de config : String.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Fleck;
using System.Timers;
using System.Windows.Media.Media3D;

namespace Trakers.Communication
{
    public class WSServer
    {
        //Server WebSocket.
        WebSocketServer server;
        List<IWebSocketConnection> allSockets;

        //Permet de savoir si un curseur pour la main gauche/droite a été créé.
        private bool leftHandCursorCreated;
        private bool rightHandCursorCreated;
        private bool messageCreated;
        private bool gestureLocked, modLocked;
        //Intervalle minimum entre les gestures.
        private int timerElapsing;
        //Timer.
        private System.Timers.Timer _timer;
        //Dernier code envoyé.
        private String lastCode;
        //Messages envoyés en WS.
        private String rightHandMessage, leftHandMessage, gestureMessage;
        //Messages précédents
        private String prevRightHandMessage, prevLeftHandMessage, prevGestureMessage;

        /*
        * Constructeur : On initialise le serveur avec une adresse et un port, au début les curseurs
        * ne sont pas créés et on indique au ThreadPool une fonction de callback de manière à vérifier
        * s'il reçoit des notifications.
        */
        public WSServer(String host, int port, int _timerElapsing)
        {
            FleckLog.Level = LogLevel.Debug;
            allSockets = new List<IWebSocketConnection>();
            server = new WebSocketServer(port, "ws://" + host + ":" + port);

            //Au départ, aucune main n'est dans le champ de recherche et aucune gesture n'est détectée.
            leftHandCursorCreated = false;
            rightHandCursorCreated = false;
            messageCreated = false;
            gestureLocked = false;
            modLocked = false;
            lastCode = "";

            timerElapsing = _timerElapsing;

            rightHandMessage = leftHandMessage = gestureMessage = "";

            //On démarre le serveur WebSocket.
            server.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    Console.WriteLine("Open!");
                    allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine("Close!");
                    allSockets.Remove(socket);
                };
                /*socket.OnMessage = message =>
                {
                    Console.WriteLine(message);
                    allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
                };*/
            });

            //On initialise le threadPool (appelé toutes les N ms).
            ThreadPool.QueueUserWorkItem(ThreadPoolCallback);

            //On instancie le timer à N ms.
            _timer = new System.Timers.Timer(timerElapsing);
            //Dès que le timer est expiré, on appelle _timer_Elapsed.
            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);

            /*var input = Console.ReadLine();
            while (input != "exit")
            {
                foreach (var socket in allSockets.ToList())
                {
                    socket.Send(input);
                }
                input = Console.ReadLine();
            }*/
        }

        /*
         * Méthode appelée à l'expiration du timer pour les gestures et modes.
         */
        public void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //On débloque la détection de gesture.
            gestureLocked = false;
            //On débloque la notification de nouveau mode.
            modLocked = false;
            //On arrête le timer.
            _timer.Stop();
        }

        /*
        * Méthode appelée lors d'une notification de type : main gauche entrée dans le champ.
        */
        public void LeftHandTracked(Point3D pt)
        {
            leftHandMessage = "0-" + pt.X + ";" + pt.Y + ";" + pt.Z;
            //Si le curseur de la main gauche n'est pas créé, alors on le crée.
            if (!leftHandCursorCreated)
                leftHandCursorCreated = true;
        }

        /*
        * Méthode appelée lors d'une notification de type : main droite entrée dans le champ.
        */
        public void RightHandTracked(Point3D pt)
        {
            rightHandMessage = "1-" + pt.X + ";" + pt.Y + ";" + pt.Z;
            //Si le curseur de la main droite n'est pas créé, alors on le crée.
            if (!rightHandCursorCreated)
                rightHandCursorCreated = true;
        }

        /*
        * Méthode appelée lors d'une notification de type : main gauche sortie du champ.
        */
        public void LeftHandQuit()
        {
            leftHandMessage = "";
            //Si le curseur de la main gauche existe, alors on le supprime.
            if (leftHandCursorCreated)
                leftHandCursorCreated = false;
        }

        /*
        * Méthode appelée lors d'une notification de type : main droite sortie du champ.
        */
        public void RightHandQuit()
        {
            rightHandMessage = "";
            //Si le curseur de la main droite existe, alors on le supprime.
            if (rightHandCursorCreated)
                rightHandCursorCreated = false;
        }

        /*
        * Méthode appelée lorsqu'une gesture a été détectée et que l'événement approprié a été lancé.
        */
        public void GesturePerformed(String code)
        {
            //Si le code vient d'être envoyé, on passe.
            if (lastCode.Equals(code))
                return;
            lastCode = code;
            //Si une gesture a été effectuée, on bloque un certain temps.
            if (!gestureLocked)
            {
                gestureLocked = true;

                //On crée un message contenant le code à envoyer.
                if (!messageCreated)
                {
                    messageCreated = true;
                    gestureMessage = "2-" + code;
                    //On démarre le timer.
                    _timer.Start();
                }
            }
        }

        /*
        * Méthode appelée lorsqu'on doit entrer dans un autre mode.
        */
        public void ModeNotification(String code)
        {
            //Si le code vient d'être envoyé, on passe.
            if (lastCode.Equals(code))
                return;
            lastCode = code;
            //Si on a été notifié.
            if (!modLocked)
            {
                modLocked = true;

                //On crée un message contenant le code à envoyer.
                if (!messageCreated)
                {
                    messageCreated = true;
                    gestureMessage = "2-" + code;
                    //On démarre le timer.
                    _timer.Start();
                }
            }
        }

        /*
        * Méthode de callback vérifiant toutes les 25 ms les nouvelles notifications.
        * Il est à noter que si le temps de rafraîchissement des trop rapide, les messages n'ont pas
        * le temps d'être envoyés.
        */
        private void ThreadPoolCallback(Object threadContext)
        {
            while (true)
            {
                //S'il existe un message.
                if (gestureMessage != null && !gestureMessage.Equals("") && !gestureMessage.Equals(prevGestureMessage))
                {
                    //On l'envoie au client (au host et au port spécifiés dans le constructeur).
                    foreach (var socket in allSockets.ToList())
                    {
                        socket.Send(gestureMessage);
                        prevGestureMessage = gestureMessage;
                    }
                }
                //Si la main gauche est détectée.
                if (leftHandMessage != null && !leftHandMessage.Equals("") && !leftHandMessage.Equals(prevLeftHandMessage))
                {
                    //On l'envoie au client (au host et au port spécifiés dans le constructeur).
                    foreach (var socket in allSockets.ToList())
                    {
                        socket.Send(leftHandMessage);
                        prevLeftHandMessage = leftHandMessage;
                    }
                }
                //Si la main droite est détectée.
                if (rightHandMessage != null && !rightHandMessage.Equals("") && !rightHandMessage.Equals(prevRightHandMessage))
                {
                    //On l'envoie au client (au host et au port spécifiés dans le constructeur).
                    foreach (var socket in allSockets.ToList())
                    {
                        socket.Send(rightHandMessage);
                        prevRightHandMessage = rightHandMessage;
                    }
                }
                
                //On attend 25 ms.
                Thread.Sleep(25);

                //Si une gesture a été effectuée et que le délai d'attente est expiré.
                if (messageCreated && !gestureLocked && !modLocked)
                {
                    //On débloque la détection de gesture et on supprime l'objet envoyant les messages OSC de gesture.
                    messageCreated = false;
                    gestureMessage = "";
                }
            }
        }

        /*
         * Getters et Setters
         */
        public void setTimerElapsing(int _timerElapsing)
        {
            timerElapsing = _timerElapsing;
        }

        public int getTimerElapsing()
        {
            return timerElapsing;
        }
    }
}