Compare commits
90 Commits
dev_script
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
23e23fc39c | |
|
|
4f79c0350a | |
|
|
9c9524f143 | |
|
|
05509e1b22 | |
|
|
ab8d1e7884 | |
|
|
946e95ca01 | |
|
|
c2746343db | |
|
|
58ce89db32 | |
|
|
11f9a4def3 | |
|
|
c0f3c001eb | |
|
|
5515110795 | |
|
|
6c42fc8eb7 | |
|
|
96d548066d | |
|
|
25d0872950 | |
|
|
1f4ce10d09 | |
|
|
b493994e14 | |
|
|
6c927541ab | |
|
|
36e9eaadc1 | |
|
|
6c14e0c6f4 | |
|
|
dafab616af | |
|
|
33a851b7bc | |
|
|
665ad2d6a8 | |
|
|
a54f970dc7 | |
|
|
7c224d362b | |
|
|
9bb185e3eb | |
|
|
dbc1c99f85 | |
|
|
1eb45e6581 | |
|
|
def875a80d | |
|
|
4d6d43279c | |
|
|
7450bb849c | |
|
|
4046f6de2f | |
|
|
bbd047dcc9 | |
|
|
b5a31830c0 | |
|
|
86dc186b87 | |
|
|
053e232e56 | |
|
|
0574e858af | |
|
|
778b8f7ee3 | |
|
|
31c646e348 | |
|
|
4fc74e3375 | |
|
|
feebab63e5 | |
|
|
2aedb712c8 | |
|
|
101977f386 | |
|
|
9fb8e14521 | |
|
|
b960f50fde | |
|
|
9f0a32d5f5 | |
|
|
1a201c9a3f | |
|
|
dda12d6fcd | |
|
|
27ec683fdd | |
|
|
b8901b50c1 | |
|
|
8362f881ba | |
|
|
aae8011ee5 | |
|
|
d6e380cba4 | |
|
|
be64245799 | |
|
|
c434f9db7e | |
|
|
a26e48eef4 | |
|
|
3c736fa2d9 | |
|
|
36765553cd | |
|
|
55e1171a70 | |
|
|
04c65e0104 | |
|
|
7b3b51a0fd | |
|
|
68b0c81a5d | |
|
|
c271f8acee | |
|
|
44938ba215 | |
|
|
5f9cb0a84f | |
|
|
1bb034d7de | |
|
|
8ed7a854b4 | |
|
|
2106b4c899 | |
|
|
599baf4b44 | |
|
|
aeeac0799b | |
|
|
8b59125c83 | |
|
|
0a0349a840 | |
|
|
77a4714bac | |
|
|
0fa11b5697 | |
|
|
bb8ee1bdbc | |
|
|
1ff2e6f6b5 | |
|
|
e705208b9d | |
|
|
7e63bd66b0 | |
|
|
0f461f62e2 | |
|
|
cd31eb378a | |
|
|
553aaa3e3b | |
|
|
7e9a104ca5 | |
|
|
125907517a | |
|
|
f560062452 | |
|
|
7f74bee98e | |
|
|
17f861755a | |
|
|
6879948d18 | |
|
|
fa7304af8d | |
|
|
0683ac9327 | |
|
|
ceb6db5be9 | |
|
|
a4ad28db7b |
56
pom.xml
56
pom.xml
|
|
@ -26,6 +26,17 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<!-- redis依赖包 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
|
@ -89,6 +100,51 @@
|
||||||
<version>${commons-io.version}</version>
|
<version>${commons-io.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Main Guacamole library -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.guacamole</groupId>
|
||||||
|
<artifactId>guacamole-common</artifactId>
|
||||||
|
<version>1.4.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>5.1.48</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>1.1.10</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis.spring.boot</groupId>
|
||||||
|
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||||
|
<version>1.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis</groupId>
|
||||||
|
<artifactId>mybatis-spring</artifactId>
|
||||||
|
<version>1.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mybatis</groupId>
|
||||||
|
<artifactId>mybatis</artifactId>
|
||||||
|
<version>3.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
package net.educoder.bridge;
|
package net.educoder.bridge;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
|
||||||
|
@MapperScan("net.educoder.bridge.dao")
|
||||||
@SpringBootApplication()
|
@SpringBootApplication()
|
||||||
public class WebsshApplication {
|
public class WebsshApplication {
|
||||||
|
|
||||||
|
|
@ -10,4 +13,6 @@ public class WebsshApplication {
|
||||||
SpringApplication.run(WebsshApplication.class, args);
|
SpringApplication.run(WebsshApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package net.educoder.bridge.common.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* windows实例信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WindowsInfo {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String uniqId;
|
||||||
|
|
||||||
|
private String instanceId;
|
||||||
|
|
||||||
|
private String userID;
|
||||||
|
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
private String port;
|
||||||
|
|
||||||
|
private String vncPort;
|
||||||
|
|
||||||
|
private String forwardTableId;
|
||||||
|
|
||||||
|
private String forwardEntryId;
|
||||||
|
|
||||||
|
private String vncForwardEntryId;
|
||||||
|
|
||||||
|
private LocalDateTime autoReleaseTime;
|
||||||
|
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
public WindowsInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowsInfo(String uniqId, String instanceId, String userID, String templateName, String port, String vncPort,
|
||||||
|
LocalDateTime autoReleaseTime, String forwardTableId, String forwardEntryId, String vncForwardEntryId) {
|
||||||
|
this.uniqId = uniqId;
|
||||||
|
this.instanceId = instanceId;
|
||||||
|
this.userID = userID;
|
||||||
|
this.templateName = templateName;
|
||||||
|
this.port = port;
|
||||||
|
this.vncPort = vncPort;
|
||||||
|
this.autoReleaseTime = autoReleaseTime;
|
||||||
|
this.forwardTableId = forwardTableId;
|
||||||
|
this.forwardEntryId = forwardEntryId;
|
||||||
|
this.vncForwardEntryId = vncForwardEntryId;
|
||||||
|
this.createTime = LocalDateTime.now();
|
||||||
|
this.updateTime = LocalDateTime.now();
|
||||||
|
this.status = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package net.educoder.bridge.common.utils;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件工具类
|
||||||
|
*
|
||||||
|
* @author 威少
|
||||||
|
*/
|
||||||
|
public class FileUtil {
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(FileUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采用Files的delete方法,不直接使用file.delete是因为file.delete在删除失败的场景下只会返回false,没有具体的错误原因返回
|
||||||
|
*/
|
||||||
|
public static String delete(File file) {
|
||||||
|
String path = file.getPath();
|
||||||
|
try {
|
||||||
|
Files.delete(file.toPath());
|
||||||
|
logger.info("删除文件成功,file: {}", path);
|
||||||
|
} catch (NoSuchFileException e) {
|
||||||
|
logger.info("删除文件失败,file: {},文件不存在", path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn("删除文件失败,file: {},e: {}", path, e.getMessage());
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package net.educoder.bridge.common.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程工具类
|
||||||
|
*
|
||||||
|
* @author 威少
|
||||||
|
*/
|
||||||
|
public class ThreadUtil {
|
||||||
|
/**
|
||||||
|
* 静默睡眠
|
||||||
|
* @param millis 毫秒
|
||||||
|
*/
|
||||||
|
public static void sleepSilently(long millis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package net.educoder.bridge.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import net.educoder.bridge.common.model.WindowsInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface WindowsInfoMapper {
|
||||||
|
|
||||||
|
int deleteByUniqId(String uniqId);
|
||||||
|
|
||||||
|
int insertSelective(WindowsInfo record);
|
||||||
|
|
||||||
|
WindowsInfo selectByUniqId(String uniqId);
|
||||||
|
|
||||||
|
List<WindowsInfo> selectByTpiId(String tpiId);
|
||||||
|
|
||||||
|
List<WindowsInfo> selectByUserId(String userID);
|
||||||
|
|
||||||
|
int updateByUniqIdSelective(WindowsInfo windowsInfo);
|
||||||
|
|
||||||
|
List<String> selectUniqIdByAutoReleaseTime(WindowsInfo windowsInfo);
|
||||||
|
|
||||||
|
List<WindowsInfo> selectNotForwardEntryHost();
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package net.educoder.bridge.git.task;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import net.educoder.bridge.git.model.GitConfig;
|
|
||||||
import net.educoder.bridge.git.service.GitService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* git初始化凭证设置
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class GitInitTask {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private GitConfig gitConfig;
|
|
||||||
@Autowired
|
|
||||||
private GitService gitService;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
gitService.gitCredentialStore(gitConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package net.educoder.bridge.git.task;
|
|
||||||
|
|
||||||
import net.educoder.bridge.git.service.ResourceFileService;
|
|
||||||
import org.apache.commons.io.Charsets;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* execeva.sh初始化
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ScriptInitTask {
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
private static final String POD_PLATFORM_MOUNT_PATH = "/data/workspace/platform/eva";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ResourceFileService readResourceFileContent;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
writeScript("execEva.sh");
|
|
||||||
writeScript("execStepOut.sh");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeScript(String scriptName) {
|
|
||||||
String path = POD_PLATFORM_MOUNT_PATH + File.separator + scriptName;
|
|
||||||
try {
|
|
||||||
String content = readResourceFileContent.getResourceFileContent("evaluate/" + scriptName);
|
|
||||||
FileUtils.writeStringToFile(new File(path), content, "UTF-8");
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.error("{} 初始化失败", scriptName, e);
|
|
||||||
throw new RuntimeException(scriptName + "初始化失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +1,37 @@
|
||||||
package net.educoder.bridge.webssh.config;
|
package net.educoder.bridge.webssh.config;
|
||||||
|
|
||||||
|
import net.educoder.bridge.webssh.handler.GuacamoleWebSocketTunnelHandler;
|
||||||
|
import net.educoder.bridge.webssh.handler.RunOnlyHandler;
|
||||||
|
import net.educoder.bridge.webssh.handler.EducoderGuacamoleWebSocketTunnelHandler;
|
||||||
import net.educoder.bridge.webssh.handler.WebsshHandler;
|
import net.educoder.bridge.webssh.handler.WebsshHandler;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSocket
|
@EnableWebSocket
|
||||||
public class WebSocketConfig implements WebSocketConfigurer {
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
|
|
||||||
@Autowired
|
@Resource
|
||||||
WebsshHandler websshHandler;
|
WebsshHandler websshHandler;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
RunOnlyHandler runOnlyHandler;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EducoderGuacamoleWebSocketTunnelHandler EducoderGuacamoleWebSocketTunnelHandler;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||||
registry.addHandler(websshHandler, "/ws").setAllowedOrigins("*");
|
registry.addHandler(websshHandler, "/ws").setAllowedOrigins("*");
|
||||||
|
registry.addHandler(runOnlyHandler, "/log").setAllowedOrigins("*");
|
||||||
|
registry.addHandler(EducoderGuacamoleWebSocketTunnelHandler,"/tunnel").setAllowedOrigins("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
package net.educoder.bridge.webssh.handler;
|
||||||
|
|
||||||
|
import net.educoder.bridge.common.model.WindowsInfo;
|
||||||
|
import net.educoder.bridge.dao.WindowsInfoMapper;
|
||||||
|
import org.apache.commons.lang.math.NumberUtils;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.net.GuacamoleSocket;
|
||||||
|
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||||
|
import org.apache.guacamole.net.InetGuacamoleSocket;
|
||||||
|
import org.apache.guacamole.net.SimpleGuacamoleTunnel;
|
||||||
|
import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
|
||||||
|
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rdp协议连接
|
||||||
|
* @author 悟空
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EducoderGuacamoleWebSocketTunnelHandler extends GuacamoleWebSocketTunnelHandler {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WindowsInfoMapper windowsInfoMapper;
|
||||||
|
|
||||||
|
|
||||||
|
private static final String DEFAULT_POSITION = "1";
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${guacamole.server.ip}")
|
||||||
|
private String guacamoleServer;
|
||||||
|
@Value("${guacamole.server.port}")
|
||||||
|
private int guacamoleServerPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(EducoderGuacamoleWebSocketTunnelHandler.class);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过tpiId及position生成uniqId,默认postion为1
|
||||||
|
*/
|
||||||
|
public String generateUniqId(String tpiId) {
|
||||||
|
return generateUniqId(tpiId, DEFAULT_POSITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateUniqId(String tpiId, String position) {
|
||||||
|
return tpiId + "-" + NumberUtils.toInt(position, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateUniqId(String envId, String tpiId, String tpiType) {
|
||||||
|
return tpiId + "-" + envId + "-" + tpiType;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
GuacamoleTunnel createTunnel(WebSocketSession session) throws GuacamoleException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
try {
|
||||||
|
properties.load(new ByteArrayInputStream(session.getUri().getQuery().replace('&','\n').getBytes()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
String tpiID = properties.getProperty("tpiID");
|
||||||
|
String envId = properties.getProperty("envId");
|
||||||
|
String tpiType = properties.getProperty("tpiType");
|
||||||
|
//生成唯一键
|
||||||
|
String uniqId = generateUniqId(envId, tpiID, tpiType);
|
||||||
|
WindowsInfo windowsInfo = getWindowsInfo(uniqId);
|
||||||
|
|
||||||
|
|
||||||
|
// Create our configuration
|
||||||
|
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||||
|
config.setProtocol("rdp");
|
||||||
|
config.setParameter("hostname", "39.105.62.120");
|
||||||
|
config.setParameter("port", windowsInfo.getVncPort());
|
||||||
|
config.setParameter("username", "Administrator");
|
||||||
|
config.setParameter("password", "Edu_123123");
|
||||||
|
config.setParameter("security", "nla");
|
||||||
|
config.setParameter("ignore-cert", "true");
|
||||||
|
config.setParameter("width",properties.getProperty("width"));
|
||||||
|
config.setParameter("height",properties.getProperty("height"));
|
||||||
|
|
||||||
|
// Connect to guacd - everything is hard-coded here.
|
||||||
|
GuacamoleSocket socket = null;
|
||||||
|
try{
|
||||||
|
socket = new ConfiguredGuacamoleSocket(new InetGuacamoleSocket(guacamoleServer, guacamoleServerPort),
|
||||||
|
config);
|
||||||
|
}catch (Exception e){
|
||||||
|
logger.error("createTunnel is Exception uniqueId:{}", uniqId, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a new tunnel which uses the connected socket
|
||||||
|
return new SimpleGuacamoleTunnel(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public WindowsInfo getWindowsInfo(String uniqId) {
|
||||||
|
return windowsInfoMapper.selectByUniqId(uniqId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSubProtocols() {
|
||||||
|
return Collections.singletonList("guacamole");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
package net.educoder.bridge.webssh.handler;
|
||||||
|
|
||||||
|
import org.apache.guacamole.GuacamoleClientException;
|
||||||
|
import org.apache.guacamole.GuacamoleConnectionClosedException;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.io.GuacamoleReader;
|
||||||
|
import org.apache.guacamole.io.GuacamoleWriter;
|
||||||
|
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||||
|
import org.apache.guacamole.protocol.GuacamoleStatus;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.socket.*;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public abstract class GuacamoleWebSocketTunnelHandler implements WebSocketHandler, SubProtocolCapable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default, minimum buffer size for instructions.
|
||||||
|
*/
|
||||||
|
private static final int BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(GuacamoleWebSocketTunnelHandler.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The underlying GuacamoleTunnel. WebSocket reads/writes will be handled as
|
||||||
|
* reads/writes to this tunnel.
|
||||||
|
*/
|
||||||
|
private GuacamoleTunnel tunnel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new tunnel for the given session. How this tunnel is created or
|
||||||
|
* retrieved is implementation-dependent.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The session associated with the active WebSocket connection.
|
||||||
|
* @return A connected tunnel, or null if no such tunnel exists.
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the tunnel, or if access
|
||||||
|
* to the tunnel is denied.
|
||||||
|
*/
|
||||||
|
abstract GuacamoleTunnel createTunnel(WebSocketSession session) throws GuacamoleException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
|
logger.debug("afterConnectionEstablished");
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Get tunnel
|
||||||
|
tunnel = createTunnel(session);
|
||||||
|
if (tunnel == null) {
|
||||||
|
String message = Integer.toString(GuacamoleStatus.RESOURCE_NOT_FOUND.getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session,
|
||||||
|
new CloseStatus(GuacamoleStatus.RESOURCE_NOT_FOUND.getWebSocketCode(), message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (GuacamoleException e) {
|
||||||
|
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage());
|
||||||
|
logger.debug("Error connecting WebSocket tunnel.", e);
|
||||||
|
String message = Integer.toString(e.getStatus().getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session, new CloseStatus(e.getStatus().getWebSocketCode(), message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Thread readThread = new Thread() {
|
||||||
|
|
||||||
|
AtomicBoolean flag = new AtomicBoolean(true);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
process(session, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
readThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
|
||||||
|
logger.debug("handleMessage");
|
||||||
|
// Ignore inbound messages if there is no associated tunnel
|
||||||
|
if (tunnel == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuacamoleWriter writer = tunnel.acquireWriter();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Write received message
|
||||||
|
writer.write(message.getPayload().toString().toCharArray());
|
||||||
|
} catch (GuacamoleConnectionClosedException e) {
|
||||||
|
logger.debug("Connection to guacd closed.", e);
|
||||||
|
} catch (GuacamoleException e) {
|
||||||
|
logger.debug("WebSocket tunnel write failed.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
tunnel.releaseWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
||||||
|
logger.debug("handleTransportError");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given status on the given WebSocket connection and closes the
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The outbound WebSocket connection to close.
|
||||||
|
* @param closeStatus
|
||||||
|
* The status to send.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
|
||||||
|
logger.debug("afterConnectionClosed");
|
||||||
|
session.close(closeStatus);
|
||||||
|
try {
|
||||||
|
if (tunnel != null) {
|
||||||
|
tunnel.close();
|
||||||
|
}
|
||||||
|
} catch (GuacamoleException e) {
|
||||||
|
logger.debug("Unable to close WebSocket tunnel.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsPartialMessages() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void process(WebSocketSession session, AtomicBoolean flag) {
|
||||||
|
|
||||||
|
if (flag.get()) {
|
||||||
|
StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
|
||||||
|
GuacamoleReader reader = tunnel.acquireReader();
|
||||||
|
char[] readMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Attempt to read
|
||||||
|
while ((readMessage = reader.read()) != null) {
|
||||||
|
|
||||||
|
// Buffer message
|
||||||
|
buffer.append(readMessage);
|
||||||
|
|
||||||
|
// Flush if we expect to wait or buffer is getting
|
||||||
|
// full
|
||||||
|
if (!reader.available() || buffer.length() >= BUFFER_SIZE) {
|
||||||
|
session.sendMessage(new TextMessage(buffer));
|
||||||
|
buffer.setLength(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more data
|
||||||
|
String message = Integer.toString(GuacamoleStatus.SUCCESS.getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session,
|
||||||
|
new CloseStatus(GuacamoleStatus.SUCCESS.getWebSocketCode(), message));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catch any thrown guacamole exception and attempt
|
||||||
|
// to pass within the WebSocket connection, logging
|
||||||
|
// each error appropriately.
|
||||||
|
catch (GuacamoleClientException e) {
|
||||||
|
logger.info("WebSocket connection terminated: {}", e.getMessage());
|
||||||
|
String message = Integer.toString(e.getStatus().getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session, new CloseStatus(e.getStatus().getWebSocketCode(), message));
|
||||||
|
} catch (GuacamoleConnectionClosedException e) {
|
||||||
|
logger.error("Connection to guacd closed.", e);
|
||||||
|
if(flag.getAndSet(false)) {
|
||||||
|
process(session, flag);
|
||||||
|
}else {
|
||||||
|
String message = Integer.toString(GuacamoleStatus.SUCCESS.getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session,
|
||||||
|
new CloseStatus(GuacamoleStatus.SUCCESS.getWebSocketCode(), message));
|
||||||
|
}
|
||||||
|
} catch (GuacamoleException e) {
|
||||||
|
logger.error("Connection to guacd terminated abnormally ", e);
|
||||||
|
if(flag.getAndSet(false)) {
|
||||||
|
process(session, flag);
|
||||||
|
}else{
|
||||||
|
String message = Integer.toString(e.getStatus().getGuacamoleStatusCode());
|
||||||
|
afterConnectionClosed(session, new CloseStatus(e.getStatus().getWebSocketCode(), message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("I/O error prevents further reads.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
package net.educoder.bridge.webssh.handler;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import net.educoder.bridge.common.utils.Base64Util;
|
||||||
|
import net.educoder.bridge.common.utils.ThreadUtil;
|
||||||
|
import net.educoder.bridge.webssh.utils.RedisHelper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅运行通过websocket回传结果
|
||||||
|
*
|
||||||
|
* @author 威少
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RunOnlyHandler extends TextWebSocketHandler {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(RunOnlyHandler.class);
|
||||||
|
private final static String TYPE = "tp";
|
||||||
|
private final static String LOG_TYPE = "log";
|
||||||
|
private final static String DATA = "data";
|
||||||
|
private final static String PROCESS_FINISHED = "ProcessFinished";
|
||||||
|
private final static String RUN_ONLY_RESULT_KEY_PREFIX = "runOnlyResult";
|
||||||
|
private final static String CASE_OUTPUT_SEPARATOR = "\\x1b\\x09\\x1d";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisHelper redisHelper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception {
|
||||||
|
super.afterConnectionEstablished(wsSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||||
|
String payload = message.getPayload();
|
||||||
|
logger.info("仅运行socket连接接收到数据:{}, session: {}, thread: {}", payload, session.getId(), Thread.currentThread().getId());
|
||||||
|
|
||||||
|
JSONObject msg = JSON.parseObject(payload);
|
||||||
|
if (LOG_TYPE.equals(msg.getString(TYPE))) {
|
||||||
|
String runOnlyResultKey = RUN_ONLY_RESULT_KEY_PREFIX + msg.getString(DATA);
|
||||||
|
// webssh先收到请求,需要等待一会
|
||||||
|
int i = 0;
|
||||||
|
while (!redisHelper.hasKey(runOnlyResultKey) && i < 5 * 10) {
|
||||||
|
ThreadUtil.sleepSilently(100);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
String runOnlyResult = redisHelper.get(runOnlyResultKey);
|
||||||
|
while (CASE_OUTPUT_SEPARATOR.equals(runOnlyResult) && redisHelper.hasKey(runOnlyResultKey)) {
|
||||||
|
ThreadUtil.sleepSilently(100);
|
||||||
|
runOnlyResult = redisHelper.get(runOnlyResultKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runOnlyResult != null) {
|
||||||
|
sendMsg(session, runOnlyResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.handleTextMessage(session, message);
|
||||||
|
close(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception {
|
||||||
|
logger.info("afterConnectionClosed, session: {}", wsSession.getId());
|
||||||
|
close(wsSession);
|
||||||
|
super.afterConnectionClosed(wsSession, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭连接
|
||||||
|
*
|
||||||
|
* @param session session
|
||||||
|
*/
|
||||||
|
public void close(WebSocketSession session) {
|
||||||
|
sendMsg(session, PROCESS_FINISHED);
|
||||||
|
ThreadUtil.sleepSilently(500);
|
||||||
|
|
||||||
|
if (session.isOpen()) {
|
||||||
|
try {
|
||||||
|
session.close();
|
||||||
|
logger.info("session {} closed", session.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("关闭仅运行socket连接失败, session: {}", session.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送数据
|
||||||
|
*
|
||||||
|
* @param session session
|
||||||
|
* @param msg 信息
|
||||||
|
*/
|
||||||
|
private void sendMsg(WebSocketSession session, String msg) {
|
||||||
|
try {
|
||||||
|
session.sendMessage(new TextMessage(Base64Util.encode(msg)));
|
||||||
|
logger.info("session {}, send msg: {} ", session, msg);
|
||||||
|
} catch (IllegalStateException | IOException e) {
|
||||||
|
logger.warn("发送内容异常, session: {}, e: {}", session.getId(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,88 +1,21 @@
|
||||||
package net.educoder.bridge.webssh.model;
|
package net.educoder.bridge.webssh.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
public class ConnectInfo {
|
public class ConnectInfo {
|
||||||
private String host;
|
private String host;
|
||||||
private String port;
|
private String port;
|
||||||
private String username;
|
private String username;
|
||||||
private String secret;
|
private String secret;
|
||||||
private String gameid;
|
private String myshixun_id;
|
||||||
|
|
||||||
private int rows;
|
private int rows;
|
||||||
private int columns;
|
private int columns;
|
||||||
private int width;
|
private int width;
|
||||||
private int height;
|
private int height;
|
||||||
|
|
||||||
public int getRows() {
|
public String getTpiID() {
|
||||||
return rows;
|
return myshixun_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRows(int rows) {
|
|
||||||
this.rows = rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getColumns() {
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setColumns(int columns) {
|
|
||||||
this.columns = columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWidth(int width) {
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeight(int height) {
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHost() {
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHost(String host) {
|
|
||||||
this.host = host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPort(String port) {
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSecret() {
|
|
||||||
return secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSecret(String secret) {
|
|
||||||
this.secret = secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGameid() {
|
|
||||||
return Integer.parseInt(gameid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGameid(String gameid) {
|
|
||||||
this.gameid = gameid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,7 @@ import net.educoder.bridge.common.utils.Base64Util;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class JchService {
|
public class JchService {
|
||||||
@Autowired
|
|
||||||
private WebsshService websshService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private WebsshOverTimeService overTimeService;
|
|
||||||
|
|
||||||
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
|
private static List<WebscoketObj> sessionQueue = new CopyOnWriteArrayList<>();
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
@ -76,16 +72,13 @@ public class JchService {
|
||||||
public void recv(String buffer, WebSocketSession session) {
|
public void recv(String buffer, WebSocketSession session) {
|
||||||
logger.debug("webssh收到数据:{}", buffer);
|
logger.debug("webssh收到数据:{}", buffer);
|
||||||
WebscoketObj webscoketObj = findBySession(session);
|
WebscoketObj webscoketObj = findBySession(session);
|
||||||
boolean overtime = Boolean.FALSE;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// logger.debug("recv函数,进程:{},sessionID:{},信息:{}",
|
|
||||||
// Thread.currentThread().getId(), session.getId(), buffer);
|
|
||||||
JSONObject object = JSONObject.parseObject(buffer);
|
JSONObject object = JSONObject.parseObject(buffer);
|
||||||
String tp = object.getString("tp");
|
String tp = object.getString("tp");
|
||||||
if ("init".equals(tp)) {
|
if ("init".equals(tp)) {
|
||||||
// 初始化连接
|
// 初始化连接
|
||||||
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","gameid":"1080","rows":"30"}}
|
// {"tp":"init","data":{"host":"106.75.96.108","port":"41080","username":"root","secret":"123123","myshixun_id":"1080","rows":"30"}}
|
||||||
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
|
ConnectInfo connectInfo = object.getObject("data", ConnectInfo.class);
|
||||||
if (webscoketObj != null) {
|
if (webscoketObj != null) {
|
||||||
WebscoketObj finalWebscoketObj = webscoketObj;
|
WebscoketObj finalWebscoketObj = webscoketObj;
|
||||||
|
|
@ -98,7 +91,6 @@ public class JchService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if ("client".equals(tp)) {
|
} else if ("client".equals(tp)) {
|
||||||
overtime = Boolean.TRUE;
|
|
||||||
String data = object.getString("data");
|
String data = object.getString("data");
|
||||||
if (webscoketObj != null) {
|
if (webscoketObj != null) {
|
||||||
transTossh(webscoketObj.getOutputStream(), data);
|
transTossh(webscoketObj.getOutputStream(), data);
|
||||||
|
|
@ -114,12 +106,10 @@ public class JchService {
|
||||||
connectInfo.getWidth(), connectInfo.getHeight());
|
connectInfo.getWidth(), connectInfo.getHeight());
|
||||||
}
|
}
|
||||||
} else if ("overtime".equals(tp)) {
|
} else if ("overtime".equals(tp)) {
|
||||||
overtime = Boolean.TRUE;
|
|
||||||
ConnectInfo connectInfo = webscoketObj.getConnectInfo();
|
ConnectInfo connectInfo = webscoketObj.getConnectInfo();
|
||||||
if (webscoketObj.getConnectInfo() != null) {
|
logger.info("前端主动延长pod存活时间, 不需要通过此接口进行延长了:{}, tpiID:{},host:{},端口:{}", session.getId(),
|
||||||
logger.info("前端主动延长pod存活时间, websocket:{}, tpiID:{},host:{},端口:{}", session.getId(),
|
connectInfo.getTpiID(), connectInfo.getHost(), connectInfo.getPort());
|
||||||
connectInfo.getGameid(), connectInfo.getHost(), connectInfo.getPort());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("转发 websocket {}命令到ssh出错: ", session.getId(), e);
|
logger.error("转发 websocket {}命令到ssh出错: ", session.getId(), e);
|
||||||
|
|
@ -127,15 +117,7 @@ public class JchService {
|
||||||
closeByWebsocket(session);
|
closeByWebsocket(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 延长pod存活时间
|
|
||||||
try {
|
|
||||||
if (webscoketObj.getConnectInfo() != null && overtime) {
|
|
||||||
int gameId = webscoketObj.getConnectInfo().getGameid();
|
|
||||||
overTimeService.websshOverTime("" + gameId);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("pod 接收消息出错", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transTossh(OutputStream outputStream, String data) throws IOException {
|
private void transTossh(OutputStream outputStream, String data) throws IOException {
|
||||||
|
|
@ -154,7 +136,7 @@ public class JchService {
|
||||||
// 启动线程
|
// 启动线程
|
||||||
java.util.Properties config = new java.util.Properties();
|
java.util.Properties config = new java.util.Properties();
|
||||||
config.put("StrictHostKeyChecking", "no");
|
config.put("StrictHostKeyChecking", "no");
|
||||||
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), connectInfo.getPort());
|
session = jsch.getSession(connectInfo.getUsername(), connectInfo.getHost(), Integer.parseInt(connectInfo.getPort()));
|
||||||
|
|
||||||
session.setConfig(config);
|
session.setConfig(config);
|
||||||
session.setPassword(connectInfo.getSecret());
|
session.setPassword(connectInfo.getSecret());
|
||||||
|
|
@ -208,8 +190,7 @@ public class JchService {
|
||||||
|
|
||||||
webscoketObj.setConnectInfo(connectInfo);
|
webscoketObj.setConnectInfo(connectInfo);
|
||||||
|
|
||||||
websshService.active("" + connectInfo.getGameid());
|
logger.info("websocket {} open,连接: tpiId:{},host:{},端口:{}", webSocketSession.getId(), connectInfo.getTpiID(),
|
||||||
logger.info("websocket {} open,连接: tpiId:{},host:{},端口:{}", webSocketSession.getId(), connectInfo.getGameid(),
|
|
||||||
connectInfo.getHost(), connectInfo.getPort());
|
connectInfo.getHost(), connectInfo.getPort());
|
||||||
|
|
||||||
// 循环读取
|
// 循环读取
|
||||||
|
|
@ -220,7 +201,7 @@ public class JchService {
|
||||||
String str = webSocketSession.isOpen() ? "is not" : "is";
|
String str = webSocketSession.isOpen() ? "is not" : "is";
|
||||||
str = webscoketObj.getSession().getId() + " " + str;
|
str = webscoketObj.getSession().getId() + " " + str;
|
||||||
str = String.format("websocket %s closed.ssh读取终止,连接: tpiId:%s,host:%s,端口:%s", str,
|
str = String.format("websocket %s closed.ssh读取终止,连接: tpiId:%s,host:%s,端口:%s", str,
|
||||||
connectInfo.getGameid(), connectInfo.getHost(), connectInfo.getPort());
|
connectInfo.getTpiID(), connectInfo.getHost(), connectInfo.getPort());
|
||||||
if (webSocketSession.isOpen()) {
|
if (webSocketSession.isOpen()) {
|
||||||
logger.error(str);
|
logger.error(str);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -232,7 +213,7 @@ public class JchService {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("连接关闭: websocketId:" + webscoketObj.getSession().getId() + ", tpiId:" + connectInfo.getGameid()
|
logger.error("连接关闭: websocketId:" + webscoketObj.getSession().getId() + ", tpiId:" + connectInfo.getTpiID()
|
||||||
+ ", host:" + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
|
+ ", host:" + connectInfo.getHost() + ",端口: " + connectInfo.getPort(), e);
|
||||||
} finally {
|
} finally {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
|
@ -303,7 +284,7 @@ public class JchService {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
ConnectInfo info = webscoketObj.getConnectInfo();
|
ConnectInfo info = webscoketObj.getConnectInfo();
|
||||||
logger.info("websocket {}连接中断 tpiId {} ", session.getId(), info.getGameid());
|
logger.info("websocket {}连接中断 tpiId {} ", session.getId(), info.getTpiID());
|
||||||
this._close(webscoketObj);
|
this._close(webscoketObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -313,10 +294,10 @@ public class JchService {
|
||||||
*
|
*
|
||||||
* @param gameId
|
* @param gameId
|
||||||
*/
|
*/
|
||||||
public int findExistConnectByGameId(int gameId) {
|
public int findExistConnectByGameId(String gameId) {
|
||||||
|
|
||||||
long count = sessionQueue.stream().filter(webscoketObj -> webscoketObj.getConnectInfo() != null
|
long count = sessionQueue.stream().filter(webscoketObj -> webscoketObj.getConnectInfo() != null
|
||||||
&& webscoketObj.getConnectInfo().getGameid() == gameId).count();
|
&& gameId.equals(webscoketObj.getConnectInfo().getTpiID())).count();
|
||||||
logger.debug("当前gameID对应的websocket数目:{}", count);
|
logger.debug("当前gameID对应的websocket数目:{}", count);
|
||||||
return (int) count;
|
return (int) count;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import javax.annotation.PostConstruct;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Service
|
//@Service
|
||||||
public class WebsshOverTimeService {
|
public class WebsshOverTimeService {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@Autowired
|
// @Autowired
|
||||||
private WebsshService websshService;
|
private WebsshService websshService;
|
||||||
|
|
||||||
private static ConcurrentHashMap<String, String> recvGameIdMap = new ConcurrentHashMap<>();
|
private static ConcurrentHashMap<String, String> recvGameIdMap = new ConcurrentHashMap<>();
|
||||||
|
|
@ -45,7 +45,7 @@ public class WebsshOverTimeService {
|
||||||
}
|
}
|
||||||
if (recvGameIds.length() > 0) {
|
if (recvGameIds.length() > 0) {
|
||||||
recvGameIds.setLength(recvGameIds.length() - 1);
|
recvGameIds.setLength(recvGameIds.length() - 1);
|
||||||
websshService.overTime(recvGameIds.toString());
|
// websshService.overTime(recvGameIds.toString());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("发送接收到websocket消息 tpi失败", e);
|
logger.error("发送接收到websocket消息 tpi失败", e);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package net.educoder.bridge.webssh.utils;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis工具类
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RedisHelper {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, String> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取缓存
|
||||||
|
*/
|
||||||
|
public String get(final String key) {
|
||||||
|
return redisTemplate.opsForValue().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否存在key
|
||||||
|
*/
|
||||||
|
public boolean hasKey(final String key) {
|
||||||
|
return redisTemplate.hasKey(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,3 +19,36 @@ git.port=30122
|
||||||
git.backUpIP=pre-git.educoder.net
|
git.backUpIP=pre-git.educoder.net
|
||||||
git.backUpDirs=/data/repositories/2018,/data/repositories/2018-2
|
git.backUpDirs=/data/repositories/2018,/data/repositories/2018-2
|
||||||
git.repoDir=/data/repositories
|
git.repoDir=/data/repositories
|
||||||
|
|
||||||
|
spring.redis.host=127.0.0.1
|
||||||
|
spring.redis.port=6379
|
||||||
|
|
||||||
|
|
||||||
|
#guacamole
|
||||||
|
guacamole.server.ip=121.40.224.66
|
||||||
|
guacamole.server.port=54482
|
||||||
|
|
||||||
|
|
||||||
|
# mysql
|
||||||
|
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
|
||||||
|
spring.datasource.url=jdbc:mysql://rm-bp13v5020p7828r5rso.mysql.rds.aliyuncs.com:3306/testbridge?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
|
||||||
|
spring.datasource.username=testeducoder
|
||||||
|
spring.datasource.password=TEST@123
|
||||||
|
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
|
||||||
|
spring.datasource.initialSize=200
|
||||||
|
spring.datasource.maxActive=400
|
||||||
|
spring.datasource.minIdle=200
|
||||||
|
spring.datasource.validationQuery=select 1
|
||||||
|
spring.datasource.testOnBorrow=false
|
||||||
|
spring.datasource.testOnReturn=false
|
||||||
|
spring.datasource.testWhileIdle=true
|
||||||
|
#mybatis.config-location=classpath:mybatis-config.xml
|
||||||
|
mybatis.type-aliases-package=net.educoder.bridge.**.model
|
||||||
|
mybatis.mapper-locations=classpath:mapper/*.xml
|
||||||
|
#mapper
|
||||||
|
mapper.mappers=tk.mybatis.springboot.util.MyMapper
|
||||||
|
mapper.not-empty=false
|
||||||
|
mapper.identity=MYSQL
|
||||||
|
|
||||||
|
#showSql
|
||||||
|
#logging.level.com.example.demo.dao=debug
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="net.educoder.bridge.dao.WindowsInfoMapper" >
|
||||||
|
<resultMap id="BaseResultMap" type="net.educoder.bridge.common.model.WindowsInfo" >
|
||||||
|
<id column="id" property="id" jdbcType="BIGINT" />
|
||||||
|
<result column="uniq_id" property="uniqId" jdbcType="VARCHAR" />
|
||||||
|
<result column="instance_id" property="instanceId" jdbcType="VARCHAR" />
|
||||||
|
<result column="user_id" property="userID" jdbcType="VARCHAR" />
|
||||||
|
<result column="port" property="port" jdbcType="VARCHAR" />
|
||||||
|
<result column="vnc_port" property="vncPort" jdbcType="VARCHAR" />
|
||||||
|
<result column="template_name" property="templateName" jdbcType="VARCHAR" />
|
||||||
|
<result column="auto_release_time" property="autoReleaseTime" jdbcType="TIMESTAMP" />
|
||||||
|
<result column="forward_table_id" property="forwardTableId" jdbcType="VARCHAR" />
|
||||||
|
<result column="forward_entry_id" property="forwardEntryId" jdbcType="VARCHAR" />
|
||||||
|
<result column="vnc_forward_entry_id" property="vncForwardEntryId" jdbcType="VARCHAR" />
|
||||||
|
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
|
||||||
|
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
|
||||||
|
<result column="status" property="status" jdbcType="INTEGER" />
|
||||||
|
|
||||||
|
</resultMap>
|
||||||
|
<sql id="Base_Column_List" >
|
||||||
|
id, uniq_id, instance_id, user_id, port, vnc_port, template_name, auto_release_time, forward_table_id, forward_entry_id, vnc_forward_entry_id, status
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<select id="selectByUniqId" resultMap="BaseResultMap" parameterType="java.lang.String" >
|
||||||
|
select
|
||||||
|
<include refid="Base_Column_List" />
|
||||||
|
from windows_info
|
||||||
|
where uniq_id = #{uniqId,jdbcType=VARCHAR} and status = 0 limit 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByUserId" resultMap="BaseResultMap" parameterType="java.lang.String" >
|
||||||
|
select
|
||||||
|
<include refid="Base_Column_List" />
|
||||||
|
from windows_info
|
||||||
|
where user_id = #{userID,jdbcType=VARCHAR}
|
||||||
|
and status = 0
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByTpiId" resultMap="BaseResultMap" parameterType="java.lang.String" >
|
||||||
|
select
|
||||||
|
<include refid="Base_Column_List" />
|
||||||
|
from windows_info
|
||||||
|
where uniq_id like concat( #{tpiId,jdbcType=VARCHAR} , '%') and status = 0
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectUniqIdByAutoReleaseTime" resultType="java.lang.String" parameterType="net.educoder.bridge.common.model.WindowsInfo">
|
||||||
|
SELECT uniq_id FROM windows_info
|
||||||
|
where status = 0
|
||||||
|
<if test="autoReleaseTime != null">
|
||||||
|
and auto_release_time < #{autoReleaseTime,jdbcType=TIMESTAMP}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
<select id="selectNotForwardEntryHost" resultMap="BaseResultMap" >
|
||||||
|
SELECT
|
||||||
|
<include refid="Base_Column_List" />
|
||||||
|
FROM windows_info
|
||||||
|
WHERE (forward_entry_id IS NULL OR (vnc_port IS NOT NULL AND vnc_forward_entry_id IS NULL)) and status = 0
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteByUniqId" parameterType="java.lang.String" >
|
||||||
|
update windows_info set status = -1
|
||||||
|
where uniq_id = #{uniqId,jdbcType=VARCHAR}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="insertSelective" useGeneratedKeys="true" keyProperty="id"
|
||||||
|
parameterType="net.educoder.bridge.common.model.WindowsInfo" >
|
||||||
|
insert into windows_info
|
||||||
|
<trim prefix="(" suffix=")" suffixOverrides="," >
|
||||||
|
<if test="id != null" >
|
||||||
|
id,
|
||||||
|
</if>
|
||||||
|
<if test="uniqId != null" >
|
||||||
|
uniq_id,
|
||||||
|
</if>
|
||||||
|
<if test="instanceId != null" >
|
||||||
|
instance_id,
|
||||||
|
</if>
|
||||||
|
<if test="userID != null" >
|
||||||
|
user_id,
|
||||||
|
</if>
|
||||||
|
<if test="port != null" >
|
||||||
|
port,
|
||||||
|
</if>
|
||||||
|
<if test="vncPort != null" >
|
||||||
|
vnc_port,
|
||||||
|
</if>
|
||||||
|
<if test="templateName != null" >
|
||||||
|
template_name,
|
||||||
|
</if>
|
||||||
|
<if test="autoReleaseTime != null" >
|
||||||
|
auto_release_time,
|
||||||
|
</if>
|
||||||
|
<if test="forwardTableId != null" >
|
||||||
|
forward_table_id,
|
||||||
|
</if>
|
||||||
|
<if test="forwardEntryId != null" >
|
||||||
|
forward_entry_id,
|
||||||
|
</if>
|
||||||
|
<if test="vncForwardEntryId != null" >
|
||||||
|
vnc_forward_entry_id,
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null" >
|
||||||
|
create_time,
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null" >
|
||||||
|
update_time,
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
<trim prefix="values (" suffix=")" suffixOverrides="," >
|
||||||
|
<if test="id != null" >
|
||||||
|
#{id,jdbcType=BIGINT},
|
||||||
|
</if>
|
||||||
|
<if test="uniqId != null" >
|
||||||
|
#{uniqId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="instanceId != null" >
|
||||||
|
#{instanceId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="userID != null" >
|
||||||
|
#{userID,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="port != null" >
|
||||||
|
#{port,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="vncPort != null" >
|
||||||
|
#{vncPort,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="templateName != null" >
|
||||||
|
#{templateName,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="autoReleaseTime != null" >
|
||||||
|
#{autoReleaseTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
<if test="forwardTableId != null" >
|
||||||
|
#{forwardTableId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="forwardEntryId != null" >
|
||||||
|
#{forwardEntryId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="vncForwardEntryId != null" >
|
||||||
|
#{vncForwardEntryId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null" >
|
||||||
|
#{createTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null" >
|
||||||
|
#{updateTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
</trim>
|
||||||
|
</insert>
|
||||||
|
<update id="updateByUniqIdSelective" parameterType="net.educoder.bridge.common.model.WindowsInfo" >
|
||||||
|
update windows_info
|
||||||
|
<set >
|
||||||
|
<if test="instanceId != null" >
|
||||||
|
instance_id = #{instanceId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="userID != null" >
|
||||||
|
user_id = #{userID,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="port != null" >
|
||||||
|
port = #{port,jdbcType=INTEGER},
|
||||||
|
</if>
|
||||||
|
<if test="vncPort != null" >
|
||||||
|
vnc_port = #{vncPort,jdbcType=INTEGER},
|
||||||
|
</if>
|
||||||
|
<if test="templateName != null" >
|
||||||
|
template_name = #{templateName,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="autoReleaseTime != null" >
|
||||||
|
auto_release_time = #{autoReleaseTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
<if test="forwardTableId != null" >
|
||||||
|
forward_table_id = #{forwardTableId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="forwardEntryId != null" >
|
||||||
|
forward_entry_id = #{forwardEntryId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="vncForwardEntryId != null" >
|
||||||
|
vnc_forward_entry_id = #{vncForwardEntryId,jdbcType=VARCHAR},
|
||||||
|
</if>
|
||||||
|
<if test="createTime != null" >
|
||||||
|
create_time = #{createTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
<if test="updateTime != null" >
|
||||||
|
update_time = #{updateTime,jdbcType=TIMESTAMP},
|
||||||
|
</if>
|
||||||
|
</set>
|
||||||
|
where uniq_id = #{uniqId,jdbcType=VARCHAR}
|
||||||
|
</update>
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue