Skip to content

Instantly share code, notes, and snippets.

@Meghatronics
Created April 23, 2021 09:24
Show Gist options
  • Select an option

  • Save Meghatronics/71e1a478ee5f8a977ef409154f0ade15 to your computer and use it in GitHub Desktop.

Select an option

Save Meghatronics/71e1a478ee5f8a977ef409154f0ade15 to your computer and use it in GitHub Desktop.
Chat Manager with socket.io in flutter
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:socket_io_client/socket_io_client.dart' as io;
import '../../data/models/chat_message.dart';
import '../../data/models/room.dart';
class ChatData {
final bool matchIsTyping;
final ChatMessage chatMessage;
const ChatData({this.matchIsTyping, this.chatMessage});
}
enum ManagerState { ready, preparing, notReady }
class ChatManager {
final Room room;
final StreamController<ChatData> _controller = StreamController<ChatData>();
bool _receiverIsTyping = false;
bool _userIsTyping = false;
ManagerState _ready = ManagerState.notReady;
io.Socket chatSocket;
ChatManager({@required this.room}) {
chatSocket = io.io(
"https://link.com", //TODO YOUR OWN URL
<String, dynamic>{
'transports': ['websocket'],
//TODO I believe this is where you can add the headers
},
);
print('chatSocket is connected ${chatSocket.connected}');
chatSocket.connect();
_initializeChatSocket();
}
Stream get chatStream => _controller.stream;
///This function starts the chat socket.
///
///Calls [_joinRoom()] and waits till room is joined.
///Then registers call backs for events to listen for:
///* 'message'
///* 'typing'
///* 'stopTyping'
void _initializeChatSocket() async {
_ready = ManagerState.preparing;
final joined = await _joinRoom();
if (!joined) return;
print('registering callbacks: $_ready');
chatSocket.on('newMessage', (data) {
final newMessage = ChatMessage.fromJson(data);
_controller.sink.add(ChatData(chatMessage: newMessage));
room.messages.add(newMessage);
});
chatSocket.on('isTyping', (space) {
if (space == room.sId) _receiverIsTyping = true;
_controller.sink.add(ChatData(matchIsTyping: _receiverIsTyping));
});
chatSocket.on('isNotTyping', (space) {
if (space == room.sId) _receiverIsTyping = false;
_controller.sink.add(ChatData(matchIsTyping: _receiverIsTyping));
});
_ready = ManagerState.ready;
print('registering callbacks DONE: $_ready');
}
bool get ready {
if (_ready == ManagerState.preparing || _ready == ManagerState.notReady)
return false;
else if (chatSocket.connected && _ready == ManagerState.ready) {
return true;
} else {
_ready = ManagerState.notReady;
chatSocket.connect();
_initializeChatSocket();
return false;
}
}
int _retryCount = 0;
///Emits a [joinRoom] event.
///Identifies socket with a room on the server.
///Must be called after connect for chat to work
Future<bool> _joinRoom() async {
print('chatSocket is connected ${chatSocket.connected} : $_ready');
if (_ready == ManagerState.preparing) {
if (chatSocket.connected) {
chatSocket.emit('enterChatRoom', {
"username": room.me.username,
"room": room.me.sId,
});
print('Joined Room');
return true;
} else
_retryCount++;
if (_retryCount == 6 || _retryCount == 12) chatSocket.connect();
if (_retryCount > 18)
return false;
else
return Future.delayed(const Duration(seconds: 1), () {
return _joinRoom();
});
} else
return false;
}
///Close this manager
///Closes the Stream controller and disposes the sockets
void close() {
_controller.close();
chatSocket.close();
chatSocket.dispose();
_ready = ManagerState.notReady;
print('chatSocket is connected ${chatSocket.connected}');
}
void sendText(String text) {
print('chatSocket is connected ${chatSocket.connected}');
final messageToSend = ChatMessage(
text: text,
senderUsername: room.me.username,
senderId: room.me.sId,
to: room.receiver.sId,
chatRoom: room.sId,
);
chatSocket.emit('chatMessage', messageToSend.toJson());
room.messages.add(messageToSend);
}
set thisUserTyping(bool isTyping) {
if (isTyping && _userIsTyping) return;
_userIsTyping = isTyping;
print('chatSocket is connected ${chatSocket.connected}');
chatSocket.emit(
_userIsTyping ? "isTyping" : "isNotTyping",
{
"to": room.receiver.sId,
"space": room.sId,
},
);
print('typing : $_userIsTyping');
if (_userIsTyping)
Future.delayed(const Duration(seconds: 10), () {
thisUserTyping = false;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment