nas延迟机制(cookie)

这个Java程序展示了如何使用Apache HttpClient库发送POST和GET请求,处理Cookie,设置超时,并从响应中获取数据。它包括执行HTTP操作,如设置请求头,处理Cookie,以及保存和重用Cookie。
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpClient {
// 创建CookieStore实例
static CookieStore cookieStore = null;
static HttpClientContext context = null;
String sendUrl = "";
String getUrl = "";
String openUrl = "";
String loginErrorUrl = "";
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><batch-contract-dTO>\n</batch-contract-dTO>";

public String postPrintTask(Map<String, String> parameterMap) {
String returnValue = null;
System.out.println("1.sendxml......");

// // 创建HttpClientBuilder
// HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// // HttpClient
// CloseableHttpClient client = httpClientBuilder.build();
// 直接创建client
//CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();

HttpPost httpPost = new HttpPost(sendUrl);

//设置连接超时
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(15000).build();//设置请求和传输超时时间
httpPost.setConfig(requestConfig);
try {
UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(getParam(parameterMap), "utf-8");
httpPost.setEntity(postEntity);
System.out.println("request line:" + httpPost.getRequestLine());
// 执行post请求
HttpResponse httpResponse = client.execute(httpPost);
String cookie = httpResponse.getFirstHeader("Set-Cookie").getValue();
if (cookie != null && cookie.startsWith(loginErrorUrl)) {
System.out.println("----loginError");
}
System.out.println("cookie:" + cookie);
//printResponse(httpResponse);

int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != 200) {
return String.valueOf(statusCode);
}
//打印平台返回数据
String returnValueText = StringUtils.castNullToEmpty(EntityUtils.toString(httpResponse.getEntity()));
//返回的returnValue值
returnValue = returnValueText.substring(returnValueText.indexOf("=") + 1);
System.out.println(returnValue + ":" + httpResponse.getEntity().isStreaming());
// cookie store
setCookieStore(httpResponse);
// context
//setContext();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流并释放资源
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnValue;
}

public String getPdfStream(Map<String, String> parameterMap, String parameterStr) {
System.out.println("3.open.....");
String returnValue = null;
CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
HttpGet httpGet = new HttpGet(openUrl + parameterStr);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(15000).build();//设置请求和传输超时时间
httpGet.setConfig(requestConfig);
System.out.println("request line:" + httpGet.getRequestLine());
try {
int statusCode = -1;
// 执行get请求
HttpResponse httpResponse = client.execute(httpGet);
statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != 200) {
System.out.println("打开pdf流失败.. status=" + statusCode);
return returnValue;
}
//httpResponse.getEntity().getContent()内容不可重复读写,只能一次消耗
BufferedInputStream buff_in = new BufferedInputStream(httpResponse.getEntity().getContent());
ByteArrayOutputStream byte_out = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int read = 0;
while ((read = buff_in.read(b)) > 0) {
byte_out.write(b, 0, read);
}

OutputStream xmlOuts = new FileOutputStream("D:\\aa.pdf");
xmlOuts.write(byte_out.toByteArray());
xmlOuts.flush();
xmlOuts.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流并释放资源
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnValue;
}

public void reqPrintPlat() {
Map<String, String> parameterMap = new HashMap<String, String>();
parameterMap.put("sysid", "icoreacss");
parameterMap.put("docno", "8888108888100431");
parameterMap.put("doctype", "01");
parameterMap.put("xslFileName", "I0009");
parameterMap.put("userName", "V_PA003_ICORE_ACSS");
parameterMap.put("password", "Q52reeE1");
parameterMap.put("isSigned", "false");
parameterMap.put("datatype", "XML");
parameterMap.put("maxTimeForCheck", "50000");
parameterMap.put("sleepTime", "2000");

//get方式请求参数
StringBuffer parameterStr = new StringBuffer("?");
parameterStr.append("sysid=" + parameterMap.get("sysid"));
parameterStr.append("&docno=" + parameterMap.get("docno"));
parameterStr.append("&doctype=" + parameterMap.get("doctype"));
parameterStr.append("&xslFileName=" + parameterMap.get("xslFileName"));
parameterStr.append("&userName=" + parameterMap.get("userName"));
parameterStr.append("&password=" + parameterMap.get("password"));
parameterStr.append("&isSigned=" + parameterMap.get("isSigned"));
parameterStr.append("&datatype=" + parameterMap.get("datatype"));
System.out.println(parameterStr);

parameterMap.put("xmlString", content);
String returnValue = postPrintTask(parameterMap);
if ("0".equals(returnValue)) {
returnValue = checkPdfExistWithWait(parameterMap, parameterStr.toString());
if ("0".equals(returnValue)) {
getPdfStream(parameterMap, parameterStr.toString());
}
}
}

public String checkPdfExistWithWait(Map<String, String> parameterMap, String parameterStr) {
System.out.println("2.get.....");
String returnValue = null;
CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
HttpGet httpGet = new HttpGet(getUrl + parameterStr);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(15000).build();//设置请求和传输超时时间
httpGet.setConfig(requestConfig);
System.out.println("request line:" + httpGet.getRequestLine());
try {
int statusCode = -1;
int maxTime = StringUtils.isEmptyStr(parameterMap.get("maxTimeForCheck")) ? (5 * 1000) : Integer
.parseInt(parameterMap.get("maxTimeForCheck"));
//该休眠时间配置值为2000毫秒,代码固定值为500毫秒,优先取配置值
int maxSleepTime = StringUtils.isEmptyStr(parameterMap.get("sleepTime")) ? 500 : Integer
.parseInt(parameterMap.get("sleepTime"));
Date beginDate = new Date();
while (new Date().getTime() - beginDate.getTime() <= maxTime) {
// 执行get请求
HttpResponse httpResponse = client.execute(httpGet);
statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode == 200) {
//打印平台返回数据
String returnValueText = StringUtils
.castNullToEmpty(EntityUtils.toString(httpResponse.getEntity()));
//返回的returnValue值
returnValue = returnValueText.substring(returnValueText.indexOf("=") + 1);
if ("0".equals(returnValue)) {
System.out.println("get成功:" + returnValue);
break;
}
}
System.out.println("getPdf:" + returnValue + ":" + httpResponse.getEntity().isStreaming());
//线程休眠
Thread.sleep(maxSleepTime);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
// 关闭流并释放资源
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnValue;
}

public static void main(String[] args) throws Exception {

HttpClient test = new HttpClient();
test.reqPrintPlat();
/*Thread.sleep(3000);
test.testCookieStore();*/

//Thread.sleep(3000);
//test.testContext();
}

public void testContext() throws Exception {
System.out.println("----testContext----");
// 使用context方式
CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
//CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(testUrl);
//设置连接超时
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(15000).build();//设置请求和传输超时时间
httpGet.setConfig(requestConfig);

System.out.println("request line:" + httpGet.getRequestLine());
try {
// 执行get请求
HttpResponse httpResponse = client.execute(httpGet, context);
//System.out.println("context cookies:"+ context.getCookieStore().getCookies());
//printResponse(httpResponse);
String cookie2 = httpResponse.getFirstHeader("Set-Cookie").getValue();
System.out.println("cookie2:" + cookie2);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流并释放资源
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static void printResponse(HttpResponse httpResponse) throws ParseException, IOException {
// 获取响应消息实体
HttpEntity entity = httpResponse.getEntity();
// 响应状态
System.out.println("status:" + httpResponse.getStatusLine());
System.out.println("headers:");
HeaderIterator iterator = httpResponse.headerIterator();
while (iterator.hasNext()) {
System.out.println("\t" + iterator.next());
}
// 判断响应实体是否为空
if (entity != null) {
String responseString = EntityUtils.toString(entity);
System.out.println("response length:" + responseString.length());
System.out.println("response content:" + responseString.replace("\r\n", ""));
}
}

/*public static void setContext() {
System.out.println("----setContext");
context = HttpClientContext.create();
Registry<CookieSpecProvider> registry = RegistryBuilder.<CookieSpecProvider> create()
.register(CookieSpecs.BEST_MATCH, new BestMatchSpecFactory())
.register(CookieSpecs.BROWSER_COMPATIBILITY, new BrowserCompatSpecFactory()).build();
context.setCookieSpecRegistry(registry);
context.setCookieStore(cookieStore);
}*/

public static void setCookieStore(HttpResponse httpResponse) {
System.out.println("----setCookieStore");
cookieStore = new BasicCookieStore();
// JSESSIONID
String setCookie = httpResponse.getFirstHeader("Set-Cookie").getValue();
//System.out.println("------setCookie:-------" + setCookie);
String JSESSIONID = setCookie.substring("BIGipServerepcis-print_StgPool=".length(), setCookie.indexOf(";"));
//System.out.println("BIGipServerepcis-print_StgPool:" + JSESSIONID);
// 新建一个Cookie
//BasicClientCookie cookie = new BasicClientCookie("JSESSIONID",JSESSIONID);
BasicClientCookie cookie = new BasicClientCookie("BIGipServerepcis-print_StgPool", JSESSIONID);
cookie.setVersion(0);
cookie.setDomain("epcisprint-staging.paic.com.cn");
cookie.setPath("/");
// cookie.setAttribute(ClientCookie.VERSION_ATTR, "0");
// cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "127.0.0.1");
// cookie.setAttribute(ClientCookie.PORT_ATTR, "8080");
// cookie.setAttribute(ClientCookie.PATH_ATTR, "/CwlProWeb");
cookieStore.addCookie(cookie);
}

public static List<NameValuePair> getParam(Map parameterMap) {
List<NameValuePair> param = new ArrayList<NameValuePair>();
Iterator it = parameterMap.entrySet().iterator();
while (it.hasNext()) {
Entry parmEntry = (Entry) it.next();
param.add(new BasicNameValuePair((String) parmEntry.getKey(), (String) parmEntry.getValue()));
}
return param;
}
@Slf4j @Component public class RequestValidator { /** * Validate the request, including service type and parameters. * * @param information All information for the HTTP request * * @throws IllegalRequestException The request is an invalid request, such as a wrong service type, a lack of * parameters or a wrong parameters. */ public void validateRequest(AbstractRequestChannelInformation information) throws IllegalRequestException { if (information instanceof GetRequestChannelInformation) { GetRequestChannelInformation getChannelInformation = (GetRequestChannelInformation) information; Map<String, String> params = getChannelInformation.getParams(); validateRelayParams(params); validateRelayAuthContext(getChannelInformation.isFFmpegChannel() ? ChannelType.FFMPEG : ChannelType.SINK, params.get(ParamKey.TYPE), getChannelInformation.getAuthContext()); if (getChannelInformation.getChannelVersion() == ChannelVersion.VERSION_1_3) { ContentType contentType = getChannelInformation.getContentType(); if (contentType == null) { // ws建立不需要contentType if (ObjectUtil.equals(getChannelInformation.getStatisticInformation().getService(), RelayConsts.Service.WS_LIVE_VIEW_ESTABLISH)) { return; } throw new IllegalRequestException("POST request without contentType"); } else if (!contentType.isMultiPart()) { throw new IllegalRequestException("Sink channel of version 1.3 need multipart"); } } } else if (information instanceof PostRequestChannelInformation) { PostRequestChannelInformation postChannelInformation = (PostRequestChannelInformation) information; Map<String, String> params = postChannelInformation.getParams(); validateRelayParams(params); validateRelayAuthContext(ChannelType.SOURCE, params.get(ParamKey.TYPE), postChannelInformation.getAuthContext()); ContentType contentType = postChannelInformation.getContentType(); if (contentType == null) { throw new IllegalRequestException("POST request without contentType"); } else if (postChannelInformation.getChannelVersion() == ChannelVersion.VERSION_1_3 && !contentType.isMultiPart()) { throw new IllegalRequestException("Source channel of version 1.3 need multipart"); } } else if (information instanceof BidirectionRequestChannelInformation) { BidirectionRequestChannelInformation bidirectionChannelInformation = (BidirectionRequestChannelInformation) information; Map<String, String> params = bidirectionChannelInformation.getParams(); validateRelayParams(params); validateRelayAuthContext(ChannelType.BIDIRECTION, params.get(ParamKey.TYPE), bidirectionChannelInformation.getAuthContext()); ContentType contentType = bidirectionChannelInformation.getContentType(); if (contentType == null) { if (ObjectUtil.equals(bidirectionChannelInformation.getStatisticInformation().getService(), RelayConsts.Service.WS_LIVE_VIEW_ESTABLISH) || ObjectUtil .equals(bidirectionChannelInformation.getStatisticInformation().getService(), RelayConsts.Service.WS_PALYBACK_ESTABLISH)) { return; } throw new IllegalRequestException("POST request without contentType"); } else if (!contentType.isMultiPart()) { throw new IllegalRequestException("Bidirection channel of version 1.3 need multipart"); } } else if (information instanceof ControlRequestChannelInformation) { ControlRequestChannelInformation controlChannelInformation = (ControlRequestChannelInformation) information; Map<String, String> params = controlChannelInformation.getParams(); if (!params.containsKey(ParamKey.DEVICE_ID)) { throw new IllegalRequestException("Control request without device id"); } if (controlChannelInformation.getHttpMethod() != HttpMethod.OPTIONS) { ContentType contentType = controlChannelInformation.getContentType(); if (contentType == null) { throw new IllegalRequestException("POST request without contentType"); } else if (contentType.isMultiPart()) { throw new IllegalRequestException("control request should not be multipart"); } } } } private void validateRelayParams(Map<String, String> relayParams) { if (!relayParams.containsKey(ParamKey.DEVICE_ID)) { throw new IllegalRequestException("Relay request without device id"); } String streamType = relayParams.get(ParamKey.TYPE); if (streamType == null) { throw new IllegalRequestException("Relay request without type"); } validateStreamParams(streamType, relayParams); } public void validateRelayParams(Map<String, String> relayParams, String wantedDeviceId, String... wantedStreamTypes) { String paramDeviceId = relayParams.get(ParamKey.DEVICE_ID); if (!wantedDeviceId.equals(paramDeviceId)) { throw new IllegalRequestException("Wrong deviceId:" + paramDeviceId); } String paramStreamType = relayParams.get(ParamKey.TYPE); if (paramStreamType == null) { throw new IllegalRequestException("Relay service without type"); } if (wantedStreamTypes == null || wantedStreamTypes.length == 0) { throw new IllegalRequestException("Wrong type:" + paramStreamType); } for (String wantedType : wantedStreamTypes) { if (paramStreamType.equals(wantedType)) { validateStreamParams(paramStreamType, relayParams); return; } } throw new IllegalRequestException("Wrong type:" + paramStreamType); } private void validateStreamParams(String streamType, Map<String, String> params) { switch (streamType) { // VIDEO, MIXED, AUDIO均无需处理 case Type.VIDEO: case RelayConsts.Type.SMART_IPC: case Type.MIXED: case Type.AUDIO: // Resolution is only used as key to build binding id. Device and app have the same resolution will be bound // with each other. The known values of resolution are listed as follows: // 1. For video and mixed type: VGA, HD, QVGA // 2. For audio type: AAC, PCM, MP2 // 3. For nvr type: VGA, HD, QVGA or AAC, PCM, MP2 // When the resolution is missing, the binding key could be built without resolution. // When the resolution is other value, the resolution is valid. For nvr type, other resolution is regarded // as video resolution. break; case RelayConsts.Type.SMART_NVR: case Type.NVR: if (params.get(ParamKey.CHANNEL) == null) { throw new IllegalRequestException("Type NVR without channel"); } break; // SDVOD, DTSPK校验相同 case Type.SDVOD: case Type.DTSPK: if (params.get(ParamKey.PLAYERID) == null) { throw new IllegalRequestException("Sdvod or Dtspk without player id"); } break; case Type.FILE: if (params.get(ParamKey.FILE_ID) == null) { throw new IllegalRequestException("File without file id"); } break; case Type.NAS: if (params.get(ParamKey.CONNECTION_ID) == null) { throw new IllegalRequestException("Nas without connection id"); } break; case Type.DOWNLOAD: if (params.get(ParamKey.BIDIRECTION_ID) == null) { throw new IllegalRequestException("Download without bidirection id"); } break; default: throw new IllegalRequestException("Unresolved type of relay request:" + streamType); } } private void validateRelayAuthContext(ChannelType channelType, String streamType, AbstractAuthContext authContext) { assert streamType != null; switch (streamType) { case Type.VIDEO: case RelayConsts.Type.SMART_IPC: case Type.AUDIO: case Type.MIXED: case RelayConsts.Type.SMART_NVR: case Type.NVR: if (channelType == ChannelType.SOURCE || channelType == ChannelType.SINK) { validateAuthContext(authContext, BindingAuthContext.class); } else { throw new IllegalRequestException("Program should not be here, " + "streamType:" + streamType + " with channelType:" + channelType.name()); } break; case Type.SDVOD: case Type.DTSPK: case Type.FILE: case Type.DOWNLOAD: case Type.NAS: validateAuthContext(authContext, BindingAuthContext.class); break; default: throw new IllegalRequestException("Unresolved type of relay request:" + streamType); } } public void validateAuthContext(AbstractAuthContext authContext, Class<?>... wantedClasses) { assert wantedClasses != null && wantedClasses.length != 0; if (authContext == null) { throw new IllegalRequestException("Missing token"); } for (Class<?> wantedClass : wantedClasses) { if (wantedClass.isInstance(authContext)) { authContext.validateAuthParams(); return; } } log.error("Wrong auth context type:{}", authContext.getClass().getSimpleName()); throw new IllegalRequestException("Wrong auth context type:" + authContext.getClass().getSimpleName()); } enum ChannelType { /* * 通道类型 */ SOURCE, SINK, FFMPEG, BIDIRECTION; } } @Component public class ProcessorTypeManager { private ProcessorType statusProcessorType; private ProcessorType controlProcessorType; private ProcessorType wsControlProcessorType; private ProcessorType optionProcessorType; private ProcessorType passthroughGetServiceProcessorType; private ProcessorType defaultGetServiceProcessorType; private ProcessorType bufferedPostServiceProcessorType; private ProcessorType defaultPostServiceProcessorType; private ProcessorType bidirectionServiceProcessorType; private ProcessorType trustCertProcessorType; @Autowired public ProcessorTypeManager(DefaultHeaderProcessor defaultHeaderProcessor, ControlHeaderProcessor controlHeaderProcessor, ControlDataProcessor controlDataProcessor, WsControlDataProcessor wsControlDataProcessor, GetRequestHeaderProcessor defaultGetServiceHeaderProcessor, PostRequestHeaderProcessor defaultPostServiceHeaderProcessor, BidirectionRequestHeaderProcessor bidirectionServiceHeaderProcessor, PassthroughGetRequestDataProcessor passthroughGetServiceDataProcessor, BufferedRequestDataProcessor bufferedPostServiceDataProcessor, TrustCertProcessor trustCertProcessor, @Qualifier("relayPostRequestDataProcessor") RelayPostRequestDataProcessor defaultPostServiceDataProcessor, @Qualifier("postRequestDataProcessor") PostRequestDataProcessor bidirectionServiceDataProcessor) { statusProcessorType = new ProcessorType(Service.STATUS, defaultHeaderProcessor, null); optionProcessorType = new ProcessorType(Service.CONTROL, defaultHeaderProcessor, null); controlProcessorType = new ProcessorType(Service.CONTROL, controlHeaderProcessor, controlDataProcessor); wsControlProcessorType = new ProcessorType(Service.CONTROL, controlHeaderProcessor, wsControlDataProcessor); passthroughGetServiceProcessorType = new ProcessorType(Service.RELAY, defaultGetServiceHeaderProcessor, passthroughGetServiceDataProcessor); defaultGetServiceProcessorType = new ProcessorType(Service.RELAY, defaultGetServiceHeaderProcessor, null); bufferedPostServiceProcessorType = new ProcessorType(Service.RELAY, defaultPostServiceHeaderProcessor, bufferedPostServiceDataProcessor); defaultPostServiceProcessorType = new ProcessorType(Service.RELAY, defaultPostServiceHeaderProcessor, defaultPostServiceDataProcessor); bidirectionServiceProcessorType = new ProcessorType(Service.RELAY, bidirectionServiceHeaderProcessor, bidirectionServiceDataProcessor); trustCertProcessorType = new ProcessorType(Service.TRUST_CERT, trustCertProcessor, null); } public ProcessorType getProcessorType(RequestChannel<? extends AbstractRequestChannelInformation> requestChannel) { if (requestChannel instanceof BidirectionRequestChannel) { return bidirectionServiceProcessorType; } else if (requestChannel instanceof PassthroughGetRequestChannel) { return passthroughGetServiceProcessorType; } else if (requestChannel instanceof GetRequestChannel) { return defaultGetServiceProcessorType; } else if (requestChannel instanceof BufferedPostRequestChannel) { return bufferedPostServiceProcessorType; } else if (requestChannel instanceof PostRequestChannel) { return defaultPostServiceProcessorType; } else if (requestChannel instanceof ControlRequestChannel) { if (requestChannel.getInformation().getHttpMethod() == HttpMethod.OPTIONS) { return optionProcessorType; } return controlProcessorType; } else if (requestChannel instanceof StatusRequestChannel) { return statusProcessorType; } else if (requestChannel instanceof TrustCertChannel) { return trustCertProcessorType; } else { throw new UnexpectedServiceException(requestChannel.getRequestType()); } } public ProcessorType getWsControlProcessorType() { return wsControlProcessorType; } } @Component public class DefaultHeaderProcessor extends AbstractHeaderProcessor<RequestChannel, StatusRequestChannelInformation> { @Autowired private CookieLoader cookieLoader; @Override protected RequestChannel<StatusRequestChannelInformation> doProcess( RequestChannel<StatusRequestChannelInformation> requestChannel) throws Exception { ResponseBuilder builder = ResponseBuilder.create(); builder.setServer("relayd"); builder.setStatus(HttpResponseStatus.OK).setEmptyContent(); String setCookie = cookieLoader.getSetCookieFieldValue(); if (setCookie != null) { builder.setCatchControl("no-cache=\"set-cookie\""); builder.addHeader("Set-Cookie", setCookie); } requestChannel.sendHttpResponseAndClose(builder.build(), RelayConsts.CloseReason.SUCCESS); return requestChannel; } } @Component public class ControlHeaderProcessor extends AbstractHeaderProcessor<ControlRequestChannel, ControlRequestChannelInformation> { private ChannelManager channelManager; @Autowired public ControlHeaderProcessor(ChannelManager channelManager) { this.channelManager = channelManager; } @Override protected ControlRequestChannel doProcess(ControlRequestChannel requestChannel) { requestChannel.createLifeTimeEvent(ILifeTimeControl.LifeTimeType.BASIC); if (requestChannel.getInformation().getHttpMethod() != HttpMethod.OPTIONS) { requestChannel.setStartDataProcess(); } channelManager.addRequestChannel(requestChannel.getChannelId(), requestChannel); return requestChannel; } } @Slf4j @Component public class GetRequestHeaderProcessor extends AuthRequiredHeaderProcessor<GetRequestChannel, GetRequestChannelInformation> { private ChannelManager channelManager; private ContainerManager containerManager; private RequestChannelHelper requestChannelHelper; private HttpResponse upgradeHttpResponse; private ByteBuf upgradeVideo; private long upgradeVideoDurationMs; public GetRequestHeaderProcessor(AuthClient authClient, GetRequestHeaderProcessorProp prop, ChannelManager channelManager, ContainerManager containerManager, RequestChannelHelper requestChannelHelper) { super(authClient, prop); this.channelManager = channelManager; this.containerManager = containerManager; this.requestChannelHelper = requestChannelHelper; ResponseBuilder builder = ResponseBuilder.create(); builder.setStatus(HttpResponseStatus.OK).setContentType(new ContentType("video/mp2t", null, null)) .setContentLength(Long.MAX_VALUE); this.upgradeHttpResponse = builder.build(); } @Override protected GetRequestChannel doBeforeAddExecutor(GetRequestChannel getChannel) throws Exception { if (getChannel instanceof IDataFollowedRelayRequestChannel) { // Version 1.3 if (log.isDebugEnabled()) { log.debug("[sid:{}] Disable auto read of GET channel:", getChannel.getSid()); } if (BooleanUtils.isFalse(getChannel.getWs())) { ((IDataFollowedRelayRequestChannel) getChannel).disableAutoRead(); } } return getChannel; } @Override protected GetRequestChannel doProcess(GetRequestChannel getChannel) throws Exception { super.doProcess(getChannel); return getChannel; } @Override public void doHeaderProcess(GetRequestChannel getChannel) throws Exception { // Add GET request channel into map manager channelManager.addRequestChannel(getChannel.getChannelId(), getChannel); if (!getChannel.isNeedMultipleMappingSource() && containerManager.removeBidirectionContainerIfExist(getChannel)) { GetRequestChannelInformation information = getChannel.getInformation(); information.setVersionUnmatch(true); // Version 1.2, single mapping and source channel is Version 1.3 if (RelayConsts.Type.DTSPK.equals(information.getParams().get(RelayConsts.ParamKey.TYPE))) { // The DTSPK Get channel of version 1.2 is device, so it is not necessary to show upgraded message. And // as the app should check device version before request, this case should not happen. getChannel.sendHttpResponseAndClose(HttpResponseStatus.BAD_REQUEST, RelayConsts.CloseReason.GET_CLOSED_WITH_LOW_VERSION); } else { // For example, sdvod with 1.2 version showUpgradeHint(getChannel); } return; } // Get and bind corresponding POST request channel of this GET request channel PostRequestChannel postChannel = obtainPostRequestChannel(getChannel); if (postChannel == null) { if (getChannel instanceof DefaultGetRequestChannel) { addRequestChannelIntoContainer((DefaultGetRequestChannel) getChannel); } else { if (log.isDebugEnabled()) { log.debug("[sid:{}] Response 404 to the GET channel which is not life-time-controllable", getChannel.getSid()); } getChannel.sendHttpResponseAndClose(HttpResponseStatus.NOT_FOUND, RelayConsts.CloseReason.NOT_FOUND); } } else { if (postChannel.getChannelVersion() == getChannel.getChannelVersion()) { // POST and GET channel has the same version bindRequestChannels(getChannel, postChannel); } else if (getChannel.getChannelVersion() == ChannelVersion.VERSION_1_2) { // Multiple mapping and GET channel version is 1.2 and show hint video postChannel.getInformation().addVersionUnmatchNum(); getChannel.getInformation().setVersionUnmatch(true); showUpgradeHint(getChannel); } else { // GET channel version is 1.3. This case should not happen as following reason: // 1. For video/nvr (multiple mapping): the app will check the device version before requesting stream. // 2. For sdvod: the app will check the device version before requesting stream. // 3. For dtspk: this is used on IPC. When the user wants to speak, 2 connections will be used, one is // preview stream(type=video) and the other one is the dtspk stream.In this case, the version of device // is 1.3 and the one of app is 1.2. The hint will be shown through preview stream and the dtspk request // will be refused by device. postChannel.getInformation().addVersionUnmatchNum(); getChannel.getInformation().setVersionUnmatch(true); getChannel.sendHttpResponseAndClose(HttpResponseStatus.BAD_REQUEST, RelayConsts.CloseReason.GET_CLOSED_WITH_HIGHT_VERSION); } } } private PostRequestChannel obtainPostRequestChannel(GetRequestChannel getChannel) { // Obtain POST channel from manager directly: // 1. For single mapping: the result is the actual POST channel. // 2. For multiple mapping: if the result is null, the device may be a single stream output IP and should be // tried with shortcut binding id. If the result is not null, the result is the actual POST channel. String bindingId = getChannel.getBindingId(); PostRequestChannel postChannel = (PostRequestChannel) channelManager.getRequestChannel(bindingId); if (postChannel != null || !getChannel.isNeedMultipleMappingSource()) { return postChannel; } Map<String, String> params = getChannel.getInformation().getParams(); String shortBindingId = BindingIdUtils.buildMultipleMappingShortBindingId(params); bindingId = channelManager.getBindingIdByShortcut(shortBindingId); if (bindingId != null) { postChannel = (PostRequestChannel) channelManager.getRequestChannel(bindingId); } if (postChannel != null) { if (log.isDebugEnabled()) { log.debug("[sid:{}] Update binding id: newBindingId={}", getChannel.getSid(), bindingId); } getChannel.updateBindingId(bindingId); } return postChannel; } private void bindRequestChannels(GetRequestChannel getChannel, PostRequestChannel postChannel) throws Exception { BindingResult bindingResult = postChannel.bindGetRequestChannel(getChannel); if (bindingResult == BindingResult.SUCCESS) { if (log.isDebugEnabled()) { boolean inSameEventLoop = postChannel.getNettyChannel().eventLoop().inEventLoop(); log.debug("[sid:{}] Bind to POST channel successfully: inSameEventLoop={}", getChannel.getSid(), inSameEventLoop); } postChannel.startDataAcceptanceAfterSinkChannelAccess(); } else { log.error("[sid:{}] Fail to bind GET channel: bindingResult={}", getChannel.getSid(), bindingResult); getChannel.sendHttpResponseAndClose(bindingResult.getResponseStatus(), bindingResult.getResponseCloseReason()); } } private void addRequestChannelIntoContainer(DefaultGetRequestChannel getChannel) throws Exception { // Set idle life time event. getChannel.createLifeTimeEvent(ILifeTimeControl.LifeTimeType.CON_IDLE); // Add itself into container. ContainerManager.AddSingleDirectionContainerResult addContainerResult = containerManager.addIntoSingleDirectionContainer(getChannel); BindingResult bindingResult = addContainerResult.getBindingResult(); if (bindingResult == BindingResult.SUCCESS) { if (log.isDebugEnabled()) { log.debug("[sid:{}] Add GET channel into container successfully: container={}", getChannel.getSid(), addContainerResult.getContainer().toString()); } // If the version of POST and GET channel don't match with each other, the GET channel will be close when // initContainer is called. Especially for multiple mapping channels. PostRequestChannel postChannel = addContainerResult.getContainer().getSourceRequestChannel(); if (postChannel != null && postChannel.getBoundGetRequestChannelNum() != 0) { if (log.isDebugEnabled()) { log.debug("[sid:{}] Initialize POST channel after GET access", getChannel.getSid()); } postChannel.startDataAcceptanceAfterSinkChannelAccess(); } } else { log.error("[sid:{}] Fail to add GET channel into container: bindingResult:{}", getChannel.getSid(), bindingResult); getChannel.sendHttpResponseAndClose(bindingResult.getResponseStatus(), bindingResult.getResponseCloseReason()); } } private void showUpgradeHint(GetRequestChannel getChannel) { if (getChannel instanceof DefaultGetRequestChannel) { ((DefaultGetRequestChannel) getChannel).createLifeTimeEvent(ILifeTimeControl.LifeTimeType.BASIC); } getChannel.sendTemplateHttpResponse(upgradeHttpResponse); IHttpData firstData = new ByteBufHttpData(0, UnpooledByteBufAllocator.DEFAULT, CharsetUtil.UTF_8, upgradeVideo); getChannel.sendTemplateData(firstData); ShowUpgradeHintTask task = new ShowUpgradeHintTask(getChannel, 1); getChannel.getNettyChannel().eventLoop().schedule(task, upgradeVideoDurationMs, TimeUnit.MILLISECONDS); } public void setUpgradeVideo(String pathname) throws Exception { FileInputStream in = null; try { in = new FileInputStream(pathname); ByteBuf buf = Unpooled.buffer(); byte[] bytes = new byte[8192]; int readSize = -1; while ((readSize = in.read(bytes)) != -1) { buf.writeBytes(bytes, 0, readSize); } upgradeVideo = Unpooled.unreleasableBuffer(buf); } finally { if (in != null) { try { in.close(); } catch (IOException e) { log.warn(e.getMessage(), e); } } } } public void setUpgradeVideoDurationMs(long upgradeVideoDurationMs) { this.upgradeVideoDurationMs = upgradeVideoDurationMs; } class ShowUpgradeHintTask implements Runnable { GetRequestChannel getChannel; int dataIndex; ShowUpgradeHintTask(GetRequestChannel getChannel, int startDataIndex) { this.getChannel = getChannel; this.dataIndex = startDataIndex; } @Override public void run() { if (getChannel.isClosed()) { log.info("[sid:{}] Show hint task is stopped: finalDataIndex={}", getChannel.getSid(), dataIndex - 1); return; } getChannel.sendTemplateData(new ByteBufHttpData(dataIndex++, UnpooledByteBufAllocator.DEFAULT, CharsetUtil.UTF_8, upgradeVideo)); getChannel.getNettyChannel().eventLoop().schedule(this, upgradeVideoDurationMs, TimeUnit.MILLISECONDS); } } } @Slf4j @Component public class PostRequestHeaderProcessor extends AuthRequiredHeaderProcessor<PostRequestChannel, PostRequestChannelInformation> { private ChannelManager channelManager; private ContainerManager containerManager; private RequestChannelHelper requestChannelHelper; private CloudAccessChannelHelper cloudAccessChannelHelper; @Autowired public PostRequestHeaderProcessor(AuthClient authClient, PostRequestHeaderProcessorProp prop, ChannelManager channelManager, ContainerManager containerManager, RequestChannelHelper requestChannelHelper, CloudAccessChannelHelper cloudAccessChannelHelper) { super(authClient, prop); this.channelManager = channelManager; this.containerManager = containerManager; this.requestChannelHelper = requestChannelHelper; this.cloudAccessChannelHelper = cloudAccessChannelHelper; } @Override protected PostRequestChannel doBeforeAddExecutor(PostRequestChannel postChannel) throws Exception { if (log.isDebugEnabled()) { log.debug("[sid:{}] Disable auto read of POST channel:", postChannel.getSid()); } postChannel.disableAutoRead(); return postChannel; } /** * General POST request added strategy is to use new POST request to kick off the old one and all GET requests * related with the old POST request will be closed . * <p> * This method could be overrided for other strategy in specific transactions. * </p> * * @param postChannel The POST request channel. */ @Override public void doHeaderProcess(final PostRequestChannel postChannel) throws Exception { // Obtain the container. SingleDirectionContainer container = containerManager.obtainSingleDirectionContainer(postChannel); if (container == null) { log.info("[sid:{}] POST channel is kicked off by others when obtaining container.", postChannel.getSid()); postChannel.sendHttpResponseAndClose(503, "Kicked off", RelayConsts.CloseReason.POST_KICKED_OFF); return; } if (postChannel instanceof CloudAccessPostRequestChannel) { doCloudAccessHeaderProcess(postChannel, container); } // Initialize the container. log.debug("[sid:{}] POST channel obtain container successfully: container={}", postChannel.getSid(), container); boolean hasGetChannels = postChannel.initContainer(container); if (hasGetChannels) { log.debug("[sid:{}] Initialize POST channel after container initailization", postChannel.getSid()); postChannel.startDataAcceptanceAfterSinkChannelAccess(); } // Add binding id shortcut if necessary PostRequestChannel oldPostChannel = null; if (postChannel.isSingleStream()) { log.debug("[sid:{}] Add binding id shortcut: bindingId={}", postChannel.getSid(), postChannel.getBindingId()); String oldBindingId = channelManager.addBindingIdShortcut(postChannel.getShortBindingId(), postChannel.getBindingId()); if (oldBindingId != null) { oldPostChannel = (PostRequestChannel) channelManager.removeRequestChannel(oldBindingId); } if (oldPostChannel != null) { log.debug("[sid:{}] Kick off old channel: oldChannelSid={}", postChannel.getSid(), oldPostChannel.getSid()); oldPostChannel.close(RelayConsts.CloseReason.POST_KICKED_OFF); } } // Add POST channel into channel manager. oldPostChannel = (PostRequestChannel) channelManager.addRequestChannel(postChannel.getChannelId(), postChannel); if (oldPostChannel != null) { log.debug("[sid:{}] Kick off old channel: oldChannelSid={}", postChannel.getSid(), oldPostChannel.getSid()); oldPostChannel.close(RelayConsts.CloseReason.POST_KICKED_OFF); } // Process after adding into channel manager postChannel.callAfterAddIntoChannelManager(); } /** * 处理PostRequestChannel的cloud access推流 */ public void doCloudAccessHeaderProcess(final PostRequestChannel postChannel, SingleDirectionContainer container) throws Exception { RequestChannel cloudAccessChannel = cloudAccessChannelHelper .createCloudAccessChannel(postChannel.getBindingId(), postChannel.getInformation().getOrignalRequest(), postChannel.getNettyChannel()); if (cloudAccessChannel instanceof CloudAccessGetRequestChannel) { CloudAccessGetRequestChannel getChannel = (CloudAccessGetRequestChannel) cloudAccessChannel; channelManager.addRequestChannel(getChannel.getChannelId(), getChannel); // Set idle life time event. getChannel.createLifeTimeEvent(ILifeTimeControl.LifeTimeType.CON_IDLE); // Add itself into container. BindingResult bindingResult = container.addBoundSinkRequestChannel(getChannel); if (bindingResult == BindingResult.SUCCESS) { if (log.isDebugEnabled()) { log.debug("[sid:{}] Add GET channel into container successfully: container={}", getChannel.getSid(), container.toString()); } } else { log.error("[sid:{}] Fail to add GET channel into container: bindingResult:{}", getChannel.getSid(), bindingResult); getChannel.close(bindingResult.getResponseCloseReason()); } } else { log.error("failed to create cloud access channel for {}", postChannel.getBindingId()); } } }
最新发布
09-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值