<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const ErrorUtils = require('../vendor/core/ErrorUtils');
const Systrace = require('../Performance/Systrace');

const deepFreezeAndThrowOnMutationInDev = require('../Utilities/deepFreezeAndThrowOnMutationInDev');
const invariant = require('invariant');
const stringifySafe = require('../Utilities/stringifySafe');

export type SpyData = {
  type: number,
  module: ?string,
  method: string | number,
  args: any[],
};

const TO_JS = 0;
const TO_NATIVE = 1;

const MODULE_IDS = 0;
const METHOD_IDS = 1;
const PARAMS = 2;
const MIN_TIME_BETWEEN_FLUSHES_MS = 5;

// eslint-disable-next-line no-bitwise
const TRACE_TAG_REACT_APPS = 1 << 17;

const DEBUG_INFO_LIMIT = 32;

class MessageQueue {
  _lazyCallableModules: {[key: string]: (void) => Object};
  _queue: [number[], number[], any[], number];
  _successCallbacks: Map<number, ?Function>;
  _failureCallbacks: Map<number, ?Function>;
  _callID: number;
  _lastFlush: number;
  _eventLoopStartTime: number;
  _immediatesCallback: ?() => void;

  _debugInfo: {[number]: [number, number]};
  _remoteModuleTable: {[number]: string};
  _remoteMethodTable: {[number]: $ReadOnlyArray<string>};

  __spy: ?(data: SpyData) => void;

  constructor() {
    this._lazyCallableModules = {};
    this._queue = [[], [], [], 0];
    this._successCallbacks = new Map();
    this._failureCallbacks = new Map();
    this._callID = 0;
    this._lastFlush = 0;
    this._eventLoopStartTime = Date.now();
    this._immediatesCallback = null;

    if (__DEV__) {
      this._debugInfo = {};
      this._remoteModuleTable = {};
      this._remoteMethodTable = {};
    }

    (this: any).callFunctionReturnFlushedQueue = this.callFunctionReturnFlushedQueue.bind(
      this,
    );
    (this: any).callFunctionReturnResultAndFlushedQueue = this.callFunctionReturnResultAndFlushedQueue.bind(
      this,
    );
    (this: any).flushedQueue = this.flushedQueue.bind(this);
    (this: any).invokeCallbackAndReturnFlushedQueue = this.invokeCallbackAndReturnFlushedQueue.bind(
      this,
    );
  }

  /**
   * Public APIs
   */

  static spy(spyOrToggle: boolean | ((data: SpyData) => void)) {
    if (spyOrToggle === true) {
      MessageQueue.prototype.__spy = info => {
        console.log(
          `${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` +
            `${info.module ? info.module + '.' : ''}${info.method}` +
            `(${JSON.stringify(info.args)})`,
        );
      };
    } else if (spyOrToggle === false) {
      MessageQueue.prototype.__spy = null;
    } else {
      MessageQueue.prototype.__spy = spyOrToggle;
    }
  }

  callFunctionReturnFlushedQueue(
    module: string,
    method: string,
    args: any[],
  ): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__callFunction(module, method, args);
    });

    return this.flushedQueue();
  }

  callFunctionReturnResultAndFlushedQueue(
    module: string,
    method: string,
    args: any[],
  ): $TEMPORARY$array<?[Array<number>, Array<number>, Array<any>, number]> {
    let result;
    this.__guard(() => {
      result = this.__callFunction(module, method, args);
    });

    return [result, this.flushedQueue()];
  }

  invokeCallbackAndReturnFlushedQueue(
    cbID: number,
    args: any[],
  ): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__invokeCallback(cbID, args);
    });

    return this.flushedQueue();
  }

  flushedQueue(): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__callImmediates();
    });

    const queue = this._queue;
    this._queue = [[], [], [], this._callID];
    return queue[0].length ? queue : null;
  }

  getEventLoopRunningTime(): number {
    return Date.now() - this._eventLoopStartTime;
  }

  registerCallableModule(name: string, module: Object) {
    this._lazyCallableModules[name] = () => module;
  }

  registerLazyCallableModule(name: string, factory: void => Object) {
    let module: Object;
    let getValue: ?(void) => Object = factory;
    this._lazyCallableModules[name] = () => {
      if (getValue) {
        module = getValue();
        getValue = null;
      }
      return module;
    };
  }

  getCallableModule(name: string): any | null {
    const getValue = this._lazyCallableModules[name];
    return getValue ? getValue() : null;
  }

  callNativeSyncHook(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ): any {
    if (__DEV__) {
      invariant(
        global.nativeCallSyncHook,
        'Calling synchronous methods on native ' +
          'modules is not supported in Chrome.\n\n Consider providing alternative ' +
          'methods to expose this method in debug mode, e.g. by exposing constants ' +
          'ahead-of-time.',
      );
    }
    this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
    try {
      return global.nativeCallSyncHook(moduleID, methodID, params);
    } catch (e) {
      if (
        typeof e === 'object' &&
        e != null &&
        typeof e.framesToPop === 'undefined' &&
        /^Exception in HostFunction: /.test(e.message)
      ) {
        e.framesToPop = 2;
      }
      throw e;
    }
  }

  processCallbacks(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ) {
    if (onFail || onSucc) {
      if (__DEV__) {
        this._debugInfo[this._callID] = [moduleID, methodID];
        if (this._callID > DEBUG_INFO_LIMIT) {
          delete this._debugInfo[this._callID - DEBUG_INFO_LIMIT];
        }
        if (this._successCallbacks.size > 500) {
          const info = {};
          this._successCallbacks.forEach((_, callID) => {
            const debug = this._debugInfo[callID];
            const module = debug && this._remoteModuleTable[debug[0]];
            const method = debug && this._remoteMethodTable[debug[0]][debug[1]];
            info[callID] = {module, method};
          });
          console.error(
            `Please report: Excessive number of pending callbacks: ${
              this._successCallbacks.size
            }. Some pending callbacks that might have leaked by never being called from native code:`,
            info,
          );
        }
      }
      // Encode callIDs into pairs of callback identifiers by shifting left and using the rightmost bit
      // to indicate fail (0) or success (1)
      // eslint-disable-next-line no-bitwise
      onFail && params.push(this._callID << 1);
      // eslint-disable-next-line no-bitwise
      onSucc && params.push((this._callID << 1) | 1);
      this._successCallbacks.set(this._callID, onSucc);
      this._failureCallbacks.set(this._callID, onFail);
    }
    if (__DEV__) {
      global.nativeTraceBeginAsyncFlow &&
        global.nativeTraceBeginAsyncFlow(
          TRACE_TAG_REACT_APPS,
          'native',
          this._callID,
        );
    }
    this._callID++;
  }

  enqueueNativeCall(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ) {
    this.processCallbacks(moduleID, methodID, params, onFail, onSucc);

    this._queue[MODULE_IDS].push(moduleID);
    this._queue[METHOD_IDS].push(methodID);

    if (__DEV__) {
      // Validate that parameters passed over the bridge are
      // folly-convertible.  As a special case, if a prop value is a
      // function it is permitted here, and special-cased in the
      // conversion.
      const isValidArgument = val => {
        const t = typeof val;
        if (
          t === 'undefined' ||
          t === 'null' ||
          t === 'boolean' ||
          t === 'string'
        ) {
          return true;
        }
        if (t === 'number') {
          return isFinite(val);
        }
        if (t === 'function' || t !== 'object') {
          return false;
        }
        if (Array.isArray(val)) {
          return val.every(isValidArgument);
        }
        for (const k in val) {
          if (typeof val[k] !== 'function' && !isValidArgument(val[k])) {
            return false;
          }
        }
        return true;
      };

      // Replacement allows normally non-JSON-convertible values to be
      // seen.  There is ambiguity with string values, but in context,
      // it should at least be a strong hint.
      const replacer = (key, val) => {
        const t = typeof val;
        if (t === 'function') {
          return '<<Function ' + val.name + '>>';
        } else if (t === 'number' && !isFinite(val)) {
          return '<<' + val.toString() + '>>';
        } else {
          return val;
        }
      };

      // Note that JSON.stringify
      invariant(
        isValidArgument(params),
        '%s is not usable as a native method argument',
        JSON.stringify(params, replacer),
      );

      // The params object should not be mutated after being queued
      deepFreezeAndThrowOnMutationInDev((params: any));
    }
    this._queue[PARAMS].push(params);

    const now = Date.now();
    if (
      global.nativeFlushQueueImmediate &&
      now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS
    ) {
      const queue = this._queue;
      this._queue = [[], [], [], this._callID];
      this._lastFlush = now;
      global.nativeFlushQueueImmediate(queue);
    }
    Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
    if (__DEV__ && this.__spy && isFinite(moduleID)) {
      this.__spy({
        type: TO_NATIVE,
        module: this._remoteModuleTable[moduleID],
        method: this._remoteMethodTable[moduleID][methodID],
        args: params,
      });
    } else if (this.__spy) {
      this.__spy({
        type: TO_NATIVE,
        module: moduleID + '',
        method: methodID,
        args: params,
      });
    }
  }

  createDebugLookup(
    moduleID: number,
    name: string,
    methods: ?$ReadOnlyArray<string>,
  ) {
    if (__DEV__) {
      this._remoteModuleTable[moduleID] = name;
      this._remoteMethodTable[moduleID] = methods || [];
    }
  }

  // For JSTimers to register its callback. Otherwise a circular dependency
  // between modules is introduced. Note that only one callback may be
  // registered at a time.
  setImmediatesCallback(fn: () => void) {
    this._immediatesCallback = fn;
  }

  /**
   * Private methods
   */

  __guard(fn: () => void) {
    if (this.__shouldPauseOnThrow()) {
      fn();
    } else {
      try {
        fn();
      } catch (error) {
        ErrorUtils.reportFatalError(error);
      }
    }
  }

  // MessageQueue installs a global handler to catch all exceptions where JS users can register their own behavior
  // This handler makes all exceptions to be propagated from inside MessageQueue rather than by the VM at their origin
  // This makes stacktraces to be placed at MessageQueue rather than at where they were launched
  // The parameter DebuggerInternal.shouldPauseOnThrow is used to check before catching all exceptions and
  // can be configured by the VM or any Inspector
  __shouldPauseOnThrow(): boolean {
    return (
      // $FlowFixMe
      typeof DebuggerInternal !== 'undefined' &&
      DebuggerInternal.shouldPauseOnThrow === true // eslint-disable-line no-undef
    );
  }

  __callImmediates() {
    Systrace.beginEvent('JSTimers.callImmediates()');
    if (this._immediatesCallback != null) {
      this._immediatesCallback();
    }
    Systrace.endEvent();
  }

  __callFunction(module: string, method: string, args: any[]): any {
    this._lastFlush = Date.now();
    this._eventLoopStartTime = this._lastFlush;
    if (__DEV__ || this.__spy) {
      Systrace.beginEvent(`${module}.${method}(${stringifySafe(args)})`);
    } else {
      Systrace.beginEvent(`${module}.${method}(...)`);
    }
    if (this.__spy) {
      this.__spy({type: TO_JS, module, method, args});
    }
    const moduleMethods = this.getCallableModule(module);
    invariant(
      !!moduleMethods,
      'Module %s is not a registered callable module (calling %s)',
      module,
      method,
    );
    invariant(
      !!moduleMethods[method],
      'Method %s does not exist on module %s',
      method,
      module,
    );
    const result = moduleMethods[method].apply(moduleMethods, args);
    Systrace.endEvent();
    return result;
  }

  __invokeCallback(cbID: number, args: any[]) {
    this._lastFlush = Date.now();
    this._eventLoopStartTime = this._lastFlush;

    // The rightmost bit of cbID indicates fail (0) or success (1), the other bits are the callID shifted left.
    // eslint-disable-next-line no-bitwise
    const callID = cbID >>> 1;
    // eslint-disable-next-line no-bitwise
    const isSuccess = cbID & 1;
    const callback = isSuccess
      ? this._successCallbacks.get(callID)
      : this._failureCallbacks.get(callID);

    if (__DEV__) {
      const debug = this._debugInfo[callID];
      const module = debug && this._remoteModuleTable[debug[0]];
      const method = debug && this._remoteMethodTable[debug[0]][debug[1]];
      invariant(
        callback,
        `No callback found with cbID ${cbID} and callID ${callID} for ` +
          (method
            ? ` ${module}.${method} - most likely the callback was already invoked`
            : `module ${module || '<unknown>'}`) +
          `. Args: '${stringifySafe(args)}'`,
      );
      const profileName = debug
        ? '<callback for ' + module + '.' + method + '>'
        : cbID;
      if (callback && this.__spy) {
        this.__spy({type: TO_JS, module: null, method: profileName, args});
      }
      Systrace.beginEvent(
        `MessageQueue.invokeCallback(${profileName}, ${stringifySafe(args)})`,
      );
    }

    if (!callback) {
      return;
    }

    this._successCallbacks.delete(callID);
    this._failureCallbacks.delete(callID);
    callback(...args);

    if (__DEV__) {
      Systrace.endEvent();
    }
  }
}

module.exports = MessageQueue;
<commit_msg>Use `warnOnce` for excessive number of callbacks error (#26508)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const ErrorUtils = require('../vendor/core/ErrorUtils');
const Systrace = require('../Performance/Systrace');

const deepFreezeAndThrowOnMutationInDev = require('../Utilities/deepFreezeAndThrowOnMutationInDev');
const invariant = require('invariant');
const stringifySafe = require('../Utilities/stringifySafe');
const warnOnce = require('../Utilities/warnOnce');

export type SpyData = {
  type: number,
  module: ?string,
  method: string | number,
  args: any[],
};

const TO_JS = 0;
const TO_NATIVE = 1;

const MODULE_IDS = 0;
const METHOD_IDS = 1;
const PARAMS = 2;
const MIN_TIME_BETWEEN_FLUSHES_MS = 5;

// eslint-disable-next-line no-bitwise
const TRACE_TAG_REACT_APPS = 1 << 17;

const DEBUG_INFO_LIMIT = 32;

class MessageQueue {
  _lazyCallableModules: {[key: string]: (void) => Object};
  _queue: [number[], number[], any[], number];
  _successCallbacks: Map<number, ?Function>;
  _failureCallbacks: Map<number, ?Function>;
  _callID: number;
  _lastFlush: number;
  _eventLoopStartTime: number;
  _immediatesCallback: ?() => void;

  _debugInfo: {[number]: [number, number]};
  _remoteModuleTable: {[number]: string};
  _remoteMethodTable: {[number]: $ReadOnlyArray<string>};

  __spy: ?(data: SpyData) => void;

  constructor() {
    this._lazyCallableModules = {};
    this._queue = [[], [], [], 0];
    this._successCallbacks = new Map();
    this._failureCallbacks = new Map();
    this._callID = 0;
    this._lastFlush = 0;
    this._eventLoopStartTime = Date.now();
    this._immediatesCallback = null;

    if (__DEV__) {
      this._debugInfo = {};
      this._remoteModuleTable = {};
      this._remoteMethodTable = {};
    }

    (this: any).callFunctionReturnFlushedQueue = this.callFunctionReturnFlushedQueue.bind(
      this,
    );
    (this: any).callFunctionReturnResultAndFlushedQueue = this.callFunctionReturnResultAndFlushedQueue.bind(
      this,
    );
    (this: any).flushedQueue = this.flushedQueue.bind(this);
    (this: any).invokeCallbackAndReturnFlushedQueue = this.invokeCallbackAndReturnFlushedQueue.bind(
      this,
    );
  }

  /**
   * Public APIs
   */

  static spy(spyOrToggle: boolean | ((data: SpyData) => void)) {
    if (spyOrToggle === true) {
      MessageQueue.prototype.__spy = info => {
        console.log(
          `${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` +
            `${info.module ? info.module + '.' : ''}${info.method}` +
            `(${JSON.stringify(info.args)})`,
        );
      };
    } else if (spyOrToggle === false) {
      MessageQueue.prototype.__spy = null;
    } else {
      MessageQueue.prototype.__spy = spyOrToggle;
    }
  }

  callFunctionReturnFlushedQueue(
    module: string,
    method: string,
    args: any[],
  ): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__callFunction(module, method, args);
    });

    return this.flushedQueue();
  }

  callFunctionReturnResultAndFlushedQueue(
    module: string,
    method: string,
    args: any[],
  ): $TEMPORARY$array<?[Array<number>, Array<number>, Array<any>, number]> {
    let result;
    this.__guard(() => {
      result = this.__callFunction(module, method, args);
    });

    return [result, this.flushedQueue()];
  }

  invokeCallbackAndReturnFlushedQueue(
    cbID: number,
    args: any[],
  ): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__invokeCallback(cbID, args);
    });

    return this.flushedQueue();
  }

  flushedQueue(): null | [Array<number>, Array<number>, Array<any>, number] {
    this.__guard(() => {
      this.__callImmediates();
    });

    const queue = this._queue;
    this._queue = [[], [], [], this._callID];
    return queue[0].length ? queue : null;
  }

  getEventLoopRunningTime(): number {
    return Date.now() - this._eventLoopStartTime;
  }

  registerCallableModule(name: string, module: Object) {
    this._lazyCallableModules[name] = () => module;
  }

  registerLazyCallableModule(name: string, factory: void => Object) {
    let module: Object;
    let getValue: ?(void) => Object = factory;
    this._lazyCallableModules[name] = () => {
      if (getValue) {
        module = getValue();
        getValue = null;
      }
      return module;
    };
  }

  getCallableModule(name: string): any | null {
    const getValue = this._lazyCallableModules[name];
    return getValue ? getValue() : null;
  }

  callNativeSyncHook(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ): any {
    if (__DEV__) {
      invariant(
        global.nativeCallSyncHook,
        'Calling synchronous methods on native ' +
          'modules is not supported in Chrome.\n\n Consider providing alternative ' +
          'methods to expose this method in debug mode, e.g. by exposing constants ' +
          'ahead-of-time.',
      );
    }
    this.processCallbacks(moduleID, methodID, params, onFail, onSucc);
    try {
      return global.nativeCallSyncHook(moduleID, methodID, params);
    } catch (e) {
      if (
        typeof e === 'object' &&
        e != null &&
        typeof e.framesToPop === 'undefined' &&
        /^Exception in HostFunction: /.test(e.message)
      ) {
        e.framesToPop = 2;
      }
      throw e;
    }
  }

  processCallbacks(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ) {
    if (onFail || onSucc) {
      if (__DEV__) {
        this._debugInfo[this._callID] = [moduleID, methodID];
        if (this._callID > DEBUG_INFO_LIMIT) {
          delete this._debugInfo[this._callID - DEBUG_INFO_LIMIT];
        }
        if (this._successCallbacks.size > 500) {
          const info = {};
          this._successCallbacks.forEach((_, callID) => {
            const debug = this._debugInfo[callID];
            const module = debug && this._remoteModuleTable[debug[0]];
            const method = debug && this._remoteMethodTable[debug[0]][debug[1]];
            info[callID] = {module, method};
          });
          warnOnce(
            'excessive-number-of-pending-callbacks',
            `Please report: Excessive number of pending callbacks: ${
              this._successCallbacks.size
            }. Some pending callbacks that might have leaked by never being called from native code: ${stringifySafe(
              info,
            )}`,
          );
        }
      }
      // Encode callIDs into pairs of callback identifiers by shifting left and using the rightmost bit
      // to indicate fail (0) or success (1)
      // eslint-disable-next-line no-bitwise
      onFail && params.push(this._callID << 1);
      // eslint-disable-next-line no-bitwise
      onSucc && params.push((this._callID << 1) | 1);
      this._successCallbacks.set(this._callID, onSucc);
      this._failureCallbacks.set(this._callID, onFail);
    }
    if (__DEV__) {
      global.nativeTraceBeginAsyncFlow &&
        global.nativeTraceBeginAsyncFlow(
          TRACE_TAG_REACT_APPS,
          'native',
          this._callID,
        );
    }
    this._callID++;
  }

  enqueueNativeCall(
    moduleID: number,
    methodID: number,
    params: any[],
    onFail: ?Function,
    onSucc: ?Function,
  ) {
    this.processCallbacks(moduleID, methodID, params, onFail, onSucc);

    this._queue[MODULE_IDS].push(moduleID);
    this._queue[METHOD_IDS].push(methodID);

    if (__DEV__) {
      // Validate that parameters passed over the bridge are
      // folly-convertible.  As a special case, if a prop value is a
      // function it is permitted here, and special-cased in the
      // conversion.
      const isValidArgument = val => {
        const t = typeof val;
        if (
          t === 'undefined' ||
          t === 'null' ||
          t === 'boolean' ||
          t === 'string'
        ) {
          return true;
        }
        if (t === 'number') {
          return isFinite(val);
        }
        if (t === 'function' || t !== 'object') {
          return false;
        }
        if (Array.isArray(val)) {
          return val.every(isValidArgument);
        }
        for (const k in val) {
          if (typeof val[k] !== 'function' && !isValidArgument(val[k])) {
            return false;
          }
        }
        return true;
      };

      // Replacement allows normally non-JSON-convertible values to be
      // seen.  There is ambiguity with string values, but in context,
      // it should at least be a strong hint.
      const replacer = (key, val) => {
        const t = typeof val;
        if (t === 'function') {
          return '<<Function ' + val.name + '>>';
        } else if (t === 'number' && !isFinite(val)) {
          return '<<' + val.toString() + '>>';
        } else {
          return val;
        }
      };

      // Note that JSON.stringify
      invariant(
        isValidArgument(params),
        '%s is not usable as a native method argument',
        JSON.stringify(params, replacer),
      );

      // The params object should not be mutated after being queued
      deepFreezeAndThrowOnMutationInDev((params: any));
    }
    this._queue[PARAMS].push(params);

    const now = Date.now();
    if (
      global.nativeFlushQueueImmediate &&
      now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS
    ) {
      const queue = this._queue;
      this._queue = [[], [], [], this._callID];
      this._lastFlush = now;
      global.nativeFlushQueueImmediate(queue);
    }
    Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
    if (__DEV__ && this.__spy && isFinite(moduleID)) {
      this.__spy({
        type: TO_NATIVE,
        module: this._remoteModuleTable[moduleID],
        method: this._remoteMethodTable[moduleID][methodID],
        args: params,
      });
    } else if (this.__spy) {
      this.__spy({
        type: TO_NATIVE,
        module: moduleID + '',
        method: methodID,
        args: params,
      });
    }
  }

  createDebugLookup(
    moduleID: number,
    name: string,
    methods: ?$ReadOnlyArray<string>,
  ) {
    if (__DEV__) {
      this._remoteModuleTable[moduleID] = name;
      this._remoteMethodTable[moduleID] = methods || [];
    }
  }

  // For JSTimers to register its callback. Otherwise a circular dependency
  // between modules is introduced. Note that only one callback may be
  // registered at a time.
  setImmediatesCallback(fn: () => void) {
    this._immediatesCallback = fn;
  }

  /**
   * Private methods
   */

  __guard(fn: () => void) {
    if (this.__shouldPauseOnThrow()) {
      fn();
    } else {
      try {
        fn();
      } catch (error) {
        ErrorUtils.reportFatalError(error);
      }
    }
  }

  // MessageQueue installs a global handler to catch all exceptions where JS users can register their own behavior
  // This handler makes all exceptions to be propagated from inside MessageQueue rather than by the VM at their origin
  // This makes stacktraces to be placed at MessageQueue rather than at where they were launched
  // The parameter DebuggerInternal.shouldPauseOnThrow is used to check before catching all exceptions and
  // can be configured by the VM or any Inspector
  __shouldPauseOnThrow(): boolean {
    return (
      // $FlowFixMe
      typeof DebuggerInternal !== 'undefined' &&
      DebuggerInternal.shouldPauseOnThrow === true // eslint-disable-line no-undef
    );
  }

  __callImmediates() {
    Systrace.beginEvent('JSTimers.callImmediates()');
    if (this._immediatesCallback != null) {
      this._immediatesCallback();
    }
    Systrace.endEvent();
  }

  __callFunction(module: string, method: string, args: any[]): any {
    this._lastFlush = Date.now();
    this._eventLoopStartTime = this._lastFlush;
    if (__DEV__ || this.__spy) {
      Systrace.beginEvent(`${module}.${method}(${stringifySafe(args)})`);
    } else {
      Systrace.beginEvent(`${module}.${method}(...)`);
    }
    if (this.__spy) {
      this.__spy({type: TO_JS, module, method, args});
    }
    const moduleMethods = this.getCallableModule(module);
    invariant(
      !!moduleMethods,
      'Module %s is not a registered callable module (calling %s)',
      module,
      method,
    );
    invariant(
      !!moduleMethods[method],
      'Method %s does not exist on module %s',
      method,
      module,
    );
    const result = moduleMethods[method].apply(moduleMethods, args);
    Systrace.endEvent();
    return result;
  }

  __invokeCallback(cbID: number, args: any[]) {
    this._lastFlush = Date.now();
    this._eventLoopStartTime = this._lastFlush;

    // The rightmost bit of cbID indicates fail (0) or success (1), the other bits are the callID shifted left.
    // eslint-disable-next-line no-bitwise
    const callID = cbID >>> 1;
    // eslint-disable-next-line no-bitwise
    const isSuccess = cbID & 1;
    const callback = isSuccess
      ? this._successCallbacks.get(callID)
      : this._failureCallbacks.get(callID);

    if (__DEV__) {
      const debug = this._debugInfo[callID];
      const module = debug && this._remoteModuleTable[debug[0]];
      const method = debug && this._remoteMethodTable[debug[0]][debug[1]];
      invariant(
        callback,
        `No callback found with cbID ${cbID} and callID ${callID} for ` +
          (method
            ? ` ${module}.${method} - most likely the callback was already invoked`
            : `module ${module || '<unknown>'}`) +
          `. Args: '${stringifySafe(args)}'`,
      );
      const profileName = debug
        ? '<callback for ' + module + '.' + method + '>'
        : cbID;
      if (callback && this.__spy) {
        this.__spy({type: TO_JS, module: null, method: profileName, args});
      }
      Systrace.beginEvent(
        `MessageQueue.invokeCallback(${profileName}, ${stringifySafe(args)})`,
      );
    }

    if (!callback) {
      return;
    }

    this._successCallbacks.delete(callID);
    this._failureCallbacks.delete(callID);
    callback(...args);

    if (__DEV__) {
      Systrace.endEvent();
    }
  }
}

module.exports = MessageQueue;
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @providesModule StyleSheetTypes
 * @flow
 * @format
 */

'use strict';

import AnimatedNode from 'AnimatedNode';

export opaque type StyleSheetStyle: number = number;

export type ColorValue = null | string;
export type DimensionValue = null | number | string | AnimatedNode;

export type LayoutStyle = {
  +display?: 'none' | 'flex',
  +width?: DimensionValue,
  +height?: DimensionValue,
  +bottom?: DimensionValue,
  +end?: DimensionValue,
  +left?: DimensionValue,
  +right?: DimensionValue,
  +start?: DimensionValue,
  +top?: DimensionValue,
  +minWidth?: DimensionValue,
  +maxWidth?: DimensionValue,
  +minHeight?: DimensionValue,
  +maxHeight?: DimensionValue,
  +margin?: DimensionValue,
  +marginBottom?: DimensionValue,
  +marginEnd?: DimensionValue,
  +marginHorizontal?: DimensionValue,
  +marginLeft?: DimensionValue,
  +marginRight?: DimensionValue,
  +marginStart?: DimensionValue,
  +marginTop?: DimensionValue,
  +marginVertical?: DimensionValue,
  +padding?: DimensionValue,
  +paddingBottom?: DimensionValue,
  +paddingEnd?: DimensionValue,
  +paddingHorizontal?: DimensionValue,
  +paddingLeft?: DimensionValue,
  +paddingRight?: DimensionValue,
  +paddingStart?: DimensionValue,
  +paddingTop?: DimensionValue,
  +paddingVertical?: DimensionValue,
  +borderWidth?: number,
  +borderBottomWidth?: number,
  +borderEndWidth?: number,
  +borderLeftWidth?: number,
  +borderRightWidth?: number,
  +borderStartWidth?: number,
  +borderTopWidth?: number,
  +position?: 'absolute' | 'relative',
  +flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse',
  +flexWrap?: 'wrap' | 'nowrap',
  +justifyContent?:
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'space-between'
    | 'space-around'
    | 'space-evenly',
  +alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline',
  +alignSelf?:
    | 'auto'
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'stretch'
    | 'baseline',
  +alignContent?:
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'stretch'
    | 'space-between'
    | 'space-around',
  +overflow?: 'visible' | 'hidden' | 'scroll',
  +flex?: number,
  +flexGrow?: number,
  +flexShrink?: number,
  +flexBasis?: number | string,
  +aspectRatio?: number,
  +zIndex?: number,
  +direction?: 'inherit' | 'ltr' | 'rtl',
};

export type TransformStyle = {
  +transform?: $ReadOnlyArray<
    | {+perspective: number | AnimatedNode}
    | {+rotate: string}
    | {+rotateX: string}
    | {+rotateY: string}
    | {+rotateZ: string}
    | {+scale: number | AnimatedNode}
    | {+scaleX: number | AnimatedNode}
    | {+scaleY: number | AnimatedNode}
    | {+translateX: number | AnimatedNode}
    | {+translateY: number | AnimatedNode}
    | {
      +translate: [number | AnimatedNode, number | AnimatedNode] | AnimatedNode,
    }
    | {+skewX: string}
    | {+skewY: string}
    // TODO: what is the actual type it expects?
    | {+matrix: $ReadOnlyArray<number | AnimatedNode> | AnimatedNode},
  >,
};

export type ShadowStyle = {
  +shadowColor?: ColorValue,
  +shadowOffset?: {
    +width?: number,
    +height?: number,
  },
  +shadowOpacity?: number | AnimatedNode,
  +shadowRadius?: number,
};

export type ViewStyle = {
  ...$Exact<LayoutStyle>,
  ...$Exact<ShadowStyle>,
  ...$Exact<TransformStyle>,
  +backfaceVisibility?: 'visible' | 'hidden',
  +backgroundColor?: ColorValue,
  +borderColor?: ColorValue,
  +borderBottomColor?: ColorValue,
  +borderEndColor?: ColorValue,
  +borderLeftColor?: ColorValue,
  +borderRightColor?: ColorValue,
  +borderStartColor?: ColorValue,
  +borderTopColor?: ColorValue,
  +borderRadius?: number,
  +borderBottomEndRadius?: number,
  +borderBottomLeftRadius?: number,
  +borderBottomRightRadius?: number,
  +borderBottomStartRadius?: number,
  +borderTopEndRadius?: number,
  +borderTopLeftRadius?: number,
  +borderTopRightRadius?: number,
  +borderTopStartRadius?: number,
  +borderStyle?: 'solid' | 'dotted' | 'dashed',
  +borderWidth?: number,
  +borderBottomWidth?: number,
  +borderEndWidth?: number,
  +borderLeftWidth?: number,
  +borderRightWidth?: number,
  +borderStartWidth?: number,
  +borderTopWidth?: number,
  +opacity?: number | AnimatedNode,
  +elevation?: number,
};

export type TextStyle = {
  ...$Exact<ViewStyle>,
  +color?: ColorValue,
  +fontFamily?: string,
  +fontSize?: number,
  +fontStyle?: 'normal' | 'italic',
  +fontWeight?:
    | 'normal'
    | 'bold'
    | '100'
    | '200'
    | '300'
    | '400'
    | '500'
    | '600'
    | '700'
    | '800'
    | '900',
  +fontVariant?: $ReadOnlyArray<
    | 'small-caps'
    | 'oldstyle-nums'
    | 'lining-nums'
    | 'tabular-nums'
    | 'proportional-nums',
  >,
  +textShadowOffset?: {+width?: number, +height?: number},
  +textShadowRadius?: number,
  +textShadowColor?: ColorValue,
  +letterSpacing?: number,
  +lineHeight?: number,
  +textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify',
  +textAlignVertical?: 'auto' | 'top' | 'bottom' | 'center',
  +includeFontPadding?: boolean,
  +textDecorationLine?:
    | 'none'
    | 'underline'
    | 'line-through'
    | 'underline line-through',
  +textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed',
  +textDecorationColor?: ColorValue,
  +writingDirection?: 'auto' | 'ltr' | 'rtl',
};

export type ImageStyle = {
  ...$Exact<ViewStyle>,
  +resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
  +tintColor?: ColorValue,
  +overlayColor?: string,
};

export type Style = {
  ...$Exact<TextStyle>,
  +resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
  +tintColor?: ColorValue,
  +overlayColor?: string,
};

export type StyleProp<+T> =
  | null
  | void
  | T
  | StyleSheetStyle
  | number
  | false
  | ''
  | $ReadOnlyArray<StyleProp<T>>;

// export type ViewStyleProp = StyleProp<$Shape<ViewStyle<DimensionValue>>>;
// export type TextStyleProp = StyleProp<
//   $Shape<TextStyle<DimensionValue, ColorValue>>,
// >;
// export type ImageStyleProp = StyleProp<
//   $Shape<ImageStyle<DimensionValue, ColorValue>>,
// >;

export type StyleObj = StyleProp<$Shape<Style>>;
export type StyleValue = StyleObj;

export type ViewStyleProp = StyleObj;
export type TextStyleProp = StyleObj;
export type ImageStyleProp = StyleObj;

export type Styles = {
  +[key: string]: $Shape<Style>,
};
export type StyleSheet<+S: Styles> = $ObjMap<S, (Object) => StyleSheetStyle>;

/*
Utility type get non-nullable types for specific style keys.
Useful when a component requires values for certain Style Keys.
So Instead:
```
type Props = {position: string};
```
You should use:
```
type Props = {position: TypeForStyleKey<'position'>};
```

This will correctly give you the type 'absolute' | 'relative' instead of the
weak type of just string;
*/
export type TypeForStyleKey<+key: $Keys<Style>> = $ElementType<Style, key>;
<commit_msg>Using ReadOnly and Exact types for StyleSheet<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @providesModule StyleSheetTypes
 * @flow
 * @format
 */

'use strict';

import AnimatedNode from 'AnimatedNode';

export opaque type StyleSheetStyle: number = number;

export type ColorValue = null | string;
export type DimensionValue = null | number | string | AnimatedNode;

export type LayoutStyle = $ReadOnly<{|
  display?: 'none' | 'flex',
  width?: DimensionValue,
  height?: DimensionValue,
  bottom?: DimensionValue,
  end?: DimensionValue,
  left?: DimensionValue,
  right?: DimensionValue,
  start?: DimensionValue,
  top?: DimensionValue,
  minWidth?: DimensionValue,
  maxWidth?: DimensionValue,
  minHeight?: DimensionValue,
  maxHeight?: DimensionValue,
  margin?: DimensionValue,
  marginBottom?: DimensionValue,
  marginEnd?: DimensionValue,
  marginHorizontal?: DimensionValue,
  marginLeft?: DimensionValue,
  marginRight?: DimensionValue,
  marginStart?: DimensionValue,
  marginTop?: DimensionValue,
  marginVertical?: DimensionValue,
  padding?: DimensionValue,
  paddingBottom?: DimensionValue,
  paddingEnd?: DimensionValue,
  paddingHorizontal?: DimensionValue,
  paddingLeft?: DimensionValue,
  paddingRight?: DimensionValue,
  paddingStart?: DimensionValue,
  paddingTop?: DimensionValue,
  paddingVertical?: DimensionValue,
  borderWidth?: number,
  borderBottomWidth?: number,
  borderEndWidth?: number,
  borderLeftWidth?: number,
  borderRightWidth?: number,
  borderStartWidth?: number,
  borderTopWidth?: number,
  position?: 'absolute' | 'relative',
  flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse',
  flexWrap?: 'wrap' | 'nowrap',
  justifyContent?:
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'space-between'
    | 'space-around'
    | 'space-evenly',
  alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline',
  alignSelf?:
    | 'auto'
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'stretch'
    | 'baseline',
  alignContent?:
    | 'flex-start'
    | 'flex-end'
    | 'center'
    | 'stretch'
    | 'space-between'
    | 'space-around',
  overflow?: 'visible' | 'hidden' | 'scroll',
  flex?: number,
  flexGrow?: number,
  flexShrink?: number,
  flexBasis?: number | string,
  aspectRatio?: number,
  zIndex?: number,
  direction?: 'inherit' | 'ltr' | 'rtl',
|}>;

export type TransformStyle = $ReadOnly<{|
  transform?: $ReadOnlyArray<
    | {|+perspective: number | AnimatedNode|}
    | {|+rotate: string|}
    | {|+rotateX: string|}
    | {|+rotateY: string|}
    | {|+rotateZ: string|}
    | {|+scale: number | AnimatedNode|}
    | {|+scaleX: number | AnimatedNode|}
    | {|+scaleY: number | AnimatedNode|}
    | {|+translateX: number | AnimatedNode|}
    | {|+translateY: number | AnimatedNode|}
    | {|
      +translate: [number | AnimatedNode, number | AnimatedNode] | AnimatedNode,
    |}
    | {|+skewX: string|}
    | {|+skewY: string|}
    // TODO: what is the actual type it expects?
    | {|
      +matrix: $ReadOnlyArray<number | AnimatedNode> | AnimatedNode,
    |},
  >,
|}>;

export type ShadowStyle = $ReadOnly<{|
  shadowColor?: ColorValue,
  shadowOffset?: $ReadOnly<{|
    width?: number,
    height?: number,
  |}>,
  shadowOpacity?: number | AnimatedNode,
  shadowRadius?: number,
|}>;

export type ViewStyle = $ReadOnly<{|
  ...$Exact<LayoutStyle>,
  ...$Exact<ShadowStyle>,
  ...$Exact<TransformStyle>,
  backfaceVisibility?: 'visible' | 'hidden',
  backgroundColor?: ColorValue,
  borderColor?: ColorValue,
  borderBottomColor?: ColorValue,
  borderEndColor?: ColorValue,
  borderLeftColor?: ColorValue,
  borderRightColor?: ColorValue,
  borderStartColor?: ColorValue,
  borderTopColor?: ColorValue,
  borderRadius?: number,
  borderBottomEndRadius?: number,
  borderBottomLeftRadius?: number,
  borderBottomRightRadius?: number,
  borderBottomStartRadius?: number,
  borderTopEndRadius?: number,
  borderTopLeftRadius?: number,
  borderTopRightRadius?: number,
  borderTopStartRadius?: number,
  borderStyle?: 'solid' | 'dotted' | 'dashed',
  borderWidth?: number,
  borderBottomWidth?: number,
  borderEndWidth?: number,
  borderLeftWidth?: number,
  borderRightWidth?: number,
  borderStartWidth?: number,
  borderTopWidth?: number,
  opacity?: number | AnimatedNode,
  elevation?: number,
|}>;

export type TextStyle = $ReadOnly<{|
  ...$Exact<ViewStyle>,
  color?: ColorValue,
  fontFamily?: string,
  fontSize?: number,
  fontStyle?: 'normal' | 'italic',
  fontWeight?:
    | 'normal'
    | 'bold'
    | '100'
    | '200'
    | '300'
    | '400'
    | '500'
    | '600'
    | '700'
    | '800'
    | '900',
  fontVariant?: $ReadOnlyArray<
    | 'small-caps'
    | 'oldstyle-nums'
    | 'lining-nums'
    | 'tabular-nums'
    | 'proportional-nums',
  >,
  textShadowOffset?: $ReadOnly<{|
    width?: number,
    height?: number,
  |}>,
  textShadowRadius?: number,
  textShadowColor?: ColorValue,
  letterSpacing?: number,
  lineHeight?: number,
  textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify',
  textAlignVertical?: 'auto' | 'top' | 'bottom' | 'center',
  includeFontPadding?: boolean,
  textDecorationLine?:
    | 'none'
    | 'underline'
    | 'line-through'
    | 'underline line-through',
  textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed',
  textDecorationColor?: ColorValue,
  writingDirection?: 'auto' | 'ltr' | 'rtl',
|}>;

export type ImageStyle = $ReadOnly<{|
  ...$Exact<ViewStyle>,
  resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
  tintColor?: ColorValue,
  overlayColor?: string,
|}>;

export type Style = {
  ...$Exact<TextStyle>,
  +resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
  +tintColor?: ColorValue,
  +overlayColor?: string,
};

export type StyleProp<+T> =
  | null
  | void
  | T
  | StyleSheetStyle
  | number
  | false
  | ''
  | $ReadOnlyArray<StyleProp<T>>;

// export type ViewStyleProp = StyleProp<$Shape<ViewStyle<DimensionValue>>>;
// export type TextStyleProp = StyleProp<
//   $Shape<TextStyle<DimensionValue, ColorValue>>,
// >;
// export type ImageStyleProp = StyleProp<
//   $Shape<ImageStyle<DimensionValue, ColorValue>>,
// >;

export type StyleObj = StyleProp<$Shape<Style>>;
export type StyleValue = StyleObj;

export type ViewStyleProp = StyleObj;
export type TextStyleProp = StyleObj;
export type ImageStyleProp = StyleObj;

export type Styles = {
  +[key: string]: $Shape<Style>,
};
export type StyleSheet<+S: Styles> = $ObjMap<S, (Object) => StyleSheetStyle>;

/*
Utility type get non-nullable types for specific style keys.
Useful when a component requires values for certain Style Keys.
So Instead:
```
type Props = {position: string};
```
You should use:
```
type Props = {position: TypeForStyleKey<'position'>};
```

This will correctly give you the type 'absolute' | 'relative' instead of the
weak type of just string;
*/
export type TypeForStyleKey<+key: $Keys<Style>> = $ElementType<Style, key>;
<|endoftext|>


<commit_before>"use strict";

const Vector2D = require("./utils/vector");
const Matter = require('../../libs/matter');

class PlayerCollider {

    constructor(id, playerId, position, radius) {
        this.id = id;
        this.playerId = playerId;
        this.type = "CIRCLE";
        this.position = position;
        this.velocity = new Vector2D(0, 0);
        this.radius = radius;
        this.speed = 30;
        this.collided = false;
        this.stunned = false;
        this.stunnedTimer = 100;
        this.force = new Vector2D(0, 0);
        this.friction = 0.5;

        this.oldPos = new Vector2D(0, 0);
    }

    applyVelocity(delta) {
        // let tmpSpeed = this.velocity.multSkalar(this.speed);
        this.velocity = this.force.multSkalar(this.speed);
        let tmpVel = this.velocity.multSkalar(delta / 1000);
        if (tmpVel.abs() < 1) {
            tmpVel = new Vector2D(0, 0);
        }
        this.position = this.position.addVec(tmpVel);
    }

    getJsonObject() {
        return {"position":this.position, "radius":this.radius, "velocity":this.velocity};
    }
}

class World {

    constructor() {
        this.colliderIds = 0;
        this.collisionObjects = new Map();
        this.collisionCallbacks = [];
        this.world = Matter.World.create({gravity:{scale: 0}});
        this.engine = Matter.Engine.create({world: this.world});
    }

    getUniqueId() {
        this.colliderIds++;
        return this.colliderIds;
    }

    createPlayerCollider(playerId, position, radius) {

        let playerColl = new Matter.Bodies.circle(position.x, position.y, radius, {density: 0.01, frictionAir: 0.5, restitution: 1});

        this.addToCollision(playerColl);
        return playerColl;
    }

    addToCollision(collisionObject) {
        Matter.World.addBody(this.world, collisionObject);
    }

    removeFromCollision(collisionObject) {
        this.collisionObjects.delete(collisionObject.id);
    }

    updatePhysicStep(delta) {

        Matter.Engine.update(this.engine, delta);

        // for (let colliderId of this.collisionObjects.keys()) {
        //     let collider = this.collisionObjects.get(colliderId);
        //
        //     for (let otherColliderId of this.collisionObjects.keys()) {
        //         if (otherColliderId === colliderId) { continue; }
        //
        //         let otherCollider = this.collisionObjects.get(otherColliderId);
        //
        //         let divX = collider.position.x - otherCollider.position.x;
        //         let divY = collider.position.y - otherCollider.position.y;
        //         let r = collider.radius + otherCollider.radius;
        //
        //         if ((divX * divX) + (divY * divY) < (r * r)) {
        //             this.collisionHappened(collider, otherCollider);
        //         } else {
        //             collider.oldPos = collider.position;
        //             otherCollider.oldPos = otherCollider.position;
        //         }
        //     }
        //
        //
        //     if (collider.stunned) {
        //         collider.stunnedTimer--;
        //
        //         if (collider.stunnedTimer < 0) {
        //             collider.stunned = false;
        //             collider.stunnedTimer = 10;
        //         }
        //
        //     } else if (!collider.collided) {
        //         collider.applyVelocity(delta);
        //     } else {
        //         collider.position = collider.oldPos;
        //         collider.collided = false;
        //     }
        //
        // }

    }

    update(delta) {
        this.updatePhysicStep(delta);
    }

    addCollisionCallback(callback) {
        this.collisionCallbacks.push(callback);
    }
}

module.exports = PlayerCollider;
module.exports = World;<commit_msg>* removed custom PlayerCollider<commit_after>"use strict";

const Vector2D = require("./utils/vector");
const Matter = require('../../libs/matter');

class World {

    constructor() {
        this.colliderIds = 0;
        this.collisionObjects = new Map();
        this.collisionCallbacks = [];
        this.world = Matter.World.create({gravity:{scale: 0}});
        this.engine = Matter.Engine.create({world: this.world});
    }

    getUniqueId() {
        this.colliderIds++;
        return this.colliderIds;
    }

    createPlayerCollider(playerId, position, radius) {

        let playerColl = new Matter.Bodies.circle(position.x, position.y, radius, {density: 0.01, frictionAir: 0.5, restitution: 1});

        this.addToCollision(playerColl);
        return playerColl;
    }

    addToCollision(collisionObject) {
        Matter.World.addBody(this.world, collisionObject);
    }

    removeFromCollision(collisionObject) {
        this.collisionObjects.delete(collisionObject.id);
    }

    updatePhysicStep(delta) {

        Matter.Engine.update(this.engine, delta);

        // for (let colliderId of this.collisionObjects.keys()) {
        //     let collider = this.collisionObjects.get(colliderId);
        //
        //     for (let otherColliderId of this.collisionObjects.keys()) {
        //         if (otherColliderId === colliderId) { continue; }
        //
        //         let otherCollider = this.collisionObjects.get(otherColliderId);
        //
        //         let divX = collider.position.x - otherCollider.position.x;
        //         let divY = collider.position.y - otherCollider.position.y;
        //         let r = collider.radius + otherCollider.radius;
        //
        //         if ((divX * divX) + (divY * divY) < (r * r)) {
        //             this.collisionHappened(collider, otherCollider);
        //         } else {
        //             collider.oldPos = collider.position;
        //             otherCollider.oldPos = otherCollider.position;
        //         }
        //     }
        //
        //
        //     if (collider.stunned) {
        //         collider.stunnedTimer--;
        //
        //         if (collider.stunnedTimer < 0) {
        //             collider.stunned = false;
        //             collider.stunnedTimer = 10;
        //         }
        //
        //     } else if (!collider.collided) {
        //         collider.applyVelocity(delta);
        //     } else {
        //         collider.position = collider.oldPos;
        //         collider.collided = false;
        //     }
        //
        // }

    }

    update(delta) {
        this.updatePhysicStep(delta);
    }

    addCollisionCallback(callback) {
        this.collisionCallbacks.push(callback);
    }
}

module.exports = PlayerCollider;
module.exports = World;<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule precomputeStyle
 * @flow
 */
'use strict';

var MatrixMath = require('MatrixMath');
var Platform = require('Platform');
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
var invariant = require('invariant');

/**
 * This method provides a hook where flattened styles may be precomputed or
 * otherwise prepared to become better input data for native code.
 */
function precomputeStyle(style: ?Object): ?Object {
  if (!style || !style.transform) {
    return style;
  }
  invariant(
    !style.transformMatrix,
    'transformMatrix and transform styles cannot be used on the same component'
  );
  var newStyle = _precomputeTransforms({...style});
  deepFreezeAndThrowOnMutationInDev(newStyle);
  return newStyle;
}

/**
 * Generate a transform matrix based on the provided transforms, and use that
 * within the style object instead.
 *
 * This allows us to provide an API that is similar to CSS, where transforms may
 * be applied in an arbitrary order, and yet have a universal, singular
 * interface to native code.
 */
function _precomputeTransforms(style: Object): Object {
  var {transform} = style;
  var result = MatrixMath.createIdentityMatrix();

  transform.forEach(transformation => {
    var key = Object.keys(transformation)[0];
    var value = transformation[key];
    if (__DEV__) {
      _validateTransform(key, value, transformation);
    }

    switch (key) {
      case 'matrix':
        MatrixMath.multiplyInto(result, result, value);
        break;
      case 'rotate':
        _multiplyTransform(result, MatrixMath.reuseRotateZCommand, [_convertToRadians(value)]);
        break;
      case 'scale':
        _multiplyTransform(result, MatrixMath.reuseScaleCommand, [value]);
        break;
      case 'scaleX':
        _multiplyTransform(result, MatrixMath.reuseScaleXCommand, [value]);
        break;
      case 'scaleY':
        _multiplyTransform(result, MatrixMath.reuseScaleYCommand, [value]);
        break;
      case 'translate':
        _multiplyTransform(result, MatrixMath.reuseTranslate3dCommand, [value[0], value[1], value[2] || 0]);
        break;
      case 'translateX':
        _multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [value, 0]);
        break;
      case 'translateY':
        _multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [0, value]);
        break;
      default:
        throw new Error('Invalid transform name: ' + key);
    }
  });

  // Android does not support the direct application of a transform matrix to
  // a view, so we need to decompose the result matrix into transforms that can
  // get applied in the specific order of (1) translate (2) scale (3) rotate.
  // Once we can directly apply a matrix, we can remove this decomposition.
  if (Platform.OS === 'android') {
    return {
      ...style,
      transformMatrix: result,
      decomposedMatrix: MatrixMath.decomposeMatrix(result),
    };
  }
  return {
    ...style,
    transformMatrix: result,
  };
}

/**
 * Performs a destructive operation on a transform matrix.
 */
function _multiplyTransform(
  result: Array<number>,
  matrixMathFunction: Function,
  args: Array<number>
): void {
  var matrixToApply = MatrixMath.createIdentityMatrix();
  var argsWithIdentity = [matrixToApply].concat(args);
  matrixMathFunction.apply(this, argsWithIdentity);
  MatrixMath.multiplyInto(result, result, matrixToApply);
}

/**
 * Parses a string like '0.5rad' or '60deg' into radians expressed in a float.
 * Note that validation on the string is done in `_validateTransform()`.
 */
function _convertToRadians(value: string): number {
  var floatValue = parseFloat(value, 10);
  return value.indexOf('rad') > -1 ? floatValue : floatValue * Math.PI / 180;
}

function _validateTransform(key, value, transformation) {
  var multivalueTransforms = [
    'matrix',
    'translate',
  ];
  if (multivalueTransforms.indexOf(key) !== -1) {
    invariant(
      Array.isArray(value),
      'Transform with key of %s must have an array as the value: %s',
      key,
      JSON.stringify(transformation)
    );
  }
  switch (key) {
    case 'matrix':
      invariant(
        value.length === 9 || value.length === 16,
        'Matrix transform must have a length of 9 (2d) or 16 (3d). ' +
          'Provided matrix has a length of %s: %s',
        value.length,
        JSON.stringify(transformation)
      );
      break;
    case 'translate':
      break;
    case 'rotate':
      invariant(
        typeof value === 'string',
        'Transform with key of "%s" must be a string: %s',
        key,
        JSON.stringify(transformation)
      );
      invariant(
        value.indexOf('deg') > -1 || value.indexOf('rad') > -1,
        'Rotate transform must be expressed in degrees (deg) or radians ' +
          '(rad): %s',
        JSON.stringify(transformation)
      );
      break;
    default:
      invariant(
        typeof value === 'number',
        'Transform with key of "%s" must be a number: %s',
        key,
        JSON.stringify(transformation)
      );
  }
}

module.exports = precomputeStyle;
<commit_msg>[ReactNative] Better error message when passing an Animated to a View<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule precomputeStyle
 * @flow
 */
'use strict';

var MatrixMath = require('MatrixMath');
var Platform = require('Platform');

var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
var invariant = require('invariant');
var stringifySafe = require('stringifySafe');

/**
 * This method provides a hook where flattened styles may be precomputed or
 * otherwise prepared to become better input data for native code.
 */
function precomputeStyle(style: ?Object): ?Object {
  if (!style || !style.transform) {
    return style;
  }
  invariant(
    !style.transformMatrix,
    'transformMatrix and transform styles cannot be used on the same component'
  );
  var newStyle = _precomputeTransforms({...style});
  deepFreezeAndThrowOnMutationInDev(newStyle);
  return newStyle;
}

/**
 * Generate a transform matrix based on the provided transforms, and use that
 * within the style object instead.
 *
 * This allows us to provide an API that is similar to CSS, where transforms may
 * be applied in an arbitrary order, and yet have a universal, singular
 * interface to native code.
 */
function _precomputeTransforms(style: Object): Object {
  var {transform} = style;
  var result = MatrixMath.createIdentityMatrix();

  transform.forEach(transformation => {
    var key = Object.keys(transformation)[0];
    var value = transformation[key];
    if (__DEV__) {
      _validateTransform(key, value, transformation);
    }

    switch (key) {
      case 'matrix':
        MatrixMath.multiplyInto(result, result, value);
        break;
      case 'rotate':
        _multiplyTransform(result, MatrixMath.reuseRotateZCommand, [_convertToRadians(value)]);
        break;
      case 'scale':
        _multiplyTransform(result, MatrixMath.reuseScaleCommand, [value]);
        break;
      case 'scaleX':
        _multiplyTransform(result, MatrixMath.reuseScaleXCommand, [value]);
        break;
      case 'scaleY':
        _multiplyTransform(result, MatrixMath.reuseScaleYCommand, [value]);
        break;
      case 'translate':
        _multiplyTransform(result, MatrixMath.reuseTranslate3dCommand, [value[0], value[1], value[2] || 0]);
        break;
      case 'translateX':
        _multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [value, 0]);
        break;
      case 'translateY':
        _multiplyTransform(result, MatrixMath.reuseTranslate2dCommand, [0, value]);
        break;
      default:
        throw new Error('Invalid transform name: ' + key);
    }
  });

  // Android does not support the direct application of a transform matrix to
  // a view, so we need to decompose the result matrix into transforms that can
  // get applied in the specific order of (1) translate (2) scale (3) rotate.
  // Once we can directly apply a matrix, we can remove this decomposition.
  if (Platform.OS === 'android') {
    return {
      ...style,
      transformMatrix: result,
      decomposedMatrix: MatrixMath.decomposeMatrix(result),
    };
  }
  return {
    ...style,
    transformMatrix: result,
  };
}

/**
 * Performs a destructive operation on a transform matrix.
 */
function _multiplyTransform(
  result: Array<number>,
  matrixMathFunction: Function,
  args: Array<number>
): void {
  var matrixToApply = MatrixMath.createIdentityMatrix();
  var argsWithIdentity = [matrixToApply].concat(args);
  matrixMathFunction.apply(this, argsWithIdentity);
  MatrixMath.multiplyInto(result, result, matrixToApply);
}

/**
 * Parses a string like '0.5rad' or '60deg' into radians expressed in a float.
 * Note that validation on the string is done in `_validateTransform()`.
 */
function _convertToRadians(value: string): number {
  var floatValue = parseFloat(value, 10);
  return value.indexOf('rad') > -1 ? floatValue : floatValue * Math.PI / 180;
}

function _validateTransform(key, value, transformation) {
  invariant(
    !value.getValue,
    'You passed an animated value or spring to a normal component. ' +
    'You need to wrap that component in an Animated. For example, ' +
    'replace <View /> by <Animated.View />.'
  );

  var multivalueTransforms = [
    'matrix',
    'translate',
  ];
  if (multivalueTransforms.indexOf(key) !== -1) {
    invariant(
      Array.isArray(value),
      'Transform with key of %s must have an array as the value: %s',
      key,
      stringifySafe(transformation),
    );
  }
  switch (key) {
    case 'matrix':
      invariant(
        value.length === 9 || value.length === 16,
        'Matrix transform must have a length of 9 (2d) or 16 (3d). ' +
          'Provided matrix has a length of %s: %s',
        value.length,
        stringifySafe(transformation),
      );
      break;
    case 'translate':
      break;
    case 'rotate':
      invariant(
        typeof value === 'string',
        'Transform with key of "%s" must be a string: %s',
        key,
        stringifySafe(transformation),
      );
      invariant(
        value.indexOf('deg') > -1 || value.indexOf('rad') > -1,
        'Rotate transform must be expressed in degrees (deg) or radians ' +
          '(rad): %s',
        stringifySafe(transformation),
      );
      break;
    default:
      invariant(
        typeof value === 'number',
        'Transform with key of "%s" must be a number: %s',
        key,
        stringifySafe(transformation),
      );
  }
}

module.exports = precomputeStyle;
<|endoftext|>


<commit_before>/* eslint-env jest */

import React from 'react'
import { mount, shallow } from 'enzyme'

jest.mock('react-relay')
jest.mock('js/components/General/withUserId')
jest.mock('js/analytics/logEvent')
jest.mock('js/components/Search/SearchPageContainer')

afterEach(() => {
  jest.resetModules()
})

describe('SearchView', () => {
  it('renders without error', () => {
    const SearchView = require('js/components/Search/SearchView').default
    shallow(<SearchView />).dive()
  })

  it('includes QueryRenderer', () => {
    const SearchView = require('js/components/Search/SearchView').default
    const wrapper = mount(<SearchView />)
    const { QueryRenderer } = require('react-relay')
    expect(wrapper.find(QueryRenderer).length).toBe(1)
  })

  it('QueryRenderer has the "variables" prop when the user is authenticated', () => {
    const withUserId = require('js/components/General/withUserId').default
    withUserId.mockImplementation(options => ChildComponent => props => (
      <ChildComponent userId={'abc123xyz456'} {...props} />
    ))
    const SearchView = require('js/components/Search/SearchView').default
    const wrapper = mount(<SearchView />)
    const { QueryRenderer } = require('react-relay')
    expect(wrapper.find(QueryRenderer).prop('variables')).toEqual({
      userId: 'abc123xyz456', // default value in withUserId mock
    })
  })

  it('QueryRenderer does not have the "variables" prop when the user is not authenticated', () => {
    const withUserId = require('js/components/General/withUserId').default
    withUserId.mockImplementation(options => ChildComponent => props => (
      <ChildComponent userId={null} {...props} />
    ))

    const SearchView = require('js/components/Search/SearchView').default
    const wrapper = mount(<SearchView />)
    const { QueryRenderer } = require('react-relay')
    expect(wrapper.find(QueryRenderer).prop('variables')).not.toBeDefined()
  })

  it('passes "app", "user", "location" props to the SearchContainer when they exist', () => {
    const fakeProps = {
      app: {
        some: 'value',
      },
      user: {
        id: 'abc123xyz456',
        vc: 233,
      },
    }
    const { QueryRenderer } = require('react-relay')
    QueryRenderer.__setQueryResponse({
      error: null,
      props: fakeProps,
      retry: jest.fn(),
    })

    const SearchView = require('js/components/Search/SearchView').default
    const wrapper = mount(
      <SearchView
        location={{
          search: '?q=tacos',
        }}
      />
    )
    const SearchContainer = require('js/components/Search/SearchPageContainer')
      .default
    const searchPageContainer = wrapper.find(SearchContainer)
    expect(searchPageContainer.prop('app')).toEqual(fakeProps.app)
    expect(searchPageContainer.prop('user')).toEqual(fakeProps.user)
    expect(searchPageContainer.prop('location')).toEqual({
      search: '?q=tacos',
    })
  })
})
<commit_msg>Remove SearchView QueryRenderer tests, because we'll remove the QR<commit_after>/* eslint-env jest */

import React from 'react'
import { mount, shallow } from 'enzyme'

jest.mock('react-relay')
jest.mock('js/components/General/withUserId')
jest.mock('js/analytics/logEvent')
jest.mock('js/components/Search/SearchPageContainer')

afterEach(() => {
  jest.resetModules()
})

describe('SearchView', () => {
  it('renders without error', () => {
    const SearchView = require('js/components/Search/SearchView').default
    shallow(<SearchView />).dive()
  })
})
<|endoftext|>


<commit_before>/**
 * Copyright 2014, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var express = require("express");
var bodyParser = require("body-parser");
var util = require('util');
var path = require('path');
var passport = require('passport');
var when = require('when');

var ui = require("./ui");
var nodes = require("./nodes");
var flows = require("./flows");
var flow = require("./flow");
var library = require("./library");
var info = require("./info");
var theme = require("./theme");
var locales = require("./locales");
var credentials = require("./credentials");
var comms = require("./comms");

var auth = require("./auth");
var needsPermission = auth.needsPermission;

var i18n;
var log;
var adminApp;
var nodeApp;
var server;
var runtime;

var errorHandler = function(err,req,res,next) {
    if (err.message === "request entity too large") {
        log.error(err);
    } else {
        console.log(err.stack);
    }
    log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.toString()},req);
    res.status(400).json({error:"unexpected_error", message:err.toString()});
};

var ensureRuntimeStarted = function(req,res,next) {
    if (!runtime.isStarted()) {
        log.error("Node-RED runtime not started");
        res.status(503).send("Not started");
    } else {
        next();
    }
}

function init(_server,_runtime) {
    server = _server;
    runtime = _runtime;
    var settings = runtime.settings;
    i18n = runtime.i18n;
    log = runtime.log;
    if (settings.httpNodeRoot !== false) {
        nodeApp = express();
    }
    if (settings.httpAdminRoot !== false) {
        comms.init(server,runtime);
        adminApp = express();
        auth.init(runtime);
        credentials.init(runtime);
        flows.init(runtime);
        flow.init(runtime);
        info.init(runtime);
        library.init(adminApp,runtime);
        locales.init(runtime);
        nodes.init(runtime);

        // Editor
        if (!settings.disableEditor) {
            ui.init(runtime);
            var editorApp = express();
            editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
            editorApp.get("/icons/:icon",ui.icon);
            theme.init(runtime);
            if (settings.editorTheme) {
                editorApp.use("/theme",theme.app());
            }
            editorApp.use("/",ui.editorResources);
            adminApp.use(editorApp);
        }
        var maxApiRequestSize = settings.apiMaxLength || '1mb';
        adminApp.use(bodyParser.json({limit:maxApiRequestSize}));
        adminApp.use(bodyParser.urlencoded({limit:maxApiRequestSize,extended:true}));

        adminApp.get("/auth/login",auth.login,errorHandler);

        if (settings.adminAuth) {
            //TODO: all passport references ought to be in ./auth
            adminApp.use(passport.initialize());
            adminApp.post("/auth/token",
                auth.ensureClientSecret,
                auth.authenticateClient,
                auth.getToken,
                auth.errorHandler
            );
            adminApp.post("/auth/revoke",needsPermission(""),auth.revoke,errorHandler);
        }

        // Flows
        adminApp.get("/flows",needsPermission("flows.read"),flows.get,errorHandler);
        adminApp.post("/flows",needsPermission("flows.write"),flows.post,errorHandler);

        adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get,errorHandler);
        adminApp.post("/flow",needsPermission("flows.write"),flow.post,errorHandler);
        adminApp.delete("/flow/:id",needsPermission("flows.write"),flow.delete,errorHandler);
        adminApp.put("/flow/:id",needsPermission("flows.write"),flow.put,errorHandler);

        // Nodes
        adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,errorHandler);
        adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,errorHandler);

        adminApp.get("/nodes/:mod",needsPermission("nodes.read"),nodes.getModule,errorHandler);
        adminApp.put("/nodes/:mod",needsPermission("nodes.write"),nodes.putModule,errorHandler);
        adminApp.delete("/nodes/:mod",needsPermission("nodes.write"),nodes.delete,errorHandler);

        adminApp.get("/nodes/:mod/:set",needsPermission("nodes.read"),nodes.getSet,errorHandler);
        adminApp.put("/nodes/:mod/:set",needsPermission("nodes.write"),nodes.putSet,errorHandler);

        adminApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,errorHandler);

        adminApp.get(/locales\/(.+)\/?$/,locales.get,errorHandler);

        // Library
        adminApp.post(new RegExp("/library/flows\/(.*)"),needsPermission("library.write"),library.post,errorHandler);
        adminApp.get("/library/flows",needsPermission("library.read"),library.getAll,errorHandler);
        adminApp.get(new RegExp("/library/flows\/(.*)"),needsPermission("library.read"),library.get,errorHandler);

        // Settings
        adminApp.get("/settings",needsPermission("settings.read"),info.settings,errorHandler);

        // Error Handler
        //adminApp.use(errorHandler);
    }
}
function start() {
    return i18n.registerMessageCatalog("editor",path.resolve(path.join(__dirname,"locales")),"editor.json").then(function(){
        comms.start();
    });
}
function stop() {
    comms.stop();
    return when.resolve();
}
module.exports = {
    init: init,
    start: start,
    stop: stop,
    library: {
        register: library.register
    },
    auth: {
        needsPermission: auth.needsPermission
    },
    comms: {
        publish: comms.publish
    },
    get adminApp() { return adminApp; },
    get nodeApp() { return nodeApp; },
    get server() { return server; }
};
<commit_msg>Option to enable cors for editor (#886)<commit_after>/**
 * Copyright 2014, 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

var express = require("express");
var bodyParser = require("body-parser");
var util = require('util');
var path = require('path');
var passport = require('passport');
var when = require('when');
var cors = require('cors');

var ui = require("./ui");
var nodes = require("./nodes");
var flows = require("./flows");
var flow = require("./flow");
var library = require("./library");
var info = require("./info");
var theme = require("./theme");
var locales = require("./locales");
var credentials = require("./credentials");
var comms = require("./comms");

var auth = require("./auth");
var needsPermission = auth.needsPermission;

var i18n;
var log;
var adminApp;
var nodeApp;
var server;
var runtime;

var errorHandler = function(err,req,res,next) {
    if (err.message === "request entity too large") {
        log.error(err);
    } else {
        console.log(err.stack);
    }
    log.audit({event: "api.error",error:err.code||"unexpected_error",message:err.toString()},req);
    res.status(400).json({error:"unexpected_error", message:err.toString()});
};

var ensureRuntimeStarted = function(req,res,next) {
    if (!runtime.isStarted()) {
        log.error("Node-RED runtime not started");
        res.status(503).send("Not started");
    } else {
        next();
    }
}

function init(_server,_runtime) {
    server = _server;
    runtime = _runtime;
    var settings = runtime.settings;
    i18n = runtime.i18n;
    log = runtime.log;
    if (settings.httpNodeRoot !== false) {
        nodeApp = express();
    }
    if (settings.httpAdminRoot !== false) {
        comms.init(server,runtime);
        adminApp = express();
        auth.init(runtime);
        credentials.init(runtime);
        flows.init(runtime);
        flow.init(runtime);
        info.init(runtime);
        library.init(adminApp,runtime);
        locales.init(runtime);
        nodes.init(runtime);

        // Editor
        if (!settings.disableEditor) {
            ui.init(runtime);
            var editorApp = express();
            editorApp.get("/",ensureRuntimeStarted,ui.ensureSlash,ui.editor);
            editorApp.get("/icons/:icon",ui.icon);
            theme.init(runtime);
            if (settings.editorTheme) {
                editorApp.use("/theme",theme.app());
            }
            editorApp.use("/",ui.editorResources);
            adminApp.use(editorApp);
        }
        var maxApiRequestSize = settings.apiMaxLength || '1mb';
        adminApp.use(bodyParser.json({limit:maxApiRequestSize}));
        adminApp.use(bodyParser.urlencoded({limit:maxApiRequestSize,extended:true}));

        adminApp.get("/auth/login",auth.login,errorHandler);

        if (settings.adminAuth) {
            //TODO: all passport references ought to be in ./auth
            adminApp.use(passport.initialize());
            adminApp.post("/auth/token",
                auth.ensureClientSecret,
                auth.authenticateClient,
                auth.getToken,
                auth.errorHandler
            );
            adminApp.post("/auth/revoke",needsPermission(""),auth.revoke,errorHandler);
        }
        if (settings.httpAdminCors) {
            var corsHandler = cors(settings.httpAdminCors);
            adminApp.use(corsHandler);
        }

        // Flows
        adminApp.get("/flows",needsPermission("flows.read"),flows.get,errorHandler);
        adminApp.post("/flows",needsPermission("flows.write"),flows.post,errorHandler);

        adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get,errorHandler);
        adminApp.post("/flow",needsPermission("flows.write"),flow.post,errorHandler);
        adminApp.delete("/flow/:id",needsPermission("flows.write"),flow.delete,errorHandler);
        adminApp.put("/flow/:id",needsPermission("flows.write"),flow.put,errorHandler);

        // Nodes
        adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll,errorHandler);
        adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post,errorHandler);

        adminApp.get("/nodes/:mod",needsPermission("nodes.read"),nodes.getModule,errorHandler);
        adminApp.put("/nodes/:mod",needsPermission("nodes.write"),nodes.putModule,errorHandler);
        adminApp.delete("/nodes/:mod",needsPermission("nodes.write"),nodes.delete,errorHandler);

        adminApp.get("/nodes/:mod/:set",needsPermission("nodes.read"),nodes.getSet,errorHandler);
        adminApp.put("/nodes/:mod/:set",needsPermission("nodes.write"),nodes.putSet,errorHandler);

        adminApp.get('/credentials/:type/:id', needsPermission("credentials.read"),credentials.get,errorHandler);

        adminApp.get(/locales\/(.+)\/?$/,locales.get,errorHandler);

        // Library
        adminApp.post(new RegExp("/library/flows\/(.*)"),needsPermission("library.write"),library.post,errorHandler);
        adminApp.get("/library/flows",needsPermission("library.read"),library.getAll,errorHandler);
        adminApp.get(new RegExp("/library/flows\/(.*)"),needsPermission("library.read"),library.get,errorHandler);

        // Settings
        adminApp.get("/settings",needsPermission("settings.read"),info.settings,errorHandler);

        // Error Handler
        //adminApp.use(errorHandler);
    }
}
function start() {
    return i18n.registerMessageCatalog("editor",path.resolve(path.join(__dirname,"locales")),"editor.json").then(function(){
        comms.start();
    });
}
function stop() {
    comms.stop();
    return when.resolve();
}
module.exports = {
    init: init,
    start: start,
    stop: stop,
    library: {
        register: library.register
    },
    auth: {
        needsPermission: auth.needsPermission
    },
    comms: {
        publish: comms.publish
    },
    get adminApp() { return adminApp; },
    get nodeApp() { return nodeApp; },
    get server() { return server; }
};
<|endoftext|>


<commit_before>/*
 *    Copyright 2016 Rethink Robotics
 *
 *    Copyright 2016 Chris Smith
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

'use strict';

let fs = require('fs');
let path = require('path');
let utils = require('util');
let log = require('./logger.js').createLogger();
const messages = require('./messages.js');

// When sourcing your workspace, CMAKE_PREFIX_PATH is AUTOMATICALLY
// prepended with the devel directory of your workspace. Workspace
// chaining works by continuing this path prepending.
let cmakePath = process.env.CMAKE_PREFIX_PATH;
let cmakePaths = cmakePath.split(':');
let jsMsgPath = path.join('share', 'node_js', 'ros');

let messagePackageMap = {};
let messagePackagePathMap = {};

//-----------------------------------------------------------------------
// Utilities for loading, finding handlers for
// message serialization/deserialization
//
//  When rosnodejs starts, it searches through your cmakepath for generated
//  javascript messages. It caches paths for any of the packages it finds.
//  Then, in rosnodejs when you ask to use a message package we check for it
//  in the cache and require it if found.
//-----------------------------------------------------------------------

function createDirectory(directory) {
  let curPath = '/';
  const paths = directory.split(path.sep);
  paths.forEach((part, index) => {
    if (!part) {
      return;
    }
    curPath = path.join(curPath, part);
    const thisPath = curPath;

    try {
      fs.mkdirSync(thisPath);
    }
    catch (err) {
      if (err.code !== 'EEXIST') {
        throw err;
      }
    }
  });
}

function copyFile(from, to, replaceCallback) {
  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(from);
    let fileData = '';
    readStream.on('data', (data) => {
      fileData += data;
    });

    readStream.on('end', () => {
      if (typeof replaceCallback === 'function') {
        fileData = replaceCallback(fileData);
      }

      // open the output file for writing
      const writeStream = fs.createWriteStream(to);
      writeStream.on('open', () => {
        writeStream.write(fileData);
        writeStream.end();
        resolve();
      });
    });
  });
}

let MessageUtils = {
  findMessageFiles() {
    if (Object.keys(messagePackagePathMap).length > 0) {
      return;
    }
    cmakePaths.forEach((cmakePath) => {
      let path_ = path.join(cmakePath, jsMsgPath);
      if (fs.existsSync(path_)) {
        let msgPackages = fs.readdirSync(path_);
        msgPackages.forEach((msgPackage) => {
          // If the message package has been found in a previous workspace,
          // don't overwrite it now. This is critical to enabling ws overlays.
          if (!messagePackagePathMap.hasOwnProperty(msgPackage)) {
            let indexPath = path.join(path_, msgPackage, '_index.js');
            messagePackagePathMap[msgPackage] = indexPath;
          }
        });
      }
    });
  },

  flatten(outputDir) {
    const finderDeclRegex = /^let _finder = require\('\.\.\/\.\.\/\.\.\/find\.js'\);/m;
    const finderCallRegex = /^let (\w+) = _finder\(\'\1\'\);/gm;

    const flatten_local = (packageName, startPath, localPath, outputDir) => {
      const flattenPath = path.join(startPath, localPath);
      fs.readdir(flattenPath, (err, files) => {
        if (err) {
          // if the path doesn't exist, it just means the package currently
          // being flattened doesn't have either msgs or srvs
          if (err.code !== 'ENOENT') {
            throw new Error('Error while flattening generated messages ' + err);
          }
          return;
        }
        // else
        const outputPath = path.join(outputDir, packageName, localPath);
        createDirectory(outputPath)

        files.forEach((file) => {
          const filePath = path.join(flattenPath, file);
          const outputFilePath = path.join(outputDir, packageName, localPath, file);
          let callback;
          if (file !== '_index.js') {
            callback = (fileData) => {
              fileData = fileData.replace(finderDeclRegex, '');
              let matchData;
              while ((matchData = finderCallRegex.exec(fileData)) !== null) {
                const matchStr = matchData[0];
                const msgPackage = matchData[1];
                const replaceStr = utils.format('let %s = require(\'../../%s/_index.js\');', msgPackage, msgPackage);
                fileData = fileData.replace(matchStr, replaceStr);
              }
              return fileData;
            };
          }
          copyFile(filePath, outputFilePath, callback);
        });
      });
    };

    outputDir = path.resolve(outputDir);
    const messageDirectory = path.join(outputDir, 'ros');
    createDirectory(messageDirectory);

    // find relevant genjs base files and copy to output directory
    const filesToCopy = ['base_deserialize.js', 'base_serialize.js'];
    cmakePaths.some((cmakePath) => {
      const checkPath = path.join(cmakePath, 'share', 'node_js');
      let files = fs.readdirSync(checkPath);
      if (!files) {
        return false;
      }
      files.forEach((fileName) => {
        if (filesToCopy.indexOf(fileName) !== -1) {
          copyFile(path.join(checkPath, fileName), path.join(outputDir, fileName));
        }
      });
      return true;
    });

    Object.keys(messagePackagePathMap).forEach((packageName) => {
      const messagePackagePath = messagePackagePathMap[packageName];
      const dir = path.dirname(messagePackagePath)

      flatten_local(packageName, dir, 'msg', messageDirectory);
      flatten_local(packageName, dir, 'srv', messageDirectory);
      // copy the index
      copyFile(messagePackagePath, path.join(messageDirectory, packageName, '_index.js'));
    });
  },

  loadMessagePackage(msgPackage) {
    const indexPath = messagePackagePathMap[msgPackage];
    if (indexPath === undefined) {
      throw new Error('Unable to find message package %s', msgPackage);
    }
    try {
      messagePackageMap[msgPackage] = require(indexPath);
    }
    catch (err) {
      console.error('Unable to include message package ' + msgPackage + ' - ' + err);
      throw new Error();
    }
  },

  getPackage(msgPackage) {
    return messagePackageMap[msgPackage];
  },

  getHandlerForMsgType(rosDataType) {
    let parts = rosDataType.split('/');
    let msgPackage = parts[0];
    let messagePackage = this.getPackage(msgPackage);
    if (messagePackage) {
      let type = parts[1];
      return messagePackage.msg[type];
    } else {
      // console.log("get message from registry");
      let type = messages.getFromRegistry(rosDataType, "message");
      if (type) {
        // console.log("got message from registry", type);
        return new type();
      } else {
        console.error('Unable to find message package ' + msgPackage);
        throw new Error();
      }
    }
  },

  getHandlerForSrvType(rosDataType) {
    let parts = rosDataType.split('/');
    let msgPackage = parts[0];
    let messagePackage = this.getPackage(msgPackage);
    if (messagePackage) {
      let type = parts[1];
      return messagePackage.srv[type];
    } else {
      // console.log("get service from registry");
      let request = messages.getFromRegistry(rosDataType, "request");
      let response = messages.getFromRegistry(rosDataType, "response");
      if (request && response) {
        return {
          // Request: new request(),
          // Response: new response()
          Request: request,
          Response: response
        };
      } else {
        console.error('Unable to find message package ' + msgPackage);
        throw new Error();
      }
    }
  }
};

//-----------------------------------------------------------------------

module.exports = MessageUtils;
<commit_msg>Update search path to match gennodejs<commit_after>/*
 *    Copyright 2016 Rethink Robotics
 *
 *    Copyright 2016 Chris Smith
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

'use strict';

let fs = require('fs');
let path = require('path');
let utils = require('util');
let log = require('./logger.js').createLogger();
const messages = require('./messages.js');

// When sourcing your workspace, CMAKE_PREFIX_PATH is AUTOMATICALLY
// prepended with the devel directory of your workspace. Workspace
// chaining works by continuing this path prepending.
let cmakePath = process.env.CMAKE_PREFIX_PATH;
let cmakePaths = cmakePath.split(':');
let jsMsgPath = path.join('share', 'gennodejs', 'ros');

let messagePackageMap = {};
let messagePackagePathMap = {};

//-----------------------------------------------------------------------
// Utilities for loading, finding handlers for
// message serialization/deserialization
//
//  When rosnodejs starts, it searches through your cmakepath for generated
//  javascript messages. It caches paths for any of the packages it finds.
//  Then, in rosnodejs when you ask to use a message package we check for it
//  in the cache and require it if found.
//-----------------------------------------------------------------------

function createDirectory(directory) {
  let curPath = '/';
  const paths = directory.split(path.sep);
  paths.forEach((part, index) => {
    if (!part) {
      return;
    }
    curPath = path.join(curPath, part);
    const thisPath = curPath;

    try {
      fs.mkdirSync(thisPath);
    }
    catch (err) {
      if (err.code !== 'EEXIST') {
        throw err;
      }
    }
  });
}

function copyFile(from, to, replaceCallback) {
  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(from);
    let fileData = '';
    readStream.on('data', (data) => {
      fileData += data;
    });

    readStream.on('end', () => {
      if (typeof replaceCallback === 'function') {
        fileData = replaceCallback(fileData);
      }

      // open the output file for writing
      const writeStream = fs.createWriteStream(to);
      writeStream.on('open', () => {
        writeStream.write(fileData);
        writeStream.end();
        resolve();
      });
    });
  });
}

let MessageUtils = {
  findMessageFiles() {
    if (Object.keys(messagePackagePathMap).length > 0) {
      return;
    }
    cmakePaths.forEach((cmakePath) => {
      let path_ = path.join(cmakePath, jsMsgPath);
      if (fs.existsSync(path_)) {
        let msgPackages = fs.readdirSync(path_);
        msgPackages.forEach((msgPackage) => {
          // If the message package has been found in a previous workspace,
          // don't overwrite it now. This is critical to enabling ws overlays.
          if (!messagePackagePathMap.hasOwnProperty(msgPackage)) {
            let indexPath = path.join(path_, msgPackage, '_index.js');
            messagePackagePathMap[msgPackage] = indexPath;
          }
        });
      }
    });
  },

  flatten(outputDir) {
    const finderDeclRegex = /^let _finder = require\('\.\.\/\.\.\/\.\.\/find\.js'\);/m;
    const finderCallRegex = /^let (\w+) = _finder\(\'\1\'\);/gm;

    const flatten_local = (packageName, startPath, localPath, outputDir) => {
      const flattenPath = path.join(startPath, localPath);
      fs.readdir(flattenPath, (err, files) => {
        if (err) {
          // if the path doesn't exist, it just means the package currently
          // being flattened doesn't have either msgs or srvs
          if (err.code !== 'ENOENT') {
            throw new Error('Error while flattening generated messages ' + err);
          }
          return;
        }
        // else
        const outputPath = path.join(outputDir, packageName, localPath);
        createDirectory(outputPath)

        files.forEach((file) => {
          const filePath = path.join(flattenPath, file);
          const outputFilePath = path.join(outputDir, packageName, localPath, file);
          let callback;
          if (file !== '_index.js') {
            callback = (fileData) => {
              fileData = fileData.replace(finderDeclRegex, '');
              let matchData;
              while ((matchData = finderCallRegex.exec(fileData)) !== null) {
                const matchStr = matchData[0];
                const msgPackage = matchData[1];
                const replaceStr = utils.format('let %s = require(\'../../%s/_index.js\');', msgPackage, msgPackage);
                fileData = fileData.replace(matchStr, replaceStr);
              }
              return fileData;
            };
          }
          copyFile(filePath, outputFilePath, callback);
        });
      });
    };

    outputDir = path.resolve(outputDir);
    const messageDirectory = path.join(outputDir, 'ros');
    createDirectory(messageDirectory);

    // find relevant genjs base files and copy to output directory
    const filesToCopy = ['base_deserialize.js', 'base_serialize.js'];
    cmakePaths.some((cmakePath) => {
      const checkPath = path.join(cmakePath, 'share', 'node_js');
      let files = fs.readdirSync(checkPath);
      if (!files) {
        return false;
      }
      files.forEach((fileName) => {
        if (filesToCopy.indexOf(fileName) !== -1) {
          copyFile(path.join(checkPath, fileName), path.join(outputDir, fileName));
        }
      });
      return true;
    });

    Object.keys(messagePackagePathMap).forEach((packageName) => {
      const messagePackagePath = messagePackagePathMap[packageName];
      const dir = path.dirname(messagePackagePath)

      flatten_local(packageName, dir, 'msg', messageDirectory);
      flatten_local(packageName, dir, 'srv', messageDirectory);
      // copy the index
      copyFile(messagePackagePath, path.join(messageDirectory, packageName, '_index.js'));
    });
  },

  loadMessagePackage(msgPackage) {
    const indexPath = messagePackagePathMap[msgPackage];
    if (indexPath === undefined) {
      throw new Error('Unable to find message package %s', msgPackage);
    }
    try {
      messagePackageMap[msgPackage] = require(indexPath);
    }
    catch (err) {
      console.error('Unable to include message package ' + msgPackage + ' - ' + err);
      throw new Error();
    }
  },

  getPackage(msgPackage) {
    return messagePackageMap[msgPackage];
  },

  getHandlerForMsgType(rosDataType) {
    let parts = rosDataType.split('/');
    let msgPackage = parts[0];
    let messagePackage = this.getPackage(msgPackage);
    if (messagePackage) {
      let type = parts[1];
      return messagePackage.msg[type];
    } else {
      // console.log("get message from registry");
      let type = messages.getFromRegistry(rosDataType, "message");
      if (type) {
        // console.log("got message from registry", type);
        return new type();
      } else {
        console.error('Unable to find message package ' + msgPackage);
        throw new Error();
      }
    }
  },

  getHandlerForSrvType(rosDataType) {
    let parts = rosDataType.split('/');
    let msgPackage = parts[0];
    let messagePackage = this.getPackage(msgPackage);
    if (messagePackage) {
      let type = parts[1];
      return messagePackage.srv[type];
    } else {
      // console.log("get service from registry");
      let request = messages.getFromRegistry(rosDataType, "request");
      let response = messages.getFromRegistry(rosDataType, "response");
      if (request && response) {
        return {
          // Request: new request(),
          // Response: new response()
          Request: request,
          Response: response
        };
      } else {
        console.error('Unable to find message package ' + msgPackage);
        throw new Error();
      }
    }
  }
};

//-----------------------------------------------------------------------

module.exports = MessageUtils;
<|endoftext|>


<commit_before><commit_msg>logging my name to the console<commit_after>console.log('Ufedojo D Opaluwa');<|endoftext|>