Skip to content

Commit

Permalink
Merge pull request #182 from project-slippi/feat/relay
Browse files Browse the repository at this point in the history
feat: add back console relay
  • Loading branch information
NikhilNarayana authored Jun 24, 2021
2 parents 952b5be + d4a46cc commit 44c810a
Show file tree
Hide file tree
Showing 10 changed files with 270 additions and 76 deletions.
73 changes: 73 additions & 0 deletions src/console/consoleRelay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Ports } from "@slippi/slippi-js";
import log from "electron-log";
import net from "net";

interface ConsoleDataBuffer {
buffersToConcat: Buffer[];
fullBuffer: Buffer;
}

export class ConsoleRelay {
private server: net.Server | null;
private dataBuffer: ConsoleDataBuffer;
private clients: net.Socket[];

public constructor(id: number) {
this.clients = [];
this.dataBuffer = {
buffersToConcat: [],
fullBuffer: Buffer.from([]),
};
this.server = net.createServer((socket) => {
socket.setNoDelay().setTimeout(20000);

// Only get the full buffer when the client connects for performance
const buf = this.getFullBuffer();
socket.write(buf);

this.clients.push(socket);
socket.on("close", (err) => {
if (err) {
console.warn(err);
}
this.clients = this.clients.filter((client) => socket !== client);
});
});
this.server.listen(Ports.RELAY_START + id, "0.0.0.0");
}

public stopRelay() {
this.clients.forEach((client) => client.destroy());
this.clients = [];
if (this.server !== null) {
this.server.close();
}
this.server = null;
}

public write(newData: Buffer) {
this.dataBuffer.buffersToConcat.push(newData);
if (this.clients) {
this.clients.forEach((client) => {
try {
client.write(newData);
} catch (err) {
log.warn(`Could not write to a client...${err}`);
}
});
}
}

public async clearBuffer() {
this.dataBuffer.buffersToConcat = [];
this.dataBuffer.fullBuffer = Buffer.from([]);
}

private getFullBuffer() {
if (this.dataBuffer.buffersToConcat.length > 0) {
this.dataBuffer.fullBuffer = Buffer.concat([this.dataBuffer.fullBuffer, ...this.dataBuffer.buffersToConcat]);
}
this.dataBuffer.buffersToConcat = [];
return this.dataBuffer.fullBuffer;
}
}
23 changes: 22 additions & 1 deletion src/console/mirrorManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import log from "electron-log";
import path from "path";

import { AutoSwitcher } from "./autoSwitcher";
import { ConsoleRelay } from "./consoleRelay";
import { consoleMirrorStatusUpdated } from "./ipc";
import { MirrorConfig, MirrorDetails } from "./types";

Expand Down Expand Up @@ -49,6 +50,7 @@ export class MirrorManager {
}

public async connect(config: MirrorConfig) {
log.info(config.id);
if (this.mirrors[config.ipAddress]) {
log.info(`[Mirroring] already connected to Wii @ ${config.ipAddress}`);
return;
Expand Down Expand Up @@ -83,6 +85,12 @@ export class MirrorManager {
.catch((err) => log.warn(err));
});

let relay: ConsoleRelay | null = null;
if (config.enableRelay) {
log.info("starting relay");
relay = new ConsoleRelay(config.id);
}

const connection = new ConsoleConnection();
connection.once("connect", () => {
log.info("[Mirroring] Connecting to Wii");
Expand Down Expand Up @@ -113,8 +121,14 @@ export class MirrorManager {
.catch((err) => log.warn(err));
});

connection.on(ConnectionEvent.DATA, (data) => fileWriter.write(data));
connection.on(ConnectionEvent.DATA, (data: Buffer) => {
fileWriter.write(data);
if (relay) {
relay.write(data);
}
});
});
log.info(config.port);
connection.connect(config.ipAddress, config.port ?? Ports.DEFAULT);

let autoSwitcher: AutoSwitcher | null = null;
Expand All @@ -141,6 +155,9 @@ export class MirrorManager {
if ((payload as GameEndType).gameEndMethod !== 7) {
autoSwitcher.handleStatusOutput(700);
}
if (relay) {
relay.clearBuffer(); // clear buffer after each game to avoid concating a gigantic array
}
break;
}
}
Expand All @@ -152,6 +169,7 @@ export class MirrorManager {
fileWriter,
connection,
autoSwitcher,
relay,
};
}

Expand All @@ -167,6 +185,9 @@ export class MirrorManager {
if (details.autoSwitcher) {
details.autoSwitcher.disconnect();
}
if (details.relay) {
details.relay.stopRelay();
}
delete this.mirrors[ip];

// FIXME: Not sure why the disconnected status update isn't working
Expand Down
5 changes: 4 additions & 1 deletion src/console/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ConsoleConnection, SlpFileWriter } from "@slippi/slippi-js";

import { AutoSwitcher } from "./autoSwitcher";
import { ConsoleRelay } from "./consoleRelay";

export interface ConsoleMirrorStatusUpdate {
status: number;
Expand All @@ -9,11 +10,12 @@ export interface ConsoleMirrorStatusUpdate {
}

export interface MirrorConfig {
id?: number;
id: number;
ipAddress: string;
port: number;
folderPath: string;
isRealTimeMode?: boolean;
enableRelay?: boolean;
autoSwitcherSettings?: AutoSwitcherSettings;
}

Expand All @@ -22,6 +24,7 @@ export interface MirrorDetails extends MirrorConfig {
connection: ConsoleConnection;
fileWriter: SlpFileWriter;
autoSwitcher: AutoSwitcher | null;
relay: ConsoleRelay | null;
}

export interface AutoSwitcherSettings {
Expand Down
4 changes: 2 additions & 2 deletions src/dolphin/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import path from "path";

import { DolphinLaunchType } from "./types";

export async function findDolphinExecutable(type: DolphinLaunchType | string, dolphinPath?: string): Promise<string> {
export async function findDolphinExecutable(type: DolphinLaunchType, dolphinPath?: string): Promise<string> {
// Make sure the directory actually exists
if (!dolphinPath) {
dolphinPath = settingsManager.getDolphinPath(type as DolphinLaunchType);
dolphinPath = settingsManager.getDolphinPath(type);
}

await fs.ensureDir(dolphinPath);
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/containers/Console/AddConnectionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import DialogTitle from "@material-ui/core/DialogTitle";
import { useTheme } from "@material-ui/core/styles";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { StoredConnection } from "@settings/types";
import { Ports } from "@slippi/slippi-js";
import merge from "lodash/merge";
import React from "react";

Expand Down Expand Up @@ -35,7 +36,7 @@ export const AddConnectionDialog: React.FC<AddConnectionDialogProps> = ({
setTitle(isEditing ? "Edit Connection" : "New Connection");
};
const defaultValues: Partial<StoredConnection> = merge(
{ isRealTimeMode: false, folderPath: spectateFolder },
{ isRealTimeMode: false, folderPath: spectateFolder, port: Ports.DEFAULT },
selectedConnection,
);
return (
Expand Down
Loading

0 comments on commit 44c810a

Please sign in to comment.