ts websocket

import { ElMessage as Message } from "element-plus";
import pako from "pako";

export type Callback = (e: Event) => void;
export type MessageCallback<RT> = (e: RT) => void;

interface Ioptions<RT> {
  url: string | null; // 链接的通道的地址
  heartTime?: number; // 心跳时间间隔
  heartMsg?: string; // 心跳信息,默认为'ping'
  isReconnect?: boolean; // 是否自动重连
  isRestory?: boolean; // 是否销毁
  reconnectTime?: number; // 重连时间间隔
  reconnectCount?: number; // 重连次数 -1 则不限制
  openCb?: Callback; // 连接成功的回调
  closeCb?: Callback; // 关闭的回调
  messageCb?: MessageCallback<KWResponseResult<RT>>; // 消息的回调
  errorCb?: Callback; // 错误的回调,
}

/**
 * 心跳基类
 */

export class Heart {
  heartTimeOut!: number; // 心跳计时器
  ServerHeartTimeOut!: number; // 心跳计时器
  timeout = 5000;
  // 重置
  reset(): void {
    clearTimeout(this.heartTimeOut);
    clearTimeout(this.ServerHeartTimeOut);
  }

  /**
   * 启动心跳
   * @param {Function} cb 回调函数
   */
  start(cb: Callback): void {
    this.heartTimeOut = setTimeout((e: Event) => {
      cb(e);
      this.ServerHeartTimeOut = setTimeout((e: Event) => {
        cb(e);
        // 重新开始检测
        this.reset();
        this.start(cb);
      }, this.timeout);
    }, this.timeout);
  }
}

export default class Socket<T, RT> extends Heart {
  ws!: WebSocket;

  reconnectTimer = 0; // 重连计时器
  reconnectCount = 10; // 变量保存,防止丢失

  options: Ioptions<RT> = {
    url: null, // 链接的通道的地址
    heartTime: 5000, // 心跳时间间隔
    heartMsg: "ping", // 心跳信息,默认为'ping'
    isReconnect: true, // 是否自动重连
    isRestory: false, // 是否销毁
    reconnectTime: 5000, // 重连时间间隔
    reconnectCount: 5, // 重连次数 -1 则不限制
    openCb: (e: Event) => {
      console.log("连接成功的默认回调::::", e);
    }, // 连接成功的回调
    closeCb: (e: Event) => {
      console.log("关闭的默认回调::::", e);
    }, // 关闭的回调
    messageCb: (e: KWResponseResult<RT>) => {
      console.log("连接成功的默认回调::::", e);
    }, // 消息的回调
    errorCb: (e: Event) => {
      console.log("错误的默认回调::::", e);
    }, // 错误的回调
  };

  constructor(ops: Ioptions<RT>) {
    super();
    Object.assign(this.options, ops);
    this.create();
  }

  /**
   * 建立连接
   */
  create(): void {
    if (!("WebSocket" in window)) {
      throw new Error("当前浏览器不支持,无法使用");
    }
    if (!this.options.url) {
      throw new Error("地址不存在,无法建立通道");
    }
    // this.ws = null
    this.ws = new WebSocket(this.options.url);
    // console.log("this.options.url", this.options.url);
    this.onopen(this.options.openCb as Callback);
    this.onclose(this.options.closeCb as Callback);
    this.onmessage(
      this.options.messageCb as MessageCallback<KWResponseResult<RT>>
    );
  }

  /**
   * 自定义连接成功事件
   * 如果callback存在,调用callback,不存在调用OPTIONS中的回调
   * @param {Function} callback 回调函数
   */
  onopen(callback: Callback): void {
    this.ws.onopen = (event) => {
      clearTimeout(this.reconnectTimer); // 清除重连定时器
      this.options.reconnectCount = this.reconnectCount; // 计数器重置
      // // 建立心跳机制
      // super.reset()
      // super.start(() => {
      //   this.send(this.options.heartMsg as string)
      // })
      if (typeof callback === "function") {
        callback(event);
      } else {
        typeof this.options.openCb === "function" && this.options.openCb(event);
      }
    };
  }

  /**
   * 自定义关闭事件
   * 如果callback存在,调用callback,不存在调用OPTIONS中的回调
   * @param {Function} callback 回调函数
   */
  onclose(callback: Callback): void {
    this.ws.onclose = (event) => {
      super.reset();
      !this.options.isRestory && this.onreconnect();
      if (typeof callback === "function") {
        callback(event);
      } else {
        typeof this.options.closeCb === "function" &&
          this.options.closeCb(event);
      }
    };
  }

  /**
   * 自定义错误事件
   * 如果callback存在,调用callback,不存在调用OPTIONS中的回调
   * @param {Function} callback 回调函数
   */
  onerror(callback: Callback): void {
    this.ws.onerror = (event) => {
      if (typeof callback === "function") {
        callback(event);
      } else {
        typeof this.options.errorCb === "function" &&
          this.options.errorCb(event);
      }
    };
  }

  /**
   * 自定义消息监听事件
   * 如果callback存在,调用callback,不存在调用OPTIONS中的回调
   * @param {Function} callback 回调函数
   */
  onmessage(callback: MessageCallback<KWResponseResult<RT>>): void {
    this.ws.onmessage = (event: MessageEvent<any>) => {
      const resMessage = event.data;
      //处理 zip压缩数据 二进制格式
      if (resMessage instanceof Blob) {
        const utf8decoder = new TextDecoder("utf-8");
        resMessage.arrayBuffer().then((buffer) => {
          const byteArray = new Uint8Array(buffer);
          const arrayBuffer = pako.ungzip(byteArray);
          const text = utf8decoder.decode(arrayBuffer);

          const msgData: KWResponseResult<RT> = JSON.parse(text);
          if (typeof callback === "function") {
            callback(msgData);
          } else {
            typeof this.options.messageCb === "function" &&
              this.options.messageCb(msgData);
          }
        });
      } else {
        const msgData: KWResponseResult<RT> = JSON.parse(resMessage);
        if (typeof callback === "function") {
          callback(msgData);
        } else {
          typeof this.options.messageCb === "function" &&
            this.options.messageCb(msgData);
        }
      }
    };
  }

  /**
   * 自定义发送消息事件
   * @param {String} data 发送的文本
   */
  send(data: T | string): void {
    if (this.ws.readyState !== this.ws.OPEN) {
      throw new Error("没有连接到服务器,无法推送");
    }
    data = JSON.stringify(data);
    this.ws.send(data);
  }

  /**
   * 连接事件
   */
  onreconnect(): void {
    if (
      (this.options.reconnectCount as number) > 0 ||
      this.options.reconnectCount === -1
    ) {
      this.reconnectTimer = setTimeout(() => {
        this.create();
        if (this.options.reconnectCount !== -1)
          (this.options.reconnectCount as number)--;
      }, this.options.reconnectTime);
    } else {
      clearTimeout(this.reconnectTimer);
      this.options.reconnectCount = this.reconnectCount;
    }
  }

  /**
   * 销毁
   */
  destroy(): void {
    super.reset();
    clearTimeout(this.reconnectTimer); // 清除重连定时器
    this.options.isRestory = true;
    this.ws.close();
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值