2023-06-02 21:28:40 +00:00
|
|
|
import 'dart:convert';
|
2022-12-13 02:43:05 +00:00
|
|
|
import 'dart:developer';
|
2024-01-17 21:50:02 +00:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:go_router/go_router.dart';
|
2023-09-04 19:39:51 +00:00
|
|
|
import 'package:mchess/api/move.dart';
|
2023-06-08 15:10:48 +00:00
|
|
|
import 'package:mchess/api/websocket_message.dart';
|
2022-12-14 22:17:31 +00:00
|
|
|
import 'package:mchess/chess_bloc/chess_bloc.dart';
|
|
|
|
import 'package:mchess/chess_bloc/chess_events.dart';
|
2023-06-02 21:28:40 +00:00
|
|
|
import 'package:mchess/api/register.dart';
|
2023-08-14 15:04:25 +00:00
|
|
|
import 'package:mchess/chess_bloc/chess_position.dart';
|
2023-06-29 23:49:18 +00:00
|
|
|
import 'package:mchess/connection_cubit/connection_cubit.dart';
|
2024-01-17 21:50:02 +00:00
|
|
|
import 'package:mchess/utils/chess_router.dart';
|
2022-12-25 15:16:23 +00:00
|
|
|
import 'package:mchess/utils/chess_utils.dart';
|
2024-01-17 21:50:02 +00:00
|
|
|
import 'package:mchess/utils/config.dart' as config;
|
2022-11-13 13:25:47 +00:00
|
|
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
|
|
|
|
|
|
|
class ServerConnection {
|
2023-12-09 19:34:52 +00:00
|
|
|
WebSocketChannel? channel;
|
2023-05-28 12:54:46 +00:00
|
|
|
Stream broadcast = const Stream.empty();
|
2022-11-13 13:25:47 +00:00
|
|
|
|
|
|
|
static final ServerConnection _instance = ServerConnection._internal();
|
|
|
|
|
|
|
|
ServerConnection._internal() {
|
2022-12-18 02:21:39 +00:00
|
|
|
log("ServerConnection._internal constructor is called");
|
2022-11-13 13:25:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
factory ServerConnection() {
|
|
|
|
return _instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
factory ServerConnection.getInstance() {
|
|
|
|
return ServerConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(String message) {
|
2023-12-09 19:34:52 +00:00
|
|
|
if (channel == null) {
|
|
|
|
log("Sending on channel without initializing");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
channel!.sink.add(message);
|
2022-11-13 13:25:47 +00:00
|
|
|
}
|
2022-11-19 12:24:38 +00:00
|
|
|
|
2024-05-19 15:22:06 +00:00
|
|
|
void connect(String? passphrase) {
|
2024-05-15 17:42:18 +00:00
|
|
|
disconnectExistingConnection();
|
2024-01-17 21:50:02 +00:00
|
|
|
channel = WebSocketChannel.connect(Uri.parse(config.getWebsocketURL()));
|
2023-12-09 19:34:52 +00:00
|
|
|
|
2024-05-19 15:22:06 +00:00
|
|
|
send(jsonEncode(passphrase));
|
2022-12-18 15:11:00 +00:00
|
|
|
|
2023-12-09 19:34:52 +00:00
|
|
|
log(channel!.closeCode.toString());
|
|
|
|
broadcast = channel!.stream.asBroadcastStream();
|
2023-06-02 21:28:40 +00:00
|
|
|
broadcast.listen(handleIncomingData);
|
|
|
|
}
|
|
|
|
|
2023-12-09 19:34:52 +00:00
|
|
|
void disconnectExistingConnection() {
|
|
|
|
if (channel == null) return;
|
|
|
|
channel!.sink.close();
|
2024-05-15 17:42:18 +00:00
|
|
|
|
|
|
|
broadcast = const Stream.empty();
|
2023-12-09 19:34:52 +00:00
|
|
|
}
|
|
|
|
|
2023-06-02 21:28:40 +00:00
|
|
|
void handleIncomingData(dynamic data) {
|
2023-12-25 16:50:58 +00:00
|
|
|
log('${DateTime.now()}: Data received:');
|
2023-06-02 21:28:40 +00:00
|
|
|
log(data);
|
2023-06-08 15:10:48 +00:00
|
|
|
var apiMessage = ApiWebsocketMessage.fromJson(jsonDecode(data));
|
|
|
|
|
|
|
|
switch (apiMessage.type) {
|
2023-12-09 19:34:52 +00:00
|
|
|
case MessageType.boardState:
|
|
|
|
handleBoardStateMessage(apiMessage);
|
|
|
|
break;
|
|
|
|
|
2023-06-08 15:10:48 +00:00
|
|
|
case MessageType.colorDetermined:
|
2023-06-08 18:23:00 +00:00
|
|
|
handleIncomingColorDeterminedMessage(apiMessage);
|
2023-06-08 15:10:48 +00:00
|
|
|
break;
|
2023-06-02 21:28:40 +00:00
|
|
|
|
2023-06-08 18:23:00 +00:00
|
|
|
case MessageType.move:
|
2023-12-25 16:50:58 +00:00
|
|
|
log('ERROR: move message received');
|
2023-06-08 18:23:00 +00:00
|
|
|
break;
|
2023-06-28 10:37:59 +00:00
|
|
|
|
|
|
|
case MessageType.invalidMove:
|
|
|
|
handleInvalidMoveMessage(apiMessage);
|
2024-01-17 21:50:02 +00:00
|
|
|
case MessageType.gameEnded:
|
|
|
|
handleGameEndedMessage(apiMessage);
|
2023-06-08 15:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-02 21:28:40 +00:00
|
|
|
|
2023-12-09 19:34:52 +00:00
|
|
|
void handleBoardStateMessage(ApiWebsocketMessage apiMessage) {
|
|
|
|
ChessMove? move;
|
|
|
|
if (apiMessage.move != null) {
|
|
|
|
move = ChessMove.fromApiMove(apiMessage.move!);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (apiMessage.position != null) {
|
|
|
|
ChessBloc.getInstance().add(
|
|
|
|
ReceivedBoardState(
|
2023-12-25 17:08:21 +00:00
|
|
|
startSquare: move?.from,
|
|
|
|
endSquare: move?.to,
|
|
|
|
position: ChessPositionManager.getInstance()
|
|
|
|
.fromPGNString(apiMessage.position!),
|
|
|
|
squareInCheck: ChessCoordinate.fromApiCoordinate(
|
|
|
|
apiMessage.squareInCheck ??
|
|
|
|
const ApiCoordinate(col: 0, row: 0)),
|
|
|
|
turnColor: ChessColor.fromApiColor(apiMessage.turnColor!)),
|
2023-12-09 19:34:52 +00:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
log('Error: no position received');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-08 18:23:00 +00:00
|
|
|
void handleIncomingColorDeterminedMessage(ApiWebsocketMessage apiMessage) {
|
2023-07-03 17:41:12 +00:00
|
|
|
ConnectionCubit.getInstance().opponentConnected();
|
|
|
|
ChessBloc.getInstance().add(InitBoard());
|
2023-12-09 19:34:52 +00:00
|
|
|
ChessBloc.getInstance().add(ColorDetermined(
|
|
|
|
myColor: ChessColor.fromApiColor(apiMessage.playerColor!)));
|
2023-06-08 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2023-06-28 10:37:59 +00:00
|
|
|
void handleInvalidMoveMessage(ApiWebsocketMessage apiMessage) {
|
|
|
|
log("invalid move message received, with move: ${apiMessage.move.toString()}");
|
2023-09-04 19:39:51 +00:00
|
|
|
ChessBloc.getInstance().add(
|
|
|
|
InvalidMovePlayed(
|
|
|
|
move: ChessMove.fromApiMove(apiMessage.move!),
|
2023-12-09 19:34:52 +00:00
|
|
|
squareInCheck: ChessCoordinate.fromApiCoordinate(
|
|
|
|
apiMessage.squareInCheck ?? const ApiCoordinate(col: 0, row: 0)),
|
2023-09-04 19:39:51 +00:00
|
|
|
),
|
|
|
|
);
|
2022-11-19 12:24:38 +00:00
|
|
|
}
|
2024-01-17 21:50:02 +00:00
|
|
|
|
|
|
|
void handleGameEndedMessage(ApiWebsocketMessage apiMessage) {
|
|
|
|
showDialog(
|
|
|
|
context: navigatorKey.currentContext!,
|
|
|
|
builder: (context) {
|
|
|
|
String msg = '';
|
|
|
|
if (apiMessage.reason == 'whiteIsCheckmated') {
|
|
|
|
msg = 'Black won! White is checkmated';
|
|
|
|
} else if (apiMessage.reason == 'blackIsCheckmated') {
|
|
|
|
msg = 'White won! Black is checkmated';
|
|
|
|
}
|
|
|
|
return AlertDialog(
|
|
|
|
title: const Text('Game ended'),
|
|
|
|
content: Text(msg),
|
|
|
|
actions: <Widget>[
|
|
|
|
TextButton(
|
|
|
|
child: const Text('Home'),
|
|
|
|
onPressed: () {
|
|
|
|
navigatorKey.currentContext!.goNamed('lobbySelector');
|
|
|
|
},
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
2022-11-13 13:25:47 +00:00
|
|
|
}
|