Skip to content

Commit

Permalink
feat: Improved client, allow page refresh, better event listener
Browse files Browse the repository at this point in the history
  • Loading branch information
edgardmessias committed Dec 1, 2020
1 parent 5ea77e3 commit fec67ca
Show file tree
Hide file tree
Showing 28 changed files with 808 additions and 561 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.DS_Store
.idea/
*.tgz
/debug.log
006.png
api-docs
app.js
Expand All @@ -14,4 +16,3 @@ session
session-*
src/app.ts
tokens
.idea/
5 changes: 3 additions & 2 deletions src/api/layers/controls.layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNNMMNNNMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
*/
import { Page } from 'puppeteer';
import { CreateConfig } from '../../config/create-config';
import { UILayer } from './ui.layer';

export class ControlsLayer extends UILayer {
constructor(page: Page) {
super(page);
constructor(public page: Page, session?: string, options?: CreateConfig) {
super(page, session, options);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/api/layers/group.layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNNMMNNNMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
*/
import { Page } from 'puppeteer';
import { CreateConfig } from '../../config/create-config';
import { Id } from '../model';
import { RetrieverLayer } from './retriever.layer';

export class GroupLayer extends RetrieverLayer {
constructor(page: Page) {
super(page);
constructor(public page: Page, session?: string, options?: CreateConfig) {
super(page, session, options);
}

/**
Expand Down
263 changes: 261 additions & 2 deletions src/api/layers/host.layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,270 @@ MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNNMMNNNMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
*/
import { Page } from 'puppeteer';
import { CreateConfig, defaultOptions } from '../../config/create-config';
import { SocketState } from '../model/enum';
import { injectApi } from '../../controllers/browser';
import { ScrapQrcode } from '../model/qrcode';
import { scrapeImg } from '../helpers';
import {
asciiQr,
isAuthenticated,
isInsideChat,
retrieveQR,
} from '../../controllers/auth';
import { sleep } from '../../utils/sleep';
import { getSpinnies } from '../../utils/spinnies';
import * as Spinnies from 'spinnies';

export class HostLayer {
constructor(public page: Page) {
this.page = page;
readonly session: string;
readonly options: CreateConfig;

protected spinnies: Spinnies = getSpinnies();
protected spinStatus = {
apiInject: '',
autoCloseRemain: 0,
previousText: '',
previousStatus: null,
state: '',
};

protected autoCloseInterval = null;

constructor(public page: Page, session?: string, options?: CreateConfig) {
this.session = session;
this.options = { ...defaultOptions, ...options };

this.page.on('load', () => {
this.initialize();
});
this.page.on('close', () => {
this.cancelAutoClose();
this.spin('Page Closed', 'fail');
});
this.spin('Initializing...', 'spinning');
this.initialize();
}

protected spin(text?: string, status?: Spinnies.SpinnerStatus) {
const name = `session-${this.session}`;

text = text || this.spinStatus.previousText;
this.spinStatus.previousText = text;

status =
status || (this.spinStatus.previousStatus as Spinnies.SpinnerStatus);
this.spinStatus.previousStatus = status;

let fullText = `{session: ${this.session}`;
if (this.spinStatus.apiInject) {
fullText += `, apiInject: ${this.spinStatus.apiInject}`;
}
if (this.spinStatus.state) {
fullText += `, state: ${this.spinStatus.state}`;
}
if (this.autoCloseInterval) {
if (!this.options.disableSpins && this.spinStatus.autoCloseRemain > 0) {
fullText += `, autoCloneRemain: ${this.spinStatus.autoCloseRemain}`;
} else if (this.options.autoClose > 0) {
fullText += `, autoClose: ${Math.round(this.options.autoClose / 1000)}`;
}
}
fullText += `}: ${text}`;

let prevText = '';

try {
prevText = this.spinnies.pick(name).text;
} catch (error) {
this.spinnies.add(name, { text: fullText, status });
prevText = fullText;
}
if (prevText !== fullText) {
this.spinnies.update(name, {
text: fullText,
status,
});
}
}

protected async initialize() {
this.spinStatus.apiInject = 'injecting';
this.spin();
await injectApi(this.page)
.then(() => {
this.spinStatus.apiInject = 'injected';
})
.catch(() => {
this.spinStatus.apiInject = 'failed';
});
this.spin();
}

protected tryAutoClose() {
if (
this.options.autoClose > 0 &&
!this.autoCloseInterval &&
!this.page.isClosed()
) {
try {
this.page.close();
} catch (error) {}
}
}

protected startAutoClose() {
if (this.options.autoClose > 0 && !this.autoCloseInterval) {
let remain = this.options.autoClose;
this.autoCloseInterval = setInterval(() => {
if (this.page.isClosed()) {
this.cancelAutoClose();
return;
}
remain -= 1000;
this.spinStatus.autoCloseRemain = Math.round(remain / 1000);
this.spin();
if (remain <= 0) {
this.cancelAutoClose();
this.tryAutoClose();
}
}, 1000);
}
}

protected cancelAutoClose() {
clearInterval(this.autoCloseInterval);
this.autoCloseInterval = null;
this.spin();
}

public async getQrCode() {
let qrResult: ScrapQrcode | undefined;

qrResult = await scrapeImg(this.page).catch(() => undefined);
if (!qrResult || !qrResult.urlCode) {
qrResult = await retrieveQR(this.page).catch(() => undefined);
}

return qrResult;
}

public async waitForQrCodeScan(
catchQR?: (
qrCode: string,
asciiQR: string,
attempt: number,
urlCode?: string
) => void
) {
let urlCode = null;
let attempt = 0;

while (true) {
const result = await this.getQrCode();
if (!result || !result.urlCode) {
break;
}
if (urlCode !== result.urlCode) {
urlCode = result.urlCode;
attempt++;

let qr = '';

if (this.options.logQR || catchQR) {
qr = await asciiQr(urlCode);
}

if (this.options.logQR) {
this.spin(`Waiting for QRCode Scan (Attempt ${attempt})...:\n${qr}`);
} else {
this.spin(`Waiting for QRCode Scan: Attempt ${attempt}`);
}

if (catchQR) {
catchQR(result.base64Image, qr, attempt, result.urlCode);
}
}
await sleep(500);
}
}

public async waitForLogin(
catchQR?: (
qrCode: string,
asciiQR: string,
attempt: number,
urlCode?: string
) => void,
statusFind?: (statusGet: string, session: string) => void
) {
this.spin('Waiting page load', 'spinning');

await this.page
.waitForFunction(`document.readyState === 'complete'`)
.catch(() => {});

this.startAutoClose();

this.spin('Checking is logged...');
let authenticated = await isAuthenticated(this.page).catch(() => null);

if (authenticated === false) {
this.spin('Waiting for QRCode Scan...');
statusFind && statusFind('notLogged', this.session);
await this.waitForQrCodeScan(catchQR);

// Wait for interface update
await sleep(200);
authenticated = await isAuthenticated(this.page).catch(() => null);

if (authenticated) {
this.spin('QRCode Success');
statusFind && statusFind('qrReadSuccess', this.session);
} else {
this.spin('QRCode Fail', 'fail');
statusFind && statusFind('qrReadFail', this.session);
this.cancelAutoClose();
this.tryAutoClose();
throw 'Failed to read the QRCode';
}
} else if (authenticated === true) {
this.spin('Authenticated');
statusFind && statusFind('isLogged', this.session);
}

if (authenticated === true) {
// Wait for interface update
await sleep(200);
this.spin('Checking phone is connected...');
const inChat = await isInsideChat(this.page)
.toPromise()
.catch(() => false);

if (!inChat) {
this.spin('Phone not connected', 'fail');
statusFind && statusFind('phoneNotConnected', this.session);
this.cancelAutoClose();
this.tryAutoClose();
throw 'Phone not connected';
}
this.cancelAutoClose();
this.spin('Connected', 'succeed');
statusFind && statusFind('inChat', this.session);
return true;
}

if (authenticated === false) {
this.cancelAutoClose();
this.tryAutoClose();
this.spin('Not logged', 'fail');
throw 'Not logged';
}

this.cancelAutoClose();
this.tryAutoClose();
this.spin('Unknow error', 'fail');
throw 'Unknow error';
}

/**
Expand Down
Loading

0 comments on commit fec67ca

Please sign in to comment.