VHomeUI: start/stop button appear only when server port is set up in config

Server: a dedicated packet for greeting
ClientStates may throw exceptions when malformed packets come.
If clientStates chain leaves a packet unhandled, then it will be handled in NetClient
This commit is contained in:
Maxmtg
2013-04-21 14:53:32 +00:00
parent 55674b2f85
commit 6cf5f19ec5
16 changed files with 140 additions and 46 deletions

5
.gitattributes vendored
View File

@@ -14316,6 +14316,7 @@ src/main/java/forge/net/IClientSocket.java -text
src/main/java/forge/net/IConnectionObserver.java -text
src/main/java/forge/net/NetServer.java -text
src/main/java/forge/net/client/INetClient.java -text
src/main/java/forge/net/client/InvalidFieldInPacketException.java -text
src/main/java/forge/net/client/NetClient.java -text
src/main/java/forge/net/client/package-info.java -text
src/main/java/forge/net/client/state/ConnectedClientState.java -text
@@ -14331,8 +14332,10 @@ src/main/java/forge/net/protocol/toclient/AuthResultPacketClt.java -text
src/main/java/forge/net/protocol/toclient/ChatPacketClt.java -text
src/main/java/forge/net/protocol/toclient/EchoPacketClt.java -text
src/main/java/forge/net/protocol/toclient/ErrorIncorrectPacketClt.java -text
src/main/java/forge/net/protocol/toclient/ErrorUnknownPacketClt.java -text
src/main/java/forge/net/protocol/toclient/ErrorNoStateForPacketClt.java -text
src/main/java/forge/net/protocol/toclient/IPacketClt.java -text
src/main/java/forge/net/protocol/toclient/WelcomePacketClt.java -text
src/main/java/forge/net/protocol/toclient/package-info.java -text
src/main/java/forge/net/protocol/toserver/AuthorizePacketSrv.java -text
src/main/java/forge/net/protocol/toserver/ChatPacketSrv.java -text
src/main/java/forge/net/protocol/toserver/EchoPacketSrv.java -text

View File

@@ -322,7 +322,7 @@ public enum FControl {
* TODO: Write javadoc for this method.
* @return
*/
private final NetServer server = new NetServer(81);
private final NetServer server = new NetServer();
public NetServer getServer() {
// TODO Auto-generated method stub
return server;

View File

@@ -1,5 +1,7 @@
package forge.gui.home;
import org.apache.commons.lang.StringUtils;
import forge.Command;
import forge.Singletons;
import forge.control.FControl;
@@ -11,6 +13,7 @@ import forge.gui.framework.ICDoc;
import forge.gui.home.sanctioned.VSubmenuConstructed;
import forge.net.NetServer;
import forge.properties.ForgePreferences;
import forge.properties.NewConstants;
import forge.properties.ForgePreferences.FPref;
/**
@@ -81,8 +84,8 @@ public enum CHomeUI implements ICDoc {
@Override
public void run() {
NetServer srv = FControl.SINGLETON_INSTANCE.getServer();
srv.listen();
srv.listen(NewConstants.SERVER_PORT_NUMBER);
VHomeUI.SINGLETON_INSTANCE.getLblStopServer().setEnabled(true);
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setEnabled(false);

View File

@@ -59,6 +59,7 @@ import forge.gui.home.variant.VSubmenuPlanechase;
import forge.gui.home.variant.VSubmenuVanguard;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
import forge.properties.NewConstants;
import forge.properties.ForgePreferences.FPref;
import forge.view.FView;
@@ -158,7 +159,7 @@ public enum VHomeUI implements IVTopLevelUI {
pnlButtons.add(lblExit, "w 110px!, h 30px!, gap 0 10px 0 0");
pnlButtons.add(lblEditor, "w 110px!, h 30px!, sx 2");
if ( Singletons.getModel().getPreferences().getPrefBoolean(FPref.DEV_MODE_ENABLED) ) {
if ( NewConstants.SERVER_PORT_NUMBER >= 80 ) {
pnlButtons.add(lblStartServer, "w 170px!, h 25px!, gap 0 10px 10px 0, sx 2 ");
pnlButtons.add(lblStopServer, "w 50px!, h 25px!, gap 0 0 10px 0");
lblStopServer.setEnabled(false);

View File

@@ -28,16 +28,15 @@ public class NetServer {
private final Server srv = new Server();
private final Set<ClientSocket> _openSockets = new CopyOnWriteArraySet<ClientSocket>();
public final int portNumber;
public int portNumber;
public final int getPortNumber() {
return portNumber;
}
public NetServer(int port) {
portNumber = port;
public NetServer() {
SelectChannelConnector connector= new SelectChannelConnector();
connector.setPort(portNumber);
connector.setMaxIdleTime(1200000); // 20 minutes
srv.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
@@ -81,7 +80,6 @@ public class NetServer {
@Override
public void onMessage(String data) {
System.out.println("Received: " + data);
_client.onMessage(data);
}
@@ -92,9 +90,8 @@ public class NetServer {
@Override
public void onOpen(Connection connection) {
_connection = connection;
_client = new NetClient(this);
_openSockets.add(this);
send("CardForge server welcomes you.");
_client = new NetClient(this);
}
@Override
@@ -103,14 +100,16 @@ public class NetServer {
}
}
public void listen() {
public void listen(int port) {
if (!srv.isStarted())
{
portNumber = port;
URI serverUri = null;
try {
srv.start();
Connector connector = srv.getConnectors()[0];
int port = connector.getLocalPort();
connector.setPort(portNumber);
srv.start();
String host = connector.getHost();
serverUri = new URI(String.format("ws://%s:%d/", host == null ? "localhost" : host ,port));
} catch (Exception e) {
@@ -127,6 +126,7 @@ public class NetServer {
public void stop() {
try {
srv.stop();
portNumber = -1;
} catch (Exception e) {
BugReporter.reportException(e);
}

View File

@@ -0,0 +1,29 @@
package forge.net.client;
/**
* Indicates incorrect field in an incoming packet
*/
public class InvalidFieldInPacketException extends RuntimeException {
private static final long serialVersionUID = 4505312413627923468L;
/**
* TODO: Write javadoc for Constructor.
* @param message
*/
public InvalidFieldInPacketException(String message) {
super(message);
}
/**
* TODO: Write javadoc for Constructor.
* @param message
* @param cause
*/
public InvalidFieldInPacketException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -12,7 +12,10 @@ import forge.net.client.state.UnauthorizedClientState;
import forge.net.client.state.IClientState;
import forge.net.protocol.ClientProtocol;
import forge.net.protocol.ClientProtocolJson;
import forge.net.protocol.toclient.ErrorIncorrectPacketClt;
import forge.net.protocol.toclient.ErrorNoStateForPacketClt;
import forge.net.protocol.toclient.IPacketClt;
import forge.net.protocol.toclient.WelcomePacketClt;
import forge.net.protocol.toserver.IPacketSrv;
public class NetClient implements IConnectionObserver, INetClient{
@@ -28,6 +31,7 @@ public class NetClient implements IConnectionObserver, INetClient{
state.push(new ConnectedClientState(this));
state.push(new UnauthorizedClientState(this));
protocol = new ClientProtocolJson();
send(new WelcomePacketClt("Welcome to server"));
}
public void autorized() {
@@ -53,9 +57,15 @@ public class NetClient implements IConnectionObserver, INetClient{
@Override
public void onMessage(String data) {
IPacketSrv p = protocol.decodePacket(data);
for(IClientState s : state) {
if ( s.processPacket(p) )
break;
boolean processed = false;
try{
for(IClientState s : state) {
if ( s.processPacket(p) ) { processed = true; break; }
}
if (!processed)
send(new ErrorNoStateForPacketClt(p.getClass().getSimpleName()));
} catch ( InvalidFieldInPacketException ex ) {
send(new ErrorIncorrectPacketClt(ex.getMessage()));
}
}

View File

@@ -3,7 +3,6 @@ package forge.net.client.state;
import forge.net.client.INetClient;
import forge.net.protocol.toclient.EchoPacketClt;
import forge.net.protocol.toclient.ErrorIncorrectPacketClt;
import forge.net.protocol.toclient.ErrorUnknownPacketClt;
import forge.net.protocol.toserver.EchoPacketSrv;
import forge.net.protocol.toserver.IPacketSrv;
import forge.net.protocol.toserver.IncorrectPacketSrv;
@@ -28,9 +27,7 @@ public class ConnectedClientState implements IClientState {
client.send(new ErrorIncorrectPacketClt(((IncorrectPacketSrv)packet).getMessage()));
return true;
}
client.send(new ErrorUnknownPacketClt());
return true;
return false;
}
}

View File

@@ -1,6 +1,9 @@
package forge.net.client.state;
import org.apache.commons.lang3.StringUtils;
import forge.net.client.INetClient;
import forge.net.client.InvalidFieldInPacketException;
import forge.net.protocol.toclient.AuthResultPacketClt;
import forge.net.protocol.toserver.AuthorizePacketSrv;
import forge.net.protocol.toserver.IPacketSrv;
@@ -25,14 +28,18 @@ public class UnauthorizedClientState implements IClientState {
public boolean processPacket(IPacketSrv packet) {
if( packet instanceof AuthorizePacketSrv ) {
AuthorizePacketSrv p = (AuthorizePacketSrv)packet;
if( true ) { // check credentials here!
client.send(new AuthResultPacketClt(p.getUsername(), true));
client.createPlayer(p.getUsername());
client.replaceState(this, new InLobbyClientState(client));
return true;
}
if( StringUtils.isBlank(p.getUsername()))
throw new InvalidFieldInPacketException("username is blank");
// check credentials here!
client.createPlayer(p.getUsername());
client.send(new AuthResultPacketClt(client.getPlayer().getName(), true));
client.replaceState(this, new InLobbyClientState(client));
return true;
}
return false;

View File

@@ -11,8 +11,9 @@ import forge.net.protocol.toclient.AuthResultPacketClt;
import forge.net.protocol.toclient.ChatPacketClt;
import forge.net.protocol.toclient.EchoPacketClt;
import forge.net.protocol.toclient.ErrorIncorrectPacketClt;
import forge.net.protocol.toclient.ErrorUnknownPacketClt;
import forge.net.protocol.toclient.ErrorNoStateForPacketClt;
import forge.net.protocol.toclient.IPacketClt;
import forge.net.protocol.toclient.WelcomePacketClt;
import forge.net.protocol.toserver.AuthorizePacketSrv;
import forge.net.protocol.toserver.ChatPacketSrv;
import forge.net.protocol.toserver.EchoPacketSrv;
@@ -37,11 +38,12 @@ public class ClientProtocolJson implements ClientProtocol<IPacketSrv, IPacketClt
headerToClassInbound.put("auth", AuthorizePacketSrv.class);
// The what we reply there
classToHeaderOutbound.put(WelcomePacketClt.class, "welcome");
classToHeaderOutbound.put(AuthResultPacketClt.class, "auth");
classToHeaderOutbound.put(ChatPacketClt.class, "s");
classToHeaderOutbound.put(EchoPacketClt.class, "echo");
classToHeaderOutbound.put(ErrorIncorrectPacketClt.class, "err:packet_args");
classToHeaderOutbound.put(ErrorUnknownPacketClt.class, "err:packet");
classToHeaderOutbound.put(ErrorNoStateForPacketClt.class, "err:packet-state");
classToHeaderOutbound.put(ErrorIncorrectPacketClt.class, "err:packet");
}
private final Gson gson = new Gson(); // looks like a single instance per class is enough
@@ -63,7 +65,7 @@ public class ClientProtocolJson implements ClientProtocol<IPacketSrv, IPacketClt
args = "{}"; // assume default empty object
try {
return gson.fromJson(parts[1].trim(), packetClass);
return gson.fromJson(args, packetClass);
} catch( JsonParseException ex ) {
return new IncorrectPacketSrv("Invalid json: " + args);
}
@@ -73,7 +75,7 @@ public class ClientProtocolJson implements ClientProtocol<IPacketSrv, IPacketClt
public String encodePacket(IPacketClt packet) {
Class<? extends IPacketClt> packetClass = packet.getClass();
String prefix = classToHeaderOutbound.get(packetClass);
return String.format("%s %s", prefix != null ? prefix : "/!unserialized!: " + packetClass.getName(), gson.toJson(packet));
return String.format("/%s %s", prefix != null ? prefix : "/!unserialized!: " + packetClass.getName(), gson.toJson(packet));
}
}

View File

@@ -0,0 +1,19 @@
package forge.net.protocol.toclient;
/**
* TODO: Write javadoc for this type.
*
*/
public class ErrorNoStateForPacketClt implements IPacketClt {
private final String message;
public ErrorNoStateForPacketClt(String simpleName) {
message = simpleName;
}
public String getMessage() {
return message;
}
}

View File

@@ -1,11 +0,0 @@
package forge.net.protocol.toclient;
/**
* TODO: Write javadoc for this type.
*
*/
public class ErrorUnknownPacketClt implements IPacketClt {
}

View File

@@ -0,0 +1,17 @@
package forge.net.protocol.toclient;
import forge.model.BuildInfo;
/**
* TODO: Write javadoc for this type.
*
*/
public class WelcomePacketClt implements IPacketClt {
public final String message;
public final String version;
public WelcomePacketClt(String welcome) {
message = welcome;
version = BuildInfo.getVersionString();
}
}

View File

@@ -0,0 +1,3 @@
/** Model (as in model-view-controller) for Forge. */
package forge.net.protocol.toclient;

View File

@@ -38,11 +38,14 @@ public class ForgeProfileProperties {
public final String cacheDir;
public final String cardPicsDir;
public final Map<String, String> cardPicsSubDir;
public final int serverPort;
private static final String _USER_DIR_KEY = "userDir";
private static final String _CACHE_DIR_KEY = "cacheDir";
private static final String _CARD_PICS_DIR_KEY = "cardPicsDir";
private static final String _CARD_PICS_SUB_DIRS_KEY = "cardPicsSubDirs";
private static final String _SERVER_PORT = "serverPort";
public ForgeProfileProperties(String filename) {
Properties props = new Properties();
@@ -60,6 +63,8 @@ public class ForgeProfileProperties {
cacheDir = _getDir(props, _CACHE_DIR_KEY, defaults.getRight());
cardPicsDir = _getDir(props, _CARD_PICS_DIR_KEY, cacheDir + "pics/cards/");
cardPicsSubDir = _getMap(props, _CARD_PICS_SUB_DIRS_KEY);
serverPort = _getInt(props, _SERVER_PORT, 0);
}
@@ -68,6 +73,13 @@ public class ForgeProfileProperties {
return FileSection.parseToMap(strMap, "->", "|");
}
private int _getInt(Properties props, String propertyKey, int defaultValue) {
String strValue = props.getProperty(propertyKey, "").trim();
if ( StringUtils.isNotBlank(strValue) && StringUtils.isNumeric(strValue) )
return Integer.parseInt(strValue);
return defaultValue;
}
private static String _getDir(Properties props, String propertyKey, String defaultVal) {
String retDir = props.getProperty(propertyKey, defaultVal).trim();
if (retDir.isEmpty()) {

View File

@@ -57,12 +57,14 @@ public final class NewConstants {
public static final String CACHE_DIR;
public static final String CACHE_CARD_PICS_DIR;
public static final Map<String, String> CACHE_CARD_PICS_SUBDIR;
public static final int SERVER_PORT_NUMBER;
static {
ForgeProfileProperties profileProps = new ForgeProfileProperties(PROFILE_FILE);
USER_DIR = profileProps.userDir;
CACHE_DIR = profileProps.cacheDir;
CACHE_CARD_PICS_DIR = profileProps.cardPicsDir;
CACHE_CARD_PICS_SUBDIR = Collections.unmodifiableMap(profileProps.cardPicsSubDir);
SERVER_PORT_NUMBER = profileProps.serverPort;
}
// data that is only in the profile dirs