commit c6aa16c782fb09c153d464251418db4ae62d06ab Author: htjcAdmin Date: Fri Aug 1 09:51:42 2025 +0800 /*上级系统模拟器代码初次提交*/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0695458 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ +/upstream.log +/.mvn/ +/upstream.2022-04-21.log +/log/ +/logs/ +/logs/inspect-upstream/info.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6bd1c40 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +FROM openjdk:8 + +MAINTAINER zk <546285615@qq.com> + + +# Set environment variables. +ENV HOME /work +ENV JAVA_OPTS "-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" + +ADD ./target/upstream-0.0.1-SNAPSHOT.jar /work/upstream.jar + +ENV DEFAULT_OPTS "" +ENV OTHER_OPTS "" + +# 开放端口 +EXPOSE 22508 + +#设置时区 +RUN echo "Asia/Shanghai" > /etc/timezone; + +# 配置容器启动后执行的命令 +ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar /work/upstream.jar $DEFAULT_OPTS $OTHER_OPTS" ] + +# Define working directory. +WORKDIR /work + + +# Define default command. +CMD ["bash"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..1218f52 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ + +电力500协议中转站 + + diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d8f7928 --- /dev/null +++ b/pom.xml @@ -0,0 +1,180 @@ + + + 4.0.0 + com.inspect + inspect-upstream + 1.0.0 + inspect-upstream + inspect-upstream + + + 1.8 + UTF-8 + UTF-8 + 2.3.7.RELEASE + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + com.thoughtworks.xstream + xstream + 1.4.21 + + + com.alibaba + fastjson + 1.2.73 + + + dom4j + dom4j + 1.6.1 + + + io.netty + netty-all + 4.1.77.Final + + + net.sf.kxml + kxml2 + 2.3.0 + + + xmlpull + xmlpull + 1.1.3.4d_b4_min + + + org.apache.commons + commons-lang3 + + + org.springframework.boot + spring-boot-starter-amqp + + + biz.paluch.logging + logstash-gelf + 1.13.0 + + + + commons-codec + commons-codec + 1.15 + + + + javolution + javolution + 5.5.1 + + + + org.projectlombok + lombok + 1.18.24 + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + ${project.artifactId} + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.3.7.RELEASE + + com.inspect.upstream.InspectUpstreamApplication + + + + repackage + + repackage + + + + + + + + diff --git a/proguard.cfg b/proguard.cfg new file mode 100644 index 0000000..b4545d7 --- /dev/null +++ b/proguard.cfg @@ -0,0 +1,65 @@ +-target 1.8 ##Specify the java version number +-dontshrink ##Default is enabled, here the shrink is turned off, that is, the unused classes/members are not deleted. +-dontoptimize ##Default is enabled, here to turn off bytecode level optimization +-useuniqueclassmembernames ## Take a unique strategy for confusing the naming of class members +-adaptclassstrings ## After confusing the class name, replace it with a place like Class.forName('className') +-dontnote +-ignorewarnings ## warnings are ignored +-dontwarn +-keep public class * extends org.springframework.boot.web.support.SpringBootServletInitializer +-keepdirectories ## Keep the package structure +-keepclasseswithmembers public class * { public static void main(java.lang.String[]);} ##Maintain the class of the main method and its method name +-keepclassmembers enum * { *; } ##Reserving enumeration members and methods +-keepclassmembers class * { + @org.springframework.beans.factory.annotation.Autowired *; + @org.springframework.beans.factory.annotation.Qualifier *; + @org.springframework.beans.factory.annotation.Value *; + @org.springframework.beans.factory.annotation.Required *; + @org.springframework.context.annotation.Bean *; + @org.springframework.context.annotation.Primary *; + @org.springframework.boot.context.properties.ConfigurationProperties *; + @org.springframework.boot.context.properties.EnableConfigurationProperties *; + @javax.inject.Inject *; + @javax.annotation.PostConstruct *; + @javax.annotation.PreDestroy *; +} +-keep @org.springframework.cache.annotation.EnableCaching class * +-keep @org.springframework.context.annotation.Configuration class * +-keep @org.springframework.boot.context.properties.ConfigurationProperties class * +-keep @org.springframework.boot.autoconfigure.SpringBootApplication class * +-allowaccessmodification +-keepattributes *Annotation* +-keepdirectories com.jayk.springboot.proguard.obfuscationdemo +-keepdirectories org.springframework.boot.autoconfigure +## Do not change names of the getters and setter, if you remove this ##thymeleaf unable to find the getter and setter i.e: ##${greetingDTO.message} +-keepclassmembers class * { + *** get*(); + void set*(***); +} +-keepclassmembernames class * { + java.lang.Class class$(java.lang.String); + java.lang.Class class$(java.lang.String, boolean); +} +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); + public static ** fromValue(java.lang.String); +} +-keepnames class * implements java.io.Serializable +-keepclassmembernames public class com.test.blah.config.liquibase.AsyncSpringLiquibase +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + !private ; + !private ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} +-keepclassmembers class * { + @org.springframework.beans.factory.annotation.Autowired ; + @org.springframework.beans.factory.annotation.Autowired ; + @org.springframework.security.access.prepost.PreAuthorize ; +} \ No newline at end of file diff --git a/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java b/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java new file mode 100644 index 0000000..509d987 --- /dev/null +++ b/src/main/java/com/inspect/upstream/InspectUpstreamApplication.java @@ -0,0 +1,31 @@ +package com.inspect.upstream; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.scheduling.annotation.EnableAsync; + +@Slf4j +@SpringBootApplication +@EnableAsync +public class InspectUpstreamApplication { + public static class CustomGenerator implements BeanNameGenerator { + + @Override + public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { + return definition.getBeanClassName(); + } + } + + public static void main(String[] args) { + new SpringApplicationBuilder(InspectUpstreamApplication.class) + .beanNameGenerator(new CustomGenerator()) + .run(args); + + log.info("\n<=====☆ UPSTREAM MODULE ☆ =====> \n .-------. ____ __ \n | _ _ \\ \\ \\ / / \n | ( ' ) | \\ _. / ' \n |(_ o _) / _( )_ .' \n | (_,_).' __ ___(_ o _)' \n | |\\ \\ | || |(_,_)' \n | | \\ `' /| `-' / \n | | \\ / \\ / \n ''-' `'-' `-..-' "); + } + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java b/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java new file mode 100644 index 0000000..89598bd --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/DeviceServerProperties.java @@ -0,0 +1,29 @@ +package com.inspect.upstream.cofiguration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@PropertySource("classpath:application.yml") +@Component +public class DeviceServerProperties { + + @Value("${deviceServer.serverIp}") + public String ip; + + @Value("${deviceServer.serverPort}") + public Integer port; + + @Value("${deviceServer.deviceServerCode}") + public String deviceServerCode; + + @Value("${deviceServer.deviceCode}") + public String deviceCode; + + @Value("${deviceServer.robotCode}") + public String robotCode; + + @Value("${deviceServer.nestCode}") + public String nestCode; + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java b/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java new file mode 100644 index 0000000..993e29e --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/UpSystemServerProperties.java @@ -0,0 +1,23 @@ +package com.inspect.upstream.cofiguration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@PropertySource("classpath:application.yml") +@Component +public class UpSystemServerProperties { + + @Value("${upSystemServer.serverIp}") + public String ip; + + @Value("${upSystemServer.serverPort}") + public Integer port; + + @Value("${upSystemServer.upCode}") + public String upCode; + + @Value("${upSystemServer.iipCode}") + public String iipCode; + +} diff --git a/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java b/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java new file mode 100644 index 0000000..3f8b402 --- /dev/null +++ b/src/main/java/com/inspect/upstream/cofiguration/WebConfig.java @@ -0,0 +1,95 @@ +package com.inspect.upstream.cofiguration; + +import com.inspect.upstream.constant.Constant; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.inspect.upstream.util.FastJson2JsonRedisSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.*; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.StandardCharsets; + +@Slf4j +@Configuration +public class WebConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); + + ObjectMapper mapper = new ObjectMapper(); + mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); + serializer.setObjectMapper(mapper); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + + return template; + } + + @Bean + public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) { + return new RabbitTemplate(connectionFactory); + } + + + /** + * 申明交换机 + */ + @Bean(Constant.EX_CHANGE_NAME) + public Exchange directExchange() { + // 申明路由交换机,durable:在rabbitmq重启后,交换机还在 + return ExchangeBuilder.directExchange(Constant.EX_CHANGE_NAME).durable(true).build(); + } + + /** + * 申明Blog队列 + * + * @return + */ + @Bean(Constant.QUEUE_NAME) + public Queue deviceQueue() { + return new Queue(Constant.QUEUE_NAME, true); + } + + + /** + * 绑定交换机-路由键 + * + * @return + */ + @Bean + public Binding bindRouting(Queue deviceQueue, Exchange directExchange) { + return BindingBuilder.bind(deviceQueue).to(directExchange).with(Constant.ROUTING_KEY_NAME).noargs(); + } + + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); + return restTemplate; + } +} diff --git a/src/main/java/com/inspect/upstream/constant/Constant.java b/src/main/java/com/inspect/upstream/constant/Constant.java new file mode 100644 index 0000000..b11d21e --- /dev/null +++ b/src/main/java/com/inspect/upstream/constant/Constant.java @@ -0,0 +1,24 @@ +package com.inspect.upstream.constant; + +public class Constant { + + /** + * 设备上报的mq routing key 路由键 + */ + public static final String ROUTING_KEY_NAME = "springboot.montdata"; + + /** + * 设备上报的交换机名 + */ + public static final String EX_CHANGE_NAME = "exchange-montdata"; + + /** + * 设备上报的队列 + */ + public static final String QUEUE_NAME = "queue-montdata"; + + /** + * 和基础数据定义的预置点转发type 类型 + */ + public static final String MODEL_UP_TYPE = "modelup-1024"; +} diff --git a/src/main/java/com/inspect/upstream/controller/ClientController.java b/src/main/java/com/inspect/upstream/controller/ClientController.java new file mode 100644 index 0000000..1c4637c --- /dev/null +++ b/src/main/java/com/inspect/upstream/controller/ClientController.java @@ -0,0 +1,59 @@ +package com.inspect.upstream.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.domain.AjaxResult; +import com.inspect.upstream.util.Color; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.MDC; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.UUID; + +@Slf4j +@RestController +@RequestMapping("/client") +public class ClientController { + + @GetMapping("gray") + public String gray() { + + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + MDC.put("traceId", uuid); + + log.info("这是一个来自springboot,logback的info级别的日志"); + log.warn("这是一条来自springboot,logback的warn级别的日志"); + log.warn("这是一条来自springboot,logback的warn级别的日志2"); + log.error("这是一条来自springboot,logback的error级别的日志", new Exception("系统错误")); + return "success"; + } + + /** + * 调用客户端发送消息 + */ + @PostMapping("sendMsg") + public AjaxResult sendMsg(String uuid, @RequestBody String msg) { + try { + if (StringUtils.isBlank(msg)) { + return AjaxResult.fail("500", "消息为空"); + } + + JSONObject jsonObject = JSONObject.parseObject(msg); + if (null == jsonObject) { + return AjaxResult.fail("500", "消息JSON解析失败"); + } + + msg = msg.replaceAll("sendCode", "SendCode"); + msg = msg.replaceAll("receiveCode", "ReceiveCode"); + msg = msg.replaceAll("type", "Type"); + //logger.info("###### 会话:{}, 巡视主机客户端接收到消息, 发送到上级 ######\n{}", uuid, msg); + //nettyClient.sendJsonMessage(uuid, msg); + return AjaxResult.success(); + } catch (Exception e) { + log.error(Color.RED + "###### 会话:{}, 客户端发送消息捕获异常:{} ######" + Color.END, uuid, e.getMessage()); + return AjaxResult.fail(500, "数据格式不正确"); + } + } + +} diff --git a/src/main/java/com/inspect/upstream/controller/DeviceServerController.java b/src/main/java/com/inspect/upstream/controller/DeviceServerController.java new file mode 100644 index 0000000..7cc5d67 --- /dev/null +++ b/src/main/java/com/inspect/upstream/controller/DeviceServerController.java @@ -0,0 +1,56 @@ +package com.inspect.upstream.controller; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.domain.AjaxResult; +import com.inspect.upstream.cofiguration.DeviceServerProperties; +import com.inspect.upstream.tcp.UpstreamMockNettyServer; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +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; + +import javax.annotation.Resource; + +@Slf4j +@RestController +@RequestMapping("/deviceServer") +public class DeviceServerController { + + @Resource + UpstreamMockNettyServer server; + + @Resource + DeviceServerProperties deviceServerProperties; + + /** + * 下发命令到设备端 + */ + @PostMapping("/sendCommand") + public AjaxResult sendCommand(@RequestBody String json) { + + try { + log.info("设备接入层server-接口,接到命令:{}", json); + // 调用设备接入层,下发命令到设备 + JSONObject jsonObject = JSONObject.parseObject(json); + + String sendCode = jsonObject.getString("SendCode"); + + String receiveCode = jsonObject.getString("ReceiveCode"); + + if (StringUtils.isEmpty(sendCode) || StringUtils.isEmpty(receiveCode)) { + log.error("SendCoded或ReceiveCode为空"); + return AjaxResult.fail(500, "SendCoded或ReceiveCode为空"); + } else { + server.sendXmlMessage(jsonObject);// to device + return AjaxResult.success(); + } + + } catch (Exception e) { + log.error("设备接入服务,处理命令下发捕获异常", e); + return AjaxResult.fail(500); + } + } + +} diff --git a/src/main/java/com/inspect/upstream/domain/AjaxResult.java b/src/main/java/com/inspect/upstream/domain/AjaxResult.java new file mode 100644 index 0000000..69f8cb0 --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/AjaxResult.java @@ -0,0 +1,84 @@ +package com.inspect.upstream.domain; + +import java.util.HashMap; + +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 1L; + + public static final String CODE_TAG = "code"; + + public static final String MSG_TAG = "msg"; + + public static final String DATA_TAG = "data"; + + public AjaxResult() { + } + + public AjaxResult(int code, String msg) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + public AjaxResult(int code, String msg, Object data) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (null != data) { + super.put(DATA_TAG, data); + } + } + + @Override + public AjaxResult put(String key, Object value) { + super.put(key, value); + return this; + } + + public static AjaxResult success() { + return AjaxResult.success("操作成功"); + } + + public static AjaxResult success(Object data) { + return AjaxResult.success("操作成功", data); + } + + public static AjaxResult success(String msg) { + return AjaxResult.success(msg, null); + } + + public static AjaxResult success(String msg, Object data) { + return new AjaxResult(HttpStatus.SUCCESS, msg, data); + } + + public static AjaxResult error() { + return AjaxResult.error("操作失败"); + } + + public static AjaxResult error(String msg) { + return AjaxResult.error(msg, null); + } + + public static AjaxResult error(String msg, Object data) { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + public static AjaxResult error(int code, String msg) { + return new AjaxResult(code, msg, null); + } + + public static AjaxResult fail(Integer code, String msg, Object data) { + return new AjaxResult(code, msg, data); + } + + public static AjaxResult fail(String msg, Object data) { + return new AjaxResult(HttpStatus.ERROR, msg, data); + } + + public static AjaxResult fail(Integer code, String msg) { + return new AjaxResult(code, msg, null); + } + + public static AjaxResult fail(Integer code) { + return new AjaxResult(code, null, null); + } + +} diff --git a/src/main/java/com/inspect/upstream/domain/HttpStatus.java b/src/main/java/com/inspect/upstream/domain/HttpStatus.java new file mode 100644 index 0000000..ff7716d --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/HttpStatus.java @@ -0,0 +1,83 @@ +package com.inspect.upstream.domain; + +public class HttpStatus { + /** + * 操作成功 + */ + public static final int SUCCESS = 200; + + /** + * 对象创建成功 + */ + public static final int CREATED = 201; + + /** + * 请求已经被接受 + */ + public static final int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + public static final int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + public static final int MOVED_PERM = 301; + + /** + * 重定向 + */ + public static final int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + public static final int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + public static final int BAD_REQUEST = 400; + + /** + * 未授权 + */ + public static final int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + public static final int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + public static final int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + public static final int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + public static final int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + public static final int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + public static final int ERROR = 500; + + /** + * 接口未实现 + */ + public static final int NOT_IMPLEMENTED = 501; +} diff --git a/src/main/java/com/inspect/upstream/domain/Result.java b/src/main/java/com/inspect/upstream/domain/Result.java new file mode 100644 index 0000000..1105ce7 --- /dev/null +++ b/src/main/java/com/inspect/upstream/domain/Result.java @@ -0,0 +1,34 @@ +package com.inspect.upstream.domain; + +public class Result { + + private String code; + + private String msg; + + private String data; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/BaseControl.java b/src/main/java/com/inspect/upstream/tcp/BaseControl.java new file mode 100644 index 0000000..50e17f2 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/BaseControl.java @@ -0,0 +1,559 @@ +package com.inspect.upstream.tcp; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +import java.util.List; + +public class BaseControl { + public String SendCode; + public String ReceiveCode; + public String Type; + public String Code; + public String Command; + public String Time; +} + +class ResponseControl extends BaseControl { + public String Items; +} + + +class RegisterResponseControl extends BaseControl { + public List Items; +} + +//注册响应消息 +@XStreamAlias("Item") +class RegisterResponseModel { + @XStreamAsAttribute + public String heart_beat_interval; //心跳间隔 + @XStreamAsAttribute + public String patroldevice_run_interval; //巡视设备运行数据间隔 + @XStreamAsAttribute + public String nest_run_interval; //无人机机巢运行数据间隔 + @XStreamAsAttribute + public String weather_interval; //微气象数据间隔 + @XStreamAsAttribute + public String env_interval; //环境数据间隔 +} + +class RobotControl extends BaseControl { + public List Items; +} + +//机器人、无人机控制 +@XStreamAlias("Item") +class RobotModel { + @XStreamAsAttribute + public String value; +} + +class TaskSendControl extends BaseControl { + public List Items; +} + +//任务下发 +@XStreamAlias("Item") +class TaskSendModel { + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String priority; //优先级 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //设备列表 格式:多个ID,采用“,”分隔" + @XStreamAsAttribute + public String fixed_start_time; //定期开始时间 + @XStreamAsAttribute + public String cycle_month; //周期(月) + @XStreamAsAttribute + public String cycle_week; //周期(周) + @XStreamAsAttribute + public String cycle_execute_time; //周期(执行时间) + @XStreamAsAttribute + public String cycle_start_time; //周期开始时间 + @XStreamAsAttribute + public String cycle_end_time; //周期结束时间 + @XStreamAsAttribute + public String interval_number; //间隔(数量) + @XStreamAsAttribute + public String interval_type; //间隔(类型) + @XStreamAsAttribute + public String interval_execute_time; //间隔(执行时间) + @XStreamAsAttribute + public String interval_start_time; //间隔开始时间 + @XStreamAsAttribute + public String interval_end_time; //间隔结束时间 + @XStreamAsAttribute + public String invalid_start_time; //不可用开始时间 + @XStreamAsAttribute + public String invalid_end_time; //不可用结束时间 + @XStreamAsAttribute + public String isenable; //是否可用 + @XStreamAsAttribute + public String creator; //编制人 + @XStreamAsAttribute + public String create_time; //编制时间 + @XStreamAsAttribute + public String type; //类型 + +} + +class LinkageTaskControl extends BaseControl { + public List Items; +} + +//联动任务下发 +@XStreamAlias("Item") +class LinkageTaskModel { + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String priority; //优先级 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //设备列表 格式:多个ID,采用“,”分隔" +} + + +class AreaControl extends BaseControl { + public List Items; +} + +//检修区域 +@XStreamAlias("Item") +class AreaModel { + @XStreamAsAttribute + public String config_code; //配置编码 检修区域配置编码 + @XStreamAsAttribute + public String enable; //是否有效 + @XStreamAsAttribute + public String start_time; //检修开始时间 + @XStreamAsAttribute + public String end_time; //检修结束时间 + @XStreamAsAttribute + public String device_level; //设备层级 + @XStreamAsAttribute + public String device_list; //检修设备列表 + @XStreamAsAttribute + public String coordinate_pixel; //检修区域坐标框 +} + +class ModelControl extends BaseControl { + public List Items; +} + +@XStreamAlias("Item") +class ModelPath { + @XStreamAsAttribute + public String device_file_path; + @XStreamAsAttribute + public String robot_file_path; + @XStreamAsAttribute + public String host_file_path; + @XStreamAsAttribute + public String video_file_path; + @XStreamAsAttribute + public String drone_file_path; + @XStreamAsAttribute + public String voice_file_path; + @XStreamAsAttribute + public String task_file_path; + @XStreamAsAttribute + public String overhaularea_file_path; + @XStreamAsAttribute + public String map_file_path; + @XStreamAsAttribute + public String total_num; + @XStreamAsAttribute + public String valid_num; + @XStreamAsAttribute + public String percent; + @XStreamAsAttribute + public String error_code; + @XStreamAsAttribute + public String task_patrolled_id; + +} + +//巡视结果统计查询 +class ResultControl extends BaseControl { + public List Items; +} + +@XStreamAlias("Item") +class Result { + @XStreamAsAttribute + public String begin_time; + @XStreamAsAttribute + public String end_time; +} + +class PatrolDeviceStateControl extends BaseControl { + public List Items; +} + +//巡视设备状态数据 +@XStreamAlias("Item") +class PatrolDeviceStateModel { + @XStreamAsAttribute + public String patroldevice_name;//巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code;//巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class PatrolDeviceRunningControl extends BaseControl { + public List Items; +} + +//巡视设备运行数据 +@XStreamAlias("Item") +class PatrolDeviceRunningModel { + @XStreamAsAttribute + public String patroldevice_name;//巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code;//巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class NestStateControl extends BaseControl { + public List Items; +} + +//无人机机巢状态数据 +@XStreamAlias("Item") +class NestStateModel { + @XStreamAsAttribute + public String nest_name; //机巢名称 + @XStreamAsAttribute + public String nest_code; //机巢编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class NestRunningControl extends BaseControl { + public List Items; +} + +//无人机机巢运行数据 +@XStreamAlias("Item") +class NestRunningModel { + @XStreamAsAttribute + public String nest_name; //机巢名称 + @XStreamAsAttribute + public String nest_code; //机巢编码 + @XStreamAsAttribute + public String module_no; //模块序号 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class RouteControl extends BaseControl { + public List Items; +} + +class LocationControl extends BaseControl { + public List Items; +} + +//巡视设备坐标 +@XStreamAlias("Item") +class LocationModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String coordinate_pixel; //坐标 + @XStreamAsAttribute + public String coordinate_geography; //经纬度 +} + + +class AlarmControl extends BaseControl { + public List Items; +} + +//巡视设备异常告警数据 +@XStreamAlias("Item") +class AlarmModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String content; //告警描述 +} + + +class EnvironmentControl extends BaseControl { + public List Items; +} + +//环境数据 +@XStreamAlias("Item") +class EnvironmentModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class TaskStateControl extends BaseControl { + public List Items; +} + +//任务状态数据 +@XStreamAlias("Item") +class TaskStateModel { + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String task_state; //任务状态 + @XStreamAsAttribute + public String plan_start_time; //计划开始时间 + @XStreamAsAttribute + public String start_time; //开始时间 + @XStreamAsAttribute + public String task_progress; //任务进度 + @XStreamAsAttribute + public String task_estimated_time; //任务预计剩余时间 + @XStreamAsAttribute + public String description; //描述 +} + + +class TaskResultControl extends BaseControl { + public List Items; +} + +//巡视结果 +@XStreamAlias("Item") +class TaskResultModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String device_name; //设备点位名称 + @XStreamAsAttribute + public String device_id; //设备点位ID + @XStreamAsAttribute + public String value_type; //值类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String recognition_type; //识别类型 + @XStreamAsAttribute + public String file_type; //采集文件类型 + @XStreamAsAttribute + public String file_path; //文件名称 + @XStreamAsAttribute + public String rectangle; //图像框 + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String valid; //结论 + @XStreamAsAttribute + public String data_type; //巡视结果数据来源 0x01摄像机,0x02机器人,0x03无人机,0x04声纹,0x05在线监测 + @XStreamAsAttribute + public String material_id; //实物ID +} + +class AnalysisControl extends BaseControl { + public List Items; +} + +//静默监视告警数据 +@XStreamAlias("Item") +class AnalysisModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String task_name; //任务名称 + @XStreamAsAttribute + public String task_code; //任务编码 + @XStreamAsAttribute + public String device_name; //设备点位名称 + @XStreamAsAttribute + public String device_id; //设备点位ID + @XStreamAsAttribute + public String alarm_level; //告警等级 + @XStreamAsAttribute + public String alarm_type; //告警类型 + @XStreamAsAttribute + public String recognition_type; //识别类型 + @XStreamAsAttribute + public String file_type; //告警文件类型 + @XStreamAsAttribute + public String task_patrolled_id; //巡视任务执行ID + @XStreamAsAttribute + public String file_path; //文件路径 + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String content; //告警描述 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + + +class MonitorControl extends BaseControl { + public List Items; +} + +//静默监视告警数据 +@XStreamAlias("Item") +class MonitorModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String alarm_level; //告警等级 + @XStreamAsAttribute + public String monitor_type; //静默监视类型 + @XStreamAsAttribute + public String file_type; //告警文件类型 + @XStreamAsAttribute + public String content; //告警描述 + @XStreamAsAttribute + public String file_path; //文件名称 + @XStreamAsAttribute + public String time; //时间 +} + +class TotalControl extends BaseControl { + public List Items; +} + +//巡视结果统计 +@XStreamAlias("Item") +class TotalModel { + @XStreamAsAttribute + public String total_num; //满足查询条件总数 + @XStreamAsAttribute + public String valid_num; //查询有效数据 + @XStreamAsAttribute + public String percent; //统计百分比,有效值 保留小数点后3位 +} + + +class ReportControl extends BaseControl { + public List Items; +} + +//巡视设备统计信息上报 +@XStreamAlias("Item") +class ReportModel { + @XStreamAsAttribute + public String patroldevice_name; //巡视设备名称 + @XStreamAsAttribute + public String patroldevice_code; //巡视设备编码 + @XStreamAsAttribute + public String commission_time; //投运时间 + @XStreamAsAttribute + public String report_time; //上报时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String value; //值 + @XStreamAsAttribute + public String value_unit; //值带单位 + @XStreamAsAttribute + public String unit; //单位 +} + +class UpdateModelControl extends BaseControl { + public List Items; +} + +//模型更新上报指令 +@XStreamAlias("Item") +class UpdateModel { + @XStreamAsAttribute + public String time; //时间 + @XStreamAsAttribute + public String type; //类型 + @XStreamAsAttribute + public String file_path; //路径 +} \ No newline at end of file diff --git a/src/main/java/com/inspect/upstream/tcp/BinaryModel.java b/src/main/java/com/inspect/upstream/tcp/BinaryModel.java new file mode 100644 index 0000000..24ee06a --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/BinaryModel.java @@ -0,0 +1,13 @@ +package com.inspect.upstream.tcp; + +import io.netty.buffer.ByteBuf; + +public class BinaryModel { + public long sendIndex; + public long receiveIndex; + public byte sourceFlag; + public int dataLength; + public ByteBuf dataBuf; + public String id; + public String uuid; +} diff --git a/src/main/java/com/inspect/upstream/tcp/ByteUtils.java b/src/main/java/com/inspect/upstream/tcp/ByteUtils.java new file mode 100644 index 0000000..709a05d --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/ByteUtils.java @@ -0,0 +1,258 @@ +package com.inspect.upstream.tcp; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.Arrays; + +public class ByteUtils { + private static final byte[] BUILD_BYTE_TABLE = new byte[]{(byte) 128, (byte) 64, (byte) 32, (byte) 16, (byte) 8, (byte) 4, (byte) 2, (byte) 1}; + + private ByteUtils() { + } + + public static String byte2Hex(byte[] bytes) { + StringBuffer stringBuffer = new StringBuffer(); + String temp = null; + for (int i = 0; i < bytes.length; i++) { + temp = Integer.toHexString(bytes[i] & 0xFF); + if (temp.length() == 1) { + //1得到一位的进行补0操作 + stringBuffer.append("0"); + } + stringBuffer.append(temp); + } + return stringBuffer.toString(); + } + + public static byte[] shortToByte(short number) { + byte[] b = new byte[2]; + for (int i = 1; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static short byteToShort(byte[] b) { + return (short) ((((b[0] & 0xff) << 8) | b[1] & 0xff)); + } + + public static byte[] intToByte(int number) { + byte[] b = new byte[4]; + for (int i = 3; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static int byteToInt(byte[] b) { + return ((((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) | ((b[2] & 0xff) << 8) | (b[3] & 0xff))); + } + + public static byte[] longToByte(long number) { + byte[] b = new byte[8]; + for (int i = 7; i >= 0; i--) { + b[i] = (byte) (number % 256); + number >>= 8; + } + return b; + } + + public static long byteToLong(byte[] b) { + return ((((long) b[0] & 0xff) << 56) | (((long) b[1] & 0xff) << 48) | (((long) b[2] & 0xff) << 40) | (((long) b[3] & 0xff) << 32) | (((long) b[4] & 0xff) << 24) + | (((long) b[5] & 0xff) << 16) | (((long) b[6] & 0xff) << 8) | ((long) b[7] & 0xff)); + } + + public static byte[] doubleToByte(double d) { + byte[] bytes = new byte[8]; + long l = Double.doubleToLongBits(d); + for (int i = 0; i < bytes.length; i++) { + bytes[i] = Long.valueOf(l).byteValue(); + l = l >> 8; + } + return bytes; + } + + public static double byteToDouble(byte[] b) { + long l; + l = b[0]; + l &= 0xff; + l |= ((long) b[1] << 8); + l &= 0xffff; + l |= ((long) b[2] << 16); + l &= 0xffffff; + l |= ((long) b[3] << 24); + l &= 0xffffffffl; + l |= ((long) b[4] << 32); + l &= 0xffffffffffl; + + l |= ((long) b[5] << 40); + l &= 0xffffffffffffl; + l |= ((long) b[6] << 48); + l &= 0xffffffffffffffl; + + l |= ((long) b[7] << 56); + + return Double.longBitsToDouble(l); + } + + public static byte[] floatToByte(float d) { + byte[] bytes = new byte[4]; + int l = Float.floatToIntBits(d); + for (int i = 0; i < bytes.length; i++) { + bytes[i] = Integer.valueOf(l).byteValue(); + l = l >> 8; + } + return bytes; + } + + public static float byteToFloat(byte[] b) { + int l; + l = b[0]; + l &= 0xff; + l |= ((long) b[1] << 8); + l &= 0xffff; + l |= ((long) b[2] << 16); + l &= 0xffffff; + l |= ((long) b[3] << 24); + l &= 0xffffffffl; + + return Float.intBitsToFloat(l); + } + + public static byte[] stringToByte(String s, Charset charset) { + return s.getBytes(charset); + } + + public static String byteToString(byte[] b, Charset charset) { + return new String(b, charset); + } + + public static byte[] objectToByte(Object obj) throws IOException { + ByteArrayOutputStream buff = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(buff); + out.writeObject(obj); + try { + return buff.toByteArray(); + } finally { + out.close(); + } + } + + public static Object byteToObject(byte[] b) throws IOException, ClassNotFoundException { + ByteArrayInputStream buff = new ByteArrayInputStream(b); + ObjectInputStream in = new ObjectInputStream(buff); + Object obj = in.readObject(); + try { + return obj; + } finally { + in.close(); + } + } + + public static boolean equalsBit(byte a, byte b) { + return Arrays.equals(byteToBitArray(a), byteToBitArray(b)); + } + + public static boolean equalsBit(byte[] a, byte[] b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + + int length = a.length; + if (b.length != length) { + return false; + } + + for (int count = 0; count < a.length; count++) { + if (!equalsBit(a[count], b[count])) { + return false; + } + } + return true; + } + + public static String bitString(byte b) { + StringBuilder buff = new StringBuilder(); + boolean[] array = byteToBitArray(b); + for (int i = 0; i < array.length; i++) { + buff.append(array[i] ? 1 : 0); + } + return buff.toString(); + } + + public static boolean[] byteToBitArray(byte b) { + boolean[] buff = new boolean[8]; + int index = 0; + for (int i = 7; i >= 0; i--) { + buff[index++] = ((b >>> i) & 1) == 1; + } + return buff; + } + + public static boolean byteBitValue(byte b, int index) { + return byteToBitArray(b)[index]; + } + + public static byte buildNewByte(boolean[] values) { + byte b = 0; + for (int i = 0; i < 8; i++) { + if (values[i]) { + b |= BUILD_BYTE_TABLE[i]; + } + } + return b; + } + + public static byte changeByteBitValue(byte b, int index, boolean newValue) { + boolean[] bitValues = byteToBitArray(b); + bitValues[index] = newValue; + return buildNewByte(bitValues); + } + + public static byte[] ipAddressBytes(String address) { + if (address == null || address.length() < 0 || address.length() > 15) { + throw new IllegalArgumentException("Invalid IP address."); + } + + final int ipSize = 4;// 最大IP位数 + final char ipSpace = '.';// IP数字的分隔符 + int[] ipNums = new int[ipSize]; + StringBuilder number = new StringBuilder();// 当前操作的数字 + StringBuilder buff = new StringBuilder(address); + int point = 0;// 当前操作的数字下标,最大到3. + char currentChar; + for (int i = 0; i < buff.length(); i++) { + currentChar = buff.charAt(i); + if (ipSpace == currentChar) { + // 当前位置等于最大于序号后,还有字符没有处理表示这是一个错误的IP. + if (point == ipSize - 1 && buff.length() - (i + 1) > 0) { + throw new IllegalArgumentException("Invalid IP address."); + } + ipNums[point++] = Integer.parseInt(number.toString()); + number.delete(0, number.length()); + } else { + number.append(currentChar); + } + } + ipNums[point] = Integer.parseInt(number.toString()); + + byte[] ipBuff = new byte[ipSize]; + int pointNum = 0; + for (int i = 0; i < 4; i++) { + pointNum = Math.abs(ipNums[i]); + if (pointNum > 255) { + throw new IllegalArgumentException("Invalid IP address."); + } + ipBuff[i] = (byte) (pointNum & 0xff); + } + + return ipBuff; + } +} + + diff --git a/src/main/java/com/inspect/upstream/tcp/ChannelCache.java b/src/main/java/com/inspect/upstream/tcp/ChannelCache.java new file mode 100644 index 0000000..4a53b2f --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/ChannelCache.java @@ -0,0 +1,65 @@ +package com.inspect.upstream.tcp; + +import io.netty.channel.ChannelHandlerContext; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class ChannelCache { + private static final Map channelPool = new ConcurrentHashMap<>(); + + public int size() { + return channelPool.size(); + } + + public static ChannelCache getInstance() { + return ChannelCacheHolder.instance; + } + + public static class ChannelCacheHolder { + public static ChannelCache instance = new ChannelCache(); + } + + public ChannelHandlerContext get(String handle) { + return channelPool.get(handle); + } + + public void add(String handle, ChannelHandlerContext ctx) { + channelPool.put(handle, ctx); + } + + public String addIfAbsent(String devId, ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + String key = (String) entry.getKey(); + return devId.equals(key) ? null : key; + } + } + channelPool.put(devId, ctx); + return null; + } + + public void remove(ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + channelPool.remove(entry.getKey()); + break; + } + } + } + + public void replace(String newKey, ChannelHandlerContext ctx) { + for (Map.Entry entry : channelPool.entrySet()) { + if (entry.getValue() == ctx) { + channelPool.remove(entry.getKey()); + channelPool.put(newKey, ctx); + break; + } + } + } + + public Set getClients() { + return channelPool.keySet(); + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/CommonUtils.java b/src/main/java/com/inspect/upstream/tcp/CommonUtils.java new file mode 100644 index 0000000..6d5b0df --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/CommonUtils.java @@ -0,0 +1,13 @@ +package com.inspect.upstream.tcp; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CommonUtils { + public static String GetNowDateString() { + Date date = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return formatter.format(date); + } + +} diff --git a/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java b/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java new file mode 100644 index 0000000..aeb9f93 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/DownXml2Json.java @@ -0,0 +1,283 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSON; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.security.AnyTypePermission; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class DownXml2Json { + + /** + * 默认为对上级的客户端的别名 + */ + private String alias; + + private String deviceAlias = "PatrolDevice"; + + private XStream getXmlStreamInstance() { + return new XStream(new Xpp3Driver(new NoNameCoder())); + } + + public DownXml2Json(String alias) { + this.alias = alias; + } + + public String DownStreamJson2Xml(String uuid, String id, String xml, Class clazz) { + try { + XStream xStream = getXmlStreamInstance(); + xStream.alias(alias, clazz); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + T obj = (T) xStream.fromXML(xml); + return JSON.toJSONString(obj); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(deviceAlias, clazz); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + T obj = (T) xStream.fromXML(xml); + return JSON.toJSONString(obj); + } catch (com.thoughtworks.xstream.XStreamException ex) { + log.error(Color.RED + "###### 客户:{}, DownStreamJson2Xml解析失败:{} ######" + Color.END, id, e.getMessage()); + return null; + } + } + } + + //任务下发 + public String TaskSendControlXml2Json(String xml) { + XStream xStream = getXmlStreamInstance(); + xStream.alias(alias, TaskSendControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskSendControl obj = (TaskSendControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //联动任务下发 + public String LinkageTaskControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, LinkageTaskControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + LinkageTaskControl obj = (LinkageTaskControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //检修去下发 + public String AreaControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, AreaControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AreaControl obj = (AreaControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机器人控制下发 + public String RobotControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RobotControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RobotControl obj = (RobotControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //无人机控制下发 + public String UavControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RobotControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RobotControl obj = (RobotControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //任务控制和同步指令 + public String BaseControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + BaseControl obj = (BaseControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //上级查询巡视结果指令 + public String ResultControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, ResultControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + ResultControl obj = (ResultControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //模型同步同步指令 + public String ModelControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, ModelControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + BaseControl obj = (BaseControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检设备状态数据 + public String PatrolDeviceStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, PatrolDeviceStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + PatrolDeviceStateControl obj = (PatrolDeviceStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检设备运行数据 + public String PatrolDeviceRunningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, PatrolDeviceRunningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + PatrolDeviceRunningControl obj = (PatrolDeviceRunningControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机巢状态数据 + public String NestStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, NestStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + NestStateControl obj = (NestStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //机巢运行数据 + public String NestRunningControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, NestRunningControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + NestRunningControl obj = (NestRunningControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //坐标数据 + public String LocationControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, LocationControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + LocationControl obj = (LocationControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡视路线 + public String RouteControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, RouteControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + RouteControl obj = (RouteControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //设备告警数据 + public String AlarmControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + //xStream.alias(alias, AlarmControl.class); + log.info("[XML] AlarmControlXml2Json alias:{}", alias); + xStream.alias(alias, AlarmControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AlarmControl obj = (AlarmControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //环境数据 + public String EnvironmentControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, EnvironmentControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + EnvironmentControl obj = (EnvironmentControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //任务状态 + public String TaskStateControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, TaskStateControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskStateControl obj = (TaskStateControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡视结果 + public String TaskResultControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, TaskResultControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + TaskResultControl obj = (TaskResultControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } + + //巡检告警数据 + public String AnalysisControlXml2Json(String xml) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(alias, AnalysisControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + AnalysisControl obj = (AnalysisControl) xStream.fromXML(xml); + String resultJson = JSON.toJSONString(obj); + return resultJson; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/MyDecoder.java b/src/main/java/com/inspect/upstream/tcp/MyDecoder.java new file mode 100644 index 0000000..c104509 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/MyDecoder.java @@ -0,0 +1,80 @@ +package com.inspect.upstream.tcp; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.RandomStringUtils; + +import java.util.List; + +@Slf4j +public class MyDecoder extends ByteToMessageDecoder { + + private final int BASE_LENGTH = 2 + 8 + 8 + 1 + 4 + 2; + + private Integer printRecvData = 0; + + public MyDecoder(Integer printRecvData) { + this.printRecvData = printRecvData; + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + try { + int length = in.readableBytes(); + if (length < BASE_LENGTH) { +// log.error("not enough readableBytes: {}", length); + return; + } + + final String uuid = RandomStringUtils.randomAlphanumeric(16); + + if(printRecvData > 0) { + ByteBuf forPrint = in.copy(); + log.info("###### 会话:{}, 客户:{}, 上行原始报文 ######\n {}", uuid, ctx.channel().id().asShortText(), ByteBufUtil.hexDump(forPrint)); + forPrint.release(); + } + + do { + byte[] start = new byte[2]; + in.readBytes(start); + if (start[0] == -21 && start[1] == -112) { + long sendIndex = in.readLongLE(); + long receiveIndex = in.readLongLE(); + byte sourceFlag = in.readByte(); + int xmlLength = in.readIntLE(); + length = in.readableBytes(); + if (length >= xmlLength + 2) { + byte[] payload = new byte[xmlLength]; + in.readBytes(payload); + in.skipBytes(2); + + BinaryModel binaryModel = new BinaryModel(); + binaryModel.receiveIndex = receiveIndex; + binaryModel.sendIndex = sendIndex; + binaryModel.sourceFlag = sourceFlag; + binaryModel.dataLength = xmlLength; + binaryModel.dataBuf = Unpooled.copiedBuffer(payload); + binaryModel.uuid = uuid; + out.add(binaryModel); + break; + } else { + in.readerIndex(in.readerIndex() - 23); +// log.error("wrong xml length: {}, total length: {}", xmlLength, length); + } + } else { + in.readerIndex(in.readerIndex() - 2); +// log.error("wrong start flag: [{},{}]", start[0], start[1]); + } + + in.readByte(); + length = in.readableBytes(); + } while (length >= BASE_LENGTH); + } catch (Exception e) { + log.error("error" , e); + } + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/SystemType.java b/src/main/java/com/inspect/upstream/tcp/SystemType.java new file mode 100644 index 0000000..62ba09c --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/SystemType.java @@ -0,0 +1,82 @@ +package com.inspect.upstream.tcp; + +public class SystemType { + public static final int system = 251; + public static final int register_request = 1; + public static final int heart_request = 2; + public static final int has_response = 4; + public static final int no_response = 3; +} + +class RobotType { + public static final int robot = 1; + public static final int robotCar = 2; + public static final int robotPtz = 3; + public static final int robotFz = 4; + public static final int robotVl = 21; + public static final int robotIr = 22; +} + +class UAVType { + public static final int uav = 20001; + public static final int uavKz = 20002; + public static final int uavYt = 20003; + public static final int uavXj = 20004; + public static final int nest = 20005; +} + +class NestCtlType { + public static final int courseReversal = 20001; // + public static final int suddenStop = 20002; // + public static final int ptzPitch = 20003; // + public static final int picModelSet = 20004; // + public static final int nestSuddenStop = 20005; // +} + +class TaskType { + public static final int taskControl = 41; + public static final int taskSend = 101; + public static final int lendonTask = 102; + public static final int taskArea = 81; +} + +class ModelType { + public static final int modelSync = 61; + public static final int modelUpdate = 11; +} + +class QueryType { + public static final int queryResult = 121; +} + +class ResponseType { + public static final String retry = "100"; + public static final String succeed = "200"; + public static final String reject = "400"; + public static final String fault = "500"; +} + +class PushType { + public static final int patrolDeviceState = 1; + public static final int patrolDeviceRunning = 2; + public static final int nestState = 20001; + public static final int nestRunning = 10004; + public static final int location = 3; + public static final int route = 4; + public static final int alarm = 5; + public static final int environment = 21; + public static final int taskState = 41; + public static final int result = 61; + public static final int analysisAlarm = 62; + public static final int monitor = 63; + public static final int total = 81; +} + +class ConfigType { + public static final int dataLength = 25; + public static final String heart_beat_interval = "30"; + public static final String patroldevice_run_interval = "300"; + public static final String nest_run_interval = "300"; + public static final String env_interval = "300"; + public static final String weather_interval = "300"; +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java b/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java new file mode 100644 index 0000000..c5483fd --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpJson2Xml.java @@ -0,0 +1,267 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSON; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UpJson2Xml { + + private String deviceAlias = "PatrolDevice"; + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + /** + * 默认为对上级的客户端的别名 + */ + private String alias; + + public UpJson2Xml(String alias) { + // 设备接入服务 + this.alias = alias; + } + + public String UpStreamJson2Xml(String json, Class clazz) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, clazz); + T obj = JSON.parseObject(json, clazz); + return xStream.toXML(obj); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(deviceAlias, clazz); + T obj = JSON.parseObject(json, clazz); + return xStream.toXML(obj); + } catch (com.thoughtworks.xstream.XStreamException ex) { + log.error(Color.RED + "###### UpStreamJson2Xml解析失败:{} ######" + Color.END, ex.getMessage()); + return null; + } + } + } + + //模型更新上报指令 + public String UpdateModelJson2Xml(String json) { + UpdateModelControl obj = JSON.parseObject(json, UpdateModelControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, UpdateModelControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务控制和模型同步 + public String ResponseJson2Xml(String json) { + ResponseControl obj = JSON.parseObject(json, ResponseControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ResponseControl.class); + obj.Items = ""; + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //模型同步 + public String ModelJson2Xml(String json) { + BaseControl obj = JSON.parseObject(json, ModelControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ModelControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //机器人控制指令 + public String RobotJson2Xml(String json) { + RobotControl obj = JSON.parseObject(json, RobotControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RobotControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机控制指令 + public String UavControlJson2Xml(String json) { + RobotControl obj = JSON.parseObject(json, RobotControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RobotControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务下发指令 + public String TaskSendJson2Xml(String json) { + TaskSendControl obj = JSON.parseObject(json, TaskSendControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskSendControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //联动任务下发指令 + public String LinkageTaskJson2Xml(String json) { + LinkageTaskControl obj = JSON.parseObject(json, LinkageTaskControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, LinkageTaskControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //检修区域指令 + public String AreaJson2Xml(String json) { + AreaControl obj = JSON.parseObject(json, AreaControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AreaControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + + //-----------------------------------------上行数据----------------------------------// + //巡视设备状态数据 + public String PatrolDeviceStateControlJson2Xml(String json) { + PatrolDeviceStateControl obj = JSON.parseObject(json, PatrolDeviceStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, PatrolDeviceStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备运行数据 + public String PatrolDeviceRunningControlJson2Xml(String json) { + PatrolDeviceRunningControl obj = JSON.parseObject(json, PatrolDeviceRunningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, PatrolDeviceRunningControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机机巢状态数据 + public String NestStateJson2Xml(String json) { + NestStateControl obj = JSON.parseObject(json, NestStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, NestStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //无人机机巢运行数据 + public String NestRunningJson2Xml(String json) { + NestRunningControl obj = JSON.parseObject(json, NestRunningControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, NestRunningControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + + //巡视设备坐标 + public String LocationControlJson2Xml(String json) { + LocationControl obj = JSON.parseObject(json, LocationControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, LocationControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视路线 + public String RouteControlJson2Xml(String json) { + RouteControl obj = JSON.parseObject(json, RouteControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, RouteControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备异常告警数据 + public String AlarmControlJson2Xml(String json) { + AlarmControl obj = JSON.parseObject(json, AlarmControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AlarmControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //环境数据 + public String EnvironmentControlJson2Xml(String json) { + EnvironmentControl obj = JSON.parseObject(json, EnvironmentControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, EnvironmentControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //任务状态数据 + public String TaskStateControlJson2Xml(String json) { + TaskStateControl obj = JSON.parseObject(json, TaskStateControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskStateControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视结果 + public String TaskResultControlJson2Xml(String json) { + TaskResultControl obj = JSON.parseObject(json, TaskResultControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, TaskResultControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //静默监视告警数据 + public String MonitorControlJson2Xml(String json) { + MonitorControl obj = JSON.parseObject(json, MonitorControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, MonitorControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡视设备统计信息上报 + public String ReportControlJson2Xml(String json) { + ReportControl obj = JSON.parseObject(json, ReportControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, ReportControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } + + //巡检告警数据 + public String AnalysisControlJson2Xml(String json) { + AnalysisControl obj = JSON.parseObject(json, AnalysisControl.class); + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.autodetectAnnotations(true); + xStream.alias(alias, AnalysisControl.class); + String resultXML = xStream.toXML(obj); + return resultXML; + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java new file mode 100644 index 0000000..fccf2b0 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServer.java @@ -0,0 +1,584 @@ +package com.inspect.upstream.tcp; + +import com.alibaba.fastjson.JSONObject; +import com.inspect.upstream.constant.Constant; +import com.inspect.upstream.controller.ClientController; +import com.inspect.upstream.cofiguration.DeviceServerProperties; +import com.inspect.upstream.util.Color; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.Xpp3Driver; +import com.thoughtworks.xstream.security.AnyTypePermission; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.util.CharsetUtil; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.concurrent.*; + +@Slf4j +@Component +public class UpstreamMockNettyServer { + /** + * 接收/发送报文xml外层别名 + */ + private final String aliasHost = "PatrolHost"; + + private final String aliasDevice = "PatrolDevice"; + + @Resource + private ClientController clientController; + private EventLoopGroup bossGroup; + private EventLoopGroup workGroup; + private long sendIndex = 0; //若重启系统后还要延续之前的序列号则需要把序列号存入redis中 + private long receiveIndex = 0; + private DownXml2Json downXml2Json = new DownXml2Json(aliasHost); + private UpJson2Xml upJson2Xml = new UpJson2Xml(aliasHost); + private UpstreamMockNettyServerHandler upstreamMockNettyServerHandler; + + @Resource + DeviceServerProperties deviceServerProperties; + + @Resource(name = "stringRedisTemplate") + private RedisTemplate redisTemplate; + + @Resource + private RabbitTemplate rabbitTemplate; + + @Value("${iip_server.authDevice.url}") + String iipAuthDeviceUrl; + + @Value("${print_recv_data:1}") + Integer printRecvData; + + @Value("${separate_packages:0}") + Integer separatePackages; + + private int serverPort; + + public void init() { + log.info("print_recv_data config: {}", printRecvData); + log.info("separate_packages config: {}", separatePackages); + + this.serverPort = deviceServerProperties.port; + upJson2Xml = new UpJson2Xml(aliasHost); + downXml2Json = new DownXml2Json(aliasHost); + } + + @Async + public void startServer() { + // 初始化 + init(); + + //new 一个主线程组 + bossGroup = new NioEventLoopGroup(); + //new 一个工作线程组 + workGroup = new NioEventLoopGroup(); + ServerBootstrap bootstrap = new ServerBootstrap() + .group(bossGroup, workGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + if(separatePackages > 0) { + ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 19, 4, 2, 0, true)); + } + ch.pipeline().addLast(new MyDecoder(printRecvData)); + upstreamMockNettyServerHandler = new UpstreamMockNettyServerHandler(UpstreamMockNettyServer.this); + ch.pipeline().addLast(upstreamMockNettyServerHandler); + } + }) + .localAddress(serverPort) + .option(ChannelOption.SO_BACKLOG, 1024) + .option(ChannelOption.SO_REUSEADDR, true) + .childOption(ChannelOption.SO_KEEPALIVE, true) + .childOption(ChannelOption.SO_LINGER, 10); + try { + ChannelFuture future = bootstrap.bind(serverPort).sync(); + log.info("###### 上级系统模拟服务器启动 ######"); + future.channel().closeFuture().sync(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + close(); + } + } + + //释放资源 + public void close() { + if (bossGroup != null) { + bossGroup.shutdownGracefully(); + } + if (workGroup != null) { + workGroup.shutdownGracefully(); + } + } + + private String compact(String xml) { + String compactXml = xml + .replaceAll(">\\s+<", "><") // 处理标签间的空白 + .replaceAll("\\s+", " "); // 压缩连续空格(可选) + return compactXml; + } + + //发送消息 + public void flushMsgToDevice(String uuid, String clientKey, boolean request, String xml) { + if (ChannelCache.getInstance().get(clientKey) != null) { + if(clientKey.startsWith("areaPatrolServer")) { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } else { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLength); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + allBuf.writeLongLE(sendIndex); + allBuf.writeLongLE(receiveIndex); + allBuf.writeByte(request ? 0x00 : 0x01); + allBuf.writeIntLE(length); + allBuf.writeBytes(byteBuf); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + redisTemplate.opsForValue().set(String.valueOf(sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + upstreamMockNettyServerHandler.sendMsg(uuid, clientKey, allBuf, compact(xml), request); + sendIndex++; + } else { + log.warn(Color.RED + "###### 客户端[{}]离线! ######" + Color.END, clientKey); + } + } + + public void flushMsgToDeviceBroadcast(String uuid, String clientKey, boolean request, String xml) { + for (String client : ChannelCache.getInstance().getClients()) { + if(clientKey.startsWith("areaPatrolServer")) { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } else { + xml = xml.replace("", ""); + xml = xml.replace("", ""); + } + ByteBuf byteBuf = Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8); + int length = byteBuf.readableBytes(); + ByteBuf allBuf = Unpooled.buffer(length + ConfigType.dataLength); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + allBuf.writeLongLE(sendIndex); + allBuf.writeLongLE(receiveIndex); + allBuf.writeByte(request ? 0x00 : 0x01); + allBuf.writeIntLE(length); + allBuf.writeBytes(byteBuf); + allBuf.writeByte(0xEB); + allBuf.writeByte(0x90); + redisTemplate.opsForValue().set(String.valueOf(sendIndex), allBuf.toString(CharsetUtil.US_ASCII), 60L, TimeUnit.SECONDS); + upstreamMockNettyServerHandler.sendMsg(uuid, client, allBuf, compact(xml), request); + sendIndex++; + try { + Thread.sleep(1); + } catch (InterruptedException e) {} + } + } + + //开启线程处理消息 + public void receiveMsg(BinaryModel binaryModel, ChannelHandlerContext context) { +// executorService.execute(() -> { + try { + dealMsgInThreadPool(binaryModel, context); + } catch (Exception e) { + log.error("error", e); + } +// }); + } + + //重新发送 + public void resetSendMsg(long sendIndex, String sendCode) { + // 获取缓存的中的值 + String msg = redisTemplate.opsForValue().get(String.valueOf(sendIndex)); + if (!StringUtil.isNullOrEmpty(msg)) { + ByteBuf allBuf = Unpooled.copiedBuffer(msg, CharsetUtil.US_ASCII); + flushMsgToDevice("", sendCode, true, msg); + } + } + + //处理接收消息 + private void dealMsgInThreadPool(BinaryModel binaryModel, ChannelHandlerContext context) throws DocumentException { + String xml = binaryModel.dataBuf.toString(CharsetUtil.UTF_8); + receiveIndex = binaryModel.sendIndex; + SAXReader saxReader = new SAXReader(); + Document document = saxReader.read(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); + Element root = document.getRootElement(); + String sendCode = root.element("SendCode").getText(); + String receiveCode = root.element("ReceiveCode").getText(); + ChannelCache.getInstance().replace(sendCode, context); + int type = 0; + if (null != root.element("Type") && !StringUtil.isNullOrEmpty(root.element("Type").getText())) { + type = Integer.parseInt(root.element("Type").getText()); + } + int command = 0; + if (null != root.element("Command") && !StringUtil.isNullOrEmpty(root.element("Command").getText())) { + command = Integer.parseInt(root.element("Command").getText()); + } + + String compactXml = compact(xml); +// log.info(Color.YELLOW + "###### 会话:{}, 客户:[{}], 消息类型:{}, 命令:{}, 消息体: ######\n{}" + Color.END, binaryModel.uuid, sendCode, type, command, compactXml); + //判断是否重发 + if (type == SystemType.system) { + if (command == SystemType.has_response || command == SystemType.no_response) { + if (null != root.element("Code")) { + String code = root.element("Code").getText(); + if (code.equals(ResponseType.retry)) { + resetSendMsg(binaryModel.receiveIndex, sendCode); + return; + } else if (code.equals(ResponseType.succeed)) { + log.info(Color.YELLOW + "###### 客户端[{}]响应结果为成功 ######" + Color.END, sendCode); + if(command == SystemType.no_response) { + return; + } + } else if (code.equals(ResponseType.fault)) { + log.warn(Color.RED + "###### 客户端[{}]响应结果为失败 ######" + Color.END, sendCode); + return; + } else if (code.equals(ResponseType.reject)) { + log.warn(Color.RED + "###### 客户端[{}]响应结果为拒绝 ######" + Color.END, sendCode); + return; + } + } + } + } + String json = null; + switch (type) { + case SystemType.system: + switch (command) { + case SystemType.register_request: + // 收到接入侧注册信息 + log.info(Color.YELLOW + "###### 客户端[{}]注册 ######" + Color.END, sendCode); + dealRegister(binaryModel.uuid, compactXml); + break; + case SystemType.heart_request: + // 处理心跳请求响应 + log.info(Color.YELLOW + "###### 客户端[{}]上报心跳 ######" + Color.END, sendCode); + sendHeartBeat(binaryModel.uuid, compactXml); + break; + case SystemType.has_response: + // 处理有返回值的消息响应 + if (null != root.element("Items") && null != root.element("Items").element("Item")) { + // 处理设备上报的模型同步响应 + if (null != root.element("Items").element("Item").attribute("device_file_path")) { + // 收到接入侧模型同步数据 + log.info(Color.YELLOW + "###### 模型同步收到客户端[{}]响应数据 ######" + Color.END, sendCode); + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, ModelControl.class); + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("uuid", binaryModel.uuid); + jsonObject.put("Type", Constant.MODEL_UP_TYPE); + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } + // 任务控制响应任务执行ID + if (null != root.element("Items").element("Item").attribute("task_patrolled_id")) { + // 收到接入侧任务下发或控制回复数据 + log.info(Color.YELLOW + "###### 任务下发收到客户端[{}]响应数据 ######" + Color.END, sendCode); + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, ModelControl.class); + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("SendCode", ""); + clientController.sendMsg(binaryModel.uuid, jsonObject.toJSONString()); + } + } else { + log.warn(Color.RED + "###### 客户端[{}]响应数据没有items ######" + Color.END, sendCode); + } + break; + default: + log.warn(Color.RED + "###### 客户端[{}]非法的消息不予处理 ######" + Color.END, sendCode); + } + break; + case PushType.patrolDeviceState:// insert into basedata_mont_patdevstadata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, PatrolDeviceStateControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备状态数据 ######" + Color.END, sendCode); + break; + case PushType.patrolDeviceRunning:// insert into basedata_mont_patdevrundata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, PatrolDeviceRunningControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备运行数据 ######" + Color.END, sendCode); + break; + case PushType.nestState:// insert into basedata_mont_neststadata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, NestStateControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报机巢状态数据 ######" + Color.END, sendCode); + break; + case PushType.nestRunning:// insert into basedata_mont_nestrundata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, NestRunningControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报机巢运行数据 ######" + Color.END, sendCode); + break; + case PushType.location:// insert into basedata_mont_patdevcoord + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, LocationControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备坐标 ######" + Color.END, sendCode); + break; + case PushType.route:// insert into basedata_mont_patdevpatroute + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, RouteControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备路线 ######" + Color.END, sendCode); + break; + case PushType.alarm:// insert into basedata_mont_patdevalmabn + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, AlarmControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备异常告警 ######" + Color.END, sendCode); + break; + case PushType.environment:// insert into basedata_mont_evndata + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, EnvironmentControl.class); + log.info(Color.YELLOW + "###### 客户端[{}]上报设备环境数据 ######" + Color.END, sendCode); + break; + case PushType.taskState:// insert into basedata_mont_taskstadata and patrol_task_status + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, TaskStateControl.class); + //root@Linx:/home/atia/data/log/inspect-main# grep -rn "type:41, messageBody:" info.log + log.info(Color.YELLOW + "###### 客户端[{}]上报设备任务状态 ######" + Color.END, sendCode); + break; + case PushType.result:// insert into basedata_mont_taskresult and patrol_task_result_main + json = downXml2Json.DownStreamJson2Xml(binaryModel.uuid, binaryModel.id, compactXml, TaskResultControl.class); + //root@Linx:/home/atia/data/log/inspect-main# grep -rn "type:61, messageBody:" info.log + log.info(Color.YELLOW + "###### 客户端[{}]上报巡视结果 ######" + Color.END, sendCode); + break; + default: + log.info(Color.RED + "###### 客户端[{}]上报的非法消息不予处理 ######" + Color.END, sendCode); + } + if (type != SystemType.system && !StringUtil.isNullOrEmpty(json)) { + if ((type == NestCtlType.courseReversal && command == 3)) { // 处理用SSCOM模拟的数据, 向无人机发送控制指令 + log.info("###### 向客户端[{}]透传200001控制指令 ######", sendCode); + flushMsgToDeviceBroadcast(binaryModel.uuid, receiveCode, false, compactXml); + } else { + JSONObject jsonObject = JSONObject.parseObject(json); + jsonObject.put("uuid", binaryModel.uuid); + json = jsonObject.toJSONString(); + // send to BasedataMontDataMqAcceptHandle + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, json); + boolean isHost = json.contains(aliasHost); + sendResponseToDevice(binaryModel.uuid, receiveCode, sendCode, isHost); + } + } else { + if ((type == NestCtlType.suddenStop && command == 7) + || (type == NestCtlType.ptzPitch && command == 6) + || (type == NestCtlType.picModelSet && command == 1) + || (type == NestCtlType.nestSuddenStop && command == 2)) {// 处理用SSCOM模拟的数据, 向无人机发送控制指令 + log.info("###### 向客户端[{}]透传200002~20005控制指令 ######", sendCode); + flushMsgToDeviceBroadcast(binaryModel.uuid, receiveCode, false, compactXml); + } + } + } + + public void sendResponseToDevice(String uuid, String sendCode, String receiveCode, boolean isHost) { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(isHost ? aliasHost : aliasDevice, ResponseControl.class); + xStream.autodetectAnnotations(true); + ResponseControl responseControl = new ResponseControl(); + responseControl.SendCode = sendCode; + responseControl.ReceiveCode = receiveCode; + responseControl.Type = String.valueOf(SystemType.system); + responseControl.Code = ResponseType.succeed; + responseControl.Command = String.valueOf(SystemType.no_response); + responseControl.Time = CommonUtils.GetNowDateString(); + responseControl.Items = ""; + String xml = xStream.toXML(responseControl); + flushMsgToDevice(uuid, receiveCode, false, xml); + } + + //处理注册应答 + public void dealRegister(String uuid, String xml) { + BaseControl obj = new BaseControl(); + try { + XStream xStream = getXmlStreamInstance(); + xStream.alias(aliasHost, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStreamEx = getXmlStreamInstance(); + xStreamEx.alias(aliasDevice, BaseControl.class); + xStreamEx.autodetectAnnotations(true); + xStreamEx.ignoreUnknownElements(); + xStreamEx.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStreamEx.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### dealRegister解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + + RegisterResponseControl responseControl = new RegisterResponseControl(); + responseControl.SendCode = obj.ReceiveCode; + responseControl.ReceiveCode = obj.SendCode; + responseControl.Type = String.valueOf(SystemType.system); + responseControl.Command = String.valueOf(SystemType.has_response); + responseControl.Time = CommonUtils.GetNowDateString(); + + // 调用基础服务鉴权设备 + if (authDevice(obj.SendCode)) { + //鉴权通过 + responseControl.Code = ResponseType.succeed; + responseControl.Items = new ArrayList<>(); + RegisterResponseModel model = new RegisterResponseModel(); + model.patroldevice_run_interval = ConfigType.patroldevice_run_interval; + model.heart_beat_interval = ConfigType.heart_beat_interval; + model.env_interval = ConfigType.env_interval; + //model.weather_interval= ConfigType.weather_interval; + + // 当连接客户端为无人机机巢时,报文中增加机巢运行数据上报间隔 + if (obj.SendCode.equals(deviceServerProperties.nestCode)) { + model.nest_run_interval = ConfigType.nest_run_interval; + } + responseControl.Items.add(model); + + // 推送消息到mq + JSONObject jsonObject = new JSONObject(); + jsonObject.put("uuid", uuid); + jsonObject.put("patroldevice_code", obj.SendCode); + jsonObject.put("SendCode", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "connect"); + jsonObject.put("HeartBeatInterval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } else { + // 鉴权不通过 + responseControl.Code = ResponseType.fault; + } + sendRegisterResponse(uuid, responseControl, obj.SendCode); + } + + private XStream getXmlStreamInstance() { + return new XStream(new Xpp3Driver(new NoNameCoder())); + } + + /** + * 鉴权巡视设备 + * + * @param sendCode 巡视设备(机器人、无人机)唯一标识 + * @return + */ + public boolean authDevice(String sendCode) { + return true; + } + + public void sendRegisterResponse(String uuid, RegisterResponseControl responseControl, String sendCode) { + String xml = ""; + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasHost, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + xml = xStream.toXML(responseControl); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasDevice, RegisterResponseControl.class); + xStream.autodetectAnnotations(true); + xml = xStream.toXML(responseControl); + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### sendRegisterResponse解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + flushMsgToDevice(uuid, sendCode, false, xml); + } + + public void sendHeartBeat(final String uuid, String xml) { + boolean isHost = true; + BaseControl obj = new BaseControl(); + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasHost, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + } catch (com.thoughtworks.xstream.XStreamException e) { + try { + XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder())); + xStream.alias(aliasDevice, BaseControl.class); + xStream.autodetectAnnotations(true); + xStream.ignoreUnknownElements(); + xStream.addPermission(AnyTypePermission.ANY); + obj = (BaseControl) xStream.fromXML(xml); + isHost = false; + } catch (com.thoughtworks.xstream.XStreamException e2) { + log.error(Color.RED + "###### sendHeartBeat解析失败:{} ######" + Color.END, e2.getMessage()); + } + } + + sendResponseToDevice(uuid, obj.ReceiveCode, obj.SendCode, isHost); + + // 推送消息到mq + JSONObject jsonObject = new JSONObject(); + jsonObject.put("uuid", uuid); + jsonObject.put("SendCode", obj.SendCode); + jsonObject.put("Type", "heartbeat"); + jsonObject.put("eventType", "heart"); + jsonObject.put("HeartBeatInterval", ConfigType.heart_beat_interval); + + rabbitTemplate.convertAndSend(Constant.EX_CHANGE_NAME, Constant.ROUTING_KEY_NAME, jsonObject.toJSONString()); + } + + public void sendXmlMessage(JSONObject obj) { + int type = obj.getInteger("Type"); + String receiveCode = obj.getString("ReceiveCode"); + String json = obj.toJSONString(); + + String xml = null; + switch (type) { + case RobotType.robotVl: + case RobotType.robot: + case RobotType.robotCar: + case RobotType.robotFz: + case RobotType.robotIr: + case RobotType.robotPtz: + xml = upJson2Xml.UpStreamJson2Xml(json, RobotControl.class); + break; + case UAVType.uav: + case UAVType.uavXj: + case UAVType.uavKz: + case UAVType.uavYt: + case UAVType.nest: + xml = upJson2Xml.UpStreamJson2Xml(json, RobotControl.class); + break; + case TaskType.taskControl: + xml = upJson2Xml.UpStreamJson2Xml(json, ResponseControl.class); + break; + case TaskType.taskSend: + xml = upJson2Xml.UpStreamJson2Xml(json, TaskSendControl.class); + break; + case TaskType.taskArea: + xml = upJson2Xml.UpStreamJson2Xml(json, AreaControl.class); + break; + case ModelType.modelSync: + xml = upJson2Xml.UpStreamJson2Xml(json, ResponseControl.class); + break; + case TaskType.lendonTask: + xml = upJson2Xml.UpStreamJson2Xml(json, LinkageTaskControl.class); + break; + default: + log.error(Color.RED + "###### 向设备端下发命令, 类型:{}错误, 不予处理 ######" + Color.END, type); + + } + if (!StringUtils.isEmpty(xml)) { + flushMsgToDevice("", receiveCode, true, xml); + } else { + log.error(Color.RED + "###### xml is empty ######" + Color.END, type); + } + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java new file mode 100644 index 0000000..8b03c65 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamMockNettyServerHandler.java @@ -0,0 +1,92 @@ +package com.inspect.upstream.tcp; + +import com.inspect.upstream.util.Color; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UpstreamMockNettyServerHandler extends ChannelInboundHandlerAdapter { + private UpstreamMockNettyServer upstreamMockNettyServer; + + public UpstreamMockNettyServerHandler(UpstreamMockNettyServer upstreamMockNettyServer) { + this.upstreamMockNettyServer = upstreamMockNettyServer; + } + + public void sendMsg(String uuid, String clientKey, ByteBuf byteBuf, String xml, boolean request) { + ChannelHandlerContext ctx = ChannelCache.getInstance().get(clientKey); + if(ctx != null) { + ctx.writeAndFlush(Unpooled.wrappedBuffer(byteBuf)).addListener( + (ChannelFuture future) -> { + if (future.isSuccess()) { + if(request) { + log.info("###### 活动连接:{}, 向客户端[{}]下发消息成功:{} ######", ChannelCache.getInstance().getClients(), clientKey, xml); + } else { + log.info(Color.CYAN + "###### 活动连接:{}, 向客户端[{}]响应成功 ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } else { + if(request) { + log.error(Color.RED + "###### 活动连接:{}, 向客户端[{}]下发消息失败:{} ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey, xml); + } else { + log.error(Color.RED + "###### 活动连接:{}, 向客户端[{}]响应失败 ######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } + }); + } else { + if(request) { + log.error(Color.RED + "###### 活动连接:{},无法向客户端[{}]下发消息,ctx==null######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } else { + log.error(Color.RED + "###### 活动连接:{},无法向客户端[{}]响应,ctx==null######" + Color.END, ChannelCache.getInstance().getClients(), clientKey); + } + } + } + + /** + * 客户端连接会触发 + */ + @Override + public void channelActive(ChannelHandlerContext ctx) { + String id = ctx.channel().id().asShortText(); + ChannelCache.getInstance().addIfAbsent(id, ctx); + log.info("###### 设备上线:{} ######", id); + } + + /** + * 客户端断开会触发 + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) { + String id = ctx.channel().id().asShortText(); + log.info("###### 设备断开:{} ######", id); + ChannelCache.getInstance().remove(ctx); + } + + /** + * 客户端发消息会触发 + */ + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + String id = ctx.channel().id().asShortText(); + BinaryModel binaryModel = (BinaryModel) msg; + binaryModel.id = id; + upstreamMockNettyServer.receiveMsg((BinaryModel) msg, ctx); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + super.userEventTriggered(ctx, evt); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error( "channel ctx: " + ctx.channel() + " exception", cause); + } +} diff --git a/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java b/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java new file mode 100644 index 0000000..bf8e930 --- /dev/null +++ b/src/main/java/com/inspect/upstream/tcp/UpstreamServerStart.java @@ -0,0 +1,22 @@ +package com.inspect.upstream.tcp; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; + +@Slf4j +@ConditionalOnProperty(name = "boot.server", havingValue = "true") +@Configuration +public class UpstreamServerStart implements CommandLineRunner { + + @Resource + UpstreamMockNettyServer upstreamMockNettyServer; + + @Override + public void run(String... args) throws Exception { + upstreamMockNettyServer.startServer(); + } +} diff --git a/src/main/java/com/inspect/upstream/util/Color.java b/src/main/java/com/inspect/upstream/util/Color.java new file mode 100644 index 0000000..ea27310 --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/Color.java @@ -0,0 +1,11 @@ +package com.inspect.upstream.util; + +public class Color { + public static final String END = "\033[0m"; + public static final String RED = "\033[31m"; + public static final String GREEN = "\033[32m"; + public static final String YELLOW = "\033[33m"; + public static final String BLUE = "\033[34m"; + public static final String MAGENTA = "\033[35m"; + public static final String CYAN = "\033[36m"; +} diff --git a/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java b/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java new file mode 100644 index 0000000..665bebe --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/FastJson2JsonRedisSerializer.java @@ -0,0 +1,58 @@ +package com.inspect.upstream.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; +import org.springframework.util.Assert; + +import java.nio.charset.Charset; + +public class FastJson2JsonRedisSerializer implements RedisSerializer { + @SuppressWarnings("unused") + private ObjectMapper objectMapper = new ObjectMapper(); + + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + static { + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + } + + public FastJson2JsonRedisSerializer(Class clazz) { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException { + if (t == null) { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException { + if (bytes == null || bytes.length <= 0) { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz); + } + + public void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "'objectMapper' must not be null"); + this.objectMapper = objectMapper; + } + + protected JavaType getJavaType(Class clazz) { + return TypeFactory.defaultInstance().constructType(clazz); + } +} diff --git a/src/main/java/com/inspect/upstream/util/HexUtils.java b/src/main/java/com/inspect/upstream/util/HexUtils.java new file mode 100644 index 0000000..c83c056 --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/HexUtils.java @@ -0,0 +1,16 @@ +package com.inspect.upstream.util; + +import org.apache.commons.codec.binary.Hex; + +import java.nio.charset.Charset; + +public class HexUtils { + public static String ascii2hex(String str) { + return convertStringToHex(str, "UTF8"); + } + + public static String convertStringToHex(String str, String charsetName) { + char[] chars = Hex.encodeHex(str.getBytes(Charset.forName(charsetName))); + return String.valueOf(chars); + } +} diff --git a/src/main/java/com/inspect/upstream/util/ProtoDef.java b/src/main/java/com/inspect/upstream/util/ProtoDef.java new file mode 100644 index 0000000..f9f152d --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/ProtoDef.java @@ -0,0 +1,86 @@ +package com.inspect.upstream.util; + +import javolution.io.Struct; +import org.apache.commons.codec.binary.Hex; + +import java.nio.ByteOrder; + +public class ProtoDef extends Struct { + Unsigned16 mark = new Unsigned16(); + Signed64 sendSeq = new Signed64(); + Signed64 recvSeq = new Signed64(); + Signed8 session = new Signed8(); + Signed32 xmlLength = new Signed32(); + + //一定要加上这个,不然会出现对齐的问题 + @Override + public boolean isPacked() { + return true; + } + + //设置为小端格式 + @Override + public ByteOrder byteOrder() { + return ByteOrder.LITTLE_ENDIAN; + } + + //测试 + public static void main(String[] args) { + String xml = +// "\n" + +// " INSPECT-SERVER-001\n" + +// " DRONE-001\n" + +// " 20001\n" + +// " DRONE-001\n" + +// " 3\n" + +// " \n" + +// " \n" + +// ""; + +// "\n" + +// " G100-001\n" + +// " L100-001\n" + +// " 61\n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// " \n" + +// ""; + + "\n" + + "\n" + + " G100-001\n" + + " L100-001\n" + + " 61\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + String dataHex = HexUtils.ascii2hex(xml); + int length = dataHex.length() / 2; + + ProtoDef proto = new ProtoDef(); + proto.mark.set(0x90EB); + proto.sendSeq.set(0x3c); + proto.recvSeq.set(0x39); + proto.session.set((byte)0); + proto.xmlLength.set(length); + + byte[] bytes = new byte[proto.getByteBuffer().limit()]; + proto.getByteBuffer().get(bytes); + String protoHex = Hex.encodeHexString(bytes, true); + + System.out.println(protoHex + dataHex + "eb90"); + } +} diff --git a/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java b/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java new file mode 100644 index 0000000..33476fd --- /dev/null +++ b/src/main/java/com/inspect/upstream/util/SpringApplicationContext.java @@ -0,0 +1,46 @@ +package com.inspect.upstream.util; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; + +@Service +public class SpringApplicationContext implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + SpringApplicationContext.applicationContext = applicationContext; + } + + public static ApplicationContext getApplicationContext() { + checkApplicationContext(); + return applicationContext; + } + + @SuppressWarnings("unchecked") + public static T getBean(String name) { + checkApplicationContext(); + return (T) applicationContext.getBean(name); + } + + @SuppressWarnings("unchecked") + public static T getBean(Class clazz) { + checkApplicationContext(); + return (T) applicationContext.getBeansOfType(clazz); + } + + + public static void cleanApplicationContext() { + applicationContext = null; + } + + private static void checkApplicationContext() { + if (applicationContext == null) { + throw new IllegalStateException( + "applicationContext未注入,请在spring的context.xml中定义SpringContextHolder"); + } + } + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..badf004 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,41 @@ +spring: + application: + name: upstream + redis: + host: 127.0.0.1 + + rabbitmq: + host: 10.10.18.13 + port: 5673 + username: guest + password: guest + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.66" + robotCode: "E100-001" + nestCode: "UAV001" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 127.0.0.1 + serverPort: 10012 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://127.0.0.1:9901/client/send + authDevice: + url: http://127.0.0.1:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: false + server: true + diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..843532a --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.66" + robotCode: "192.168.1.15" + nestCode: "192.168.1.16" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 192.168.1.99 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: false + server: true + diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..20a5447 --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "INSPECT-SERVER-001" + robotCode: "DRONE-001" + nestCode: "NEST-001" + deviceCode: "DRONE-001" + +upSystemServer: + serverIp: 10.10.18.100 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "INSPECT-SERVER-001" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: true + server: true + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..72de509 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,42 @@ +spring: + application: + name: upstream + redis: + host: 199.199.199.1 + + rabbitmq: + host: 199.199.199.4 + port: 5672 + username: guest + password: guest + + +server: + port: 22508 + +deviceServer: + serverIp: 127.0.0.1 + serverPort: 10011 + deviceServerCode: "192.168.1.116" + robotCode: "192.168.1.15" + nestCode: "192.168.1.16" + deviceCode: "192.168.1.15" + +upSystemServer: + serverIp: 10.10.18.100 + serverPort: 10011 + upCode: "192.168.1.99" + iipCode: "192.168.1.66" + +iip_server: + send: + url: http://199.199.199.104:9901/client/send + authDevice: + url: http://199.199.199.105:9902/eqpbook/checkPatrolDeviceIsExist/%s + +up_time_interval_setting: time_interval_up_system_setting + +boot: + client: true + server: true + diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..a466703 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/info.log + + + + ${log.path}/info/info.%d{yyyy-MM-dd}.%i.log + ${log.maxFileSize} + + ${log.maxHistory} + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/error.log + + + + ${log.path}/error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java b/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java new file mode 100644 index 0000000..b426d32 --- /dev/null +++ b/src/test/java/com/inspect/upstream/InspectUpstreamApplicationTests.java @@ -0,0 +1,13 @@ +package com.inspect.upstream; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class InspectUpstreamApplicationTests { + + @Test + void contextLoads() { + } + +}