<commit_before>/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
 * for the full text of the license. */

OpenLayers.ProxyHost = "";
//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";

/**
 * Ajax reader for OpenLayers
 *
 *  @uri url to do remote XML http get
 *  @param {String} 'get' format params (x=y&a=b...)
 *  @who object to handle callbacks for this request
 *  @complete  the function to be called on success
 *  @failure  the function to be called on failure
 *
 *   example usage from a caller:
 *
 *     caps: function(request) {
 *      -blah-
 *     },
 *
 *     OpenLayers.loadURL(url,params,this,caps);
 *
 * Notice the above example does not provide an error handler; a default empty
 * handler is provided which merely logs the error if a failure handler is not
 * supplied
 *
 */

/**
* @param {} request
*/
OpenLayers.nullHandler = function(request) {
    alert("Unhandled request return " + request.statusText);
};

/**
 * Function: loadURL
 * Background load a document.
 *
 * Parameters:
 * uri - {String} URI of source doc
 * params - {String} Params on get (doesnt seem to work)
 * caller - {Object} object which gets callbacks
 * onComplete - {Function} callback for success
 * onFailure - {Function} callback for failure
 *
 * Both callbacks optional (though silly)
 */
OpenLayers.loadURL = function(uri, params, caller,
                                  onComplete, onFailure) {

    if (OpenLayers.ProxyHost && uri.startsWith("http")) {
        uri = OpenLayers.ProxyHost + escape(uri);
    }

    var success = (onComplete) ? onComplete.bind(caller)
                                : OpenLayers.nullHandler;

    var failure = (onFailure) ? onFailure.bind(caller)
                           : OpenLayers.nullHandler;

    // from prototype.js
    new OpenLayers.Ajax.Request(uri,
                     {   method: 'get',
                         parameters: params,
                         onComplete: success,
                         onFailure: failure
                      }
                     );
};

/**
 * Function: parseXMLString
 * Parse XML into a doc structure
 *
 * Parameters:
 * text - {String}
 *
 * Return:
 * {?} Parsed AJAX Responsev
 */
OpenLayers.parseXMLString = function(text) {

    //MS sucks, if the server is bad it dies
    var index = text.indexOf('<');
    if (index > 0) {
        text = text.substring(index);
    }

    var ajaxResponse = OpenLayers.Util.Try(
        function() {
            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
            xmldom.loadXML(text);
            return xmldom;
        },
        function() {
            return new DOMParser().parseFromString(text, 'text/xml');
        },
        function() {
            var req = new XMLHttpRequest();
            req.open("GET", "data:" + "text/xml" +
                     ";charset=utf-8," + encodeURIComponent(text), false);
            if (req.overrideMimeType) {
                req.overrideMimeType("text/xml");
            }
            req.send(null);
            return req.responseXML;
        }
    );

    return ajaxResponse;
};

/**
 * Namespace: OpenLayers.Ajax
 */
OpenLayers.Ajax = {

    /**
     * Method: emptyFunction
     */
    emptyFunction: function () {},

    /**
     * Method: getTransport
     *
     * Return:
     * {Object} Transport mechanism for whichever browser we're in, or false if
     *          none available.
     */
    getTransport: function() {
        return OpenLayers.Util.Try(
            function() {return new ActiveXObject('Msxml2.XMLHTTP')},
            function() {return new ActiveXObject('Microsoft.XMLHTTP')},
            function() {return new XMLHttpRequest()}
        ) || false;
    },

    /**
     * Property: activeRequestCount
     * {Integer}
     */
    activeRequestCount: 0
};

/**
 * Namespace: OpenLayers.Ajax.Responders
 * {Object}
 */
OpenLayers.Ajax.Responders = {

    /**
     * Property: responders
     * {Array}
     */
    responders: [],

    /**
     * Method: register
     *
     * Parameters:
     * responderToAdd - {?}
     */
    register: function(responderToAdd) {
      for (var i = 0; i < this.responders.length; i++)
          if (responderToAdd == this.responders[i])
              return;
      this.responders.push(responderToAdd);
    },

    /**
     * Method: dispatch
     *
     * Parameters:
     * callback - {?}
     * request - {?}
     * transport - {?}
     * json - {?}
     */
    dispatch: function(callback, request, transport, json) {
        for (var i = 0; i < this.responders.length; i++) {
            responder = this.responders[i];

            if (responder[callback] &&
                typeof responder[callback] == 'function') {
                try {
                    responder[callback].apply(responder,
                                              [request, transport, json]);
                } catch (e) {}
            }
        }
    }
};

OpenLayers.Ajax.Responders.register({
    /**
     * Function: onCreate
     */
    onCreate: function() {
        OpenLayers.Ajax.activeRequestCount++;
    },

    /**
     * Function: onComplete
     */
     onComplete: function() {
         OpenLayers.Ajax.activeRequestCount--;
     }
});

/**
 * Namespace: OpenLayers.Ajax.Base
 * {Object}
 */
OpenLayers.Ajax.Base = function() {};
OpenLayers.Ajax.Base.prototype = {

    /**
     * Function: setOptions
     *
     * Parameters:
     * options - {Object}
     */
    setOptions: function(options) {
        this.options = {
            'method': 'post',
            'asynchronous': true,
            'parameters': ''
        };
        OpenLayers.Util.extend(this.options, options || {});
    },

    /**
     * Function: responseIsSuccess
     *
     * Return:
     * {Boolean}
     */
    responseIsSuccess: function() {
        return this.transport.status == undefined ||
               this.transport.status == 0 ||
               (this.transport.status >= 200 && this.transport.status < 300);
    },

    /**
     * Function: responseIsFailure
     *
     * Return:
     * {Boolean}
     */
    responseIsFailure: function() {
        return !this.responseIsSuccess();
    }
};

/**
 * Class: OpenLayers.Ajax.Request
 *
 * Inherit:
 *  - <OpenLayers.Ajax.Base>
 */
OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {

      /**
       * Constructor: OpenLayers.Ajax.Request
       *
       * Parameters:
       * url - {String}
       * options - {Object}
       */
    initialize: function(url, options) {
        this.transport = OpenLayers.Ajax.getTransport();
        this.setOptions(options);
        this.request(url);
    },

    /**
     * Method: request
     *
     * Parameters:
     * url - {String}
     */
    request: function(url) {
        var parameters = this.options.parameters || '';
        if (parameters.length > 0) parameters += '&_=';

        try {
            this.url = url;
            if (this.options.method == 'get' && parameters.length > 0) {
               this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
            }

            OpenLayers.Ajax.Responders.dispatch('onCreate',
                                                this,
                                                this.transport);

            this.transport.open(this.options.method,
                                this.url,
                                this.options.asynchronous);

            if (this.options.asynchronous) {
                this.transport.onreadystatechange =
                    this.onStateChange.bind(this);

                setTimeout((function() {
                    this.respondToReadyState(1)
                }).bind(this), 10);
            }

            this.setRequestHeaders();

            var body = this.options.postBody ? this.options.postBody
                                             : parameters;
            this.transport.send(this.options.method == 'post' ? body : null);

            // Force Firefox to handle ready state 4 for synchronous requests
            if (!this.options.asynchronous &&
                this.transport.overrideMimeType) {

                this.onStateChange();
            }

        } catch (e) {
            this.dispatchException(e);
        }
    },

    /**
     * Method: setRequestHeaders
     */
    setRequestHeaders: function() {
        var requestHeaders = [
            'X-Requested-With',
            'XMLHttpRequest',
            'X-Prototype-Version',
            'OpenLayers'
        ];

        if (this.options.method == 'post' && !this.options.postBody) {
            requestHeaders.push('Content-type',
                                'application/x-www-form-urlencoded');

            // Force "Connection: close" for Mozilla browsers to work around
            // a bug where XMLHttpReqeuest sends an incorrect Content-length
            // header. See Mozilla Bugzilla #246651.
            if (this.transport.overrideMimeType) {
                requestHeaders.push('Connection', 'close');
            }
        }

        if (this.options.requestHeaders) {
            requestHeaders.push.apply(requestHeaders,
                                      this.options.requestHeaders);
        }

        for (var i = 0; i < requestHeaders.length; i += 2) {
            this.transport.setRequestHeader(requestHeaders[i],
                                            requestHeaders[i+1]);
        }
    },

    /**
     * Method: onStateChange
     */
    onStateChange: function() {
        var readyState = this.transport.readyState;
        if (readyState != 1) {
          this.respondToReadyState(this.transport.readyState);
        }
    },

    /**
     * Method: header
     *
     * Return:
     * {?}
     */
    header: function(name) {
        try {
            return this.transport.getResponseHeader(name);
        } catch (e) {}
    },

    /**
     * Method: evalJSON
     *
     * Return:
     * {?}
     */
    evalJSON: function() {
        try {
            return eval(this.header('X-JSON'));
        } catch (e) {}
    },

    /**
     * Method: evalResponse
     *
     * Return:
     * {?}
     */
    evalResponse: function() {
        try {
            return eval(this.transport.responseText);
        } catch (e) {
            this.dispatchException(e);
        }
    },

    /**
     * Method: respondToReadyState
     *
     * Parameters:
     * readyState - {?}
     */
    respondToReadyState: function(readyState) {
        var event = OpenLayers.Ajax.Request.Events[readyState];
        var transport = this.transport, json = this.evalJSON();

        if (event == 'Complete') {
            try {
                var responseSuccess = this.responseIsSuccess() ? 'Success'
                                                                : 'Failure';

                (this.options['on' + this.transport.status] ||
                 this.options['on' + responseSuccess] ||
                 OpenLayers.Ajax.emptyFunction)(transport, json);
            } catch (e) {
                this.dispatchException(e);
            }

            var contentType = this.header('Content-type') || '';
            if (contentType.match(/^text\/javascript/i)) {
                this.evalResponse();
            }
        }

        try {
            (this.options['on' + event] ||
             OpenLayers.Ajax.emptyFunction)(transport, json);
             OpenLayers.Ajax.Responders.dispatch('on' + event,
                                                 this,
                                                 transport,
                                                 json);
        } catch (e) {
            this.dispatchException(e);
        }

        // Avoid memory leak in MSIE: clean up the oncomplete event handler
        if (event == 'Complete') {
            this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
        }
    },

    /**
     * Method: dispatchException
     *
     * Parameters:
     * exception - {?}
     */
    dispatchException: function(exception) {
        if (this.options.onException) {
            this.options.onException(this, exception);
        } else {
            // if we get here, Responders.dispatch('onException') will never
            // be called. too bad. we should probably take out the Responders
            // stuff anyway.
            throw exception;
        }
        OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
    }

});

/**
 * Property: Events
 * {Array(String)}
 */
OpenLayers.Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

/**
 * Function: getElementsByTagNameNS
 *
 * Parameters:
 * parentnode - {?}
 * nsuri - {?}
 * nsprefix - {?}
 * tagname - {?}
 *
 * Return:
 * {?}
 */
OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri,
                                                   nsprefix, tagname) {
    var elem = null;
    if (parentnode.getElementsByTagNameNS) {
        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
    } else {
        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
    }
    return elem;
};

/**
 * Function: serializeXMLToString
 * Wrapper function around XMLSerializer, which doesn't exist/work in
 *     IE/Safari. We need to come up with a way to serialize in those browser:
 *     for now, these browsers will just fail. #535, #536
 *
 * Parameters:
 * xmldom {XMLNode} xml dom to serialize
 *
 * Return:
 * {?}
 */
OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
    var serializer = new XMLSerializer();
    data = serializer.serializeToString(xmldom);
    return data;
}
<commit_msg>#885 - keep responder variable in closure - thanks for quick review crschmidt<commit_after>/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
 * for the full text of the license. */

OpenLayers.ProxyHost = "";
//OpenLayers.ProxyHost = "examples/proxy.cgi?url=";

/**
 * Ajax reader for OpenLayers
 *
 *  @uri url to do remote XML http get
 *  @param {String} 'get' format params (x=y&a=b...)
 *  @who object to handle callbacks for this request
 *  @complete  the function to be called on success
 *  @failure  the function to be called on failure
 *
 *   example usage from a caller:
 *
 *     caps: function(request) {
 *      -blah-
 *     },
 *
 *     OpenLayers.loadURL(url,params,this,caps);
 *
 * Notice the above example does not provide an error handler; a default empty
 * handler is provided which merely logs the error if a failure handler is not
 * supplied
 *
 */

/**
* @param {} request
*/
OpenLayers.nullHandler = function(request) {
    alert("Unhandled request return " + request.statusText);
};

/**
 * Function: loadURL
 * Background load a document.
 *
 * Parameters:
 * uri - {String} URI of source doc
 * params - {String} Params on get (doesnt seem to work)
 * caller - {Object} object which gets callbacks
 * onComplete - {Function} callback for success
 * onFailure - {Function} callback for failure
 *
 * Both callbacks optional (though silly)
 */
OpenLayers.loadURL = function(uri, params, caller,
                                  onComplete, onFailure) {

    if (OpenLayers.ProxyHost && uri.startsWith("http")) {
        uri = OpenLayers.ProxyHost + escape(uri);
    }

    var success = (onComplete) ? onComplete.bind(caller)
                                : OpenLayers.nullHandler;

    var failure = (onFailure) ? onFailure.bind(caller)
                           : OpenLayers.nullHandler;

    // from prototype.js
    new OpenLayers.Ajax.Request(uri,
                     {   method: 'get',
                         parameters: params,
                         onComplete: success,
                         onFailure: failure
                      }
                     );
};

/**
 * Function: parseXMLString
 * Parse XML into a doc structure
 *
 * Parameters:
 * text - {String}
 *
 * Return:
 * {?} Parsed AJAX Responsev
 */
OpenLayers.parseXMLString = function(text) {

    //MS sucks, if the server is bad it dies
    var index = text.indexOf('<');
    if (index > 0) {
        text = text.substring(index);
    }

    var ajaxResponse = OpenLayers.Util.Try(
        function() {
            var xmldom = new ActiveXObject('Microsoft.XMLDOM');
            xmldom.loadXML(text);
            return xmldom;
        },
        function() {
            return new DOMParser().parseFromString(text, 'text/xml');
        },
        function() {
            var req = new XMLHttpRequest();
            req.open("GET", "data:" + "text/xml" +
                     ";charset=utf-8," + encodeURIComponent(text), false);
            if (req.overrideMimeType) {
                req.overrideMimeType("text/xml");
            }
            req.send(null);
            return req.responseXML;
        }
    );

    return ajaxResponse;
};

/**
 * Namespace: OpenLayers.Ajax
 */
OpenLayers.Ajax = {

    /**
     * Method: emptyFunction
     */
    emptyFunction: function () {},

    /**
     * Method: getTransport
     *
     * Return:
     * {Object} Transport mechanism for whichever browser we're in, or false if
     *          none available.
     */
    getTransport: function() {
        return OpenLayers.Util.Try(
            function() {return new ActiveXObject('Msxml2.XMLHTTP')},
            function() {return new ActiveXObject('Microsoft.XMLHTTP')},
            function() {return new XMLHttpRequest()}
        ) || false;
    },

    /**
     * Property: activeRequestCount
     * {Integer}
     */
    activeRequestCount: 0
};

/**
 * Namespace: OpenLayers.Ajax.Responders
 * {Object}
 */
OpenLayers.Ajax.Responders = {

    /**
     * Property: responders
     * {Array}
     */
    responders: [],

    /**
     * Method: register
     *
     * Parameters:
     * responderToAdd - {?}
     */
    register: function(responderToAdd) {
      for (var i = 0; i < this.responders.length; i++)
          if (responderToAdd == this.responders[i])
              return;
      this.responders.push(responderToAdd);
    },

    /**
     * Method: dispatch
     *
     * Parameters:
     * callback - {?}
     * request - {?}
     * transport - {?}
     * json - {?}
     */
    dispatch: function(callback, request, transport, json) {
        var responder;
        for (var i = 0; i < this.responders.length; i++) {
            responder = this.responders[i];

            if (responder[callback] &&
                typeof responder[callback] == 'function') {
                try {
                    responder[callback].apply(responder,
                                              [request, transport, json]);
                } catch (e) {}
            }
        }
    }
};

OpenLayers.Ajax.Responders.register({
    /**
     * Function: onCreate
     */
    onCreate: function() {
        OpenLayers.Ajax.activeRequestCount++;
    },

    /**
     * Function: onComplete
     */
     onComplete: function() {
         OpenLayers.Ajax.activeRequestCount--;
     }
});

/**
 * Namespace: OpenLayers.Ajax.Base
 * {Object}
 */
OpenLayers.Ajax.Base = function() {};
OpenLayers.Ajax.Base.prototype = {

    /**
     * Function: setOptions
     *
     * Parameters:
     * options - {Object}
     */
    setOptions: function(options) {
        this.options = {
            'method': 'post',
            'asynchronous': true,
            'parameters': ''
        };
        OpenLayers.Util.extend(this.options, options || {});
    },

    /**
     * Function: responseIsSuccess
     *
     * Return:
     * {Boolean}
     */
    responseIsSuccess: function() {
        return this.transport.status == undefined ||
               this.transport.status == 0 ||
               (this.transport.status >= 200 && this.transport.status < 300);
    },

    /**
     * Function: responseIsFailure
     *
     * Return:
     * {Boolean}
     */
    responseIsFailure: function() {
        return !this.responseIsSuccess();
    }
};

/**
 * Class: OpenLayers.Ajax.Request
 *
 * Inherit:
 *  - <OpenLayers.Ajax.Base>
 */
OpenLayers.Ajax.Request = OpenLayers.Class(OpenLayers.Ajax.Base, {

      /**
       * Constructor: OpenLayers.Ajax.Request
       *
       * Parameters:
       * url - {String}
       * options - {Object}
       */
    initialize: function(url, options) {
        this.transport = OpenLayers.Ajax.getTransport();
        this.setOptions(options);
        this.request(url);
    },

    /**
     * Method: request
     *
     * Parameters:
     * url - {String}
     */
    request: function(url) {
        var parameters = this.options.parameters || '';
        if (parameters.length > 0) parameters += '&_=';

        try {
            this.url = url;
            if (this.options.method == 'get' && parameters.length > 0) {
               this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
            }

            OpenLayers.Ajax.Responders.dispatch('onCreate',
                                                this,
                                                this.transport);

            this.transport.open(this.options.method,
                                this.url,
                                this.options.asynchronous);

            if (this.options.asynchronous) {
                this.transport.onreadystatechange =
                    this.onStateChange.bind(this);

                setTimeout((function() {
                    this.respondToReadyState(1)
                }).bind(this), 10);
            }

            this.setRequestHeaders();

            var body = this.options.postBody ? this.options.postBody
                                             : parameters;
            this.transport.send(this.options.method == 'post' ? body : null);

            // Force Firefox to handle ready state 4 for synchronous requests
            if (!this.options.asynchronous &&
                this.transport.overrideMimeType) {

                this.onStateChange();
            }

        } catch (e) {
            this.dispatchException(e);
        }
    },

    /**
     * Method: setRequestHeaders
     */
    setRequestHeaders: function() {
        var requestHeaders = [
            'X-Requested-With',
            'XMLHttpRequest',
            'X-Prototype-Version',
            'OpenLayers'
        ];

        if (this.options.method == 'post' && !this.options.postBody) {
            requestHeaders.push('Content-type',
                                'application/x-www-form-urlencoded');

            // Force "Connection: close" for Mozilla browsers to work around
            // a bug where XMLHttpReqeuest sends an incorrect Content-length
            // header. See Mozilla Bugzilla #246651.
            if (this.transport.overrideMimeType) {
                requestHeaders.push('Connection', 'close');
            }
        }

        if (this.options.requestHeaders) {
            requestHeaders.push.apply(requestHeaders,
                                      this.options.requestHeaders);
        }

        for (var i = 0; i < requestHeaders.length; i += 2) {
            this.transport.setRequestHeader(requestHeaders[i],
                                            requestHeaders[i+1]);
        }
    },

    /**
     * Method: onStateChange
     */
    onStateChange: function() {
        var readyState = this.transport.readyState;
        if (readyState != 1) {
          this.respondToReadyState(this.transport.readyState);
        }
    },

    /**
     * Method: header
     *
     * Return:
     * {?}
     */
    header: function(name) {
        try {
            return this.transport.getResponseHeader(name);
        } catch (e) {}
    },

    /**
     * Method: evalJSON
     *
     * Return:
     * {?}
     */
    evalJSON: function() {
        try {
            return eval(this.header('X-JSON'));
        } catch (e) {}
    },

    /**
     * Method: evalResponse
     *
     * Return:
     * {?}
     */
    evalResponse: function() {
        try {
            return eval(this.transport.responseText);
        } catch (e) {
            this.dispatchException(e);
        }
    },

    /**
     * Method: respondToReadyState
     *
     * Parameters:
     * readyState - {?}
     */
    respondToReadyState: function(readyState) {
        var event = OpenLayers.Ajax.Request.Events[readyState];
        var transport = this.transport, json = this.evalJSON();

        if (event == 'Complete') {
            try {
                var responseSuccess = this.responseIsSuccess() ? 'Success'
                                                                : 'Failure';

                (this.options['on' + this.transport.status] ||
                 this.options['on' + responseSuccess] ||
                 OpenLayers.Ajax.emptyFunction)(transport, json);
            } catch (e) {
                this.dispatchException(e);
            }

            var contentType = this.header('Content-type') || '';
            if (contentType.match(/^text\/javascript/i)) {
                this.evalResponse();
            }
        }

        try {
            (this.options['on' + event] ||
             OpenLayers.Ajax.emptyFunction)(transport, json);
             OpenLayers.Ajax.Responders.dispatch('on' + event,
                                                 this,
                                                 transport,
                                                 json);
        } catch (e) {
            this.dispatchException(e);
        }

        // Avoid memory leak in MSIE: clean up the oncomplete event handler
        if (event == 'Complete') {
            this.transport.onreadystatechange = OpenLayers.Ajax.emptyFunction;
        }
    },

    /**
     * Method: dispatchException
     *
     * Parameters:
     * exception - {?}
     */
    dispatchException: function(exception) {
        if (this.options.onException) {
            this.options.onException(this, exception);
        } else {
            // if we get here, Responders.dispatch('onException') will never
            // be called. too bad. we should probably take out the Responders
            // stuff anyway.
            throw exception;
        }
        OpenLayers.Ajax.Responders.dispatch('onException', this, exception);
    }

});

/**
 * Property: Events
 * {Array(String)}
 */
OpenLayers.Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

/**
 * Function: getElementsByTagNameNS
 *
 * Parameters:
 * parentnode - {?}
 * nsuri - {?}
 * nsprefix - {?}
 * tagname - {?}
 *
 * Return:
 * {?}
 */
OpenLayers.Ajax.getElementsByTagNameNS  = function(parentnode, nsuri,
                                                   nsprefix, tagname) {
    var elem = null;
    if (parentnode.getElementsByTagNameNS) {
        elem = parentnode.getElementsByTagNameNS(nsuri, tagname);
    } else {
        elem = parentnode.getElementsByTagName(nsprefix + ':' + tagname);
    }
    return elem;
};

/**
 * Function: serializeXMLToString
 * Wrapper function around XMLSerializer, which doesn't exist/work in
 *     IE/Safari. We need to come up with a way to serialize in those browser:
 *     for now, these browsers will just fail. #535, #536
 *
 * Parameters:
 * xmldom {XMLNode} xml dom to serialize
 *
 * Return:
 * {?}
 */
OpenLayers.Ajax.serializeXMLToString = function(xmldom) {
    var serializer = new XMLSerializer();
    data = serializer.serializeToString(xmldom);
    return data;
}
<|endoftext|>


<commit_before>/*!
 * ws: a node.js websocket client
 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

'use strict';

const EventEmitter = require('events');
const crypto = require('crypto');
const Ultron = require('ultron');
const http = require('http');
const util = require('util');
const url = require('url');

const PerMessageDeflate = require('./PerMessageDeflate');
const Extensions = require('./Extensions');
const WebSocket = require('./WebSocket');

/**
 * Create a `WebSocketServer` instance.
 *
 * @param {Object} options Configuration options
 * @param {String} options.host The hostname where to bind the server
 * @param {Number} options.port The port where to bind the server
 * @param {http.Server} options.server A pre-created HTTP/S server to use
 * @param {Function} options.verifyClient An hook to reject connections
 * @param {Function} options.handleProtocols An hook to handle protocols
 * @param {String} options.path Accept only connections matching this path
 * @param {Boolean} options.noServer Enable no server mode
 * @param {Boolean} options.clientTracking Specifies whether or not to track clients
 * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
 * @param {Number} options.maxPayload The maximum allowed message size
 * @param {Function} callback A listener for the `listening` event
 * @constructor
 * @public
 */
function WebSocketServer (options, callback) {
  if (this instanceof WebSocketServer === false) {
    return new WebSocketServer(options, callback);
  }

  EventEmitter.call(this);

  options = Object.assign({
    host: '0.0.0.0',
    port: null,
    server: null,
    verifyClient: null,
    handleProtocols: null,
    path: null,
    noServer: false,
    clientTracking: true,
    perMessageDeflate: true,
    maxPayload: 100 * 1024 * 1024,
    backlog: null // use default (511 as implemented in net.js)
  }, options);

  if (options.port == null && !options.server && !options.noServer) {
    throw new TypeError('missing or invalid options');
  }

  if (options.port != null) {
    this._server = http.createServer((req, res) => {
      const body = http.STATUS_CODES[426];

      res.writeHead(426, {
        'Content-Length': body.length,
        'Content-Type': 'text/plain'
      });
      res.end(body);
    });
    this._server.allowHalfOpen = false;
    this._server.listen(options.port, options.host, options.backlog, callback);
  } else if (options.server) {
    this._server = options.server;
  }

  if (this._server) {
    this._ultron = new Ultron(this._server);
    this._ultron.on('listening', () => this.emit('listening'));
    this._ultron.on('error', (err) => this.emit('error', err));
    this._ultron.on('upgrade', (req, socket, head) => {
      this.handleUpgrade(req, socket, head, (client) => {
        this.emit(`connection${req.url}`, client);
        this.emit('connection', client);
      });
    });
  }

  if (options.clientTracking) this.clients = new Set();
  this.options = options;
  this.path = options.path;
}

util.inherits(WebSocketServer, EventEmitter);

/**
 * Close the server.
 *
 * @param {Function} cb Callback
 * @public
 */
WebSocketServer.prototype.close = function (cb) {
  // terminate all associated clients
  var error = null;

  if (this.clients) {
    for (const client of this.clients) {
      try {
        client.terminate();
      } catch (e) {
        error = e;
      }
    }
  }

  if (this._server) {
    // close the http server if it was internally created
    if (this.options.port != null) this._server.close();
    this._ultron.destroy();
    this._ultron = this._server = null;
  }

  if (cb) cb(error);
  else if (error) throw error;
};

/**
 * See if a given request should be handled by this server instance.
 *
 * @param {http.IncomingMessage} req Request object to inspect
 * @return {Boolean} `true` if the request is valid, else `false`
 * @public
 */
WebSocketServer.prototype.shouldHandle = function (req) {
  if (this.options.path && url.parse(req.url).pathname !== this.options.path) {
    return false;
  }

  return true;
};

/**
 * Handle a HTTP Upgrade request.
 *
 * @param {http.IncomingMessage} req The request object
 * @param {net.Socket} socket The network socket between the server and client
 * @param {Buffer} head The first packet of the upgraded stream
 * @param {Function} cb Callback
 * @public
 */
WebSocketServer.prototype.handleUpgrade = function (req, socket, head, cb) {
  if (
    !this.shouldHandle(req) ||
    !req.headers.upgrade ||
    req.headers.upgrade.toLowerCase() !== 'websocket'
  ) {
    return abortConnection(socket, 400);
  }

  handleHybiUpgrade.apply(this, arguments);
};

module.exports = WebSocketServer;

/**
 * Entirely private apis,
 * which may or may not be bound to a specific WebSocket instance.
 */

function handleHybiUpgrade (req, socket, upgradeHead, cb) {
  // handle premature socket errors
  var errorHandler = () => {
    try { socket.destroy(); } catch (e) {}
  };
  socket.on('error', errorHandler);

  // verify key presence
  if (!req.headers['sec-websocket-key']) {
    return abortConnection(socket, 400);
  }

  // verify version
  var version = +req.headers['sec-websocket-version'];
  if (version !== 8 && version !== 13) {
    return abortConnection(socket, 400);
  }

  // verify protocol
  var protocols = req.headers['sec-websocket-protocol'];

  // verify client
  var origin = version !== 13
    ? req.headers['sec-websocket-origin']
    : req.headers['origin'];

  // handle extensions offer
  var extensionsOffer = Extensions.parse(req.headers['sec-websocket-extensions']);

  // handler to call when the connection sequence completes
  var completeHybiUpgrade2 = (protocol) => {
    // calc key
    var key = crypto.createHash('sha1')
      .update(`${req.headers['sec-websocket-key']}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`, 'binary')
      .digest('base64');

    var headers = [
      'HTTP/1.1 101 Switching Protocols',
      'Upgrade: websocket',
      'Connection: Upgrade',
      `Sec-WebSocket-Accept: ${key}`
    ];

    if (protocol) {
      headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
    }

    var extensions = {};
    try {
      extensions = acceptExtensions.call(this, extensionsOffer);
    } catch (err) {
      return abortConnection(socket, 400);
    }

    if (Object.keys(extensions).length) {
      var serverExtensions = {};
      Object.keys(extensions).forEach((token) => {
        serverExtensions[token] = [extensions[token].params];
      });
      headers.push(`Sec-WebSocket-Extensions: ${Extensions.format(serverExtensions)}`);
    }

    // allows external modification/inspection of handshake headers
    this.emit('headers', headers);

    socket.setTimeout(0);
    socket.setNoDelay(true);

    try {
      socket.write(headers.concat('', '').join('\r\n'));
    } catch (e) {
      // if the upgrade write fails, shut the connection down hard
      try { socket.destroy(); } catch (e) {}
      return;
    }

    var client = new WebSocket([req, socket, upgradeHead], {
      protocolVersion: version,
      protocol: protocol,
      extensions: extensions,
      maxPayload: this.options.maxPayload
    });

    if (this.clients) {
      this.clients.add(client);
      client.on('close', () => this.clients.delete(client));
    }

    // signal upgrade complete
    socket.removeListener('error', errorHandler);
    cb(client);
  };

  // optionally call external protocol selection handler before
  // calling completeHybiUpgrade2
  var completeHybiUpgrade1 = () => {
    // choose from the sub-protocols
    if (this.options.handleProtocols) {
      var protList = (protocols || '').split(/, */);
      var callbackCalled = false;
      this.options.handleProtocols(protList, (result, protocol) => {
        callbackCalled = true;
        if (!result) return abortConnection(socket, 401);

        completeHybiUpgrade2(protocol);
      });
      if (!callbackCalled) {
        // the handleProtocols handler never called our callback
        abortConnection(socket, 501, 'Could not process protocols');
      }
    } else {
      completeHybiUpgrade2(protocols && protocols.split(/, */)[0]);
    }
  };

  // optionally call external client verification handler
  if (this.options.verifyClient) {
    var info = {
      secure: req.connection.authorized !== undefined || req.connection.encrypted !== undefined,
      origin: origin,
      req: req
    };
    if (this.options.verifyClient.length === 2) {
      this.options.verifyClient(info, (result, code, message) => {
        if (!result) return abortConnection(socket, code || 401, message);

        completeHybiUpgrade1();
      });
      return;
    } else if (!this.options.verifyClient(info)) {
      return abortConnection(socket, 401);
    }
  }

  completeHybiUpgrade1();
}

function acceptExtensions (offer) {
  var extensions = {};
  var options = this.options.perMessageDeflate;
  var maxPayload = this.options.maxPayload;
  if (options && offer[PerMessageDeflate.extensionName]) {
    var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true, maxPayload);
    perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);
    extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
  }
  return extensions;
}

/**
 * Close the connection when preconditions are not fulfilled.
 *
 * @param {net.Socket} socket The socket of the upgrade request
 * @param {Number} code The HTTP response status code
 * @param {String} [message] The HTTP response body
 * @api private
 */
function abortConnection (socket, code, message) {
  if (socket.writable) {
    message = message || http.STATUS_CODES[code];
    socket.write(
      `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
      'Connection: close\r\n' +
      'Content-type: text/html\r\n' +
      `Content-Length: ${Buffer.byteLength(message)}\r\n` +
      '\r\n' +
      message
    );
  }
  socket.destroy();
}
<commit_msg>[fix] Invoke the close callback when the close event is emitted<commit_after>/*!
 * ws: a node.js websocket client
 * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
 * MIT Licensed
 */

'use strict';

const EventEmitter = require('events');
const crypto = require('crypto');
const Ultron = require('ultron');
const http = require('http');
const util = require('util');
const url = require('url');

const PerMessageDeflate = require('./PerMessageDeflate');
const Extensions = require('./Extensions');
const WebSocket = require('./WebSocket');

/**
 * Create a `WebSocketServer` instance.
 *
 * @param {Object} options Configuration options
 * @param {String} options.host The hostname where to bind the server
 * @param {Number} options.port The port where to bind the server
 * @param {http.Server} options.server A pre-created HTTP/S server to use
 * @param {Function} options.verifyClient An hook to reject connections
 * @param {Function} options.handleProtocols An hook to handle protocols
 * @param {String} options.path Accept only connections matching this path
 * @param {Boolean} options.noServer Enable no server mode
 * @param {Boolean} options.clientTracking Specifies whether or not to track clients
 * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
 * @param {Number} options.maxPayload The maximum allowed message size
 * @param {Function} callback A listener for the `listening` event
 * @constructor
 * @public
 */
function WebSocketServer (options, callback) {
  if (this instanceof WebSocketServer === false) {
    return new WebSocketServer(options, callback);
  }

  EventEmitter.call(this);

  options = Object.assign({
    host: '0.0.0.0',
    port: null,
    server: null,
    verifyClient: null,
    handleProtocols: null,
    path: null,
    noServer: false,
    clientTracking: true,
    perMessageDeflate: true,
    maxPayload: 100 * 1024 * 1024,
    backlog: null // use default (511 as implemented in net.js)
  }, options);

  if (options.port == null && !options.server && !options.noServer) {
    throw new TypeError('missing or invalid options');
  }

  if (options.port != null) {
    this._server = http.createServer((req, res) => {
      const body = http.STATUS_CODES[426];

      res.writeHead(426, {
        'Content-Length': body.length,
        'Content-Type': 'text/plain'
      });
      res.end(body);
    });
    this._server.allowHalfOpen = false;
    this._server.listen(options.port, options.host, options.backlog, callback);
  } else if (options.server) {
    this._server = options.server;
  }

  if (this._server) {
    this._ultron = new Ultron(this._server);
    this._ultron.on('listening', () => this.emit('listening'));
    this._ultron.on('error', (err) => this.emit('error', err));
    this._ultron.on('upgrade', (req, socket, head) => {
      this.handleUpgrade(req, socket, head, (client) => {
        this.emit(`connection${req.url}`, client);
        this.emit('connection', client);
      });
    });
  }

  if (options.clientTracking) this.clients = new Set();
  this.options = options;
  this.path = options.path;
}

util.inherits(WebSocketServer, EventEmitter);

/**
 * Close the server.
 *
 * @param {Function} cb Callback
 * @public
 */
WebSocketServer.prototype.close = function (cb) {
  // terminate all associated clients
  if (this.clients) {
    for (const client of this.clients) client.terminate();
  }

  if (this._server) {
    // close the http server if it was internally created
    if (this.options.port != null) this._server.close(cb);
    this._ultron.destroy();
    this._ultron = this._server = null;
  } else if (cb) {
    cb();
  }
};

/**
 * See if a given request should be handled by this server instance.
 *
 * @param {http.IncomingMessage} req Request object to inspect
 * @return {Boolean} `true` if the request is valid, else `false`
 * @public
 */
WebSocketServer.prototype.shouldHandle = function (req) {
  if (this.options.path && url.parse(req.url).pathname !== this.options.path) {
    return false;
  }

  return true;
};

/**
 * Handle a HTTP Upgrade request.
 *
 * @param {http.IncomingMessage} req The request object
 * @param {net.Socket} socket The network socket between the server and client
 * @param {Buffer} head The first packet of the upgraded stream
 * @param {Function} cb Callback
 * @public
 */
WebSocketServer.prototype.handleUpgrade = function (req, socket, head, cb) {
  if (
    !this.shouldHandle(req) ||
    !req.headers.upgrade ||
    req.headers.upgrade.toLowerCase() !== 'websocket'
  ) {
    return abortConnection(socket, 400);
  }

  handleHybiUpgrade.apply(this, arguments);
};

module.exports = WebSocketServer;

/**
 * Entirely private apis,
 * which may or may not be bound to a specific WebSocket instance.
 */

function handleHybiUpgrade (req, socket, upgradeHead, cb) {
  // handle premature socket errors
  var errorHandler = () => {
    try { socket.destroy(); } catch (e) {}
  };
  socket.on('error', errorHandler);

  // verify key presence
  if (!req.headers['sec-websocket-key']) {
    return abortConnection(socket, 400);
  }

  // verify version
  var version = +req.headers['sec-websocket-version'];
  if (version !== 8 && version !== 13) {
    return abortConnection(socket, 400);
  }

  // verify protocol
  var protocols = req.headers['sec-websocket-protocol'];

  // verify client
  var origin = version !== 13
    ? req.headers['sec-websocket-origin']
    : req.headers['origin'];

  // handle extensions offer
  var extensionsOffer = Extensions.parse(req.headers['sec-websocket-extensions']);

  // handler to call when the connection sequence completes
  var completeHybiUpgrade2 = (protocol) => {
    // calc key
    var key = crypto.createHash('sha1')
      .update(`${req.headers['sec-websocket-key']}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`, 'binary')
      .digest('base64');

    var headers = [
      'HTTP/1.1 101 Switching Protocols',
      'Upgrade: websocket',
      'Connection: Upgrade',
      `Sec-WebSocket-Accept: ${key}`
    ];

    if (protocol) {
      headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
    }

    var extensions = {};
    try {
      extensions = acceptExtensions.call(this, extensionsOffer);
    } catch (err) {
      return abortConnection(socket, 400);
    }

    if (Object.keys(extensions).length) {
      var serverExtensions = {};
      Object.keys(extensions).forEach((token) => {
        serverExtensions[token] = [extensions[token].params];
      });
      headers.push(`Sec-WebSocket-Extensions: ${Extensions.format(serverExtensions)}`);
    }

    // allows external modification/inspection of handshake headers
    this.emit('headers', headers);

    socket.setTimeout(0);
    socket.setNoDelay(true);

    try {
      socket.write(headers.concat('', '').join('\r\n'));
    } catch (e) {
      // if the upgrade write fails, shut the connection down hard
      try { socket.destroy(); } catch (e) {}
      return;
    }

    var client = new WebSocket([req, socket, upgradeHead], {
      protocolVersion: version,
      protocol: protocol,
      extensions: extensions,
      maxPayload: this.options.maxPayload
    });

    if (this.clients) {
      this.clients.add(client);
      client.on('close', () => this.clients.delete(client));
    }

    // signal upgrade complete
    socket.removeListener('error', errorHandler);
    cb(client);
  };

  // optionally call external protocol selection handler before
  // calling completeHybiUpgrade2
  var completeHybiUpgrade1 = () => {
    // choose from the sub-protocols
    if (this.options.handleProtocols) {
      var protList = (protocols || '').split(/, */);
      var callbackCalled = false;
      this.options.handleProtocols(protList, (result, protocol) => {
        callbackCalled = true;
        if (!result) return abortConnection(socket, 401);

        completeHybiUpgrade2(protocol);
      });
      if (!callbackCalled) {
        // the handleProtocols handler never called our callback
        abortConnection(socket, 501, 'Could not process protocols');
      }
    } else {
      completeHybiUpgrade2(protocols && protocols.split(/, */)[0]);
    }
  };

  // optionally call external client verification handler
  if (this.options.verifyClient) {
    var info = {
      secure: req.connection.authorized !== undefined || req.connection.encrypted !== undefined,
      origin: origin,
      req: req
    };
    if (this.options.verifyClient.length === 2) {
      this.options.verifyClient(info, (result, code, message) => {
        if (!result) return abortConnection(socket, code || 401, message);

        completeHybiUpgrade1();
      });
      return;
    } else if (!this.options.verifyClient(info)) {
      return abortConnection(socket, 401);
    }
  }

  completeHybiUpgrade1();
}

function acceptExtensions (offer) {
  var extensions = {};
  var options = this.options.perMessageDeflate;
  var maxPayload = this.options.maxPayload;
  if (options && offer[PerMessageDeflate.extensionName]) {
    var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true, maxPayload);
    perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);
    extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
  }
  return extensions;
}

/**
 * Close the connection when preconditions are not fulfilled.
 *
 * @param {net.Socket} socket The socket of the upgrade request
 * @param {Number} code The HTTP response status code
 * @param {String} [message] The HTTP response body
 * @api private
 */
function abortConnection (socket, code, message) {
  if (socket.writable) {
    message = message || http.STATUS_CODES[code];
    socket.write(
      `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
      'Connection: close\r\n' +
      'Content-type: text/html\r\n' +
      `Content-Length: ${Buffer.byteLength(message)}\r\n` +
      '\r\n' +
      message
    );
  }
  socket.destroy();
}
<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const execSync = require('child_process').execSync;
const os = require('os');

function convertPowershellDate(date) {
  const parts = date.toString().split(' ');
  return `${parts[0]} ${parts[1]} ${parts[2]} ${parts[3]} ${parts[4]}`;
}

function processLogEvent(event) {
  let createdAtMilis = event.TimeCreated.replace(/\//g, '').replace('Date(', '').replace(')', '');
  createdAtMilis = parseInt(createdAtMilis, 10);
  return {
    id: event.Id,
    providerName: event.ProviderName,
    providerId: event.ProviderId,
    logName: event.LogName,
    processId: event.ProcessId,
    threadId: event.ThreadId,
    machineName: event.MachineName,
    timeCreated: new Date(createdAtMilis),
    levelDisplayName: event.LevelDisplayName,
    message: event.Message
  };
}

function parseLogData(data) {
  let events;
  try {
    events = JSON.parse(data);
  } catch (e) {
    throw e;
  }

  return Array.isArray(events) ?
    events.map(event => processLogEvent(event)) :
    [processLogEvent(events)];
}

class WinEventEmitter extends EventEmitter {
  constructor (options) {
    super();

    if (!/win/gi.test(os.platform())) {
      throw new Error('Only Windows is supported');
    }

    const defaultOptions = {
      providers: ['*'],
      maxEvents: 100,
      frequency: 10000
    };
    this.options = Object.assign({}, defaultOptions, options);
    this.options.startTime || (this.options.startTime = new Date());
    this.options.endTime  || (this.options.endTime = new Date(Date.now() + this.options.frequency));
    this._id = -1;
  }

  start () {
    this._id = setTimeout(() => {
      const providers = null
      const getAllLogs = (this.options.providers && this.options.providers.length > 0 && this.options.providers[0]=='*')
      if (!getAllLogs) {
        providers = `'${this.options.providers.join('\', \'')}'`;
      }
      let startTime = convertPowershellDate(this.options.startTime), endTime = convertPowershellDate(this.options.endTime);

      let creds = '';
      let credsOpt = '';
      if (this.options.userName && this.options.password) {
        creds =  `$User = '${this.options.userName}'; $Pass = ConvertTo-SecureString -String '${this.options.password}' -AsPlainText -Force; $Credential = New-Object –TypeName 'System.Management.Automation.PSCredential' –ArgumentList $User, $Pass; `;
        credsOpt = ' -Credentials $Credential';
      }

      let computerOpt = '';
      if (this.options.computerName) {
        computerOpt = ` -ComputerName ${this.options.computerName}`;
      }

      let powershellCmd = `powershell "${creds}Get-WinEvent -FilterHashTable @{ProviderName=${providers}; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}${credsOpt}${computerOpt} | ConvertTo-Json`;
      if (getAllLogs) {
        powerSHellCmd = `powershell "${creds}Get-WinEvent ---ListLog  *; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}${credsOpt}${computerOpt} | ConvertTo-Json`;
      }
      this.emit('powerShellCmd', powerSHellCmd)
      let data;
      try {
        data = execSync(powershellCmd, {stdio: [1]}).toString();
        this.emit('raw.data', data)
      } catch (e) {
        // Ignore missing events
        if (!e.message.indexOf('NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand')) {
          this.emit('error', e);
        }
      }

      if (this._stop) { return; }
      var parsedData = null
      if (data) {
        try {
          parsedData = parseLogData(data)
          this.emit('data', parsedData)
        } catch (err) {
          this.emit('error', err)
        }
      }

      // Ensure no time gaps
      var now = Date.now()
      this.options.startTime = new Date(this.options.endTime || now)
      this.options.endTime = new Date(now + this.options.frequency)

      this.start();
    }, this.options.frequency);
  }

  stop () {
    clearTimeout(this._id);
    this._stop = true;
    this.emit('end');
  }
}

module.exports = WinEventEmitter;
<commit_msg>fix typo<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const execSync = require('child_process').execSync;
const os = require('os');

function convertPowershellDate(date) {
  const parts = date.toString().split(' ');
  return `${parts[0]} ${parts[1]} ${parts[2]} ${parts[3]} ${parts[4]}`;
}

function processLogEvent(event) {
  let createdAtMilis = event.TimeCreated.replace(/\//g, '').replace('Date(', '').replace(')', '');
  createdAtMilis = parseInt(createdAtMilis, 10);
  return {
    id: event.Id,
    providerName: event.ProviderName,
    providerId: event.ProviderId,
    logName: event.LogName,
    processId: event.ProcessId,
    threadId: event.ThreadId,
    machineName: event.MachineName,
    timeCreated: new Date(createdAtMilis),
    levelDisplayName: event.LevelDisplayName,
    message: event.Message
  };
}

function parseLogData(data) {
  let events;
  try {
    events = JSON.parse(data);
  } catch (e) {
    throw e;
  }

  return Array.isArray(events) ?
    events.map(event => processLogEvent(event)) :
    [processLogEvent(events)];
}

class WinEventEmitter extends EventEmitter {
  constructor (options) {
    super();

    if (!/win/gi.test(os.platform())) {
      throw new Error('Only Windows is supported');
    }

    const defaultOptions = {
      providers: ['*'],
      maxEvents: 100,
      frequency: 10000
    };
    this.options = Object.assign({}, defaultOptions, options);
    this.options.startTime || (this.options.startTime = new Date());
    this.options.endTime  || (this.options.endTime = new Date(Date.now() + this.options.frequency));
    this._id = -1;
  }

  start () {
    this._id = setTimeout(() => {
      const providers = null
      const getAllLogs = (this.options.providers && this.options.providers.length > 0 && this.options.providers[0]=='*')
      if (!getAllLogs) {
        providers = `'${this.options.providers.join('\', \'')}'`;
      }
      let startTime = convertPowershellDate(this.options.startTime), endTime = convertPowershellDate(this.options.endTime);

      let creds = '';
      let credsOpt = '';
      if (this.options.userName && this.options.password) {
        creds =  `$User = '${this.options.userName}'; $Pass = ConvertTo-SecureString -String '${this.options.password}' -AsPlainText -Force; $Credential = New-Object –TypeName 'System.Management.Automation.PSCredential' –ArgumentList $User, $Pass; `;
        credsOpt = ' -Credentials $Credential';
      }

      let computerOpt = '';
      if (this.options.computerName) {
        computerOpt = ` -ComputerName ${this.options.computerName}`;
      }

      let powershellCmd = `powershell "${creds}Get-WinEvent -FilterHashTable @{ProviderName=${providers}; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}${credsOpt}${computerOpt} | ConvertTo-Json`;
      if (getAllLogs) {
        powershellCmd = `powershell "${creds}Get-WinEvent ---ListLog  *; StartTime='${startTime}'; EndTime='${endTime}';} -MaxEvents ${this.options.maxEvents}${credsOpt}${computerOpt} | ConvertTo-Json`;
      }
      this.emit('powerShellCmd', powerSHellCmd)
      let data;
      try {
        data = execSync(powershellCmd, {stdio: [1]}).toString();
        this.emit('raw.data', data)
      } catch (e) {
        // Ignore missing events
        if (!e.message.indexOf('NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand')) {
          this.emit('error', e);
        }
      }

      if (this._stop) { return; }
      var parsedData = null
      if (data) {
        try {
          parsedData = parseLogData(data)
          this.emit('data', parsedData)
        } catch (err) {
          this.emit('error', err)
        }
      }

      // Ensure no time gaps
      var now = Date.now()
      this.options.startTime = new Date(this.options.endTime || now)
      this.options.endTime = new Date(now + this.options.frequency)

      this.start();
    }, this.options.frequency);
  }

  stop () {
    clearTimeout(this._id);
    this._stop = true;
    this.emit('end');
  }
}

module.exports = WinEventEmitter;
<|endoftext|>


<commit_before>'use strict';

var d              = require('es5-ext/lib/Object/descriptor')
  , validateValues = require('../utils/validate-values')
  , relation       = require('./')
  , SetReadOnly    = require('./set-read-only')
  , setEmitter     = require('./set-emitter')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty
  , getPrototypeOf = Object.getPrototypeOf

  , hashTypes = { object: true, prototype: true, 'relation-set-item': true }
  , itemDelete = function (item) { item.$delete(); };

Object.defineProperties(relation, {
	value: d.gs(function () {
		var value = this.__value;
		if ((typeof value === 'function') && !value._id_) {
			if (value.length) return value;
			if (this.__external.__value) {
				if (value._resolved_) return value._value_;
				value._value_ = value.call(this.obj);
				value._resolved_ = true;
				return value._value_;
			}
			value = value.call(this.obj);
			if (this.__multiple.__value) {
				return new SetReadOnly(this.__ns.__value, value);
			}
			return (value == null) ? null : this.__ns.__value.normalize(value);
		}
		if (this.__multiple.__value) return this;
		return value;
	}, function self(value) {
		var error = this.validate(value);
		if (error) throw error;
		this.$setValue(value);
	}),
	$setValue: d(function (value) {
		var ns;
		if (this.__multiple.__value) {
			this._reset_(value);
			return;
		}
		if ((value == null) || ((typeof value === 'function') && !value._type_)) {
			this._signal_(value);
			return;
		}
		ns = this.__ns.__value;
		value = ns.is(value) ? value : ns.prototype.$create(value);
		this._signal_(value);
	}),
	$$setValue: d(function (nu) {
		var old, parent;
		if (this.hasOwnProperty('_value')) {
			old = this._value;
			if (nu === undefined) {
				delete this._value;
				getPrototypeOf(this).on('change', this._update_);
				if (!this.hasOwnProperty('_descriptor_')) delete this.obj[this.name];
			} else if (this._value === nu) {
				return;
			} else {
				this._value = nu;
				if (nu && nu._type_ === 'object') nu.on('selfupdate', this._update_);
			}
			if (old && old._type_ === 'object') old.off('selfupdate', this._update_);
		} else {
			if (nu === undefined) return;
			defineProperty(this, '_value', d('cw', nu));
			getPrototypeOf(this).off('change', this._update_);
			if (!this.hasOwnProperty('_descriptor_')) {
				this._descriptor_.enumerable =
					hashTypes.hasOwnProperty(this.obj._type_);
				defineProperty(this.obj, this.name, this._descriptor_);
			}
			if (nu && nu._type_ === 'object') nu.on('selfupdate', this._update_);
		}

		nu = this._value;
		if ((typeof nu === 'function') && !nu._type_ && !nu.length &&
				!this.__external.__value) {
			this._setGetter_();
		} else {
			this._deleteGetter_();
			this._update_();
		}
		if (!this.__multiple.__value) return;
		if (old === undefined) {
			parent = getPrototypeOf(this);
			if (parent._type_ !== 'relation') return;
			if (!parent.__multiple.__value) return;
			setEmitter.emitSet(this, setEmitter.getItems(parent), 'delete');
			setEmitter.getItems.clearAll();
		} else if (nu === undefined) {
			parent = getPrototypeOf(this);
			if (parent._type_ !== 'relation') return;
			if (!parent.__multiple.__value) return;
			setEmitter.emitSet(this, setEmitter.getItems(parent), 'add');
			setEmitter.getItems.clearAll();
		}
	}),
	validateValue: d(function (value) {
		var error, index, ns = this.__ns.__value;
		if ((error = ns.prototype.validateCreate(value))) return error;
		if (this.validateRelation) {
			if ((error = this.validateRelation(value))) return error;
		}
		if (this.unique && ((index = this._index_))) {
			if (index.get(ns._serialize_(ns.normalize(value))).count) {
				return new TypeError(value + " is already set on other object");
			}
		}
		return null;
	}),
	validateCreateValue: d(function (value, data) {
		var error, index, normalized, ns, unique;
		ns = data ? data.ns : this.__ns.__value;
		unique = data ? data.unique : this.__unique.__value;
		if (!data) data = this;
		if ((error = ns.prototype.validateCreate(value))) return error;
		if (data.validateRelation) {
			if ((error = data.validateRelation(value))) return error;
		}
		if (unique && ((index = this._selfIndex_))) {
			normalized = ns.normalize(value);
			if (normalized == null) return null;
			if (index.get(ns._serialize_(normalized)).count) {
				return new TypeError(value + " is already set on other object");
			}
		}
		return null;
	}),
	_validate_: d(function (data, value, validate) {
		if (data.writeOnce && (this._value != null)) {
			return new TypeError("Property is read-only");
		}
		if (value === null) {
			if (data.required) return new TypeError("Property is required");
			return null;
		}
		if ((typeof value === 'function') && !value._type_) return null;

		if (isArray(value)) {
			if (!data.multiple) {
				return new TypeError("Invalid value");
			}
			if (!value.length) {
				if (!data.required) return null;
				return new TypeError("Invalid value");
			}
			return validateValues(this, value, validate, data);
		}
		return validate.call(this, value, data);
	}),
	validate: d(function (value) {
		if (value === undefined) {
			if (this.required && (getPrototypeOf(this)._value == null)) {
				return new TypeError("Property is required");
			}
			return null;
		}
		return this._validate_(this, value, this.validateValue);
	}),
	validateCreate: d(function (value, data) {
		if (!data) data = this;
		if (value === undefined) {
			if (data.required && this._value == null) {
				return new TypeError("Property is required");
			}
			return null;
		}
		return this._validate_(data || this, value, this.validateCreateValue);
	}),
	$delete: d(function () {
		this._forEachRelation_(itemDelete);
		this._forEachItem_(itemDelete);
		this._itemPrototype_.$delete();
		if (this.hasOwnProperty('_value')) this._signal_();
	}),
	delete: d(function () {
		var defined = this.hasOwnProperty('_value');
		this.$delete();
		if (!defined) this._signal_();
	}),
	objectValue: d.gs(function () {
		var value = this.value, type;
		if (value == null) return value;
		type = typeof value;
		if ((type === 'object') || (type === 'function')) return value;
		value = Object(value);
		value.__proto__ = this.__ns.__value.prototype;
		return value;
	})
});
<commit_msg>On delete relation delete its extensions<commit_after>'use strict';

var d              = require('es5-ext/lib/Object/descriptor')
  , validateValues = require('../utils/validate-values')
  , relation       = require('./')
  , SetReadOnly    = require('./set-read-only')
  , setEmitter     = require('./set-emitter')

  , isArray = Array.isArray
  , defineProperty = Object.defineProperty
  , getPrototypeOf = Object.getPrototypeOf

  , hashTypes = { object: true, prototype: true, 'relation-set-item': true }
  , itemDelete = function (item) { item.$delete(); };

Object.defineProperties(relation, {
	value: d.gs(function () {
		var value = this.__value;
		if ((typeof value === 'function') && !value._id_) {
			if (value.length) return value;
			if (this.__external.__value) {
				if (value._resolved_) return value._value_;
				value._value_ = value.call(this.obj);
				value._resolved_ = true;
				return value._value_;
			}
			value = value.call(this.obj);
			if (this.__multiple.__value) {
				return new SetReadOnly(this.__ns.__value, value);
			}
			return (value == null) ? null : this.__ns.__value.normalize(value);
		}
		if (this.__multiple.__value) return this;
		return value;
	}, function self(value) {
		var error = this.validate(value);
		if (error) throw error;
		this.$setValue(value);
	}),
	$setValue: d(function (value) {
		var ns;
		if (this.__multiple.__value) {
			this._reset_(value);
			return;
		}
		if ((value == null) || ((typeof value === 'function') && !value._type_)) {
			this._signal_(value);
			return;
		}
		ns = this.__ns.__value;
		value = ns.is(value) ? value : ns.prototype.$create(value);
		this._signal_(value);
	}),
	$$setValue: d(function (nu) {
		var old, parent;
		if (this.hasOwnProperty('_value')) {
			old = this._value;
			if (nu === undefined) {
				delete this._value;
				getPrototypeOf(this).on('change', this._update_);
				if (!this.hasOwnProperty('_descriptor_')) delete this.obj[this.name];
			} else if (this._value === nu) {
				return;
			} else {
				this._value = nu;
				if (nu && nu._type_ === 'object') nu.on('selfupdate', this._update_);
			}
			if (old && old._type_ === 'object') old.off('selfupdate', this._update_);
		} else {
			if (nu === undefined) return;
			defineProperty(this, '_value', d('cw', nu));
			getPrototypeOf(this).off('change', this._update_);
			if (!this.hasOwnProperty('_descriptor_')) {
				this._descriptor_.enumerable =
					hashTypes.hasOwnProperty(this.obj._type_);
				defineProperty(this.obj, this.name, this._descriptor_);
			}
			if (nu && nu._type_ === 'object') nu.on('selfupdate', this._update_);
		}

		nu = this._value;
		if ((typeof nu === 'function') && !nu._type_ && !nu.length &&
				!this.__external.__value) {
			this._setGetter_();
		} else {
			this._deleteGetter_();
			this._update_();
		}
		if (!this.__multiple.__value) return;
		if (old === undefined) {
			parent = getPrototypeOf(this);
			if (parent._type_ !== 'relation') return;
			if (!parent.__multiple.__value) return;
			setEmitter.emitSet(this, setEmitter.getItems(parent), 'delete');
			setEmitter.getItems.clearAll();
		} else if (nu === undefined) {
			parent = getPrototypeOf(this);
			if (parent._type_ !== 'relation') return;
			if (!parent.__multiple.__value) return;
			setEmitter.emitSet(this, setEmitter.getItems(parent), 'add');
			setEmitter.getItems.clearAll();
		}
	}),
	validateValue: d(function (value) {
		var error, index, ns = this.__ns.__value;
		if ((error = ns.prototype.validateCreate(value))) return error;
		if (this.validateRelation) {
			if ((error = this.validateRelation(value))) return error;
		}
		if (this.unique && ((index = this._index_))) {
			if (index.get(ns._serialize_(ns.normalize(value))).count) {
				return new TypeError(value + " is already set on other object");
			}
		}
		return null;
	}),
	validateCreateValue: d(function (value, data) {
		var error, index, normalized, ns, unique;
		ns = data ? data.ns : this.__ns.__value;
		unique = data ? data.unique : this.__unique.__value;
		if (!data) data = this;
		if ((error = ns.prototype.validateCreate(value))) return error;
		if (data.validateRelation) {
			if ((error = data.validateRelation(value))) return error;
		}
		if (unique && ((index = this._selfIndex_))) {
			normalized = ns.normalize(value);
			if (normalized == null) return null;
			if (index.get(ns._serialize_(normalized)).count) {
				return new TypeError(value + " is already set on other object");
			}
		}
		return null;
	}),
	_validate_: d(function (data, value, validate) {
		if (data.writeOnce && (this._value != null)) {
			return new TypeError("Property is read-only");
		}
		if (value === null) {
			if (data.required) return new TypeError("Property is required");
			return null;
		}
		if ((typeof value === 'function') && !value._type_) return null;

		if (isArray(value)) {
			if (!data.multiple) {
				return new TypeError("Invalid value");
			}
			if (!value.length) {
				if (!data.required) return null;
				return new TypeError("Invalid value");
			}
			return validateValues(this, value, validate, data);
		}
		return validate.call(this, value, data);
	}),
	validate: d(function (value) {
		if (value === undefined) {
			if (this.required && (getPrototypeOf(this)._value == null)) {
				return new TypeError("Property is required");
			}
			return null;
		}
		return this._validate_(this, value, this.validateValue);
	}),
	validateCreate: d(function (value, data) {
		if (!data) data = this;
		if (value === undefined) {
			if (data.required && this._value == null) {
				return new TypeError("Property is required");
			}
			return null;
		}
		return this._validate_(data || this, value, this.validateCreateValue);
	}),
	$delete: d(function () {
		if (this.hasOwnProperty('_children_')) this._children_.forEach(itemDelete);
		this._forEachRelation_(itemDelete);
		this._forEachItem_(itemDelete);
		this._itemPrototype_.$delete();
		if (this.hasOwnProperty('_value')) this._signal_();
	}),
	delete: d(function () {
		var defined = this.hasOwnProperty('_value');
		this.$delete();
		if (!defined) this._signal_();
	}),
	objectValue: d.gs(function () {
		var value = this.value, type;
		if (value == null) return value;
		type = typeof value;
		if ((type === 'object') || (type === 'function')) return value;
		value = Object(value);
		value.__proto__ = this.__ns.__value.prototype;
		return value;
	})
});
<|endoftext|>


<commit_before>/**
 * Every api method and call can be protected by setting a minimum permission level on it. These lookup values
 * are used to ensure readers don't update user accounts, etc.
 *
 * @type {{ADMIN: number, EDITOR: number, AUTHOR: number, READER: number, NONE: number}}
 */
var permissions = function() {
    var Strings = require('../strings'),
        Response = require('./response'),
        strings = new Strings('en'),
        AVAILABLE_PRIVILEGES = {
            ADMIN: 0,
            EDITOR: 1,
            AUTHOR: 2,
            READER: 3,
            EXTERNAL: 3,
            NONE: 4
        };

    /**
     * Method should evaluate a current user's privileges and determine if the user can do something in the system.
     *
     * @param permissionLevel
     * @param req
     * @param res
     * @param next
     */
    function userHasPrivileges(permissionLevel, req, res, next) {
        var response = new Response(res),
            userPrivLevel = AVAILABLE_PRIVILEGES[req.identity.profile.role.toUpperCase()],
            isValid = (userPrivLevel <= parseInt(permissionLevel, 10));

        if(!isValid){
            response.write(response.STATUS_CODES.FORBIDDEN, strings.group('errors').user_privileges_exceeded);
        }
        else {
            next();
        }
    }

    this.requireAdmin = function(req, res, next){
        userHasPrivileges(AVAILABLE_PRIVILEGES.ADMIN, req, res, next);
    };

    this.requireEditor = function(req, res, next){
        userHasPrivileges(AVAILABLE_PRIVILEGES.EDITOR, req, res, next);
    };

    this.requireAuthor = function(req, res, next){
        userHasPrivileges(AVAILABLE_PRIVILEGES.AUTHOR, req, res, next);
    };

    this.requireReader = function(req, res, next){
        userHasPrivileges(AVAILABLE_PRIVILEGES.READER, req, res, next);
    };
};

module.exports = permissions;<commit_msg>Added "adminorself" permission check.<commit_after>/**
 * Every api method and call can be protected by setting a minimum permission level on it. These lookup values
 * are used to ensure readers don't update user accounts, etc.
 *
 * @type {{ADMIN: number, EDITOR: number, AUTHOR: number, READER: number, NONE: number}}
 */
var permissions = function() {
    var Strings = require('../strings'),
        Response = require('./response'),
        strings = new Strings('en'),
        AVAILABLE_PRIVILEGES = {
            ADMIN: 0,
            EDITOR: 1,
            AUTHOR: 2,
            READER: 3,
            EXTERNAL: 3,
            NONE: 4
        };

    /**
     * Method should evaluate a current user's privileges and determine if the user can do something in the system.
     *
     * @param permissionLevel
     * @param req
     * @param res
     * @param next
     */
    function userHasPrivileges(permissionLevel, req) {
        var userPrivLevel = AVAILABLE_PRIVILEGES[req.identity.profile.role.toUpperCase()];

        return (userPrivLevel <= parseInt(permissionLevel, 10));
    }

    function handleResponse(isValid, res, next){
        var response = new Response(res);

        if(!isValid){
            response.write(response.STATUS_CODES.FORBIDDEN, JSON.stringify({ message: strings.group('errors').user_privileges_exceeded}), res);
        }
        else {
            next();
        }
    }

    function validateUserHandleResponse(permissionLevel, req, res, next){
        var isValid = userHasPrivileges(permissionLevel, req);
        handleResponse(isValid, res, next);
    }

    this.requireAdmin = function(req, res, next){
        validateUserHandleResponse(AVAILABLE_PRIVILEGES.ADMIN, req, res, next);
    };

    this.requireAdminOrSelf = function(req, res, next){
        var isValid = userHasPrivileges(AVAILABLE_PRIVILEGES.ADMIN, req);

        //This check handles the case if the base privileges aren't enough but the user is trying to take action on itself
        if(!isValid && (req.body._id == req.identity.profile._id) ){
            isValid = true;
        }

        handleResponse(isValid, res, next)
    };

    this.requireEditor = function(req, res, next){
        validateUserHandleResponse(AVAILABLE_PRIVILEGES.EDITOR, req, res, next);
    };

    this.requireAuthor = function(req, res, next){
        validateUserHandleResponse(AVAILABLE_PRIVILEGES.AUTHOR, req, res, next);
    };

    this.requireReader = function(req, res, next){
        validateUserHandleResponse(AVAILABLE_PRIVILEGES.READER, req, res, next);
    };
};

module.exports = permissions;<|endoftext|>


<commit_before>var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var Static = require('node-static');
var config = require('./config');
var Cache = require(config.paths.LIB_ROOT + 'cache');

// create server object
process.mono = new EventEmitter();
process.mono.config = config;

// create caches
process.mono.cache = {
    client: Cache(),
    instances: Cache()
};

// error handling
process.mono.error = require(config.paths.LIB_ROOT + 'error');

// static file servers
process.mono.file = {
    client: new Static.Server(config.paths.CLIENT_ROOT, {cache: 604800}),
    module: new Static.Server(config.paths.MODULE_ROOT, {cache: 604800}),
    app: new Static.Server(config.paths.APPLICATION_ROOT, {cache: 604800}),
    public: new Static.Server(config.paths.PUBLIC_ROOT, {cache: 604800})
};

// init session api
process.mono.session = require(config.paths.SERVER_ROOT + 'session');

// db connection api
process.mono.getDbClients = require(config.paths.SERVER_ROOT + 'dbs');

// get db clients
process.mono.getDbClients(config.databases, function(err, clients) {

    // terminate process on error
    if (err) {
        throw new Error(err);
    }

    // add db clients to api
    process.mono.db = clients;

    // init core server module
    require('./moduleInstance').core();

    // emit api ready
    process.mono.emit('ready', Server);
});
<commit_msg>adapt api changes from the dbs module<commit_after>var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var Static = require('node-static');
var config = require('./config');
var Cache = require(config.paths.LIB_ROOT + 'cache');

// create server object
process.mono = new EventEmitter();
process.mono.config = config;

// create caches
process.mono.cache = {
    client: Cache(),
    instances: Cache()
};

// error handling
process.mono.error = require(config.paths.LIB_ROOT + 'error');

// static file servers
process.mono.file = {
    client: new Static.Server(config.paths.CLIENT_ROOT, {cache: 604800}),
    module: new Static.Server(config.paths.MODULE_ROOT, {cache: 604800}),
    app: new Static.Server(config.paths.APPLICATION_ROOT, {cache: 604800}),
    public: new Static.Server(config.paths.PUBLIC_ROOT, {cache: 604800})
};

// init session api
process.mono.session = require(config.paths.SERVER_ROOT + 'session');

// db connection api
process.mono.getDb = require(config.paths.SERVER_ROOT + 'dbs');

// get db clients
process.mono.config.systemDb = 'mongodb://localhost:27017/app_' + config.id;
process.mono.getDb(process.mono.config.systemDb, function(err, db) {

    // terminate process on error
    if (err) {
        throw new Error(err);
    }

    // init core server module
    require('./moduleInstance').core();

    // emit api ready
    process.mono.emit('ready');
});
<|endoftext|>


<commit_before>/** @module BrokerV2 */

'use strict';

var Common = require('../../common');
var Db = require('../db');
var Events = require('events');
var Logule = require('logule');
var Handlers = require('./api-handlers');
var Restify = require('restify');
var RestifyMiddleware = require('../../common/restify-middleware');
var Url = require('url');
var Util = require('util');

/**
 * The Broker starts a restify broker that talks to the CF cloud controller
 * API, primarily for updating the service catalog and service plans.
 * @constructor
 * @param {Object} opts - Broker options.
 */
var BrokerV2 = function(opts) {
  if (!(this instanceof BrokerV2)) {
    return new BrokerV2(opts);
  }

  Events.EventEmitter.call(this);

  this.opts = opts;

  this.log = Logule.init(module, this.opts.name);
  this.db = new Db(opts.database);

  this.createRestServer();

  return this;
};

Util.inherits(BrokerV2, Events.EventEmitter);

/**
 * Will shutdown the server gracefully.
 *
 * @this {BrokerV2}
 * @callback {Error}
 */
BrokerV2.prototype.stop = function(cb) {
  var broker = this;

  if (broker.restServer) {
    broker.restServer.close();
  }

  broker.log.info('Broker has shut down.');

  return (cb ? cb() : null);
};

/**
 * This is the main entry point to start the broker, after the constructor
 * has been instantiated.
 *
 * @this {BrokerV2}
 * @callback {Error}
 */
BrokerV2.prototype.start = function(cb) {
  var broker = this;

  broker.startRestServer(function(err, server) {
    if (err) {
      throw new Error('Broker REST server failed to start: ' + err);
    }
    broker.restServer = server;

    broker.initPeriodicJobs();
    broker.emit('start');
    broker.log.info('Broker now started with PID: ' + process.pid);
    return (cb ? cb(err) : err);
  });
};

/**
 * Creates the REST API server that the cloud controller will use
 * to communicate {un}provisioning/{un}binding requests.
 *
 * See also, Restify on NPM.
 *
 * @this {BrokerV2}
 * @callback {Error, RestifyServer}
 */
BrokerV2.prototype.createRestServer = function() {
  var broker = this;
  var versionNS = '/v' + broker.opts.semver.major;

  var server = Restify.createServer({
    name: broker.opts.name,
    version: broker.opts.apiVersion
  });

  server.use(RestifyMiddleware.validateAPIVersion(broker.opts.semver));
  server.use(Restify.authorizationParser());
  server.use(Handlers.authenticate(broker));
  server.use(Restify.acceptParser(server.acceptable));
  server.use(Restify.queryParser());
  server.use(Restify.bodyParser());
  server.use(RestifyMiddleware.requestLogger({
    prefix: 'HTTP Request'
  }));

  // Catalog
  server.get(versionNS + '/catalog', function(req, res, next) {
    Handlers.handleCatalogRequest(broker, req, res, next);
  });

  // Provision
  server.put(versionNS + '/service_instances/:instance_id', function(req, res, next) {
    Handlers.handleProvisionRequest(broker, req, res, next);
  });

  // Poll
  server.get(versionNS + '/service_instances/:instance_id/last_operation', function(
    req, res, next) {
    Handlers.handlePollRequest(broker, req, res, next);
  });

  // Deprovision
  server.del(versionNS + '/service_instances/:instance_id', function(req, res, next) {
    Handlers.handleDeProvisionRequest(broker, req, res, next);
  });

  // Bind
  server.put(versionNS +
    '/service_instances/:instance_id/service_bindings/:binding_id',
    function(req, res, next) {
      Handlers.handleBindRequest(broker, req, res, next);
    });

  // Unbind
  server.del(versionNS +
    '/service_instances/:instance_id/service_bindings/:binding_id',
    function(req, res, next) {
      Handlers.handleUnbindRequest(broker, req, res, next);
    });

  broker.restServer = server;
};

/**
 * Starts the REST API server that the cloud controller will use
 * to communicate {un}provisioning/{un}binding requests.
 *
 * See also, Restify on NPM.
 *
 * @this {BrokerV2}
 * @callback {Error, RestifyServer}
 */
BrokerV2.prototype.startRestServer = function(cb) {
  var broker = this;
  var server = broker.restServer;

  server.listen(broker.opts.port, function() {
    broker.opts.port = Url.parse(server.url).port;
    broker.log.info('%s broker is listening at %s', server.name, server.url);
    cb(null, server);
  });
};

/**
 * Sets up background jobs to run at predefined intervals.
 *
 * @this {BrokerV2}
 */
BrokerV2.prototype.initPeriodicJobs = function() {};

module.exports = BrokerV2;
<commit_msg>Refine functions in BrokerV2<commit_after>/** @module BrokerV2 */

'use strict';

var Common = require('../../common');
var Db = require('../db');
var Events = require('events');
var Logule = require('logule');
var Handlers = require('./api-handlers');
var Restify = require('restify');
var RestifyMiddleware = require('../../common/restify-middleware');
var Url = require('url');
var Util = require('util');

/**
 * The Broker starts a restify broker that talks to the CF cloud controller
 * API, primarily for updating the service catalog and service plans.
 * @constructor
 * @param {Object} opts - Broker options.
 */
var BrokerV2 = function(opts) {
  if (!(this instanceof BrokerV2)) {
    return new BrokerV2(opts);
  }

  Events.EventEmitter.call(this);

  this.opts = opts;

  this.log = Logule.init(module, this.opts.name);
  this.db = new Db(opts.database);

  this.restServer = this.createRestServer();

  return this;
};

Util.inherits(BrokerV2, Events.EventEmitter);

/**
 * Will shutdown the server gracefully.
 *
 * @this {BrokerV2}
 */
BrokerV2.prototype.stop = function() {
  var broker = this;

  if (broker.restServer) {
    broker.restServer.close();
  }

  broker.log.info('Broker has been shutdown.');
};

/**
 * This is the main entry point to start the broker, after the constructor
 * has been instantiated.
 *
 * @this {BrokerV2}
 */
BrokerV2.prototype.start = function() {
  var broker = this;
  var server = broker.restServer;

  server.listen(broker.opts.port, function(error) {
    if (error) {
      throw new Error('Broker REST server failed to listen on port %s : %s', broker.opts.port, error);
    }
    broker.log.info('%s broker is listening on port %s', server.name, broker.opts.port);

    broker.initPeriodicJobs();

    broker.log.info('Broker now started with PID: ' + process.pid);
  });
};

/**
 * Creates the REST API server that the cloud controller will use
 * to communicate {un}provisioning/{un}binding requests.
 *
 * See also, Restify on NPM.
 *
 * @this {BrokerV2}
 */
BrokerV2.prototype.createRestServer = function() {
  var broker = this;
  var versionNS = '/v' + broker.opts.semver.major;

  var server = Restify.createServer({
    name: broker.opts.name,
    version: broker.opts.apiVersion
  });

  server.use(RestifyMiddleware.validateAPIVersion(broker.opts.semver));
  server.use(Restify.authorizationParser());
  server.use(Handlers.authenticate(broker));
  server.use(Restify.acceptParser(server.acceptable));
  server.use(Restify.queryParser());
  server.use(Restify.bodyParser());
  server.use(RestifyMiddleware.requestLogger({
    prefix: 'HTTP Request'
  }));

  // Catalog
  server.get(versionNS + '/catalog',
    function(req, res, next) {
      Handlers.handleCatalogRequest(broker, req, res, next);
    }
  );

  // Provision
  server.put(versionNS + '/service_instances/:instance_id',
    function(req, res, next) {
      Handlers.handleProvisionRequest(broker, req, res, next);
    }
  );

  // Poll
  server.get(versionNS + '/service_instances/:instance_id/last_operation',
    function(
      req, res, next) {
      Handlers.handlePollRequest(broker, req, res, next);
    }
  );

  // Deprovision
  server.del(versionNS + '/service_instances/:instance_id',
    function(req, res, next) {
      Handlers.handleDeProvisionRequest(broker, req, res, next);
    }
  );

  // Bind
  server.put(versionNS + '/service_instances/:instance_id/service_bindings/:binding_id',
    function(req, res, next) {
      Handlers.handleBindRequest(broker, req, res, next);
    }
  );

  // Unbind
  server.del(versionNS + '/service_instances/:instance_id/service_bindings/:binding_id',
    function(req, res, next) {
      Handlers.handleUnbindRequest(broker, req, res, next);
    }
  );

  return server;
};

/**
 * Sets up background jobs to run at predefined intervals.
 *
 * @this {BrokerV2}
 */
BrokerV2.prototype.initPeriodicJobs = function() {};

module.exports = BrokerV2;
<|endoftext|>


<commit_before>const db = require('./db')
const _ = require('lodash/fp')

function createCashboxBatch (rec) {
  const sql = 'INSERT INTO cashbox_batches (device_id, created) VALUES ($1, now()) RETURNING *'
  const sql2 = `
    UPDATE bills SET cashbox_batch_id=$1
    FROM cash_in_txs
    WHERE bills.cash_in_txs_id = cash_in_txs.id AND
          cash_in_txs.device_id = $2 AND
          bills.cashbox_batch_id IS NULL
  `
  return db.tx(async t => {
    const newBatch = await t.oneOrNone(sql, [rec.deviceId])
    return t.oneOrNone(sql2, [newBatch.id, newBatch.device_id])
  })
}

function getBatches () {
  const sql = `SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by,
  json_agg(b.*) AS bills FROM cashbox_batches cb LEFT JOIN bills b ON cb.id=b.cashbox_batch_id GROUP BY cb.id`
  return db.any(sql).then(res => _.map(it => ({
    id: it.id,
    deviceId: it.device_id,
    created: it.created,
    operationType: it.operation_type,
    billCountOverride: it.bill_count_override,
    performedBy: it.performed_by,
    bills: it.bills
  }), res))
}

function editBatchById (id, performedBy) {
  const sql = `UPDATE cashbox_batches SET performed_by=$1 WHERE id=$2`
  return db.none(sql, [performedBy, id])
}

function getBillsByBatchId (id) {
  const sql = `SELECT * FROM bills WHERE cashbox_batch_id=$1`
  return db.any(sql, [id])
}

module.exports = { createCashboxBatch, getBatches, getBillsByBatchId, editBatchById }
<commit_msg>fix: query result formatting<commit_after>const db = require('./db')
const _ = require('lodash/fp')

function createCashboxBatch (rec) {
  const sql = 'INSERT INTO cashbox_batches (device_id, created) VALUES ($1, now()) RETURNING *'
  const sql2 = `
    UPDATE bills SET cashbox_batch_id=$1
    FROM cash_in_txs
    WHERE bills.cash_in_txs_id = cash_in_txs.id AND
          cash_in_txs.device_id = $2 AND
          bills.cashbox_batch_id IS NULL
  `
  return db.tx(async t => {
    const newBatch = await t.oneOrNone(sql, [rec.deviceId])
    return t.oneOrNone(sql2, [newBatch.id, newBatch.device_id])
  })
}

function getBatches () {
  const sql = `SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by,
  json_agg(b.*) AS bills FROM cashbox_batches cb LEFT JOIN bills b ON cb.id=b.cashbox_batch_id GROUP BY cb.id`
  return db.any(sql).then(res => _.map(it => _.mapKeys(ite => _.camelCase(ite), it), res))
}

function editBatchById (id, performedBy) {
  const sql = `UPDATE cashbox_batches SET performed_by=$1 WHERE id=$2`
  return db.none(sql, [performedBy, id])
}

function getBillsByBatchId (id) {
  const sql = `SELECT * FROM bills WHERE cashbox_batch_id=$1`
  return db.any(sql, [id])
}

module.exports = { createCashboxBatch, getBatches, getBillsByBatchId, editBatchById }
<|endoftext|>