refactoring des chanels : classe parente abstraite

This commit is contained in:
SeekDaSky 2017-12-08 02:38:07 +01:00
parent c0d3d1d1a5
commit ecaed684fc
3 changed files with 277 additions and 516 deletions

View File

@ -0,0 +1,271 @@
package Channels
import Collections.Message
import Collections.Stack
import org.json.JSONArray
import org.json.JSONObject
import seekdasky.kWebSocket.Client
import seekdasky.kWebSocket.Event
import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Message.buildTextMessage
import seekdasky.kWebSocket.Server
abstract class AbstractChannel : AsynchronousListener {
var clients : MutableList<Client>;
val messages : MutableMap<String, Stack<Pair<String, Message>>>;
val serv : Server;
abstract val chanName : String;
constructor(serv : Server){
this.clients = mutableListOf();
this.messages = mutableMapOf();
this.serv = serv;
}
override fun filter(c: Client): Boolean {
val regex = "\\/$chanName\\/(.*)".toRegex()
val result = regex.findAll(c.URL);
if(result.count() == 1){
return true;
}
return false;
}
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)");
}
override fun processConnection(c: Client) {
this.clients.add(c);
val regex = "\\/$chanName\\/(.*)".toRegex();
val result = regex.findAll(c.URL).elementAt(0).groups[1]?.value ?: "";
//create stack if not present
if(this.messages[result] == null){
this.messages[result] = Stack( 50);
}
//bind client to channel
if(c.data["emergencyChannel"] == null){
c.data["emergencyChannel"] = result;
}
c.data["IsLogged"] = false;
}
fun manuallyDispatchMessage(channel : String, msg : Message, operation : String){
val channelStack = this.messages[channel];
if(channelStack != null){
synchronized(channelStack, {
channelStack.push(Pair(msg.user,msg));
})
this.dispatchMessage(channel,msg,operation);
}else if (channel == ""){
//broadcast
for(c in this.messages.values){
synchronized(c,{
c.push(Pair(msg.user,msg));
})
}
this.dispatchMessage(channel,msg,operation);
}
}
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){
e.client.data["Username"] = json.getString("name");
//if the client correctly identified with the Interop server
if(ConnectChannel.isConnected(e.client)){
//log
System.out.println("Emergency connection ("+this.clients.count()+" clients connected)");
//return OK to the 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
val array = JSONObject();
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
if(chanMessages != null){
synchronized(chanMessages,{
chanMessages.toList().forEach {
array.put(it.second.id,it.second.toJSON())
}
})
}
//build JSON
val jsonMessage = JSONObject();
jsonMessage.put("error",false);
jsonMessage.put("add",array);
e.client.send(buildTextMessage(jsonMessage.toString()));
}else{
val jsonError = JSONObject();
jsonError.put("error","Invalid credentials");
e.client.send(buildTextMessage(jsonError.toString()));
}
}else{
//tried to access chat without logging in
val jsonError = JSONObject();
jsonError.put("error","You must send your credential before sending anything else");
e.client.send(buildTextMessage(jsonError.toString()));
}
return;
}else if(json.has("message")){
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
val message = Message();
if(chanMessages != null){
message.user = e.client.data["Username"].toString();
message.message = json.getString("message");
message.id = "-1";
var lat : Float;
var lng : Float;
//javascript may send float as integer so we double check that
try {
lat = (json.getJSONArray("location")[0] as Double).toFloat();
}catch(e : Exception){
lat = (json.getJSONArray("location")[0] as Integer).toFloat();
}
try {
lng = (json.getJSONArray("location")[1] as Double).toFloat();
}catch(e : Exception){
lng = (json.getJSONArray("location")[1] as Integer).toFloat();
}
message.location = mutableListOf(lat,lng);
if(json.has("type")){
message.type = json.getInt("type");
}
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();
}
for(c in this.clients){
this.dispatchMessage(chanName,message,"add");
}
}else{
System.out.println("unknown JSON: "+json.toString());
}
}catch (e : Exception){
//System.out.println("Something went wrong (probably JSON parsing error");
e.printStackTrace();
}
}
fun dispatchMessage(channel: String, message: Message, operation : String){
val authorizedOperations = listOf<String>("add","upd","del");
if(!authorizedOperations.contains(operation)){
throw Exception("Unauthorized operation");
}
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
for (op in authorizedOperations){
if(op == operation){
jsonMessage.put(op,array);
}else{
jsonMessage.put(op, JSONArray());
}
}
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 == "")){
c.send(buildTextMessage(jsonMessage.toString()));
}
}
}
fun deleteMessage(id : String){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
array?.toList()?.forEach{
if(it.second.id == id){
array.remove(it);
val msg = Message()
msg.id = id;
this.dispatchMessage(key,msg,"del");
}
}
}
}
fun updateMessage(msg : Message){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
var index = 0;
array?.toList()?.forEach{
if(it.second.id == msg.id){
msg.user = it.second.user;
msg.location = it.second.location;
msg.timestamp = it.second.timestamp;
array.set(index,Pair(it.first,msg));
this.dispatchMessage(key,msg,"upd");
}
index++;
}
}
}
fun getMessages(chan : String) : MutableList<Pair<String, Message>>{
val channel = this.messages[chan]?.toList();
val returned = mutableListOf<Pair<String, Message>>()
if(channel != null){
for (m in channel){
returned.add(Pair(m.second.id,m.second));
}
}
return returned;
}
}

View File

@ -1,265 +1,10 @@
package Channels
import Collections.Message
import Collections.Stack
import org.json.JSONArray
import org.json.JSONObject
import seekdasky.kWebSocket.Client
import seekdasky.kWebSocket.Event
import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Message.buildTextMessage
import seekdasky.kWebSocket.Server
class Emergency : AsynchronousListener {
class Emergency : AbstractChannel {
var clients : MutableList<Client>;
val messages : MutableMap<String,Stack<Pair<String,Message>>>;
val serv : Server;
override val chanName = "emergency";
constructor(serv : Server){
this.clients = mutableListOf();
this.messages = mutableMapOf();
this.serv = serv;
}
override fun filter(c: Client): Boolean {
val regex = "\\/emergency\\/(.*)".toRegex()
val result = regex.findAll(c.URL);
if(result.count() == 1){
return true;
}
return false;
}
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)");
}
override fun processConnection(c: Client) {
this.clients.add(c);
val regex = "\\/emergency\\/(.*)".toRegex();
val result = regex.findAll(c.URL).elementAt(0).groups[1]?.value ?: "";
//create stack if not present
if(this.messages[result] == null){
this.messages[result] = Stack( 50);
}
//bind client to channel
if(c.data["emergencyChannel"] == null){
c.data["emergencyChannel"] = result;
}
c.data["IsLogged"] = false;
}
fun manuallyDispatchMessage(channel : String, msg : Message, operation : String){
val channelStack = this.messages[channel];
if(channelStack != null){
synchronized(channelStack, {
channelStack.push(Pair(msg.user,msg));
})
this.dispatchMessage(channel,msg,operation);
}else if (channel == ""){
//broadcast
for(c in this.messages.values){
synchronized(c,{
c.push(Pair(msg.user,msg));
})
}
this.dispatchMessage(channel,msg,operation);
}
}
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){
e.client.data["Username"] = json.getString("name");
//if the client correctly identified with the Interop server
if(ConnectChannel.isConnected(e.client)){
//log
System.out.println("Emergency connection ("+this.clients.count()+" clients connected)");
//return OK to the 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
val array = JSONObject();
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
if(chanMessages != null){
synchronized(chanMessages,{
chanMessages.toList().forEach {
array.put(it.second.id,it.second.toJSON())
}
})
}
//build JSON
val jsonMessage = JSONObject();
jsonMessage.put("error",false);
jsonMessage.put("add",array);
e.client.send(buildTextMessage(jsonMessage.toString()));
}else{
val jsonError = JSONObject();
jsonError.put("error","Invalid credentials");
e.client.send(buildTextMessage(jsonError.toString()));
}
}else{
//tried to access chat without logging in
val jsonError = JSONObject();
jsonError.put("error","You must send your credential before sending anything else");
e.client.send(buildTextMessage(jsonError.toString()));
}
return;
}else if(json.has("message")){
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
val message = Message();
if(chanMessages != null){
message.user = e.client.data["Username"].toString();
message.message = json.getString("message");
message.id = "-1";
var lat : Float;
var lng : Float;
//javascript may send float as integer so we double check that
try {
lat = (json.getJSONArray("location")[0] as Double).toFloat();
}catch(e : Exception){
lat = (json.getJSONArray("location")[0] as Integer).toFloat();
}
try {
lng = (json.getJSONArray("location")[1] as Double).toFloat();
}catch(e : Exception){
lng = (json.getJSONArray("location")[1] as Integer).toFloat();
}
message.location = mutableListOf(lat,lng);
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();
}
for(c in this.clients){
this.dispatchMessage(chanName,message,"add");
}
}else{
System.out.println("unknown JSON: "+json.toString());
}
}catch (e : Exception){
//System.out.println("Something went wrong (probably JSON parsing error");
e.printStackTrace();
}
}
fun dispatchMessage(channel: String,message: Message, operation : String){
val authorizedOperations = listOf<String>("add","upd","del");
if(!authorizedOperations.contains(operation)){
throw Exception("Unauthorized operation");
}
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
for (op in authorizedOperations){
if(op == operation){
jsonMessage.put(op,array);
}else{
jsonMessage.put(op,JSONArray());
}
}
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 == "")){
c.send(buildTextMessage(jsonMessage.toString()));
}
}
}
fun deleteMessage(id : String){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
array?.toList()?.forEach{
if(it.second.id == id){
array.remove(it);
val msg = Message()
msg.id = id;
this.dispatchMessage(key,msg,"del");
}
}
}
}
fun updateMessage(msg : Message){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
var index = 0;
array?.toList()?.forEach{
if(it.second.id == msg.id){
msg.user = it.second.user;
msg.location = it.second.location;
msg.timestamp = it.second.timestamp;
array.set(index,Pair(it.first,msg));
this.dispatchMessage(key,msg,"upd");
}
index++;
}
}
}
fun getMessages(chan : String) : MutableList<Pair<String,Message>>{
val channel = this.messages[chan]?.toList();
val returned = mutableListOf<Pair<String,Message>>()
if(channel != null){
for (m in channel){
returned.add(Pair(m.second.id,m.second));
}
}
return returned;
}
constructor(server: Server) : super(server);
}

View File

@ -1,266 +1,11 @@
package Channels
import Collections.Message
import Collections.Stack
import org.json.JSONArray
import org.json.JSONObject
import seekdasky.kWebSocket.Client
import seekdasky.kWebSocket.Event
import seekdasky.kWebSocket.Listeners.AsynchronousListener
import seekdasky.kWebSocket.Message.buildTextMessage
import seekdasky.kWebSocket.Server
class Event : AsynchronousListener {
class Event : AbstractChannel {
var clients : MutableList<Client>;
val messages : MutableMap<String, Stack<Pair<String, Message>>>;
val serv : Server;
override val chanName = "event";
constructor(serv : Server){
this.clients = mutableListOf();
this.messages = mutableMapOf();
this.serv = serv;
}
override fun filter(c: Client): Boolean {
val regex = "\\/event\\/(.*)".toRegex()
val result = regex.findAll(c.URL);
if(result.count() == 1){
return true;
}
return false;
}
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)");
}
override fun processConnection(c: Client) {
this.clients.add(c);
val regex = "\\/event\\/(.*)".toRegex();
val result = regex.findAll(c.URL).elementAt(0).groups[1]?.value ?: "";
//create stack if not present
if(this.messages[result] == null){
this.messages[result] = Stack( 50);
}
//bind client to channel
if(c.data["emergencyChannel"] == null){
c.data["emergencyChannel"] = result;
}
c.data["IsLogged"] = false;
}
fun manuallyDispatchMessage(channel : String, msg : Message, operation : String){
val channelStack = this.messages[channel];
if(channelStack != null){
synchronized(channelStack, {
channelStack.push(Pair(msg.user,msg));
})
this.dispatchMessage(channel,msg,operation);
}else if (channel == ""){
//broadcast
for(c in this.messages.values){
synchronized(c,{
c.push(Pair(msg.user,msg));
})
}
this.dispatchMessage(channel,msg,operation);
constructor(server: Server) : super(server);
}
}
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){
e.client.data["Username"] = json.getString("name");
//if the client correctly identified with the Interop server
if(ConnectChannel.isConnected(e.client)){
//log
System.out.println("Emergency connection ("+this.clients.count()+" clients connected)");
//return OK to the 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
val array = JSONObject();
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
if(chanMessages != null){
synchronized(chanMessages,{
chanMessages.toList().forEach {
array.put(it.second.id,it.second.toJSON())
}
})
}
//build JSON
val jsonMessage = JSONObject();
jsonMessage.put("error",false);
jsonMessage.put("add",array);
e.client.send(buildTextMessage(jsonMessage.toString()));
}else{
val jsonError = JSONObject();
jsonError.put("error","Invalid credentials");
e.client.send(buildTextMessage(jsonError.toString()));
}
}else{
//tried to access chat without logging in
val jsonError = JSONObject();
jsonError.put("error","You must send your credential before sending anything else");
e.client.send(buildTextMessage(jsonError.toString()));
}
return;
}else if(json.has("message")){
val chanMessages = this.messages[e.client.data["emergencyChannel"]];
val message = Message();
if(chanMessages != null){
message.user = e.client.data["Username"].toString();
message.message = json.getString("message");
message.id = "-1";
message.type = json.getInt("type");
var lat : Float;
var lng : Float;
//javascript may send float as integer so we double check that
try {
lat = (json.getJSONArray("location")[0] as Double).toFloat();
}catch(e : Exception){
lat = (json.getJSONArray("location")[0] as Integer).toFloat();
}
try {
lng = (json.getJSONArray("location")[1] as Double).toFloat();
}catch(e : Exception){
lng = (json.getJSONArray("location")[1] as Integer).toFloat();
}
message.location = mutableListOf(lat,lng);
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();
}
for(c in this.clients){
this.dispatchMessage(chanName,message,"add");
}
}else{
System.out.println("unknown JSON: "+json.toString());
}
}catch (e : Exception){
//System.out.println("Something went wrong (probably JSON parsing error");
e.printStackTrace();
}
}
fun dispatchMessage(channel: String, message: Message, operation : String){
val authorizedOperations = listOf<String>("add","upd","del");
if(!authorizedOperations.contains(operation)){
throw Exception("Unauthorized operation");
}
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
for (op in authorizedOperations){
if(op == operation){
jsonMessage.put(op,array);
}else{
jsonMessage.put(op, JSONArray());
}
}
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 == "")){
c.send(buildTextMessage(jsonMessage.toString()));
}
}
}
fun deleteMessage(id : String){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
array?.toList()?.forEach{
if(it.second.id == id){
array.remove(it);
val msg = Message()
msg.id = id;
this.dispatchMessage(key,msg,"del");
}
}
}
}
fun updateMessage(msg : Message){
this.messages.keys.forEach {
val key = it;
val array = this.messages[it];
var index = 0;
array?.toList()?.forEach{
if(it.second.id == msg.id){
msg.user = it.second.user;
msg.location = it.second.location;
msg.timestamp = it.second.timestamp;
array.set(index,Pair(it.first,msg));
this.dispatchMessage(key,msg,"upd");
}
index++;
}
}
}
fun getMessages(chan : String) : MutableList<Pair<String,Message>>{
val channel = this.messages[chan]?.toList();
val returned = mutableListOf<Pair<String,Message>>()
if(channel != null){
for (m in channel){
returned.add(Pair(m.second.id,m.second));
}
}
return returned;
}
}