package cn.timer.api.aspect;

import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

/**
 * @author wuqingjun
 * @email 284718418@qq.com
 * @date 2021/12/28
 */
@Slf4j
public class ChannelSftpFactory extends BasePooledObjectFactory<ChannelSftp> {


    public ChannelSftpFactory(String host, Integer port, String protocol, String username, String password,
                              String sessionStrictHostKeyChecking, Integer sessionConnectTimeout, Integer channelConnectedTimeout) {
        super();
        this.host = host;
        this.port = port;
        this.protocol = protocol;
        this.username = username;
        this.password = password;
        this.sessionStrictHostKeyChecking = sessionStrictHostKeyChecking;
        this.sessionConnectTimeout = sessionConnectTimeout;
        this.channelConnectedTimeout = channelConnectedTimeout;
    }
    // host
    private String host;
    // 端口
    private Integer port;
    // 协议
    private String protocol;
    // 用户
    private String username;
    // 密码
    private String password;

    private String sessionStrictHostKeyChecking;
    // session超时时间
    private Integer sessionConnectTimeout;
    // channel超时时间
    private Integer channelConnectedTimeout;

    // 设置第一次登陆的时候提示,可选值:(ask | yes | no)
    private static final String SESSION_CONFIG_STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";

    @Override
    public ChannelSftp create() throws Exception {
        return null;
    }

    @Override
    public PooledObject<ChannelSftp> makeObject() throws Exception {
        JSch jsch = new JSch();
        //log.info("sftp尝试连接[" + username + "@" + host + "], use password[" + password + "]");
        Session session = createSession(jsch, host, username, port);
        session.setPassword(password);
        session.connect(sessionConnectTimeout);
        //log.info("sftp已连接到:{}", host);
        Channel channel = session.openChannel(protocol);
        channel.connect(channelConnectedTimeout);
        //log.info("sftp创建channel:{}", host);
        return new DefaultPooledObject<ChannelSftp>((ChannelSftp) channel);
    }

    @Override
    public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
        return new DefaultPooledObject<>(channelSftp);
    }

    @Override
    public void destroyObject(PooledObject<ChannelSftp> sftpPooled) throws Exception {
        ChannelSftp sftp = sftpPooled.getObject();
        try {
            if (sftp != null) {
                if (sftp.isConnected()) {
                    sftp.disconnect();
                } else if (sftp.isClosed()) {
                    log.info("sftp连接已关闭");
                }
                if (null != sftp.getSession()) {
                    sftp.getSession().disconnect();
                }
            }
        } catch (JSchException e) {
            log.error("关闭sftp连接失败: {}", e);
            e.printStackTrace();
            throw new Exception("关闭sftp连接失败");
        }
    }

    @Override
    public boolean validateObject(PooledObject<ChannelSftp> sftpPooled) {
        try {
            ChannelSftp sftp = sftpPooled.getObject();
            if (sftp != null) {
                return (sftp.isConnected() && sftp.getSession().isConnected());
            }
        } catch (JSchException e) {
            log.error("sftp连接校验失败: {}", e);
            e.printStackTrace();
            throw new RuntimeException("sftp连接校验失败");
        }
        return false;
    }

    /**
     * 创建session
     *
     * @param jsch
     * @param host
     * @param username
     * @param port
     * @return
     * @throws Exception
     */
    private Session createSession(JSch jsch, String host, String username, Integer port) throws Exception {
        Session session = null;
        if (port <= 0) {
            session = jsch.getSession(username, host);
        } else {
            session = jsch.getSession(username, host, port);
        }
        if (session == null) {
            throw new RuntimeException(host + " sftp建立连接session is null");
        }
        session.setConfig(SESSION_CONFIG_STRICT_HOST_KEY_CHECKING, sessionStrictHostKeyChecking);
        return session;
    }
}