npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ailhc/enet

v1.2.7

Published

General front-end Socket network management module, with high scalability, development does not need to care about the implementation of the underlying socket, communication protocols, developers can customize the implementation of different underlying so

Downloads

73

Readme

@ailhc/enet

介绍

enet 是一个基于TypeScript的零依赖、跨平台、灵活、高可扩展的网络库

可以轻松集成到任意js/ts项目中

可以根据项目需要进行多层次定制(socket层,协议层,网络通信反馈层)

🧰有用工具和库

😆Demo

基于CocosCreator2.4.2的聊天室demo(含服务端实现):egf-net-ws

灵感来源

  1. pinus:一个基于Node.js的分布式水平扩展游戏服务器轻量级强大框架

  2. 宝爷的Cocos Creator 通用框架设计 —— 网络

特性

  1. 跨平台:适用于任意ts/js项目
  2. 灵活、高可扩展:可以根据项目需要进行多层次定制
  3. 零依赖
  4. 强类型:基于TypeScript
  5. 功能强大:提供完整的基本实现:握手、心跳、重连
  6. 可靠:完善的单元测试

如何使用?

安装

  1. 通过npm安装

     npm i @ailhc/enet   
  2. 本地link npm包

    a. clone 项目仓库

     git clone https://github.com/AILHC/EasyGameFrameworkOpen
        

    b. 在packages/enet文件夹下

     npm link

    c. 在项目游戏项目目录下

     npm link @ailhc/enet    
  3. 使用源码

    a. clone 项目仓库

     git clone https://github.com/AILHC/EasyGameFrameworkOpen

    b. 直接复制packages/enet/src下的ts源码到项目文件夹下使用(排除index.ts)

使用

  1. 基础使用(三步)
//三行代码初始化
import { NetNode } from "@ailhc/enet";
const net = new NetNode<string>();
net.init();

//一行代码连接服务器
net.connect("wss://echo.websocket.org/");

//两行代码发收个消息
net.onPush<string>("Msg", (dpkg) => { console.log(dpkg.data) });
net.notify<string>("Msg", msg);

//一步两步,就这么简单~ 如丝般
  1. 进阶使用(不改源码定制属于你的网络层)

    1. 定制网络通信的反馈和交互逻辑

       每个项目都有自己的网络通信的反馈和交互逻辑和定制需求,而且希望能够通用且能可控。
      //两步轻松定制
      //实现网络事件处理器接口enet.INetEventHandler 
      //这些方法大部分是可选的,按需求自定义
      
      export class ProtobufNetTest implements enet.INetEventHandler {
          init(){
              const netMgr = new NetNode<string>();
              //注入处理器
              netMgr.init({
                  netEventHandler: this
              })
          }
      
          onStartConnenct?(connectOpt: enet.IConnectOptions): void {
              console.log(`start connect:${connectOpt.url}`)
          }
                 
          onConnectEnd?(connectOpt: enet.IConnectOptions): void {
              console.log(`connect end:${connectOpt.url}`);
          }
          onError?(event: any, connectOpt: enet.IConnectOptions): void {
              console.error(`socket error`);
              console.error(event);
          }
          onClosed?(event: any, connectOpt: enet.IConnectOptions): void {
              console.error(`socket close`);
              console.error(event);
          }
          onStartReconnect(reConnectCfg: enet.IReconnectConfig, connectOpt: enet.IConnectOptions): void {
              console.log(`start reconnect:${connectOpt.url}`);
          }
          onReconnecting?(curCount: number, reConnectCfg: enet.IReconnectConfig, connectOpt: enet.IConnectOptions): void {
              console.log(`url:${connectOpt.url} reconnect count:${curCount},less count:${reConnectCfg.reconnectCount}`);
          }
          onReconnectEnd?(isOk: boolean, reConnectCfg: enet.IReconnectConfig, connectOpt: enet.IConnectOptions): void {
              console.log(`url:${connectOpt.url}reconnect end ${isOk ? "ok" : "fail"} `);
          }
          onStartRequest?(reqCfg: enet.IRequestConfig, connectOpt: enet.IConnectOptions): void {
              console.log(`start request:${reqCfg.protoKey},id:${reqCfg.reqId}`);
          }
          onData?(dpkg: enet.IDecodePackage<any>, connectOpt: enet.IConnectOptions): void {
              console.log(`data :${dpkg.key}`);
          }
          onRequestTimeout?(reqCfg: enet.IRequestConfig, connectOpt: enet.IConnectOptions): void {
              console.warn(`request timeout:${reqCfg.protoKey}`);
          }
          onCustomError?(dpkg: enet.IDecodePackage<any>, connectOpt: enet.IConnectOptions): void {
              console.error(`proto key:${dpkg.key},reqId:${dpkg.reqId},code:${dpkg.code},errorMsg:${dpkg.errorMsg}`);
          }
          onKick(dpkg: enet.IDecodePackage<any>, copt: enet.IConnectOptions) {
              console.log(`be kick`);
          }
      }
      
    2. 定制协议处理层

       可能很多都会用protobuf作为通信协议处理,但它只是编解码数据的一个库,一些特殊和业务向的通信则需要自己处理
      
       这个网络库提供这个协议处理扩展的能力
          //两步轻松定制
          //默认的协议处理是将数据序列化成字符串,然后发送出去
      
          //第一步实现协议处理接口,可以将字符串转成二进制数据
          import { Byte } from "./byte";
          //ByteProtoHandler.ts
          //#region 
          class ByteProtoHandler<ProtoKeyType> implements enet.IProtoHandler<ProtoKeyType> {
              private _heartbeatCfg: enet.IHeartBeatConfig;
              protected _byteUtil: Byte = new Byte();//这个二进制处理库可以在egf-pbws库里拿源码(这个是复制Laya的二进制处理库)
              public get heartbeatConfig(): enet.IHeartBeatConfig {
                  return this._heartbeatCfg;
              }
              encodePkg(pkg: enet.IPackage<any>, useCrypto?: boolean): enet.NetData {
                  const byteUtil = this._byteUtil;
                  byteUtil.clear();
                  byteUtil.endian = Byte.LITTLE_ENDIAN;
                  const str = JSON.stringify(pkg);
                  byteUtil.writeUTFString(str);
                  const buffer = byteUtil.buffer;
                  byteUtil.clear();
                  return buffer;
              }
              protoKey2Key(protoKey: ProtoKeyType): string {
                  return protoKey as any;
              }
              encodeMsg<T>(msg: enet.IMessage<T, ProtoKeyType>, useCrypto?: boolean): enet.NetData {
                  return this.encodePkg({ type: PackageType.DATA, data: msg } as enet.IPackage);
              }
              decodePkg(data: enet.NetData): enet.IDecodePackage<any> {
                  const byteUtil = this._byteUtil;
                  byteUtil.clear();
                  byteUtil.endian = Byte.LITTLE_ENDIAN;
                  byteUtil.writeArrayBuffer(data);
                  byteUtil.pos = 0;
                  const dataStr = byteUtil.readUTFString();
      
                  const parsedData: enet.IDecodePackage = JSON.parse(dataStr);
                  const pkgType = parsedData.type;
                  if (parsedData.type === PackageType.DATA) {
                      const msg: enet.IMessage = parsedData.data;
                      return {
                          key: msg && msg.key, type: pkgType,
                          data: msg.data, reqId: parsedData.data && parsedData.data.reqId
                      } as enet.IDecodePackage;
                  } else {
                      if (pkgType === PackageType.HANDSHAKE) {
                          this._heartbeatCfg = parsedData.data;
                      }
                      return {
                          type: pkgType,
                          data: parsedData.data
                      } as enet.IDecodePackage;
                  }
      
              }
      
          }
          //#endregion
          //第二步 注入协议处理器
          //...省略代码
          const netMgr = new NetNode<string>();
          const protoHandler = new ByteProtoHandler(); 
          netMgr.init({
              protoHandler: protoHandler
          })
          //...
    3. 定制socket层

       使用ts/js开发项目的,大部分是使用websocket进行socket网络通信,当然也有可能使用socket.io,现在越来越少了。
       也可能有的项目会自己基于tcp、udp进行socket通信
       同样这个socket层也是可以定制的
      //两步轻松定制
      //socket的定制实现可以参考enet/src/wsocket.ts
      //比如
      export class IOSocket implements enet.ISocket {
          //...省略
      }
      //
      //...省略
      //注入socket
      const netMgr = new NetNode<string>();
      const ioSocket = new IOSocket(); 
      netMgr.init({
          socket: ioSocket
      })
      //...
  2. 其他使用(重连、心跳)

    提供丰富的配置项进行配置

    /**
     * 重连配置接口
     */
    interface IReconnectConfig {
        /**
         * 重连次数
         * 默认:4
         */
        reconnectCount?: number;
        /**
         * 连接超时时间,单位毫秒
         * 默认: 120000 2分钟
         */
        connectTimeout?: number;
    }
    interface INodeConfig {
        /**
         * 底层socket实现
         */
        socket?: ISocket;
        /**
         * 网络事件处理器
         * 默认:使用log输出方式
         */
        netEventHandler?: INetEventHandler;
        /**
         * 协议编码,解码处理器
         * 默认: 使用字符串协议处理器
         */
        protoHandler?: IProtoHandler;
        /**
         * 重连配置,有默认值
         */
        reConnectCfg?: IReconnectConfig;
        /**心跳间隔阈值 ,默认100*/
        heartbeatGapThreashold?: number;
        /**使用加密 */
        useCrypto?: boolean;
    }

CHANGELOG