diff --git a/core/src/main/java/com/taobao/arthas/core/shell/session/SessionManager.java b/core/src/main/java/com/taobao/arthas/core/shell/session/SessionManager.java new file mode 100644 index 000000000..011888fef --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/session/SessionManager.java @@ -0,0 +1,9 @@ +package com.taobao.arthas.core.shell.session; + +/** + * Arthas Session Manager + * @author gongdewei 2020-03-20 + */ +public interface SessionManager { + +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/session/impl/SessionManagerImpl.java b/core/src/main/java/com/taobao/arthas/core/shell/session/impl/SessionManagerImpl.java new file mode 100644 index 000000000..9ba2ed8e6 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/session/impl/SessionManagerImpl.java @@ -0,0 +1,9 @@ +package com.taobao.arthas.core.shell.session.impl; + +/** + * Arthas Session Manager + * @author gongdewei 2020-03-20 + */ +public interface SessionManagerImpl { + +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java index d241fe400..8276ecf4d 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java @@ -7,6 +7,7 @@ import java.net.URI; import java.net.URL; import com.taobao.arthas.common.IOUtils; +import com.taobao.arthas.core.shell.term.impl.http.api.HttpApiHandler; import com.taobao.arthas.core.util.LogUtil; import com.taobao.middleware.logger.Logger; @@ -30,6 +31,7 @@ import io.termd.core.util.Logging; /** * @author Julien Viet * @author hengyunabc 2019-11-06 + * @author gongdewei 2020-03-18 */ public class HttpRequestHandler extends SimpleChannelInboundHandler { private static final Logger logger = LogUtil.getArthasLogger(); @@ -38,10 +40,13 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler options; + + @Override + public String toString() { + return "ApiRequest{" + + "action='" + action + '\'' + + ", sync=" + sync + + ", command='" + command + '\'' + + ", options=" + options + + '}'; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public boolean isSync() { + return sync; + } + + public void setSync(boolean sync) { + this.sync = sync; + } + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } + + public Map getOptions() { + return options; + } + + public void setOptions(Map options) { + this.options = options; + } +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiResponse.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiResponse.java new file mode 100644 index 000000000..5382aedff --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiResponse.java @@ -0,0 +1,72 @@ +package com.taobao.arthas.core.shell.term.impl.http.api; + +/** + * Http Api exception + * @author gongdewei 2020-03-19 + */ +public class ApiResponse { + private String requestId; + private ApiState state; + private String message; + private String sessionId; + private String consumerId; + private String jobId; + private T body; + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public ApiState getState() { + return state; + } + + public void setState(ApiState state) { + this.state = state; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getConsumerId() { + return consumerId; + } + + public void setConsumerId(String consumerId) { + this.consumerId = consumerId; + } + + public String getJobId() { + return jobId; + } + + public void setJobId(String jobId) { + this.jobId = jobId; + } + + public T getBody() { + return body; + } + + public void setBody(T body) { + this.body = body; + } + +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiState.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiState.java new file mode 100644 index 000000000..ec3cfce0d --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/ApiState.java @@ -0,0 +1,14 @@ +package com.taobao.arthas.core.shell.term.impl.http.api; + +/** + * Http API response state + * @author gongdewei 2020-03-19 + */ +public enum ApiState { + /** accepted */ + SCHEDULED, + RUNNING, + SUCCEEDED, + FAILED, + REFUSED +} diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/HttpApiHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/HttpApiHandler.java new file mode 100644 index 000000000..f4662c3c9 --- /dev/null +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/api/HttpApiHandler.java @@ -0,0 +1,111 @@ +package com.taobao.arthas.core.shell.term.impl.http.api; + +import com.alibaba.fastjson.JSON; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.taobao.arthas.core.server.ArthasBootstrap; +import com.taobao.arthas.core.shell.ShellServer; +import com.taobao.arthas.core.util.LogUtil; +import com.taobao.arthas.core.util.StringUtils; +import com.taobao.middleware.logger.Logger; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.*; +import io.netty.util.CharsetUtil; + + +/** + * Http Restful Api Handler + * @author gongdewei 2020-03-18 + */ +public class HttpApiHandler { + + private static final Logger logger = LogUtil.getArthasLogger(); + + public HttpResponse handle(FullHttpRequest request) throws Exception { + DefaultFullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), + HttpResponseStatus.OK); + + ApiResponse result = null; + String requestBody = null; + try { + HttpMethod method = request.method(); + if (HttpMethod.POST.equals(method)){ + requestBody = getBody(request); + ApiRequest apiRequest = parseRequest(requestBody); + result = processRequest(apiRequest); + } else { + result = createResponse(ApiState.REFUSED, "Unsupported http method: "+method.name()); + } + } catch (Throwable e) { + result = createResponse(ApiState.FAILED, "Process request error: "+e.getMessage()); + logger.error("arthas", "arthas process http api request error: " + request.uri()+", request body: "+requestBody, e); + } + if (result == null) { + result = createResponse(ApiState.FAILED, "The request was not processed"); + } + + String jsonResult = JSON.toJSONString(result); + response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=utf-8"); + response.content().writeBytes(jsonResult.getBytes("UTF-8")); + return response; + } + + private ApiRequest parseRequest(String requestBody) throws ApiException { + if (StringUtils.isBlank(requestBody)){ + throw new ApiException("parse request failed: request body is empty"); + } + try { + //Object jsonRequest = JSON.parse(requestBody); + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(requestBody, ApiRequest.class); + } catch (Exception e) { + throw new ApiException("parse request failed: "+e.getMessage(), e); + } + } + + private ApiResponse processRequest(ApiRequest apiRequest) { + + String action = apiRequest.getAction(); + if ("exec".equalsIgnoreCase(action)){ + return processExecRequest(apiRequest); + } else if("init_session".equalsIgnoreCase(action)){ + return processInitSessionRequest(apiRequest); + } else if("close_session".equalsIgnoreCase(action)){ + return processCloseSessionRequest(apiRequest); + } + + return createResponse(ApiState.REFUSED, "Unsupported action: "+action); + } + + private ApiResponse processInitSessionRequest(ApiRequest apiRequest) { +// ShellServer shellServer = getShellServer(); +// shellServer.createShell() + + return null; + } + + private ApiResponse processCloseSessionRequest(ApiRequest apiRequest) { + return null; + } + + private ApiResponse processExecRequest(ApiRequest apiRequest) { + String command = apiRequest.getCommand(); + //TODO + return null; + } + + private ApiResponse createResponse(ApiState apiState, String message) { + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setState(apiState); + apiResponse.setMessage(message); + return apiResponse; + } + + private String getBody(FullHttpRequest request){ + ByteBuf buf = request.content(); + return buf.toString(CharsetUtil.UTF_8); + } + +// private ShellServer getShellServer() { +// return ArthasBootstrap.getInstance().getShellServer(); +// } +}