Skip to content

Commit

Permalink
refactor: 🎨 migrate to socket module
Browse files Browse the repository at this point in the history
migrate from using the state feature of the shared module to the socket module
  • Loading branch information
drazisil committed Sep 28, 2024
1 parent 9dba87f commit f7ed2c2
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 220 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"rusty-motors-shard": "link:packages/shard",
"rusty-motors-shared": "link:packages/shared",
"rusty-motors-shared-packets": "link:packages/shared-packets",
"rusty-motors-socket": "link:src/socket",
"rusty-motors-transactions": "link:packages/transactions",
"sequelize": "^6.37.3",
"sqlite": "^5.1.1",
Expand Down
56 changes: 23 additions & 33 deletions packages/gateway/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import { randomUUID } from "node:crypto";
import {
type OnDataHandler,
type ServerLogger,
type ServiceResponse,
addSocket,
fetchStateFromDatabase,
getOnDataHandler,
removeSocket,
wrapSocket,
} from "rusty-motors-shared";
import { getServerLogger } from "rusty-motors-shared";
import { newSocket } from "rusty-motors-socket";

Check warning on line 25 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L25

Added line #L25 was not covered by tests

import { Socket } from "node:net";
import { getGatewayServer } from "./GatewayServer.js";
Expand Down Expand Up @@ -83,20 +80,20 @@ export function socketErrorHandler({
* @param {string} options.connectionId The connection ID
* @param {import("pino").Logger} [options.log=getServerLogger({ name: "socketEndHandler" })] The logger to use
*/
export function socketEndHandler({
connectionId,
log = getServerLogger({
name: "socketEndHandler",
}),
}: {
connectionId: string;
log?: ServerLogger;
}) {
log.debug(`Connection ${connectionId} ended`);

// Remove the socket from the global state
removeSocket(fetchStateFromDatabase(), connectionId).save();
}
// export function socketEndHandler({
// connectionId,
// log = getServerLogger({
// name: "socketEndHandler",
// }),
// }: {
// connectionId: string;
// log?: ServerLogger;
// }) {
// log.debug(`Connection ${connectionId} ended`);

// // Remove the socket from the global state
// removeSocket(fetchStateFromDatabase(), connectionId).save();
// }

/**
* Handle incoming TCP connections
Expand All @@ -122,14 +119,7 @@ export function onSocketConnection({
throw Error("localPort or remoteAddress is undefined");
}

// This is a new connection so generate a new connection ID
const newConnectionId = randomUUID();

// Wrap the socket and add it to the global state
const wrappedSocket = wrapSocket(incomingSocket, newConnectionId);

// Add the socket to the global state
addSocket(fetchStateFromDatabase(), wrappedSocket).save();
const socket = newSocket(incomingSocket);

Check warning on line 122 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L122

Added line #L122 was not covered by tests

// =======================
// Handle incoming socket in shadow mode
Expand All @@ -138,17 +128,17 @@ export function onSocketConnection({
try {
// Get expected message type
const messageType = getPortMessageType(localPort);
log.debug(`[${newConnectionId}] Expected message type: ${messageType}`);
log.debug(`[${socket.id}] Expected message type: ${messageType}`);

Check warning on line 131 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L131

Added line #L131 was not covered by tests

switch (messageType) {
case "Game": {
// Handle game messages
// Create a new user status
const userStatus = UserStatusManager.newUserStatus();
log.debug(`[${newConnectionId}] Created new user status`);
log.debug(`[${socket.id}] Created new user status`);

Check warning on line 138 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L138

Added line #L138 was not covered by tests

UserStatusManager.addUserStatus(userStatus);
log.debug(`[${newConnectionId}] Added user status to manager`);
log.debug(`[${socket.id}] Added user status to manager`);

Check warning on line 141 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L141

Added line #L141 was not covered by tests

break;
}
Expand All @@ -159,12 +149,12 @@ export function onSocketConnection({
}

default: {
log.warn(`[${newConnectionId}] No message type found`);
log.warn(`[${socket.id}] No message type found`);

Check warning on line 152 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L152

Added line #L152 was not covered by tests
break;
}
}
} catch (error) {
log.error(`[${newConnectionId}] Error handling socket: ${error}`);
log.error(`[${socket.id}] Error handling socket: ${error}`);

Check warning on line 157 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L157

Added line #L157 was not covered by tests
}

// This is a new TCP socket, so it's probably not using HTTP
Expand All @@ -182,7 +172,7 @@ export function onSocketConnection({
}

incomingSocket.on("error", (error) =>
socketErrorHandler({ connectionId: newConnectionId, error }),
socketErrorHandler({ connectionId: socket.id, error }),

Check warning on line 175 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L175

Added line #L175 was not covered by tests
);

// Add the data handler to the socket
Expand Down Expand Up @@ -212,7 +202,7 @@ export function onSocketConnection({
},
async () => {
portOnDataHandler({
connectionId: newConnectionId,
connectionId: socket.id,

Check warning on line 205 in packages/gateway/src/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/gateway/src/index.ts#L205

Added line #L205 was not covered by tests
message: rawMessage,
})
.then((response: ServiceResponse) => {
Expand Down
3 changes: 0 additions & 3 deletions packages/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ export {
createInitialState,
fetchStateFromDatabase,
addOnDataHandler,
addSocket,
getOnDataHandler,
removeSocket,
wrapSocket,
addEncryption,
getEncryption,
McosSession,
Expand Down
184 changes: 6 additions & 178 deletions packages/shared/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,9 @@

// eslint-disable-next-line no-unused-vars
import { Cipher, Decipher } from "crypto";
import { Socket } from "node:net";
import type { Logger } from "pino";
import { SerializedBufferOld } from "./SerializedBufferOld.js";
import { Serializable } from "rusty-motors-shared-packets";

/**
* @external RawMessage
* @see {@link "packages/shared/messageFactory.js.RawMessage"}
*/
import type { ServerLogger } from "./log.js";

/**
* State management for the gateway server.
Expand Down Expand Up @@ -146,47 +140,11 @@ export class McosSession {
}
}

/**
* @external net
* @see {@link https://nodejs.org/api/net.html}
*/

/**
* A wrapped socket.
*
* This is a socket that has been wrapped with a connection id.
* @interface
*/
interface WrappedSocket {
socket: Socket;
connectionId: string;
}

/**
* Wrap a socket with a connection id.
*
* @param {module:NetConnectOpts.Socket} socket The socket to wrap.
* @param {string} connectionId The connection id to wrap the socket with.
* @returns {WrappedSocket} The wrapped socket.
*/
export function wrapSocket(
socket: Socket,
connectionId: string,
): WrappedSocket {
return {
socket,
connectionId,
};
}

type OnDataHandlerArgs = {
connectionId: string;
message: Serializable;
log?: Logger;
log?: ServerLogger;
};
/**
* @requires module:packages/shared/RawMessage
*/

export interface ServiceResponse {
connectionId: string;
Expand Down Expand Up @@ -219,10 +177,10 @@ export type OnDataHandler = (
*/
export interface State {
filePaths: Record<string, string>;
sockets: Record<string, WrappedSocket>;
// sockets: Record<string, WrappedSocket>;
encryptions: Record<string, McosEncryption>;
sessions: Record<string, McosSession>;
queuedConnections: Record<string, WrappedSocket>;
// queuedConnections: Record<string, WrappedSocket>;
onDataHandlers: Record<string, OnDataHandler>;
save: (state?: State) => void;
}
Expand Down Expand Up @@ -250,10 +208,10 @@ export function createInitialState({
}): State {
return {
filePaths: {},
sockets: {},
// sockets: {},
encryptions: {},
sessions: {},
queuedConnections: {},
// queuedConnections: {},
onDataHandlers: {},
save: function (state?: State) {
if (typeof state === "undefined") {
Expand Down Expand Up @@ -320,136 +278,6 @@ export function getOnDataHandler(
return state.onDataHandlers[port.toString()];
}

/**
* Add a socket to the state.
*
* This function adds a socket to the state.
* The returned state is a new state object, and the original state is not
* modified. You should then call the save function on the new state to update
* the database.
*
* @param {State} state The state to add the socket to.
* @param {WrappedSocket} socket The socket to add to the state.
* @returns {State} The state with the socket added.
*/
export function addSocket(state: State, socket: WrappedSocket): State {
const sockets = state.sockets;
sockets[socket.connectionId] = socket;
return {
...state,
sockets,
};
}

/**
* Get a socket from the state.
*
* This function gets a socket from the state.
*
* @param {State} state The state to get the socket from.
* @param {string} connectionId The connection id of the socket to get.
* @returns {WrappedSocket | undefined} The socket with the given connection id, or undefined if no socket
*/
export function getSocket(
state: State,
connectionId: string,
): WrappedSocket | undefined {
return state.sockets[connectionId];
}

/**
* Get all the sockets from the state.
*
* This function gets all the sockets from the state.
*
* @param {State} state The state to get the sockets from.
* @returns {Record<string, WrappedSocket>} An array of all the sockets in the state.
*/
export function getSockets(state: State): Record<string, WrappedSocket> {
return state.sockets;
}

/**
* Remove a socket from the state.
*
* This function removes a socket from the state.
* The returned state is a new state object, and the original state is not
* modified. You should then call the save function on the new state to update
* the database.
*
* @param {State} state The state to remove the socket from.
* @param {string} connectionId The connection id of the socket to remove.
* @returns {State} The state with the socket removed.
*/
export function removeSocket(state: State, connectionId: string): State {
const sockets = state.sockets;
delete sockets[connectionId];
return {
...state,
sockets,
};
}

/**
* Add a queued connection to the state.
*
* This function adds a queued connection to the state.
* The returned state is a new state object, and the original state is not
* modified. You should then call the save function on the new state to update
* the database.
*
* @param {State} state The state to add the queued connection to.
* @param {WrappedSocket} socket The queued connection to add to the state.
* @returns {State} The state with the queued connection added.
*/
export function addQueuedConnection(
state: State,
socket: WrappedSocket,
): State {
const queuedConnections = state.queuedConnections;
queuedConnections[socket.connectionId] = socket;
return {
...state,
queuedConnections,
};
}

/**
* Get queued connections from the state.
*
* This function gets all the queued connections from the state.
*
* @param {State} state The state to get the queued connections from.
* @returns {string[]} An array of all the queued connections in the state.
*/
export function getQueuedConnections(state: State): string[] {
return Object.keys(state.queuedConnections);
}

/**
* Remove a queued connection from the state.
*
* This function removes a queued connection from the state.
* The returned state is a new state object, and the original state is not
* modified. You should then call the save function on the new state to update
* the database.
*
* @param {State} state The state to remove the queued connection from.
* @param {string} connectionId The connection id of the queued connection to remove.
* @returns {State} The state with the queued connection removed.
*/
export function removeQueuedConnection(
state: State,
connectionId: string,
): State {
const queuedConnections = state.queuedConnections;
delete queuedConnections[connectionId];
return {
...state,
queuedConnections,
};
}

/**
* Add an encryption to the state.
*
Expand Down
Loading

0 comments on commit f7ed2c2

Please sign in to comment.