mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
connection: improved error processing and stability in connect dialog
This commit is contained in:
parent
adf57a0677
commit
0b0e947741
6 changed files with 55 additions and 24 deletions
|
|
@ -34,7 +34,7 @@ public class MageUI {
|
||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
|
|
||||||
// catch errors in popup threads (example: card popup over cards or chat/log messages)
|
// catch errors in popup threads (example: card popup over cards or chat/log messages)
|
||||||
t = ThreadUtils.findRealException(r, t);
|
t = ThreadUtils.findRunnableException(r, t);
|
||||||
if (t != null && !(t instanceof CancellationException)) {
|
if (t != null && !(t instanceof CancellationException)) {
|
||||||
logger.error("Catch unhandled error in POPUP thread: " + t.getMessage(), t);
|
logger.error("Catch unhandled error in POPUP thread: " + t.getMessage(), t);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import mage.client.util.gui.countryBox.CountryItemEditor;
|
||||||
import mage.client.util.sets.ConstructedFormats;
|
import mage.client.util.sets.ConstructedFormats;
|
||||||
import mage.remote.Connection;
|
import mage.remote.Connection;
|
||||||
import mage.utils.StreamUtils;
|
import mage.utils.StreamUtils;
|
||||||
|
import mage.utils.ThreadUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
@ -61,6 +62,7 @@ public class ConnectDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showDialog() {
|
public void showDialog() {
|
||||||
|
this.lblStatus.setText("");
|
||||||
String serverAddress = MagePreferences.getServerAddressWithDefault(ClientDefaultSettings.serverName);
|
String serverAddress = MagePreferences.getServerAddressWithDefault(ClientDefaultSettings.serverName);
|
||||||
this.txtServer.setText(serverAddress);
|
this.txtServer.setText(serverAddress);
|
||||||
this.txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(ClientDefaultSettings.port)));
|
this.txtPort.setText(Integer.toString(MagePreferences.getServerPortWithDefault(ClientDefaultSettings.port)));
|
||||||
|
|
@ -83,6 +85,7 @@ public class ConnectDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveSettings() {
|
private void saveSettings() {
|
||||||
|
ThreadUtils.sleep(3000);
|
||||||
String serverAddress = txtServer.getText().trim();
|
String serverAddress = txtServer.getText().trim();
|
||||||
MagePreferences.setServerAddress(serverAddress);
|
MagePreferences.setServerAddress(serverAddress);
|
||||||
MagePreferences.setServerPort(Integer.parseInt(txtPort.getText().trim()));
|
MagePreferences.setServerPort(Integer.parseInt(txtPort.getText().trim()));
|
||||||
|
|
@ -678,8 +681,10 @@ public class ConnectDialog extends MageDialog {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground() throws Exception {
|
protected Boolean doInBackground() throws Exception {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
lblStatus.setText("Connecting...");
|
lblStatus.setText("Connecting...");
|
||||||
setConnectButtonsState(false);
|
setConnectButtonsState(false);
|
||||||
|
});
|
||||||
result = MageFrame.connect(connection);
|
result = MageFrame.connect(connection);
|
||||||
lastConnectError = SessionHandler.getLastConnectError();
|
lastConnectError = SessionHandler.getLastConnectError();
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -688,32 +693,44 @@ public class ConnectDialog extends MageDialog {
|
||||||
@Override
|
@Override
|
||||||
protected void done() {
|
protected void done() {
|
||||||
try {
|
try {
|
||||||
get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); // catch exceptions
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
if (result) {
|
if (result) {
|
||||||
lblStatus.setText("");
|
lblStatus.setText("Connected");
|
||||||
connected();
|
|
||||||
|
// for ux: after connection client can load additional resources and data,
|
||||||
|
// so the connection dialog will be visible all that time
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
doAfterConnected();
|
||||||
MageFrame.getInstance().prepareAndShowTablesPane();
|
MageFrame.getInstance().prepareAndShowTablesPane();
|
||||||
|
btnConnect.setEnabled(true);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
lblStatus.setText("Could not connect: " + lastConnectError);
|
lblStatus.setText("Could not connect: " + lastConnectError);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
logger.fatal("Update Players Task error", ex);
|
logger.fatal("Connection: can't load data from server", ex);
|
||||||
} catch (CancellationException ex) {
|
} catch (CancellationException ex) {
|
||||||
logger.info("Connect: canceled");
|
logger.info("Connect: canceled");
|
||||||
lblStatus.setText("Connect was canceled");
|
lblStatus.setText("Connect was canceled");
|
||||||
} catch (TimeoutException ex) {
|
} catch (TimeoutException ex) {
|
||||||
logger.fatal("Connection timeout: ", ex);
|
logger.fatal("Connection: timeout", ex);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (!result) {
|
||||||
MageFrame.stopConnecting();
|
MageFrame.stopConnecting();
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
setConnectButtonsState(true);
|
setConnectButtonsState(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connected() {
|
private void doAfterConnected() {
|
||||||
this.saveSettings();
|
this.saveSettings();
|
||||||
this.hideDialog();
|
this.hideDialog();
|
||||||
ConstructedFormats.ensureLists();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void keyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_keyTyped
|
private void keyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_keyTyped
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class LinePool {
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecute(Runnable r, Throwable t) {
|
protected void afterExecute(Runnable r, Throwable t) {
|
||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
t = ThreadUtils.findRealException(r, t);
|
t = ThreadUtils.findRunnableException(r, t);
|
||||||
if (t != null && !(t instanceof CancellationException)) {
|
if (t != null && !(t instanceof CancellationException)) {
|
||||||
// TODO: show sound errors in client logs?
|
// TODO: show sound errors in client logs?
|
||||||
//logger.error("Catch unhandled error in SOUND thread: " + t.getMessage(), t);
|
//logger.error("Catch unhandled error in SOUND thread: " + t.getMessage(), t);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import mage.interfaces.callback.ClientCallback;
|
||||||
import mage.players.PlayerType;
|
import mage.players.PlayerType;
|
||||||
import mage.players.net.UserData;
|
import mage.players.net.UserData;
|
||||||
import mage.utils.CompressUtil;
|
import mage.utils.CompressUtil;
|
||||||
|
import mage.utils.ThreadUtils;
|
||||||
import mage.view.*;
|
import mage.view.*;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jboss.remoting.*;
|
import org.jboss.remoting.*;
|
||||||
|
|
@ -118,10 +119,13 @@ public class SessionImpl implements Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMessageToUser(String message) {
|
private void showMessageToUser(String message) {
|
||||||
|
if (message == null) {
|
||||||
|
message = "Unknown error, look at logs for details";
|
||||||
|
}
|
||||||
if (message.contains("free port for use")) {
|
if (message.contains("free port for use")) {
|
||||||
message += " (try to close and restart a client app)";
|
message += " (try to close and restart a client app)";
|
||||||
}
|
}
|
||||||
client.showMessage("Remote task error. " + message);
|
client.showMessage("Remote task error: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doRemoteWorkAndHandleErrors(boolean closeConnectionOnFinish, boolean mustWaitServerMessageOnFail,
|
private boolean doRemoteWorkAndHandleErrors(boolean closeConnectionOnFinish, boolean mustWaitServerMessageOnFail,
|
||||||
|
|
@ -180,17 +184,18 @@ public class SessionImpl implements Session {
|
||||||
logger.warn("Connect: wrong versions");
|
logger.warn("Connect: wrong versions");
|
||||||
connectStop(false);
|
connectStop(false);
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
showMessageToUser(ex.getMessage());
|
showMessageToUser(ex.toString());
|
||||||
}
|
}
|
||||||
} catch (CannotConnectException ex) {
|
} catch (CannotConnectException ex) {
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
handleCannotConnectException(ex);
|
handleCannotConnectException(ex);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
Throwable ex = ThreadUtils.findRootException(t);
|
||||||
logger.fatal("Connect: FAIL", t);
|
logger.fatal("Connect: FAIL", t);
|
||||||
connectStop(false);
|
connectStop(false);
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
showMessageToUser(t.getMessage());
|
showMessageToUser(ex.toString());
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
lastRemotingTask = null;
|
lastRemotingTask = null;
|
||||||
|
|
@ -470,6 +475,8 @@ public class SessionImpl implements Session {
|
||||||
|
|
||||||
private void handleCannotConnectException(CannotConnectException ex) {
|
private void handleCannotConnectException(CannotConnectException ex) {
|
||||||
logger.warn("Cannot connect", ex);
|
logger.warn("Cannot connect", ex);
|
||||||
|
|
||||||
|
// try to find a known error
|
||||||
Throwable t = ex.getCause();
|
Throwable t = ex.getCause();
|
||||||
String message = "";
|
String message = "";
|
||||||
while (t != null) {
|
while (t != null) {
|
||||||
|
|
@ -493,6 +500,7 @@ public class SessionImpl implements Session {
|
||||||
t = t.getCause();
|
t = t.getCause();
|
||||||
}
|
}
|
||||||
client.showMessage("Unable connect to server. " + message);
|
client.showMessage("Unable connect to server. " + message);
|
||||||
|
setLastError(message);
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("StackTrace", t);
|
logger.trace("StackTrace", t);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.utils;
|
package mage.utils;
|
||||||
|
|
||||||
|
import com.google.common.base.Throwables;
|
||||||
|
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
@ -31,7 +33,7 @@ public final class ThreadUtils {
|
||||||
* Find real exception object after thread task completed. Can be used in afterExecute
|
* Find real exception object after thread task completed. Can be used in afterExecute
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public static Throwable findRealException(Runnable r, Throwable t) {
|
public static Throwable findRunnableException(Runnable r, Throwable t) {
|
||||||
// executer.submit - return exception in result
|
// executer.submit - return exception in result
|
||||||
// executer.execute - return exception in t
|
// executer.execute - return exception in t
|
||||||
if (t == null && r instanceof Future<?>) {
|
if (t == null && r instanceof Future<?>) {
|
||||||
|
|
@ -47,4 +49,8 @@ public final class ThreadUtils {
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Throwable findRootException(Throwable t) {
|
||||||
|
return Throwables.getRootCause(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ public class ThreadExecutorImpl implements ThreadExecutor {
|
||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
|
|
||||||
// catch errors in CALL threads (from client commands)
|
// catch errors in CALL threads (from client commands)
|
||||||
t = ThreadUtils.findRealException(r, t);
|
t = ThreadUtils.findRunnableException(r, t);
|
||||||
if (t != null && !(t instanceof CancellationException)) {
|
if (t != null && !(t instanceof CancellationException)) {
|
||||||
logger.error("Catch unhandled error in CALL thread: " + t.getMessage(), t);
|
logger.error("Catch unhandled error in CALL thread: " + t.getMessage(), t);
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +83,7 @@ public class ThreadExecutorImpl implements ThreadExecutor {
|
||||||
super.afterExecute(r, t);
|
super.afterExecute(r, t);
|
||||||
|
|
||||||
// catch errors in GAME threads (from game processing)
|
// catch errors in GAME threads (from game processing)
|
||||||
t = ThreadUtils.findRealException(r, t);
|
t = ThreadUtils.findRunnableException(r, t);
|
||||||
if (t != null && !(t instanceof CancellationException)) {
|
if (t != null && !(t instanceof CancellationException)) {
|
||||||
// it's impossible to brake game thread in normal use case, so each bad use case must be researched
|
// it's impossible to brake game thread in normal use case, so each bad use case must be researched
|
||||||
logger.error("Catch unhandled error in GAME thread: " + t.getMessage(), t);
|
logger.error("Catch unhandled error in GAME thread: " + t.getMessage(), t);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue