会话启动接口器的集成

This commit is contained in:
lqyan
2024-02-02 13:54:12 +08:00
parent ea32eda8f3
commit 0106d1a787
18 changed files with 587 additions and 59 deletions

View File

@@ -1,5 +1,7 @@
package com.jhinno.sdk.openapi;
import lombok.Getter;
/**
* <p>
* 这个异常标识传入的SDK方法的参数错误
@@ -17,13 +19,9 @@ package com.jhinno.sdk.openapi;
* @author yanlongqi
* @date 2024/1/31 10:36
*/
@Getter
public class ArgsException extends RuntimeException {
/**
* 用户名
*/
private String username;
/**
* 错误信息
*/
@@ -69,15 +67,6 @@ public class ArgsException extends RuntimeException {
@Override
public String getMessage() {
return String.format("[ErrorMessage]:%s", errorMessage);
}
/**
* 获取一个错误信息
*
* @return 错误信息
*/
public String getErrorMessage() {
return errorMessage;
}

View File

@@ -21,4 +21,15 @@ public class CommonConstant {
* 默认的token有效时间单位分钟
*/
public static final int DEFAULT_TOKEN_EFFECTIVE_TIME = 30;
/**
* token 默认剩余时间
*/
public static final int DEFAULT_TOKEN_RESIDUE_TIME = 5;
/**
* 获取token时AES加密的默认key
*/
public static final String DEFAULT_AES_KEY = "jin5no@aqec8gtw6";
}

View File

@@ -28,11 +28,21 @@ package com.jhinno.sdk.openapi;
*/
public class ServiceException extends RuntimeException {
/**
* 请求错误码
*/
private int errorCode;
/**
* 错误信息
*/
private String errorMessage;
/**
* 请求的路径
*/
private String requestPath;
/**
* 创建一个默认的实例
*/
@@ -44,21 +54,60 @@ public class ServiceException extends RuntimeException {
/**
* 创建一个包含错误消息的实例。
*
* @param requestPath 请求路径
* @param errorCode 错误码
* @param errorMessage 错误信息
*/
public ServiceException(String errorMessage) {
this(errorMessage, null);
public ServiceException(String requestPath, int errorCode, String errorMessage) {
this(requestPath, errorCode, errorMessage, null);
}
/**
* 创建一个包含错误消息和异常的实例
*
* @param requestPath 请求路径
* @param errorCode 错误码
* @param errorMessage 错误信息
* @param cause 一个异常
*/
public ServiceException(String errorMessage, Throwable cause) {
public ServiceException(String requestPath, int errorCode, String errorMessage, Throwable cause) {
super(null, cause);
this.errorMessage = errorMessage;
this.requestPath = requestPath;
this.errorCode = errorCode;
}
/**
* 获取请求码
*
* @return 请求码
*/
public int getErrorCode() {
return errorCode;
}
/**
* 获取错信息
*
* @return 错误信息
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* 获取请求路径
*
* @return 请求路径
*/
public String getRequestPath() {
return requestPath;
}
@Override
public String getMessage() {
return String.format("%s\n[请求路径]: %s\n[错误码]: %s", errorMessage, requestPath, errorCode);
}
}

View File

@@ -1,5 +1,7 @@
package com.jhinno.sdk.openapi.api;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson2.TypeReference;
import com.jhinno.sdk.openapi.ArgsException;
import com.jhinno.sdk.openapi.CommonConstant;
@@ -13,6 +15,8 @@ import java.util.HashMap;
import java.util.Map;
/**
* 定义一个请求的执行器,
*
* @author yanlongqi
* @date 2024/1/30 19:39
*/
@@ -21,8 +25,27 @@ public class JHApiExecution {
/**
* JHApiClient实例
*/
private static JHApiClient JH_API_CLIENT;
public JHApiClient jhApiClient;
/**
* token的超时时间
*/
private int tokenTimeout = CommonConstant.DEFAULT_TOKEN_EFFECTIVE_TIME;
/**
* token提前获取的时间
*/
private int tokenResidueTime = CommonConstant.DEFAULT_TOKEN_RESIDUE_TIME;
/**
* 获取一个执行器的实例
*
* @param jhApiClient 请求的客户端
*/
protected JHApiExecution(JHApiClient jhApiClient) {
this.jhApiClient = jhApiClient;
}
/**
* 用户令牌的缓存
@@ -35,14 +58,33 @@ public class JHApiExecution {
* @param jhApiClient 客户端实例
*/
public void setJHApiClient(JHApiClient jhApiClient) {
this.JH_API_CLIENT = jhApiClient;
this.jhApiClient = jhApiClient;
}
/**
* 设置token超时的时间单位分钟
*
* @param tokenTimeout token的超时时间
*/
public void setTokenTimeout(int tokenTimeout) {
this.tokenTimeout = tokenTimeout;
}
/**
* 设置提前获取token的时间单位分钟
*
* @param tokenResidueTime 提前获取token的时间
*/
public void setTokenResidueTime(int tokenResidueTime) {
this.tokenResidueTime = tokenResidueTime;
}
/**
* 获取用户的Token
*
* @param username 用户名
* @param isForce 是否强制获取token
* @param isForce 是否强制获取toke
* @return 用户的token
*/
public String getToken(String username, boolean isForce) {
@@ -50,15 +92,22 @@ public class JHApiExecution {
throw new ArgsException("用户名称不能为空!");
}
TokenInfo tokenInfo = TOKEN_INFO_MAP.get(username);
// 如果是强制获取、用户令牌为空、用户令牌过期等,则获取令牌
if (isForce || tokenInfo == null || System.currentTimeMillis() - tokenInfo.getCurrentTimestamp() <= CommonConstant.DEFAULT_TOKEN_EFFECTIVE_TIME * 60 * 1000) {
Map<String, Object> params = new HashMap<>(2);
String url = JHApiClient.getUrl(AuthPathConstant.AUTH_TOKEN, params);
ResponseResult<Token> result = JH_API_CLIENT.get(url, new TypeReference<ResponseResult<Token>>() {
// 防止因为服务器时间的问题二导致token不可用可以通过此配置提前获取token
int tokenEffectiveTime = (tokenTimeout - tokenResidueTime) * 60 * 1000;
// 如果是强制获取、用户令牌为空、用户令牌过期等,则获取令牌
if (isForce || tokenInfo == null || System.currentTimeMillis() - tokenInfo.getCurrentTimestamp() < tokenEffectiveTime) {
Map<String, Object> params = new HashMap<>(2);
params.put("timeout", tokenTimeout);
AES aes = new AES(CommonConstant.DEFAULT_AES_KEY.getBytes());
String base64 = aes.encryptBase64(String.format("%s,%s", username, System.currentTimeMillis()));
params.put("username", base64);
String url = JHApiClient.getUrl(AuthPathConstant.AUTH_TOKEN_PATH, params);
ResponseResult<Token> result = jhApiClient.get(url, new TypeReference<ResponseResult<Token>>() {
});
if (StringUtils.equals(result.getResult(), CommonConstant.FAILED)) {
throw new ServiceException("获取token失败");
throw new ServiceException(AuthPathConstant.AUTH_TOKEN_PATH, result.getCode(), result.getMessage());
}
Token token = result.getData();
tokenInfo = new TokenInfo();
@@ -70,5 +119,27 @@ public class JHApiExecution {
return tokenInfo.getToken();
}
/**
* 获取用户的Token获取缓存不强制获取
*
* @param username 用户名
* @return 用户的token
*/
public String getToken(String username) {
return getToken(username, false);
}
/**
* 构建一个带token的请求头
*
* @param username 用户名
* @return 请求头
*/
protected Map<String, String> getHeaders(String username) {
Map<String, String> headers = new HashMap<>();
headers.put("token", getToken(username));
return headers;
}
}

View File

@@ -0,0 +1,13 @@
package com.jhinno.sdk.openapi.api.app;
/**
* @author yanlongqi
* @date 2024/2/1 16:27
*/
public class AppPathConstant {
/**
* 申请会话
*/
public static final String APPS_START_PATH = "/ws/api/apps/{appId}/start";
}

View File

@@ -0,0 +1,90 @@
package com.jhinno.sdk.openapi.api.app;
import lombok.Data;
/**
* 启动会话的请求参数
*
* @author yanlongqi
* @date 2024/2/1 16:31
*/
@Data
public class AppStartRequest {
/**
* 是否启动一个新的会话非必填默认false
* <p>
* 如果是true则会启动一个新的会话否则复用已经启动好的会话
*/
private boolean startNew;
/**
* 工作路径
*/
private String cwd;
/**
* 工作文件
*/
private String workFile;
/**
* 指标
*/
private String metrics;
/**
* <p>
* 请求获取到的JHClient协议链接的过期目标时间。必填
* </p>
* <p>
* 注意:
* </p>
* 1. 该时间戳是获取到的加密串的过期时间,需要传入一个未来的时间
* 当前是2024-02-01 17:53:12假设加密串5分钟之后过期则该参数为20240101175812
* </p>
* <p>
* 2. 该时间错由景行的JHClient进行验证并不是在服务端进行验证
* 所以为了防止客户端的时间和服务器的时间不一致而导会话不能启动,
* 因此此字段尽量在浏览器的生成
* </p>
*/
private String currentTimestamp;
/**
* 会话类型
*/
private String sessionType;
private String sessionOwner;
/**
* 启动参数
* <p>
* 例如启动一个demo.exe 该demo.exe需要传入用户名在命令行的的操作为 demo.exe -u admin
* </p>
*
* <p>
* 此处传入的参数则为:"-u admin"
* </p>
*/
private String param;
private String loginUser;
private String sessionId;
private String remoteAddr;
private String remotePort;
private boolean isInMeetingRoom;
private String currentMeetingId;
private boolean jhClientInstalled;
}

View File

@@ -0,0 +1,38 @@
package com.jhinno.sdk.openapi.api.app;
import com.alibaba.fastjson2.JSON;
import lombok.Getter;
/**
* 会话启动信息
*
* @author yanlongqi
* @date 2024/2/1 18:39
*/
@Getter
public class AppStartedInfo {
/**
* JHClient的地址用于拉起对应会话的JHClient客户端
*
* <ul>
* <li>
* 测试时:可将其粘贴纸浏览器的地址栏里面拉起JHClient客户端
* </li>
* <li>
* 开发时:通过使用a标签或者使用iframe的方式拉起JHClient客户端
* </li>
* </ul>
*/
private String jhappUrl;
/**
* 会话id
*/
private String desktopId;
// @Override
// public String toString() {
// return JSON.toJSONString(this);
// }
}

View File

@@ -0,0 +1,51 @@
package com.jhinno.sdk.openapi.api.app;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.TypeReference;
import com.jhinno.sdk.openapi.CommonConstant;
import com.jhinno.sdk.openapi.ServiceException;
import com.jhinno.sdk.openapi.api.JHApiExecution;
import com.jhinno.sdk.openapi.api.ResponseResult;
import com.jhinno.sdk.openapi.client.JHApiClient;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* @author yanlongqi
* @date 2024/2/1 16:26
*/
public class JHAppApiExecution extends JHApiExecution {
/**
* 获取一个执行器的实例
*
* @param jhApiClient 请求的客户端
*/
public JHAppApiExecution(JHApiClient jhApiClient) {
super(jhApiClient);
}
/**
* 启动一个会话
*
* @param username 用户名
* @param appId 应用拆
* @param appStartRequest 启动参数
* @return JHClient协议链接
*/
public AppStartedInfo desktopStart(String username, String appId, AppStartRequest appStartRequest) {
String path = AppPathConstant.APPS_START_PATH.replace("{appId}", appId);
ResponseResult<List<AppStartedInfo>> result = jhApiClient.post(path, appStartRequest, getHeaders(username), new TypeReference<ResponseResult<List<AppStartedInfo>>>() {
});
if (StringUtils.equals(result.getResult(), CommonConstant.FAILED)) {
throw new ServiceException(path, result.getCode(), result.getMessage());
}
List<AppStartedInfo> data = result.getData();
if (CollectionUtil.isEmpty(data)) {
throw new ServiceException(path, result.getCode(), "获取到的会话信息为空");
}
return data.get(0);
}
}

View File

@@ -1,12 +0,0 @@
package com.jhinno.sdk.openapi.api.auth;
import com.jhinno.sdk.openapi.api.JHApiExecution;
/**
* @author yanlongqi
* @date 2024/1/30 19:47
*/
public class AuthJHApiClientExecution extends JHApiExecution {
}

View File

@@ -9,7 +9,7 @@ public class AuthPathConstant {
/**
* 获取用户token
*/
public static final String AUTH_TOKEN = "/ws/api/auth/token";
public static final String AUTH_TOKEN_PATH = "/ws/api/auth/token";
/**
* 注销token

View File

@@ -20,17 +20,17 @@ public class DefaultHttpClientConfig {
/**
* 默认socket连接超时的时间
* 默认socket连接超时的时间(单位:秒)
*/
public static final int SOCKET_TIMEOUT = 5000;
/**
* 默认连接超时的时间
* 默认连接超时的时间(单位:秒)
*/
public static final int CONNECT_TIMEOUT = 5000;
/**
* 默认请求超时的时间
* 默认请求超时的时间(单位:秒)
*/
public static final int CONNECTION_REQUEST_TIMEOUT = 5000;
}

View File

@@ -42,12 +42,14 @@ public class JHApiClient {
/**
* 基础的请求URL地址
* https://192.168.3.12/appform
* <p>
* 如:<a href="https://192.168.3.12/appform">https://192.168.3.12/appform</a>
* </p>
*/
private String baseUrl;
private final String baseUrl;
/**
* 初始化一个JHApiClient的实例值得注意的是该实例只能内部创建
* 初始化一个JHApiClient的实例可使用自定义的客户端
*
* @param baseUrl 景行接口服务的基础地址
* @param closeableHttpClient 可关闭的HTTP客户端
@@ -66,7 +68,7 @@ public class JHApiClient {
/**
* 每次发送请求的配置,如果该配置未进行设置则走{@link DefaultHttpClientConfig中的默认配置
* 每次发送请求的配置,如果该配置未进行设置则走 {@link DefaultHttpClientConfig 中的默认配置
*/
private RequestConfig requestConfig;
@@ -85,7 +87,7 @@ public class JHApiClient {
/**
* <p>
* 通过{@link DefaultHttpClientConfig默认配置的最大连接数和服务每次能并行接收的请求数量构建一个JHApiClient实例
* 通过 {@link DefaultHttpClientConfig 默认配置的最大连接数和服务每次能并行接收的请求数量构建一个JHApiClient实例
* </p>
*
* @param baseUrl 景行接口服务的基础地址
@@ -96,7 +98,7 @@ public class JHApiClient {
}
/**
* 通过外部传入的{@link CloseableHttpClient构建一个请求客户端
* 通过外部传入的 {@link CloseableHttpClient 构建一个请求客户端
* <p>
*
* @param httpClient 请求连接池
@@ -151,9 +153,9 @@ public class JHApiClient {
* </p>
*
* <p>
* {@link JHApiClient 默认只配置了 socket连接超时的时间(socketTimeout) 、连接超时的时间(connectTimeout)、
* 请求超时的时间(connectionRequestTimeout)这三项,其默认配置在{@link DefaultHttpClientConfig中。
* 如果你要自定义你自己的配置,则可以通过{@link HttpClients构建自己的RequestConfig来请求接口
* {@link JHApiClient 默认只配置了 socket连接超时的时间(socketTimeout) 、连接超时的时间(connectTimeout)、
* 请求超时的时间(connectionRequestTimeout)这三项,其默认配置在{@link DefaultHttpClientConfig 中。
* 如果你要自定义你自己的配置,则可以通过{@link HttpClients 构建自己的RequestConfig来请求接口
* </p>
*
* @param requestConfig HTTP请求的配置