package com.example.upsecuritydata.util;

import com.jcraft.jsch.*;
import com.xxl.job.core.context.XxlJobHelper;

import java.io.*;
import java.util.Properties;

public class JschUtil {

    // sftp通道
    ChannelSftp chSftp;
    private JSch jSch;
    // session对象
    private Session session;
    // JAVA与主机的连接通道
    private Channel channel;
    // 主机ip
    private String host;

    // 主机端口号
    private int port;

    // 主机账号
    private String username;

    // 主机密码
    private String password;

    public JschUtil(String host, int port, String username, String password) {
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public JschUtil() {
    }

    /**
     * 检测是否可以和主机通信
     *
     * @return
     */
    public boolean connect() {

        jSch = new JSch();

        boolean reulst = false;

        try {

            // 根据主机账号、ip、端口获取一个Session对象
            session = jSch.getSession(username, host, port);

            // 存放主机密码
            session.setPassword(password);

            // 首次连接,去掉公钥确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            // 超时连接时间为30秒
            session.setTimeout(300000);

            // 进行连接
            session.connect();

            // 获取连接结果
            reulst = session.isConnected();

            if (!reulst) {
                XxlJobHelper.log("【连接】获取连接失败");
            }

        } catch (JSchException e) {
            XxlJobHelper.log(e.getMessage());
        } finally {
            close();
        }
        return reulst;
    }

    /**
     * 关闭连接
     */
    public void close() {

        if (channel != null && channel.isConnected()) {
            channel.disconnect();
        }

        if (session != null && session.isConnected()) {
            session.disconnect();
        }

        if (chSftp != null && chSftp.isConnected()) {
            chSftp.quit();
        }

    }

    /**
     * 执行shell命令
     *
     * @param command
     * @return
     */
    public String execCommand(String command) {

        jSch = new JSch();

        // 存放执行命令结果
        StringBuffer result = new StringBuffer();
        int exitStatus = 0;

        try {

            // 根据主机账号、ip、端口获取一个Session对象
            session = jSch.getSession(username, host, port);

            // 存放主机密码
            session.setPassword(password);

            // 去掉首次连接确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            // 超时连接时间为3秒
            session.setTimeout(3000);

            // 进行连接
            session.connect();

            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);

            channel.setInputStream(null);
            // 错误信息输出流,用于输出错误的信息,当exitstatus<0的时候
            ((ChannelExec) channel).setErrStream(System.err);

            // 执行命令,等待执行结果
            channel.connect();

            // 获取命令执行结果
            InputStream in = channel.getInputStream();

            /**
             * 通过channel获取信息的方式,采用官方Demo代码
             */
            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    result.append(new String(tmp, 0, i));
                }
                // 从channel获取全部信息之后,channel会自动关闭
                if (channel.isClosed()) {
                    if (in.available() > 0) {
                        continue;
                    }
                    exitStatus = channel.getExitStatus();
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                }
            }


        } catch (IOException e) {
            XxlJobHelper.log(e.getMessage());
        } catch (JSchException e) {
            XxlJobHelper.log(e.getMessage());
        } finally {
            close();
        }

        XxlJobHelper.log("退出码为:" + exitStatus);
        return result.toString();
    }

    /**
     * 文件上传至主机
     *
     * @param directory  当前文件路径
     * @param uploadFile 上传至主机的路径
     */
    public void upload(String directory, String uploadFile) {
        // 创建JSch对象
        jSch = new JSch();

        try {
            // 根据主机账号、ip、端口获取一个Session对象
            session = jSch.getSession(username, host, port);
            // 存放主机密码
            session.setPassword(password);
            // 去掉首次连接确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            // 超时连接时间为60秒
            session.setTimeout(60000);
            // 进行连接
            session.connect();
            // 打开SFTP通道
            chSftp = (ChannelSftp) session.openChannel("sftp");
            // 建立STFP连接
            chSftp.connect(60000);
            // 设置编码格式
            chSftp.setFilenameEncoding("UTF-8");
            // 创建一个文件名称问uploadFile的文件
            File file = new File(uploadFile);
            chSftp.put(new FileInputStream(file), directory, ChannelSftp.OVERWRITE);
            XxlJobHelper.log("文件上传成功到:" + file.getName());
        } catch (JSchException | SftpException | FileNotFoundException e) {
            XxlJobHelper.log(e.getMessage());
        } finally {
            close();
        }
    }

    /**
     * 将主机文件下载至本地
     *
     * @param directory    下载到本地的位置
     * @param downloadFile 下载文件在虚拟机的位置
     */
    public void download(String directory, String downloadFile) {

        try {
            jSch = new JSch();

            // 根据主机账号、ip、端口获取一个Session对象
            session = jSch.getSession(username, host, port);

            // 存放主机密码
            session.setPassword(password);

            // 去掉首次连接确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            // 超时连接时间为3秒
            session.setTimeout(30000);

            // 进行连接
            session.connect();

            // 打开SFTP通道
            chSftp = (ChannelSftp) session.openChannel("sftp");

            // 建立SFTP通道的连接
            chSftp.connect();

            // 设置编码格式
            chSftp.setFilenameEncoding("UTF-8");

            /**
             * 说明:
             * 1、当前上读取文件信息没有任何反馈,如果没有异常则代表成功
             * 2、如果需要判断是否读取成功的进度,可参考https://blog.csdn.net/coding99/article/details/52416373?locationNum=13&fps=1
             * 3、将src文件下载到dst路径中
             */
            chSftp.get(directory, downloadFile);

            XxlJobHelper.log("文件下载成功");
        } catch (JSchException | SftpException e) {
            XxlJobHelper.log(e.getMessage());
        } finally {
            close();
        }
    }

    /**
     * 如果此目录不存在将新建目录
     */
    public void directory(String path) {

        try {
            jSch = new JSch();

            // 根据主机账号、ip、端口获取一个Session对象
            session = jSch.getSession(username, host, port);

            // 存放主机密码
            session.setPassword(password);

            // 去掉首次连接确认
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            // 超时连接时间为3秒
            session.setTimeout(30000);

            // 进行连接
            session.connect();

            // 打开SFTP通道
            chSftp = (ChannelSftp) session.openChannel("sftp");

            // 建立SFTP通道的连接
            chSftp.connect();

            String[] folders = path.split("/");
            for (String folder : folders) {
                if (folder.length() > 0) {
                    try {
                        chSftp.cd(folder);
                    } catch (SftpException e) {
                        try {
                            chSftp.mkdir(folder);
                            XxlJobHelper.log("生成目录" + folder);
                            chSftp.cd(folder);
                        } catch (SftpException ex) {
                            throw new RuntimeException(ex);
                        }
                    }
                }
            }

        } catch (JSchException e) {
            throw new RuntimeException(e);
        } finally {
            close();
        }
    }

}