v9.6.2017.0808   重构正向工程,基于映射表查找数据库字段类型到实体类型的映射
大石头 编写于 2017-08-08 21:38:06
X
; (function (root, factory) {
    var ws = factory(root);
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else if (typeof module !== 'undefined' && module.exports) {
        module.exports = factory();
    } else {
        root.ws = factory();
    }
}(this, function (root, undefined) {

    if (!('WebSocket' in window)) return;

    var _handlers = {}, wsocket,
        eventTarget = document.createElement('div'),
        settings = {
            //是否自动重连
            automaticOpen: true,
            //自动重连延迟重连速度速度
            reconnectDecay: 1.5
        },
        func = function () { },
        //对外泄露 API 😄
        _api = {
            CONNECTING: WebSocket.CONNECTING,
            OPEN: WebSocket.OPEN,
            CLOSING: WebSocket.CLOSING,
            CLOSED: WebSocket.CLOSED
        };

    /**
     * [ws]
     * @param  参数 url 为建立连接的URL
     * @param  参数 protocols 为服务器选择的子协定
     * @param  参数 options 初始化定义参数   
     */
    function ws(url, protocols, options) {
        var self = this;
        //websocket url
        this.url = url;
        //websocket 状态
        this.readyState = WebSocket.CONNECTING;

        /**
         * 服务器选择的子协定,这是建立 WebSocket 对象时 protocols 参数里的其中一个字符串。
         */
        this.protocol = protocols ? protocols : null;

        // 绑定选项定义设置
        if (!options) { options = {}; }
        for (var key in settings) {
            if (typeof options[key] !== 'undefined') this[key] = options[key];
            else this[key] = settings[key];
        }

        // 公开 API
        for (var a in _api) this[a] = _api[a];

        //用事件处理程序
        eventTarget.addEventListener('open', function (event) { self !== window && self.onopen(event); });
        eventTarget.addEventListener('close', function (event) { self !== window && self.onclose(event); });
        eventTarget.addEventListener('connecting', function (event) { self !== window && self.onconnecting(event); });
        eventTarget.addEventListener('message', function (event) { self !== window && self.onmessage(event); });
        eventTarget.addEventListener('error', function (event) { self !== window && self.onerror(event); });

        // 公开事件目标的API
        this.addEventListener = eventTarget.addEventListener.bind(eventTarget);
        this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget);
        this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget);


        if (this.automaticOpen === true && this !== window) this.open();
        return this;
    }


    /**
     * [generateEvent 该函数产生一个事件,与标准兼容,兼容的浏览器和IE9 - IE11?]
     * http://stackoverflow.com/questions/19345392/why-arent-my-parameters-getting-passed-through-to-a-dispatched-event/19345563#19345563
     * https://msdn.microsoft.com/library/ff975299(v=vs.85).aspx
     * @param eventName 位字符串类型的事件名字
     * @param 参数的args对象的可选对象,该事件将使用
     */
    function generateEvent(eventName, args) {
        var evt = document.createEvent("CustomEvent");
        evt.initCustomEvent(eventName, false, false, args);
        return evt;
    }

    ws.prototype.onconnecting = func;
    ws.prototype.onerror = func;
    ws.prototype.onopen = func;
    ws.prototype.onmessage = func;

    /**
     * [send 发送 websocket 消息]
     * @param 参数 data 为发消息的内容
     */
    ws.prototype.send = function (data) {
        if (this.wsocket) this.wsocket.send(data);
        else {
            throw 'INVALID_STATE_ERR : Pausing to reconnect websocket';
        }
    };
    ws.prototype.invoke=function(action, args, callback) {
        var msg = { action: action, args: args };
        if (this.wsocket) this.wsocket.send(JSON.stringify(msg));
        else {
            throw 'INVALID_STATE_ERR : Pausing to reconnect websocket';
        }
    }

    /**
     * [close 关闭 websocket 连接。]
     * 如果已经关闭了连接,此方法不起作用。
     * 
     * 错误代码参考:https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
     * @param 参数 code 为错误代码 1000为正常关闭
     * @param 参数 reason 为错误理由
     */
    ws.prototype.close = function (code, reason) {
        // 默认CLOSE_NORMAL代码
        if (typeof code === 'undefined') code = 1000;
        if (this.wsocket) this.wsocket.close(code, reason);
    };


    /**
     * [open 打开建立 websocket 握手连接]
     */
    ws.prototype.open = function () {
        var self = this;
        wsocket = new WebSocket(this.url, this.protocol || []);
        eventTarget.dispatchEvent(generateEvent('connecting'));
        wsocket.onopen = function (event) {
            self.protocol = ws.protocol;
            self.readyState = WebSocket.OPEN;

            var e = generateEvent('open');
            eventTarget.dispatchEvent(e);
        };
        wsocket.onclose = function (event) {
            self.readyState = WebSocket.CLOSED;
            var e = generateEvent('connecting');
            e.code = event.code;
            e.reason = event.reason;
            e.wasClean = event.wasClean;
            eventTarget.dispatchEvent(e);

            eventTarget.dispatchEvent(generateEvent('close'));
        };
        wsocket.onmessage = function (event) {
            var e = generateEvent('message');
            e.data = event.data;
            eventTarget.dispatchEvent(e);
        };
        wsocket.onerror = function (event) {
            var e = generateEvent('error');
            eventTarget.dispatchEvent(e);
        };
        this.wsocket = wsocket;
        return this;
    };
    return ws;
}));