awesome-im

1.0.7 • Public • Published

IM

Lightweight, extensible, JavaScript Instant Messaging.

功能

  1. 异常断开时,内部实现自动重连(下面几种方式即可无限重连)的情况:
    1. 服务端断网
    2. 服务端重启
    3. 客户端断网
  2. 不会自动重连的情况:
    1. 客户端主动断线(im.disconnect())
    2. 服务端主动断线(需要服务端发送一个断开连接的标识(前后端约定),在 MESSAG 监听到后,调用im.disconnect())
  3. 心跳机制。
  4. 监听客户端的连接状态
  5. 设置ping间隔
  6. 设置userId
  7. 区分会话类型(在发送消息时确定)
    1. server:0 server <-> user
    2. 单聊:1 user1 <-> user2
  8. 消息发送(默认时server会话类型)
    1. 文字消息
    2. 图片消息
    3. 文件消息
    4. ping消息(内置)
    5. 信令消息(在与服务交互时使用)
  9. 监听
    1. 消息监听
    2. 连接状态监听
  10. 信令消息的库扩展性(客户端和服务端可根据约定signalName实现业务层逻辑)
  11. 透传服务端发送的消息(content的消息透传)

注意事项

  1. 客户端主动发送消息,服务端收到消息并返回,从而形成一个闭环,才能证明客户端发送消息成功了。通过messageId才能形成闭环,也就是在客户端主动发消息情况下,服务端需返回客户端携带的messageId。客户端在send回调中拿到消息。
  2. 服务端主动给客户端发送消息不用携带messageId,客户端在消息监听中获取到消息。
  3. 需要在连接成功(监听 STATUS 为表示连接成功)后,才能发送消息、监听消息。

Usage

NPM、AMD and CommonJS module

参见集成客户端 demo(需注意:当前没有连接服务端)({your app path}/node_modules/awesome-im/src/example/client.html).

// 静态文件引入 awesome-im
// <script src="${path}awesome-im/dist/index.umd.js"></script>

// npm 安装、引入
// npm i awesome-im@latest
// import im from "awesome-im"


// websocket 地址
const url = "ws://localhost:8088";

// 初始化
im.init({
   pingGap: 6000,
   userId: "allenye" // 自定义用户ID
});

// 连接
im.connect(url).then(res => {
   console.log("connect ->", res)
})

// 监听连接状态
im.addEventListener("STATUS", evt => {
   console.log("连接状态->", evt)
})

// 监听消息
im.addEventListener("MESSAGE", evt => {
   console.log("监听消息->", evt)
})

// 发送信令消息
im.send(new im.Message.SignalMessage({
    signalName: "start", // 信令名称自定义,与服务端约定。
    // signalName: "end",
    to: "server"
})).then(res => {
    console.log("发送SignalMessage成功", res)
})

// 发送文字消息
im.send(new im.Message.TextMessage({
    // message: "message 可以扩展"
    message: {
        test: 123,
        array: [123, 456],
        object: {
            name: "allen"
        }
    },
    from: "allen",
    to: "server"
})).then(res => {
    console.log("发送TextMessage成功 ->", res)
})

// 修改会话类型(需要设置 conversationType),需要注意需要服务处理 user1、user2 之间的通信。
// 默认时server会话(im.Message.ConversationType.SERVER)
im.send(new im.Message.TextMessage({
    conversationType: im.Message.ConversationType.PRIVATE, // 单聊会话
    message: "发送一条单聊会话消息",
    from: "user1",
    to: "user2"
})).then(res => {
    console.log("发送TextMessage成功 ->", res)
})

服务端 demo

参见集成服务端nodejs demo ({your app path}/node_modules/awesome-im/src/example/server.js).

// nodejs
const WebSocket = require('ws');
const { encode, decode } = require("@msgpack/msgpack");

const server = new WebSocket.Server({ port: 8088 });

server.on('connection', (socket) => {
    console.log('Client connected');
    // setInterval(() => {
    //     server.clients.forEach((client) => {
    //         client.send(encode({
    //             code: ErrorCode.SUCCESS,
    //             data: {
    //                 messageType: MessageType.SIGNAL,
    //                 sentTime: new Date().getTime(),
    //                 messageUId: 'CBE5-1922-F8C9-730B',
    //                 conversationType: ConversationType.SERVER,
    //                 to: 'allen',
    //                 signalName: 'end',
    //                 from: 'server',
    //                 content: {
    //                     message: "一条服务端发送的消息"
    //                 },
    //             },
    //             errMsg: "success!"
    //         }));
    //     })
    // }, 2000);

    // 当接收到消息时,向所有连接的客户端广播消息
    socket.on('message', (message) => {
        // console.log(`Received message: ${message}`);
        const _data = decode(message)
        server.clients.forEach((client) => {
            if (client.readyState === WebSocket.OPEN) {
                const data = {
                    ..._data,
                    time: new Date().getTime()
                }
                console.log(data)
                client.send(encode({
                    code: ErrorCode.SUCCESS,
                    data: data
                }));
            }
        });
    });

    // 当连接关闭时,向所有连接的客户端广播消息
    socket.on('close', () => {
        console.log('Client disconnected');
        server.clients.forEach((client) => {
            if (client.readyState === WebSocket.OPEN) {
                client.send(encode({ errMsg: "close", code: 4 }));
            }
        });
    });
});

服务返回数据格式

服务端主动发送消息,不用携带 messageId。

{
    "code": 0,
    "data": {
        "messageType": "SignalMsg",
        "sentTime": 1681900543414,
        "messageUId": "CBE5-1922-F8C9-730B",
        "conversationType": 0,
        "to": "allen",
        "signalName": "login", // 可扩展
        "from": "server",
        "messageDirection": 2
    },
    "errMsg": "success!"
}

服务端收到客户端发送的消息后(服务端发送闭环消息),需要携带messageId

{
    "code": 0,
    "data": {
        "messageType": "TextMsg",
        "sentTime": 1681900543414,
        "messageId": "**需要携带客户端发送消息的messageId,从而达到闭环。**",
        "messageUId": "CBE5-1922-F8C9-730B",
        "conversationType": 0,
        "to": "allen",
        "signalName": "end", // 可扩展
        "from": "server",
        "content": {
            // 可以扩展
            "message": "客户端发送消息后,服务端需要返回一条消息(闭环)。证明客户端发送的消息成功了。"
        },
        "messageDirection": 2
    },
    "errMsg": "success!"
}

消息、会话相关枚举数据

// 消息类型
export const MessageType = {
    TEXT: "TxtMsg",
    IMAGE: "ImgMsg",
    FILE: "FileMsg",
    PING: "PingMsg",
    SIGNAL: "SignalMsg"
}

// 会话类型
export const ConversationType = {
    /**
     * 客户端与服务端的会话
     */
    SERVER: 0,
    /**
     * 单聊
     */
    PRIVATE: 1,
    /**
     * 讨论组
     */
    DISCUSSION: 2,
    /**
     * 群组聊天
     */
    GROUP: 3,
    /**
     * 聊天室会话
     */
    CHATROOM: 4,
    /**
     * 系统消息
     */
    SYSTEM: 5,
}
// 消息方向
export const MessageDirection = {
    /**
     * 发送消息。
     */
    SEND: 1,
    /**
     * 接收消息。
     */
    RECEIVE: 2
}

// 事件监听
const event = {
    STATUS: "STATUS",
    MESSAGE: "MESSAGE",
    TEST: "TEST",
}

Package Sidebar

Install

npm i awesome-im

Weekly Downloads

0

Version

1.0.7

License

ISC

Unpacked Size

291 kB

Total Files

17

Last publish

Collaborators

  • allenye