package
trmpj.ws;
import
java.util.concurrent.ConcurrentHashMap;
import
javax.websocket.CloseReason;
import
javax.websocket.OnClose;
import
javax.websocket.OnMessage;
import
javax.websocket.OnOpen;
import
javax.websocket.Session;
import
javax.websocket.server.PathParam;
import
javax.websocket.server.ServerEndpoint;
import
trmpj.TPair;
import
trmpj.TReq;
import
trmpj.TSession;
import
trmpj.TWs;
import
trmpj.req.TReqEnd;
import
trmpj.req.TReqGame;
import
trmpj.req.TReqPrepared;
import
trmpj.res.TResEnded;
import
trmpj.res.TResError;
import
trmpj.res.TResGame;
import
trmpj.res.TResInvalid;
import
trmpj.res.TResNone;
import
trmpj.res.TResStart;
import
trmpj.res.TResWait;
/**
* 対戦用処理
*
*/
@ServerEndpoint
(value =
"/ws/round/{pairId}"
)
public
class
TWsRound
extends
TWs {
/**
* pairId => TPairのマップ
*/
private
static
ConcurrentHashMap<String, TPair> pairs =
new
ConcurrentHashMap<String, TPair>();
/**
* pairId => Threadのマップ
*/
private
static
ConcurrentHashMap<String, Thread> threads =
new
ConcurrentHashMap<String, Thread>();
/**
* openハンドラ
* @param pairId
* @param session
*/
@OnOpen
public
void
onOpen(
@PathParam
(
"pairId"
) String pairId, Session session) {
String accessdId = generateAccessId();
session.getUserProperties().put(KEY_ACCESS_ID, accessdId);
TSession ts =
new
TSession(session);
sessions.putIfAbsent(accessdId, ts);
}
/**
* messageハンドラ
* @param pairId
* @param session
* @param message
*/
@OnMessage
public
void
onMessage(
@PathParam
(
"pairId"
) String pairId, Session session, String message) {
String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
TSession ts =
null
;
try
{
if
(!sessions.containsKey(accessdId)) {
throw
new
Exception();
}
ts = sessions.get(accessdId);
TReq req = ts.receiveMessage(message, TReq.
class
);
if
(req ==
null
) {
throw
new
Exception();
}
if
(!pairs.containsKey(pairId)) {
pairs.putIfAbsent(pairId,
new
TPair(pairId));
}
TPair pair = pairs.get(pairId);
synchronized
(pair) {
if
(req.command.equals(TReq.COMMAND_PREPARED)) {
TReqPrepared reqPrepared = ts.receiveMessage(message, TReqPrepared.
class
);
if
(reqPrepared ==
null
) {
throw
new
Exception();
}
if
(pair.isPrepared()) {
throw
new
Exception();
}
ts.setUser(reqPrepared.user);
pair.addTSession(ts);
if
(pair.isDuplicated()) {
throw
new
Exception();
}
if
(pair.isPrepared()) {
threads.remove(pairId);
TResStart resStart =
new
TResStart();
resStart.users.addAll(pair.getUsers());
pair.sendMessage(resStart);
return
;
}
TResWait resWait =
new
TResWait();
ts.sendMessage(resWait);
if
(!threads.containsKey(pairId)) {
threads.putIfAbsent(pairId,
new
Thread(
new
TRunnable(pairId)));
threads.get(pair).start();
}
return
;
}
else
if
(req.command.equals(TReq.COMMAND_GAME)) {
TReqGame reqGame = ts.receiveMessage(message, TReqGame.
class
);
if
(reqGame ==
null
) {
throw
new
Exception();
}
if
(pair.isDuplicated()) {
throw
new
Exception();
}
if
(!pair.isPrepared() || pair.isEnded()) {
throw
new
Exception();
}
TResGame resGame =
new
TResGame();
resGame.useId = ts.getUser().userId;
resGame.data = reqGame.data;
pair.sendMessage(resGame);
return
;
}
else
if
(req.command.equals(TReq.COMMAND_END)) {
TReqEnd reqEnd = ts.receiveMessage(message, TReqEnd.
class
);
if
(reqEnd ==
null
) {
throw
new
Exception();
}
if
(pair.isDuplicated()) {
throw
new
Exception();
}
pair.setEnded(
true
);
TResEnded resEnded =
new
TResEnded();
ts.sendMessage(resEnded);
return
;
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
if
(ts !=
null
) {
TResError resError =
new
TResError();
ts.sendMessage(resError);
}
}
/**
* closeハンドラ
* @param pairId
* @param session
* @param reason
*/
@OnClose
public
void
onClose(
@PathParam
(
"pairId"
) String pairId, Session session, CloseReason reason) {
String accessdId = (String) session.getUserProperties().get(KEY_ACCESS_ID);
TSession ts =
null
;
try
{
if
(!sessions.containsKey(accessdId)) {
throw
new
Exception();
}
ts = sessions.get(accessdId);
if
(!pairs.containsKey(pairId)) {
throw
new
Exception();
}
TPair pair = pairs.get(pairId);
synchronized
(pair) {
pair.removeTSession(ts);
if
(pair.isEmpty()) {
pairs.remove(pairId);
return
;
}
if
(pair.isPrepared() && !pair.isEnded()) {
TResNone resNone =
new
TResNone();
pair.sendMessage(resNone);
return
;
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
sessions.remove(accessdId);
}
/**
* 2人が揃うまで待つ別スレッド
* @author furuta
*
*/
public
class
TRunnable
implements
Runnable {
/**
* ペアID
*/
private
String pairId;
/**
* コンストラクタ
* @param pairId
*/
public
TRunnable(String pairId) {
this
.pairId = pairId;
}
/**
* 処理
*/
public
void
run() {
try
{
Thread.sleep(
10000
);
if
(!pairs.containsKey(pairId)) {
throw
new
Exception();
}
TPair pair = pairs.get(pairId);
synchronized
(pair) {
if
(!pair.isPrepared()) {
TResInvalid resInvalid =
new
TResInvalid();
pair.sendMessage(resInvalid);
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
threads.remove(pairId);
}
}
}