<commit_before>var _ = require('lodash'),
    async = require('async'),
    util = require('./util'),
    sdk = require('postman-collection'),

    createAuthInterface = require('../authorizer/auth-interface'),
    AuthLoader = require('../authorizer/index').AuthLoader,
    ReplayController = require('./replay-controller'),

    DOT_AUTH = '.auth';

module.exports = [
    // File loading
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve files for.')); }

        var triggers = run.triggers,
            cursor = context.coords,
            resolver = run.options.fileResolver,
            request = context.item && context.item.request,
            mode,
            data;

        if (!request) { return done(new Error('No request to send.')); }

        // if body is disabled than skip loading files.
        // @todo this may cause problem if body is enabled/disabled programmatically from pre-request script.
        if (request.body && request.body.disabled) { return done(); }

        // todo: add helper functions in the sdk to do this cleanly for us
        mode = _.get(request, 'body.mode');
        data = _.get(request, ['body', mode]);

        // if there is no mode specified, or no data for the specified mode we cannot resolve anything!
        // @note that if source is not readable, there is no point reading anything, yet we need to warn that file
        // upload was not done. hence we will have to proceed even without an unreadable source
        if (!data) { // we do not need to check `mode` here since false mode returns no `data`
            return done();
        }

        // in this block, we simply use async.waterfall to ensure that all form of file reading is async. essentially,
        // we first determine the data mode and based on it pass the waterfall functions.
        async.waterfall([async.constant(data), {
            // form data parsing simply "enriches" all form parameters having file data type by replacing / setting the
            // value as a read stream
            formdata: function (formdata, next) {
                // ensure that we only process the file type
                async.eachSeries(_.filter(formdata.all(), {type: 'file'}), function (formparam, callback) {
                    if (!formparam || formparam.disabled) {
                        return callback(); // disabled params will be filtered in body-builder.
                    }

                    var paramIsComposite = Array.isArray(formparam.src);

                    // handle missing file src
                    if (!formparam.src || (paramIsComposite && !formparam.src.length)) {
                        triggers.console(cursor, 'warn',
                            `Form param \`${formparam.key}\`, file load error: missing file source`);
                        // set disabled, it will be filtered in body-builder.
                        formparam.disabled = true;

                        return callback();
                    }

                    // handle form param with a single file
                    if (!paramIsComposite) {
                        // eslint-disable-next-line security/detect-non-literal-fs-filename
                        util.createReadStream(resolver, formparam.src, function (err, stream) {
                            if (err) {
                                triggers.console(cursor, 'warn',
                                    `Form param \`${formparam.key}\`, file load error: ${err.message || err}`);
                                formparam.disabled = true;
                            }
                            else {
                                formparam.value = stream;
                            }

                            callback();
                        });

                        return;
                    }

                    // handle form param with multiple files
                    async.map(formparam.src, function (src, next) {
                        // eslint-disable-next-line security/detect-non-literal-fs-filename
                        util.createReadStream(resolver, src, function (err, stream) {
                            if (err) {
                                triggers.console(cursor, 'warn',
                                    `Form param \`${formparam.key}\`, file (${src}) load error: ${err.message || err}`);

                                // don't throw error or disable param if one of the src fails to load
                                return next();
                            }

                            next(null, {src: src, value: stream});
                        });
                    }, function (err, results) {
                        if (err) {
                            // Swallow the error after triggering a warning message for the user.
                            run.triggers.console(cursor, 'warn',
                                `Form param \`${formparam.key}\` load error: ${err.message || err}`);
                            formparam.disabled = true;

                            return done();
                        }

                        _.forEach(results, function (result) {
                            // Insert individual param above the current formparam
                            result && formdata.insert(new sdk.FormParam(_.assign(formparam.toJSON(), result)),
                                formparam);
                        });

                        // remove the current formparam after exploding src
                        formdata.remove(formparam);

                        done();
                    });
                }, next);
            },
            // file data
            file: function (filedata, next) {
                // eslint-disable-next-line security/detect-non-literal-fs-filename
                util.createReadStream(resolver, filedata.src, function (err, stream) {
                    if (err) {
                        triggers.console(cursor, 'warn', 'Binary file load error: ' + err.message || err);
                        filedata.value = null; // ensure this does not mess with requester
                        delete filedata.content; // @todo - why content?
                    }
                    else {
                        filedata.content = stream;
                    }
                    next();
                });
            }
        }[mode] || async.constant()], function (err) {
            // just as a precaution, show the error in console. each resolver anyway should handle their own console
            // warnings.
            // @todo - get cursor here.
            err && triggers.console(cursor, 'warn', 'file data resolution error: ' + (err.message || err));
            done(null); // absorb the error since a console has been trigerred
        });
    },
    // Authorization
    function (context, run, done) {
        // validate all stuff. dont ask.
        if (!context.item) { return done(new Error('runtime: nothing to authorize.')); }

        // bail out if there is no auth
        if (!(context.auth && context.auth.type)) { return done(null); }

        // get auth handler
        var auth = context.auth,
            authType = auth.type,
            originalAuth = context.originalItem.getAuth(),
            originalAuthParams = originalAuth && originalAuth.parameters(),
            authHandler = AuthLoader.getHandler(authType),
            authPreHook,
            authInterface,
            authSignHook = function () {
                try {
                    authHandler.sign(authInterface, context.item.request, function (err) {
                        // handle all types of errors in one place, see catch block
                        if (err) { throw err; }

                        done();
                    });
                }
                catch (err) {
                    // handles synchronous and asynchronous errors in auth.sign
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not sign the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    done();
                }
            };

        // bail out if there is no matching auth handler for the type
        if (!authHandler) {
            run.triggers.console(context.coords, 'warn', 'runtime: could not find a handler for auth: ' + auth.type);

            return done();
        }

        authInterface = createAuthInterface(auth);

        /**
         * We go through the `pre` request send validation for the auth. In this step one of the three things can happen
         *
         * If the Auth `pre` hook
         * 1. gives a go, we sign the request and proceed to send the request.
         * 2. gives a no go, we don't sign the request, but proceed to send the request.
         * 3. gives a no go, with a intermediate request,
         *      a. we suspend current request, send the intermediate request
         *      b. invoke Auth `init` hook with the response of the intermediate request
         *      c. invoke Auth `pre` hook, and repeat from 1
         */
        authPreHook = function () {
            authHandler.pre(authInterface, function (err, success, request) {
                // there was an error in pre hook of auth
                if (err) {
                    // warn the user
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not validate the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    return done();
                }

                // sync all auth system parameters to the original auth
                originalAuthParams && auth.parameters().each(function (param) {
                    param && param.system &&
                        originalAuthParams.upsert({key: param.key, value: param.value, system: true});
                });

                // authHandler gave a go, sign the request
                if (success) { return authSignHook(); }

                // auth gave a no go, but no intermediate request
                if (!request) { return done(); }

                // prepare for sending intermediate request
                var replayController = new ReplayController(context.replayState, run),
                    item = new sdk.Item({request: request});

                // auth handler gave a no go, and an intermediate request.
                // make the intermediate request the response is passed to `init` hook
                replayController.requestReplay(context,
                    item,
                    // marks the auth as source for intermediate request
                    {source: auth.type + DOT_AUTH},
                    function (err, response) {
                        // errors for intermediate requests are passed to request callback
                        // passing it here will add it to original request as well, so don't do it
                        if (err) { return done(); }

                        // pass the response to Auth `init` hook
                        authHandler.init(authInterface, response, function (error) {
                            if (error) {
                                // warn about the err
                                run.triggers.console(context.coords, 'warn', 'runtime~' + authType + '.auth: ' +
                                    'could not initialize auth: ' + (error.message || error), error);

                                // swallow the error, we've warned the user
                                return done();
                            }

                            // schedule back to pre hook
                            authPreHook();
                        });
                    },
                    function (err) {
                        // warn users that maximum retries have exceeded
                        if (err) {
                            run.triggers.console(
                                context.coords, 'warn', 'runtime~' + authType + '.auth: ' + (err.message || err)
                            );
                        }
                        // but don't bubble up the error with the request
                        done();
                    }
                );
            });
        };

        // start the by calling the pre hook of the auth
        authPreHook();
    },
    // Proxy lookup
    function (context, run, done) {
        var proxies = run.options.proxies,
            request = context.item.request,

            url;

        if (!request) { return done(new Error('No request to resolve proxy for.')); }

        url = request.url && request.url.toString();

        async.waterfall([
            // try resolving custom proxies before falling-back to system proxy
            function (cb) {
                if (_.isFunction(_.get(proxies, 'resolve'))) {
                    return cb(null, proxies.resolve(url));
                }

                return cb(null, undefined);
            },
            // fallback to system proxy
            function (config, cb) {
                if (config) {
                    return cb(null, config);
                }

                return _.isFunction(run.options.systemProxy) ? run.options.systemProxy(url, cb) : cb(null, undefined);
            }
        ], function (err, config) {
            if (err) {
                run.triggers.console(context.coords, 'warn', 'proxy lookup error: ' + (err.message || err));
            }

            config && (request.proxy = sdk.ProxyConfig.isProxyConfig(config) ? config : new sdk.ProxyConfig(config));

            return done();
        });
    },
    // Certificate lookup + reading from whichever file resolver is provided
    function (context, run, done) {
        var request,
            pfxPath,
            keyPath,
            certPath,
            fileResolver,

            certificate;

        // A. Check if we have the file resolver
        fileResolver = run.options.fileResolver;

        if (!fileResolver) { return done(); } // No point going ahead

        // B. Ensure we have the request
        request = _.get(context.item, 'request');
        if (!request) { return done(new Error('No request to resolve certificates for.')); }

        // C. See if any cert should be sent, by performing a URL matching
        certificate = run.options.certificates && run.options.certificates.resolveOne(request.url);
        if (!certificate) { return done(); }

        // D. Fetch the paths
        // @todo: check why aren't we reading ca file (why are we not supporting ca file)
        pfxPath = _.get(certificate, 'pfx.src');
        keyPath = _.get(certificate, 'key.src');
        certPath = _.get(certificate, 'cert.src');

        // E. Read from the path, and add the values to the certificate, also associate
        // the certificate with the current request.
        async.mapValues({
            pfx: pfxPath,
            key: keyPath,
            cert: certPath
        }, function (value, key, next) {
            // bail out if value is not defined
            // @todo add test with server which only accepts cert file
            if (!value) { return next(); }

            // eslint-disable-next-line security/detect-non-literal-fs-filename
            fileResolver.readFile(value, function (err, data) {
                // Swallow the error after triggering a warning message for the user.
                err && run.triggers.console(context.coords, 'warn',
                    `certificate "${key}" load error:  ${(err.message || err)}`);
                next(null, data);
            });
        }, function (err, fileContents) {
            if (err) {
                // Swallow the error after triggering a warning message for the user.
                run.triggers.console(context.coords, 'warn', 'certificate load error: ' + (err.message || err));

                return done();
            }

            if (fileContents) {
                !_.isNil(fileContents.pfx) && _.set(certificate, 'pfx.value', fileContents.pfx);
                !_.isNil(fileContents.key) && _.set(certificate, 'key.value', fileContents.key);
                !_.isNil(fileContents.cert) && _.set(certificate, 'cert.value', fileContents.cert);

                (fileContents.cert || fileContents.key || fileContents.pfx) && (request.certificate = certificate);
            }
            done();
        });
    }
];
<commit_msg>Common error handler for form param file load<commit_after>var _ = require('lodash'),
    async = require('async'),
    util = require('./util'),
    sdk = require('postman-collection'),

    createAuthInterface = require('../authorizer/auth-interface'),
    AuthLoader = require('../authorizer/index').AuthLoader,
    ReplayController = require('./replay-controller'),

    DOT_AUTH = '.auth';

module.exports = [
    // File loading
    function (context, run, done) {
        if (!context.item) { return done(new Error('Nothing to resolve files for.')); }

        var triggers = run.triggers,
            cursor = context.coords,
            resolver = run.options.fileResolver,
            request = context.item && context.item.request,
            mode,
            data;

        if (!request) { return done(new Error('No request to send.')); }

        // if body is disabled than skip loading files.
        // @todo this may cause problem if body is enabled/disabled programmatically from pre-request script.
        if (request.body && request.body.disabled) { return done(); }

        // todo: add helper functions in the sdk to do this cleanly for us
        mode = _.get(request, 'body.mode');
        data = _.get(request, ['body', mode]);

        // if there is no mode specified, or no data for the specified mode we cannot resolve anything!
        // @note that if source is not readable, there is no point reading anything, yet we need to warn that file
        // upload was not done. hence we will have to proceed even without an unreadable source
        if (!data) { // we do not need to check `mode` here since false mode returns no `data`
            return done();
        }

        // in this block, we simply use async.waterfall to ensure that all form of file reading is async. essentially,
        // we first determine the data mode and based on it pass the waterfall functions.
        async.waterfall([async.constant(data), {
            // form data parsing simply "enriches" all form parameters having file data type by replacing / setting the
            // value as a read stream
            formdata: function (formdata, next) {
                // ensure that we only process the file type
                async.eachSeries(_.filter(formdata.all(), {type: 'file'}), function (formparam, callback) {
                    if (!formparam || formparam.disabled) {
                        return callback(); // disabled params will be filtered in body-builder.
                    }

                    var paramIsComposite = Array.isArray(formparam.src),
                        onLoadError = function (err, disableParam) {
                            triggers.console(cursor, 'warn',
                                `Form param \`${formparam.key}\`, file load error: ${err}`);

                            // set disabled, it will be filtered in body-builder.
                            disableParam && (formparam.disabled = true);
                        };

                    // handle missing file src
                    if (!formparam.src || (paramIsComposite && !formparam.src.length)) {
                        onLoadError('missing file source', true);

                        return callback();
                    }

                    // handle form param with a single file
                    if (!paramIsComposite) {
                        // eslint-disable-next-line security/detect-non-literal-fs-filename
                        util.createReadStream(resolver, formparam.src, function (err, stream) {
                            if (err) {
                                onLoadError(err.message || err, true);
                            }
                            else {
                                formparam.value = stream;
                            }

                            callback();
                        });

                        return;
                    }

                    // handle form param with multiple files
                    async.map(formparam.src, function (src, next) {
                        // eslint-disable-next-line security/detect-non-literal-fs-filename
                        util.createReadStream(resolver, src, function (err, stream) {
                            if (err) {
                                // @note don't throw error or disable param if one of the src fails to load
                                onLoadError(err.message || err);

                                return next();
                            }

                            next(null, {src: src, value: stream});
                        });
                    }, function (err, results) {
                        if (err) {
                            // Swallow the error after triggering a warning message for the user.
                            run.triggers.console(cursor, 'warn',
                                `Form param \`${formparam.key}\` load error: ${err.message || err}`);
                            formparam.disabled = true;

                            return done();
                        }

                        _.forEach(results, function (result) {
                            // Insert individual param above the current formparam
                            result && formdata.insert(new sdk.FormParam(_.assign(formparam.toJSON(), result)),
                                formparam);
                        });

                        // remove the current formparam after exploding src
                        formdata.remove(formparam);

                        done();
                    });
                }, next);
            },
            // file data
            file: function (filedata, next) {
                // eslint-disable-next-line security/detect-non-literal-fs-filename
                util.createReadStream(resolver, filedata.src, function (err, stream) {
                    if (err) {
                        triggers.console(cursor, 'warn', 'Binary file load error: ' + err.message || err);
                        filedata.value = null; // ensure this does not mess with requester
                        delete filedata.content; // @todo - why content?
                    }
                    else {
                        filedata.content = stream;
                    }
                    next();
                });
            }
        }[mode] || async.constant()], function (err) {
            // just as a precaution, show the error in console. each resolver anyway should handle their own console
            // warnings.
            // @todo - get cursor here.
            err && triggers.console(cursor, 'warn', 'file data resolution error: ' + (err.message || err));
            done(null); // absorb the error since a console has been trigerred
        });
    },
    // Authorization
    function (context, run, done) {
        // validate all stuff. dont ask.
        if (!context.item) { return done(new Error('runtime: nothing to authorize.')); }

        // bail out if there is no auth
        if (!(context.auth && context.auth.type)) { return done(null); }

        // get auth handler
        var auth = context.auth,
            authType = auth.type,
            originalAuth = context.originalItem.getAuth(),
            originalAuthParams = originalAuth && originalAuth.parameters(),
            authHandler = AuthLoader.getHandler(authType),
            authPreHook,
            authInterface,
            authSignHook = function () {
                try {
                    authHandler.sign(authInterface, context.item.request, function (err) {
                        // handle all types of errors in one place, see catch block
                        if (err) { throw err; }

                        done();
                    });
                }
                catch (err) {
                    // handles synchronous and asynchronous errors in auth.sign
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not sign the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    done();
                }
            };

        // bail out if there is no matching auth handler for the type
        if (!authHandler) {
            run.triggers.console(context.coords, 'warn', 'runtime: could not find a handler for auth: ' + auth.type);

            return done();
        }

        authInterface = createAuthInterface(auth);

        /**
         * We go through the `pre` request send validation for the auth. In this step one of the three things can happen
         *
         * If the Auth `pre` hook
         * 1. gives a go, we sign the request and proceed to send the request.
         * 2. gives a no go, we don't sign the request, but proceed to send the request.
         * 3. gives a no go, with a intermediate request,
         *      a. we suspend current request, send the intermediate request
         *      b. invoke Auth `init` hook with the response of the intermediate request
         *      c. invoke Auth `pre` hook, and repeat from 1
         */
        authPreHook = function () {
            authHandler.pre(authInterface, function (err, success, request) {
                // there was an error in pre hook of auth
                if (err) {
                    // warn the user
                    run.triggers.console(context.coords,
                        'warn',
                        'runtime~' + authType + '.auth: could not validate the request: ' + (err.message || err),
                        err
                    );

                    // swallow the error, we've warned the user
                    return done();
                }

                // sync all auth system parameters to the original auth
                originalAuthParams && auth.parameters().each(function (param) {
                    param && param.system &&
                        originalAuthParams.upsert({key: param.key, value: param.value, system: true});
                });

                // authHandler gave a go, sign the request
                if (success) { return authSignHook(); }

                // auth gave a no go, but no intermediate request
                if (!request) { return done(); }

                // prepare for sending intermediate request
                var replayController = new ReplayController(context.replayState, run),
                    item = new sdk.Item({request: request});

                // auth handler gave a no go, and an intermediate request.
                // make the intermediate request the response is passed to `init` hook
                replayController.requestReplay(context,
                    item,
                    // marks the auth as source for intermediate request
                    {source: auth.type + DOT_AUTH},
                    function (err, response) {
                        // errors for intermediate requests are passed to request callback
                        // passing it here will add it to original request as well, so don't do it
                        if (err) { return done(); }

                        // pass the response to Auth `init` hook
                        authHandler.init(authInterface, response, function (error) {
                            if (error) {
                                // warn about the err
                                run.triggers.console(context.coords, 'warn', 'runtime~' + authType + '.auth: ' +
                                    'could not initialize auth: ' + (error.message || error), error);

                                // swallow the error, we've warned the user
                                return done();
                            }

                            // schedule back to pre hook
                            authPreHook();
                        });
                    },
                    function (err) {
                        // warn users that maximum retries have exceeded
                        if (err) {
                            run.triggers.console(
                                context.coords, 'warn', 'runtime~' + authType + '.auth: ' + (err.message || err)
                            );
                        }
                        // but don't bubble up the error with the request
                        done();
                    }
                );
            });
        };

        // start the by calling the pre hook of the auth
        authPreHook();
    },
    // Proxy lookup
    function (context, run, done) {
        var proxies = run.options.proxies,
            request = context.item.request,

            url;

        if (!request) { return done(new Error('No request to resolve proxy for.')); }

        url = request.url && request.url.toString();

        async.waterfall([
            // try resolving custom proxies before falling-back to system proxy
            function (cb) {
                if (_.isFunction(_.get(proxies, 'resolve'))) {
                    return cb(null, proxies.resolve(url));
                }

                return cb(null, undefined);
            },
            // fallback to system proxy
            function (config, cb) {
                if (config) {
                    return cb(null, config);
                }

                return _.isFunction(run.options.systemProxy) ? run.options.systemProxy(url, cb) : cb(null, undefined);
            }
        ], function (err, config) {
            if (err) {
                run.triggers.console(context.coords, 'warn', 'proxy lookup error: ' + (err.message || err));
            }

            config && (request.proxy = sdk.ProxyConfig.isProxyConfig(config) ? config : new sdk.ProxyConfig(config));

            return done();
        });
    },
    // Certificate lookup + reading from whichever file resolver is provided
    function (context, run, done) {
        var request,
            pfxPath,
            keyPath,
            certPath,
            fileResolver,

            certificate;

        // A. Check if we have the file resolver
        fileResolver = run.options.fileResolver;

        if (!fileResolver) { return done(); } // No point going ahead

        // B. Ensure we have the request
        request = _.get(context.item, 'request');
        if (!request) { return done(new Error('No request to resolve certificates for.')); }

        // C. See if any cert should be sent, by performing a URL matching
        certificate = run.options.certificates && run.options.certificates.resolveOne(request.url);
        if (!certificate) { return done(); }

        // D. Fetch the paths
        // @todo: check why aren't we reading ca file (why are we not supporting ca file)
        pfxPath = _.get(certificate, 'pfx.src');
        keyPath = _.get(certificate, 'key.src');
        certPath = _.get(certificate, 'cert.src');

        // E. Read from the path, and add the values to the certificate, also associate
        // the certificate with the current request.
        async.mapValues({
            pfx: pfxPath,
            key: keyPath,
            cert: certPath
        }, function (value, key, next) {
            // bail out if value is not defined
            // @todo add test with server which only accepts cert file
            if (!value) { return next(); }

            // eslint-disable-next-line security/detect-non-literal-fs-filename
            fileResolver.readFile(value, function (err, data) {
                // Swallow the error after triggering a warning message for the user.
                err && run.triggers.console(context.coords, 'warn',
                    `certificate "${key}" load error:  ${(err.message || err)}`);
                next(null, data);
            });
        }, function (err, fileContents) {
            if (err) {
                // Swallow the error after triggering a warning message for the user.
                run.triggers.console(context.coords, 'warn', 'certificate load error: ' + (err.message || err));

                return done();
            }

            if (fileContents) {
                !_.isNil(fileContents.pfx) && _.set(certificate, 'pfx.value', fileContents.pfx);
                !_.isNil(fileContents.key) && _.set(certificate, 'key.value', fileContents.key);
                !_.isNil(fileContents.cert) && _.set(certificate, 'cert.value', fileContents.cert);

                (fileContents.cert || fileContents.key || fileContents.pfx) && (request.certificate = certificate);
            }
            done();
        });
    }
];
<|endoftext|>


<commit_before>var logger = require('pomelo-logger').getLogger('pomelo-rpc', 'mqtt-mailbox');
var EventEmitter = require('events').EventEmitter;
var constants = require('../../util/constants');
var Tracer = require('../../util/tracer');
var MqttCon = require('mqtt-connection');
var utils = require('../../util/utils');
var util = require('util');
var net = require('net');

var MailBox = function(server, opts) {
  EventEmitter.call(this);
  this.curId = 0;
  this.id = server.id;
  this.host = server.host;
  this.port = server.port;
  this.requests = {};
  this.timeout = {};
  this.queue = [];
  this.bufferMsg = opts.bufferMsg;
  this.keepalive = opts.keepalive || constants.DEFAULT_PARAM.KEEPALIVE;
  this.interval = opts.interval || constants.DEFAULT_PARAM.INTERVAL;
  this.timeoutValue = opts.timeout || constants.DEFAULT_PARAM.CALLBACK_TIMEOUT;
  this.keepaliveTimer = null;
  this.lastPing = -1;
  this.lastPong = -1;
  this.connected = false;
  this.closed = false;
  this.opts = opts;
};

util.inherits(MailBox, EventEmitter);

MailBox.prototype.connect = function(tracer, cb) {
  tracer && tracer.info('client', __filename, 'connect', 'mqtt-mailbox try to connect');
  if (this.connected) {
    tracer && tracer.error('client', __filename, 'connect', 'mailbox has already connected');
    return cb(new Error('mailbox has already connected.'));
  }

  var self = this;

  var stream = net.createConnection(this.port, this.host);
  this.socket = MqttCon(stream);

  this.socket.connect({
    clientId: 'MQTT_RPC_' + Date.now()
  }, function() {
    if (self.connected) {
      return;
    }

    self.connected = true;
    if (self.bufferMsg) {
      self._interval = setInterval(function() {
        flush(self);
      }, self.interval);
    }

    self.setupKeepAlive();
    cb();
  });

  this.socket.on('publish', function(pkg) {
    pkg = pkg.payload.toString();
    try {
      pkg = JSON.parse(pkg);
      if (pkg instanceof Array) {
        processMsgs(self, pkg);
      } else {
        processMsg(self, pkg);
      }
    } catch (err) {
      logger.error('rpc client process remote server %s message with error: %s', self.id, err.stack);
    }
  });

  this.socket.on('error', function(err) {
    logger.error('rpc socket is error, remote server %s host: %s, port: %s', self.id, self.host, self.port);
    self.emit('close', self.id);
  });

  this.socket.on('pingresp', function() {
    self.lastPong = Date.now();
  });

  this.socket.on('disconnect', function(reason) {
    logger.error('rpc socket is disconnect from remote server %s, reason: %s', self.id, reason);
    var reqs = self.requests;
    for (var id in reqs) {
      var ReqCb = reqs[id];
      ReqCb(tracer, new Error('disconnect with remote server ' + self.id));
    }
    self.emit('close', self.id);
  });
};

/**
 * close mailbox
 */
MailBox.prototype.close = function() {
  if (this.closed) {
    return;
  }
  this.closed = true;
  this.connected = false;
  if (this._interval) {
    clearInterval(this._interval);
    this._interval = null;
  }
  this.socket.destroy();
};

/**
 * send message to remote server
 *
 * @param msg {service:"", method:"", args:[]}
 * @param opts {} attach info to send method
 * @param cb declaration decided by remote interface
 */
MailBox.prototype.send = function(tracer, msg, opts, cb) {
  tracer && tracer.info('client', __filename, 'send', 'mqtt-mailbox try to send');
  if (!this.connected) {
    tracer && tracer.error('client', __filename, 'send', 'mqtt-mailbox not init');
    cb(tracer, new Error('mqtt-mailbox is not init'));
    return;
  }

  if (this.closed) {
    tracer && tracer.error('client', __filename, 'send', 'mailbox has already closed');
    cb(tracer, new Error('mqtt-mailbox has already closed'));
    return;
  }

  var id = this.curId++;
  this.requests[id] = cb;
  setCbTimeout(this, id, tracer, cb);

  var pkg;
  if (tracer && tracer.isEnabled) {
    pkg = {
      traceId: tracer.id,
      seqId: tracer.seq,
      source: tracer.source,
      remote: tracer.remote,
      id: id,
      msg: msg
    };
  } else {
    pkg = {
      id: id,
      msg: msg
    };
  }
  if (this.bufferMsg) {
    enqueue(this, pkg);
  } else {
    doSend(this.socket, pkg);
  }
};

MailBox.prototype.setupKeepAlive = function() {
  var self = this;
  this.keepaliveTimer = setInterval(function() {
    self.checkKeepAlive();
  }, this.keepalive);
}

MailBox.prototype.checkKeepAlive = function() {
  if (this.closed) {
    return;
  }

  // console.log('checkKeepAlive lastPing %d lastPong %d ~~~', this.lastPing, this.lastPong);
  var now = Date.now();
  var KEEP_ALIVE_TIMEOUT = this.keepalive * 2;
  if (this.lastPing > 0) {
    if (this.lastPong < this.lastPing) {
      if (now - this.lastPing > KEEP_ALIVE_TIMEOUT) {
        logger.error('mqtt rpc client checkKeepAlive timeout from remote server %s for %d', this.id, KEEP_ALIVE_TIMEOUT);
        this.close();
      }
    } else {
      this.socket.pingreq();
      this.lastPing = Date.now();
    }
  } else {
    this.socket.pingreq();
    this.lastPing = Date.now();
  }
}

var enqueue = function(mailbox, msg) {
  mailbox.queue.push(msg);
};

var flush = function(mailbox) {
  if (mailbox.closed || !mailbox.queue.length) {
    return;
  }
  doSend(mailbox.socket, mailbox.queue);
  mailbox.queue = [];
};

var doSend = function(socket, msg) {
  socket.publish({
    topic: 'rpc',
    payload: JSON.stringify(msg)
  });
}

var processMsgs = function(mailbox, pkgs) {
  for (var i = 0, l = pkgs.length; i < l; i++) {
    processMsg(mailbox, pkgs[i]);
  }
};

var processMsg = function(mailbox, pkg) {
  var pkgId = pkg.id;
  clearCbTimeout(mailbox, pkgId);
  var cb = mailbox.requests[pkgId];
  if (!cb) {
    return;
  }

  delete mailbox.requests[pkgId];
  var rpcDebugLog = mailbox.opts.rpcDebugLog;
  var tracer = null;
  var sendErr = null;
  if (rpcDebugLog) {
    tracer = new Tracer(mailbox.opts.rpcLogger, mailbox.opts.rpcDebugLog, mailbox.opts.clientId, pkg.source, pkg.resp, pkg.traceId, pkg.seqId);
  }
  var pkgResp = pkg.resp;

  cb(tracer, sendErr, pkgResp);
};

var setCbTimeout = function(mailbox, id, tracer, cb) {
  var timer = setTimeout(function() {
    logger.warn('rpc request is timeout, id: %s, host: %s, port: %s', id, mailbox.host, mailbox.port);
    clearCbTimeout(mailbox, id);
    if (mailbox.requests[id]) {
      delete mailbox.requests[id];
    }
    logger.error('rpc callback timeout, remote server %s host: %s, port: %s', id, mailbox.host, mailbox.port);
    cb(tracer, new Error('rpc callback timeout'));
  }, mailbox.timeoutValue);
  mailbox.timeout[id] = timer;
};

var clearCbTimeout = function(mailbox, id) {
  if (!mailbox.timeout[id]) {
    logger.warn('timer is not exsits, id: %s, host: %s, port: %s', id, mailbox.host, mailbox.port);
    return;
  }
  clearTimeout(mailbox.timeout[id]);
  delete mailbox.timeout[id];
};

/**
 * Factory method to create mailbox
 *
 * @param {Object} server remote server info {id:"", host:"", port:""}
 * @param {Object} opts construct parameters
 *                      opts.bufferMsg {Boolean} msg should be buffered or send immediately.
 *                      opts.interval {Boolean} msg queue flush interval if bufferMsg is true. default is 50 ms
 */
module.exports.create = function(server, opts) {
  return new MailBox(server, opts || {});
};<commit_msg>更新mqtt mailbox<commit_after>var logger = require('pomelo-logger').getLogger('pomelo-rpc', 'mqtt-mailbox');
var EventEmitter = require('events').EventEmitter;
var constants = require('../../util/constants');
var Tracer = require('../../util/tracer');
var MqttCon = require('mqtt-connection');
var utils = require('../../util/utils');
var util = require('util');
var net = require('net');

var MailBox = function(server, opts) {
  EventEmitter.call(this);
  this.curId = 0;
  this.id = server.id;
  this.host = server.host;
  this.port = server.port;
  this.requests = {};
  this.timeout = {};
  this.queue = [];
  this.bufferMsg = opts.bufferMsg;
  this.keepalive = opts.keepalive || constants.DEFAULT_PARAM.KEEPALIVE;
  this.interval = opts.interval || constants.DEFAULT_PARAM.INTERVAL;
  this.timeoutValue = opts.timeout || constants.DEFAULT_PARAM.CALLBACK_TIMEOUT;
  this.keepaliveTimer = null;
  this.lastPing = -1;
  this.lastPong = -1;
  this.connected = false;
  this.closed = false;
  this.opts = opts;
  this.serverId = opts.context.serverId;
};

util.inherits(MailBox, EventEmitter);

MailBox.prototype.connect = function(tracer, cb) {
  tracer && tracer.info('client', __filename, 'connect', 'mqtt-mailbox try to connect');
  if (this.connected) {
    tracer && tracer.error('client', __filename, 'connect', 'mailbox has already connected');
    return cb(new Error('mailbox has already connected.'));
  }

  var self = this;

  var stream = net.createConnection(this.port, this.host);
  this.socket = MqttCon(stream);

  var connectTimeout = setTimeout(function() {
    logger.error('rpc client %s connect to remote server %s timeout', self.serverId, self.id);
    self.emit('close', self.id);
  }, CONNECT_TIMEOUT);

  this.socket.connect({
    clientId: 'MQTT_RPC_' + Date.now()
  }, function() {
    if (self.connected) {
      return;
    }

    clearTimeout(connectTimeout);
    self.connected = true;
    if (self.bufferMsg) {
      self._interval = setInterval(function() {
        flush(self);
      }, self.interval);
    }

    self.setupKeepAlive();
    cb();
  });

  this.socket.on('publish', function(pkg) {
    pkg = pkg.payload.toString();
    try {
      pkg = JSON.parse(pkg);
      if (pkg instanceof Array) {
        processMsgs(self, pkg);
      } else {
        processMsg(self, pkg);
      }
    } catch (err) {
      logger.error('rpc client %s process remote server %s message with error: %s', self.serverId, self.id, err.stack);
    }
  });

  this.socket.on('error', function(err) {
    logger.error('rpc socket %s is error, remote server %s host: %s, port: %s', self.serverId, self.id, self.host, self.port);
    self.emit('close', self.id);
  });

  this.socket.on('pingresp', function() {
    self.lastPong = Date.now();
  });

  this.socket.on('disconnect', function(reason) {
    logger.error('rpc socket %s is disconnect from remote server %s, reason: %s', self.serverId, self.id, reason);
    var reqs = self.requests;
    for (var id in reqs) {
      var ReqCb = reqs[id];
      ReqCb(tracer, new Error(self.serverId + ' disconnect with remote server ' + self.id));
    }
    self.emit('close', self.id);
  });
};

/**
 * close mailbox
 */
MailBox.prototype.close = function() {
  if (this.closed) {
    return;
  }
  this.closed = true;
  this.connected = false;
  if (this._interval) {
    clearInterval(this._interval);
    this._interval = null;
  }
  this.socket.destroy();
};

/**
 * send message to remote server
 *
 * @param msg {service:"", method:"", args:[]}
 * @param opts {} attach info to send method
 * @param cb declaration decided by remote interface
 */
MailBox.prototype.send = function(tracer, msg, opts, cb) {
  tracer && tracer.info('client', __filename, 'send', 'mqtt-mailbox try to send');
  if (!this.connected) {
    tracer && tracer.error('client', __filename, 'send', 'mqtt-mailbox not init');
    cb(tracer, new Error(this.serverId + ' mqtt-mailbox is not init ' + this.id));
    return;
  }

  if (this.closed) {
    tracer && tracer.error('client', __filename, 'send', 'mailbox has already closed');
    cb(tracer, new Error(this.serverId + ' mqtt-mailbox has already closed ' + this.id));
    return;
  }

  var id = this.curId++;
  this.requests[id] = cb;
  setCbTimeout(this, id, tracer, cb);

  var pkg;
  if (tracer && tracer.isEnabled) {
    pkg = {
      traceId: tracer.id,
      seqId: tracer.seq,
      source: tracer.source,
      remote: tracer.remote,
      id: id,
      msg: msg
    };
  } else {
    pkg = {
      id: id,
      msg: msg
    };
  }
  if (this.bufferMsg) {
    enqueue(this, pkg);
  } else {
    doSend(this.socket, pkg);
  }
};

MailBox.prototype.setupKeepAlive = function() {
  var self = this;
  this.keepaliveTimer = setInterval(function() {
    self.checkKeepAlive();
  }, this.keepalive);
}

MailBox.prototype.checkKeepAlive = function() {
  if (this.closed) {
    return;
  }

  // console.log('checkKeepAlive lastPing %d lastPong %d ~~~', this.lastPing, this.lastPong);
  var now = Date.now();
  var KEEP_ALIVE_TIMEOUT = this.keepalive * 2;
  if (this.lastPing > 0) {
    if (this.lastPong < this.lastPing) {
      if (now - this.lastPing > KEEP_ALIVE_TIMEOUT) {
        logger.error('mqtt rpc client %s checkKeepAlive timeout from remote server %s for %d lastPing: %s lastPong: %s', this.serverId, this.id, KEEP_ALIVE_TIMEOUT, this.lastPing, this.lastPong);
        this.emit('close', this.id);
        this.lastPing = -1;
        // this.close();
      }
    } else {
      this.socket.pingreq();
      this.lastPing = Date.now();
    }
  } else {
    this.socket.pingreq();
    this.lastPing = Date.now();
  }
}

var enqueue = function(mailbox, msg) {
  mailbox.queue.push(msg);
};

var flush = function(mailbox) {
  if (mailbox.closed || !mailbox.queue.length) {
    return;
  }
  doSend(mailbox.socket, mailbox.queue);
  mailbox.queue = [];
};

var doSend = function(socket, msg) {
  socket.publish({
    topic: 'rpc',
    payload: JSON.stringify(msg)
  });
}

var processMsgs = function(mailbox, pkgs) {
  for (var i = 0, l = pkgs.length; i < l; i++) {
    processMsg(mailbox, pkgs[i]);
  }
};

var processMsg = function(mailbox, pkg) {
  var pkgId = pkg.id;
  clearCbTimeout(mailbox, pkgId);
  var cb = mailbox.requests[pkgId];
  if (!cb) {
    return;
  }

  delete mailbox.requests[pkgId];
  var rpcDebugLog = mailbox.opts.rpcDebugLog;
  var tracer = null;
  var sendErr = null;
  if (rpcDebugLog) {
    tracer = new Tracer(mailbox.opts.rpcLogger, mailbox.opts.rpcDebugLog, mailbox.opts.clientId, pkg.source, pkg.resp, pkg.traceId, pkg.seqId);
  }
  var pkgResp = pkg.resp;

  cb(tracer, sendErr, pkgResp);
};

var setCbTimeout = function(mailbox, id, tracer, cb) {
  var timer = setTimeout(function() {
    // logger.warn('rpc request is timeout, id: %s, host: %s, port: %s', id, mailbox.host, mailbox.port);
    clearCbTimeout(mailbox, id);
    if (mailbox.requests[id]) {
      delete mailbox.requests[id];
    }
    var eMsg = util.format('rpc %s callback timeout %d, remote server %s host: %s, port: %s', mailbox.serverId, mailbox.timeoutValue, id, mailbox.host, mailbox.port);
    logger.error(eMsg);
    cb(tracer, new Error(eMsg));
  }, mailbox.timeoutValue);
  mailbox.timeout[id] = timer;
};

var clearCbTimeout = function(mailbox, id) {
  if (!mailbox.timeout[id]) {
    logger.warn('timer is not exsits, serverId: %s remote: %s, host: %s, port: %s', mailbox.serverId, id, mailbox.host, mailbox.port);
    return;
  }
  clearTimeout(mailbox.timeout[id]);
  delete mailbox.timeout[id];
};

/**
 * Factory method to create mailbox
 *
 * @param {Object} server remote server info {id:"", host:"", port:""}
 * @param {Object} opts construct parameters
 *                      opts.bufferMsg {Boolean} msg should be buffered or send immediately.
 *                      opts.interval {Boolean} msg queue flush interval if bufferMsg is true. default is 50 ms
 */
module.exports.create = function(server, opts) {
  return new MailBox(server, opts || {});
};<|endoftext|>


<commit_before>/*:
 * @plugindesc This plugin allows you to run with two types of events when a certain picture collides with some sprites.
 * @author biud436
 *
 * @param Delay
 * @type number
 * @min 1
 * @desc if it is less than the time you want a delay to take, it will wait the event to complete.
 * @default 200
 *
 * @help
 * =============================================================================
 * Script Calls
 * =============================================================================
 *
 * This command will run some event when it collides with certain picture:
 *
 *    RS.PictureTool.runEventCollideWithPicture(picId, eventId);
 *
 * This command will run the common event when it collides with a picId picture:
 *
 *    RS.PictureTool.runCommonEventCollideWithPicture(picId, eventId, commonEventId);
 *
 * This command will run a certain event when the picture collides with a game player:
 *
 *    RS.PictureTool.runEventCollideWithPlayer(picId, eventId);
 *
 * This command will run a certain common event when the picture collides with a game player:
 *
 *    RS.PictureTool.runCommonEventCollideWithPlayer(picId, eventId, commonEventId);
 *
 * =============================================================================
 * Version Log
 * =============================================================================
 * 2018.04.13 (v1.0.0) - First Release.
 * 2018.04.16 (v1.0.1) - Fixed a hanging bug.
 */
 /*:ko
  * @plugindesc 그림이 특정 캐릭터 스프라이트와 충돌하면 특정 이벤트가 실행됩니다.
  * @author 러닝은빛(biud436)
  *
  * @param Delay
  * @type number
  * @min 1
  * @desc 키보드와 마우스 이벤트 업데이트를 위한 딜레이 시간 (간격이 짧으면 키보드와 마우스가 먹통됩니다, 1000ms = 1초)
  * @default 200
  *
  * @help
  * =============================================================================
  * 스크립트 호출
  * =============================================================================
  *
  * 특정 그림과 특정 이벤트 eventId가 충돌하면 eventId를 실행합니다.
  *
  *    RS.PictureTool.runEventCollideWithPicture(picId, eventId);
  *
  * 특정 그림과 특정 이벤트 eventId가 충돌하면 특정 커먼 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runCommonEventCollideWithPicture(picId, eventId, commonEventId);
  *
  * 그림과 플레이어가 충돌하면 특정 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runEventCollideWithPlayer(picId, eventId);
  *
  * 그림과 플레이어가 충돌하면 특정 커먼 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runCommonEventCollideWithPlayer(picId, eventId, commonEventId);
  *
  * =============================================================================
  * 버전 로그
  * =============================================================================
  * 2018.04.13 (v1.0.0) - 공개
  * 2018.04.16 (v1.0.1) - 멈춤 버그를 수정하였습니다.
  */

var RS = RS || {};

RS.PictureTool = RS.PictureTool || {};

(function ($) {

  var parameters = PluginManager.parameters('RS_PictureTool');

  $.Params = $.Params || {};
  $.Params.frameTime = performance.now();

  $.Params.FN = {
    NONE: -1,
    RUN_EVENT_COLLIDE_WITH_PICTURE: 0,
    RUN_COMMONEVENT_COLLIDE_WITH_PICTURE: 1,
    RUN_EVENT_COLLIDE_WITH_PLAYER: 2,
    RUN_COMMONEVENT_COLLIDEWITH_PLAYER: 3
  };

  $.Params.currentFunc = $.Params.FN.NONE;
  $.Params.funcArgs = [];
  $.Params.isCall = false;

  // 멈춤 현상 방지를 위한 고정 딜레이 값 (마우스와 키보드 입력 업데이트가 선행되고 있으므로)
  $.Params.delay = Number(parameters["Delay"] || 200);

  // ===========================================================================
  // Game_Character
  // ===========================================================================

  var alias_Game_Character_initMembers = Game_Character.prototype.initMembers;
  Game_Character.prototype.initMembers = function() {
    alias_Game_Character_initMembers.call(this);
    this._spritePointer = null;
  };

  Game_Character.prototype.getFrame = function () {
    var sx = this.screenX();
    var sy = this.screenY();

    if(this._spritePointer) {
      return this._spritePointer.getFrame(sx, sy);
    }

    return new Rectangle(sx, sy, $gameMap.tileWidth(), $gameMap.tileHeight() );
  };

  // ===========================================================================
  // Sprite_Character
  // ===========================================================================

  var alias_Sprite_Character_setCharacter = Sprite_Character.prototype.setCharacter;
  Sprite_Character.prototype.setCharacter = function(character) {
    alias_Sprite_Character_setCharacter.call(this, character);

    var self = this;

    this._character._spritePointer = this;

    this.on('removed', function () {
      self._character._spritePointer = null;
    }, this);

  };

  Sprite_Character.prototype.getFrame = function (sx, sy) {
    if (this._tileId > 0) {
        this.updateTileFrame();
    } else {
        this.updateCharacterFrame();
    }

    var tw = $gameMap.tileWidth();
    var th = $gameMap.tileHeight();

    if(this.frame) {
      return this.frame;
    } else {
      return new Rectangle(sx - tw / 2, sy - th, this.width, this.height);
    }

  };

  // ===========================================================================
  // RS.PictureTool
  // ===========================================================================

  $.isMap = function () {
    return SceneManager._scene instanceof Scene_Map;
  };

  /**
   * 픽처 찾기
   */
  $.findPicture = function (picId) {
    var container;
    if(!$.isMap()) return false;
    container = SceneManager._scene._spriteset._pictureContainer.children;
    if(!container) return false;
    return container[picId - 1];
  };

  /**
   * 그림의 영역 찾기
   */
  $.findPictureBound = function(picId) {
    var pic = $.findPicture(picId);
    if(!pic) return false;
    if(pic.frame) {
      return pic.frame;
    } else {
      return new Rectangle(pic.x, pic.y, pic.width, pic.height);
    }
  };

  $.isCheckHit = function (p, q) {
    var ret = false;
    if( (p.x + p.width > q.x) && (p.x < q.x + q.width)) {
      if( (p.y + p.height > q.y) && (p.y < q.y + q.height)) {
        ret = true;
      }
    }
    return ret;
  };

  $.isCheckHitWithCircle = function (p, q) {
    var ret = false;
    var dx, dy, ar, dist;

    dx = p.x - q.x;
    dy = p.y - q.y;
    dist = dx * dx + dy * dy;

    // TODO: 임시로 정한 반지름
    ar = (p.width / 2) + (q.width / 2);

    if ( dist < ar * ar ) {
      ret = true;
    }

    return ret;

  };

  $.isValid = function (picId, eventId, isPlayer) {

    var pic = $.findPictureBound(picId);
    if(!pic) return false;
    if(performance.now() - $.Params.frameTime < $.Params.delay) return false;

    var frame;

    if(isPlayer) {
      frame = $gamePlayer.getFrame();
    } else {
      frame = $gameMap.event(eventId).getFrame();
    }

    return $.isCheckHit(frame, pic);

  };

  $.runEventCollideWithPicture = function (picId, eventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_EVENT_COLLIDE_WITH_PICTURE;
    $.Params.funcArgs = [picId, eventId];
  };

  $.runCommonEventCollideWithPicture = function (picId, eventId, commonEventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PICTURE;
    $.Params.funcArgs = [picId, eventId, commonEventId];
  };

  $.runEventCollideWithPlayer = function (picId, eventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_EVENT_COLLIDE_WITH_PLAYER;
    $.Params.funcArgs = [picId, eventId];
  };

  $.runCommonEventCollideWithPlayer = function (picId, eventId, commonEventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PLAYER;
    $.Params.funcArgs = [picId, eventId, commonEventId];
  };

  /**
   * 특정 그림과 특정 이벤트 eventId가 충돌하면 eventId를 실행합니다.
   */
  $.runEventCollideWithPictureImpl = function (picId, eventId) {

    if(!$.isValid(picId, eventId)) return false;

    var e = $gameMap.event(eventId);

    if(!$gameMap.isEventRunning() && !e.isStarting()) {

      setTimeout(function () {
        e.start();
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 특정 그림과 특정 이벤트 eventId가 충돌하면 특정 커먼 이벤트를 실행합니다.
   */
  $.runCommonEventCollideWithPictureImpl = function (picId, eventId, commonEventId) {

    if(!$.isValid(picId, eventId)) return false;

    if(!$gameMap.isEventRunning()) {

      setTimeout(function () {
        $gameTemp.reserveCommonEvent(commonEventId);
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림과 플레이어가 충돌하면 특정 이벤트를 실행합니다.
   */
  $.runEventCollideWithPlayerImpl = function (picId, eventId) {

    if(!$.isValid(picId, eventId, true)) return false;

    var e = $gameMap.event(eventId);

    if(!$gameMap.isEventRunning() && !e.isStarting()) {

      setTimeout(function () {
        e.start();
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림과 플레이어가 충돌하면 특정 커먼 이벤트를 실행합니다.
   */
  $.runCommonEventCollideWithPlayerImpl = function (picId, eventId, commonEventId) {

    if(!$.isValid(picId, eventId, true)) return false;

    if(!$gameMap.isEventRunning()) {

      setTimeout(function () {
        $gameTemp.reserveCommonEvent(commonEventId);
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림의 표시에서 만든 텍스처를 메모리에서 즉각 제거합니다.
   */
  $.deletePicture = function (picId) {
    var container;
    if(!$.isMap()) return false;
    container = SceneManager._scene._spriteset._pictureContainer;
    if(!container) return false;
    var picSprite = $.findPicture(picId);
    var sprite = new Sprite_Picture(picId);
    container.addChild(sprite);
    container.swapChildren(picSprite, sprite);
    container.removeChild(picSprite);
    picSprite.destroy({children:true, texture:true, baseTexture:true});
  };

  Game_Screen.prototype.erasePicture = function(pictureId) {
    var realPictureId = this.realPictureId(pictureId);
    this._pictures[realPictureId] = null;
    $.deletePicture(realPictureId);
  };

  //============================================================================
  // Scene_Map
  //============================================================================

  Scene_Map.prototype.updatePictureTool = function () {
    if(!$.Params.isCall) return;

    var args = $.Params.funcArgs;

    switch ($.Params.currentFunc) {
      case $.Params.FN.RUN_EVENT_COLLIDE_WITH_PICTURE:
        $.runEventCollideWithPictureImpl(args[0], args[1]);
        break;
      case $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PICTURE:
        $.runCommonEventCollideWithPictureImpl(args[0], args[1], args[2]);
        break;
      case $.Params.FN.RUN_EVENT_COLLIDE_WITH_PLAYER:
        $.runEventCollideWithPlayerImpl(args[0], args[1]);
        break;
      case $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PLAYER:
        $.runCommonEventCollideWithPlayerImpl(args[0], args[1], args[2]);
        break;
    }

    $.Params.isCall = false;
    $.Params.currentFunc = $.Params.FN.NONE;
    $.Params.funcArgs = [];

  };

  var alias_Scene_Map_update = Scene_Map.prototype.update;
  Scene_Map.prototype.update = function() {
    alias_Game_Map_update.call(this);
    this.updatePictureTool();
  };

})(RS.PictureTool);
<commit_msg>Fixed a hanging bug.<commit_after>/*:
 * @plugindesc This plugin allows you to run with two types of events when a certain picture collides with some sprites.
 * @author biud436
 *
 * @param Delay
 * @type number
 * @min 1
 * @desc if it is less than the time you want a delay to take, it will wait the event to complete.
 * @default 200
 *
 * @help
 * =============================================================================
 * Script Calls
 * =============================================================================
 *
 * This command will run some event when it collides with certain picture:
 *
 *    RS.PictureTool.runEventCollideWithPicture(picId, eventId);
 *
 * This command will run the common event when it collides with a picId picture:
 *
 *    RS.PictureTool.runCommonEventCollideWithPicture(picId, eventId, commonEventId);
 *
 * This command will run a certain event when the picture collides with a game player:
 *
 *    RS.PictureTool.runEventCollideWithPlayer(picId, eventId);
 *
 * This command will run a certain common event when the picture collides with a game player:
 *
 *    RS.PictureTool.runCommonEventCollideWithPlayer(picId, eventId, commonEventId);
 *
 * =============================================================================
 * Version Log
 * =============================================================================
 * 2018.04.13 (v1.0.0) - First Release.
 * 2018.04.16 (v1.0.1) - Fixed a hanging bug.
 */
 /*:ko
  * @plugindesc 그림이 특정 캐릭터 스프라이트와 충돌하면 특정 이벤트가 실행됩니다.
  * @author 러닝은빛(biud436)
  *
  * @param Delay
  * @type number
  * @min 1
  * @desc 키보드와 마우스 이벤트 업데이트를 위한 딜레이 시간 (간격이 짧으면 키보드와 마우스가 먹통됩니다, 1000ms = 1초)
  * @default 200
  *
  * @help
  * =============================================================================
  * 스크립트 호출
  * =============================================================================
  *
  * 특정 그림과 특정 이벤트 eventId가 충돌하면 eventId를 실행합니다.
  *
  *    RS.PictureTool.runEventCollideWithPicture(picId, eventId);
  *
  * 특정 그림과 특정 이벤트 eventId가 충돌하면 특정 커먼 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runCommonEventCollideWithPicture(picId, eventId, commonEventId);
  *
  * 그림과 플레이어가 충돌하면 특정 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runEventCollideWithPlayer(picId, eventId);
  *
  * 그림과 플레이어가 충돌하면 특정 커먼 이벤트를 실행합니다.
  *
  *    RS.PictureTool.runCommonEventCollideWithPlayer(picId, eventId, commonEventId);
  *
  * =============================================================================
  * 버전 로그
  * =============================================================================
  * 2018.04.13 (v1.0.0) - 공개
  * 2018.04.16 (v1.0.1) - 멈춤 버그를 수정하였습니다.
  */

var RS = RS || {};

RS.PictureTool = RS.PictureTool || {};

(function ($) {

  var parameters = PluginManager.parameters('RS_PictureTool');

  $.Params = $.Params || {};
  $.Params.frameTime = performance.now();

  $.Params.FN = {
    NONE: -1,
    RUN_EVENT_COLLIDE_WITH_PICTURE: 0,
    RUN_COMMONEVENT_COLLIDE_WITH_PICTURE: 1,
    RUN_EVENT_COLLIDE_WITH_PLAYER: 2,
    RUN_COMMONEVENT_COLLIDEWITH_PLAYER: 3
  };

  $.Params.currentFunc = $.Params.FN.NONE;
  $.Params.funcArgs = [];
  $.Params.isCall = false;

  // 멈춤 현상 방지를 위한 고정 딜레이 값 (마우스와 키보드 입력 업데이트가 선행되고 있으므로)
  $.Params.delay = Number(parameters["Delay"] || 200);

  // ===========================================================================
  // Game_Character
  // ===========================================================================

  var alias_Game_Character_initMembers = Game_Character.prototype.initMembers;
  Game_Character.prototype.initMembers = function() {
    alias_Game_Character_initMembers.call(this);
    this._spritePointer = null;
  };

  Game_Character.prototype.getFrame = function () {
    var sx = this.screenX();
    var sy = this.screenY();

    if(this._spritePointer) {
      return this._spritePointer.getFrame(sx, sy);
    }

    return new Rectangle(sx, sy, $gameMap.tileWidth(), $gameMap.tileHeight() );
  };

  // ===========================================================================
  // Sprite_Character
  // ===========================================================================

  var alias_Sprite_Character_setCharacter = Sprite_Character.prototype.setCharacter;
  Sprite_Character.prototype.setCharacter = function(character) {
    alias_Sprite_Character_setCharacter.call(this, character);

    var self = this;

    this._character._spritePointer = this;

    this.on('removed', function () {
      self._character._spritePointer = null;
    }, this);

  };

  Sprite_Character.prototype.getFrame = function (sx, sy) {
    if (this._tileId > 0) {
        this.updateTileFrame();
    } else {
        this.updateCharacterFrame();
    }

    var tw = $gameMap.tileWidth();
    var th = $gameMap.tileHeight();

    if(this.frame) {
      return this.frame;
    } else {
      return new Rectangle(sx - tw / 2, sy - th, this.width, this.height);
    }

  };

  // ===========================================================================
  // RS.PictureTool
  // ===========================================================================

  $.isMap = function () {
    return SceneManager._scene instanceof Scene_Map;
  };

  /**
   * 픽처 찾기
   */
  $.findPicture = function (picId) {
    var container;
    if(!$.isMap()) return false;
    container = SceneManager._scene._spriteset._pictureContainer.children;
    if(!container) return false;
    return container[picId - 1];
  };

  /**
   * 그림의 영역 찾기
   */
  $.findPictureBound = function(picId) {
    var pic = $.findPicture(picId);
    if(!pic) return false;
    if(pic.frame) {
      return pic.frame;
    } else {
      return new Rectangle(pic.x, pic.y, pic.width, pic.height);
    }
  };

  $.isCheckHit = function (p, q) {
    var ret = false;
    if( (p.x + p.width > q.x) && (p.x < q.x + q.width)) {
      if( (p.y + p.height > q.y) && (p.y < q.y + q.height)) {
        ret = true;
      }
    }
    return ret;
  };

  $.isCheckHitWithCircle = function (p, q) {
    var ret = false;
    var dx, dy, ar, dist;

    dx = p.x - q.x;
    dy = p.y - q.y;
    dist = dx * dx + dy * dy;

    // TODO: 임시로 정한 반지름
    ar = (p.width / 2) + (q.width / 2);

    if ( dist < ar * ar ) {
      ret = true;
    }

    return ret;

  };

  $.isValid = function (picId, eventId, isPlayer) {

    var pic = $.findPictureBound(picId);
    if(!pic) return false;
    if(performance.now() - $.Params.frameTime < $.Params.delay) return false;

    var frame;

    if(isPlayer) {
      frame = $gamePlayer.getFrame();
    } else {
      frame = $gameMap.event(eventId).getFrame();
    }

    return $.isCheckHit(frame, pic);

  };

  $.runEventCollideWithPicture = function (picId, eventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_EVENT_COLLIDE_WITH_PICTURE;
    $.Params.funcArgs = [picId, eventId];
  };

  $.runCommonEventCollideWithPicture = function (picId, eventId, commonEventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PICTURE;
    $.Params.funcArgs = [picId, eventId, commonEventId];
  };

  $.runEventCollideWithPlayer = function (picId, eventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_EVENT_COLLIDE_WITH_PLAYER;
    $.Params.funcArgs = [picId, eventId];
  };

  $.runCommonEventCollideWithPlayer = function (picId, eventId, commonEventId) {
    $.Params.isCall = true;
    $.Params.currentFunc = $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PLAYER;
    $.Params.funcArgs = [picId, eventId, commonEventId];
  };

  /**
   * 특정 그림과 특정 이벤트 eventId가 충돌하면 eventId를 실행합니다.
   */
  $.runEventCollideWithPictureImpl = function (picId, eventId) {

    if(!$.isValid(picId, eventId)) return false;

    var e = $gameMap.event(eventId);

    if(!$gameMap.isEventRunning() && !e.isStarting()) {

      setTimeout(function () {
        e.start();
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 특정 그림과 특정 이벤트 eventId가 충돌하면 특정 커먼 이벤트를 실행합니다.
   */
  $.runCommonEventCollideWithPictureImpl = function (picId, eventId, commonEventId) {

    if(!$.isValid(picId, eventId)) return false;

    if(!$gameMap.isEventRunning()) {

      setTimeout(function () {
        $gameTemp.reserveCommonEvent(commonEventId);
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림과 플레이어가 충돌하면 특정 이벤트를 실행합니다.
   */
  $.runEventCollideWithPlayerImpl = function (picId, eventId) {

    if(!$.isValid(picId, eventId, true)) return false;

    var e = $gameMap.event(eventId);

    if(!$gameMap.isEventRunning() && !e.isStarting()) {

      setTimeout(function () {
        e.start();
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림과 플레이어가 충돌하면 특정 커먼 이벤트를 실행합니다.
   */
  $.runCommonEventCollideWithPlayerImpl = function (picId, eventId, commonEventId) {

    if(!$.isValid(picId, eventId, true)) return false;

    if(!$gameMap.isEventRunning()) {

      setTimeout(function () {
        $gameTemp.reserveCommonEvent(commonEventId);
      }, 0);

    }

    $.Params.frameTime = performance.now();

    return true;

  };

  /**
   * 그림의 표시에서 만든 텍스처를 메모리에서 즉각 제거합니다.
   */
  $.deletePicture = function (picId) {
    var container;
    if(!$.isMap()) return false;
    container = SceneManager._scene._spriteset._pictureContainer;
    if(!container) return false;
    var picSprite = $.findPicture(picId);
    var sprite = new Sprite_Picture(picId);
    container.addChild(sprite);
    container.swapChildren(picSprite, sprite);
    container.removeChild(picSprite);
    picSprite.destroy({children:true, texture:true, baseTexture:true});
  };

  Game_Screen.prototype.erasePicture = function(pictureId) {
    var realPictureId = this.realPictureId(pictureId);
    this._pictures[realPictureId] = null;
    $.deletePicture(realPictureId);
  };

  //============================================================================
  // Scene_Map
  //============================================================================

  Scene_Map.prototype.updatePictureTool = function () {
    if(!$.Params.isCall) return;

    var args = $.Params.funcArgs;

    switch ($.Params.currentFunc) {
      case $.Params.FN.RUN_EVENT_COLLIDE_WITH_PICTURE:
        $.runEventCollideWithPictureImpl(args[0], args[1]);
        break;
      case $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PICTURE:
        $.runCommonEventCollideWithPictureImpl(args[0], args[1], args[2]);
        break;
      case $.Params.FN.RUN_EVENT_COLLIDE_WITH_PLAYER:
        $.runEventCollideWithPlayerImpl(args[0], args[1]);
        break;
      case $.Params.FN.RUN_COMMONEVENT_COLLIDE_WITH_PLAYER:
        $.runCommonEventCollideWithPlayerImpl(args[0], args[1], args[2]);
        break;
    }

    $.Params.isCall = false;
    $.Params.currentFunc = $.Params.FN.NONE;
    $.Params.funcArgs = [];

  };

  var alias_Scene_Map_update = Scene_Map.prototype.update;
  Scene_Map.prototype.update = function() {
    alias_Scene_Map_update.call(this);
    this.updatePictureTool();
  };

})(RS.PictureTool);
<|endoftext|>


<commit_before>'use strict';

var Defaults = {};

Defaults.MIN_FEE_PER_KB = 0;
Defaults.MAX_FEE_PER_KB = 10000 * 1000; // 10k sat/b
Defaults.MIN_TX_FEE = 0;
Defaults.MAX_TX_FEE = 0.1 * 1e8;
Defaults.MAX_TX_SIZE_IN_KB = 100;

Defaults.MAX_KEYS = 100;

// Time after which a tx proposal can be erased by any copayer. in seconds
Defaults.DELETE_LOCKTIME = 600;

// Allowed consecutive txp rejections before backoff is applied.
Defaults.BACKOFF_OFFSET = 10;

// Time a copayer need to wait to create a new tx after her previous proposal was rejected. in seconds.
Defaults.BACKOFF_TIME = 600;

Defaults.MAX_MAIN_ADDRESS_GAP = 20;

// TODO: should allow different gap sizes for external/internal chains
Defaults.SCAN_ADDRESS_GAP = Defaults.MAX_MAIN_ADDRESS_GAP + 10;

Defaults.FEE_LEVELS = {
  btc: [{
    name: 'urgent',
    nbBlocks: 2,
    multiplier: 1.5,
    defaultValue: 75000,
  }, {
    name: 'priority',
    nbBlocks: 2,
    defaultValue: 50000
  }, {
    name: 'normal',
    nbBlocks: 3,
    defaultValue: 30000
  }, {
    name: 'economy',
    nbBlocks: 6,
    defaultValue: 25000
  }, {
    name: 'superEconomy',
    nbBlocks: 24,
    defaultValue: 10000
  }],
  bch: [{
    name: 'normal',
    nbBlocks: 2,
    defaultValue: 2000,
  }]
};

// How many levels to fallback to if the value returned by the network for a given nbBlocks is -1
Defaults.FEE_LEVELS_FALLBACK = 2;

Defaults.FIAT_RATE_PROVIDER = 'BitPay';
Defaults.FIAT_RATE_FETCH_INTERVAL = 10; // In minutes
Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME = 120; // In minutes

Defaults.HISTORY_LIMIT = 1001;

// The maximum amount of an UTXO to be considered too big to be used in the tx before exploring smaller
// alternatives (proportinal to tx amount).
Defaults.UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR = 2;

// The minimum amount an UTXO need to contribute proportional to tx amount.
Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR = 0.1;

// The maximum threshold to consider fees non-significant in relation to tx amount.
Defaults.UTXO_SELECTION_MAX_FEE_VS_TX_AMOUNT_FACTOR = 0.05;

// The maximum amount to pay for using small inputs instead of one big input
// when fees are significant (proportional to how much we would pay for using that big input only).
Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR = 5;

// Minimum allowed amount for tx outputs (including change) in SAT
Defaults.MIN_OUTPUT_AMOUNT = 5000;

// Number of confirmations from which tx in history will be cached
// (ie we consider them inmutables)
Defaults.CONFIRMATIONS_TO_START_CACHING = 6 * 6; // ~ 6hrs

// Number of addresses from which tx history is enabled in a wallet
Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100;

// Number of addresses from which balance in cache for a few seconds
Defaults.BALANCE_CACHE_ADDRESS_THRESOLD = Defaults.HISTORY_CACHE_ADDRESS_THRESOLD;

Defaults.BALANCE_CACHE_DURATION = 10;

// Cache time for blockchain height (in ms)
// this is actually erased on 'new block' notifications
// so, 30m seems fine
Defaults.BLOCKHEIGHT_CACHE_TIME = 30 * 60 * 1000;

// Cache time fee levels (in ms)
Defaults.FEE_LEVEL_CACHE_DURATION = 30 * 60 * 1000;

// Max allowed timespan for notification queries in seconds
Defaults.MAX_NOTIFICATIONS_TIMESPAN = 60 * 60 * 24 * 14; // ~ 2 weeks
Defaults.NOTIFICATIONS_TIMESPAN = 60;

Defaults.SESSION_EXPIRATION = 1 * 60 * 60; // 1 hour to session expiration

Defaults.RateLimit = {
  createWallet: {
    windowMs: 60 * 60 * 1000, // hour window
    delayAfter: 8, // begin slowing down responses after the 3rd request
    delayMs: 3000, // slow down subsequent responses by 3 seconds per request
    max: 15, // start blocking after 20 request
    message: 'Too many wallets created from this IP, please try again after an hour',
  },
  estimateFee: {
   windowMs: 60 * 10 *1000, // 10 min window
    delayAfter: 5, // begin slowing down responses after the 3rd request
    delayMs: 300, // slow down subsequent responses by 3 seconds per request

    max: 10, // start blocking after 200 request
    message: 'Too many request',
  },

  // otherPosts: {
  //   windowMs: 60 * 60 * 1000, // 1 hour window
  //   max: 1200 , // 1 post every 3 sec average, max.
  // },
};

Defaults.COIN = 'btc';
Defaults.INSIGHT_REQUEST_POOL_SIZE = 10;
Defaults.INSIGHT_TIMEOUT = 30000;

Defaults.ADDRESS_SYNC_BATCH_SIZE = 500000;

Defaults.LOCK_WAIT_TIME =    5 * 1000; // wait time 5s
Defaults.LOCK_EXE_TIME =     40 * 1000; // max lock time 50s
Defaults.SERVER_EXE_TIME = Defaults.LOCK_EXE_TIME * 1.5;

Defaults.BE_KEY_SALT = 'bws-auth-keysalt';

module.exports = Defaults;
<commit_msg>change dflt fee cache duration to 6 min<commit_after>'use strict';

var Defaults = {};

Defaults.MIN_FEE_PER_KB = 0;
Defaults.MAX_FEE_PER_KB = 10000 * 1000; // 10k sat/b
Defaults.MIN_TX_FEE = 0;
Defaults.MAX_TX_FEE = 0.1 * 1e8;
Defaults.MAX_TX_SIZE_IN_KB = 100;

Defaults.MAX_KEYS = 100;

// Time after which a tx proposal can be erased by any copayer. in seconds
Defaults.DELETE_LOCKTIME = 600;

// Allowed consecutive txp rejections before backoff is applied.
Defaults.BACKOFF_OFFSET = 10;

// Time a copayer need to wait to create a new tx after her previous proposal was rejected. in seconds.
Defaults.BACKOFF_TIME = 600;

Defaults.MAX_MAIN_ADDRESS_GAP = 20;

// TODO: should allow different gap sizes for external/internal chains
Defaults.SCAN_ADDRESS_GAP = Defaults.MAX_MAIN_ADDRESS_GAP + 10;

Defaults.FEE_LEVELS = {
  btc: [{
    name: 'urgent',
    nbBlocks: 2,
    multiplier: 1.5,
    defaultValue: 75000,
  }, {
    name: 'priority',
    nbBlocks: 2,
    defaultValue: 50000
  }, {
    name: 'normal',
    nbBlocks: 3,
    defaultValue: 30000
  }, {
    name: 'economy',
    nbBlocks: 6,
    defaultValue: 25000
  }, {
    name: 'superEconomy',
    nbBlocks: 24,
    defaultValue: 10000
  }],
  bch: [{
    name: 'normal',
    nbBlocks: 2,
    defaultValue: 2000,
  }]
};

// How many levels to fallback to if the value returned by the network for a given nbBlocks is -1
Defaults.FEE_LEVELS_FALLBACK = 2;

Defaults.FIAT_RATE_PROVIDER = 'BitPay';
Defaults.FIAT_RATE_FETCH_INTERVAL = 10; // In minutes
Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME = 120; // In minutes

Defaults.HISTORY_LIMIT = 1001;

// The maximum amount of an UTXO to be considered too big to be used in the tx before exploring smaller
// alternatives (proportinal to tx amount).
Defaults.UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR = 2;

// The minimum amount an UTXO need to contribute proportional to tx amount.
Defaults.UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR = 0.1;

// The maximum threshold to consider fees non-significant in relation to tx amount.
Defaults.UTXO_SELECTION_MAX_FEE_VS_TX_AMOUNT_FACTOR = 0.05;

// The maximum amount to pay for using small inputs instead of one big input
// when fees are significant (proportional to how much we would pay for using that big input only).
Defaults.UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR = 5;

// Minimum allowed amount for tx outputs (including change) in SAT
Defaults.MIN_OUTPUT_AMOUNT = 5000;

// Number of confirmations from which tx in history will be cached
// (ie we consider them inmutables)
Defaults.CONFIRMATIONS_TO_START_CACHING = 6 * 6; // ~ 6hrs

// Number of addresses from which tx history is enabled in a wallet
Defaults.HISTORY_CACHE_ADDRESS_THRESOLD = 100;

// Number of addresses from which balance in cache for a few seconds
Defaults.BALANCE_CACHE_ADDRESS_THRESOLD = Defaults.HISTORY_CACHE_ADDRESS_THRESOLD;

Defaults.BALANCE_CACHE_DURATION = 10;

// Cache time for blockchain height (in ms)
// this is actually erased on 'new block' notifications
// so, 30m seems fine
Defaults.BLOCKHEIGHT_CACHE_TIME = 30 * 60 * 1000;

// Cache time fee levels (in ms)
Defaults.FEE_LEVEL_CACHE_DURATION = 6 * 60 * 1000;

// Max allowed timespan for notification queries in seconds
Defaults.MAX_NOTIFICATIONS_TIMESPAN = 60 * 60 * 24 * 14; // ~ 2 weeks
Defaults.NOTIFICATIONS_TIMESPAN = 60;

Defaults.SESSION_EXPIRATION = 1 * 60 * 60; // 1 hour to session expiration

Defaults.RateLimit = {
  createWallet: {
    windowMs: 60 * 60 * 1000, // hour window
    delayAfter: 8, // begin slowing down responses after the 3rd request
    delayMs: 3000, // slow down subsequent responses by 3 seconds per request
    max: 15, // start blocking after 20 request
    message: 'Too many wallets created from this IP, please try again after an hour',
  },
  estimateFee: {
   windowMs: 60 * 10 *1000, // 10 min window
    delayAfter: 5, // begin slowing down responses after the 3rd request
    delayMs: 300, // slow down subsequent responses by 3 seconds per request

    max: 10, // start blocking after 200 request
    message: 'Too many request',
  },

  // otherPosts: {
  //   windowMs: 60 * 60 * 1000, // 1 hour window
  //   max: 1200 , // 1 post every 3 sec average, max.
  // },
};

Defaults.COIN = 'btc';
Defaults.INSIGHT_REQUEST_POOL_SIZE = 10;
Defaults.INSIGHT_TIMEOUT = 30000;

Defaults.ADDRESS_SYNC_BATCH_SIZE = 500000;

Defaults.LOCK_WAIT_TIME =    5 * 1000; // wait time 5s
Defaults.LOCK_EXE_TIME =     40 * 1000; // max lock time 50s
Defaults.SERVER_EXE_TIME = Defaults.LOCK_EXE_TIME * 1.5;

Defaults.BE_KEY_SALT = 'bws-auth-keysalt';

module.exports = Defaults;
<|endoftext|>


<commit_before>import {types as tt} from "./tokentype"
import {Parser} from "./state"
import {reservedWords} from "./identifier"
import {has} from "./util"

const pp = Parser.prototype

// Convert existing expression atom to assignable pattern
// if possible.

pp.toAssignable = function(node, isBinding) {
  if (this.options.ecmaVersion >= 6 && node) {
    switch (node.type) {
    case "Identifier":
    case "ObjectPattern":
    case "ArrayPattern":
    case "AssignmentPattern":
      break

    case "ObjectExpression":
      node.type = "ObjectPattern"
      for (let i = 0; i < node.properties.length; i++) {
        let prop = node.properties[i]
        if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter")
        this.toAssignable(prop.value, isBinding)
      }
      break

    case "ArrayExpression":
      node.type = "ArrayPattern"
      this.toAssignableList(node.elements, isBinding)
      break

    case "AssignmentExpression":
      if (node.operator === "=") {
        node.type = "AssignmentPattern"
      } else {
        this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
      }
      break

    case "MemberExpression":
      if (!isBinding) break

    default:
      this.raise(node.start, "Assigning to rvalue")
    }
  }
  return node
}

// Convert list of expression atoms to binding list.

pp.toAssignableList = function(exprList, isBinding) {
  let end = exprList.length
  if (end) {
    let last = exprList[end - 1]
    if (last && last.type == "RestElement") {
      --end
    } else if (last && last.type == "SpreadElement") {
      last.type = "RestElement"
      let arg = last.argument
      this.toAssignable(arg, isBinding)
      if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
        this.unexpected(arg.start)
      --end
    }
  }
  for (let i = 0; i < end; i++) {
    let elt = exprList[i]
    if (elt) this.toAssignable(elt, isBinding)
  }
  return exprList
}

// Parses spread element.

pp.parseSpread = function(refShorthandDefaultPos) {
  let node = this.startNode()
  this.next()
  node.argument = this.parseMaybeAssign(refShorthandDefaultPos)
  return this.finishNode(node, "SpreadElement")
}

pp.parseRest = function() {
  let node = this.startNode()
  this.next()
  node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected()
  return this.finishNode(node, "RestElement")
}

// Parses lvalue (assignable) atom.

pp.parseBindingAtom = function() {
  if (this.options.ecmaVersion < 6) return this.parseIdent()
  switch (this.type) {
  case tt.name:
    return this.parseIdent()

  case tt.bracketL:
    let node = this.startNode()
    this.next()
    node.elements = this.parseBindingList(tt.bracketR, true, true)
    return this.finishNode(node, "ArrayPattern")

  case tt.braceL:
    return this.parseObj(true)

  default:
    this.unexpected()
  }
}

pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
  var elts = [], first = true
  while (!this.eat(close)) {
    if (first) first = false
    else this.expect(tt.comma)
    if (allowEmpty && this.type === tt.comma) {
      elts.push(null)
    } else if (allowTrailingComma && this.afterTrailingComma(close)) {
      break
    } else if (this.type === tt.ellipsis) {
      elts.push(this.parseAssignableListItemTypes(this.parseRest()))
      this.expect(close)
      break
    } else {
      var left = this.parseMaybeDefault()
      this.parseAssignableListItemTypes(left)
      elts.push(this.parseMaybeDefault(null, left))
    }
  }
  return elts
}

pp.parseAssignableListItemTypes = function(param) {
  return param
}

// Parses assignment pattern around given atom if possible.

pp.parseMaybeDefault = function(startPos, left) {
  startPos = startPos || this.markPosition()
  left = left || this.parseBindingAtom()
  if (!this.eat(tt.eq)) return left
  let node = this.startNodeAt(startPos)
  node.operator = "="
  node.left = left
  node.right = this.parseMaybeAssign()
  return this.finishNode(node, "AssignmentPattern")
}

// Verify that a node is an lval — something that can be assigned
// to.

pp.checkLVal = function(expr, isBinding, checkClashes) {
  switch (expr.type) {
  case "Identifier":
    if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name)))
      this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode")
    if (checkClashes) {
      if (has(checkClashes, expr.name))
        this.raise(expr.start, "Argument name clash in strict mode")
      checkClashes[expr.name] = true
    }
    break

  case "MemberExpression":
    if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression")
    break

  case "ObjectPattern":
    for (let i = 0; i < expr.properties.length; i++) {
      var prop = expr.properties[i];
      if (prop.type === "Property") prop = prop.value;
      this.checkLVal(prop, isBinding, checkClashes)
    }
    break

  case "ArrayPattern":
    for (let i = 0; i < expr.elements.length; i++) {
      let elem = expr.elements[i]
      if (elem) this.checkLVal(elem, isBinding, checkClashes)
    }
    break

  case "AssignmentPattern":
    this.checkLVal(expr.left, isBinding, checkClashes)
    break

  case "SpreadProperty":
  case "RestElement":
    this.checkLVal(expr.argument, isBinding, checkClashes)
    break

  default:
    this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
  }
}
<commit_msg>fix spread properties in assignment position - fixes #1315<commit_after>import {types as tt} from "./tokentype"
import {Parser} from "./state"
import {reservedWords} from "./identifier"
import {has} from "./util"

const pp = Parser.prototype

// Convert existing expression atom to assignable pattern
// if possible.

pp.toAssignable = function(node, isBinding) {
  if (this.options.ecmaVersion >= 6 && node) {
    switch (node.type) {
    case "Identifier":
    case "ObjectPattern":
    case "ArrayPattern":
    case "AssignmentPattern":
      break

    case "ObjectExpression":
      node.type = "ObjectPattern"
      for (let i = 0; i < node.properties.length; i++) {
        let prop = node.properties[i]
        if (prop.type === "SpreadProperty") continue;
        if (prop.kind !== "init") this.raise(prop.key.start, "Object pattern can't contain getter or setter")
        this.toAssignable(prop.value, isBinding)
      }
      break

    case "ArrayExpression":
      node.type = "ArrayPattern"
      this.toAssignableList(node.elements, isBinding)
      break

    case "AssignmentExpression":
      if (node.operator === "=") {
        node.type = "AssignmentPattern"
      } else {
        this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
      }
      break

    case "MemberExpression":
      if (!isBinding) break

    default:
      this.raise(node.start, "Assigning to rvalue")
    }
  }
  return node
}

// Convert list of expression atoms to binding list.

pp.toAssignableList = function(exprList, isBinding) {
  let end = exprList.length
  if (end) {
    let last = exprList[end - 1]
    if (last && last.type == "RestElement") {
      --end
    } else if (last && last.type == "SpreadElement") {
      last.type = "RestElement"
      let arg = last.argument
      this.toAssignable(arg, isBinding)
      if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern")
        this.unexpected(arg.start)
      --end
    }
  }
  for (let i = 0; i < end; i++) {
    let elt = exprList[i]
    if (elt) this.toAssignable(elt, isBinding)
  }
  return exprList
}

// Parses spread element.

pp.parseSpread = function(refShorthandDefaultPos) {
  let node = this.startNode()
  this.next()
  node.argument = this.parseMaybeAssign(refShorthandDefaultPos)
  return this.finishNode(node, "SpreadElement")
}

pp.parseRest = function() {
  let node = this.startNode()
  this.next()
  node.argument = this.type === tt.name || this.type === tt.bracketL ? this.parseBindingAtom() : this.unexpected()
  return this.finishNode(node, "RestElement")
}

// Parses lvalue (assignable) atom.

pp.parseBindingAtom = function() {
  if (this.options.ecmaVersion < 6) return this.parseIdent()
  switch (this.type) {
  case tt.name:
    return this.parseIdent()

  case tt.bracketL:
    let node = this.startNode()
    this.next()
    node.elements = this.parseBindingList(tt.bracketR, true, true)
    return this.finishNode(node, "ArrayPattern")

  case tt.braceL:
    return this.parseObj(true)

  default:
    this.unexpected()
  }
}

pp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {
  var elts = [], first = true
  while (!this.eat(close)) {
    if (first) first = false
    else this.expect(tt.comma)
    if (allowEmpty && this.type === tt.comma) {
      elts.push(null)
    } else if (allowTrailingComma && this.afterTrailingComma(close)) {
      break
    } else if (this.type === tt.ellipsis) {
      elts.push(this.parseAssignableListItemTypes(this.parseRest()))
      this.expect(close)
      break
    } else {
      var left = this.parseMaybeDefault()
      this.parseAssignableListItemTypes(left)
      elts.push(this.parseMaybeDefault(null, left))
    }
  }
  return elts
}

pp.parseAssignableListItemTypes = function(param) {
  return param
}

// Parses assignment pattern around given atom if possible.

pp.parseMaybeDefault = function(startPos, left) {
  startPos = startPos || this.markPosition()
  left = left || this.parseBindingAtom()
  if (!this.eat(tt.eq)) return left
  let node = this.startNodeAt(startPos)
  node.operator = "="
  node.left = left
  node.right = this.parseMaybeAssign()
  return this.finishNode(node, "AssignmentPattern")
}

// Verify that a node is an lval — something that can be assigned
// to.

pp.checkLVal = function(expr, isBinding, checkClashes) {
  switch (expr.type) {
  case "Identifier":
    if (this.strict && (reservedWords.strictBind(expr.name) || reservedWords.strict(expr.name)))
      this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode")
    if (checkClashes) {
      if (has(checkClashes, expr.name))
        this.raise(expr.start, "Argument name clash in strict mode")
      checkClashes[expr.name] = true
    }
    break

  case "MemberExpression":
    if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression")
    break

  case "ObjectPattern":
    for (let i = 0; i < expr.properties.length; i++) {
      var prop = expr.properties[i];
      if (prop.type === "Property") prop = prop.value;
      this.checkLVal(prop, isBinding, checkClashes)
    }
    break

  case "ArrayPattern":
    for (let i = 0; i < expr.elements.length; i++) {
      let elem = expr.elements[i]
      if (elem) this.checkLVal(elem, isBinding, checkClashes)
    }
    break

  case "AssignmentPattern":
    this.checkLVal(expr.left, isBinding, checkClashes)
    break

  case "SpreadProperty":
  case "RestElement":
    this.checkLVal(expr.argument, isBinding, checkClashes)
    break

  default:
    this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
  }
}
<|endoftext|>


<commit_before>var tempo = 120;

console.log(!!performance);

var time = !!performance ? performance : Date;

function getNow () {
  return time.now() | 0;
}

var timing = {
  startTime: getNow(),
  pattern: function (beat, noteValue) {
    return (beat / noteValue * this.note(1)) | 0;
  },
  note: function (noteValue) {
    return (60 / tempo * 4000 / noteValue) | 0;
  },
  current: function (){
    return getNow() - this.startTime;
  },
};
<commit_msg>fix ios compat<commit_after>var tempo = 120;

var performance = performance;

var time = !!performance ? performance : Date;

function getNow () {
  return time.now() | 0;
}

var timing = {
  startTime: getNow(),
  pattern: function (beat, noteValue) {
    return (beat / noteValue * this.note(1)) | 0;
  },
  note: function (noteValue) {
    return (60 / tempo * 4000 / noteValue) | 0;
  },
  current: function (){
    return getNow() - this.startTime;
  },
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'
process.title = 'ucompiler'

require('debug').enable('UCompiler:*')
var UCompiler = require('..')
var knownCommands = ['go', 'watch']
var parameters = process.argv.slice(2)

if (!parameters.length || knownCommands.indexOf(parameters[0]) === -1) {
  console.log('Usage: ucompiler go|watch [path]')
  process.exit(0)
}

const options = {
  save: true,
  saveIncludedFiles: false,
  errorCallback: function(e) {
    console.log(e.stack)
  }
}
if (parameters[0] === 'go') {
  UCompiler.compile(process.cwd(), options, parameters[1] || null).then(function(result) {
    if (!result.status) {
      process.exit(1)
    }
  }, function(e) {
    console.error(e.stack)
    process.exit(1)
  })
} else if (parameters[0] === 'watch') {
  UCompiler.watch(
    process.cwd(),
    options,
    parameters[1] ?
      parameters[1]
        .split(',')
        .map(function(_) { return _.trim()})
        .filter(function(_) { return _}) : parameters[1]
  ).catch(e => console.log(e.stack))
}
<commit_msg>:bug: Log e instead of stack when stack is not found<commit_after>#!/usr/bin/env node
'use strict'
process.title = 'ucompiler'

require('debug').enable('UCompiler:*')
var UCompiler = require('..')
var knownCommands = ['go', 'watch']
var parameters = process.argv.slice(2)

if (!parameters.length || knownCommands.indexOf(parameters[0]) === -1) {
  console.log('Usage: ucompiler go|watch [path]')
  process.exit(0)
}

const options = {
  save: true,
  saveIncludedFiles: false,
  errorCallback: function(e) {
    console.log(e.stack || e)
  }
}
if (parameters[0] === 'go') {
  UCompiler.compile(process.cwd(), options, parameters[1] || null).then(function(result) {
    if (!result.status) {
      process.exit(1)
    }
  }, function(e) {
    errorCallback(e)
    process.exit(1)
  })
} else if (parameters[0] === 'watch') {
  UCompiler.watch(
    process.cwd(),
    options,
    parameters[1] ?
      parameters[1]
        .split(',')
        .map(function(_) { return _.trim()})
        .filter(function(_) { return _}) : parameters[1]
  ).catch(errorCallback)
}
<|endoftext|>