[+] 优化房间创建、关闭、广播、终端列表逻辑

现在已经能够拉出视频
This commit is contained in:
acgist
2023-03-04 23:33:40 +08:00
parent 07678b3297
commit 0f23156df1
21 changed files with 317 additions and 140 deletions

View File

@@ -22,6 +22,8 @@ module.exports = {
name: "桃夭媒体服务",
// 地址
host: "127.0.0.1",
// host: "192.168.1.100",
// host: "192.168.8.100",
// 端口
port: 8888,
// 协议

View File

@@ -18,7 +18,7 @@ const taoyao = new Taoyao(mediasoupWorkers);
* 创建Mediasoup Worker列表
*/
async function buildMediasoupWorkers() {
// 可配置的事件
// 监听事件
// mediasoup.observer.on("newworker", fn(worker));
const { workerSize } = config.mediasoup;
console.info("创建Mediasoup Worker数量", workerSize);
@@ -29,16 +29,6 @@ async function buildMediasoupWorkers() {
rtcMinPort: Number(config.mediasoup.workerSettings.rtcMinPort),
rtcMaxPort: Number(config.mediasoup.workerSettings.rtcMaxPort),
});
worker.on("died", (error) => {
console.warn("Mediasoup Worker停止服务", worker.pid, error);
setTimeout(() => process.exit(1), 2000);
});
worker.observer.on("close", () => {
console.warn("Mediasoup Worker关闭服务", worker.pid);
});
// 可配置的事件
// worker.observer.on("newrouter", fn(router));
// worker.observer.on("newwebrtcserver", fn(router));
// 配置WebRTC服务
const webRtcServerOptions = JSON.parse(
JSON.stringify(config.mediasoup.webRtcServerOptions)
@@ -49,6 +39,16 @@ async function buildMediasoupWorkers() {
const webRtcServer = await worker.createWebRtcServer(webRtcServerOptions);
worker.appData.webRtcServer = webRtcServer;
mediasoupWorkers.push(worker);
// 监听事件
worker.on("died", (error) => {
console.warn("Mediasoup Worker停止服务", worker.pid, error);
setTimeout(() => process.exit(1), 2000);
});
worker.observer.on("close", () => {
console.warn("Mediasoup Worker关闭服务", worker.pid);
});
// worker.observer.on("newrouter", fn(router));
// worker.observer.on("newwebrtcserver", fn(router));
}
}

View File

@@ -159,7 +159,7 @@ const signalChannel = {
console.debug("信令通道消息:", content);
me.taoyao.on(JSON.parse(content));
} catch (error) {
console.error("处理信令消息异常:", data, error);
console.error("处理信令消息异常:", data.toString(), error);
}
});
});
@@ -322,15 +322,18 @@ class Room {
/**
* 关闭资源
*/
close() {
const self = this;
if (self.close) {
closeAll() {
const me = this;
if (me.close) {
return;
}
self.close = true;
if (self.mediasoupRouter) {
self.mediasoupRouter.close();
}
me.close = true;
// me.producers.forEach(v => v.close());
// me.consumers.forEach(v => v.close());
// me.dataProducers.forEach(v => v.close());
// me.dataConsumers.forEach(v => v.close());
me.transports.forEach(v => v.close());
me.mediasoupRouter.close();
}
}
@@ -404,6 +407,9 @@ class Taoyao {
case "room::create":
this.roomCreate(message, body);
break;
case "room::close":
this.roomClose(message, body);
break;
}
}
@@ -812,8 +818,9 @@ class Taoyao {
);
});
await transport.enableTraceEvent(["bwe"]);
// await transport.enableTraceEvent([ 'probation', 'bwe' ]);
transport.on("trace", (trace) => {
console.debug("transport trace event", trace, trace.type, transport.id);
console.debug("transport trace event", transport.id, trace.type, trace);
});
// 可配置的事件
// transport.on("routerclose", fn());
@@ -842,30 +849,42 @@ class Taoyao {
}
}
/**
* 关闭房间信令
*
* @param {*} message 消息
* @param {*} body 消息主体
*/
async roomClose(message, body) {
const roomId = body.roomId;
const room = this.rooms.get(roomId);
if(!room) {
console.warn("房间无效:", roomId);
return;
}
console.info("关闭房间:", roomId);
room.closeAll();
this.rooms.delete(roomId);
}
/**
* 创建房间信令
*
* @param {*} message 消息
* @param {*} body 消息主体
*
* @returns 房间
*/
async roomCreate(message, body) {
const me = this;
const roomId = body.roomId;
let room = this.rooms.get(roomId);
let room = me.rooms.get(roomId);
if (room) {
this.push(message);
return room;
console.debug("创建房间已经存在:", room);
me.push(message);
return;
}
const mediasoupWorker = this.nextMediasoupWorker();
const mediasoupWorker = me.nextMediasoupWorker();
const { mediaCodecs } = config.mediasoup.routerOptions;
const mediasoupRouter = await mediasoupWorker.createRouter({ mediaCodecs });
mediasoupRouter.observer.on("close", () => {
// TODO通知房间关闭
});
// 可配置的事件
// mediasoupRouter.on("workerclose", () => {});
// mediasoupRouter.observer.on("newtransport", fn(transport));
// TODO下面两个监控改为配置启用
const audioLevelObserver = await mediasoupRouter.createAudioLevelObserver({
maxEntries: 1,
@@ -883,10 +902,22 @@ class Taoyao {
audioLevelObserver,
activeSpeakerObserver,
});
this.rooms.set(roomId, room);
me.rooms.set(roomId, room);
console.info("创建房间", roomId);
this.push(message);
return room;
me.push(message);
// 监听事件
mediasoupRouter.observer.on("close", () => {
console.info("房间路由关闭:", roomId, mediasoupRouter);
room.closeAll();
me.rooms.delete(roomId);
me.push(
protocol.buildMessage("room::close", {
roomId: roomId
})
);
});
// mediasoupRouter.on("workerclose", () => {});
// mediasoupRouter.observer.on("newtransport", fn(transport));
}
}

View File

@@ -59,7 +59,7 @@
</el-tab-pane>
<el-tab-pane label="创建房间" name="create">
<el-form-item label="媒体服务">
<el-select v-model="room.mediaId" placeholder="媒体服务标识">
<el-select v-model="room.mediaClientId" placeholder="媒体服务标识">
<el-option
v-for="value in medias"
:key="value.clientId"
@@ -79,7 +79,7 @@
</el-form>
<template #footer>
<el-button type="primary" @click="enterRoom" v-if="roomActive === 'enter'">进入</el-button>
<el-button type="primary" @click="createRoom" v-if="roomActive === 'create'">创建</el-button>
<el-button type="primary" @click="roomCreate" v-if="roomActive === 'create'">创建</el-button>
</template>
</el-dialog>
@@ -90,7 +90,7 @@
<el-button type="primary" @click="roomActive = 'create';roomVisible = true;">创建房间</el-button>
<el-button>邀请终端</el-button>
<el-button>退出房间</el-button>
<el-button type="danger">关闭房间</el-button>
<el-button @click="closeRoom()" type="danger">关闭房间</el-button>
</div>
<!-- 终端 -->
@@ -149,14 +149,17 @@ export default {
this.medias = await this.taoyao.mediaList();
},
async enterRoom() {
await this.taoyao.enterRoom(this.room.roomId);
await this.taoyao.enterRoom(this.room.roomId, this.room.password);
await this.taoyao.produceMedia();
this.roomVisible = false;
},
async createRoom() {
const room = await this.taoyao.createRoom(this.room);
this.room = room;
await this.enterRoom(room.roomId);
async roomCreate() {
const room = await this.taoyao.roomCreate(this.room);
this.room.roomId = room.roomId;
await this.enterRoom();
},
async closeRoom() {
this.taoyao.closeRoom();
},
/**
* 信令回调

View File

@@ -394,6 +394,7 @@ class Taoyao {
}, 5000);
});
}
/************************ 回调 ************************/
/**
* 回调策略:
* 1. 如果注册请求回调同时执行结果返回true不再执行后面所有回调。
@@ -450,25 +451,32 @@ class Taoyao {
* @param {*} message 消息
*/
async postCallback(message) {
const self = this;
const me = this;
switch (message.header.signal) {
case "room::client::list":
me.defaultRoomClientList(message);
break;
case "client::reboot":
self.defaultClientReboot(message);
me.defaultClientReboot(message);
break;
case "client::shutdown":
self.defaultClientShutdown(message);
me.defaultClientShutdown(message);
break;
case "room::close":
me.defaultRoomClose(message);
break;
case "room::enter":
self.defaultRoomEnter(message);
break;
case "room::client::list":
self.defaultRoomClientList(message);
me.defaultRoomEnter(message);
break;
case "platform::error":
self.callbackError(message);
me.callbackError(message);
break;
default:
console.warn("不支持的信令:", message);
break;
}
}
/************************ 信令 ************************/
/**
* 配置默认回调
*
@@ -505,6 +513,53 @@ class Taoyao {
console.info("关闭终端");
window.close();
}
/**
* 房间终端列表信令
*
* @param {*} message 消息
*/
defaultRoomClientList(message) {
const me = this;
message.body.forEach(v => {
if (v.clientId === me.clientId) {
// 忽略自己
} else {
me.remoteClients.set(v.clientId, me.roomId);
}
});
}
/**
* 关闭房间信令
*
* @param {*} message 消息
*/
defaultRoomClose(message) {
const me = this;
const { roomId } = message.body;
if(me.roomId !== roomId) {
return;
}
console.info("关闭房间:", roomId);
me.close();
}
/**
* 创建房间信令
*
* @param {*} room 房间
*
* @returns 房间
*/
async roomCreate(room) {
const me = this;
if (!room) {
me.callbackError("无效房间");
return;
}
const response = await me.request(
protocol.buildMessage("room::create", room)
);
return response.body;
}
defaultRoomEnter(message) {
const { roomId, clientId } = message.body;
if (clientId === this.clientId) {
@@ -513,16 +568,6 @@ class Taoyao {
this.remoteClients.set(clientId, roomId);
}
}
defaultRoomClientList(message) {
const self = this;
message.body.forEach((v) => {
if (v.clientId === self.clientId) {
// 忽略自己
} else {
self.remoteClients.set(v.clientId, self.roomId);
}
});
}
/**
* 错误回调
*/
@@ -562,21 +607,7 @@ class Taoyao {
);
return response.body;
}
/**
* 创建房间
*/
async createRoom(room) {
const self = this;
if (!room) {
this.callbackError("无效房间");
return;
}
const response = await self.request(
protocol.buildMessage("room::create", room)
);
return response.body;
}
async enterRoom(roomId) {
async enterRoom(roomId, password) {
const self = this;
if (!roomId) {
this.callbackError("无效房间");
@@ -586,7 +617,7 @@ class Taoyao {
self.mediasoupDevice = new mediasoupClient.Device();
const response = await self.request(
protocol.buildMessage("media::router::rtp::capabilities", {
roomId: self.roomId,
roomId: self.roomId
})
);
const routerRtpCapabilities = response.body.rtpCapabilities;
@@ -594,6 +625,7 @@ class Taoyao {
await self.request(
protocol.buildMessage("room::enter", {
roomId: roomId,
password: password,
rtpCapabilities: self.consume
? self.mediasoupDevice.rtpCapabilities
: undefined,
@@ -604,6 +636,17 @@ class Taoyao {
})
);
}
async closeRoom() {
const me = this;
if(!me.roomId) {
console.warn("房间无效:", me.roomId);
return;
}
me.push(protocol.buildMessage("room::close", {
roomId: me.roomId
}));
}
/************************ 媒体 ************************/
/**
* 生产媒体
*/

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { fileURLToPath, URL } from "node:url";
import fs from "node:fs";
export default defineConfig({
plugins: [vue()],

View File

@@ -143,10 +143,6 @@ public interface Constant {
* 房间ID
*/
String ROOM_ID = "roomId";
/**
* 媒体服务ID
*/
String MEDIA_ID = "mediaId";
/**
* 媒体流ID
*/
@@ -179,6 +175,10 @@ public interface Constant {
* 数据消费者ID
*/
String DATA_CONSUMER_ID = "dataConsumerId";
/**
* 媒体服务ID
*/
String MEDIA_CLIENT_ID = "mediaClientId";
/**
* ICE服务
*/

View File

@@ -162,11 +162,11 @@ public class BootAutoConfiguration {
public void init() {
final Runtime runtime = Runtime.getRuntime();
final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
final String maxMemory = FileUtils.formatSize(runtime.maxMemory());
final String freeMemory = FileUtils.formatSize(runtime.freeMemory());
final String totalMemory = FileUtils.formatSize(runtime.totalMemory());
final String maxMemory = FileUtils.formatSize(runtime.maxMemory());
log.info("操作系统名称:{}", System.getProperty("os.name"));
log.info("操作系统架构:{}", System.getProperty("os.arch"));
log.info("操作系统名称:{}", System.getProperty("os.name"));
log.info("操作系统版本:{}", System.getProperty("os.version"));
log.info("可用的处理器数量:{}", runtime.availableProcessors());
log.info("Java版本{}", System.getProperty("java.version"));
@@ -175,9 +175,9 @@ public class BootAutoConfiguration {
log.info("ClassPath{}", System.getProperty("java.class.path"));
log.info("虚拟机名称:{}", System.getProperty("java.vm.name"));
log.info("虚拟机参数:{}", runtimeMXBean.getInputArguments().stream().collect(Collectors.joining(" ")));
log.info("虚拟机最大内存:{}", maxMemory);
log.info("虚拟机空闲内存:{}", freeMemory);
log.info("虚拟机已用内存:{}", totalMemory);
log.info("虚拟机最大内存:{}", maxMemory);
log.info("工作目录:{}", System.getProperty("user.dir"));
log.info("用户目录:{}", System.getProperty("user.home"));
log.info("临时目录:{}", System.getProperty("java.io.tmpdir"));

View File

@@ -1,5 +1,6 @@
package com.acgist.taoyao.boot.utils;
import java.math.BigDecimal;
import java.util.Map;
/**
@@ -61,8 +62,35 @@ public final class MapUtils {
return null;
} else if(object instanceof Long value) {
return value;
} else if(object instanceof Integer value) {
return value.longValue();
} else if(object instanceof Double value) {
return value.longValue();
}
return Long.valueOf(object.toString());
return new BigDecimal(object.toString()).longValue();
}
/**
* @param body 消息主体
* @param key 参数名称
*
* @return 参数值
*/
public static final Double getDouble(Map<?, ?> body, String key) {
if(body == null) {
return null;
}
final Object object = body.get(key);
if(object == null) {
return null;
} else if(object instanceof Long value) {
return value.doubleValue();
} else if(object instanceof Integer value) {
return value.doubleValue();
} else if(object instanceof Double value) {
return value;
}
return new BigDecimal(object.toString()).doubleValue();
}
/**
@@ -78,10 +106,14 @@ public final class MapUtils {
final Object object = body.get(key);
if(object == null) {
return null;
} else if(object instanceof Long value) {
return value.intValue();
} else if(object instanceof Integer value) {
return value;
} else if(object instanceof Double value) {
return value.intValue();
}
return Integer.valueOf(object.toString());
return new BigDecimal(object.toString()).intValue();
}
/**

View File

@@ -60,12 +60,12 @@ public class ClientStatus {
* @param body 消息主体
*/
public void copy(Map<String, Object> body) {
this.setLatitude(MapUtils.get(body, Constant.LATITUDE));
this.setLongitude(MapUtils.get(body, Constant.LONGITUDE));
this.setHumidity(MapUtils.get(body, Constant.HUMIDITY));
this.setTemperature(MapUtils.get(body, Constant.TEMPERATURE));
this.setSignal(MapUtils.get(body, Constant.SIGNAL));
this.setBattery(MapUtils.get(body, Constant.BATTERY));
this.setLatitude(MapUtils.getDouble(body, Constant.LATITUDE));
this.setLongitude(MapUtils.getDouble(body, Constant.LONGITUDE));
this.setHumidity(MapUtils.getDouble(body, Constant.HUMIDITY));
this.setTemperature(MapUtils.getDouble(body, Constant.TEMPERATURE));
this.setSignal(MapUtils.getInteger(body, Constant.SIGNAL));
this.setBattery(MapUtils.getInteger(body, Constant.BATTERY));
this.setAlarming(MapUtils.getBoolean(body, Constant.ALARMING));
this.setCharging(MapUtils.getBoolean(body, Constant.CHARGING));
this.setRecording(MapUtils.getBoolean(body, Constant.RECORDING));

View File

@@ -196,7 +196,7 @@ public class Room implements Closeable {
@Override
public void close() {
log.info("关闭房间:{}", this.roomId);
// TODO
// TODO:关闭房间
}
}

View File

@@ -40,7 +40,7 @@ public class MediaConsumeProtocol extends ProtocolRoomAdapter implements Applica
public static final String SIGNAL = "media::consume";
protected MediaConsumeProtocol() {
public MediaConsumeProtocol() {
super("消费媒体信令", SIGNAL);
}

View File

@@ -51,7 +51,7 @@ public class MediaTransportWebRtcCreateProtocol extends ProtocolRoomAdapter {
public static final String SIGNAL = "media::transport::webrtc::create";
protected MediaTransportWebRtcCreateProtocol() {
public MediaTransportWebRtcCreateProtocol() {
super("创建WebRTC通道信令", SIGNAL);
}

View File

@@ -32,7 +32,7 @@ import lombok.extern.slf4j.Slf4j;
}
"""
},
flow = "终端->服务->终端"
flow = "终端->信令服务->终端"
)
public class PlatformScriptProtocol extends ProtocolClientAdapter {

View File

@@ -62,7 +62,7 @@ public class PlatformShutdownProtocol extends ProtocolClientAdapter implements C
if(this.applicationContext instanceof ConfigurableApplicationContext context) {
// API关闭
if(context.isActive()) {
// 如果需要完整广播可以设置延时
// 如果需要广播完成可以设置延时
context.close();
} else {
// 其他情况

View File

@@ -19,16 +19,17 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
@Description(
body = """
{
"roomId": "房间ID",
...
}
""",
flow = "终端->信令服务->终端"
flow = "终端->信令服务-)终端"
)
public class RoomBroadcastProtocol extends ProtocolRoomAdapter {
public static final String SIGNAL = "room::broadcast";
protected RoomBroadcastProtocol() {
public RoomBroadcastProtocol() {
super("房间广播信令", SIGNAL);
}

View File

@@ -17,6 +17,36 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
*/
@Protocol
@Description(
body = {
"""
{
"roomId": "房间ID"
}
""",
"""
[
{
"ip": "终端IP",
"name": "终端名称",
"clientId": "终端ID",
"clientType": "终端类型",
"latitude": 纬度,
"longitude": 经度,
"humidity": 湿度,
"temperature": 温度,
"signal": 信号强度0~100,
"battery": 电池电量0~100,
"alarming": 是否发生告警true|false,
"charging": 是否正在充电true|false,
"recording": 是否正在录像true|false,
"lastHeartbeat": "最后心跳时间",
"status": {更多状态},
"config": {更多配置}
},
...
]
"""
},
flow = "终端=>信令服务->终端"
)
public class RoomClientListProtocol extends ProtocolRoomAdapter {

View File

@@ -4,6 +4,7 @@ import java.util.Map;
import com.acgist.taoyao.boot.annotation.Description;
import com.acgist.taoyao.boot.annotation.Protocol;
import com.acgist.taoyao.boot.config.Constant;
import com.acgist.taoyao.boot.model.Message;
import com.acgist.taoyao.signal.client.Client;
import com.acgist.taoyao.signal.client.ClientType;
@@ -17,6 +18,11 @@ import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
*/
@Protocol
@Description(
body = """
{
"roomId": "房间ID"
}
""",
flow = "终端->信令服务->媒体服务->信令服务+)终端"
)
public class RoomCloseProtocol extends ProtocolRoomAdapter {
@@ -29,9 +35,15 @@ public class RoomCloseProtocol extends ProtocolRoomAdapter {
@Override
public void execute(String clientId, ClientType clientType, Room room, Client client, Client mediaClient, Message message, Map<String, Object> body) {
room.close();
this.clientManager.broadcast(message);
// TODO释放房间
if(clientType == ClientType.WEB) {
mediaClient.push(this.build(Map.of(Constant.ROOM_ID, room.getRoomId())));
} else if(clientType == ClientType.MEDIA) {
room.close();
room.broadcast(message);
// TODO移除
} else {
this.logNoAdapter(clientType);
}
}
}

View File

@@ -16,25 +16,30 @@ import com.acgist.taoyao.signal.event.MediaClientRegisterEvent;
import com.acgist.taoyao.signal.party.media.Room;
import com.acgist.taoyao.signal.protocol.ProtocolClientAdapter;
import lombok.extern.slf4j.Slf4j;
/**
* 创建房间信令
*
* @author acgist
*/
@Slf4j
@Protocol
@Description(
body = """
{
"name": "房间名称",
"passowrd": "房间密码",
"mediaId": "媒体服务标识",
"clientSize": "终端数量"
}
""",
flow = "终端->服务端+)终端"
body = {
"""
{
"name": "房间名称",
"passowrd": "房间密码(选填)",
"mediaClientId": "媒体服务ID"
}
""",
"""
{
"name": "房间名称",
"clientSize": "终端数量",
"mediaClientId": "媒体服务ID"
}
"""
},
flow = "终端->信令服务->媒体服务->信令服务+)终端"
)
public class RoomCreateProtocol extends ProtocolClientAdapter implements ApplicationListener<MediaClientRegisterEvent> {
@@ -53,19 +58,13 @@ public class RoomCreateProtocol extends ProtocolClientAdapter implements Applica
@Override
public void execute(String clientId, ClientType clientType, Client client, Message message, Map<String, Object> body) {
if(clientType == ClientType.WEB) {
final String roomId = MapUtils.get(body, Constant.ROOM_ID);
if (roomId != null && this.roomManager.room(roomId) != null) {
log.info("房间已经存在:{}", roomId);
return;
}
// 创建房间
// WEB同步创建房间
final Room room = this.roomManager.create(
MapUtils.get(body, Constant.NAME),
MapUtils.get(body, Constant.PASSWORD),
MapUtils.get(body, Constant.MEDIA_ID),
MapUtils.get(body, Constant.MEDIA_CLIENT_ID),
message.cloneWithoutBody()
);
// 广播消息
message.setBody(room.getRoomStatus());
this.clientManager.broadcast(message);
} else {

View File

@@ -2,6 +2,8 @@ package com.acgist.taoyao.signal.protocol.room;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.acgist.taoyao.boot.annotation.Description;
import com.acgist.taoyao.boot.annotation.Protocol;
import com.acgist.taoyao.boot.config.Constant;
@@ -12,8 +14,8 @@ import com.acgist.taoyao.boot.utils.MapUtils;
import com.acgist.taoyao.signal.client.Client;
import com.acgist.taoyao.signal.client.ClientType;
import com.acgist.taoyao.signal.party.media.ClientWrapper;
import com.acgist.taoyao.signal.party.media.Room;
import com.acgist.taoyao.signal.party.media.ClientWrapper.SubscribeType;
import com.acgist.taoyao.signal.party.media.Room;
import com.acgist.taoyao.signal.protocol.ProtocolRoomAdapter;
import lombok.extern.slf4j.Slf4j;
@@ -39,7 +41,7 @@ import lombok.extern.slf4j.Slf4j;
}
"""
},
flow = "终端->服务-)终端"
flow = "终端->信令服务-)终端"
)
public class RoomEnterProtocol extends ProtocolRoomAdapter {
@@ -59,7 +61,7 @@ public class RoomEnterProtocol extends ProtocolRoomAdapter {
final Object rtpCapabilities = MapUtils.get(body, Constant.RTP_CAPABILITIES);
final Object sctpCapabilities = MapUtils.get(body, Constant.SCTP_CAPABILITIES);
final String roomPassowrd = room.getPassword();
if(roomPassowrd != null && !roomPassowrd.equals(password)) {
if(StringUtils.isNotEmpty(roomPassowrd) && !roomPassowrd.equals(password)) {
throw MessageCodeException.of(MessageCode.CODE_3401, "密码错误");
}
// 进入房间
@@ -74,7 +76,7 @@ public class RoomEnterProtocol extends ProtocolRoomAdapter {
));
room.broadcast(message);
log.info("进入房间:{} - {}", clientId, room.getRoomId());
// 推送房间用户信息
// 推送房间用户信息TODO event
final Message roomClientListMessage = this.roomClientListProtocol.build();
roomClientListMessage.setBody(room.clientStatus());
client.push(roomClientListMessage);

View File

@@ -24,7 +24,29 @@ import lombok.Setter;
* @author acgist
*/
@Protocol
@Description
@Description(
body = """
{
"diskspace": [
{
"path": "存储路径",
"free": 存储空闲,
"total": 存储总量
},
...
],
"maxMemory": 最大能用内存,
"freeMemory": 空闲内存,
"totalMemory": 已用内存,
"osArch": "系统架构",
"osName": "系统名称",
"osVersion": "系统版本",
"javaVmName": "虚拟机名称",
"javaVersion": "虚拟机版本",
"cpuProcessors": CPU核心数量
}
"""
)
public class SystemInfoProtocol extends ProtocolClientAdapter {
public static final String SIGNAL = "system::info";
@@ -38,10 +60,10 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
final Map<String, Object> info = new HashMap<>();
// 硬盘
final List<Diskspace> diskspace = new ArrayList<>();
// File.listRoots(); -> 不全
// FileSystems.getDefault().getFileStores(); -> 重复
// File.listRoots();
// FileSystems.getDefault().getFileStores();
Stream.of(File.listRoots()).forEach(v -> {
diskspace.add(new Diskspace(v.getPath(), v.getTotalSpace(), v.getFreeSpace()));
diskspace.add(new Diskspace(v.getPath(), v.getFreeSpace(), v.getTotalSpace()));
});
info.put("diskspace", diskspace);
// 内存
@@ -53,8 +75,8 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
info.put("freeMemoryGracefully", FileUtils.formatSize(runtime.freeMemory()));
info.put("totalMemoryGracefully", FileUtils.formatSize(runtime.totalMemory()));
// 其他
info.put("osName", System.getProperty("os.name"));
info.put("osArch", System.getProperty("os.arch"));
info.put("osName", System.getProperty("os.name"));
info.put("osVersion", System.getProperty("os.version"));
info.put("javaVmName", System.getProperty("java.vm.name"));
info.put("javaVersion", System.getProperty("java.version"));
@@ -71,10 +93,6 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
* 路径
*/
private final String path;
/**
* 总量
*/
private final Long total;
/**
* 空闲
*/
@@ -82,18 +100,22 @@ public class SystemInfoProtocol extends ProtocolClientAdapter {
/**
* 总量
*/
private final String totalGracefully;
private final Long total;
/**
* 空闲
*/
private final String freeGracefully;
/**
* 总量
*/
private final String totalGracefully;
public Diskspace(String path, Long total, Long free) {
public Diskspace(String path, Long free, Long total) {
this.path = path;
this.total = total;
this.free = free;
this.totalGracefully = FileUtils.formatSize(total);
this.total = total;
this.freeGracefully = FileUtils.formatSize(free);
this.totalGracefully = FileUtils.formatSize(total);
}
}