Documentation du code

This commit is contained in:
SeekDaSky 2017-12-08 06:06:46 +01:00
parent b944b060c1
commit 317c4164b3
12 changed files with 259 additions and 88 deletions

View File

@ -7,11 +7,18 @@ import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Message.*;
import seekdasky.kWebSocket.Server
/**
* Classe s'occupant de la partie chat simple du site, ancienne version que l'on a pas eu le temps de refactorer, pour un meilleur exemple regardez les classe contenues dans le package Channels
*/
class Channel : AsynchronousListener {
//nom du channel, utilisé pour définir l'URL d'écoute
val channelName : String;
//list des clients
var clients : MutableList<Client>;
//liste des messages du chat
val messages : Stack<Pair<Client, String>>;
//instance du serveur
val serv : Server;
constructor(serv : Server , chanName : String){
@ -21,43 +28,56 @@ class Channel : AsynchronousListener {
this.serv = serv;
}
/**
* comme toute les autres méthodes filter
*/
override fun filter(c: Client): Boolean {
return this.channelName == c.URL;
}
/**
* méthode executée quand le client ferme son socket
*/
override fun processClosed(e: Event) {
this.clients.remove(e.client);
ConnectChannel.notifyDisconnect(e.client);
System.out.println("A client disconnected ("+this.clients.count()+" clients connected)");
}
/**
* les clients sont ajouté a la liste lors de leur première connection mais ne sont pas loggués
*/
override fun processConnection(c: Client) {
this.clients.add(c);
c.data["IsLogged"] = false;
}
/**
* méthode gérant la connexion et l'envoi de message
*/
override fun processEvent(e: Event) {
try{
val json = JSONObject(e.message.getString())
if(json.has("close")){
return
}
if(e.client.data["IsLogged"] != true){
//json format : {username:xxx}
if(json.has("name") && json.getString("name") != null){
e.client.data["Username"] = json.getString("name");
//on demande si le client est bien connecté
if(ConnectChannel.isConnected(e.client)){
System.out.println("A client connected ("+this.clients.count()+" clients connected)");
//on loggue le client et on lui notifie le succès
e.client.data["IsLogged"] = true;
val jsonLogin = JSONObject();
jsonLogin.put("error",false);
e.client.send(buildTextMessage(jsonLogin.toString()));
//on lui envoie la liste des messages
val array = JSONArray();
//gare a la concurrence
synchronized(this.messages,{
this.messages.toList().forEach {
array.put(JSONArray(listOf(it.first.data["Username"],it.second)))
@ -87,6 +107,7 @@ class Channel : AsynchronousListener {
return;
}else if(json.has("message")){
//gare a la concurrence
synchronized(this.messages,{
this.messages.push(Pair(e.client,json.getString("message")))
});

View File

@ -1,43 +0,0 @@
import seekdasky.kWebSocket.Client
import seekdasky.kWebSocket.Event
import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Server
class ChannelDispatcher : AsynchronousListener{
val serv : Server;
private var channels : MutableList<Channel>;
constructor(serv : Server){
this.serv = serv;
this.channels = mutableListOf();
}
override fun filter(c: Client): Boolean {
for(chan in this.channels){
if(chan.channelName == c.URL){
return false;
}
}
return true;
}
override fun processClosed(e: Event) {
//no client should arrive here
}
override fun processConnection(c: Client) {
System.out.println("new channel created: "+c.URL);
//if a client is handled here it means we have no channel at this address, let's create it
var newChan = Channel(this.serv,c.URL);
this.serv.addListener(newChan);
//we transfer the client to the new channel
newChan.processConnection(c);
this.channels.add(newChan);
}
override fun processEvent(e: Event) {
//no client should arrive here
}
}

View File

@ -10,20 +10,43 @@ import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Message.buildTextMessage
import seekdasky.kWebSocket.Server
/**
* La classe abstraite AbstractChannel fournis toutes les méthodes nécéssaire a la gestion du channel (authentification, méthode de gestion des messages
* utilisés par les classes Interop, dispatch des messages a tout les clients, la seule partie abstraite est le nom du channel (propriété ChanName)
* qui sert a définir l'URL d'écoute.
*/
abstract class AbstractChannel : AsynchronousListener {
//liste de tout les clients du channel
var clients : MutableList<Client>;
//map ayant en clé le nom du channel et en valeur la stack de message, la stack est composé de paire nom d'utilisateur/message
val messages : MutableMap<String, Stack<Pair<String, Message>>>;
//instance du serveur pour dispatcher les évenements
val serv : Server;
//propriété abstraite servant a définir l'addresse d'écoute
abstract val chanName : String;
/**
* Constructeur de la classe
*
* @param serv Server instance du serveur
*/
constructor(serv : Server){
this.clients = mutableListOf();
this.messages = mutableMapOf();
this.serv = serv;
}
override fun filter(c: Client): Boolean {
/**
* Methode permettant de filtrer les évenements passés a la méthode ProcessEvent()
*
* @param c Client client a filtrer
*/
override fun filter(c: Client): Boolean{
//on compare l'addresse liée au client a l'adresse d'écoute du channel
val regex = "\\/$chanName\\/(.*)".toRegex()
val result = regex.findAll(c.URL);
if(result.count() == 1){
@ -32,40 +55,62 @@ abstract class AbstractChannel : AsynchronousListener {
return false;
}
/**
* Lorsqu'un client quitte le channel, on notifie la classe d'authentification et on retire le client de notre liste
*
* @param e Event évenement lancé par le serveur
*/
override fun processClosed(e: Event) {
this.clients.remove(e.client);
ConnectChannel.notifyDisconnect(e.client);
System.out.println("A client disconnected ("+this.clients.count()+" clients connected)");
}
/**
* Méthode executée lors de la première connexion du client
*/
override fun processConnection(c: Client) {
//on rajoute le client a notre liste
this.clients.add(c);
val regex = "\\/$chanName\\/(.*)".toRegex();
val result = regex.findAll(c.URL).elementAt(0).groups[1]?.value ?: "";
//create stack if not present
//si le sous-channel auquel le client esaie d'accéder n'existe pas, on le créé
if(this.messages[result] == null){
this.messages[result] = Stack( 50);
}
//bind client to channel
if(c.data["emergencyChannel"] == null){
c.data["emergencyChannel"] = result;
//on rajoute au client une donnée permettant de savoir a quel sous-channel il est lié
if(c.data["channel"] == null){
c.data["channel"] = result;
}
//le client est conecté mais pas logué, il devra envoyer un message spécial pour l'être
c.data["IsLogged"] = false;
}
fun manuallyDispatchMessage(channel : String, msg : Message, operation : String){
/**
* Méthode appelée par les classes Interop afin de dispatcher les mesages envoyé par l'API REST du site
*
* @param channel String nom du sous-channel auquel il faut dispatch, un nom vide signifie un broadcast a tout les sous channels
* @param msg Messag message a dispatcher
*/
fun manuallyDispatchMessage(channel : String, msg : Message){
//on récupère la stach du sous-channel
val channelStack = this.messages[channel];
//si il existe, on dispatch
if(channelStack != null){
//gare aux modifications concurrentes
synchronized(channelStack, {
channelStack.push(Pair(msg.user,msg));
})
this.dispatchMessage(channel,msg,operation);
//dispatch
this.dispatchMessage(channel,msg,"add");
//sinon si la chaine est vide on broadcast
}else if (channel == ""){
//broadcast
for(c in this.messages.values){
@ -74,42 +119,43 @@ abstract class AbstractChannel : AsynchronousListener {
})
}
this.dispatchMessage(channel,msg,operation);
//dispatch
this.dispatchMessage(channel,msg,"add");
}
}
/**
* Méthode principale du listener, elle prend en charge tout les messages de tout les clients
*/
override fun processEvent(e: Event) {
try{
val json = JSONObject(e.message.getString())
//dead code, should remove it later
if(json.has("close")){
return
}
//si l'utilisateur n'est pas log, on le check
if(e.client.data["IsLogged"] != true){
//json format : {username:xxx}
if(json.has("name") && json.getString("name") != null){
//on set le nom d'utilisateur
e.client.data["Username"] = json.getString("name");
//if the client correctly identified with the Interop server
//On vérifie qu'il est bien connecté a l'aide de la classe ConnectChannel
if(ConnectChannel.isConnected(e.client)){
//log
System.out.println("Emergency connection ("+this.clients.count()+" clients connected)");
//return OK to the client
//on retourne une réponse de succès au client
e.client.data["IsLogged"] = true;
val jsonLogin = JSONObject();
jsonLogin.put("error",false);
e.client.send(buildTextMessage(jsonLogin.toString()));
//give the client the list of the most recent messages
//on envoie au client la liste des messages récent
val array = JSONObject();
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
val chanMessages = this.messages[e.client.data["channel"]];
if(chanMessages != null){
//gare a la concurrence
synchronized(chanMessages,{
chanMessages.toList().forEach {
array.put(it.second.id,it.second.toJSON())
@ -117,11 +163,11 @@ abstract class AbstractChannel : AsynchronousListener {
})
}
//build JSON
//on construit le JSON
val jsonMessage = JSONObject();
jsonMessage.put("error",false);
jsonMessage.put("add",array);
//on envoie la sauce
e.client.send(buildTextMessage(jsonMessage.toString()));
}else{
val jsonError = JSONObject();
@ -131,27 +177,32 @@ abstract class AbstractChannel : AsynchronousListener {
}
}else{
//tried to access chat without logging in
//Tentative d'accès au chat sans loggin
val jsonError = JSONObject();
jsonError.put("error","You must send your credential before sending anything else");
e.client.send(buildTextMessage(jsonError.toString()));
}
return;
//si le client envoie un message sur le canal websocket (pas utilisé sur le site car tout passe par l'API REST et les Interops mais utilisable en serveur standalone
}else if(json.has("message")){
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
//on récupère le channel
val chanMessages = this.messages[e.client.data["channel"]];
val message = Message();
//toujours vrai mais il est important de faire la vérification pour l'analyseur de code kotlin
if(chanMessages != null){
//on peuple l'objet message
message.user = e.client.data["Username"].toString();
message.message = json.getString("message");
message.id = "-1";
//ligne pourrie, on ne peut pas donner d'id vu que c'est le serveur de l'API qui le fait, par défaut on utilise le timestamp (qui plus est un id est toujours une string
message.id = System.currentTimeMillis().toString();
//on check les coordonnés GPS
var lat : Float;
var lng : Float;
//javascript may send float as integer so we double check that
//étant doné que javascript fait un peu ce qu'il veut avec les nombres on peut recevoir des int ou des double, il faut tout cast en float
try {
lat = (json.getJSONArray("location")[0] as Double).toFloat();
}catch(e : Exception){
@ -166,20 +217,24 @@ abstract class AbstractChannel : AsynchronousListener {
message.location = mutableListOf(lat,lng);
//utilisé que par le channel Event si tout va bien
if(json.has("type")){
message.type = json.getInt("type");
}
//concurrence encore
synchronized(chanMessages,{
chanMessages.push(Pair(e.client.data["Username"].toString(),message))
});
}
var chanName = "";
if(e.client.data["emergencyChannel"] != null){
chanName = e.client.data["emergencyChannel"].toString();
//obligatoire pour l'analyseur de code kotlin
if(e.client.data["channel"] != null){
chanName = e.client.data["channel"].toString();
}
//dispatch.....SPATCH!!!!
for(c in this.clients){
this.dispatchMessage(chanName,message,"add");
}
@ -188,25 +243,35 @@ abstract class AbstractChannel : AsynchronousListener {
}
}catch (e : Exception){
//System.out.println("Something went wrong (probably JSON parsing error");
//utile pour debug
e.printStackTrace();
}
}
/**
* SPATCH!! methode envoyant aux bon clients les opérations demandées
* @param channel String sous-channel
* @param message Message message a dispatch
* @param operation String operation a effectuer (add, upd, del)
*/
fun dispatchMessage(channel: String, message: Message, operation : String){
//whitelist
val authorizedOperations = listOf<String>("add","upd","del");
//wow much security, very reliable, wow
if(!authorizedOperations.contains(operation)){
throw Exception("Unauthorized operation");
}
//on construit le JSON
val array = JSONObject();
array.put(message.id,message.toJSON())
val jsonMessage = JSONObject();
jsonMessage.put("error",false);
//all operations must be present but can be empty
//toutes les opréations doivent être présente mais peuvent être vide
for (op in authorizedOperations){
if(op == operation){
jsonMessage.put(op,array);
@ -215,40 +280,59 @@ abstract class AbstractChannel : AsynchronousListener {
}
}
//SPATCH!!
for(c in this.clients){
//dispatch message to logged client in the right channel or in any channel if channel is an empty string (broadcast)
if(c.data["IsLogged"] == true && ((channel != "" && c.data["emergencyChannel"] == channel) || channel == "")){
//on envoie a tout les clients loggés du bon channel, ou en broadcast si aucun channel n'est précisé
if(c.data["IsLogged"] == true && ((channel != "" && c.data["channel"] == channel) || channel == "")){
c.send(buildTextMessage(jsonMessage.toString()));
}
}
}
/**
* Methode utilisée par les classes Interop pour que l'API puisse agir sur les channels
* @param id String id du message a supprimer
*/
fun deleteMessage(id : String){
//comme tout les ids sont unique, on doit parcourir tout les channels a la recherche du message
this.messages.keys.forEach {
//comme j'utilise la version fonctionnelle des boucle, la variable it (qui contiens l'item) se reécrit dans la deuxieme boucle
val key = it;
val array = this.messages[it];
array?.toList()?.forEach{
if(it.second.id == id){
//on enleve de la stack
array.remove(it);
//on créer un message vide, seul l'id est utile
val msg = Message()
msg.id = id;
//on envoie au client
this.dispatchMessage(key,msg,"del");
//petite optimisation pour éviter de continuer a parcourir les channels
return;
}
}
}
}
/**
* Methode utilisée par les classes Interop pour que l'API puisse agir sur les channels
* @param msg Message message avec le contenu modifié
*/
fun updateMessage(msg : Message){
//comme pour le delete, on doit tout parcourir
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
var index = 0;
array?.toList()?.forEach{
if(it.second.id == msg.id){
//on peuple le nouveau message des anciennes valeurs
msg.user = it.second.user;
msg.location = it.second.location;
msg.timestamp = it.second.timestamp;
array.set(index,Pair(it.first,msg));
//on envoie
this.dispatchMessage(key,msg,"upd");
}
index++;
@ -256,6 +340,10 @@ abstract class AbstractChannel : AsynchronousListener {
}
}
/**
* Methode implémentée mais pas utilisée suite a une décision durant la nuit
* aucune idée de si ça marche du coup
*/
fun getMessages(chan : String) : MutableList<Pair<String, Message>>{
val channel = this.messages[chan]?.toList();
val returned = mutableListOf<Pair<String, Message>>()

View File

@ -2,6 +2,9 @@ package Channels
import seekdasky.kWebSocket.Server
/**
* Classe gérant le channel emergency
*/
class Emergency : AbstractChannel {
override val chanName = "emergency";

View File

@ -2,6 +2,9 @@ package Channels
import seekdasky.kWebSocket.Server
/**
* classe gérant le channel Event
*/
class Event : AbstractChannel {
override val chanName = "event";

View File

@ -3,6 +3,9 @@ package Collections
import org.json.JSONObject
import java.lang.System;
/**
* Modèle de donnée standard pour tout les messages de channel
*/
class Message {
var user = "";
@ -14,10 +17,13 @@ class Message {
var type = -1;
//par défaut la date de message est celle actuelle
constructor(){
//on converti le timestamp de milliseconde en seconde (UNIX timestamp)
this.timestamp = System.currentTimeMillis() / 1000;
}
//permet de facilement serialiser le message
fun toJSON() : JSONObject{
val json = JSONObject();
json.put("user",user);
@ -25,6 +31,7 @@ class Message {
json.put("timestamp",timestamp);
json.put("location",location);
//le type n'est pas présent sur tout les channels
if(this.type >= 0){
json.put("type",type);
}

View File

@ -1,25 +1,39 @@
package Collections
/**
* Stack FIFO codée pour m'adier a avoir un historique de conversation limité et facile a utiliser
* la classe est générique et réutilisable ailleur au besoin
*/
class Stack<T>(size : Int){
var itCounter = 0;
//taille max de la stack
val size = size;
//collection utilisée pour stocker les données
var items:MutableList<T> = mutableListOf()
//vérifie si la stack est vide
fun isEmpty():Boolean = this.items.isEmpty()
//retourne le nombre d'élément de la stack
fun count():Int = this.items.count()
override fun toString() = this.items.toString()
/**
* Rajoute un élément en haut de la stack
* @param element T item a ajouter
*/
fun push(element: T){
//BEWARE this stack is programmed to empty itself automatically if you push an item when the stack is full
//ATTENTION cette stack est faite pour évacuer les éléments les plus anciens toute seule en cas de saturation
if(this.items.count() == this.size ){
this.pull();
}
this.items.add(element)
}
/**
* retire un élément en pas de la stack
*/
fun pull():T?{
if (this.isEmpty()){
return null
@ -28,14 +42,22 @@ class Stack<T>(size : Int){
}
}
/**
* permet de mettre a jour des élements dans la stack
*/
fun set(index : Int, item : T){
this.items.set(index,item);
}
//enlève un élément de la stack
fun remove(item : T){
this.items.remove(item);
}
/**
* Plutot que d'implémenter l'interface Iterable moi même (risque de bug en cas d'itération concurrente), lorsque l'on a besoin d'itérer sur la stack
* on peut apppeller cette méthode et itérer sur la collection Kotlin qui est thread safe
*/
fun toList() : MutableList<T>{
return this.items.toMutableList();
}

View File

@ -9,13 +9,22 @@ import seekdasky.kWebSocket.Listeners.InteropListener
import seekdasky.kWebSocket.Message.InteropMessage
import seekdasky.kWebSocket.Message.buildTextMessage
/**
* Singleton permettant de gérer les conecion par Interop et par WebSocket, Singleton utilisé par les classes lsiteners pour vérifier l'identité des clients
*/
object ConnectChannel : InteropListener, AsynchronousListener() {
//utilisé pour que chaque gues ai un id unique (dans la limite de 500)
private var lastGuestIndex = 0;
//clints s'étant loggué mais ne s'étant pas encore connecté a un channel (si un client se loggue sans jamais se connecter a un socket il sera éjecté de la satck
private val notBoundYet = Stack<Pair<String, String>>(500);
//client connecté a un channel WebSocket
private val connected = mutableMapOf<Client, String>();
/**
* méthode de filtre pour le WebSOcket
*/
override fun filter(c: Client): Boolean {
return c.URL == "/connect";
}
@ -28,13 +37,20 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
return
}
/**
* méthode de login par WebSocket
*/
override fun processEvent(e: Event) {
try {
val json = JSONObject(e.message.toString());
//si l'utilisateur est un guest
if(json.getString("type") == "guest"){
//on lui donne un id unique (dans la limtite de 500)
this.lastGuestIndex = ++this.lastGuestIndex % 500;
val guestName = "Guest"+this.lastGuestIndex;
//on retourne au client son id de guest
val jsonReturn = JSONObject();
jsonReturn.put("error", false);
jsonReturn.put("name", guestName);
@ -44,6 +60,7 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
e.client.send(buildTextMessage(jsonReturn.toString()));
}else{
//on n'autorise pas la connection en tant qu'admin ou utilisateur (car aucun lien possible avec la base de donnée pour vérifier les tokens
val jsonReturn = JSONObject();
jsonReturn.put("error", "Admin or User login is disabled when using the websocket API, please use the REST API to access you account");
@ -56,6 +73,9 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
}
}
/**
* méthode de filtre pour le socket Interop
*/
override fun filter(e: InteropEvent): Boolean {
try{
val json = JSONObject(e.message.string);
@ -68,13 +88,18 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
}
}
/**
* méthode de loggin par Interop
*/
override fun processEvent(e: InteropEvent) {
try {
val json = JSONObject(e.message.string);
if(json.getString("type") == "guest"){
//Login de guest
this.lastGuestIndex = ++this.lastGuestIndex % 500;
val guestName = "Guest"+this.lastGuestIndex;
//on retourne l'id de l'utilisateur
val jsonReturn = JSONObject();
jsonReturn.put("error", false);
jsonReturn.put("name", guestName);
@ -84,6 +109,7 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
e.client.send(InteropMessage(encode(jsonReturn.toString())));
}else{
//la vérification de token étant faite par l'API REST, on peut logg les utilisateurs et admin
val jsonReturn = JSONObject();
jsonReturn.put("error", false);
jsonReturn.put("name", json.getString("name"));
@ -98,15 +124,21 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
}
}
/**
* méthode appelée par les Listeners Interop et WebSocket pour vérifier l'identitée d'un client
*/
fun isConnected(client : Client) : Boolean{
//est ce que l'utilisateur est deja log sur un autre channel
for(c in this.connected.keys){
if(c.data["Username"] == client.data["Username"]){
return true;
}
}
//est ce qu'il ne s'est pas encore log sur un channel
for(p in this.notBoundYet.toList()) {
if (p.second == client.data["Username"]) {
//on rajoute le client au clients utilisant un channel
this.connected.put(client, p.first);
this.notBoundYet.remove(p);
return true;
@ -116,6 +148,9 @@ object ConnectChannel : InteropListener, AsynchronousListener() {
return false;
}
/**
* lorsqu'un client se déconnecte, on remet son ID dans la catégorie des clients pas encore connecté afin de ne pas avoir a su re loguer a chaque changement de channel
*/
fun notifyDisconnect(client : Client){
val clientType = this.connected[client];
if(clientType != null){

View File

@ -6,9 +6,14 @@ import org.json.JSONObject
import seekdasky.kWebSocket.InteropEvent
import seekdasky.kWebSocket.Listeners.InteropListener
/**
* Classe Interop permettant de gérer toutes les suppréssions de message
*/
class DelMessage : InteropListener {
//channel emergency
val emergencyController : Emergency;
//channel event
val eventController : Event;
constructor(emergency : Emergency, event : Event){
@ -16,6 +21,9 @@ class DelMessage : InteropListener {
this.eventController = event;
}
/**
* Comme pour les Listeners WebSocket, cette méthode filtre les évenements entrant
*/
override fun filter(e: InteropEvent): Boolean {
val json = JSONObject(e.message.string);
@ -24,12 +32,15 @@ class DelMessage : InteropListener {
json.getString("operation") == "DelMessage";
}
/**
* méthode gérant la suppression de message
*/
override fun processEvent(e: InteropEvent) {
try {
val json = JSONObject(e.message.string);
//on dispatch au bon channel
if(json.getString("channelType") == "Emergency"){
this.emergencyController.deleteMessage(json.getString("id"));
}else if(json.getString("channelType") == "Event"){

View File

@ -7,16 +7,26 @@ import org.json.JSONObject
import seekdasky.kWebSocket.InteropEvent
import seekdasky.kWebSocket.Listeners.InteropListener
/**
* Classe Interop permettant de gérer tous les ajouts de message
*/
class PostMessage : InteropListener {
//channel emergency
val emergencyController : Emergency;
//channel event
val eventController : Event;
constructor(emergency : Emergency, event : Event){
this.emergencyController = emergency;
this.eventController = event;
}
/**
* cf: DelMessage
*/
override fun filter(e: InteropEvent): Boolean {
val json = JSONObject(e.message.string);
@ -25,12 +35,15 @@ class PostMessage : InteropListener {
json.getString("operation") == "PostMessage";
}
/**
* méthode traitant l'ajout de message
*/
override fun processEvent(e: InteropEvent) {
try {
val json = JSONObject(e.message.string);
//javascript may send float as integer so we double check that
//javascript fait un peu ce qu'il veut au niveau des nombres et peut envoyer des doubles ou des int, on doit tout cast en float
var lat : Float;
var lng : Float
try {
@ -47,26 +60,24 @@ class PostMessage : InteropListener {
val location = mutableListOf<Float>(lat, lng);
//on peuple le modèle
val message = Message();
message.location = location;
message.message = json.getString("message");
message.user = json.getString("username");
message.id = json.getString("id");
message.timestamp = System.currentTimeMillis() / 1000;
if(json.getString("channelType") == "Emergency"){
this.emergencyController.manuallyDispatchMessage(
json.getString("channelName"),
message,
"add"
message
);
}else if(json.getString("channelType") == "Event"){
message.type = json.getInt("type");
this.eventController.manuallyDispatchMessage(
json.getString("channelName"),
message,
"add"
message
);
}

View File

@ -7,6 +7,9 @@ import org.json.JSONObject
import seekdasky.kWebSocket.InteropEvent
import seekdasky.kWebSocket.Listeners.InteropListener
/**
* Classe Interop permettant de gérer toutes les mise a jour de message
*/
class UpdMessage : InteropListener {
val emergencyController : Emergency;

View File

@ -7,22 +7,32 @@ import seekdasky.kWebSocket.Server
fun main(args: Array<String>){
val server = Server("0.0.0.0",9999,null);
//on démarre le serveur WebSOcket
val server = Server("0.0.0.0",9999,null)
//on démarre le serveur Interop
server.startInteropServer("localhost",9998);
//channels WebSocket pilotés par Interop
val emergencyChannel = Emergency(server);
val eventChannel = Event(server);
//channel WebSocket
server.addListener(Channel(server,"/chat"));
//on bind les listeners
server.addListener(emergencyChannel);
server.addListener(eventChannel)
server.addListener(eventChannel);
//service de login par WebSocket
server.addListener(ConnectChannel);
//Listeners Interops
server.addInteropListener(PostMessage(emergencyChannel,eventChannel));
server.addInteropListener(DelMessage(emergencyChannel,eventChannel));
server.addInteropListener(UpdMessage(emergencyChannel,eventChannel));
//login Interop
server.addInteropListener(ConnectChannel);
//et c'est partiiiiiiii
server.startServer();
//méthode bloquant le thread principal tant que le serveur est en vie
server.block();
}