Advertisement
the_usik

Application class

Aug 3rd, 2021
1,017
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import EventEmitter from "events";
  2. import { AntiCaptcha } from "./common/services/captcha";
  3. import ILAProxy, { IProxyData, ProxyType } from "./common/net/proxy";
  4. import { IVKAccount, IVKPureAccount } from "./types";
  5.  
  6. import {
  7.     initDataStorage, DataStorage,
  8.     getRandomString, checkConnection
  9. } from "./utils";
  10.  
  11. import ILAServiceCompound from "./vk/services";
  12. import { validateAccount } from "./vk/providers/validate_account";
  13. import { Logger } from "@utils/logger";
  14. import { ITask } from "./vk/services/listener";
  15.  
  16. type IlaEventType =
  17.     "added-accounts" | "added-proxies" |
  18.     "accounts-required" | "proxies-required" |
  19.     "tasks-required" | "anticaptcha-required" |
  20.     "auth-started" | "auth-stoped" | "auth-completed" |
  21.     "auth-error" | "connection-failed" | "anticaptcha-updated";
  22.  
  23. class ILAEventEmitter extends EventEmitter {
  24.     public on = (event: IlaEventType, fn: (...args: any[]) => void) => super.on(event, fn);
  25.     public emit = (event: IlaEventType, ...args: any[]) => super.emit(event, ...args);
  26. }
  27.  
  28. export class Application extends ILAEventEmitter {
  29.     private inited = false;
  30.     private serverConnected = false;
  31.  
  32.     private storage: DataStorage;
  33.     private services: ILAServiceCompound;
  34.  
  35.     private authHandler = {
  36.         error: (error) => {
  37.             Logger.error("[auth_error]:", error);
  38.             this.emit("auth-error", error);
  39.         },
  40.         complete: (accounts) => {
  41.             let invalidCount = 0;
  42.  
  43.             accounts.forEach(({ login, password, session }) => {
  44.                 const pure = { login, password };
  45.                 if (!session?.valid) {
  46.                     invalidCount++;
  47.                     return this.deleteAccount(pure);
  48.                 }
  49.  
  50.                 const account = this.findAccount(pure) as (IVKAccount | undefined);
  51.                 if (!account) return;
  52.  
  53.                 account.session = session;
  54.             });
  55.  
  56.             this.storage.accounts.save();
  57.             this.emit("auth-completed", {
  58.                 invalid: invalidCount,
  59.                 total: accounts.length
  60.             });
  61.         },
  62.         started: count => this.emit("auth-started", count),
  63.         stoped: count => this.emit("auth-stoped", count)
  64.     }
  65.  
  66.     private listenerHandler = {
  67.         started: (...args) => { Logger.log("Listener started event:", ...args) },
  68.         stoped: (...args) => { Logger.log("Listener stoped event:", ...args) },
  69.         error: (error) => { Logger.error("Listener error:", error) },
  70.         "task-completed": (...args) => { Logger.log("Task completed:", ...args) }
  71.     }
  72.  
  73.     public constructor() {
  74.         super();
  75.  
  76.         this.services = new ILAServiceCompound();
  77.         this.storage = initDataStorage();
  78.  
  79.         this.services.authenticator.setHandler((type, payload) => {
  80.             if (!this.authHandler[type]) return Logger.warn("Unhandled authorization response type:", type);
  81.             this.authHandler[type](payload);
  82.         });
  83.  
  84.         this.services.listener.setHandler((type, payload) => {
  85.             if (!this.listenerHandler[type]) return Logger.warn("Unhandled listener response type:", type);
  86.             this.listenerHandler[type](payload);
  87.         })
  88.     }
  89.  
  90.     public get isConnectionEstabilished() {
  91.         return this.serverConnected;
  92.     }
  93.  
  94.     public async init() {
  95.         if (this.inited) return Promise.resolve();
  96.  
  97.         await this.storage.read();
  98.         const { systemProxy } = this.storage.cache.data.settings;
  99.  
  100.         globalThis.SYSTEM_PROXY_DATA = systemProxy;
  101.  
  102.         this.storage.on("error", error => Logger.error("Storage error:", error));
  103.         this.storage.on("restored", (data: any) => Logger.log(`File "${data.file.name}" content restored.`));
  104.  
  105.         this.on("added-accounts", () => this.startAuthenticator());
  106.         this.on("added-proxies", () => this.services.authenticator.setProxies(this.storage.proxies.data))
  107.         this.on("anticaptcha-updated", key => this.services.authenticator.setAntiCaptchaKey(key));
  108.     }
  109.  
  110.     public async start() {
  111.         const { systemProxy } = this.getSettings();
  112.         const result = await checkConnection(systemProxy && ILAProxy.from(systemProxy));
  113.  
  114.         if (!result) {
  115.             this.serverConnected = false;
  116.             Logger.warn("Failed connection to the vk.com, mail. System proxy required");
  117.             return this.emit("connection-failed");
  118.         }
  119.  
  120.         this.serverConnected = true;
  121.         Logger.log("Success connection to the vk.com, mail.ru");
  122.     }
  123.  
  124.     public stop() { }
  125.  
  126.     public reset() { }
  127.  
  128.     public getAuthorizationStatus() {
  129.         return this.services.authenticator.isRunning;
  130.     }
  131.  
  132.     public async startAuthenticator() {
  133.         const {
  134.             antiCaptchaKey
  135.         } = this.getSettings();
  136.  
  137.         if (!this.serverConnected) {
  138.             return this.emit("connection-failed");
  139.         }
  140.  
  141.         const accounts = this.getAccounts({ authorized: false });
  142.         if (!accounts.length) return;
  143.  
  144.         const proxies = this.storage.proxies.data;
  145.  
  146.         if (!proxies.length) {
  147.             return this.emit("proxies-required");
  148.         }
  149.  
  150.         if (!antiCaptchaKey) {
  151.             return this.emit("anticaptcha-required");
  152.         }
  153.  
  154.         Logger.log("Starting authenticator...");
  155.  
  156.         this.services.authenticator.setAntiCaptchaKey(antiCaptchaKey);
  157.         this.services.authenticator.setProxies(proxies);
  158.         this.services.authenticator.setAccounts(accounts);
  159.         this.services.authenticator.start()
  160.             .catch(error => this.emit("auth-error", error));
  161.  
  162.         return true;
  163.     }
  164.  
  165.     public stopAuthenticator() {
  166.         this.services.authenticator.stop();
  167.     }
  168.  
  169.     public startListener() {
  170.         const { tasks } = this.storage.cache.data;
  171.         const accounts = this.getAccounts({ authorized: true });
  172.         const proxies = this.storage.proxies.data;
  173.  
  174.         if (!this.serverConnected) {
  175.             return this.emit("connection-failed");
  176.         }
  177.  
  178.         if (!accounts.length) {
  179.             return this.emit("accounts-required");
  180.         }
  181.  
  182.         if (!tasks.length) {
  183.             return this.emit("tasks-required");
  184.         }
  185.  
  186.         if (!proxies.length) {
  187.             return this.emit("proxies-required");
  188.         }
  189.  
  190.         Logger.log("Listener starting...");
  191.  
  192.         const { listener } = this.services;
  193.         listener.setTasks(tasks);
  194.         listener.setAccounts(accounts);
  195.         return listener.start();
  196.     }
  197.  
  198.     public async stopListener() {
  199.         const { listener } = this.services;
  200.         await listener.stop();
  201.     }
  202.  
  203.     public getListenerTasks() {
  204.         return this.storage.cache.data.tasks;
  205.     }
  206.  
  207.     public getListenerStatus() {
  208.         return this.services.listener.isRunning;
  209.     }
  210.  
  211.     public addAccountsString(text: string) {
  212.         const pattern = /(\S+):(\S+)/;
  213.         const dirtAccounts = text.trim().split("\n").map(line => {
  214.             const result = line.match(pattern);
  215.             if (!result) return false;
  216.  
  217.             const [, login, password] = result!;
  218.             return { login, password };
  219.         })
  220.         const pureAccounts = dirtAccounts.filter(a => a) as IVKPureAccount[];
  221.  
  222.         this.addAccounts(pureAccounts);
  223.  
  224.         return {
  225.             total: dirtAccounts.length,
  226.             added: pureAccounts.length
  227.         }
  228.     }
  229.  
  230.     private addAccounts(elementOrArray: IVKPureAccount | IVKPureAccount[]) {
  231.         const { accounts } = this.storage;
  232.         let oldSize = accounts.data.length;
  233.  
  234.         (Array.isArray(elementOrArray))
  235.             ? elementOrArray.forEach(this.addUniqueAccount.bind(this))
  236.             : this.addUniqueAccount(elementOrArray);
  237.  
  238.         accounts.save();
  239.  
  240.         const newAccounts = accounts.data.slice(oldSize, accounts.data.length);
  241.         this.emit("added-accounts", newAccounts);
  242.  
  243.         return this;
  244.     }
  245.  
  246.     private addUniqueAccount(account: IVKPureAccount) {
  247.         const accountsFile = this.storage.accounts;
  248.         const result = this.findAccount(account);
  249.  
  250.         if (result) return false;
  251.  
  252.         this.normalizeAccount(account);
  253.         accountsFile.data.push(account);
  254.  
  255.         return true;
  256.     }
  257.  
  258.     private findAccount(account: IVKPureAccount, returnIndex = false) {
  259.         const { data } = this.storage.accounts;
  260.         const predicate = a => a.login == account.login && a.password == account.password;
  261.         return returnIndex ? data.findIndex(predicate) : data.find(predicate);
  262.     }
  263.  
  264.     private normalizeAccount(account: IVKAccount) {
  265.         account.session = {
  266.             cookies: {},
  267.             valid: true
  268.         }
  269.  
  270.         return account;
  271.     }
  272.  
  273.     private deleteAccount(account: IVKPureAccount) {
  274.         const index = this.findAccount(account, true) as number;
  275.         if (index == -1) return false;
  276.  
  277.         this.storage.accounts.data.splice(index, 1);
  278.  
  279.         return true;
  280.     }
  281.  
  282.     private deleteInvalidAccounts() {
  283.         const invalidAccounts = this.getInvalidAccounts();
  284.         const invalidCount = invalidAccounts.length;
  285.         if (!invalidAccounts.length) return null;
  286.         const deletedCount = invalidAccounts
  287.             .map(this.deleteAccount.bind(this))
  288.             .filter(status => status)
  289.             .length;
  290.  
  291.         return Object.freeze({ invalidCount, deletedCount });
  292.     }
  293.  
  294.     public clearAccounts() {
  295.         this.storage.accounts.data = [];
  296.         return this.storage.accounts.save();
  297.     }
  298.  
  299.     public clearSessions() {
  300.         const accountsFile = this.storage.accounts;
  301.         const accounts = accountsFile.data;
  302.         accounts.forEach(account => delete account.session);
  303.  
  304.         return accountsFile.save();
  305.     }
  306.  
  307.     public validateAccounts(accounts = this.getAuthorizedAccounts()) {
  308.         const pure = accounts.filter(validateAccount);
  309.         return Promise.all(pure);
  310.     }
  311.  
  312.     public getAccounts(filter?: { authorized?: boolean }): IVKAccount[] {
  313.         if (!filter) return this.storage.accounts.data;
  314.  
  315.         if (filter.authorized != undefined) {
  316.             return !filter.authorized
  317.                 ? this.getUnauthorizedAccounts()
  318.                 : this.getAuthorizedAccounts();
  319.         }
  320.  
  321.         return this.storage.accounts.data;
  322.     }
  323.  
  324.     private getUnauthorizedAccounts = (accounts = this.getAccounts()) => accounts.filter(account => this.isValidAccount(account) && !this.isAuthorizedAccount(account));
  325.     private getInvalidAccounts = (accounts = this.getAccounts()) => accounts.filter(account => !this.isValidAccount(account));
  326.     private getAuthorizedAccounts = (accounts = this.getAccounts()) => accounts.filter(this.isAuthorizedAccount);
  327.     private isAuthorizedAccount = (account: IVKAccount) => account.session && account.session?.valid && account.session?.cookies?.base;
  328.     private isValidAccount = (account: IVKAccount) => account.session?.valid;
  329.  
  330.     public addProxies(type: ProxyType, content: string) {
  331.         const lines = content.trim().split("\n");
  332.         const proxies = lines.map(line => {
  333.             const proxy = ILAProxy.fromString(type, line).getProxyData();
  334.             const finded = this.findProxy(proxy);
  335.             return finded ? false : proxy;
  336.         }).filter(proxy => proxy) as IProxyData[];
  337.  
  338.         this.storage.proxies.data = [
  339.             ...this.getProxies(),
  340.             ...proxies
  341.         ];
  342.         this.storage.proxies.save();
  343.         this.emit("added-proxies");
  344.  
  345.         return true;
  346.     }
  347.  
  348.     private findProxy(proxy: IProxyData) {
  349.         return this.storage.proxies.data.find(a => {
  350.             return a.address == proxy.address && a.port == proxy.port && a.type == proxy.type;
  351.         });
  352.     }
  353.  
  354.     public deleteProxy() { }
  355.     public clearProxies() { }
  356.     public getProxies() {
  357.         return this.storage.proxies.data;
  358.     }
  359.  
  360.     public validateProxy() { }
  361.     public validateProxies() { }
  362.  
  363.     public addTask(data: any) {
  364.         const task: ITask = {
  365.             enable: true,
  366.             id: getRandomString(16),
  367.             monetize: true,
  368.             performed: false,
  369.             playlist: data.playlist,
  370.             progress: {
  371.                 initial: data.playlist.listens,
  372.                 actual: data.playlist.listens,
  373.                 target: data.playlist.listens + data.totalCount
  374.             },
  375.             speed: 0
  376.         }
  377.  
  378.         const cache = this.storage.cache.data;
  379.         cache.tasks.push(task);
  380.         this.storage.cache.save()
  381.             .then(() => Logger.log("addTask(): cache saved..."))
  382.             .catch(error => Logger.error("addTask(): cache saving error:", error));
  383.  
  384.         this.startListener();
  385.  
  386.         return;
  387.     }
  388.  
  389.     public reloadTask() { }
  390.     public reloadTasks() { }
  391.     public deleteTask(id: string) {
  392.         const { listener } = this.services;
  393.         if (listener.isRunning) {
  394.             return this.services.listener.deleteTask(id);
  395.         }
  396.  
  397.         const cache = this.storage.cache.data
  398.         const index = cache.tasks.findIndex(task => task.id == id);
  399.         if (index == -1) {
  400.             throw new Error("Task with specify id not found");
  401.         }
  402.  
  403.         cache.tasks.splice(index, 1);
  404.         return this.storage.cache.save();
  405.     }
  406.  
  407.     public clearTasks() { }
  408.  
  409.     public getTasks() {
  410.         return this.storage.cache.data.tasks
  411.     }
  412.  
  413.     public validateTasks() { }
  414.  
  415.     public getHistory() {
  416.         return this.storage.cache.data.tasksHistory;
  417.     }
  418.     public clearHistory() { }
  419.  
  420.     public async setAnticaptcha(key: string) {
  421.         const { settings } = this.storage.cache.data;
  422.  
  423.         if (settings.antiCaptchaKey == key) return true;
  424.  
  425.         const valid = await AntiCaptcha.isValidKey(key);
  426.         if (!valid) throw new Error("Key is invalid");
  427.  
  428.         AntiCaptcha.setKey(key);
  429.  
  430.         settings.antiCaptchaKey = key;
  431.         this.storage.cache.save();
  432.         this.emit("anticaptcha-updated", key);
  433.  
  434.         return true;
  435.     }
  436.  
  437.     public getAnticaptcha() {
  438.         return this.storage.cache.data.settings.antiCaptchaKey;
  439.     }
  440.  
  441.     public getSettings() {
  442.         const { cache } = this.storage;
  443.         return cache.data.settings;
  444.     }
  445.  
  446.     public async setSystemProxy(type: ProxyType, proxyString: string) {
  447.         try {
  448.  
  449.             const { cache } = this.storage;
  450.             const proxy = ILAProxy.fromString(type, proxyString);
  451.             const connected = await checkConnection(proxy);
  452.             if (!connected) return false;
  453.  
  454.             this.serverConnected = true;
  455.             cache.data.settings.systemProxy = proxy.getProxyData();
  456.             globalThis.SYSTEM_PROXY_DATA = proxy.getProxyData();
  457.  
  458.             return cache.save();
  459.         } catch (error) {
  460.             this.serverConnected = false;
  461.             return false;
  462.         }
  463.     }
  464.  
  465.     public save() {
  466.         return this.storage.save();
  467.     }
  468. }
  469.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement