<commit_before>import { sync, Sync } from 'common';
import { PoolOpts, WorkerOpts, Work } from './types';
import Protocol from './stockfishProtocol';

export abstract class AbstractWorker {
  protected url: string;
  protected poolOpts: PoolOpts;
  protected workerOpts: WorkerOpts;
  protected protocol: Sync<Protocol>;

  constructor(url: string, poolOpts: PoolOpts, workerOpts: WorkerOpts) {
    this.url = url;
    this.poolOpts = poolOpts;
    this.workerOpts = workerOpts;
    this.protocol = sync(this.boot());
  }

  stop(): Promise<void> {
    return this.protocol.promise.then(protocol => protocol.stop());
  }

  start(work: Work) {
    const timeout = new Promise((_resolve, reject) => {
      setTimeout(reject, 1000);
    });

    Promise.race([this.stop(), timeout]).catch(() => {
      this.destroy();
      this.protocol = sync(this.boot());
    }).then(() => {
      this.protocol.promise.then(protocol => protocol.start(work));
    });
  }

  isComputing(): boolean {
    return !!this.protocol.sync && this.protocol.sync.isComputing();
  }

  abstract boot(): Promise<Protocol>;
  abstract send(cmd: string): void;
  abstract destroy(): void;
}

class WebWorker extends AbstractWorker {
  worker: Worker;

  boot(): Promise<Protocol> {
    this.worker = new Worker(this.url);
    const protocol = new Protocol(this.send.bind(this), this.workerOpts);
    this.worker.addEventListener('message', e => {
      protocol.received(e.data);
    }, true);
    return Promise.resolve(protocol);
  }

  destroy() {
    this.worker.terminate();
  }

  send(cmd: string) {
    this.worker.postMessage(cmd);
  }
}

class PNaClWorker extends AbstractWorker {
  private worker?: HTMLObjectElement;

  boot(): Promise<Protocol> {
    return new Promise((resolve, reject) => {
      try {
        this.worker = document.createElement('object');
        this.worker.width = '0';
        this.worker.height = '0';
        this.worker.data = this.url;
        this.worker.type = 'application/x-pnacl';
        this.worker.addEventListener('crash', () => { this.poolOpts.onCrash((this.worker as any).lastError); });
        this.worker.addEventListener('error', () => { this.poolOpts.onCrash((this.worker as any).lastError); });
        this.worker.addEventListener('load', () => {
          resolve(new Protocol(this.send.bind(this), this.workerOpts));
        });
        this.worker.addEventListener('message', e => {
          if (this.protocol.sync) this.protocol.sync.received((e as any).data);
        }, true);
        document.body.appendChild(this.worker);
      } catch (err) {
        console.log('exception while booting pnacl', err);
        this.destroy();
        this.poolOpts.onCrash(err);
        reject(err);
      }
    });
  }

  destroy() {
    if (this.worker) this.worker.remove();
    delete this.worker;
  }

  send(cmd: string) {
    if (this.worker) (this.worker as any).postMessage(cmd);
  }
}<commit_msg>make pnacl error handling more robust<commit_after>import { sync, Sync } from 'common';
import { PoolOpts, WorkerOpts, Work } from './types';
import Protocol from './stockfishProtocol';

export abstract class AbstractWorker {
  protected url: string;
  protected poolOpts: PoolOpts;
  protected workerOpts: WorkerOpts;
  protected protocol: Sync<Protocol>;

  constructor(url: string, poolOpts: PoolOpts, workerOpts: WorkerOpts) {
    this.url = url;
    this.poolOpts = poolOpts;
    this.workerOpts = workerOpts;
    this.protocol = sync(this.boot());
  }

  stop(): Promise<void> {
    return this.protocol.promise.then(protocol => protocol.stop());
  }

  start(work: Work) {
    const timeout = new Promise((_resolve, reject) => {
      setTimeout(reject, 1000);
    });

    Promise.race([this.stop(), timeout]).catch(() => {
      this.destroy();
      this.protocol = sync(this.boot());
    }).then(() => {
      this.protocol.promise.then(protocol => protocol.start(work));
    });
  }

  isComputing(): boolean {
    return !!this.protocol.sync && this.protocol.sync.isComputing();
  }

  abstract boot(): Promise<Protocol>;
  abstract send(cmd: string): void;
  abstract destroy(): void;
}

class WebWorker extends AbstractWorker {
  worker: Worker;

  boot(): Promise<Protocol> {
    this.worker = new Worker(this.url);
    const protocol = new Protocol(this.send.bind(this), this.workerOpts);
    this.worker.addEventListener('message', e => {
      protocol.received(e.data);
    }, true);
    return Promise.resolve(protocol);
  }

  destroy() {
    this.worker.terminate();
  }

  send(cmd: string) {
    this.worker.postMessage(cmd);
  }
}

class PNaClWorker extends AbstractWorker {
  private listener?: HTMLElement;
  private worker?: HTMLObjectElement;

  boot(): Promise<Protocol> {
    return new Promise((resolve, reject) => {
      try {
        // Use a listener div to ensure listeners are active before the
        // load event fires.
        this.listener = document.createElement('div');
        this.listener.addEventListener('load', () => {
          resolve(new Protocol(this.send.bind(this), this.workerOpts));
        }, true);
        this.listener.addEventListener('error', e => {
          this.poolOpts.onCrash(e);
          reject(e);
        }, true);
        this.listener.addEventListener('message', e => {
          if (this.protocol.sync) this.protocol.sync.received((e as any).data);
        }, true);
        this.listener.addEventListener('crash', e => {
          const err = this.worker ? (this.worker as any).lastError : e;
          this.poolOpts.onCrash(err);
        }, true);
        document.body.appendChild(this.listener);

        this.worker = document.createElement('object');
        this.worker.width = '0';
        this.worker.height = '0';
        this.worker.data = this.url;
        this.worker.type = 'application/x-pnacl';
        this.listener.appendChild(this.worker);
      } catch (err) {
        console.log('exception while booting pnacl', err);
        this.destroy();
        this.poolOpts.onCrash(err);
        reject(err);
      }
    });
  }

  destroy() {
    if (this.worker) this.worker.remove();
    delete this.worker;
    if (this.listener) this.listener.remove();
    delete this.listener;
  }

  send(cmd: string) {
    if (this.worker) (this.worker as any).postMessage(cmd);
  }
}
{'fraction_non_alphanumeric': 0.15214976995081708, 'fraction_numerical': 0.0019038553069966682, 'mean_word_length': 2.994930291508238, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '728966', 'n_tokens_mistral': 1887, 'n_tokens_neox': 1887, 'n_words': 393}