[+] 终端告警信令

This commit is contained in:
acgist
2023-02-27 08:15:23 +08:00
parent 71ada0a8ca
commit 4f6ae876d7
8 changed files with 203 additions and 143 deletions

View File

@@ -6,6 +6,7 @@
width="30%" width="30%"
title="终端设置" title="终端设置"
:show-close="false" :show-close="false"
v-if="taoyao === null"
v-model="signalVisible" v-model="signalVisible"
> >
<el-form ref="SignalSetting"> <el-form ref="SignalSetting">
@@ -81,7 +82,7 @@
<!-- 菜单 --> <!-- 菜单 -->
<div class="menus"> <div class="menus">
<el-button type="primary" @click="signalVisible = true">连接信令</el-button> <el-button type="primary" :disabled="taoyao !== null" @click="signalVisible = true">连接信令</el-button>
<el-button type="primary" @click="roomActive = 'enter'; roomVisible = true;">选择房间</el-button> <el-button type="primary" @click="roomActive = 'enter'; roomVisible = true;">选择房间</el-button>
<el-button type="primary" @click="roomActive = 'create';roomVisible = true;">创建房间</el-button> <el-button type="primary" @click="roomActive = 'create';roomVisible = true;">创建房间</el-button>
<el-button>邀请终端</el-button> <el-button>邀请终端</el-button>
@@ -107,8 +108,8 @@ export default {
data() { data() {
return { return {
room: {}, room: {},
rooms: [], rooms: null,
medias: [], medias: null,
config: { config: {
clientId: "taoyao", clientId: "taoyao",
host: "localhost", host: "localhost",
@@ -116,7 +117,7 @@ export default {
username: "taoyao", username: "taoyao",
password: "taoyao", password: "taoyao",
}, },
taoyao: {}, taoyao: null,
roomActive: "enter", roomActive: "enter",
roomVisible: false, roomVisible: false,
signalVisible: false, signalVisible: false,
@@ -131,11 +132,13 @@ export default {
}, },
methods: { methods: {
async connectSignal() { async connectSignal() {
let self = this; const me = this;
self.taoyao = new Taoyao({ ...this.config }); me.taoyao = new Taoyao({ ...this.config });
self.remoteClients = self.taoyao.remoteClients; await me.taoyao.connectSignal(me.callback, me.callbackMedia);
await self.taoyao.connectSignal(self.callback, self.callbackMedia); me.signalVisible = false;
self.signalVisible = false; me.remoteClients = me.taoyao.remoteClients;
// 全局绑定
window.taoyao = me.taoyao;
}, },
async loadList() { async loadList() {
this.rooms = await this.taoyao.roomList(); this.rooms = await this.taoyao.roomList();
@@ -208,8 +211,8 @@ export default {
<style> <style>
.menus{width:100%;top:1rem;left:0;text-align:center;position:fixed;z-index:1;} .menus{width:100%;top:1rem;left:0;text-align:center;position:fixed;z-index:1;}
.clients{width:100%;height:100%;top:0;left:0;position:fixed;} .clients{width:100%;height:100%;top:0;left:0;position:fixed;}
.client{float:left;width:50vw;height:50vh;border:1px solid #eee;} .client{float:left;width:50vw;height:50vh;box-shadow:0 0 1px 0px rgba(0,0,0,0.4);}
.client .buttons{width:100%;bottom:1rem;left:0;text-align:center;position:absolute;padding:0.8rem 0;background: rgba(0,0,0,0.6);text-align:center;} .client .buttons{width:100%;bottom:1rem;left:0;text-align:center;position:absolute;padding:0.8rem 0;background: rgba(0,0,0,0.4);text-align:center;}
.client audio{display:none;} .client audio{display:none;}
.client video{width:100%;height:100%;} .client video{width:100%;height:100%;}
</style> </style>

View File

@@ -12,14 +12,15 @@
<el-button title="拍照" :icon="Camera" circle /> <el-button title="拍照" :icon="Camera" circle />
<el-button title="录像" :icon="VideoCamera" circle /> <el-button title="录像" :icon="VideoCamera" circle />
<el-button title="媒体信息" :icon="InfoFilled" circle /> <el-button title="媒体信息" :icon="InfoFilled" circle />
<el-select placeholder="视频质量"> <el-popover placement="top" :width="200" trigger="hover">
<el-option <template #reference>
v-for="option in options" <el-button>视频质量</el-button>
:key="option.value" </template>
:label="option.label" <el-table :data="options">
:value="option.value" <el-table-column width="100" property="value" label="标识" />
/> <el-table-column width="100" property="label" label="名称" />
</el-select> </el-table>
</el-popover>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -1,7 +1,6 @@
/** /**
* 桃夭 * 桃夭
*/ */
import { TaoyaoClient } from "./TaoyaoClient.js";
import * as mediasoupClient from "mediasoup-client"; import * as mediasoupClient from "mediasoup-client";
import { import {
protocol, protocol,
@@ -30,9 +29,7 @@ const signalChannel = {
channel: null, channel: null,
// 地址 // 地址
address: null, address: null,
// 回调 // 请求回调
callback: null,
// 回调事件
callbackMapping: new Map(), callbackMapping: new Map(),
// 心跳时间 // 心跳时间
heartbeatTime: 30 * 1000, heartbeatTime: 30 * 1000,
@@ -156,15 +153,15 @@ const signalChannel = {
} }
// 前置回调 // 前置回调
if (!done) { if (!done) {
await self.preCallback(message); await self.taoyao.preCallback(message);
} }
// 全局回调 // 全局回调
if (!done && self.callback) { if (!done && self.callback) {
done = await self.callback(message); done = await self.taoyao.callback(message);
} }
// 后置回调 // 后置回调
if (!done) { if (!done) {
await self.postCallback(message); await self.taoyao.postCallback(message);
} }
}; };
}); });
@@ -257,103 +254,6 @@ const signalChannel = {
clearTimeout(self.heartbeatTimer); clearTimeout(self.heartbeatTimer);
clearTimeout(self.reconnectTimer); clearTimeout(self.reconnectTimer);
}, },
/**
* 前置回调
*
* @param {*} message
*/
async preCallback(message) {
const self = this;
switch (message.header.signal) {
case "client::config":
self.defaultClientConfig(message);
break;
case "client::register":
console.info("终端注册成功");
break;
case "media::consume":
await self.taoyao.consumeMedia(message);
break;
}
},
/**
* 后置回调
*
* @param {*} message 消息
*/
async postCallback(message) {
const self = this;
switch (message.header.signal) {
case "client::reboot":
self.defaultClientReboot(message);
break;
case "client::shutdown":
self.defaultClientShutdown(message);
break;
case "room::enter":
self.defaultRoomEnter(message);
break;
case "room::client::list":
self.defaultRoomClientList(message);
break;
case "platform::error":
self.callbackError(message);
break;
}
},
/**
* 配置默认回调
*
* @param {*} message 消息
*/
defaultClientConfig(message) {
const self = this;
self.taoyao.audio = { ...defaultAudioConfig, ...message.body.media.audio };
self.taoyao.video = { ...defaultVideoConfig, ...message.body.media.video };
self.taoyao.webrtc = message.body.webrtc;
console.debug(
"终端配置",
self.taoyao.audio,
self.taoyao.video,
self.taoyao.webrtc
);
},
/**
* 终端重启默认回调
*
* @param {*} message 消息
*/
defaultClientReboot(message) {
console.info("重启终端");
location.reload();
},
/**
* 终端重启默认回调
*
* @param {*} message 消息
*/
defaultClientShutdown(message) {
console.info("关闭终端");
window.close();
},
defaultRoomEnter(message) {
const { roomId, clientId } = message.body;
if(clientId === this.taoyao.clientId) {
// 忽略自己
} else {
this.taoyao.remoteClients.set(clientId, roomId);
}
},
defaultRoomClientList(message) {
const self = this;
message.body.forEach(v => {
if(v.clientId === self.taoyao.clientId) {
// 忽略自己
} else {
self.taoyao.remoteClients.set(v.clientId, self.taoyao.roomId);
}
});
},
}; };
/** /**
@@ -479,6 +379,103 @@ class Taoyao {
callback callback
); );
} }
/**
* 前置回调
*
* @param {*} message
*/
async preCallback(message) {
const self = this;
switch (message.header.signal) {
case "client::config":
self.defaultClientConfig(message);
break;
case "client::register":
console.info("终端注册成功");
break;
case "media::consume":
await self.consumeMedia(message);
break;
}
}
/**
* 后置回调
*
* @param {*} message 消息
*/
async postCallback(message) {
const self = this;
switch (message.header.signal) {
case "client::reboot":
self.defaultClientReboot(message);
break;
case "client::shutdown":
self.defaultClientShutdown(message);
break;
case "room::enter":
self.defaultRoomEnter(message);
break;
case "room::client::list":
self.defaultRoomClientList(message);
break;
case "platform::error":
self.callbackError(message);
break;
}
}
/**
* 配置默认回调
*
* @param {*} message 消息
*/
defaultClientConfig(message) {
const self = this;
self.audio = { ...defaultAudioConfig, ...message.body.media.audio };
self.video = { ...defaultVideoConfig, ...message.body.media.video };
self.webrtc = message.body.webrtc;
console.debug(
"终端配置",
self.audio,
self.video,
self.webrtc
);
}
/**
* 终端重启默认回调
*
* @param {*} message 消息
*/
defaultClientReboot(message) {
console.info("重启终端");
location.reload();
}
/**
* 终端重启默认回调
*
* @param {*} message 消息
*/
defaultClientShutdown(message) {
console.info("关闭终端");
window.close();
}
defaultRoomEnter(message) {
const { roomId, clientId } = message.body;
if (clientId === this.clientId) {
// 忽略自己
} else {
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);
}
});
}
/** /**
* 错误回调 * 错误回调
*/ */

View File

@@ -1,6 +0,0 @@
/**
* 桃夭终端
*/
class TaoyaoClient {}
export { TaoyaoClient };

View File

@@ -13,10 +13,3 @@
[信令格式](https://localhost:8888/protocol/list) [信令格式](https://localhost:8888/protocol/list)
## 测试脚本
```
let socket = new WebSocket("wss://localhost:8888/websocket.signal");
socket.send('{"header":{"signal":"client::register","v":"1.0.0","id":"1"},"body":{"username":"taoyao","password":"taoyao","clientId":"taoyao"}}');
socket.send('{"header":{"signal":"client::heartbeat","v":"1.0.0","id":"1"},"body":{}}');
```

View File

@@ -1,5 +1,39 @@
package com.acgist.taoyao.signal.flute.media; package com.acgist.taoyao.signal.flute.media;
import lombok.Getter;
import lombok.Setter;
/**
* 数据消费者
*
* @author acgist
*/
@Getter
@Setter
public class DataConsumer { public class DataConsumer {
/**
* 消费者终端
*/
private final ClientWrapper consumeClient;
/**
* 生产者
*/
private final Producer producer;
/**
* 数据流ID
*/
private final String streamId;
/**
* 消费者标识
*/
private final String consumerId;
public DataConsumer(ClientWrapper consumeClient, Producer producer, String streamId, String consumerId) {
this.consumeClient = consumeClient;
this.producer = producer;
this.streamId = streamId;
this.consumerId = consumerId;
}
} }

View File

@@ -1,9 +1,42 @@
package com.acgist.taoyao.signal.flute.media; package com.acgist.taoyao.signal.flute.media;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.Setter;
/**
* 数据生产者
*
* @author acgist
*/
@Setter
@Getter
public class DataProducer { public class DataProducer {
private Map<String, DataConsumer> dataConsumers; /**
* 生产者终端
*/
private final ClientWrapper produceClient;
/**
* 数据流ID
*/
private final String streamId;
/**
* 生产者标识
*/
private final String producerId;
/**
* 消费者
*/
private final Map<String, DataConsumer> dataConsumers;
public DataProducer(ClientWrapper produceClient, String streamId, String producerId) {
this.produceClient = produceClient;
this.streamId = streamId;
this.producerId = producerId;
this.dataConsumers = new ConcurrentHashMap<>();
}
} }

View File

@@ -39,16 +39,21 @@ public class ClientAlarmProtocol extends ProtocolClientAdapter {
@Override @Override
public void execute(String clientId, ClientType clientType, Client client, Message message, Map<String, Object> body) { public void execute(String clientId, ClientType clientType, Client client, Message message, Map<String, Object> body) {
final String alarmMessage = MapUtils.get(body, Constant.MESSAGE);
final String alarmDatetime = MapUtils.get(body, Constant.DATETIME);
log.warn( log.warn(
""" """
终端发生告警:{} 终端告警:{}
{} 终端类型:{}
{} 告警描述:{}
告警时间:{}
""", """,
clientId, clientId,
MapUtils.get(body, Constant.MESSAGE), clientType,
MapUtils.get(body, Constant.DATETIME) alarmMessage,
alarmDatetime
); );
// 业务逻辑
} }
} }