Skip to content

Commit

Permalink
fix(client): Make chatMessages and sendChatMessage always available
Browse files Browse the repository at this point in the history
This change makes sure the chat fields on the client class are always 
present, so consumers don’t have to double check whether they are there 
before using them.

This commit also moves the dummy transport logic out of the client and 
into a dedicated `DummyTransport`.
  • Loading branch information
delucis committed Jan 15, 2021
1 parent 6df7bf6 commit b14ea29
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 46 deletions.
2 changes: 1 addition & 1 deletion examples/react-web/src/chess/board.js
Expand Up @@ -67,7 +67,7 @@ class Board extends React.Component {

{this._getStatus()}
{disconnected}
{this.props.sendChatMessage && this.props.chatMessages && (
{this.props.isMultiplayer && this.props.playerID !== null && (
<Chat
onSend={this.props.sendChatMessage}
messages={this.props.chatMessages}
Expand Down
15 changes: 9 additions & 6 deletions examples/react-web/src/chess/chat.js
Expand Up @@ -7,7 +7,8 @@ const Chat = ({ onSend, messages }) => {
setMessage(event.target.value);
};

const triggerSend = () => {
const triggerSend = (event) => {
event.preventDefault();
onSend(message);
setMessage('');
};
Expand All @@ -18,19 +19,21 @@ const Chat = ({ onSend, messages }) => {
style={{
height: 200,
maxWidth: 400,
padding: '.5em',
overflow: 'scroll',
border: '1px solid black',
}}
>
{messages.map((message) => (
<div key={message.id}>
<div>{message.sender}</div>
<div>{JSON.stringify(message.payload)}</div>
<div key={message.id} style={{ marginBottom: '.25em' }}>
<strong>Player {message.sender}:</strong> {message.payload}
</div>
))}
</div>
<input onChange={onChange} value={message} />
<button onClick={triggerSend}>Send</button>
<form onSubmit={triggerSend}>
<input onChange={onChange} value={message} />
<button type="submit">Send</button>
</form>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -177,7 +177,7 @@
},
"coveragePathIgnorePatterns": [
"/node_modules/",
"src/.*/random.alea.js",
"src/client/transport/dummy",
"src/client/debug/.*",
"src/types.ts"
],
Expand Down
2 changes: 2 additions & 0 deletions src/client/client.test.ts
Expand Up @@ -279,6 +279,8 @@ describe('multiplayer', () => {
subscribeMatchData(fn) {
this.callback = fn;
}

subscribeChatMessage() {}
}
const customTransport = () =>
(new CustomTransport() as unknown) as Transport;
Expand Down
61 changes: 23 additions & 38 deletions src/client/client.ts
Expand Up @@ -18,6 +18,7 @@ import { CreateGameReducer } from '../core/reducer';
import { InitializeGame } from '../core/initialize';
import { PlayerView } from '../plugins/main';
import type { Transport, TransportOpts } from './transport/transport';
import { DummyTransport } from './transport/dummy';
import { ClientManager } from './manager';
import type {
ActivePlayersArg,
Expand Down Expand Up @@ -308,31 +309,17 @@ export class _ClientImpl<G extends any = any> {

this.store = createStore(this.reducer, this.initialState, enhancer);

this.transport = ({
isConnected: true,
onAction: () => {},
subscribe: () => {},
subscribeMatchData: () => {},
subscribeChatMessage: () => {},
connect: () => {},
disconnect: () => {},
updateMatchID: () => {},
updatePlayerID: () => {},
} as unknown) as Transport;

if (multiplayer) {
// typeof multiplayer is 'function'
this.transport = multiplayer({
gameKey: game,
game: this.game,
store: this.store,
matchID,
playerID,
credentials,
gameName: this.game.name,
numPlayers,
});
}
if (!multiplayer) multiplayer = DummyTransport;
this.transport = multiplayer({
gameKey: game,
game: this.game,
store: this.store,
matchID,
playerID,
credentials,
gameName: this.game.name,
numPlayers,
});

this.createDispatchers();

Expand All @@ -341,20 +328,18 @@ export class _ClientImpl<G extends any = any> {
this.notifySubscribers();
});

if (this.transport.onChatMessage) {
this.chatMessages = [];
this.sendChatMessage = (payload) => {
this.transport.onChatMessage(this.matchID, {
id: nanoid(7),
sender: this.playerID,
payload: payload,
});
};
this.transport.subscribeChatMessage((message) => {
this.chatMessages = [...this.chatMessages, message];
this.notifySubscribers();
this.chatMessages = [];
this.sendChatMessage = (payload) => {
this.transport.onChatMessage(this.matchID, {
id: nanoid(7),
sender: this.playerID,
payload: payload,
});
}
};
this.transport.subscribeChatMessage((message) => {
this.chatMessages = [...this.chatMessages, message];
this.notifySubscribers();
});
}

private notifySubscribers() {
Expand Down
21 changes: 21 additions & 0 deletions src/client/transport/dummy.ts
@@ -0,0 +1,21 @@
import { Transport } from './transport';
import type { TransportOpts } from './transport';

/**
* This class doesn’t do anything, but simplifies the client class by providing
* dummy functions to call, so we don’t need to mock them in the client.
*/
class DummyImpl extends Transport {
connect() {}
disconnect() {}
onAction() {}
onChatMessage() {}
subscribe() {}
subscribeChatMessage() {}
subscribeMatchData() {}
updateCredentials() {}
updateMatchID() {}
updatePlayerID() {}
}

export const DummyTransport = (opts: TransportOpts) => new DummyImpl(opts);

0 comments on commit b14ea29

Please sign in to comment.