123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- // 与客户端交互方法列表
- import wsPlugins from './plugins/index';
- // const ReWebSocket = require('reconnecting-websocket');
- // websocket重连
- import ReWebSocket from '../node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs';
- // const Bowser = require('bowser');
- // 浏览器信息获取
- import Bowser from "../node_modules/bowser/es5";
- const browser = Bowser.getParser(window.navigator.userAgent);
- interface callbacks {
- // 连接客户端状态
- connectResult: any,
- // 登录客户端状态
- loginResult: any
- }
- export default class Ws {
- [x: string]: any;
- // 连接地址
- static url: string = '';
- // 传入的配置项(方法)
- static opts: Object = {};
- // 密码加密公钥
- static publicKey = '';
- // 是否连接客户端
- private isConnectSuccessQt: Boolean = false;
- // 是否登录客户端
- private isLoginSuccess: Boolean = false;
- // 唯一实例
- private static _instance: any = null;
- // 当前连接的webSocket
- webSocket: any;
- // 最大重连数
- reConnectCount: number = 3;
- // 连接失败次数
- connectFailCount: number = 0;
- // 重连完成标识
- connectEnd: Boolean = false;
- // 登录完成标识
- loginEnd: Boolean = false;
- // 最大重登数
- reLoginCount: number = 1;
- // 连接失败次数
- loginFailCount: number = 0;
- // 当前websocket登录配置
- config: Object = {};
- // 登陆IP
- loginIp: string;
- // 登陆端口
- loginPort: string;
- // 登录用户名
- userName: string;
- // 登录密码,密码与token二选一
- userPwd: string;
- // 登录token,密码与token二选一
- token: string;
- // 用户标识符
- userCode: Number = 0;
- // 回调函数
- private callback: callbacks;
- // 创建的控件ID列表
- ids: Array<String> = [];
- // 创建的控件列表
- ctrls: Array<String> = [];
- // 心跳
- heartBeatTimer: any = null;
- // 监听的方法表
- listerns: any;
- constructor({
- url= 'ws://localhost:1234',
- publicKey= 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbEpPpxpLJft4W9YZj8bRh2bYYZshBEsKOlxgyn11rlEyTasjBSZRV9aj33tvQ2T55izH0fWl+dL/dLZChawFrlGDcH8JuWge2xYMgII9mggcYa0UiQ7pLXJ9ivXZ/cOY3HzrRQdR7dGTSNn3Z0Ctbns6mLgvlA2r3qMNs/8wHBwIDAQAB',
- reConnectCount = 3,
- reLoginCount = 1,
- loginIp= location.hostname,
- loginPort= location.port,
- userName = '',
- userPwd = '',
- token = '',
- callback = {
- connectResult: null,
- loginResult: null
- }
- } : {
- url: string,
- publicKey: string,
- reConnectCount: number,
- reLoginCount: number,
- loginIp: string,
- loginPort: string,
- userName: string,
- userPwd: string,
- token: string
- callback: callbacks,
- }) {
- // if (/https/.test(location.protocol)) {
- // url = `wss:${url}`;
- // } else {
- // url = `ws:${url}`;
- // }
- // url = `ws://localhost:1234`;
- this.url = url;
- this.userCode = new Date().valueOf();
- this.webSocket = null;
- this.reConnectCount = reConnectCount;
- this.reLoginCount = reLoginCount;
- this.publicKey = publicKey;
- this.loginIp = loginIp;
- this.loginPort = loginPort;
- this.userName = userName;
- this.userPwd = userPwd;
- this.token = token;
- this.callback = callback;
-
- this.connectFailCount = this.connectFailCount;
- // 基础操作所需功能或属性
- this.ids = [];
- this.ctrls = [];
- // 是否连接客户端
- this.isConnectSuccessQt = false;
- // 是否登陆客户端
- this.isLoginSuccess = false;
- this.heartBeatTimer = null;
- // 初始化配置参数
- this.initConfig();
- // 连接客户端
- this.connectQt();
- // 获取与客户端交互方法列表
- const plugins = [];
- Object.keys(wsPlugins).forEach(item => {
- if(hasKey(wsPlugins, item)){
- plugins.push(wsPlugins[item]);
- }
- });
- // 与客户端通讯功能注册
- usePlugin(plugins);
- // 用户注册监听事件表
- this.listerns = new Map();
- // 传入登录配置,则登录
- if(this.userName) {
- this.detectConnectQt().then((res: Boolean) => {
- if(res) {
- // 登陆客户端
- this.loginClient();
- // 心跳保活
- this._heartbeat();
- }
- });
- }
- }
- /**
- * @description 获得实例对象
- */
- public static getInstance(options: any):Ws {
- if(!this._instance) {
- this._instance = new Ws(options);
- }
- return this._instance;
- }
- /**
- * @description 用户注册监听事件
- * @params {String} eventType 事件名称
- * @params {any} callback 回调函数
- */
- on(eventType: String, callback: any) {
- this.listerns.set(eventType, callback);
- }
- /**
- * @description 用户取消监听事件
- * @params {String} eventType 事件名称
- */
- off(eventType: string) {
- delete this.listerns[eventType];
- }
- /**
- * @description 发送消息给客户端
- * @params {String} method 事件名称
- * @params {Object} data 传输消息的数据内容
- */
- emit(method: any, data: { method: any; }) {
- const { webSocket } = this;
- data.method = method;
- // 不需要判断登录和连接的方法过滤
- let filterList = ['heartbeat', 'login', 'logout', 'browserInfo'];
- if(filterList.includes(method)) {
- webSocket.send(JSON.stringify(data));
- return;
- }
- return new Promise((resolve, reject) => {
- this.detectConnectQt().then(con => {
- if(con) {
- this.detectLoginClient().then(login => {
- if(login) {
- webSocket.send(JSON.stringify(data));
- resolve(true);
- } else {
- // 登录失败
- reject(2);
- }
- })
- } else {
- // 连接失败
- reject(1);
- }
- })
- })
- }
- /*
- * 初始化配置
- */
- initConfig() {
- this.config = {
- userName: this.userName,
- userCode: this.userCode,
- loginPort: this.loginPort,
- loginIp: this.loginIp,
- userPwd: this.userPwd,
- token: this.token,
- };
- // 浏览器信息
- const browserInfo = {
- name: '',
- version: '',
- platform: ''
- };
- browserInfo.name = browser.getBrowserName().toLowerCase();
- browserInfo.version = browser.getBrowser().version.toLowerCase();
- browserInfo.platform =
- browser._ua.indexOf('Win64') >= 0 || browser._ua.indexOf('Wow64') >= 0
- ? 'win64'
- : 'win32';
- this.config['browser'] = browserInfo;
- }
- /**
- * @description 连接客户端
- */
- connectQt() {
- this.connectEnd = false;
- // 连接客户端
- this.webSocket = new ReWebSocket(this.url, '', {
- maxRetries: this.reConnectCount
- });
- this.addEvents();
- }
- /**
- * @description 检测连接客户端状态
- */
- detectConnectQt() {
- let _this = this;
- return new Promise((resolve, reject) => {
- if(!this.connectEnd) { // 连接中
- let _interval = setInterval(() => {
- if(_this.connectEnd) {
- clearInterval(_interval);
- resolve(_this.isConnectSuccessQt);
- }
- }, 50)
- } else {
- resolve(_this.isConnectSuccessQt);
- }
- })
- }
- /**
- * @description 检测登录客户端状态
- */
- detectLoginClient() {
- let _this = this;
- return new Promise((resolve, reject) => {
- if(!this.loginEnd) { // 连接中
- let _interval = setInterval(() => {
- if(_this.loginEnd) {
- clearInterval(_interval);
- resolve(_this.isLoginSuccess);
- }
- }, 50)
- } else {
- resolve(_this.isLoginSuccess);
- }
- })
- }
- /**
- * @description 登录客户端
- * @params {Object} config 登录相关配置
- */
- login(config: Object) {
- this.loginEnd = false;
- Object.assign(this.config, config);
- // 未连接客户端
- if(!this.isOpen()) {
- // 连接失败
- return false
- } else {
- // 若已登录,先注销
- if (this.isLoginSuccess) {
- this.logout();
- }
- // 登陆客户端
- this.loginClient();
- // 心跳保活
- this._heartbeat();
- }
- }
- /**
- * @description 连接客户端完成后登陆
- */
- // loginAfterConnectEnd() {
- // // 未连接客户端
- // if(!this.isOpen()) {
- // // 连接失败
- // return false
- // } else {
- // // 若已登录,先注销
- // if (this.isLoginSuccess) {
- // this.logout();
- // }
- // // 登陆客户端
- // this.loginClient();
- // // 心跳保活
- // this._heartbeat();
- // }
- // }
- /**
- * @description 登出客户端
- */
- logout() {
- // 退出客户端
- this.logoutClient();
- this.isLoginSuccess = false;
- if (typeof this.callback.loginResult === 'function') {
- this.callback.loginResult.call(this, this.isLoginSuccess);
- }
- }
- /**
- * @description 添加websocket/window监听事件
- */
- addEvents() {
- const webSocket = this.webSocket;
- webSocket.addEventListener('open', () => this.onOpen());
- webSocket.addEventListener('message', (e: any) => this.onMessage(e));
- webSocket.addEventListener('error', () => this.onError());
- window.addEventListener('resize', () => this.reLocatedPosition());
- window.addEventListener('scroll', () => this.reLocatedPosition());
- }
- /**
- * @description 移除websocket/window监听事件
- */
- removeEvents() {
- const webSocket = this.webSocket;
- webSocket.removeEventListener('open', this.onOpen);
- webSocket.removeEventListener('message', this.onMessage);
- webSocket.removeEventListener('error', this.onError);
- webSocket.removeEventListener('resize', this.reLocatedPosition);
- webSocket.removeEventListener('scroll', this.reLocatedPosition);
- }
- /**
- * @description 连接客户端成功事件
- */
- onOpen() {
- this.isConnectSuccessQt = true;
- this.connectEnd = true;
- if (typeof this.callback.connectResult === 'function') {
- this.callback.connectResult.call(this, this.isConnectSuccessQt);
- }
- }
- /**
- * @description 接收客户端消息
- * @params {Object} event 接收客户端的消息数据
- */
- onMessage(event: { data: string; }) {
- try {
- const data = JSON.parse(event.data);
- const { method } = data;
- const callback = this.listerns.get(method);
- if (method === 'loginState') {
- this.loginFailCount ++;
- if(this.loginFailCount < this.reLoginCount + 1) { // 登录未到最大次数
- if(data.params.loginResult === 0) { // 登录成功
- this.isLoginSuccess = data.params.loginResult === 0;
- if (typeof this.callback.loginResult === 'function') {
- this.callback.loginResult.call(this, this.isLoginSuccess);
- }
- } else { // 登录失败
- this.loginClient();
- }
- } else { // 登录达到最大次数
- this.loginEnd = true;
- this.isLoginSuccess = data.params.loginResult === 0;
- if (typeof this.callback.loginResult === 'function') {
- this.callback.loginResult.call(this, this.isLoginSuccess);
- }
- }
- }
- if (callback) {
- if (method === 'loginState') {
- callback(this.isLoginSuccess);
- } else if (method === 'createCtrlResult') {
- callback(data.params.array);
- } else {
- callback(data);
- }
- }
- } catch (e) {
- // console.error('error', e);
- }
- }
- /**
- * @description 客户端发生错误事件
- */
- onError() {
- this.isConnectSuccessQt = false;
- clearTimeout(this.heartbeatTimer);
- this.connectFailCount ++;
- if(this.connectFailCount === this.reConnectCount + 1) {
- this.connectEnd = true;
- if (typeof this.callback.connectResult === 'function') {
- this.callback.connectResult.call(this, this.isConnectSuccessQt);
- }
- }
- }
- /**
- * @description 判断是否成功连接客户端
- */
- isOpen() {
- if (!this.webSocket) return false;
- return this.webSocket.readyState === 1;
- }
- /**
- * @description 心跳事件
- */
- _heartbeat() {
- this.heartbeat();
- clearTimeout(this.heartbeatTimer);
- this.heartbeatTimer = setTimeout(() => {
- this._heartbeat();
- }, 10000);
- }
- /**
- * @description 获取当前浏览器缩放和滚动条信息
- */
- getScrollInfo() {
- let ratio = detectZoom();
- let scrollX = window.pageXOffset;
- let scrollY = window.pageYOffset;
- var hasscrollbary = hasScrollbarY();
- var hasscrollbarx = hasScrollbarX();
- var scrollbarWidth = getScrollbarWidth();
- let scrollXH = hasscrollbarx ? scrollbarWidth : 0;
- let scrollYW = hasscrollbary ? scrollbarWidth : 0;
- return { ratio, scrollX, scrollY, scrollXH, scrollYW };
- }
- }
- function promisify(func: Function) {
- return new Promise((resolve, reject) => {
- func('1', (data) => resolve(data))
- })
- }
- /**
- * @description 判断对象是否含有某属性
- * @params {Object} obj 对象
- * @params {String} key 属性key
- */
- function hasKey<O>(obj: O, key: keyof any): key is keyof O {
- return key in obj
- }
- /**
- * @description 与客户端通讯功能注册
- * @params {Array} plugins 功能列表
- */
- function usePlugin(plugins: any[]) {
- plugins.forEach((plugin) => {
- Object.getOwnPropertyNames(plugin).forEach(prop => {
- Ws.prototype[prop] = plugin[prop];
- });
- });
- }
- function detectZoom() {
- var ratio = 0,
- screen = window.screen,
- ua = navigator.userAgent.toLowerCase();
- if (window.devicePixelRatio !== undefined) {
- ratio = window.devicePixelRatio;
- } else if (~ua.indexOf('msie')) {
- if (screen['deviceXDPI'] && screen['logicalXDPI']) {
- ratio = screen['deviceXDPI'] / screen['logicalXDPI'];
- }
- } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
- ratio = window.outerWidth / window.innerWidth;
- }
- if (ratio) {
- ratio = Math.round(ratio * 100);
- }
- return ratio;
- }
- function hasScrollbarY() {
- return (
- document.body.scrollHeight >
- (window.innerHeight || document.documentElement.clientHeight)
- );
- }
- function hasScrollbarX() {
- return (
- document.body.scrollWidth >
- (window.innerWidth || document.documentElement.clientWidth)
- );
- }
- function getScrollbarWidth() {
- var scrollDiv = document.createElement('div');
- scrollDiv.style.cssText =
- 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
- document.body.appendChild(scrollDiv);
- var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
- document.body.removeChild(scrollDiv);
- return scrollbarWidth;
- }
|