package com.dhcc.finance.config;

import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;

import com.dhcc.common.config.bean.DhccPrincipalHandshakeHandler;
import com.dhcc.common.config.bean.WebSocketChannelInterceptor;
import com.dhcc.common.config.bean.WebSocketHandshakeInterceptor;
import com.dhcc.common.constant.SysConstants;

/**
 * 
 * @功能描述：配置基于STOMP的websocket
 * @author chenrui
 * @date 2019年3月9日 上午11:16:09
 * @修改日志：
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
	
	@Bean
    public WebSocketChannelInterceptor webSocketChannelInterceptor(){
        return new WebSocketChannelInterceptor();
    }
	
	/*
	 * (非 Javadoc)  
	 * @Title: configureMessageBroker
	 * @Description: 配置消息代理，哪种路径的消息会进行代理处理
	 * @param config  
	 * @author chenrui
	 * @date 2019年3月9日 上午11:28:51
	 * @modifyLog：
	 */
	@Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
		/*//客户端发送消息的请求前缀
		config.setApplicationDestinationPrefixes("/app");
        //客户端订阅消息的请求前缀，topic一般用于广播推送，queue用于点对点推送
		config.enableSimpleBroker("/topic", "/queue");
        //服务端通知客户端的前缀，可以不设置，默认为user
		config.setUserDestinationPrefix("/user");*/
        
		/*使用中间件*/
		config.enableStompBrokerRelay(SysConstants.WEB_SOCKET_CONFIG.STOMP_BROKER_RELAY)
		.setRelayHost(SysConstants.WEB_SOCKET_CONFIG.RELAY_HOST)
		.setRelayPort(SysConstants.WEB_SOCKET_CONFIG.RELAY_PORT)
		.setSystemLogin(SysConstants.WEB_SOCKET_CONFIG.SYSTEM_LOGIN)
		.setSystemPasscode(SysConstants.WEB_SOCKET_CONFIG.SYSTEM_PASSCODE)
		.setClientLogin(SysConstants.WEB_SOCKET_CONFIG.CLIENT_LOGIN)
		.setClientPasscode(SysConstants.WEB_SOCKET_CONFIG.CLIENT_PASSCODE);
		/*
		 *  "/app" 为配置应用服务器的地址前缀，表示所有以/app 开头的客户端消息或请求
         *  都会路由到带有@MessageMapping 注解的方法中
		 */
		config.setApplicationDestinationPrefixes(SysConstants.WEB_SOCKET_CONFIG.APPLICATION_DESTINATION_PREFIXES);
		/*
         *  1. 配置一对一消息前缀， 客户端接收一对一消息需要配置的前缀 如“'/user/'+userid + '/message'”，
         *     是客户端订阅一对一消息的地址 stompClient.subscribe js方法调用的地址
         *  2. 使用@SendToUser发送私信的规则不是这个参数设定，在框架内部是用UserDestinationMessageHandler处理，
         *     而不是而不是 AnnotationMethodMessageHandler 或  SimpleBrokerMessageHandler
         *     or StompBrokerRelayMessageHandler，是在@SendToUser的URL前加“user+sessionId"组成
         */
        config.setUserDestinationPrefix(SysConstants.WEB_SOCKET_CONFIG.USER_DESTINATION_PREFIX);
        /*
         * 自定义路径分割符
         * 注释掉的这段代码添加的分割符为. 分割是类级别的@messageMapping和方法级别的@messageMapping的路径
         * 例如类注解路径为 “topic”,方法注解路径为“hello”，那么客户端JS stompClient.send 方法调用的路径为“/app/topic.hello”
         * 注释掉此段代码后，类注解路径“/topic”,方法注解路径“/hello”,JS调用的路径为“/app/topic/hello”
         */
        //registry.setPathMatcher(new AntPathMatcher("."));
       
    }

	/*
	 * (非 Javadoc)  
	 * @Title: registerStompEndpoints
	 * @Description: 添加这个Endpoint，这样在网页中就可以通过websocket连接上服务,也就是我们配置websocket的服务地址,并且可以指定是否使用socketjs
	 * @param registry  
	 * @author chenrui
	 * @date 2019年3月9日 上午11:28:10
	 * @modifyLog：
	 */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint(SysConstants.WEB_SOCKET_CONFIG.DEFAULT_ENDPOINT)
        .addInterceptors(new WebSocketHandshakeInterceptor()) /*添加自定义拦截器*/
        .setHandshakeHandler(new DhccPrincipalHandshakeHandler()) /*添加拦截处理，这里DhccPrincipalHandshakeHandler 封装的认证用户信息*/
        .setAllowedOrigins("*"); /*支持跨域*/
    }
    
    /*
     * (非 Javadoc)  
     * @Title: configureWebSocketTransport
     * @Description: 配置发送与接收的消息参数，可以指定消息字节大小，缓存大小，发送超时时间
     * @param registration  
     * @author chenrui
     * @date 2019年3月9日 下午2:26:50
     * @modifyLog：
     */
    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
        registration.setMessageSizeLimit(SysConstants.WEB_SOCKET_CONFIG.MESSAGE_SIZE_LIMIT) /*setMessageSizeLimit 设置消息缓存的字节数大小 字节*/
                    .setSendBufferSizeLimit(SysConstants.WEB_SOCKET_CONFIG.SEND_BUFFER_SIZE_LIMIT) /*setSendBufferSizeLimit 设置websocket会话时，缓存的大小 字节*/
                    .setSendTimeLimit(SysConstants.WEB_SOCKET_CONFIG.SEND_TIME_LIMIT); /*setSendTimeLimit 设置消息发送会话超时时间，毫秒*/
    }
    
    /*
     * (非 Javadoc)  
     * @Title: configureClientInboundChannel
     * @Description: 设置输入消息通道的线程数，默认线程为1，可以自己自定义线程数，最大线程数，线程存活时间
     * In a messaging application, messages are passed through channels for asynchronous executions that are backed by thread pools. Configuring such an application requires good knowledge of the channels and the flow of messages. Therefore, it is recommended to review Flow of Messages.
     * The obvious place to start is to configure the thread pools that back the clientInboundChannel and the clientOutboundChannel. By default, both are configured at twice the number of available processors.
     * If the handling of messages in annotated methods is mainly CPU-bound, the number of threads for the clientInboundChannel should remain close to the number of processors. If the work they do is more IO-bound and requires blocking or waiting on a database or other external system, the thread pool size probably needs to be increased.
     * @param registration  
     * @author chenrui
     * @date 2019年3月9日 下午2:26:41
     * @modifyLog：
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {

        /*
         * 配置消息线程池
         * 1. corePoolSize 配置核心线程池，当线程数小于此配置时，不管线程中有无空闲的线程，都会产生新线程处理任务
         * 2. maxPoolSize 配置线程池最大数，当线程池数等于此配置时，不会产生新线程
         * 3. keepAliveSeconds 线程池维护线程所允许的空闲时间，单位秒
         */
        /*registration.taskExecutor()
			.corePoolSize(SysConstants.WEB_SOCKET_CONFIG.CORE_POOL_SIZE) 
            .maxPoolSize(SysConstants.WEB_SOCKET_CONFIG.MAX_POOL_SIZE) 
            .keepAliveSeconds(SysConstants.WEB_SOCKET_CONFIG.KEEP_ALIVE_SECONDS); */
        /*
         * 添加stomp自定义拦截器，可以根据业务做一些处理
         * 消息拦截器，实现ChannelInterceptor接口
         */
        //registration.interceptors(webSocketChannelInterceptor());
    }
    
    /*
     * (非 Javadoc)  
     * @Title: configureClientOutboundChannel
     * @Description: 设置输出消息通道的线程数，默认线程为1，可以自己自定义线程数，最大线程数，线程存活时间
     * In a messaging application, messages are passed through channels for asynchronous executions that are backed by thread pools. Configuring such an application requires good knowledge of the channels and the flow of messages. Therefore, it is recommended to review Flow of Messages.
     * The obvious place to start is to configure the thread pools that back the clientInboundChannel and the clientOutboundChannel. By default, both are configured at twice the number of available processors.
     * If the handling of messages in annotated methods is mainly CPU-bound, the number of threads for the clientInboundChannel should remain close to the number of processors. If the work they do is more IO-bound and requires blocking or waiting on a database or other external system, the thread pool size probably needs to be increased.
     * @param registration  
     * @author chenrui
     * @date 2019年3月9日 下午2:26:32
     * @modifyLog：
     */
    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        /*registration.taskExecutor()
	        .corePoolSize(SysConstants.WEB_SOCKET_CONFIG.CORE_POOL_SIZE) 
	        .maxPoolSize(SysConstants.WEB_SOCKET_CONFIG.MAX_POOL_SIZE) 
	        .keepAliveSeconds(SysConstants.WEB_SOCKET_CONFIG.KEEP_ALIVE_SECONDS); */
        /*registration.interceptors(webSocketChannelInterceptor());*/
    }
    
    /*
     * (非 Javadoc)  
     * @Title: configureMessageConverters
     * @Description: 
     * 添加自定义的消息转换器，spring 提供多种默认的消息转换器，
     * 返回false,不会添加消息转换器，返回true，会添加默认的消息转换器，当然也可以把自己写的消息转换器添加到转换链中
     * @param list
     * @return  
     * @author chenrui
     * @date 2019年3月9日 下午2:28:45
     * @modifyLog：
     */
    @Override
    public boolean configureMessageConverters(List<MessageConverter> list) {
        return true;
    }
    
    /*
     * (非 Javadoc)  
     * @Title: addArgumentResolvers
     * @Description: 自定义控制器方法的参数类型
     * @param list  
     * @author chenrui
     * @date 2019年3月9日 下午2:30:41
     * @modifyLog：
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {

    }

    /*
     * (非 Javadoc)  
     * @Title: addReturnValueHandlers
     * @Description: 自定义控制器方法返回值类型
     * @param list  
     * @author chenrui
     * @date 2019年3月9日 下午2:30:49
     * @modifyLog：
     */
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {

    }
}
