Skip to content

Commit

Permalink
Merge pull request #135 from rune-js/promise-errors
Browse files Browse the repository at this point in the history
Adding cleaner error handling for promises.
  • Loading branch information
TheBlackParade authored Mar 18, 2020
2 parents d5b316e + 8894bde commit 96d281d
Show file tree
Hide file tree
Showing 21 changed files with 87 additions and 44 deletions.
42 changes: 42 additions & 0 deletions src/error-handling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { logger } from '@runejs/logger/dist/logger';

/*
* Error handling! Feel free to add other types of errors or warnings here. :)
*/

export class WidgetsClosedWarning extends Error {
constructor() {
super();
this.name = 'WidgetsClosedWarning';
this.message = 'The active widget was closed before the action could be completed.';
}
}

export class ActionsCancelledWarning extends Error {
constructor() {
super();
this.name = 'ActionsCancelledWarning';
this.message = 'Pending and active actions were cancelled before they could be completed.';
}
}

const warnings = [
WidgetsClosedWarning,
ActionsCancelledWarning
];

export function initErrorHandling(): void {
process.on('unhandledRejection', (error, promise) => {
for(const t of warnings) {
if(error instanceof t) {
logger.warn(`Promise cancelled with warning: ${error.name}`);
return;
}
}

logger.error(`Unhandled promise rejection from ${promise}, reason: ${error}`);
if(error.hasOwnProperty('stack')) {
logger.error((error as any).stack);
}
});
}
8 changes: 0 additions & 8 deletions src/game-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,6 @@ export function runGameServer(): void {
world.generateFakePlayers();
}

process.on('unhandledRejection', (err, promise) => {
if(err === 'WIDGET_CLOSED' || err === 'ACTION_CANCELLED') {
return;
}

logger.error(`Unhandled promise rejection from ${promise}, reason: ${err}`);
});

net.createServer(socket => {
logger.info('Socket opened');

Expand Down
2 changes: 2 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { runGameServer } from './game-server';
import { runWebServer } from './web-server';
import 'source-map-support/register';
import { initErrorHandling } from '@server/error-handling';
// import { dumpItems } from '@server/data-dump';

initErrorHandling();
runGameServer();
runWebServer();
// dumpItems();
12 changes: 6 additions & 6 deletions src/net/data-parser/client-login-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,25 @@ export class ClientLoginParser extends DataParser {

public parse(buffer?: RsBuffer): void {
if(!buffer) {
throw ('No data supplied for login');
throw new Error('No data supplied for login');
}

const loginType = buffer.readUnsignedByte();

if(loginType !== 16 && loginType !== 18) {
throw ('Invalid login type ' + loginType);
throw new Error('Invalid login type ' + loginType);
}

let loginEncryptedSize = buffer.readUnsignedByte() - (36 + 1 + 1 + 2);

if(loginEncryptedSize <= 0) {
throw ('Invalid login packet length ' + loginEncryptedSize);
throw new Error('Invalid login packet length ' + loginEncryptedSize);
}

const gameVersion = buffer.readIntBE();

if(gameVersion !== 435) {
throw ('Invalid game version ' + gameVersion);
throw new Error('Invalid game version ' + gameVersion);
}

const isLowDetail: boolean = buffer.readByte() === 1;
Expand All @@ -72,15 +72,15 @@ export class ClientLoginParser extends DataParser {
const blockId = decrypted.readByte();

if(blockId !== 10) {
throw ('Invalid block id ' + blockId);
throw new Error('Invalid block id ' + blockId);
}

const clientKey1 = decrypted.readIntBE();
const clientKey2 = decrypted.readIntBE();
const incomingServerKey = decrypted.readLongBE();

if(this.clientConnection.serverKey !== incomingServerKey) {
throw (`Server key mismatch - ${this.clientConnection.serverKey} != ${incomingServerKey}`);
throw new Error(`Server key mismatch - ${this.clientConnection.serverKey} != ${incomingServerKey}`);
}

const clientUuid = decrypted.readIntBE();
Expand Down
4 changes: 2 additions & 2 deletions src/net/data-parser/login-handshake-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class LoginHandshakeParser extends DataParser {

public parse(buffer: RsBuffer, packetId: number): void {
if(!buffer) {
throw ('No data supplied for login handshake');
throw new Error('No data supplied for login handshake');
}

if(packetId === 14) {
Expand All @@ -23,7 +23,7 @@ export class LoginHandshakeParser extends DataParser {

this.clientConnection.serverKey = serverKey;
} else {
throw 'Invalid login handshake packet id.';
throw new Error('Invalid login handshake packet id.');
}
}
}
2 changes: 1 addition & 1 deletion src/net/data-parser/update-server-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class UpdateServerParser extends DataParser {
}

if(!cacheFile || cacheFile.getBuffer().length === 0) {
throw `Cache file not found; file(${file}) with index(${index})`;
throw new Error(`Cache file not found; file(${file}) with index(${index})`);
}

const cacheFileBuffer = cacheFile.getBuffer();
Expand Down
4 changes: 2 additions & 2 deletions src/net/data-parser/version-handshake-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class VersionHandshakeParser extends DataParser {

public parse(buffer: RsBuffer, packetId: number): void {
if(!buffer) {
throw ('No data supplied for version handshake');
throw new Error('No data supplied for version handshake');
}

if(packetId === 15) {
Expand All @@ -18,7 +18,7 @@ export class VersionHandshakeParser extends DataParser {
outputBuffer.writeByte(gameVersion === 435 ? 0 : 6);
this.clientConnection.socket.write(outputBuffer.getData());
} else {
throw 'Invalid version handshake packet id.';
throw new Error('Invalid version handshake packet id.');
}
}
}
4 changes: 2 additions & 2 deletions src/plugins/commands/give-item-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ const action: commandAction = (details) => {
let amount: number = args.amount as number;

if(amount > 2000000000) {
throw `Unable to give more than 2,000,000,000.`;
throw new Error(`Unable to give more than 2,000,000,000.`);
}

const itemDefinition = gameCache.itemDefinitions.get(itemId);
if(!itemDefinition) {
throw `Item ID ${itemId} not found!`;
throw new Error(`Item ID ${itemId} not found!`);
}

let actualAmount = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/commands/new-dialogue-test-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const action: commandAction = (details) => {
player => [ Emote.GENERIC, `See ya around.` ]
]).then(() => {
// do something with dialogue result.
}).catch(() => {});
});
};

export default new RunePlugin({ type: ActionType.COMMAND, commands: 'd', action });
6 changes: 3 additions & 3 deletions src/plugins/npcs/lumbridge/lumbridge-farm-helpers-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ const millieDialogue: npcAction = (details) => {
player => [ Emote.HAPPY, `Great! Thanks for your help.` ]
],
`I'm fine, thanks.`, [
player => [ Emote.GENERIC, `Then I bring my wheat here?` ]
player => [ Emote.GENERIC, `I'm fine, thanks.` ]
]
]
]).catch(() => {});
]);
};

const gillieDialogue: npcAction = (details) => {
Expand Down Expand Up @@ -82,7 +82,7 @@ const gillieDialogue: npcAction = (details) => {
player => [ Emote.GENERIC, `I'm fine, thanks.` ],
]
]
]).catch(() => {});
]);
};

export default new RunePlugin([{
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/objects/ladders/ladder-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const action: objectAction = (details) => {
action({...details, option: `climb-${direction}`});
return;
}
}).catch(error => console.error(error));
});
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/quests/cooks-assistant-quest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ const startQuestAction: npcAction = (details) => {
`Go on your merry way!` ]
]
]
]).catch(error => console.error(error));
]);
};

function youStillNeed(quest: QuestProgress): DialogueTree {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/skills/skill-guide-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function parseSkillGuides(): SkillGuide[] {
const skillGuides = safeLoad(readFileSync('data/config/skill-guides.yaml', 'utf8'), { schema: JSON_SCHEMA }) as SkillGuide[];

if(!skillGuides || skillGuides.length === 0) {
throw 'Unable to read skill guides.';
throw new Error('Unable to read skill guides.');
}

logger.info(`${skillGuides.length} skill guides found.`);
Expand Down
17 changes: 12 additions & 5 deletions src/world/actor/dialogue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { gameCache } from '@server/game-server';
import { logger } from '@runejs/logger/dist/logger';
import _ from 'lodash';
import { wrapText } from '@server/util/strings';
import { ActionsCancelledWarning, WidgetsClosedWarning } from '@server/error-handling';

export enum Emote {
POMPOUS = 'POMPOUS',
Expand Down Expand Up @@ -328,7 +329,7 @@ async function runParsedDialogue(player: Player, dialogueTree: ParsedDialogueTre

for(let i = 0; i < dialogueTree.length; i++) {
if(stopLoop) {
return Promise.reject('ACTION_CANCELLED');
throw new ActionsCancelledWarning();
}

const sub: Subscription[] = [];
Expand Down Expand Up @@ -404,7 +405,8 @@ async function runParsedDialogue(player: Player, dialogueTree: ParsedDialogueTre
const lines = textDialogueAction.lines;

if(lines.length > 5) {
throw `Too many lines for text dialogue! Dialogue has ${lines.length} lines but the maximum is 5: ${JSON.stringify(lines)}`;
throw new Error(`Too many lines for text dialogue! Dialogue has ${lines.length} lines but ` +
`the maximum is 5: ${JSON.stringify(lines)}`);
}

widgetId = textWidgetIds[lines.length - 1];
Expand Down Expand Up @@ -461,7 +463,8 @@ async function runParsedDialogue(player: Player, dialogueTree: ParsedDialogueTre
const lines = actorDialogueAction.lines;

if(lines.length > 4) {
throw `Too many lines for actor dialogue! Dialogue has ${lines.length} lines but the maximum is 4: ${JSON.stringify(lines)}`;
throw new Error(`Too many lines for actor dialogue! Dialogue has ${lines.length} lines but ` +
`the maximum is 4: ${JSON.stringify(lines)}`);
}

const animation = actorDialogueAction.animation;
Expand Down Expand Up @@ -498,14 +501,18 @@ async function runParsedDialogue(player: Player, dialogueTree: ParsedDialogueTre
widgetId: widgetId,
type: 'CHAT',
closeOnWalk: true,
forceClosed: () => reject('WIDGET_CLOSED')
forceClosed: () => reject(new WidgetsClosedWarning())
};
}
}).then(() => {
sub.forEach(s => s.unsubscribe());
}).catch(error => {
sub.forEach(s => s.unsubscribe());
stopLoop = true;

if(!(error instanceof ActionsCancelledWarning) && !(error instanceof WidgetsClosedWarning)) {
throw error;
}
});
}

Expand All @@ -516,7 +523,7 @@ export async function dialogue(participants: (Player | NpcParticipant)[], dialog
const player = participants.find(p => p instanceof Player) as Player;

if(!player) {
return Promise.reject('Player instance not provided to dialogue action.');
throw new Error('Player instance not provided to dialogue action.');
}

let npcParticipants = participants.filter(p => !(p instanceof Player)) as NpcParticipant[];
Expand Down
7 changes: 4 additions & 3 deletions src/world/actor/player/action/dialogue-action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Player } from '@server/world/actor/player/player';
import { gameCache } from '@server/game-server';
import { Npc } from '@server/world/actor/npc/npc';
import { WidgetsClosedWarning } from '@server/error-handling';

export const dialogueWidgetIds = {
PLAYER: [ 64, 65, 66, 67 ],
Expand Down Expand Up @@ -85,11 +86,11 @@ export class DialogueAction {

public async dialogue(options: DialogueOptions): Promise<DialogueAction> {
if(options.lines.length < lineConstraints[options.type][0] || options.lines.length > lineConstraints[options.type][1]) {
throw 'Invalid line length.';
throw new Error('Invalid line length.');
}

if(options.type === 'NPC' && options.npc === undefined) {
throw 'NPC not supplied.';
throw new Error('NPC not supplied.');
}

this._action = null;
Expand Down Expand Up @@ -138,7 +139,7 @@ export class DialogueAction {
widgetId: widgetId,
type: 'CHAT',
closeOnWalk: true,
forceClosed: () => reject('WIDGET_CLOSED')
forceClosed: () => reject(new WidgetsClosedWarning())
};

const sub = this.p.dialogueInteractionEvent.subscribe(action => {
Expand Down
2 changes: 1 addition & 1 deletion src/world/actor/player/action/item-selection-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export async function itemSelectionAction(player: Player, type: 'COOKING' | 'MAK
widgetId = 309;
} else {
if(items.length > 5) {
throw `Too many items provided to the item selection action!`;
throw new Error(`Too many items provided to the item selection action!`);
}

widgetId = (301 + items.length);
Expand Down
5 changes: 2 additions & 3 deletions src/world/actor/player/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,13 +536,13 @@ export class Player extends Actor {
return Promise.resolve();
} else {
if(messages.length > 5) {
throw `Dialogues have a maximum of 5 lines!`;
throw new Error(`Dialogues have a maximum of 5 lines!`);
}

return dialogueAction(this, { type: 'TEXT', lines: messages }).then(async d => {
d.close();
return Promise.resolve();
}).catch(() => {});
});
}
}

Expand Down Expand Up @@ -733,7 +733,6 @@ export class Player extends Actor {
this.activeWidget = widget;
} else {
this.queuedWidgets.push(widget);
console.log(this.queuedWidgets);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/world/config/item-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function parseItemData(itemDefinitions: Map<number, ItemDefinition>): Map
const itemDataList = safeLoad(readFileSync('data/config/item-data.yaml', 'utf8'), { schema: JSON_SCHEMA }) as ItemData[];

if(!itemDataList || itemDataList.length === 0) {
throw 'Unable to read item data.';
throw new Error('Unable to read item data.');
}

const itemDetailsMap: Map<number, ItemDetails> = new Map<number, ItemDetails>();
Expand Down
2 changes: 1 addition & 1 deletion src/world/config/npc-spawn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function parseNpcSpawns(): NpcSpawn[] {
const npcSpawns = safeLoad(readFileSync('data/config/npc-spawns.yaml', 'utf8'), { schema: JSON_SCHEMA }) as NpcSpawn[];

if(!npcSpawns || npcSpawns.length === 0) {
throw 'Unable to read npc spawns.';
throw new Error('Unable to read npc spawns.');
}

logger.info(`${npcSpawns.length} npc spawns found.`);
Expand Down
2 changes: 1 addition & 1 deletion src/world/config/server-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function parseServerConfig(useDefault?: boolean): ServerConfig {
logger.warn('Server config not provided, using default...');
return parseServerConfig(true);
} else {
throw 'Syntax Error';
throw new Error('Syntax Error');
}
}

Expand Down
Loading

0 comments on commit 96d281d

Please sign in to comment.