diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/common/WebSocketConsts.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/common/WebSocketConsts.java new file mode 100644 index 0000000..8b577e2 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/common/WebSocketConsts.java @@ -0,0 +1,18 @@ +package com.xkcoding.websocket.common; + +/** + *

+ * WebSocket常量 + *

+ * + * @package: com.xkcoding.websocket.common + * @description: WebSocket常量 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:01 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public interface WebSocketConsts { + String PUSH_SERVER = "/topic/server"; +} diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/config/WebSocketConfig.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/config/WebSocketConfig.java new file mode 100644 index 0000000..47de6d4 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/config/WebSocketConfig.java @@ -0,0 +1,43 @@ +package com.xkcoding.websocket.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +/** + *

+ * WebSocket配置 + *

+ * + * @package: com.xkcoding.websocket.config + * @description: WebSocket配置 + * @author: yangkai.shen + * @date: Created in 2018-12-14 15:58 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Configuration +@EnableWebSocket +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + // 注册一个 /notification 端点,前端通过这个端点进行连接 + registry.addEndpoint("/notification") + //解决跨域问题 + .setAllowedOrigins("*") + .withSockJS(); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + //定义了一个客户端订阅地址的前缀信息,也就是客户端接收服务端发送消息的前缀信息 + registry.enableSimpleBroker("/topic"); + } + +} diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/Server.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/Server.java new file mode 100644 index 0000000..8d51a73 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/Server.java @@ -0,0 +1,220 @@ +package com.xkcoding.websocket.model; + +import cn.hutool.core.util.NumberUtil; +import com.xkcoding.websocket.model.server.*; +import com.xkcoding.websocket.util.IpUtil; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.CentralProcessor.TickType; +import oshi.hardware.GlobalMemory; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.Util; + +import java.net.UnknownHostException; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +/** + *

+ * 服务器相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model + * @description: 服务器相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class Server { + + private static final int OSHI_WAIT_SECOND = 1000; + + /** + * CPU相关信息 + */ + private Cpu cpu = new Cpu(); + + /** + * 內存相关信息 + */ + private Mem mem = new Mem(); + + /** + * JVM相关信息 + */ + private Jvm jvm = new Jvm(); + + /** + * 服务器相关信息 + */ + private Sys sys = new Sys(); + + /** + * 磁盘相关信息 + */ + private List sysFiles = new LinkedList(); + + public Cpu getCpu() { + return cpu; + } + + public void setCpu(Cpu cpu) { + this.cpu = cpu; + } + + public Mem getMem() { + return mem; + } + + public void setMem(Mem mem) { + this.mem = mem; + } + + public Jvm getJvm() { + return jvm; + } + + public void setJvm(Jvm jvm) { + this.jvm = jvm; + } + + public Sys getSys() { + return sys; + } + + public void setSys(Sys sys) { + this.sys = sys; + } + + public List getSysFiles() { + return sysFiles; + } + + public void setSysFiles(List sysFiles) { + this.sysFiles = sysFiles; + } + + public void copyTo() throws Exception { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + + setCpuInfo(hal.getProcessor()); + + setMemInfo(hal.getMemory()); + + setSysInfo(); + + setJvmInfo(); + + setSysFiles(si.getOperatingSystem()); + } + + /** + * 设置CPU信息 + */ + private void setCpuInfo(CentralProcessor processor) { + // CPU信息 + long[] prevTicks = processor.getSystemCpuLoadTicks(); + Util.sleep(OSHI_WAIT_SECOND); + long[] ticks = processor.getSystemCpuLoadTicks(); + long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()]; + long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()]; + long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()]; + long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()]; + long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()]; + long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()]; + long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()]; + long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()]; + long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal; + cpu.setCpuNum(processor.getLogicalProcessorCount()); + cpu.setTotal(totalCpu); + cpu.setSys(cSys); + cpu.setUsed(user); + cpu.setWait(iowait); + cpu.setFree(idle); + } + + /** + * 设置内存信息 + */ + private void setMemInfo(GlobalMemory memory) { + mem.setTotal(memory.getTotal()); + mem.setUsed(memory.getTotal() - memory.getAvailable()); + mem.setFree(memory.getAvailable()); + } + + /** + * 设置服务器信息 + */ + private void setSysInfo() { + Properties props = System.getProperties(); + sys.setComputerName(IpUtil.getHostName()); + sys.setComputerIp(IpUtil.getHostIp()); + sys.setOsName(props.getProperty("os.name")); + sys.setOsArch(props.getProperty("os.arch")); + sys.setUserDir(props.getProperty("user.dir")); + } + + /** + * 设置Java虚拟机 + */ + private void setJvmInfo() throws UnknownHostException { + Properties props = System.getProperties(); + jvm.setTotal(Runtime.getRuntime().totalMemory()); + jvm.setMax(Runtime.getRuntime().maxMemory()); + jvm.setFree(Runtime.getRuntime().freeMemory()); + jvm.setVersion(props.getProperty("java.version")); + jvm.setHome(props.getProperty("java.home")); + } + + /** + * 设置磁盘信息 + */ + private void setSysFiles(OperatingSystem os) { + FileSystem fileSystem = os.getFileSystem(); + OSFileStore[] fsArray = fileSystem.getFileStores(); + for (OSFileStore fs : fsArray) { + long free = fs.getUsableSpace(); + long total = fs.getTotalSpace(); + long used = total - free; + SysFile sysFile = new SysFile(); + sysFile.setDirName(fs.getMount()); + sysFile.setSysTypeName(fs.getType()); + sysFile.setTypeName(fs.getName()); + sysFile.setTotal(convertFileSize(total)); + sysFile.setFree(convertFileSize(free)); + sysFile.setUsed(convertFileSize(used)); + sysFile.setUsage(NumberUtil.mul(NumberUtil.div(used, total, 4), 100)); + sysFiles.add(sysFile); + } + } + + /** + * 字节转换 + * + * @param size 字节大小 + * @return 转换后值 + */ + public String convertFileSize(long size) { + long kb = 1024; + long mb = kb * 1024; + long gb = mb * 1024; + if (size >= gb) { + return String.format("%.1f GB", (float) size / gb); + } else if (size >= mb) { + float f = (float) size / mb; + return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); + } else if (size >= kb) { + float f = (float) size / kb; + return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); + } else { + return String.format("%d B", size); + } + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Cpu.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Cpu.java new file mode 100644 index 0000000..d84cb19 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Cpu.java @@ -0,0 +1,101 @@ +package com.xkcoding.websocket.model.server; + +import cn.hutool.core.util.NumberUtil; + +/** + *

+ * CPU相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model.server + * @description: CPU相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class Cpu { + /** + * 核心数 + */ + private int cpuNum; + + /** + * CPU总的使用率 + */ + private double total; + + /** + * CPU系统使用率 + */ + private double sys; + + /** + * CPU用户使用率 + */ + private double used; + + /** + * CPU当前等待率 + */ + private double wait; + + /** + * CPU当前空闲率 + */ + private double free; + + public int getCpuNum() { + return cpuNum; + } + + public void setCpuNum(int cpuNum) { + this.cpuNum = cpuNum; + } + + public double getTotal() { + return NumberUtil.round(NumberUtil.mul(total, 100), 2) + .doubleValue(); + } + + public void setTotal(double total) { + this.total = total; + } + + public double getSys() { + return NumberUtil.round(NumberUtil.mul(sys / total, 100), 2) + .doubleValue(); + } + + public void setSys(double sys) { + this.sys = sys; + } + + public double getUsed() { + return NumberUtil.round(NumberUtil.mul(used / total, 100), 2) + .doubleValue(); + } + + public void setUsed(double used) { + this.used = used; + } + + public double getWait() { + return NumberUtil.round(NumberUtil.mul(wait / total, 100), 2) + .doubleValue(); + } + + public void setWait(double wait) { + this.wait = wait; + } + + public double getFree() { + return NumberUtil.round(NumberUtil.mul(free / total, 100), 2) + .doubleValue(); + } + + public void setFree(double free) { + this.free = free; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Jvm.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Jvm.java new file mode 100644 index 0000000..a0b770b --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Jvm.java @@ -0,0 +1,133 @@ +package com.xkcoding.websocket.model.server; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.NumberUtil; + +import java.lang.management.ManagementFactory; +import java.util.Date; + +/** + *

+ * JVM相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model.server + * @description: JVM相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class Jvm { + /** + * 当前JVM占用的内存总数(M) + */ + private double total; + + /** + * JVM最大可用内存总数(M) + */ + private double max; + + /** + * JVM空闲内存(M) + */ + private double free; + + /** + * JDK版本 + */ + private String version; + + /** + * JDK路径 + */ + private String home; + + /** + * JDK启动时间 + */ + private String startTime; + + /** + * JDK运行时间 + */ + private String runTime; + + public double getTotal() { + return NumberUtil.div(total, (1024 * 1024), 2); + } + + public void setTotal(double total) { + this.total = total; + } + + public double getMax() { + return NumberUtil.div(max, (1024 * 1024), 2); + } + + public void setMax(double max) { + this.max = max; + } + + public double getFree() { + return NumberUtil.div(free, (1024 * 1024), 2); + } + + public void setFree(double free) { + this.free = free; + } + + public double getUsed() { + return NumberUtil.div(total - free, (1024 * 1024), 2); + } + + public double getUsage() { + return NumberUtil.mul(NumberUtil.div(total - free, total, 4), 100); + } + + /** + * 获取JDK名称 + */ + public String getName() { + return ManagementFactory.getRuntimeMXBean() + .getVmName(); + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getHome() { + return home; + } + + public void setHome(String home) { + this.home = home; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getStartTime() { + return DateUtil.formatDateTime(new Date(ManagementFactory.getRuntimeMXBean() + .getStartTime())); + } + + + public void setRunTime(String runTime) { + this.runTime = runTime; + } + + public String getRunTime() { + long startTime = ManagementFactory.getRuntimeMXBean() + .getStartTime(); + return DateUtil.formatBetween(DateUtil.current(false) - startTime); + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Mem.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Mem.java new file mode 100644 index 0000000..0b72bf4 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Mem.java @@ -0,0 +1,61 @@ +package com.xkcoding.websocket.model.server; + +import cn.hutool.core.util.NumberUtil; + +/** + *

+ * 內存相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model.server + * @description: 內存相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:09 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class Mem { + /** + * 内存总量 + */ + private double total; + + /** + * 已用内存 + */ + private double used; + + /** + * 剩余内存 + */ + private double free; + + public double getTotal() { + return NumberUtil.div(total, (1024 * 1024 * 1024), 2); + } + + public void setTotal(long total) { + this.total = total; + } + + public double getUsed() { + return NumberUtil.div(used, (1024 * 1024 * 1024), 2); + } + + public void setUsed(long used) { + this.used = used; + } + + public double getFree() { + return NumberUtil.div(free, (1024 * 1024 * 1024), 2); + } + + public void setFree(long free) { + this.free = free; + } + + public double getUsage() { + return NumberUtil.mul(NumberUtil.div(used, total, 4), 100); + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Sys.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Sys.java new file mode 100644 index 0000000..f2321cb --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/Sys.java @@ -0,0 +1,81 @@ +package com.xkcoding.websocket.model.server; + +/** + *

+ * 系统相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model.server + * @description: 系统相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:10 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class Sys { + /** + * 服务器名称 + */ + private String computerName; + + /** + * 服务器Ip + */ + private String computerIp; + + /** + * 项目路径 + */ + private String userDir; + + /** + * 操作系统 + */ + private String osName; + + /** + * 系统架构 + */ + private String osArch; + + public String getComputerName() { + return computerName; + } + + public void setComputerName(String computerName) { + this.computerName = computerName; + } + + public String getComputerIp() { + return computerIp; + } + + public void setComputerIp(String computerIp) { + this.computerIp = computerIp; + } + + public String getUserDir() { + return userDir; + } + + public void setUserDir(String userDir) { + this.userDir = userDir; + } + + public String getOsName() { + return osName; + } + + public void setOsName(String osName) { + this.osName = osName; + } + + public String getOsArch() { + return osArch; + } + + public void setOsArch(String osArch) { + this.osArch = osArch; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/SysFile.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/SysFile.java new file mode 100644 index 0000000..823cf75 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/model/server/SysFile.java @@ -0,0 +1,107 @@ +package com.xkcoding.websocket.model.server; + +/** + *

+ * 系统文件相关信息实体 + *

+ * + * @package: com.xkcoding.websocket.model.server + * @description: 系统文件相关信息实体 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:10 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class SysFile { + /** + * 盘符路径 + */ + private String dirName; + + /** + * 盘符类型 + */ + private String sysTypeName; + + /** + * 文件类型 + */ + private String typeName; + + /** + * 总大小 + */ + private String total; + + /** + * 剩余大小 + */ + private String free; + + /** + * 已经使用量 + */ + private String used; + + /** + * 资源的使用率 + */ + private double usage; + + public String getDirName() { + return dirName; + } + + public void setDirName(String dirName) { + this.dirName = dirName; + } + + public String getSysTypeName() { + return sysTypeName; + } + + public void setSysTypeName(String sysTypeName) { + this.sysTypeName = sysTypeName; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public String getTotal() { + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + public String getFree() { + return free; + } + + public void setFree(String free) { + this.free = free; + } + + public String getUsed() { + return used; + } + + public void setUsed(String used) { + this.used = used; + } + + public double getUsage() { + return usage; + } + + public void setUsage(double usage) { + this.usage = usage; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/KV.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/KV.java new file mode 100644 index 0000000..2db7086 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/KV.java @@ -0,0 +1,33 @@ +package com.xkcoding.websocket.payload; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + *

+ * 键值匹配 + *

+ * + * @package: com.xkcoding.websocket.payload + * @description: 键值匹配 + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:41 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class KV { + /** + * 键 + */ + private String key; + + /** + * 值 + */ + private Object value; +} diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/ServerVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/ServerVO.java new file mode 100644 index 0000000..d36b38a --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/ServerVO.java @@ -0,0 +1,39 @@ +package com.xkcoding.websocket.payload; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.Server; +import com.xkcoding.websocket.payload.server.*; +import lombok.Data; + +import java.util.List; + +/** + *

+ * 服务器信息VO + *

+ * + * @package: com.xkcoding.websocket.payload + * @description: 服务器信息VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:25 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class ServerVO { + List cpu = Lists.newArrayList(); + List jvm = Lists.newArrayList(); + List mem = Lists.newArrayList(); + List sysFile = Lists.newArrayList(); + List sys = Lists.newArrayList(); + + public ServerVO create(Server server) { + cpu.add(CpuVO.create(server.getCpu())); + jvm.add(JvmVO.create(server.getJvm())); + mem.add(MemVO.create(server.getMem())); + sysFile.add(SysFileVO.create(server.getSysFiles())); + sys.add(SysVO.create(server.getSys())); + return null; + } +} diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/CpuVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/CpuVO.java new file mode 100644 index 0000000..8cd3258 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/CpuVO.java @@ -0,0 +1,37 @@ +package com.xkcoding.websocket.payload.server; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.server.Cpu; +import com.xkcoding.websocket.payload.KV; +import lombok.Data; + +import java.util.List; + +/** + *

+ * CPU相关信息实体VO + *

+ * + * @package: com.xkcoding.websocket.payload.server + * @description: CPU相关信息实体VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:27 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class CpuVO { + List data = Lists.newArrayList(); + + public static CpuVO create(Cpu cpu) { + CpuVO vo = new CpuVO(); + vo.data.add(new KV("核心数", cpu.getCpuNum())); + vo.data.add(new KV("CPU总的使用率", cpu.getTotal())); + vo.data.add(new KV("CPU系统使用率", cpu.getSys())); + vo.data.add(new KV("CPU用户使用率", cpu.getUsed())); + vo.data.add(new KV("CPU当前等待率", cpu.getWait())); + vo.data.add(new KV("CPU当前空闲率", cpu.getFree())); + return vo; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/JvmVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/JvmVO.java new file mode 100644 index 0000000..bc2940c --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/JvmVO.java @@ -0,0 +1,39 @@ +package com.xkcoding.websocket.payload.server; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.server.Jvm; +import com.xkcoding.websocket.payload.KV; +import lombok.Data; + +import java.util.List; + +/** + *

+ * JVM相关信息实体VO + *

+ * + * @package: com.xkcoding.websocket.payload.server + * @description: JVM相关信息实体VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:28 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class JvmVO { + List data = Lists.newArrayList(); + + public static JvmVO create(Jvm jvm) { + JvmVO vo = new JvmVO(); + vo.data.add(new KV("当前JVM占用的内存总数(M)", jvm.getTotal())); + vo.data.add(new KV("JVM最大可用内存总数(M)", jvm.getMax())); + vo.data.add(new KV("JVM空闲内存(M)", jvm.getFree())); + vo.data.add(new KV("JDK版本", jvm.getVersion())); + vo.data.add(new KV("JDK路径", jvm.getHome())); + vo.data.add(new KV("JDK启动时间", jvm.getStartTime())); + vo.data.add(new KV("JDK运行时间", jvm.getRunTime())); + return vo; + } + +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/MemVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/MemVO.java new file mode 100644 index 0000000..b580e15 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/MemVO.java @@ -0,0 +1,34 @@ +package com.xkcoding.websocket.payload.server; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.server.Mem; +import com.xkcoding.websocket.payload.KV; +import lombok.Data; + +import java.util.List; + +/** + *

+ * 內存相关信息实体VO + *

+ * + * @package: com.xkcoding.websocket.payload.server + * @description: 內存相关信息实体VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:28 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class MemVO { + List data = Lists.newArrayList(); + + public static MemVO create(Mem mem) { + MemVO vo = new MemVO(); + vo.data.add(new KV("内存总量", mem.getTotal())); + vo.data.add(new KV("已用内存", mem.getUsed())); + vo.data.add(new KV("剩余内存", mem.getFree())); + return vo; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysFileVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysFileVO.java new file mode 100644 index 0000000..1f4429a --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysFileVO.java @@ -0,0 +1,44 @@ +package com.xkcoding.websocket.payload.server; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.server.SysFile; +import com.xkcoding.websocket.payload.KV; +import lombok.Data; + +import java.util.List; + +/** + *

+ * 系统文件相关信息实体VO + *

+ * + * @package: com.xkcoding.websocket.payload.server + * @description: 系统文件相关信息实体VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:30 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class SysFileVO { + List> data = Lists.newArrayList(); + + public static SysFileVO create(List sysFiles) { + SysFileVO vo = new SysFileVO(); + for (SysFile sysFile : sysFiles) { + List item = Lists.newArrayList(); + + item.add(new KV("盘符路径", sysFile.getDirName())); + item.add(new KV("盘符类型", sysFile.getSysTypeName())); + item.add(new KV("文件类型", sysFile.getTypeName())); + item.add(new KV("总大小", sysFile.getTotal())); + item.add(new KV("剩余大小", sysFile.getFree())); + item.add(new KV("已经使用量", sysFile.getUsed())); + item.add(new KV("资源的使用率", sysFile.getUsage())); + + vo.data.add(item); + } + return vo; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysVO.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysVO.java new file mode 100644 index 0000000..6b722db --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/payload/server/SysVO.java @@ -0,0 +1,36 @@ +package com.xkcoding.websocket.payload.server; + +import com.google.common.collect.Lists; +import com.xkcoding.websocket.model.server.Sys; +import com.xkcoding.websocket.payload.KV; +import lombok.Data; + +import java.util.List; + +/** + *

+ * 系统相关信息实体VO + *

+ * + * @package: com.xkcoding.websocket.payload.server + * @description: 系统相关信息实体VO + * @author: yangkai.shen + * @date: Created in 2018-12-14 17:28 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Data +public class SysVO { + List data = Lists.newArrayList(); + + public static SysVO create(Sys sys) { + SysVO vo = new SysVO(); + vo.data.add(new KV("服务器名称", sys.getComputerName())); + vo.data.add(new KV("服务器Ip", sys.getComputerIp())); + vo.data.add(new KV("项目路径", sys.getUserDir())); + vo.data.add(new KV("操作系统", sys.getOsName())); + vo.data.add(new KV("系统架构", sys.getOsArch())); + return vo; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/task/ServerTask.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/task/ServerTask.java new file mode 100644 index 0000000..73e27a2 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/task/ServerTask.java @@ -0,0 +1,49 @@ +package com.xkcoding.websocket.task; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONUtil; +import com.xkcoding.websocket.common.WebSocketConsts; +import com.xkcoding.websocket.model.Server; +import com.xkcoding.websocket.payload.ServerVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + *

+ * 服务器定时推送任务 + *

+ * + * @package: com.xkcoding.websocket.task + * @description: 服务器定时推送任务 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:04 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +@Slf4j +@Component +public class ServerTask { + @Autowired + private SimpMessagingTemplate wsTemplate; + + /** + * 按照标准时间来算,每隔 10s 执行一次 + */ + @Scheduled(cron = "0/10 * * * * ?") + public void websocket() throws Exception { + log.info("【推送消息】开始执行:{}", DateUtil.formatDateTime(new Date())); + // 查询服务器状态 + Server server = new Server(); + server.copyTo(); + ServerVO serverVO = new ServerVO(); + serverVO.create(server); + wsTemplate.convertAndSend(WebSocketConsts.PUSH_SERVER, JSONUtil.toJsonStr(serverVO)); + log.info("【推送消息】执行结束:{}", DateUtil.formatDateTime(new Date())); + } +} diff --git a/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/util/IpUtil.java b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/util/IpUtil.java new file mode 100644 index 0000000..68ac0c5 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/java/com/xkcoding/websocket/util/IpUtil.java @@ -0,0 +1,169 @@ +package com.xkcoding.websocket.util; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + *

+ * IP 工具类 + *

+ * + * @package: com.xkcoding.websocket.util + * @description: IP 工具类 + * @author: yangkai.shen + * @date: Created in 2018-12-14 16:08 + * @copyright: Copyright (c) 2018 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class IpUtil { + public static String getIpAddr(HttpServletRequest request) { + if (request == null) { + return "unknown"; + } + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Forwarded-For"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; + } + + public static boolean internalIp(String ip) { + byte[] addr = textToNumericFormatV4(ip); + return internalIp(addr) || "127.0.0.1".equals(ip); + } + + private static boolean internalIp(byte[] addr) { + final byte b0 = addr[0]; + final byte b1 = addr[1]; + // 10.x.x.x/8 + final byte SECTION_1 = 0x0A; + // 172.16.x.x/12 + final byte SECTION_2 = (byte) 0xAC; + final byte SECTION_3 = (byte) 0x10; + final byte SECTION_4 = (byte) 0x1F; + // 192.168.x.x/16 + final byte SECTION_5 = (byte) 0xC0; + final byte SECTION_6 = (byte) 0xA8; + switch (b0) { + case SECTION_1: + return true; + case SECTION_2: + if (b1 >= SECTION_3 && b1 <= SECTION_4) { + return true; + } + case SECTION_5: + switch (b1) { + case SECTION_6: + return true; + } + default: + return false; + } + } + + /** + * 将IPv4地址转换成字节 + * + * @param text IPv4地址 + * @return byte 字节 + */ + public static byte[] textToNumericFormatV4(String text) { + if (text.length() == 0) { + return null; + } + + byte[] bytes = new byte[4]; + String[] elements = text.split("\\.", -1); + try { + long l; + int i; + switch (elements.length) { + case 1: + l = Long.parseLong(elements[0]); + if ((l < 0L) || (l > 4294967295L)) { + return null; + } + bytes[0] = (byte) (int) (l >> 24 & 0xFF); + bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 2: + l = Integer.parseInt(elements[0]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[0] = (byte) (int) (l & 0xFF); + l = Integer.parseInt(elements[1]); + if ((l < 0L) || (l > 16777215L)) { + return null; + } + bytes[1] = (byte) (int) (l >> 16 & 0xFF); + bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 3: + for (i = 0; i < 2; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + l = Integer.parseInt(elements[2]); + if ((l < 0L) || (l > 65535L)) { + return null; + } + bytes[2] = (byte) (int) (l >> 8 & 0xFF); + bytes[3] = (byte) (int) (l & 0xFF); + break; + case 4: + for (i = 0; i < 4; ++i) { + l = Integer.parseInt(elements[i]); + if ((l < 0L) || (l > 255L)) { + return null; + } + bytes[i] = (byte) (int) (l & 0xFF); + } + break; + default: + return null; + } + } catch (NumberFormatException e) { + return null; + } + return bytes; + } + + public static String getHostIp() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + } + return "127.0.0.1"; + } + + public static String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + } + return "未知"; + } +} \ No newline at end of file diff --git a/spring-boot-demo-websocket/src/main/resources/static/js/sockjs.min.js b/spring-boot-demo-websocket/src/main/resources/static/js/sockjs.min.js new file mode 100644 index 0000000..fe361c7 --- /dev/null +++ b/spring-boot-demo-websocket/src/main/resources/static/js/sockjs.min.js @@ -0,0 +1,27 @@ +/* SockJS client, version 0.3.4, http://sockjs.org, MIT License + +Copyright (c) 2011-2012 VMware, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// JSON2 by Douglas Crockford (minified). +var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c1?this._listeners[a]=d.slice(0,e).concat(d.slice(e+1)):delete this._listeners[a];return}return},d.prototype.dispatchEvent=function(a){var b=a.type,c=Array.prototype.slice.call(arguments,0);this["on"+b]&&this["on"+b].apply(this,c);if(this._listeners&&b in this._listeners)for(var d=0;d=3e3&&a<=4999},c.countRTO=function(a){var b;return a>100?b=3*a:b=a+200,b},c.log=function(){b.console&&console.log&&console.log.apply&&console.log.apply(console,arguments)},c.bind=function(a,b){return a.bind?a.bind(b):function(){return a.apply(b,arguments)}},c.flatUrl=function(a){return a.indexOf("?")===-1&&a.indexOf("#")===-1},c.amendUrl=function(b){var d=a.location;if(!b)throw new Error("Wrong url for SockJS");if(!c.flatUrl(b))throw new Error("Only basic urls are supported in SockJS");return b.indexOf("//")===0&&(b=d.protocol+b),b.indexOf("/")===0&&(b=d.protocol+"//"+d.host+b),b=b.replace(/[/]+$/,""),b},c.arrIndexOf=function(a,b){for(var c=0;c=0},c.delay=function(a,b){return typeof a=="function"&&(b=a,a=0),setTimeout(b,a)};var i=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,j={"\0":"\\u0000","\x01":"\\u0001","\x02":"\\u0002","\x03":"\\u0003","\x04":"\\u0004","\x05":"\\u0005","\x06":"\\u0006","\x07":"\\u0007","\b":"\\b","\t":"\\t","\n":"\\n","\x0b":"\\u000b","\f":"\\f","\r":"\\r","\x0e":"\\u000e","\x0f":"\\u000f","\x10":"\\u0010","\x11":"\\u0011","\x12":"\\u0012","\x13":"\\u0013","\x14":"\\u0014","\x15":"\\u0015","\x16":"\\u0016","\x17":"\\u0017","\x18":"\\u0018","\x19":"\\u0019","\x1a":"\\u001a","\x1b":"\\u001b","\x1c":"\\u001c","\x1d":"\\u001d","\x1e":"\\u001e","\x1f":"\\u001f",'"':'\\"',"\\":"\\\\","\x7f":"\\u007f","\x80":"\\u0080","\x81":"\\u0081","\x82":"\\u0082","\x83":"\\u0083","\x84":"\\u0084","\x85":"\\u0085","\x86":"\\u0086","\x87":"\\u0087","\x88":"\\u0088","\x89":"\\u0089","\x8a":"\\u008a","\x8b":"\\u008b","\x8c":"\\u008c","\x8d":"\\u008d","\x8e":"\\u008e","\x8f":"\\u008f","\x90":"\\u0090","\x91":"\\u0091","\x92":"\\u0092","\x93":"\\u0093","\x94":"\\u0094","\x95":"\\u0095","\x96":"\\u0096","\x97":"\\u0097","\x98":"\\u0098","\x99":"\\u0099","\x9a":"\\u009a","\x9b":"\\u009b","\x9c":"\\u009c","\x9d":"\\u009d","\x9e":"\\u009e","\x9f":"\\u009f","\xad":"\\u00ad","\u0600":"\\u0600","\u0601":"\\u0601","\u0602":"\\u0602","\u0603":"\\u0603","\u0604":"\\u0604","\u070f":"\\u070f","\u17b4":"\\u17b4","\u17b5":"\\u17b5","\u200c":"\\u200c","\u200d":"\\u200d","\u200e":"\\u200e","\u200f":"\\u200f","\u2028":"\\u2028","\u2029":"\\u2029","\u202a":"\\u202a","\u202b":"\\u202b","\u202c":"\\u202c","\u202d":"\\u202d","\u202e":"\\u202e","\u202f":"\\u202f","\u2060":"\\u2060","\u2061":"\\u2061","\u2062":"\\u2062","\u2063":"\\u2063","\u2064":"\\u2064","\u2065":"\\u2065","\u2066":"\\u2066","\u2067":"\\u2067","\u2068":"\\u2068","\u2069":"\\u2069","\u206a":"\\u206a","\u206b":"\\u206b","\u206c":"\\u206c","\u206d":"\\u206d","\u206e":"\\u206e","\u206f":"\\u206f","\ufeff":"\\ufeff","\ufff0":"\\ufff0","\ufff1":"\\ufff1","\ufff2":"\\ufff2","\ufff3":"\\ufff3","\ufff4":"\\ufff4","\ufff5":"\\ufff5","\ufff6":"\\ufff6","\ufff7":"\\ufff7","\ufff8":"\\ufff8","\ufff9":"\\ufff9","\ufffa":"\\ufffa","\ufffb":"\\ufffb","\ufffc":"\\ufffc","\ufffd":"\\ufffd","\ufffe":"\\ufffe","\uffff":"\\uffff"},k=/[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,l,m=JSON&&JSON.stringify||function(a){return i.lastIndex=0,i.test(a)&&(a=a.replace(i,function(a){return j[a]})),'"'+a+'"'},n=function(a){var b,c={},d=[];for(b=0;b<65536;b++)d.push(String.fromCharCode(b));return a.lastIndex=0,d.join("").replace(a,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),a.lastIndex=0,c};c.quote=function(a){var b=m(a);return k.lastIndex=0,k.test(b)?(l||(l=n(k)),b.replace(k,function(a){return l[a]})):b};var o=["websocket","xdr-streaming","xhr-streaming","iframe-eventsource","iframe-htmlfile","xdr-polling","xhr-polling","iframe-xhr-polling","jsonp-polling"];c.probeProtocols=function(){var a={};for(var b=0;b0&&h(a)};return c.websocket!==!1&&h(["websocket"]),d["xhr-streaming"]&&!c.null_origin?e.push("xhr-streaming"):d["xdr-streaming"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-streaming"):h(["iframe-eventsource","iframe-htmlfile"]),d["xhr-polling"]&&!c.null_origin?e.push("xhr-polling"):d["xdr-polling"]&&!c.cookie_needed&&!c.null_origin?e.push("xdr-polling"):h(["iframe-xhr-polling","jsonp-polling"]),e};var p="_sockjs_global";c.createHook=function(){var a="a"+c.random_string(8);if(!(p in b)){var d={};b[p]=function(a){return a in d||(d[a]={id:a,del:function(){delete d[a]}}),d[a]}}return b[p](a)},c.attachMessage=function(a){c.attachEvent("message",a)},c.attachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.addEventListener(c,d,!1):(a.attachEvent("on"+c,d),b.attachEvent("on"+c,d))},c.detachMessage=function(a){c.detachEvent("message",a)},c.detachEvent=function(c,d){typeof b.addEventListener!="undefined"?b.removeEventListener(c,d,!1):(a.detachEvent("on"+c,d),b.detachEvent("on"+c,d))};var q={},r=!1,s=function(){for(var a in q)q[a](),delete q[a]},t=function(){if(r)return;r=!0,s()};c.attachEvent("unload",t),c.unload_add=function(a){var b=c.random_string(8);return q[b]=a,r&&c.delay(s),b},c.unload_del=function(a){a in q&&delete q[a]},c.createIframe=function(b,d){var e=a.createElement("iframe"),f,g,h=function(){clearTimeout(f);try{e.onload=null}catch(a){}e.onerror=null},i=function(){e&&(h(),setTimeout(function(){e&&e.parentNode.removeChild(e),e=null},0),c.unload_del(g))},j=function(a){e&&(i(),d(a))},k=function(a,b){try{e&&e.contentWindow&&e.contentWindow.postMessage(a,b)}catch(c){}};return e.src=b,e.style.display="none",e.style.position="absolute",e.onerror=function(){j("onerror")},e.onload=function(){clearTimeout(f),f=setTimeout(function(){j("onload timeout")},2e3)},a.body.appendChild(e),f=setTimeout(function(){j("timeout")},15e3),g=c.unload_add(i),{post:k,cleanup:i,loaded:h}},c.createHtmlfile=function(a,d){var e=new ActiveXObject("htmlfile"),f,g,i,j=function(){clearTimeout(f)},k=function(){e&&(j(),c.unload_del(g),i.parentNode.removeChild(i),i=e=null,CollectGarbage())},l=function(a){e&&(k(),d(a))},m=function(a,b){try{i&&i.contentWindow&&i.contentWindow.postMessage(a,b)}catch(c){}};e.open(),e.write(' + + + + + + + \ No newline at end of file