Skip to content

Commit

Permalink
Fail fast from Device commands if we didn't login successfully
Browse files Browse the repository at this point in the history
  • Loading branch information
dhleong committed Nov 7, 2018
1 parent f32c8f7 commit ac7e0a7
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 15 deletions.
63 changes: 58 additions & 5 deletions lib/device.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ class Device extends EventEmitter {
}

this._retryDelay = 500;
this._socket = null;
this._osk = null;
this._connectedAt = 0;

// init clean state
this._onClose();
}

/**
Expand Down Expand Up @@ -148,6 +148,9 @@ class Device extends EventEmitter {

const socket = await this.openSocket();

// ensure we're logged in properly
await this.login();

return new Promise((resolve, reject) => {
/* eslint-disable consistent-return */
socket.startOsk((err, packet) => {
Expand Down Expand Up @@ -202,6 +205,9 @@ class Device extends EventEmitter {

const socket = await this.openSocket();

// ensure we're logged in properly
await this.login();

const msSinceConnect = Date.now() - this._connectedAt;
const delay = POST_CONNECT_SENDKEY_DELAY - msSinceConnect;
if (delay > 0) {
Expand Down Expand Up @@ -268,6 +274,9 @@ class Device extends EventEmitter {
async startTitle(titleId) {
const socket = await this.openSocket();

// ensure we're logged in properly
await this.login();

return new Promise((resolve, reject) => {
socket.startTitle(titleId, (err) => {
if (err) return reject(err);
Expand Down Expand Up @@ -296,6 +305,9 @@ class Device extends EventEmitter {
return this;
}

// ensure we're logged in properly
await this.login();

const isRetry = arguments.length > 0;
const doRequestStandby = (resolve, reject) => {
socket.requestStandby((err) => {
Expand Down Expand Up @@ -323,6 +335,35 @@ class Device extends EventEmitter {
}
}

/**
* Connect to the device and wake it, if it's not already
* awake, and ensure we're logged in. In general, methods
* that require logged-in state (such as `turnOff()`) will
* call this for you, so you probably don't need to worry
* about it yourself.
*/
async login() {
const errorFromResult = (result) => {
if (!result.error) return null;
return new Error(`Failed to login: ${result.error} (${result.result})`);
};
if (this._loginResult !== null) {
const e = errorFromResult(this._loginResult);
if (e) throw e;
return this;
}

return new Promise((resolve, reject) => {
this.once('login_result', (packet) => {
const e = errorFromResult(packet);
if (e) reject(e);
else resolve(this);
});

this._connect(/* autoLogin: */ true);
});
}

/**
* If this device is awake, connect to it and
* resolve to the socket; otherwise, resolve
Expand All @@ -339,16 +380,23 @@ class Device extends EventEmitter {
* Connect to this device, waking it if necessary;
* @return the socket, or `undefined` if autoLogin is false
*/
async _connect() {
async _connect(autoLogin) {
if (this._socket) return this._socket;

// find the right device, if any
const result = await this._detect();

const opts = {
...this.opts,
};
if (autoLogin !== undefined) {
this.opts = autoLogin;
}

return new Promise((resolve, reject) => {
// we don't need to return anything from this callback:
// eslint-disable-next-line
this._waker().wake(this.opts, result.device, (err, socket) => {
this._waker().wake(opts, result.device, (err, socket) => {
if (err) return reject(err);
if (!this.opts.autoLogin) return resolve();
if (!socket) return reject(new Error('No socket'));
Expand All @@ -365,6 +413,8 @@ class Device extends EventEmitter {
}).on('ready', () => {
this.emit('ready', this);
}).on('login_result', (loginResult) => {
// NOTE: we're more likely to get this event from the waker
this._loginResult = loginResult;
this.emit('login_result', loginResult);
}).on('login_retry', () => {
this.emit('login_retry', this);
Expand Down Expand Up @@ -428,10 +478,12 @@ class Device extends EventEmitter {
});
}

/** reset state when disconnected */
_onClose() {
this._socket = null;
this._osk = null;
this._connectedAt = 0;
this._loginResult = null;
}

/** Create a new Waker instance */
Expand All @@ -452,6 +504,7 @@ class Device extends EventEmitter {
this.emit('logging-in', d);
}).on('login_result', (packet) => {
// yuck
this._loginResult = packet;
this.emit('login_result', packet);
});
}
Expand Down
12 changes: 6 additions & 6 deletions lib/ps4socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,6 @@ Ps4Socket.prototype.isLoggedIn = function() {
* called when we get the login_result event
*/
Ps4Socket.prototype.login = function(pinCodeOrConfig, callback) {
if (this.loggedIn) {
// perhaps our timeout was too aggressive
if (callback) callback(null);
return;
}

let config = pinCodeOrConfig || {};
if (typeof (config) === 'string' || typeof (config) === 'number') {
config = { pinCode: config };
Expand All @@ -239,6 +233,12 @@ Ps4Socket.prototype.login = function(pinCodeOrConfig, callback) {
config = {};
}

if (this.loggedIn) {
// perhaps our timeout was too aggressive
if (cb) cb(null);
return;
}

config = {
pinCode: '',
timeout: DEFAULT_LOGIN_TIMEOUT,
Expand Down
4 changes: 2 additions & 2 deletions lib/waker.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,15 @@ Waker.prototype._login = function(device, creds, loginOpts, callback, err) {
pinCode: '', // assume we're registered...?
});
socket.retries = 0;
socket.on('login_result', (packet) => {
socket.once('login_result', (packet) => {
if (packet.result !== 0) {
this.emit('login_result', packet);
}

if (this.config.keepSocket) {
callback(null, socket);
} else {
this.close();
socket.close();
callback(null);
}
}).on('error', (e) => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"dev": "babel lib -d dist -w",
"lint": "eslint lib",
"prepublish": "npm run build",
"test": "mocha --compilers js:@babel/register test test/"
"test": "mocha --require @babel/register test test/"
},
"repository": {
"type": "git",
Expand Down
24 changes: 23 additions & 1 deletion test/device-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class FakeWaker {
constructor() {
this.calls = [];
this.pendingResults = [];
this.loginResult = {}; // success by default
}

wake(opts, device, cb) {
Expand All @@ -92,6 +93,11 @@ class FakeWaker {
let result = this.pendingResults.shift();

cb(...result);

const [err, socket] = result;
if (socket) {
socket.emit('login_result', this.loginResult);
}
}
}

Expand Down Expand Up @@ -129,7 +135,9 @@ describe("Device", function() {
let _deviceDotEmit = device.emit.bind(device);
device.emit = function(...args) {
_deviceDotEmit(...args);
events.push(args);
if (args[0] !== 'login_result') {
events.push(args);
}
};

// patch setTimeout so we don't have to wait
Expand Down Expand Up @@ -264,6 +272,20 @@ describe("Device", function() {
return device.turnOff().should.become(device);
});

// NOTE: this test describes the behavior for all
// login-requiring methods:
it("Rejects early when login fails", function() {
pendingDetectPromise = Promise.resolve({
address: '123.456.789.0',
status: 'OK'
});

waker.pendingResults.push([null, socket]);
waker.loginResult = {error: "Login error"}

return device.turnOff().should.be.rejectedWith(/Login error/);
});

it("Errors on second error", function() {
pendingDetectPromise = Promise.resolve({
address: '123.456.789.0',
Expand Down

0 comments on commit ac7e0a7

Please sign in to comment.