├── .gitignore ├── .babelrc ├── LICENSE ├── package.json ├── src └── index.js ├── README.md └── dist └── vue-signalr.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "stage-2", "es2015" 4 | ], 5 | "plugins": ["transform-runtime"] 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Alexandre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wynnyo/vue-signalr", 3 | "version": "1.0.1", 4 | "description": "Signalr client for vue js", 5 | "main": "dist/vue-signalr.js", 6 | "files": [ 7 | "dist/vue-signalr.js", 8 | "src" 9 | ], 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "build": "babel src/index.js --out-file dist/vue-signalr.js", 13 | "run": "node dist/vue-signalr.js" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/wynnyo/vue-signalr.git" 18 | }, 19 | "keywords": [ 20 | "vue", 21 | "vuejs", 22 | "signalr" 23 | ], 24 | "author": "wynnyo ", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/wynnyo/vue-signalr/issues" 28 | }, 29 | "homepage": "https://github.com/wynnyo/vue-signalr#readme", 30 | "dependencies": { 31 | "@microsoft/signalr": "^5.0.0", 32 | "tslib": "^2.0.0" 33 | }, 34 | "devDependencies": { 35 | "babel-cli": "^6.26.0", 36 | "babel-plugin-transform-runtime": "^6.23.0", 37 | "babel-preset-es2015": "^6.24.1", 38 | "babel-preset-stage-2": "^6.24.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import * as SignalR from '@microsoft/signalr' 2 | 3 | const EventEmitter = require('events') 4 | 5 | const defaultOptions = { 6 | log: false, 7 | } 8 | 9 | class SocketConnection extends EventEmitter { 10 | constructor(connection, options = {}) { 11 | super() 12 | 13 | this.connection = connection 14 | this.options = Object.assign(defaultOptions, options) 15 | this.listened = [] 16 | 17 | this.toSend = [] 18 | 19 | this.offline = false 20 | 21 | this.socket = undefined 22 | } 23 | 24 | /** 25 | * 同一种消息只定义一次 26 | * 27 | * @param {string| symbol} event 28 | * @param {(...args: any[]) => void} listener 29 | * @memberof SocketConnection 30 | */ 31 | one(event, listener) { 32 | if (this.listeners(event).length === 0) { 33 | this.on(event, listener) 34 | } 35 | } 36 | 37 | async _initialize() { 38 | try { 39 | await this.socket.start() 40 | this.emit('onstart') 41 | if (this.offline) { 42 | this.emit('onrestart') 43 | } 44 | this.offline = false 45 | } catch (error) { 46 | setTimeout(async () => { 47 | await this._initialize() 48 | }, 5000) 49 | } 50 | } 51 | 52 | async start(options = {}) { 53 | this.options = Object.assign(defaultOptions, options) 54 | 55 | // 组件重新加载时, 如果 socket 存在, 不需要新建 56 | if (!this.socket) { 57 | this.socket = new SignalR.HubConnectionBuilder().configureLogging(SignalR.LogLevel.Information).withUrl(this.connection, this.options).build() 58 | 59 | this.socket.onclose(async () => { 60 | this.offline = true 61 | this.emit('onclose') 62 | await this._initialize() 63 | }) 64 | 65 | await this._initialize() 66 | } 67 | } 68 | 69 | async authenticate(accessToken, options = {}) { 70 | this.connection = `${this.connection}?authorization=${accessToken}` 71 | 72 | /* eslint-disable no-underscore-dangle */ 73 | await this.start() 74 | } 75 | 76 | listen(method) { 77 | if (this.offline) return 78 | 79 | if (this.listened.some((v) => v === method)) return 80 | this.listened.push(method) 81 | 82 | this.one('onstart', () => { 83 | this.socket.on(method, (data) => { 84 | if (this.options.log) console.log({ type: 'receive', method, data }) 85 | 86 | this.emit(method, data) 87 | }) 88 | }) 89 | } 90 | 91 | send(methodName, ...args) { 92 | if (this.options.log) console.log({ type: 'send', methodName, args }) 93 | if (this.offline) return 94 | 95 | if (this.socket) { 96 | this.socket.send(methodName, ...args) 97 | return 98 | } 99 | 100 | this.one('onstart', () => this.socket.send(methodName, ...args)) 101 | } 102 | 103 | async invoke(methodName, ...args) { 104 | if (this.options.log) console.log({ type: 'invoke', methodName, args }) 105 | if (this.offline) return false 106 | 107 | if (this.socket) { 108 | return this.socket.invoke(methodName, ...args) 109 | } 110 | 111 | // eslint-disable-next-line no-async-promise-executor 112 | return new Promise(async (resolve) => this.one('onstart', () => resolve(this.socket.invoke(methodName, ...args)))) 113 | } 114 | } 115 | 116 | if (!SignalR) { 117 | throw new Error('[Vue-SignalR] Cannot locate signalr-client') 118 | } 119 | 120 | function install(Vue, connection) { 121 | if (!connection) { 122 | throw new Error('[Vue-SignalR] Cannot locate connection') 123 | } 124 | 125 | const Socket = new SocketConnection(connection) 126 | 127 | Vue.socket = Socket 128 | 129 | Object.defineProperties(Vue.prototype, { 130 | $socket: { 131 | get() { 132 | return Socket 133 | }, 134 | }, 135 | }) 136 | 137 | Vue.mixin({ 138 | created() { 139 | if (this.$options.sockets) { 140 | const methods = Object.getOwnPropertyNames(this.$options.sockets) 141 | 142 | methods.forEach((method) => { 143 | Socket.listen(method) 144 | 145 | Socket.one(method, (data) => this.$options.sockets[method].call(this, data)) 146 | }) 147 | } 148 | 149 | if (this.$options.subscribe) { 150 | Socket.one('authenticated', () => { 151 | this.$options.subscribe.forEach((channel) => { 152 | Socket.invoke('join', channel) 153 | }) 154 | }) 155 | } 156 | }, 157 | }) 158 | } 159 | 160 | export default install 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-signalr 2 | ## BLOG [wynno.com](http://wynnyo.com/archives/vue-signalr) 3 | 4 | ## Thanks [@latelierco/vue-signalr (github.com)](https://github.com/latelierco/vue-signalr#readme) 5 | 6 | ## 关于项目说明 7 | 8 | 个人在使用 @latelierco/vue-signalr 时发现了一些问题, 于是 clone 下项目进行了一些改进 9 | 10 | ## 问题的复现 11 | 12 | - 在 main.js 下 13 | 14 | ```javascript 15 | import VueSignalR from '@latelierco/vue-signal' 16 | Vue.use(VueSignalR, process.env.VUE_APP_BASE_API + 'hub/message') 17 | ``` 18 | 19 | - 在 app.vue 20 | 21 | ```js 22 | created() { 23 | // 启动 24 | this.$socket.start() 25 | // 监听 init 事件 26 | this.$socket.on('init', () => { 27 | console.log('init') 28 | }) 29 | // 监听 reconnect 事件 30 | this.$socket.on('reconnect', () => { 31 | console.log('reconnect') 32 | }) 33 | // 输出 $socket 34 | console.log(this.$socket) 35 | }, 36 | sockets: { 37 | // 监听 ReceiveMessage 事件 38 | ReceiveMessage(data) { 39 | console.log(data) 40 | } 41 | } 42 | ``` 43 | 44 | - 当我编辑多次 app.vue 然后保存 45 | 46 | ![image-20201221112232103](http://images.wynnyo.com/Markdown/image-20201221112232103.png?x-oss-process=style/wynnyo-style) 47 | 48 | - 这时我断开后端 49 | 50 | ![image-20201221112447020](http://images.wynnyo.com/Markdown/image-20201221112447020.png?x-oss-process=style/wynnyo-style) 51 | 52 | - 查看 $socket, 发现 event 注册了多次 53 | 54 | ![image-20201221112816365](http://images.wynnyo.com/Markdown/image-20201221112816365.png?x-oss-process=style/wynnyo-style) 55 | 56 | ## 分析原因 57 | 58 | 热启动不会重新启动一个 app, 只会把当前组件销毁并重启, 由于 $socket 是绑定到 *Vue* 和 *Vue.prototype* 上的, 所以会出现这个问题 59 | 60 | ## 解决问题 61 | 62 | - 在源码中加入 63 | 64 | ```javascript 65 | /** 66 | * 同一种消息只定义一次 67 | * 68 | * @param {string| symbol} event 69 | * @param {(...args: any[]) => void} listener 70 | * @memberof SocketConnection 71 | */ 72 | one(event, listener) { 73 | if (this.listeners(event).length === 0) { 74 | this.on(event, listener) 75 | } 76 | } 77 | 78 | Vue.mixin({ 79 | created() { 80 | if (this.$options.sockets) { 81 | const methods = Object.getOwnPropertyNames(this.$options.sockets) 82 | methods.forEach(method => { 83 | Socket.listen(method) 84 | // 使用 one 代替 on 85 | Socket.one(method, data => this.$options.sockets[method].call(this, data)) 86 | }) 87 | } 88 | 89 | if (this.$options.subscribe) { 90 | Socket.one('authenticated', () => { 91 | this.$options.subscribe.forEach(channel => { 92 | Socket.invoke('join', channel) 93 | }) 94 | }) 95 | } 96 | } 97 | }) 98 | ``` 99 | 100 | - 其他监听也许要修改 101 | 102 | - 修改 app.vue 103 | 104 | ```javascript 105 | created() { 106 | // 启动 107 | this.$socket.start() 108 | // 监听 init 事件 109 | this.$socket.one('init', () => { 110 | console.log('init') 111 | }) 112 | // 监听 reconnect 事件 113 | this.$socket.one('reconnect', () => { 114 | console.log('reconnect') 115 | }) 116 | // 输出 $socket 117 | console.log(this.$socket) 118 | }, 119 | ``` 120 | 121 | 122 | ## 其他修改 123 | 124 | ### 关于 *SocketConnection* 实例 和 HubConnection 实例讨论 125 | 126 | - 个人观点: 在 app 中应该只有一个 *SocketConnection* 和 HubConnection 实例 127 | 128 | - 现有项目: 实现了 只有一个 *SocketConnection* 实例, 未实现只有一个 HubConnection 实例 129 | 130 | - 出现的问题, 在 断开 signal server 端时, 出现 init 和 reconnect 事件是无限循环 131 | 132 | - 修改: 133 | 134 | - 把 build HubConnection 实例放到 start 方法中, 并判断 socket 不为空时才创建 135 | 136 | ```javascript 137 | async start(options = {}) { 138 | this.options = Object.assign(defaultOptions, options) 139 | 140 | // 组件重新加载时, 如果 socket 存在, 不需要新建 141 | if (!this.socket) { 142 | this.socket = new SignalR.HubConnectionBuilder() 143 | .configureLogging(SignalR.LogLevel.Information) 144 | .withUrl(this.connection, this.options) 145 | .build() 146 | 147 | this.socket.onclose(async () => { 148 | this.offline = true 149 | await this._initialize() 150 | }) 151 | 152 | await this._initialize() 153 | } 154 | } 155 | ``` 156 | 157 | - 在 *_initialize* 方法中, 只做 HubConnection 的启动 158 | 159 | ```javascript 160 | async _initialize() { 161 | try { 162 | await this.socket.start() 163 | } catch (error) { 164 | // 这里把重试改为了 5s, 减小客户端压力 165 | setTimeout(async () => { 166 | await this._initialize() 167 | }, 5000) 168 | } 169 | } 170 | ``` 171 | 172 | - 其他修改 173 | 174 | - init 事件监听更名为 onstart 175 | - reconnect 事件监听更名为 onrestart 176 | - 新增事件监听 onclose 177 | 178 | 179 | ## 安装 180 | 181 | 182 | ```console 183 | $ npm install @wynnyo/vue-signalr --save 184 | ``` 185 | 186 | ## 使用 187 | 188 | 189 | ```js 190 | import Vue from 'vue' 191 | import VueSignalR from '@wynnyo/vue-signalr' 192 | 193 | Vue.use(VueSignalR, 'SOCKET_URL'); 194 | 195 | new Vue({ 196 | el: '#app', 197 | render: h => h(App), 198 | 199 | created() { 200 | this.$socket.start({ 201 | log: false // Active only in development for debugging. 202 | }); 203 | // socket 链接触发事件 204 | this.$socket.one('onstart', () => { 205 | }) 206 | // socket 断开链接触发的事件 207 | this.$socket.one('onclose', () => { 208 | }) 209 | // socket 重新链接触发事件 210 | this.$socket.one('onrestart', () => { 211 | }) 212 | }, 213 | }); 214 | ``` 215 | 216 | ## 在其他组件中使用 217 | 218 | ```js 219 | Vue.extend({ 220 | 221 | ... 222 | 223 | methods: { 224 | 225 | someMethod() { 226 | this.$socket.invoke('socketName', payloadData) 227 | .then(response => { 228 | ... 229 | }) 230 | } 231 | 232 | async someAsyncMethod() { 233 | const response = await this.$socket.invoke('socketName', payloadData) 234 | ... 235 | } 236 | 237 | }, 238 | 239 | // Register your listener here. 240 | sockets: { 241 | 242 | // Equivalent of 243 | // signalrHubConnection.on('someEvent', (data) => this.someActionWithData(data)) 244 | someEvent(data) { 245 | this.someActionWithData(data) 246 | } 247 | 248 | otherSomeEvent(data) { 249 | this.otheSomeActionWithOtherSomeData(data) 250 | } 251 | 252 | } 253 | 254 | }); 255 | ``` 256 | -------------------------------------------------------------------------------- /dist/vue-signalr.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _getOwnPropertyNames = require('babel-runtime/core-js/object/get-own-property-names'); 8 | 9 | var _getOwnPropertyNames2 = _interopRequireDefault(_getOwnPropertyNames); 10 | 11 | var _defineProperties = require('babel-runtime/core-js/object/define-properties'); 12 | 13 | var _defineProperties2 = _interopRequireDefault(_defineProperties); 14 | 15 | var _promise = require('babel-runtime/core-js/promise'); 16 | 17 | var _promise2 = _interopRequireDefault(_promise); 18 | 19 | var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); 20 | 21 | var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); 22 | 23 | var _regenerator = require('babel-runtime/regenerator'); 24 | 25 | var _regenerator2 = _interopRequireDefault(_regenerator); 26 | 27 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 28 | 29 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 30 | 31 | var _assign = require('babel-runtime/core-js/object/assign'); 32 | 33 | var _assign2 = _interopRequireDefault(_assign); 34 | 35 | var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); 36 | 37 | var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); 38 | 39 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 40 | 41 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 42 | 43 | var _createClass2 = require('babel-runtime/helpers/createClass'); 44 | 45 | var _createClass3 = _interopRequireDefault(_createClass2); 46 | 47 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 48 | 49 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 50 | 51 | var _inherits2 = require('babel-runtime/helpers/inherits'); 52 | 53 | var _inherits3 = _interopRequireDefault(_inherits2); 54 | 55 | var _signalr = require('@microsoft/signalr'); 56 | 57 | var SignalR = _interopRequireWildcard(_signalr); 58 | 59 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 60 | 61 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 62 | 63 | var EventEmitter = require('events'); 64 | 65 | var defaultOptions = { 66 | log: false 67 | }; 68 | 69 | var SocketConnection = function (_EventEmitter) { 70 | (0, _inherits3.default)(SocketConnection, _EventEmitter); 71 | 72 | function SocketConnection(connection) { 73 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 74 | (0, _classCallCheck3.default)(this, SocketConnection); 75 | 76 | var _this = (0, _possibleConstructorReturn3.default)(this, (SocketConnection.__proto__ || (0, _getPrototypeOf2.default)(SocketConnection)).call(this)); 77 | 78 | _this.connection = connection; 79 | _this.options = (0, _assign2.default)(defaultOptions, options); 80 | _this.listened = []; 81 | 82 | _this.toSend = []; 83 | 84 | _this.offline = false; 85 | 86 | _this.socket = undefined; 87 | return _this; 88 | } 89 | 90 | /** 91 | * 同一种消息只定义一次 92 | * 93 | * @param {string| symbol} event 94 | * @param {(...args: any[]) => void} listener 95 | * @memberof SocketConnection 96 | */ 97 | 98 | 99 | (0, _createClass3.default)(SocketConnection, [{ 100 | key: 'one', 101 | value: function one(event, listener) { 102 | if (this.listeners(event).length === 0) { 103 | this.on(event, listener); 104 | } 105 | } 106 | }, { 107 | key: '_initialize', 108 | value: function () { 109 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2() { 110 | var _this2 = this; 111 | 112 | return _regenerator2.default.wrap(function _callee2$(_context2) { 113 | while (1) { 114 | switch (_context2.prev = _context2.next) { 115 | case 0: 116 | _context2.prev = 0; 117 | _context2.next = 3; 118 | return this.socket.start(); 119 | 120 | case 3: 121 | this.emit('onstart'); 122 | if (this.offline) { 123 | this.emit('onrestart'); 124 | } 125 | this.offline = false; 126 | _context2.next = 11; 127 | break; 128 | 129 | case 8: 130 | _context2.prev = 8; 131 | _context2.t0 = _context2['catch'](0); 132 | 133 | setTimeout((0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee() { 134 | return _regenerator2.default.wrap(function _callee$(_context) { 135 | while (1) { 136 | switch (_context.prev = _context.next) { 137 | case 0: 138 | _context.next = 2; 139 | return _this2._initialize(); 140 | 141 | case 2: 142 | case 'end': 143 | return _context.stop(); 144 | } 145 | } 146 | }, _callee, _this2); 147 | })), 5000); 148 | 149 | case 11: 150 | case 'end': 151 | return _context2.stop(); 152 | } 153 | } 154 | }, _callee2, this, [[0, 8]]); 155 | })); 156 | 157 | function _initialize() { 158 | return _ref.apply(this, arguments); 159 | } 160 | 161 | return _initialize; 162 | }() 163 | }, { 164 | key: 'start', 165 | value: function () { 166 | var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4() { 167 | var _this3 = this; 168 | 169 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 170 | return _regenerator2.default.wrap(function _callee4$(_context4) { 171 | while (1) { 172 | switch (_context4.prev = _context4.next) { 173 | case 0: 174 | this.options = (0, _assign2.default)(defaultOptions, options); 175 | 176 | // 组件重新加载时, 如果 socket 存在, 不需要新建 177 | 178 | if (this.socket) { 179 | _context4.next = 6; 180 | break; 181 | } 182 | 183 | this.socket = new SignalR.HubConnectionBuilder().configureLogging(SignalR.LogLevel.Information).withUrl(this.connection, this.options).build(); 184 | 185 | this.socket.onclose((0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3() { 186 | return _regenerator2.default.wrap(function _callee3$(_context3) { 187 | while (1) { 188 | switch (_context3.prev = _context3.next) { 189 | case 0: 190 | _this3.offline = true; 191 | _this3.emit('onclose'); 192 | _context3.next = 4; 193 | return _this3._initialize(); 194 | 195 | case 4: 196 | case 'end': 197 | return _context3.stop(); 198 | } 199 | } 200 | }, _callee3, _this3); 201 | }))); 202 | 203 | _context4.next = 6; 204 | return this._initialize(); 205 | 206 | case 6: 207 | case 'end': 208 | return _context4.stop(); 209 | } 210 | } 211 | }, _callee4, this); 212 | })); 213 | 214 | function start() { 215 | return _ref3.apply(this, arguments); 216 | } 217 | 218 | return start; 219 | }() 220 | }, { 221 | key: 'authenticate', 222 | value: function () { 223 | var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(accessToken) { 224 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 225 | return _regenerator2.default.wrap(function _callee5$(_context5) { 226 | while (1) { 227 | switch (_context5.prev = _context5.next) { 228 | case 0: 229 | this.connection = this.connection + '?authorization=' + accessToken; 230 | 231 | /* eslint-disable no-underscore-dangle */ 232 | _context5.next = 3; 233 | return this.start(); 234 | 235 | case 3: 236 | case 'end': 237 | return _context5.stop(); 238 | } 239 | } 240 | }, _callee5, this); 241 | })); 242 | 243 | function authenticate(_x4) { 244 | return _ref5.apply(this, arguments); 245 | } 246 | 247 | return authenticate; 248 | }() 249 | }, { 250 | key: 'listen', 251 | value: function listen(method) { 252 | var _this4 = this; 253 | 254 | if (this.offline) return; 255 | 256 | if (this.listened.some(function (v) { 257 | return v === method; 258 | })) return; 259 | this.listened.push(method); 260 | 261 | this.one('onstart', function () { 262 | _this4.socket.on(method, function (data) { 263 | if (_this4.options.log) console.log({ type: 'receive', method: method, data: data }); 264 | 265 | _this4.emit(method, data); 266 | }); 267 | }); 268 | } 269 | }, { 270 | key: 'send', 271 | value: function send(methodName) { 272 | var _this5 = this; 273 | 274 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 275 | args[_key - 1] = arguments[_key]; 276 | } 277 | 278 | if (this.options.log) console.log({ type: 'send', methodName: methodName, args: args }); 279 | if (this.offline) return; 280 | 281 | if (this.socket) { 282 | var _socket; 283 | 284 | (_socket = this.socket).send.apply(_socket, [methodName].concat(args)); 285 | return; 286 | } 287 | 288 | this.one('onstart', function () { 289 | var _socket2; 290 | 291 | return (_socket2 = _this5.socket).send.apply(_socket2, [methodName].concat(args)); 292 | }); 293 | } 294 | }, { 295 | key: 'invoke', 296 | value: function () { 297 | var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee7(methodName) { 298 | var _this6 = this; 299 | 300 | for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 301 | args[_key2 - 1] = arguments[_key2]; 302 | } 303 | 304 | var _socket3; 305 | 306 | return _regenerator2.default.wrap(function _callee7$(_context7) { 307 | while (1) { 308 | switch (_context7.prev = _context7.next) { 309 | case 0: 310 | if (this.options.log) console.log({ type: 'invoke', methodName: methodName, args: args }); 311 | 312 | if (!this.offline) { 313 | _context7.next = 3; 314 | break; 315 | } 316 | 317 | return _context7.abrupt('return', false); 318 | 319 | case 3: 320 | if (!this.socket) { 321 | _context7.next = 5; 322 | break; 323 | } 324 | 325 | return _context7.abrupt('return', (_socket3 = this.socket).invoke.apply(_socket3, [methodName].concat((0, _toConsumableArray3.default)(args)))); 326 | 327 | case 5: 328 | return _context7.abrupt('return', new _promise2.default(function () { 329 | var _ref7 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(resolve) { 330 | return _regenerator2.default.wrap(function _callee6$(_context6) { 331 | while (1) { 332 | switch (_context6.prev = _context6.next) { 333 | case 0: 334 | return _context6.abrupt('return', _this6.one('onstart', function () { 335 | var _socket4; 336 | 337 | return resolve((_socket4 = _this6.socket).invoke.apply(_socket4, [methodName].concat((0, _toConsumableArray3.default)(args)))); 338 | })); 339 | 340 | case 1: 341 | case 'end': 342 | return _context6.stop(); 343 | } 344 | } 345 | }, _callee6, _this6); 346 | })); 347 | 348 | return function (_x6) { 349 | return _ref7.apply(this, arguments); 350 | }; 351 | }())); 352 | 353 | case 6: 354 | case 'end': 355 | return _context7.stop(); 356 | } 357 | } 358 | }, _callee7, this); 359 | })); 360 | 361 | function invoke(_x5) { 362 | return _ref6.apply(this, arguments); 363 | } 364 | 365 | return invoke; 366 | }() 367 | }]); 368 | return SocketConnection; 369 | }(EventEmitter); 370 | 371 | if (!SignalR) { 372 | throw new Error('[Vue-SignalR] Cannot locate signalr-client'); 373 | } 374 | 375 | function install(Vue, connection) { 376 | if (!connection) { 377 | throw new Error('[Vue-SignalR] Cannot locate connection'); 378 | } 379 | 380 | var Socket = new SocketConnection(connection); 381 | 382 | Vue.socket = Socket; 383 | 384 | (0, _defineProperties2.default)(Vue.prototype, { 385 | $socket: { 386 | get: function get() { 387 | return Socket; 388 | } 389 | } 390 | }); 391 | 392 | Vue.mixin({ 393 | created: function created() { 394 | var _this7 = this; 395 | 396 | if (this.$options.sockets) { 397 | var methods = (0, _getOwnPropertyNames2.default)(this.$options.sockets); 398 | 399 | methods.forEach(function (method) { 400 | Socket.listen(method); 401 | 402 | Socket.one(method, function (data) { 403 | return _this7.$options.sockets[method].call(_this7, data); 404 | }); 405 | }); 406 | } 407 | 408 | if (this.$options.subscribe) { 409 | Socket.one('authenticated', function () { 410 | _this7.$options.subscribe.forEach(function (channel) { 411 | Socket.invoke('join', channel); 412 | }); 413 | }); 414 | } 415 | } 416 | }); 417 | } 418 | 419 | exports.default = install; 420 | --------------------------------------------------------------------------------