VAServerService.java
12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
package com.viontech.fanxing.task.service;
import com.alibaba.fastjson.JSONObject;
import com.viontech.fanxing.commons.base.LocalCache;
import com.viontech.fanxing.commons.config.VionConfig;
import com.viontech.fanxing.commons.constant.RedisKeys;
import com.viontech.fanxing.commons.exception.FanXingException;
import com.viontech.fanxing.commons.model.Task;
import com.viontech.fanxing.commons.model.main.VaServerInfo;
import com.viontech.fanxing.commons.service.RedisService;
import com.viontech.fanxing.task.model.TaskData;
import com.viontech.fanxing.task.model.vaserver.VaServerOverViewModel;
import com.viontech.fanxing.task.repository.VAServerRedisRepository;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 与 视频分析服务 交互的 service
*
* @author 谢明辉
* @date 2021/7/13
*/
@Service
@Slf4j
public class VAServerService {
protected final static Pattern IP_PATTERN = Pattern.compile("((?:1[0-9][0-9]\\.|2[0-4][0-9]\\.|25[0-5]\\.|[1-9][0-9]\\.|[0-9]\\.){3}(?:1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9]))");
@Resource
private RedisService redisService;
@Resource
private VAServerRedisRepository vaServerRedisRepository;
@Resource
private TaskDataService taskDataService;
@Resource
private VAServerHttpService vaServerHttpService;
@Resource
private VionConfig vionConfig;
/**
* 设备注册
*/
public void registerVAServer(VaServerInfo vaServerInfo) {
String devId = vaServerInfo.getDevID();
VaServerInfo vaServer = vaServerRedisRepository.getVAServerInfoById(devId);
Float availableResources = vaServer == null ? vaServerInfo.getVideoResource() : vaServer.getAvailableResources();
vaServerInfo.setAvailableResources(availableResources);
vaServerRedisRepository.addOrUpdate(devId, vaServerInfo);
keepalive(devId);
}
/**
* 设备心跳
*/
public void keepalive(String devId) {
VaServerInfo vaserverInfo = vaServerRedisRepository.getVAServerInfoById(devId);
if (vaserverInfo != null) {
vaserverInfo.setStatus(1);
vaServerRedisRepository.addOrUpdate(devId, vaserverInfo);
} else {
throw new FanXingException("设备未注册");
}
RBucket<Date> bucket = redisService.getValue(RedisKeys.getVAServerKeepAliveKey(devId));
bucket.set(new Date());
bucket.expire(2, TimeUnit.MINUTES);
}
/**
* 下发任务,关联任务和vaServer,修改vaServer可用资源数
*/
public boolean executeTask(TaskData taskData, VaServerInfo server) {
Task task = taskData.getTask();
// 执行任务下发,成功后关联任务和vaServer,减少vaServer的可用资源数量
vaServerHttpService.addTask(taskData, server);
RMap<String, String> map = redisService.getTaskVaServerMap();
map.put(task.getUnid(), server.getDevID());
modifyVAServerResource(server.getDevID(), -task.getResourceNeed());
return true;
}
/**
* 1. 解除任务和vaServer的关联
* 2. vaServer 资源数增加
* 3. 请求 vaServer 终止任务
* <p>
* 删除任务
*/
public boolean terminateTask(String taskUnid) {
TaskData taskData = taskDataService.getRepository().getTaskDataByUnid(taskUnid);
if (taskData == null) {
return true;
}
Task task = taskData.getTask();
RMap<String, String> map = redisService.getTaskVaServerMap();
String vaServerId = map.get(taskUnid);
// 如果vaServerId不为空,需要终止任务
if (vaServerId != null) {
VaServerInfo vaServerInfo = vaServerRedisRepository.getVAServerInfoById(vaServerId);
// 如果找不到对应的 vaServer , 相当于已经停止了任务
if (vaServerInfo == null) {
return true;
}
// 如果 vaServer 为离线, 那么无法停止
if (0 == vaServerInfo.getStatus()) {
return false;
}
// 下发终止任务请求
vaServerHttpService.rmTask(taskUnid, vaServerInfo);
// 解除任务和 vaServer 关联, 恢复资源数量
map.remove(taskUnid);
modifyVAServerResource(vaServerId, task.getResourceNeed());
return true;
}
return true;
}
public void modifyVAServerResource(String devId, float param) {
RLock vaServerLock = redisService.getLockMust("lock:vaserver:" + devId);
try {
VaServerInfo vaServerInfo = vaServerRedisRepository.getVAServerInfoById(devId);
if (vaServerInfo == null) {
return;
}
float v = vaServerInfo.getAvailableResources() + param;
if (v > vaServerInfo.getVideoResource()) {
v = vaServerInfo.getVideoResource();
}
vaServerInfo.setAvailableResources(v);
vaServerRedisRepository.addOrUpdate(devId, vaServerInfo);
} finally {
vaServerLock.forceUnlock();
}
}
/**
* 修改任务
*/
public boolean updateTask(TaskData taskData) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskData.getTask().getUnid());
vaServerHttpService.updateTask(taskData, vaServerInfo);
return true;
}
/**
* 截图
*/
public Object snapshot(String taskUnid) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.snapshot(taskUnid, vaServerInfo);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
/**
* 获取点播地址
*/
public Object getAnalyzeStream(String taskUnid) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.getAnalyzeStream(taskUnid, vaServerInfo);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
/**
* 输出分析流
*/
public String startAnalyzeStream(String taskUnid) {
TaskData taskData = taskDataService.getRepository().getTaskDataByUnid(taskUnid);
if (taskData == null) {
throw new FanXingException("找不到对应的任务");
}
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
String rtmpUrl = vionConfig.getSrs().getRtmpUrl(taskUnid);
String httpUrl = "/srs/live/" + taskUnid + ".flv";
vaServerHttpService.startAnalyzeStream(taskUnid, vaServerInfo, rtmpUrl);
return httpUrl;
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
/**
* 录像上传
*/
public Object uploadVideo() {
return null;
}
/**
* 获取 VAServer 运行状态配置参数等
*/
public JSONObject getStatus(String devId) {
VaServerInfo vaServerInfo = vaServerRedisRepository.getVAServerInfoById(devId);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.status(vaServerInfo);
} else {
throw new FanXingException("无法获取到对应的设备", devId);
}
}
/**
* 场景切换
*/
public Object switchScene(String taskUnid, String sceneId) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.switchScene(taskUnid, vaServerInfo, sceneId);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
/**
* 任务轮训状态切换
*/
public Object updateRotationStatus(String taskUnid, Integer rotationStatus) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
return vaServerHttpService.updateRotationStatus(taskUnid, rotationStatus, vaServerInfo);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
/**
* 任务轮训状态查询
*/
public Object getRotationStatus(String taskUnid) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.getRotationStatus(taskUnid, vaServerInfo);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
public JSONObject getCurrentScene(String taskUnid) {
VaServerInfo vaServerInfo = taskDataService.taskRunOn(taskUnid);
if (vaServerInfo != null) {
if (vaServerInfo.getStatus() == 0) {
throw new FanXingException("设备离线");
}
return vaServerHttpService.getCurrentScene(taskUnid, vaServerInfo);
} else {
throw new FanXingException("任务不在运行状态", taskUnid);
}
}
public Object getDefaultAlgorithmConfig(String taskAlgType) {
RMap<String, VaServerInfo> map = vaServerRedisRepository.getVaServerInfoMap();
for (VaServerInfo item : map.readAllValues()) {
if (item.getStatus() == 1) {
try {
return vaServerHttpService.getDefaultAlgorithmConfig(item, taskAlgType);
} catch (Exception e) {
log.error(item.getDevID() + "访问失败", e);
}
}
}
throw new FanXingException("无法获取到默认配置");
}
/**
* 获取所有vaServer信息
*/
@LocalCache(value = "vaServerOverview", duration = 10, timeunit = TimeUnit.SECONDS)
public Collection<VaServerOverViewModel> vaServerOverview() {
HashMap<String, VaServerOverViewModel> map = new HashMap<>();
Collection<VaServerInfo> vaServerInfos = vaServerRedisRepository.getVaServerInfoMap().readAllValues();
for (VaServerInfo vaServer : vaServerInfos) {
String serviceBaseUrl = vaServer.getServiceBaseUrl();
Matcher matcher = IP_PATTERN.matcher(serviceBaseUrl);
String ip = "无法获取";
if (matcher.find()) {
ip = matcher.group();
}
JSONObject status = new JSONObject();
try {
if (vaServer.getStatus() == 1) {
status = vaServerHttpService.status(vaServer);
status.remove("resource");
}
} catch (Exception e) {
log.error("", e);
}
status.put("devId", vaServer.getDevID());
status.put("serviceName", vaServer.getDockerContainerName());
status.put("status", vaServer.getStatus());
status.put("platType", vaServer.getPlatType());
status.put("softVersion", vaServer.getSoftVersion());
status.put("algoVersion", vaServer.getAlgoVersion());
status.put("availableResource", vaServer.getAvailableResources());
status.put("videoResource", vaServer.getVideoResource());
VaServerOverViewModel model = map.computeIfAbsent(ip, x -> new VaServerOverViewModel());
model.setIp(ip).addInfo(status);
model.addTotal(vaServer.getVideoResource()).addUsed(vaServer.getVideoResource() - vaServer.getAvailableResources());
}
return map.values();
}
public VAServerRedisRepository getVaServerRedisRepository() {
return vaServerRedisRepository;
}
}