Messing around with the protocol a bit as the server is developed.

main
Mari 3 years ago
parent b4b5946352
commit 84bbdd31f0
  1. 1
      client/package-lock.json
  2. 30
      client/src/actions/NetworkAction.ts
  3. 12
      client/src/reducers/ClientReducer.ts
  4. 10
      client/src/reducers/ServerReducer.ts
  5. 30
      client/src/ui/debug/ConsoleConnection.tsx

@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
"name": "hexmap",
"version": "0.1.0",
"dependencies": {
"@testing-library/jest-dom": "^5.14.1",

@ -92,14 +92,14 @@ export function isServerSocketStartupAction(action: AppAction): action is Server
return action.type === SERVER_SOCKET_STARTUP
}
export const SERVER_SENT = "SERVER_SENT"
export const SERVER_ACT = "SERVER_ACT"
/** Sent by the server when another client has performed an action. Never sent for the client's own actions. */
export interface ServerSentAction extends BaseAction {
readonly type: typeof SERVER_SENT
export interface ServerActAction extends BaseAction {
readonly type: typeof SERVER_ACT
readonly actions: readonly SyncableAction[]
}
export function isServerSentAction(action: AppAction): action is ServerSentAction {
return action.type === SERVER_SENT
export function isServerActAction(action: AppAction): action is ServerActAction {
return action.type === SERVER_ACT
}
export type SyncableAction = SendableAction
@ -110,11 +110,11 @@ export function isSyncableAction(action: AppAction): action is SyncableAction {
export type ServerAction =
ServerHelloAction | ServerGoodbyeAction | ServerRefreshAction |
ServerOKAction | ServerFailedAction |
ServerSocketStartupAction | ServerSentAction
ServerSocketStartupAction | ServerActAction
export function isServerAction(action: AppAction) {
return isServerHelloAction(action) || isServerGoodbyeAction(action) || isServerRefreshAction(action)
|| isServerOKAction(action) || isServerFailedAction(action)
|| isServerSocketStartupAction(action) || isServerSentAction(action)
|| isServerSocketStartupAction(action) || isServerActAction(action)
}
export const CLIENT_HELLO = "CLIENT_HELLO"
@ -152,14 +152,14 @@ export interface SentAction {
readonly action: SendableAction
}
export const CLIENT_SENT = "CLIENT_SENT"
export const CLIENT_ACT = "CLIENT_ACT"
/** Sent to the server when the user performs an action. */
export interface ClientSentAction extends BaseAction {
readonly type: typeof CLIENT_SENT
readonly nested: readonly SentAction[]
export interface ClientActAction extends BaseAction {
readonly type: typeof CLIENT_ACT
readonly actions: readonly SentAction[]
}
export function isClientSentAction(action: AppAction): action is ClientSentAction {
return action.type === CLIENT_SENT
export function isClientActAction(action: AppAction): action is ClientActAction {
return action.type === CLIENT_ACT
}
export type SendableAction = CellColorAction | UserActiveColorAction
@ -167,9 +167,9 @@ export function isSendableAction(action: AppAction): action is SendableAction {
return isCellColorAction(action) || isUserActiveColorAction(action)
}
export type ClientAction = ClientHelloAction | ClientRefreshAction | ClientPendingAction | ClientSentAction
export type ClientAction = ClientHelloAction | ClientRefreshAction | ClientPendingAction | ClientActAction
export function isClientAction(action: AppAction): action is ClientAction {
return isClientHelloAction(action) || isClientRefreshAction(action) || isClientPendingAction(action) || isClientSentAction(action)
return isClientHelloAction(action) || isClientRefreshAction(action) || isClientPendingAction(action) || isClientActAction(action)
}
export type NetworkAction = ServerAction | ClientAction;

@ -1,4 +1,4 @@
import {CLIENT_HELLO, CLIENT_PENDING, CLIENT_REFRESH, CLIENT_SENT, ClientAction} from "../actions/NetworkAction";
import {CLIENT_HELLO, CLIENT_PENDING, CLIENT_REFRESH, CLIENT_ACT, ClientAction} from "../actions/NetworkAction";
import {NetworkState, ServerConnectionState} from "../state/NetworkState";
// TODO: Verify that only one special message exists at a time.
@ -23,16 +23,16 @@ export function clientReducer(oldState: NetworkState, action: ClientAction): Net
...oldState,
pendingActions: [...oldState.pendingActions, action.pending],
}
case CLIENT_SENT:
if (!action.nested.every((innerAction, index) =>
case CLIENT_ACT:
if (!action.actions.every((innerAction, index) =>
innerAction.id === oldState.nextID + index && innerAction.action === oldState.pendingActions[index])) {
throw Error("Only the next actions can be sent, and only with the next IDs.")
}
return {
...oldState,
nextID: oldState.nextID + action.nested.length,
sentActions: [...oldState.sentActions, ...action.nested],
pendingActions: oldState.pendingActions.slice(action.nested.length),
nextID: oldState.nextID + action.actions.length,
sentActions: [...oldState.sentActions, ...action.actions],
pendingActions: oldState.pendingActions.slice(action.actions.length),
}
}
}

@ -7,7 +7,7 @@ import {
SERVER_HELLO,
SERVER_OK,
SERVER_REFRESH,
SERVER_SENT,
SERVER_ACT,
SERVER_SOCKET_STARTUP,
ServerAction,
ServerFailedAction,
@ -15,7 +15,7 @@ import {
ServerHelloAction,
ServerOKAction,
ServerRefreshAction,
ServerSentAction,
ServerActAction,
ServerSocketStartupAction,
SocketState,
SyncableAction,
@ -131,6 +131,8 @@ function serverOkReducer(oldState: AppState, action: ServerOKAction): AppState {
for (let index = 0; index < action.ids.length; index += 1) {
okIndexes[action.ids[index]] = true
}
// TODO: Technically, the server is not obligated to apply the actions in order, so this should reconstruct the
// array the way the server put it. In practice, this is how the server behaves, so it does no harm.
const receivedActions = oldState.network.sentActions.filter((sent) => !!okIndexes[sent.id]).map((sent) => sent.action)
const stillWaitingActions = oldState.network.sentActions.filter((sent) => !okIndexes[sent.id])
const {newServerState, newLocalState, appliedUnsentActions} = recalculateStates({
@ -209,7 +211,7 @@ function serverSocketStartupReducer(oldState: NetworkState, action: ServerSocket
}
}
function serverSentReducer(oldState: AppState, action: ServerSentAction): AppState {
function serverSentReducer(oldState: AppState, action: ServerActAction): AppState {
if (oldState.network.serverState === null) {
return oldState
}
@ -259,7 +261,7 @@ export function serverReducer(oldState: AppState, action: ServerAction): AppStat
...oldState,
network: serverSocketStartupReducer(oldState.network, action)
}
case SERVER_SENT:
case SERVER_ACT:
return serverSentReducer(oldState, action)
}
}

@ -1,16 +1,15 @@
import {
ActionFailure,
CLIENT_SENT,
CLIENT_ACT,
ClientAction,
ClientSentAction,
isClientSentAction,
ClientActAction,
isClientActAction,
SendableAction,
SentAction,
SERVER_FAILED,
SERVER_GOODBYE,
SERVER_HELLO,
SERVER_OK,
SERVER_SENT,
SERVER_ACT,
SERVER_SOCKET_STARTUP,
ServerAction,
SocketState
@ -46,7 +45,7 @@ export function orientationFromString(string: string): HexMapRepresentation {
/** Fake "connection" to a "server" that actually just goes back and forth with the console. */
export class ConsoleConnection {
public receivedMessages: ClientAction[] = []
private dispatch: (action: ServerAction) => void
private readonly dispatch: (action: ServerAction) => void
constructor(dispatch: (action: ServerAction) => void) {
this.dispatch = dispatch
@ -54,8 +53,8 @@ export class ConsoleConnection {
receive(action: ClientAction): void {
this.receivedMessages.push(action)
if (isClientSentAction(action)) {
console.log(`Received Sent action containing: ${action.nested.map((value) => `${value.id}/${value.action.type}`).join(", ")}`)
if (isClientActAction(action)) {
console.log(`Received Sent action containing: ${action.actions.map((value) => `${value.id}/${value.action.type}`).join(", ")}`)
} else {
console.log(`Received: ${action.type}`)
}
@ -104,10 +103,11 @@ export class ConsoleConnection {
})
}
public sendFailed(failures: readonly ActionFailure[]): void {
public sendFailed(ids: readonly number[], error: string = "No thanks."): void {
this.dispatch({
type: SERVER_FAILED,
failures
ids,
error
})
}
@ -122,7 +122,7 @@ export class ConsoleConnection {
public sendColorChange(color: string = "#FF0000FF"): void {
this.dispatch({
type: SERVER_SENT,
type: SERVER_ACT,
actions: [{
type: USER_ACTIVE_COLOR,
color
@ -132,7 +132,7 @@ export class ConsoleConnection {
public sendColorAtTile(color: string = "#FFFF00FF", line: number = 0, cell: number = 0): void {
this.dispatch({
type: SERVER_SENT,
type: SERVER_ACT,
actions: [{
type: CELL_COLOR,
at: { line, cell },
@ -157,9 +157,9 @@ export function ConsoleConnector({specialMessage, pendingMessages, nextID}: {spe
const sentMessages: SentAction[] = pendingMessages.map((action, index) => {
return { id: index + nextID, action }
});
const sentMessage: ClientSentAction = {
type: CLIENT_SENT,
nested: sentMessages
const sentMessage: ClientActAction = {
type: CLIENT_ACT,
actions: sentMessages
};
connector.current.receive(sentMessage)
dispatch(sentMessage)

Loading…
Cancel
Save