Marco
8f4cd2266f
This is another step to allow reconnecting after connection loss or browser closing. When the game is left with the X button on the bottom right, we will close the websocket connection, to let the server know, that we are gone. The server still has issues that prevent this from working flawlessly. Remove unused import
151 lines
4.4 KiB
Dart
151 lines
4.4 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:mchess/api/move.dart';
|
|
import 'package:mchess/api/websocket_message.dart';
|
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
|
import 'package:mchess/chess_bloc/chess_events.dart';
|
|
import 'package:mchess/api/register.dart';
|
|
import 'package:mchess/chess_bloc/chess_position.dart';
|
|
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
|
import 'package:mchess/utils/chess_utils.dart';
|
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
|
|
|
class ServerConnection {
|
|
WebSocketChannel? channel;
|
|
late bool wasConnected = false;
|
|
Stream broadcast = const Stream.empty();
|
|
|
|
static final ServerConnection _instance = ServerConnection._internal();
|
|
|
|
ServerConnection._internal() {
|
|
log("ServerConnection._internal constructor is called");
|
|
}
|
|
|
|
factory ServerConnection() {
|
|
return _instance;
|
|
}
|
|
|
|
factory ServerConnection.getInstance() {
|
|
return ServerConnection();
|
|
}
|
|
|
|
void send(String message) {
|
|
if (channel == null) {
|
|
log("Sending on channel without initializing");
|
|
return;
|
|
}
|
|
channel!.sink.add(message);
|
|
}
|
|
|
|
void connect(String playerID, lobbyID, String? passphrase) {
|
|
String url;
|
|
if (kDebugMode) {
|
|
url = 'ws://localhost:8080/api/ws';
|
|
} else {
|
|
url = 'wss://chess.sw-gross.de:9999/api/ws';
|
|
}
|
|
channel = WebSocketChannel.connect(Uri.parse(url));
|
|
|
|
send(
|
|
jsonEncode(
|
|
WebsocketMessageIdentifyPlayer(
|
|
playerID: (playerID),
|
|
lobbyID: (lobbyID),
|
|
passphrase: (passphrase),
|
|
),
|
|
),
|
|
);
|
|
|
|
log(channel!.closeCode.toString());
|
|
broadcast = channel!.stream.asBroadcastStream();
|
|
broadcast.listen(handleIncomingData);
|
|
}
|
|
|
|
void disconnectExistingConnection() {
|
|
if (channel == null) return;
|
|
channel!.sink.close();
|
|
}
|
|
|
|
void handleIncomingData(dynamic data) {
|
|
log("Data received:");
|
|
log(data);
|
|
var apiMessage = ApiWebsocketMessage.fromJson(jsonDecode(data));
|
|
|
|
switch (apiMessage.type) {
|
|
case MessageType.boardState:
|
|
handleBoardStateMessage(apiMessage);
|
|
break;
|
|
|
|
case MessageType.colorDetermined:
|
|
handleIncomingColorDeterminedMessage(apiMessage);
|
|
break;
|
|
|
|
case MessageType.move:
|
|
handleIncomingMoveMessage(apiMessage);
|
|
break;
|
|
|
|
case MessageType.invalidMove:
|
|
handleInvalidMoveMessage(apiMessage);
|
|
}
|
|
}
|
|
|
|
void handleBoardStateMessage(ApiWebsocketMessage apiMessage) {
|
|
ChessMove? move;
|
|
if (apiMessage.move != null) {
|
|
move = ChessMove.fromApiMove(apiMessage.move!);
|
|
}
|
|
|
|
if (apiMessage.position != null) {
|
|
ChessBloc.getInstance().add(
|
|
ReceivedBoardState(
|
|
startSquare: move?.from,
|
|
endSquare: move?.to,
|
|
position: ChessPositionManager.getInstance()
|
|
.fromPGNString(apiMessage.position!),
|
|
squareInCheck: ChessCoordinate.fromApiCoordinate(
|
|
apiMessage.squareInCheck ?? const ApiCoordinate(col: 0, row: 0)),
|
|
),
|
|
);
|
|
} else {
|
|
log('Error: no position received');
|
|
}
|
|
}
|
|
|
|
void handleIncomingColorDeterminedMessage(ApiWebsocketMessage apiMessage) {
|
|
ConnectionCubit.getInstance().opponentConnected();
|
|
ChessBloc.getInstance().add(InitBoard());
|
|
ChessBloc.getInstance().add(ColorDetermined(
|
|
myColor: ChessColor.fromApiColor(apiMessage.playerColor!)));
|
|
}
|
|
|
|
void handleIncomingMoveMessage(ApiWebsocketMessage apiMessage) {
|
|
if (apiMessage.position != null) {
|
|
var move = ChessMove.fromApiMove(apiMessage.move!);
|
|
ChessBloc.getInstance().add(
|
|
ReceivedBoardState(
|
|
startSquare: move.from,
|
|
endSquare: move.to,
|
|
position: ChessPositionManager.getInstance()
|
|
.fromPGNString(apiMessage.position!),
|
|
squareInCheck: ChessCoordinate.fromApiCoordinate(
|
|
apiMessage.squareInCheck ?? const ApiCoordinate(col: 0, row: 0)),
|
|
),
|
|
);
|
|
} else {
|
|
log('Error: no position received');
|
|
}
|
|
}
|
|
|
|
void handleInvalidMoveMessage(ApiWebsocketMessage apiMessage) {
|
|
log("invalid move message received, with move: ${apiMessage.move.toString()}");
|
|
ChessBloc.getInstance().add(
|
|
InvalidMovePlayed(
|
|
move: ChessMove.fromApiMove(apiMessage.move!),
|
|
squareInCheck: ChessCoordinate.fromApiCoordinate(
|
|
apiMessage.squareInCheck ?? const ApiCoordinate(col: 0, row: 0)),
|
|
),
|
|
);
|
|
}
|
|
}
|