package com.hg.ecommerce.websocket.support;
import static com.hg.ecommerce.websocket.support.BasicType.*;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hg.ecommerce.config.ProjectContainer;
import com.hg.ecommerce.websocket.ConnectionHub;
import com.hg.ecommerce.websocket.exception.BadMessageException;
import com.hg.ecommerce.websocket.exception.NoGenericSuperInterfaceException;
/**
* 使用此类为不同的SocketEvent注册监听器,时间触发后,监听器会自动执行方法,完成用户所实现的业务逻辑
* @author Li He
* @see com.hg.ecommerce.websocket.support.SocketEvent
* @see com.hg.ecommerce.websocket.support.SocketEventListener
*/
@SuppressWarnings("rawtypes")
public class Socket {
/**
* all the socket event listeners bind to the specific event name
*/
private Map<String, List<SocketEventListener>> hub = new HashMap<String, List<SocketEventListener>>();
/**
* all the attributes for the socket
*/
private Map<String, String> attributes = new HashMap<String, String>();
/**
* core socket session
*/
private WebSocketSession session;
public Socket(WebSocketSession session) {
this.session = session;
}
/**
* bind a listener to a event here
* @param event event name
* @param listener listener class
* @return
*/
public Socket on(String event, SocketEventListener listener){
List<SocketEventListener> temp = getHub().get(event);
if(temp==null){
temp = new ArrayList<SocketEventListener>();
}
temp.add(listener);
getHub().put(event, temp);
return this;
}
/**
* Get all the listeners on the specific event
* @param event
* @return
*/
protected List<SocketEventListener> getListeners(String event){
return getHub().get(event);
}
/**
* 检测某一事件是否注册监听器
* @param event event name
* @return Boolean value
*/
protected boolean hasListeners(String event){
if(getListeners(event)==null||getListeners(event).size()==0){
return false;
}
return true;
}
/**
* 执行某一注册事件的全部监听器, 为同一事件注册多个监听器时,同一个事件的监听器消耗的消息必须为同一类型,否则后果无法预料
* @param event 事件名称
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
@SuppressWarnings("unchecked")
public <T> boolean performEvent(String name, String rawMessage) throws NoGenericSuperInterfaceException,BadMessageException{
if(hasListeners(name)){
List<SocketEventListener> listeners = getListeners(name);
for(SocketEventListener listener : listeners){
Class<T> cls = guessCls(listener);
//I will handle most basic type
try {
T message;
if(STRING.equals(cls.getName())){
message = (T)rawMessage;
}else{
message = ProjectContainer.getInstance(ObjectMapper.class).readValue(rawMessage, cls);
}
listener.actionPerformed(message);
} catch (IOException e) {
throw new BadMessageException("Bad Message, Cannot read Instance of Class:"+cls.getName()+" from the given raw message", e);
}
}
return true;
}
return false;
}
@SuppressWarnings("unchecked")
public <T> Class<T> guessCls(SocketEventListener<T> listener) throws NoGenericSuperInterfaceException{
Type type = listener.getClass().getGenericInterfaces()[0];
if(type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType)type;
return (Class<T>)parameterizedType.getActualTypeArguments()[0];
}else{
//父接口没有使用任何的泛型,默认使用Object.class
throw new NoGenericSuperInterfaceException("The anonymous SocketEventListener is not derived from an interface with the specified Generic Type");
}
}
/**
* Get Session Id
* @return
*/
public String getSessionId(){
return session.getId();
}
/**
* socket is active or not?
* @return boolean value
*/
public boolean isActive(){
return session.isOpen();
}
/**
* close the under session
* @throws IOException exception
*/
public void close() throws IOException{
session.close();
}
/**
* close the under session
* @throws IOException exception
*/
public void close(CloseStatus status) throws IOException{
session.close(status);
}
/**
* 触发前端事件,以对象形式触发
* @param event
* @param message
* @return for chain invocation
* @throws IOException send message exception
*/
public Socket emit(String event, Object message) {
ObjectMapper mapper = ProjectContainer.getInstance(ObjectMapper.class);
SocketMessage socketMessage = new SocketMessage();
socketMessage.setEventName(event);
try {
socketMessage.setPayload(mapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
//this actually should never happen
e.printStackTrace();
}
try {
TextMessage textMessage = new TextMessage(mapper.writeValueAsString(socketMessage));
session.sendMessage(textMessage);
} catch (JsonProcessingException e) {
//this actually should never happen
e.printStackTrace();
} catch (IOException e) {
//this actually should never happen
e.printStackTrace();
}
return this;
}
/**
* 广播事件与消息,消息接受者为除了自己以外的全部在线用户
* @param event event name
* @param message message object
* @return chain invocation
*/
public Socket broadcast(String event, Object message){
for(Socket socket : ConnectionHub.getOtherSockets(getSessionId())){
socket.emit(event, message);
}
return this;
}
/**
* Get Hub Object
* @return Map
*/
public Map<String, List<SocketEventListener>> getHub() {
return hub;
}
public Socket setAttribute(String name, String value){
attributes.put(name, value);
return this;
}
public String getAttribute(String name){
return attributes.get(name);
}
}