瀏覽代碼

动态带宽扩容

rindy 3 年之前
父節點
當前提交
8e407051a8
共有 4 個文件被更改,包括 1700 次插入73 次删除
  1. 1395 2
      package-lock.json
  2. 1 1
      package.json
  3. 128 70
      server/fashilong.js
  4. 176 0
      server/network.js

文件差異過大導致無法顯示
+ 1395 - 2
package-lock.json


+ 1 - 1
package.json

@@ -4,6 +4,7 @@
   "description": "",
   "main": "index.js",
   "dependencies": {
+    "@alicloud/ecs20140526": "^2.1.0",
     "accepts": "^1.3.7",
     "any-promise": "^1.3.0",
     "cache-content-type": "^1.0.1",
@@ -50,7 +51,6 @@
     "vary": "^1.1.2",
     "ylru": "^1.2.1"
   },
-  "devDependencies": {},
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },

+ 128 - 70
server/fashilong.js

@@ -1,39 +1,42 @@
-var server = require("http").createServer();
-const TLSSigAPIv2 = require('tls-sig-api-v2')
-const appids = require('./../config/appid')
+const network = require('./network')
+
+var server = require("http").createServer()
+const TLSSigAPIv2 = require("tls-sig-api-v2")
+const appids = require("./../config/appid")
 const api = new TLSSigAPIv2.Api(appids.fashilong.appid, appids.fashilong.key)
 const PORT = 3031
-const LEADER = 'leader'
+const LEADER = "leader"
+let userCount = 0
 
 function getSig(userId) {
     return api.genSig(userId, 86400)
 }
 
 const EVENT = {
-    someOneInRoom: 'someOneInRoom', // 有人进入房间
-    someOneLeaveRoom: 'someOneLeaveRoom', // 有人离开房间
-    startCall: 'startCall', // 开始通话
-    stopCall: 'stopCall', // 结束通话
-    webSyncAction: 'webSyncAction', // 通知h5的事件
-    clientSyncAction: 'clientSyncAction', // 通知非H5的事件
-    action: 'action', // 通知所有连接设备的事件
-    roomClose: 'roomClose', // 房间已结束/房主已离开
-    roomIn: 'roomIn', // 通知设备成功进入房间
-    changeVoiceStatus: 'changeVoiceStatus', // 通知某设备语音状态
-    changeOnlineStatus: 'changeOnlineStatus', // 通知某设备的在线状态
-    roomPersonChange: 'roomPersonChange', // 房间人数变化事件
-    changeRoomEnableTalk: 'changeRoomEnableTalk' // 改变房间是否可通话的配置
+    someOneInRoom: "someOneInRoom", // 有人进入房间
+    someOneLeaveRoom: "someOneLeaveRoom", // 有人离开房间
+    startCall: "startCall", // 开始通话
+    stopCall: "stopCall", // 结束通话
+    webSyncAction: "webSyncAction", // 通知h5的事件
+    clientSyncAction: "clientSyncAction", // 通知非H5的事件
+    action: "action", // 通知所有连接设备的事件
+    roomClose: "roomClose", // 房间已结束/房主已离开
+    roomIn: "roomIn", // 通知设备成功进入房间
+    changeVoiceStatus: "changeVoiceStatus", // 通知某设备语音状态
+    changeOnlineStatus: "changeOnlineStatus", // 通知某设备的在线状态
+    roomPersonChange: "roomPersonChange", // 房间人数变化事件
+    changeRoomEnableTalk: "changeRoomEnableTalk", // 改变房间是否可通话的配置
 }
 
 const CODEMAP = {
-    3001: '房间已被解散',
-    3002: '房主主动解散'
+    3001: "房间已被解散",
+    3002: "房主主动解散",
 }
 
 module.exports = class WebSocketServer {
     constructor() {
-        this._pageMap = new Map();
-        this._roomIDS = new Map();
+        this._pageMap = new Map()
+        this._roomIDS = new Map()
         this._roomPerson = new Map()
         this._roomsConfig = {}
     }
@@ -46,18 +49,20 @@ module.exports = class WebSocketServer {
             pingInterval: 10000,
             pingTimeout: 5000,
             cookie: false,
-        });
-        server.listen(PORT, { origins: "*" });
+        })
+        server.listen(PORT, { origins: "*" })
 
-        this.io.on("connection", (socket) => {
+        this.io.on("connection", socket => {
             let user = socket.handshake.query
             const { roomId, userId, sceneNum, isClient, role, userLimitNum, roomType } = user
             const webRoomId = `${roomId}_${sceneNum}_web`
             const clientRoom = `${userId}${roomId}`
-                // 加入客户端与H5单独的通讯房间 
-            socket.join(clientRoom, () => {})
-            socket.on(EVENT.clientSyncAction, (data) => {
-                console.log(data, 'clientSyncAction')
+            // 加入客户端与H5单独的通讯房间
+            socket.join(clientRoom, () => {
+                console.log(user, user.nickname && decodeURIComponent(user.nickname))
+            })
+            socket.on(EVENT.clientSyncAction, data => {
+                //console.log(data, 'clientSyncAction')
                 socket.broadcast.to(clientRoom).emit(EVENT.clientSyncAction, data)
             })
 
@@ -70,30 +75,32 @@ module.exports = class WebSocketServer {
                     }
                 })
                 this._roomPerson.set(roomId, _roomPerson)
-                socket.broadcast.to(roomId).emit(EVENT.changeVoiceStatus, { roomsPerson: sortRoomUser(_roomPerson) })
+                socket.broadcast
+                    .to(roomId)
+                    .emit(EVENT.changeVoiceStatus, { roomsPerson: sortRoomUser(_roomPerson) })
             })
 
             // 房主,保存房间配置
             if (isClient && role === LEADER && !this._roomsConfig[roomId]) {
-                console.log('in', user)
+                //console.log('in', user)
                 this._roomsConfig[roomId] = {
                     userLimitNum,
-                    enableTalk: user.enableTalk
+                    enableTalk: user.enableTalk,
                 }
             }
 
             // 1v1保存房主
-            if (roomType === '1v1' && !this._roomsConfig[roomId]) {
-                console.log(roomType, roomId, user)
+            if (roomType === "1v1" && !this._roomsConfig[roomId]) {
+                //console.log(roomType, roomId, user)
                 this._roomsConfig[roomId] = {
-                    leaderId: userId
+                    leaderId: userId,
                 }
             }
-            if (roomType === '1v1' && sortRoomUser(this._roomPerson.get(roomId)).length > 2) {
+            if (roomType === "1v1" && sortRoomUser(this._roomPerson.get(roomId)).length > 2) {
                 setTimeout(() => {
-                    socket.emit('roomInFail', {
-                        type: 'full',
-                        msg: '房间人数已满'
+                    socket.emit("roomInFail", {
+                        type: "full",
+                        msg: "房间人数已满",
                     })
                 }, 1000)
                 return this
@@ -101,13 +108,19 @@ module.exports = class WebSocketServer {
 
             socket.on(EVENT.changeRoomEnableTalk, data => {
                 this._roomsConfig[roomId].enableTalk = data
-                socket.broadcast.to(roomId).emit(EVENT.changeRoomEnableTalk, this._roomsConfig[roomId])
+                socket.broadcast
+                    .to(roomId)
+                    .emit(EVENT.changeRoomEnableTalk, this._roomsConfig[roomId])
             })
 
             // 若有房间人数限制
-            if (userLimitNum && this._roomPerson.get(roomId) && sortRoomUser(this._roomPerson.get(roomId)).length >= userLimitNum) {
+            if (
+                userLimitNum &&
+                this._roomPerson.get(roomId) &&
+                sortRoomUser(this._roomPerson.get(roomId)).length >= userLimitNum
+            ) {
                 setTimeout(() => {
-                    socket.emit('roomInFail', { type: 'full', msg: '房间人数已满' })
+                    socket.emit("roomInFail", { type: "full", msg: "房间人数已满" })
                 }, 1000)
                 return this
             }
@@ -115,9 +128,15 @@ module.exports = class WebSocketServer {
             if (this._roomsConfig[roomId]) {
                 is1v1 = this._roomsConfig[roomId].leaderId === userId
             }
-            console.log(this._roomsConfig[roomId], userId, !is1v1, user.role !== LEADER, (this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)))
-                // 非房主进来房间,判断房间是否存在,以及房间内是否有房主,若无则通知房间已关闭
-            if (!is1v1 && user.role !== LEADER && ((this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)) || (!this._roomPerson.get(roomId)))) {
+            //console.log(this._roomsConfig[roomId], userId, !is1v1, user.role !== LEADER, (this._roomPerson.get(roomId) && !this._roomPerson.get(roomId).find(item => item.role === LEADER)))
+            // 非房主进来房间,判断房间是否存在,以及房间内是否有房主,若无则通知房间已关闭
+            if (
+                !is1v1 &&
+                user.role !== LEADER &&
+                ((this._roomPerson.get(roomId) &&
+                    !this._roomPerson.get(roomId).find(item => item.role === LEADER)) ||
+                    !this._roomPerson.get(roomId))
+            ) {
                 setTimeout(() => {
                     socket.emit(EVENT.roomClose, { code: 3001, msg: CODEMAP[3001] })
                 }, 1000)
@@ -146,31 +165,58 @@ module.exports = class WebSocketServer {
                 } else {
                     // 通知客户端的房间配置
                     let roomsPerson = this._roomPerson.get(roomId) || []
-                    socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] })
+                    socket.emit(EVENT.roomIn, {
+                        user,
+                        roomsPerson: sortRoomUser(roomsPerson),
+                        roomsConfig: this._roomsConfig[roomId],
+                    })
                 }
+
+                userCount++
+                console.log("在线人数1:" + userCount)
+                network.autoUpdate(userCount)
             })
             let clientPerson = this._roomPerson.get(clientRoom) || []
             if (isClient) {
                 clientPerson.push(user)
                 this._roomPerson.set(clientRoom, clientPerson)
             }
-
+           
             if (!isClient) {
                 socket.join(webRoomId, () => {
-                    // let roomsPerson = this._roomPerson.get(roomId) || []
-                    // socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
+                    //let roomsPerson = this._roomPerson.get(roomId) || []
+                    //socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
 
+                    let roomPerson = this._roomPerson.get(roomId)
+                    let __roomPerson = updateRoomUser(roomPerson, user)
+                    let actionName = ""
+                    socket.broadcast
+                        .to(roomId)
+                        .emit(EVENT.roomPersonChange, {
+                            roomsPerson: sortRoomUser(__roomPerson),
+                            actionName,
+                            user,
+                        })
                 })
             }
             // 开始通话
             socket.on(EVENT.startCall, () => {
                 if (!isClient) {
                     let roomsPerson = this._roomPerson.get(roomId) || []
-                        // 返回h5房间内的信息
-                    socket.emit(EVENT.roomIn, { user, roomsPerson: sortRoomUser(roomsPerson), roomsConfig: this._roomsConfig[roomId] })
-                        // 判断是否某些情况断线重连
+                    // 返回h5房间内的信息
+                    socket.emit(EVENT.roomIn, {
+                        user,
+                        roomsPerson: sortRoomUser(roomsPerson),
+                        roomsConfig: this._roomsConfig[roomId],
+                    })
+                    // 判断是否某些情况断线重连
                     if (!user.isInRoom) {
-                        socket.broadcast.to(roomId).emit(EVENT.someOneInRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
+                        socket.broadcast
+                            .to(roomId)
+                            .emit(EVENT.someOneInRoom, {
+                                user,
+                                roomsPerson: sortRoomUser(roomsPerson),
+                            })
                     }
                     user.isInRoom = true
                     updateRoomUser(roomsPerson, user)
@@ -181,46 +227,59 @@ module.exports = class WebSocketServer {
                 user.onlineStatus = data.status
                 let roomPerson = this._roomPerson.get(roomId)
                 let __roomPerson = updateRoomUser(roomPerson, user)
-                let actionName = user.onlineStatus ? 'inRoom' : 'leaveRoom'
-                socket.broadcast.to(roomId).emit(EVENT.roomPersonChange, { roomsPerson: sortRoomUser(__roomPerson), actionName, user })
+                let actionName = user.onlineStatus ? "inRoom" : "leaveRoom"
+                socket.broadcast
+                    .to(roomId)
+                    .emit(EVENT.roomPersonChange, {
+                        roomsPerson: sortRoomUser(__roomPerson),
+                        actionName,
+                        user,
+                    })
             })
 
             socket.on(EVENT.stopCall, () => {
                 socket.leave(roomId)
-                console.log(role, user, 'stopCall')
+                //console.log(role, user, 'stopCall')
                 if (role === LEADER) {
-                    socket.broadcast.to(roomId).emit(EVENT.roomClose, { code: 3002, msg: CODEMAP[3002] })
+                    socket.broadcast
+                        .to(roomId)
+                        .emit(EVENT.roomClose, { code: 3002, msg: CODEMAP[3002] })
                     delete this._roomsConfig[roomId]
                 }
                 let roomsPerson = this._roomPerson.get(roomId) || []
                 roomsPerson = removeRoomUser(roomsPerson, user)
                 this._roomPerson.set(roomId, roomsPerson)
-                socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
+                socket.broadcast
+                    .to(roomId)
+                    .emit(EVENT.someOneLeaveRoom, { user, roomsPerson: sortRoomUser(roomsPerson) })
                 user.isInRoom = false
                 updateRoomUser(roomsPerson, user)
             })
 
-            socket.on(EVENT.webSyncAction, (data) => {
+            socket.on(EVENT.webSyncAction, data => {
                 socket.broadcast.to(webRoomId).emit(EVENT.webSyncAction, data)
             })
 
-            socket.on(EVENT.action, (data) => {
+            socket.on(EVENT.action, data => {
                 socket.broadcast.to(roomId).emit(EVENT.action, data)
             })
 
-            socket.on("disconnect", (reason) => {
+            socket.on("disconnect", reason => {
                 socket.leave(roomId)
                 if (!isClient) {
                     let roomsPerson = this._roomPerson.get(roomId) || []
                     roomsPerson = removeRoomUser(roomsPerson, user)
                     this._roomPerson.set(roomId, roomsPerson)
-                        // socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson })
+                    // socket.broadcast.to(roomId).emit(EVENT.someOneLeaveRoom, { user, roomsPerson })
                     socket.leave(webRoomId)
                     socket.leave(roomId)
                 }
+                userCount--
+                console.log("在线人数2:" + userCount)
+                network.autoUpdate(userCount)
             })
 
-            socket.on('reconnect', () => {
+            socket.on("reconnect", () => {
                 socket.join(roomId)
                 if (!isClient) {
                     let roomsPerson = this._roomPerson.get(roomId) || []
@@ -229,22 +288,21 @@ module.exports = class WebSocketServer {
                     socket.join(webRoomId)
                     socket.join(roomId)
                 }
+                console.log("重连")
             })
 
-            socket.on("error", function(reason) {
+            socket.on("error", function (reason) {
                 console.log("异常关闭", reason)
             })
-            return this;
 
+            return this
         })
-
     }
 
     close() {
-        this.server.disconnect(true);
+        this.server.disconnect(true)
     }
-
-};
+}
 
 function removeRoomUser(roomsPerson, user) {
     for (let i = 0; i < roomsPerson.length; i++) {
@@ -259,7 +317,7 @@ function removeRoomUser(roomsPerson, user) {
 function sortRoomUser(roomsPerson) {
     if (!roomsPerson) return []
     const res = new Map()
-    return roomsPerson.filter((a) => !res.has(a.userId) && res.set(a.userId, 1))
+    return roomsPerson.filter(a => !res.has(a.userId) && res.set(a.userId, 1))
 }
 
 function updateRoomUser(roomsPerson, user) {
@@ -270,4 +328,4 @@ function updateRoomUser(roomsPerson, user) {
         }
     })
     return roomsPerson
-}
+}

+ 176 - 0
server/network.js

@@ -0,0 +1,176 @@
+const Ecs20140526 = require('@alicloud/ecs20140526').default
+const $Ecs20140526 = require('@alicloud/ecs20140526')
+const OpenApi = require('@alicloud/openapi-client').default;
+const $OpenApi = require('@alicloud/openapi-client');
+const $tea = require('@alicloud/tea-typescript')
+
+const STATUS = {
+    /**
+     * 等待状态
+     */
+    pending: "pending",
+    /**
+     * 完成状态
+     */
+    fulfilled: "fulfilled"
+
+}
+
+function getLocalTimeToUTC() {
+    var date = new Date()
+    date.setMilliseconds(0)
+    date.setMinutes(date.getMinutes() + date.getTimezoneOffset() + 3)
+    return date
+}
+
+function dateFormat(fmt, date) {
+    let ret;
+    const opt = {
+        "Y+": date.getFullYear().toString(),        // 年
+        "m+": (date.getMonth() + 1).toString(),     // 月
+        "d+": date.getDate().toString(),            // 日
+        "H+": date.getHours().toString(),           // 时
+        "M+": date.getMinutes().toString(),         // 分
+        "S+": date.getSeconds().toString()          // 秒
+        // 有其他格式化字符需求可以继续添加,必须转化成字符串
+    };
+    for (let k in opt) {
+        ret = new RegExp("(" + k + ")").exec(fmt);
+        if (ret) {
+            fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
+        };
+    };
+    return fmt;
+}
+
+
+class Client {
+
+    /**
+     * 使用AK&SK初始化账号Client
+     * @param accessKeyId
+     * @param accessKeySecret
+     * @return Client
+     * @throws Exception
+     */
+    static createClient(accessKeyId, accessKeySecret) {
+        let config = new $OpenApi.Config({
+            // 您的AccessKey ID
+            accessKeyId: accessKeyId,
+            // 您的AccessKey Secret
+            accessKeySecret: accessKeySecret,
+        });
+        // 访问的域名
+        config.endpoint = "ecs-cn-hangzhou.aliyuncs.com";
+
+        return new Ecs20140526(config);
+    }
+
+    constructor() {
+        this.band = 0
+        this.status = STATUS.fulfilled;
+        this.client = Client.createClient("LTAIUrvuHqj8pvry", "JLOVl0k8Ke0aaM8nLMMiUAZ3EiiqI4")
+        // 看房服务器
+        this.instanceId = 'i-wz9g1c3fleilk1n9q5uu'
+        this.describeInstances()
+        setInterval(() => {
+            this.describeInstances()
+        }, 15000);
+    }
+
+    /**
+     * 查看实例详细信息
+     */
+    async describeInstances() {
+        //https://help.aliyun.com/document_detail/25506.html#h2-url-4
+        try {
+            let describeInstancesRequest = new $Ecs20140526.DescribeInstancesRequest({
+                regionId: "cn-shenzhen",
+                instanceIds: "[\"" + this.instanceId + "\"]",
+            });
+
+            let response = await this.client.describeInstances(describeInstancesRequest);
+
+            if (response.body.totalCount > 0) {
+                if (response.body.instances.instance[0]) {
+                    let band = response.body.instances.instance[0].internetMaxBandwidthOut
+                    if (band) {
+                        if (this.band) {
+                            if (this.band != band) {
+                                if (this.band < band) {
+                                    console.log("带宽已升级:" + band + "MB")
+                                } else if (this.band > band) {
+                                    console.log("带宽已变化:" + band + "MB")
+                                }
+                            } else {
+                                console.log('当前带宽:'+ band + "MB",'连接数:'+(this.conns || 0))
+                            }
+                            // 当带宽有变化时重置为初始状态
+                            this.status = STATUS.fulfilled
+                        }
+                        if(!this.band){
+                            console.log("带宽初始值:" + band + "MB")
+                        }
+                        this.band = band
+                    }
+                }
+            }
+        } catch (error) {
+            console.log("获取带宽出错:", error)
+        }
+    }
+
+    async modifyInstanceNetwork(band) {
+        //https://help.aliyun.com/document_detail/25545.htm?spm=a2c4g.11186623.0.0.1ec05d7aOys0wB#t9937.html
+        if (!band || band > 100 || this.band >= 100 || band<=this.band) {
+            return
+        }
+
+        console.log("开始升级带宽:"+band)
+
+        this.status = STATUS.pending
+
+        try {
+            var utc = getLocalTimeToUTC()
+            var startTime = dateFormat('YYYY-mm-ddTHH:MMZ', utc)
+            utc.setHours(utc.getHours() + 4)
+            var endTime = dateFormat('YYYY-mm-ddTHHZ', utc)
+            console.log(startTime, endTime)
+
+            let modifyInstanceNetworkSpecRequest = new $Ecs20140526.ModifyInstanceNetworkSpecRequest({
+                instanceId: this.instanceId,
+                internetMaxBandwidthOut: band,
+                startTime: startTime,
+                endTime: endTime,
+                autoPay: true,
+            });
+            let response = await this.client.modifyInstanceNetworkSpec(modifyInstanceNetworkSpecRequest);
+
+            console.log(response)
+        } catch (error) {
+
+            this.status = STATUS.fulfilled
+
+            console.log("升级带宽出错:", error)
+        }
+    }
+
+    async autoUpdate(conns) {
+        this.conns = conns
+        if (this.status == STATUS.pending) {
+            return
+        }
+
+        if (conns >= 300 && conns < 800) {
+            await this.modifyInstanceNetwork(50)
+        } else if (conns >= 800 && conns < 1500) {
+            await this.modifyInstanceNetwork(75)
+        } else if (conns > 1500) {
+            await this.modifyInstanceNetwork(100)
+        }
+    }
+}
+
+const client = new Client()
+
+module.exports = client