Quellcode durchsuchen

增加流媒体服务模块

xucaiqin vor 1 Jahr
Ursprung
Commit
5089089aed
21 geänderte Dateien mit 894 neuen und 0 gelöschten Zeilen
  1. 77 0
      iot-module/iot-module-stream/iot-module-stream-biz/pom.xml
  2. 18 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/StreamApplication.java
  3. 24 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/IndexController.java
  4. 26 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RecordController.java
  5. 36 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RtmpController.java
  6. 35 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RtspController.java
  7. 33 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/ApiInfo.java
  8. 16 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/PullPara.java
  9. 16 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/PushPara.java
  10. 14 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/StreamPage.java
  11. 16 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/properties/StreamMediaProperties.java
  12. 195 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/ApiProxy.java
  13. 27 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/StreamMediaService.java
  14. 67 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/impl/StreamMediaServiceImpl.java
  15. 18 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-local.yaml
  16. 16 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-stress.yaml
  17. 16 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-test.yaml
  18. 28 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap.yaml
  19. 189 0
      iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/logback-spring.xml
  20. 26 0
      iot-module/iot-module-stream/pom.xml
  21. 1 0
      iot-module/pom.xml

+ 77 - 0
iot-module/iot-module-stream/iot-module-stream-biz/pom.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.jot.joy</groupId>
+        <artifactId>iot-module-stream</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>iot-module-stream-biz</artifactId>
+    <packaging>jar</packaging>
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <!-- Spring Cloud 基础 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+        <!-- Registry 注册中心相关 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <!-- Config 配置中心相关 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-starter-pagehelper</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-starter-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.middle.platform</groupId>
+            <artifactId>iot-starter-redis</artifactId>
+        </dependency>
+
+
+    </dependencies>
+    <build>
+        <!-- 设置构建的 jar 包名 -->
+        <plugins>
+            <!-- 打包 -->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring.boot.version}</version> <!-- 如果 spring.boot.version 版本修改,则这里也要跟着修改 -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 18 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/StreamApplication.java

@@ -0,0 +1,18 @@
+package com.middle.platform.stream.biz;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-26 10:33:05
+ */
+@SpringBootApplication
+@EnableTransactionManagement
+public class StreamApplication {
+    public static void main(String[] args) {
+        // 启动 Spring Boot 应用
+        SpringApplication.run(StreamApplication.class, args);
+    }
+}

+ 24 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/IndexController.java

@@ -0,0 +1,24 @@
+package com.middle.platform.stream.biz.controller;
+
+import com.middle.platform.common.core.utils.DateTimeUtil;
+import com.middle.platform.common.core.utils.Result;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-15 08:46:49
+ */
+@RestController
+@RequestMapping("/index")
+public class IndexController {
+    @Value("${spring.application.name}")
+    private String name;
+
+    @GetMapping("")
+    public Result<Object> server() {
+        return Result.ok(name + ":" + DateTimeUtil.nowStr());
+    }
+}

+ 26 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RecordController.java

@@ -0,0 +1,26 @@
+package com.middle.platform.stream.biz.controller;
+
+import com.middle.platform.common.core.utils.Result;
+import com.middle.platform.stream.biz.pojo.StreamPage;
+import com.middle.platform.stream.biz.service.StreamMediaService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-15 08:46:49
+ */
+@RestController
+@RequestMapping("/record")
+public class RecordController {
+    @Resource
+    private StreamMediaService streamMediaService;
+
+    @PostMapping("/page")
+    public Result<Object> page(@RequestBody StreamPage streamPage) {
+        return Result.ok(streamMediaService.rtmpPage(streamPage));
+    }
+}

+ 36 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RtmpController.java

@@ -0,0 +1,36 @@
+package com.middle.platform.stream.biz.controller;
+
+import com.middle.platform.common.core.utils.Result;
+import com.middle.platform.stream.biz.pojo.PullPara;
+import com.middle.platform.stream.biz.pojo.PushPara;
+import com.middle.platform.stream.biz.pojo.StreamPage;
+import com.middle.platform.stream.biz.service.StreamMediaService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-15 08:46:49
+ */
+@RestController
+@RequestMapping("/rtmp")
+public class RtmpController {
+    @Resource
+    private StreamMediaService streamMediaService;
+
+    @PostMapping("/page")
+    public Result<Object> page(@RequestBody StreamPage streamPage) {
+        return Result.ok(streamMediaService.rtmpPage(streamPage));
+    }
+
+    @GetMapping("/pull")
+    public Result<Object> pull(PullPara pullPara) {
+        return Result.ok(streamMediaService.rtspPull(pullPara));
+    }
+
+    @GetMapping("/push")
+    public Result<Object> push(PushPara pushPara) {
+        return Result.ok(streamMediaService.rtspPush(pushPara));
+    }
+}
+

+ 35 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/controller/RtspController.java

@@ -0,0 +1,35 @@
+package com.middle.platform.stream.biz.controller;
+
+import com.middle.platform.common.core.utils.Result;
+import com.middle.platform.stream.biz.pojo.PullPara;
+import com.middle.platform.stream.biz.pojo.PushPara;
+import com.middle.platform.stream.biz.pojo.StreamPage;
+import com.middle.platform.stream.biz.service.StreamMediaService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author xucaiqin
+ * @date 2023-12-15 08:46:49
+ */
+@RestController
+@RequestMapping("/rtsp")
+public class RtspController {
+    @Resource
+    private StreamMediaService streamMediaService;
+
+    @PostMapping("/page")
+    public Result<Object> page(@RequestBody StreamPage streamPage) {
+        return Result.ok(streamMediaService.rtspPage(streamPage));
+    }
+
+    @GetMapping("/pull")
+    public Result<Object> pull(PullPara pullPara) {
+        return Result.ok(streamMediaService.rtspPull(pullPara));
+    }
+
+    @GetMapping("/push")
+    public Result<Object> push(PushPara pushPara) {
+        return Result.ok(streamMediaService.rtspPush(pushPara));
+    }
+}

+ 33 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/ApiInfo.java

@@ -0,0 +1,33 @@
+package com.middle.platform.stream.biz.pojo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-26 13:48:20
+ */
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+public enum ApiInfo {
+    RTMP_PULL("/rtmp/api/pull", "从远程拉取rtmp到m7s中"),
+    RTMP_PUSH("/rtmp/api/push", "将本地的流推送到远端"),
+    RTMP_LIST("/rtmp/api/list", "获取所有rtmp流"),
+    RTSP_PULL("/rtsp/api/pull", "拉取rtsp流"),
+    RTSP_PUSH("/rtsp/api/push", "推送rtsp流"),
+    RTSP_LIST("/rtsp/api/list", "rtsp流列表"),
+    RECORD_LIST("/record/api/list", "罗列所有录制的文件"),
+    RECORD_LIST_PAGE("/record/api/list/page", "分页查询所有录制的文件"),
+    RECORD_LIST_RECORDING("/record/api/list/recording", "罗列所有正在录制中的流的信息"),
+    RECORD_LIST_RECORDING_PAGE("/record/api/list/recording/page", "分页查询正在录制中的流的信息"),
+    RECORD_DELETE("/record/api/recordfile/delete", "删除某个录制文件"),
+    RECORD_MODIFY("/record/api/recordfile/modify", "修改某个录制文件"),
+    RECORD_START("/record/api/start", "开始录制某个流"),
+    RECORD_STOP("/record/api/stop", "停止录制某个流"),
+    RECORD_INDEX("/record/", "rtsp流列表"),
+    ;
+    private String url;
+    private String desc;
+}

+ 16 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/PullPara.java

@@ -0,0 +1,16 @@
+package com.middle.platform.stream.biz.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-28 14:33:43
+ */
+@Getter
+@Setter
+public class PullPara {
+    private String streamPath;
+    private String target;
+    private String save;
+}

+ 16 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/PushPara.java

@@ -0,0 +1,16 @@
+package com.middle.platform.stream.biz.pojo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-28 14:33:43
+ */
+@Getter
+@Setter
+public class PushPara {
+    private String streamPath;
+    private String target;
+    private String save;
+}

+ 14 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/pojo/StreamPage.java

@@ -0,0 +1,14 @@
+package com.middle.platform.stream.biz.pojo;
+
+import com.middle.platform.common.core.modle.BasePara;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-28 14:26:41
+ */
+@Getter
+@Setter
+public class StreamPage extends BasePara {
+}

+ 16 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/properties/StreamMediaProperties.java

@@ -0,0 +1,16 @@
+package com.middle.platform.stream.biz.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-26 11:20:10
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "stream.media")
+public class StreamMediaProperties {
+    private String url;
+}

+ 195 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/ApiProxy.java

@@ -0,0 +1,195 @@
+package com.middle.platform.stream.biz.service;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.middle.platform.common.core.utils.OkHttpUtils;
+import com.middle.platform.stream.biz.pojo.ApiInfo;
+import com.middle.platform.stream.biz.properties.StreamMediaProperties;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 接口代理实现
+ *
+ * @author xucaiqin
+ * @date 2024-04-26 13:47:08
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class ApiProxy {
+    private final StreamMediaProperties streamMediaProperties;
+
+    private String encode(String url) {
+        return URLEncoder.encode(url, StandardCharsets.UTF_8);
+    }
+
+    private String getHttp(ApiInfo apiInfo, Map<String, Object> para) {
+        log.debug("{}入参->{}", apiInfo.getDesc(), JSONObject.toJSONString(para));
+        OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(streamMediaProperties.getUrl() + apiInfo.getUrl());
+        if (CollUtil.isNotEmpty(para)) {
+            for (Map.Entry<String, Object> p : para.entrySet()) {
+                //跳过非空参数
+                Object v = p.getValue();
+                String k = p.getKey();
+                if (Objects.isNull(v)) {
+                    continue;
+                }
+                if (v instanceof Integer i) {
+                    okHttpUtils.addPara(k, String.valueOf(i));
+                } else if (v instanceof Long i) {
+                    okHttpUtils.addPara(k, String.valueOf(i));
+                } else if (v instanceof String i) {
+                    okHttpUtils.addPara(k, i);
+                } else if ((v.getClass().isArray()) && v instanceof String[] l) {
+                    for (int i = 0; i < l.length; i++) {
+                        okHttpUtils.addPara(k + "[" + i + "]", l[i]);
+                    }
+                } else {
+                    okHttpUtils.addPara(k, v.toString());
+                }
+            }
+        }
+        String sync;
+        try {
+            sync = okHttpUtils.get().sync();
+        } catch (Exception e) {
+            log.error("接口服务异常", e.getCause());
+            throw new RuntimeException("接口服务异常!");
+        }
+        log.debug("{}:返回值->{}", apiInfo.getDesc(), sync);
+        return sync;
+    }
+//    private String postHttp(PayCenterEnum payCenterEnum, Map<String, Object> para) {
+//        log.info("{}入参->{}", payCenterEnum.getDesc(), JSONObject.toJSONString(para));
+//        OkHttpUtils okHttpUtils = OkHttpUtils.builder().url(payCenterAddr + payCenterEnum.getAddr());
+//        if (!CollectionUtils.isEmpty(para)) {
+//            for (Map.Entry<String, Object> p : para.entrySet()) {
+//                //跳过非空参数
+//                Object v = p.getValue();
+//                String k = p.getKey();
+//                if (Objects.isNull(v)) {
+//                    continue;
+//                }
+//                if (v instanceof ChannelEnum channelEnum) {
+//                    okHttpUtils.addBodyPara(k, channelEnum.getChannel());
+//                } else if (v instanceof Integer i) {
+//                    okHttpUtils.addBodyPara(k, String.valueOf(i));
+//                } else if (v instanceof Long i) {
+//                    okHttpUtils.addBodyPara(k, String.valueOf(i));
+//                } else if (v instanceof String i) {
+//                    okHttpUtils.addBodyPara(k, i);
+//                } else if ((v.getClass().isArray()) && v instanceof String[] l) {
+//                    for (int i = 0; i < l.length; i++) {
+//                        okHttpUtils.addPara(k + "[" + i + "]", l[i]);
+//                    }
+//                } else {
+//                    okHttpUtils.addBodyPara(k, JSONObject.toJSONString(v));
+//                }
+//            }
+//        }
+//        String sync;
+//        try {
+//            sync = okHttpUtils.post(true).sync();
+//        } catch (Exception e) {
+//            log.error("中台服务异常", e.getCause());
+//            throw new RuntimeException("支付服务异常!");
+//        }
+//        log.info("{}返回值->{}", payCenterEnum.getDesc(), sync);
+//        return changeRes(sync);
+//    }
+
+    /**
+     * 获取所有rtmp列表
+     *
+     * @return
+     */
+    public Object rtmpList() {
+        String sync = getHttp(ApiInfo.RTMP_LIST, new HashMap<>());
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    /**
+     * 推送rtmp流
+     *
+     * @param streamPath 流标识
+     * @param target     RTMP地址
+     * @return
+     */
+    public Object rtmpPush(String streamPath, String target) {
+        String sync = getHttp(ApiInfo.RTMP_PUSH, new HashMap<>() {{
+            put("streamPath", streamPath);
+            put("target", encode(target));
+        }});
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    public Object rtmpPull(String streamPath, String target, String save) {
+        String sync = getHttp(ApiInfo.RTMP_PULL, new HashMap<>() {{
+            put("streamPath", streamPath);
+            put("target", encode(target));
+            put("save", save);
+        }});
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    /**
+     * 获取所有rtsp列表
+     *
+     * @return
+     */
+    public Object rtspList() {
+        String sync = getHttp(ApiInfo.RTSP_LIST, new HashMap<>());
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    /**
+     * 推送rtsp流
+     *
+     * @param streamPath 流标识
+     * @param target     RTSP地址
+     * @return
+     */
+    public Object rtspPush(String streamPath, String target) {
+        String sync = getHttp(ApiInfo.RTSP_PUSH, new HashMap<>() {{
+            put("streamPath", streamPath);
+            put("target", encode(target));
+        }});
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    public Object rtspPull(String streamPath, String target, String save) {
+        String sync = getHttp(ApiInfo.RTSP_PULL, new HashMap<>() {{
+            put("streamPath", streamPath);
+            put("target", encode(target));
+            put("save", save);
+        }});
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+    public Object recordListPage(String type, String pageSize, String pageNum, String streamPath) {
+        String sync = getHttp(ApiInfo.RECORD_LIST_PAGE, new HashMap<>() {{
+            put("type", type);
+            put("pageSize", pageSize);
+            put("pageNum", pageNum);
+            put("streamPath", streamPath);
+        }});
+        return JSONObject.parseObject(sync, new TypeReference<>() {
+        });
+    }
+
+}

+ 27 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/StreamMediaService.java

@@ -0,0 +1,27 @@
+package com.middle.platform.stream.biz.service;
+
+import com.middle.platform.stream.biz.pojo.PullPara;
+import com.middle.platform.stream.biz.pojo.PushPara;
+import com.middle.platform.stream.biz.pojo.StreamPage;
+
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-26 11:21:39
+ */
+public interface StreamMediaService {
+    List<Object> rtspPage(StreamPage streamPage);
+
+    List<Object> rtspPull(PullPara pullPara);
+
+
+    List<Object> rtspPush(PushPara pushPara);
+
+
+
+    List<Object> rtmpPage(StreamPage streamPage);
+
+    List<Object> rtmpPull(PullPara pullPara);
+
+}

+ 67 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/java/com/middle/platform/stream/biz/service/impl/StreamMediaServiceImpl.java

@@ -0,0 +1,67 @@
+package com.middle.platform.stream.biz.service.impl;
+
+import com.middle.platform.stream.biz.pojo.PullPara;
+import com.middle.platform.stream.biz.pojo.PushPara;
+import com.middle.platform.stream.biz.pojo.StreamPage;
+import com.middle.platform.stream.biz.service.ApiProxy;
+import com.middle.platform.stream.biz.service.StreamMediaService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author xucaiqin
+ * @date 2024-04-26 11:21:53
+ */
+@Service
+@RequiredArgsConstructor
+public class StreamMediaServiceImpl implements StreamMediaService {
+    private final ApiProxy apiProxy;
+
+    @Override
+    public List<Object> rtmpPage(StreamPage streamPage) {
+        //todo yewuku
+        //fenye
+        ArrayList<Object> objects = new ArrayList<>();
+
+        Object o = apiProxy.rtmpList();
+
+
+        return new ArrayList<>() {{
+            add(o);
+        }};
+    }
+
+    @Override
+    public List<Object> rtmpPull(PullPara pullPara) {
+        //todo 业务功能增加
+        Object o = apiProxy.rtmpPull(pullPara.getStreamPath(), pullPara.getTarget(), pullPara.getSave());
+
+        return null;
+    }
+
+    @Override
+    public List<Object> rtspPage(StreamPage streamPage) {
+        //todo 查询业务表-拼接数据
+        Object o = apiProxy.rtspList();
+
+        return null;
+    }
+
+    @Override
+    public List<Object> rtspPull(PullPara pullPara) {
+        //todo 业务功能增加
+        Object o = apiProxy.rtspPull(pullPara.getStreamPath(), pullPara.getTarget(), pullPara.getSave());
+
+        return null;
+    }
+
+    @Override
+    public List<Object> rtspPush(PushPara pushPara) {
+        return null;
+    }
+
+
+}

+ 18 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-local.yaml

@@ -0,0 +1,18 @@
+spring:
+  cloud:
+    nacos:
+      server-addr: 127.0.0.1:8848
+      discovery:
+        namespace: 78524032-ad7a-4724-8f8b-eef5ac08c5b5
+      config:
+        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
+        namespace: 78524032-ad7a-4724-8f8b-eef5ac08c5b5
+        group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
+        name: ${spring.application.name} # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
+        file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties
+        username: nacos
+        password: nacos
+        shared-configs:
+          - data-id: common.yaml
+            group: common
+            refresh: true

+ 16 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-stress.yaml

@@ -0,0 +1,16 @@
+spring:
+  cloud:
+    nacos:
+      server-addr: 10.10.10.120:8848
+      discovery:
+        namespace: iot
+      config:
+        server-addr: 10.10.10.120:8848 # Nacos 服务器地址
+        namespace: iot
+        group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
+        name: ${spring.application.name} # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
+        file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties
+        shared-configs:
+          - data-id: common.yaml
+            group: common
+            refresh: true

+ 16 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap-test.yaml

@@ -0,0 +1,16 @@
+spring:
+  cloud:
+    nacos:
+      server-addr: 10.10.10.224:8848
+      discovery:
+        namespace: iot
+      config:
+        server-addr: 10.10.10.224:8848 # Nacos 服务器地址
+        namespace: iot
+        group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
+        name: ${spring.application.name} # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
+        file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties
+        shared-configs:
+          - data-id: common.yaml
+            group: common
+            refresh: true

+ 28 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/bootstrap.yaml

@@ -0,0 +1,28 @@
+server:
+  port: 9005
+spring:
+  application:
+    name: iot-stream
+  profiles:
+    active: local
+  # Servlet 配置
+  servlet:
+    # 文件上传相关配置项
+    multipart:
+      max-file-size: 16MB # 单个文件大小
+      max-request-size: 32MB # 设置总上传的文件大小
+  # Jackson 配置项
+  jackson:
+    serialization:
+      write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
+      write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
+      write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
+      fail-on-empty-beans: false # 允许序列化无属性的 Bean
+  main:
+    allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
+
+logging:
+  level:
+    root: info
+    com.middle.platform: debug
+

+ 189 - 0
iot-module/iot-module-stream/iot-module-stream-biz/src/main/resources/logback-spring.xml

@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
+<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
+<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
+                         当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
+<configuration scan="true" scanPeriod="10 seconds">
+    <!--关闭logback自身的debug日志打印-->
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+    <contextName>logback</contextName>
+    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
+
+    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
+    <property name="log.path" value="logs"/>
+    <property name="LOG_HOME" value="iot-stream"/>
+<!--    <springProperty scope="context" name="LOG_HOME" source="spring.application.name" defaultValue="iot-manage"/>-->
+    <!--0. 日志格式和颜色渲染 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+
+    <!--1. 输出到控制台-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>debug</level>
+        </filter>
+        <encoder>
+            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
+            <!-- 设置字符集 -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--2. 输出到文档-->
+    <!-- 2.1 level为 DEBUG 日志,时间滚动输出  -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${log.path}/${LOG_HOME}/debug.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${log.path}/${LOG_HOME}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.2 level为 INFO 日志,时间滚动输出  -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${log.path}/${LOG_HOME}/info.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 每天日志归档路径以及格式 -->
+            <fileNamePattern>${log.path}/${LOG_HOME}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录info级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.3 level为 WARN 日志,时间滚动输出  -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${log.path}/${LOG_HOME}/warn.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/${LOG_HOME}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录warn级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 2.4 level为 ERROR 日志,时间滚动输出  -->
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文档的路径及文档名 -->
+        <file>${log.path}/${LOG_HOME}/error.log</file>
+        <!--日志文档输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/${LOG_HOME}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文档保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文档只记录ERROR级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+
+    <!-- 4. 最终的策略 -->
+    <root level="info">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="DEBUG_FILE"/>
+        <appender-ref ref="INFO_FILE"/>
+        <appender-ref ref="WARN_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+    </root>
+
+    <!-- 4.1 开发环境:打印控制台-->
+    <springProfile name="dev">
+        <root level="info">
+            <appender-ref ref="CONSOLE"/>
+            <appender-ref ref="DEBUG_FILE"/>
+            <appender-ref ref="INFO_FILE"/>
+            <appender-ref ref="WARN_FILE"/>
+            <appender-ref ref="ERROR_FILE"/>
+        </root>
+    </springProfile>
+    <!--  4.2 测试环境:输出到文档-->
+    <springProfile name="test">
+        <root level="info">
+            <appender-ref ref="CONSOLE"/>
+            <appender-ref ref="DEBUG_FILE"/>
+            <appender-ref ref="INFO_FILE"/>
+            <appender-ref ref="WARN_FILE"/>
+            <appender-ref ref="ERROR_FILE"/>
+        </root>
+    </springProfile>
+    <!--  4.3 生产环境:输出到文档-->
+    <springProfile name="pro">
+        <root level="info">
+            <appender-ref ref="CONSOLE"/>
+            <appender-ref ref="DEBUG_FILE"/>
+            <appender-ref ref="INFO_FILE"/>
+            <appender-ref ref="ERROR_FILE"/>
+            <appender-ref ref="WARN_FILE"/>
+        </root>
+    </springProfile>
+
+</configuration>

+ 26 - 0
iot-module/iot-module-stream/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.middle.platform</groupId>
+        <artifactId>iot-module</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <groupId>com.jot.joy</groupId>
+    <artifactId>iot-module-stream</artifactId>
+    <packaging>pom</packaging>
+    <description>流媒体服务器</description>
+    <modules>
+        <module>iot-module-stream-biz</module>
+    </modules>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+</project>

+ 1 - 0
iot-module/pom.xml

@@ -17,6 +17,7 @@
         <module>iot-module-data</module>
         <module>iot-module-manage</module>
         <module>iot-module-demo</module>
+        <module>iot-module-stream</module>
     </modules>
     <properties>
         <maven.compiler.source>17</maven.compiler.source>