Skip to content

Commit

Permalink
bot: prevent concurrent logins
Browse files Browse the repository at this point in the history
  • Loading branch information
siddharthvp committed Nov 13, 2024
1 parent 21d5512 commit 144061a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,30 @@ export class Mwn {

/************** CORE FUNCTIONS *******************/

private loginInProgress: Promise<ApiResponse> = null;

/**
* Executes a Login
* @see https://www.mediawiki.org/wiki/API:Login
* @returns {Promise}
*/
async login(loginOptions?: { username?: string; password?: string; apiUrl?: string }): Promise<ApiResponse> {
// Avoid multiple logins taking place concurrently, for instance when session loss occurs
// in the middle of a batch operation.
if (!this.loginInProgress) {
this.loginInProgress = this.loginInternal(loginOptions);
this.loginInProgress.then(() => {
this.loginInProgress = null;
});
}
return this.loginInProgress;
}

private async loginInternal(loginOptions?: {
username?: string;
password?: string;
apiUrl?: string;
}): Promise<ApiResponse> {
this.options = merge(this.options, loginOptions);
if (!this.options.username || !this.options.password || !this.options.apiUrl) {
return rejectWithError({
Expand Down
15 changes: 15 additions & 0 deletions tests/login.bot.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const { Mwn, expect, verifyTokenAndSiteInfo } = require('./base/test_base');
const { bot: localBot, sinon } = require('./base/local_wiki');

const testwiki = require('./mocking/loginCredentials.js');

Expand All @@ -17,6 +18,20 @@ describe('login', async function () {
});
});

it('avoids concurrent logins', async function () {
const spy = sinon.spy(localBot, 'loginInternal');
const [mainPage, serverTime] = await Promise.all([localBot.read('Main Page'), localBot.getServerTime()]);
expect(spy).to.have.been.calledOnce;
sinon.restore();
expect(serverTime).to.be.a('string');
expect(mainPage).to.be.a('object');

await localBot.logout();
expect(localBot.loggedIn).to.be.false;
await localBot.login();
expect(localBot.loggedIn).to.be.true;
});

let bot = new Mwn();
it('successfully logs in through init', async function () {
bot = await Mwn.init(testwiki.account1);
Expand Down

0 comments on commit 144061a

Please sign in to comment.