package io.renren.modules.sys.controller.algs;

import com.jcraft.jsch.ChannelSftp;
import com.spotify.docker.client.LogStream;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Image;
import io.minio.errors.*;
import io.renren.common.annotation.SysLog;
import io.renren.common.utils.*;
import io.renren.common.validator.ValidatorUtils;
import io.renren.common.validator.group.AddGroup;
import io.renren.common.validator.group.UpdateGroup;
import io.renren.modules.sys.entity.algs.*;
import io.renren.modules.sys.entity.serverport.ServerPort;
import io.renren.modules.sys.service.*;
import io.renren.modules.sys.service.impl.AlgTrainLogServiceImpl;
import io.renren.modules.sys.service.impl.AlgTrainServiceImpl;
import io.renren.modules.sys.service.impl.AlgsModelsServiceImpl;
import io.renren.modules.sys.service.impl.AlgsServiceImpl;
import io.swagger.models.auth.In;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static io.renren.common.utils.ShiroUtils.getUserId;

/**
 * @Author: Ivan Q
 * @Date: 2021/6/11 16:28
 */
@RestController
@RequestMapping("/algstrain")
public class algTrainController {
    //获取host地址
    @Value("${host}")
    private String host;
    //获取远程连接docker ip地址
    @Value("${remote-docker}")
    private String remoteDocker;
    @Autowired
    AlgTrainServiceImpl algTrainService;
    @Autowired
    CategoryService categoryService;
    @Autowired
    BaseImageService baseImageService;
    @Autowired
    AlgsService algsService;
    @Autowired
    AlgTrainLogServiceImpl algTrainLogService;
    @Autowired
    AlgsModelsServiceImpl algsModelsService;
    @Autowired
    ApprovalService approvalService;
    @Autowired
    VersionService versionService;
    @Autowired
    ServerPortService serverPortService;
    /**
     * 所有列表
     */
    @GetMapping("/list")
    /*
    把这个@RequiresPermissions注解去掉，那么如果在角色管理中，去掉查看功能的话也可以获取列表，但是没有每条数据右侧的查看按钮；
    不去掉的话那就是必须在打开查看模板功能，否则不能获取列表数据。
     */
    @RequiresPermissions("train:list")
    public R list(@RequestParam Map<String, Object> params){
        //只有超级管理员，才能查看所有模板列表
        //先这样写，之后去掉
        if(getUserId() != Constant.SUPER_ADMIN){
            params.put("createUserId", getUserId());
        }
        PageUtils page = algTrainService.queryPageOnUse(params);
        return R.ok().put("page", page);
    }

    /**
     * 信息
     * 这个方法貌似用不到，如果要用需要增加权限
     */
    @GetMapping("/info/{algTrainId}")
    public R info(@PathVariable("algTrainId") Long algTrainId){
        AlgTrain algTrain = algTrainService.getById(algTrainId);
//        Long categoryId = algsTemplsService.querycategoryId(tmpId);
//        temp.setCategoryId((categoryId));

//        不需要获取创建人的信息，总的列表中已经有了
//        String username = userService.getById(temp.getUid()).getUsername();
        return R.ok().put("algTrain", algTrain);
    }

    /**
     * 保存
     */
    @SysLog("保存任务")
    @PostMapping("/save")
    @RequiresPermissions("train:save")
    @Transactional
    public R save(@RequestBody HashMap<String,String> map) throws Exception {
        AlgTrain algTrain=new AlgTrain();
        algTrain.setMissName(map.get("missName"));

        Long categoryId = categoryService.getByName(map.get("classificationtag"));
        algTrain.setCategoryId(categoryId);
        algTrain.setRemark(map.get("remark"));
        algTrain.setUid(Long.parseLong(map.get("uid")));
        algTrain.setAlgorithmId(Long.parseLong(map.get("algorithmId")));
        ValidatorUtils.validateEntity(algTrain, AddGroup.class);
        List<AlgTrain> list = algTrainService.list();
        for(AlgTrain train : list){
            if(train.getMissName().equals(algTrain.getMissName())) return R.error("已经存在重复名称的任务");
        }
        Algorithm alg=algsService.getById(algTrain.getAlgorithmId());
        //如果是智能算法
        if(alg.getFrameId()!=-1){
            algTrain.setVersionId(Long.parseLong(map.get("versionId")));
            algTrain.setRunfileName(map.get("fileSelected"));
            algTrain.setMissStatus((byte) 1);//missStatus 0:停止 1:待开始 2:运行中 3:已结束 4:已发布
            algTrain.setAlgFrameId(alg.getFrameId());

//        user.setCreateUserId(getUserId());

            algTrainService.save(algTrain);
            //重新获取，目的是获取algTrainId
            algTrain=algTrainService.selectByMissName(map.get("missName"));

            //在服务器中创建存放算法文件的文件夹
            FTPUtils.mkdir("algTrain"+algTrain.getAlgorithmTrainingId());
            //获取所选算法版本的文件列表
            List<FileTest> fileList=MinIoUtils.listFiles("algorithm","alg"+map.get("algorithmId")+"/version"+map.get("versionId"));
            for(FileTest file:fileList){
                //从minio中获得目标文件的输入流
                InputStream input= MinIoUtils.getFileInputStream("algorithm","alg"+map.get("algorithmId")+"/version"+map.get("versionId")+"/"+file.getFilename());
                //从minio中获取的文件上传至服务器
                FTPUtils.uploadFile("algTrain"+algTrain.getAlgorithmTrainingId(),file.getFilename(),input);
            }
        }else {
            //如果是传统算法
            algTrain.setRunfileName(map.get("fileSelected"));
            algTrain.setMissStatus((byte) 1);//missStatus 0:停止 1:待开始 2:运行中 3:已结束 4:已发布
            algTrain.setAlgFrameId(alg.getFrameId());
            algTrainService.save(algTrain);
            //重新获取，目的是获取algTrainId
            algTrain=algTrainService.selectByMissName(map.get("missName"));

            //在服务器中创建存放算法文件的文件夹
            FTPUtils.mkdir("algTrain"+algTrain.getAlgorithmTrainingId());
            //获取所选算法版本的文件列表
            List<FileTest> fileList=MinIoUtils.listFiles("algorithm","alg"+map.get("algorithmId"));
            for(FileTest file:fileList){
                //从minio中获得目标文件的输入流
                InputStream input= MinIoUtils.getFileInputStream("algorithm","alg"+map.get("algorithmId")+"/"+file.getFilename());
                //从minio中获取的文件上传至服务器
                FTPUtils.uploadFile("algTrain"+algTrain.getAlgorithmTrainingId(),file.getFilename(),input);
            }
        }


        //以下部分是创建容器部分

        //首先获取内存大小限制，并转换为以字节为单位
        Long memoryMB=Long.parseLong(map.get("memory"));
        Long memoryByte=memoryMB*1024*1024;

        //选择一个未使用的端口进行映射,并标记已使用
        Long portInt=serverPortService.selectNotUsedPort().getServerPortId();
        ServerPort serverPort=new ServerPort(portInt,1);
        serverPortService.updateServerPort(serverPort);
        /*boolean isPortUsing=PortUtils.isPortUsing(host,portInt);
        if(isPortUsing){
            while (isPortUsing){
                portInt=random.nextInt(60999)%(60999-32768+1)+32768;
                isPortUsing=PortUtils.isPortUsing(host,portInt);
            }
        }*/
        //获取该算法在被创建时所选的算法框架
        String baseImageName=baseImageService.getById(alg.getFrameId()).getBaseImageName();
        String containerId=DockerClientUtils.createContainer("algTrain"+algTrain.getAlgorithmTrainingId(),String.valueOf(portInt),memoryByte,baseImageName,map.get("setCpus"));

        //保存该训练任务所在容器id
        algTrain.setContainerId(containerId);
        //保存该容器对外暴露的tensorboard端口
        algTrain.setIpAddress("http://"+remoteDocker+":"+portInt);
        algTrainService.update(algTrain);
        return R.ok();


    }

    /**
     * Description:根据algorithmTrainingId，安装用户上传的whl包到对应容器内
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/installWhl")
    public R installWhl(String algorithmTrainingId) throws DockerException, InterruptedException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        Vector<ChannelSftp.LsEntry> vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId);
        for(int i=0;i<vector.size();i++){
            //读取所上传算法文件，若包含whl后缀的文件，则进行安装
            String suffix=vector.get(i).getFilename().substring(vector.get(i).getFilename().lastIndexOf('.'));
            if(suffix.equals(".whl")){
                DockerClientUtils.install(algTrain.getContainerId(),"algTrain"+algorithmTrainingId,vector.get(i).getFilename());
                System.out.println("安装了"+vector.get(i).getFilename());
            }
        }
        return R.ok();
    }

    /**
     * Description:根据algorithmTrainingId，开始训练
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/startTraining")
    public R startTraining(String algorithmTrainingId) throws DockerException, InterruptedException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        String execOutput=DockerClientUtils.execPython(algTrain.getContainerId(),"algTrain"+algTrain.getAlgorithmTrainingId(),algTrain.getRunfileName());

        //完成训练后，将任务状态改为已结束，并保存结束时间
        algTrain.setMissStatus((byte) 3);

        //将对应版本训练状态改为已训练
        /*Version version=versionService.getById(algTrain.getVersionId());
        version.setVersionStatus((byte) 1);
        versionService.update(version);*/

        Date date = new Date();
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        algTrain.setMissStopTime(date);
        algTrainService.update(algTrain);

        //保存日志到数据库
        String algorithmTrainingLogContent= (String) getOutput(algorithmTrainingId).get("output");
        AlgTrainLog algTrainLog=new AlgTrainLog();
        algTrainLog.setAlgorithmTrainingId(Long.parseLong(algorithmTrainingId));
        algTrainLog.setAlgorithmTrainingLogContent(algorithmTrainingLogContent);
        algTrainLogService.save(algTrainLog);

        System.out.println(algTrainLogService.selectByAlgTrainId(Long.parseLong(algorithmTrainingId)).getAlgorithmTrainingLogContent());

        //若有tensorboard文件 则保存至minio
        /*Vector<ChannelSftp.LsEntry> vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId);
        for(int i=0;i<vector.size();i++){
            if(vector.get(i).getFilename().equals("testTensorboard")){
                saveTensorboardFile(algorithmTrainingId);
            }
        }*/
        try {
            saveTensorboardFile(algorithmTrainingId);
        }catch (Exception e){
            throw e;
        }
        return R.ok();
    }
    /**
     * Description:根据algorithmTrainingId，开始训练，并附带参数
     * @param algorithmTrainingId
     * @param algParameters
     * @return
     */
    @GetMapping("/startTrainingWithPara")
    public R startTrainingWithPara(String algorithmTrainingId,String algParameters) throws DockerException, InterruptedException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        String[] params=algParameters.split(",");
        String execOutput=DockerClientUtils.execPythonWithPara(algTrain.getContainerId(),"algTrain"+algTrain.getAlgorithmTrainingId(),algTrain.getRunfileName(),params);
        //完成训练后，将任务状态改为已结束，并保存结束时间
        algTrain.setMissStatus((byte) 3);
        Date date = new Date();
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        algTrain.setMissStopTime(date);
        algTrainService.update(algTrain);
        return R.ok();
    }

    /**
     * Description:根据algorithmTrainingId，保存对应的tensorboard文件到minio
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/saveTensorboardFile")
    public R saveTensorboardFile(String algorithmTrainingId) throws DockerException, InterruptedException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        DockerClientUtils.copyFile(algTrain.getContainerId(),"/opt/testTensorboard","/opt/algTrain"+algTrain.getAlgorithmTrainingId());
        Vector<ChannelSftp.LsEntry> vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId+"/testTensorboard");
        for(int i=0;i<vector.size();i++){
            System.out.println(vector.get(i));
        }
        ChannelSftp.LsEntry entry=vector.lastElement();
        String tensorboardFile=entry.getFilename();
        Long fileSize=entry.getAttrs().getSize();
        System.out.println(tensorboardFile+","+fileSize);
        InputStream inputStream=null;
        try {
            inputStream=FTPUtils.downloadFile("/opt/uploadFile/algTrain"+algorithmTrainingId+"/testTensorboard/"+tensorboardFile);
            MinIoUtils.uploadFileByInputStream(inputStream,fileSize,"tensorboardfile","tensorboardFile"+algorithmTrainingId+"/"+tensorboardFile);
            inputStream.close();//记得关闭inputStream 不然后续会报错
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            inputStream.close();
        }

        return R.ok();
    }

    /**
     * Description:根据algorithmTrainingId，查看该训练任务下的所有文件
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/showFiles")
    public R showFiles(String algorithmTrainingId){
        Vector<ChannelSftp.LsEntry> vector=new Vector();
        //显示目标testTensorboard下的tensorboard文件
        vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId+"/testTensorboard");
        System.out.println(vector.get(2).getFilename());
        return R.ok();
    }

    /**
     * Description:根据algorithmTrainingId，获得运行python文件的日志
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/getOutput")
    public R getOutput(String algorithmTrainingId) throws DockerException, InterruptedException, IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        DockerClientUtils.copyFile(algTrain.getContainerId(),"/nohup.out","/opt/algTrain"+algTrain.getAlgorithmTrainingId());
        InputStream inputStream=FTPUtils.downloadFile("/opt/uploadFile/algTrain"+algorithmTrainingId+"/nohup.out");
        String result = new BufferedReader(new InputStreamReader(inputStream))
                .lines().collect(Collectors.joining("\n"));
        inputStream.close();
        System.out.println(result);

        return R.ok().put("output",result);
    }

    /**
     * Description:比较两个算法训练的tensorboard图
     * @param
     * @return
     */
    @PostMapping("/algorithmTrainCompare")
    public R algorithmTrainCompare(@RequestBody String[] algorithmTrainingIds) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidResponseException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InternalException, DockerException, InterruptedException {
        for(String algorithmTrainingId:algorithmTrainingIds){
            System.out.println(algorithmTrainingId);
        }

        //若已存在testTensorboard目录，则删除，然后新建
        if(FTPUtils.isDirExist("testTensorboard")){
            FTPUtils.removeDir("testTensorboard");
        }
        FTPUtils.mkdir("testTensorboard");
        for (String algorithmTrainingId:algorithmTrainingIds){
            AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
            String missName=algTrain.getMissName();
            FTPUtils.mkdir("testTensorboard/"+missName);
            FileTest file=MinIoUtils.listFiles("tensorboardfile","tensorboardFile"+algorithmTrainingId).get(0);
            InputStream inputStream=MinIoUtils.getFileInputStream("tensorboardfile","tensorboardFile"+algorithmTrainingId+"/"+file.getFilename());
            FTPUtils.uploadFile("testTensorboard/"+missName,file.getFilename(),inputStream);
        }
        Long memoryByte=500*1024*1024l;

        //选择一个未使用的端口进行映射,并标记已使用
        Long portInt=serverPortService.selectNotUsedPort().getServerPortId();
        ServerPort serverPort=new ServerPort(portInt,1);
        serverPortService.updateServerPort(serverPort);
        String containerId=DockerClientUtils.createContainer("testTensorboard",String.valueOf(portInt),memoryByte,"tensorflow/tensorflow:1.14.0","");
        DockerClientUtils.execTensorboard(containerId,"testTensorboard");

        return R.ok().put("port",portInt).put("containerId",containerId);
    }

    /**
     * Description:改变任务运行状态为运行中
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/changeMissStatus")
    @Transactional
    public R changeMissStatus(String algorithmTrainingId){
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));

        //点击开始训练时，将任务状态改为运行中，并记录开始时间
        algTrain.setMissStatus((byte) 2);
        Date date = new Date();
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        algTrain.setMissCreationTime(date);
        algTrainService.update(algTrain);
        return R.ok();
    }

    /**
     * Description:打开发布页面时，查询当前算法已有的模型及python文件
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/getModelAndPythonFile")
    public R getModelAndPythonFile(String algorithmTrainingId){
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        //从服务器获取该训练任务下有哪几个文件
        Vector<ChannelSftp.LsEntry> vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId);
        List<ChannelSftp.LsEntry> models=new ArrayList<>();
        List<ChannelSftp.LsEntry> pythonFiles=new ArrayList<>();
        for(int i=0;i<vector.size();i++){
            int lastPointLocation=vector.get(i).getFilename().lastIndexOf('.');
            if(lastPointLocation==-1) continue;
            //根据后缀名，判断属于哪类文件
            String suffix=vector.get(i).getFilename().substring(lastPointLocation);
            if(suffix.equals(".py"))    pythonFiles.add(vector.get(i));
            else if(!suffix.equals(".")&&!suffix.equals(".csv")&&!suffix.equals(".out"))    models.add(vector.get(i));
        }
        return R.ok().put("algTrain",algTrain).put("models",models).put("pythonFiles",pythonFiles);
    }

    /**
     * Description:算法发布，将训练好的模型及python文件上传至minio
     * @param request
     * @return
     */
    @PostMapping("/algorithmPublish")
    @Transactional
    public R algorithmPublish(MultipartHttpServletRequest request) throws IOException, InvalidResponseException, InvalidKeyException, NoSuchAlgorithmException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InsufficientDataException, InternalException {
        String algorithmTrainingId=request.getParameter("algorithmTrainingId");
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        Long frameId=algTrain.getAlgFrameId();
        //将前端选择的文件传入list
        List<String> models=Arrays.asList(request.getParameter("models").split(","));
        List<String> pythonFiles=Arrays.asList(request.getParameter("pythonFiles").split(","));

        AlgorithmModel model=new AlgorithmModel();
        model.setModelName(request.getParameter("missName"));
        model.setCategoryId(Long.parseLong(request.getParameter("categoryId")));
        model.setUid(Long.parseLong(request.getParameter("uid")));
        model.setAppFile(request.getParameter("appFile"));
        model.setImageFile(request.getParameter("imageFile"));
        model.setForm(frameId==-1?(byte)1:(byte)2);
        model.setAlgorithmId(algTrain.getAlgorithmId());
        model.setRemark("未发布");
        //因要先申请审批，所以先设置为未同意发布状态
        model.setIsApprovaled((byte) 0);


        List<AlgorithmModel> list = algsModelsService.list();
        for(AlgorithmModel algorithmModel : list){
            if(algorithmModel.getModelName().equals(model.getModelName())) return R.error("已经存在重复名称的算法");
        }
        algsModelsService.save(model);
        int modelId=algsModelsService.selectByModelName(request.getParameter("missName")).getModelId();

        //申请审批
        Approval approval=new Approval();
        approval.setAlgorithmTrainingId(Long.parseLong(algorithmTrainingId));
        approval.setModelId((long) modelId);
        approval.setCategoryId(Long.parseLong(request.getParameter("categoryId")));
        approval.setUid(Long.parseLong(request.getParameter("uid")));
        Date date = new Date();
        approval.setApplyTime(date);
        approval.setApprovalStatus((byte) 0);
        approvalService.save(approval);

        Vector<ChannelSftp.LsEntry> vector=FTPUtils.showFiles("algTrain"+algorithmTrainingId);
        for(int i=0;i<vector.size();i++){
            //从服务器中有的文件与前端所选文件一一对比，若匹配成功，则上传
            String fileName=vector.get(i).getFilename();
            Long fileSize=vector.get(i).getAttrs().getSize();
            if(models.contains(fileName)||pythonFiles.contains(fileName)){
                InputStream inputStream=null;
                try {
                    inputStream=FTPUtils.downloadFile("/opt/uploadFile/algTrain"+algorithmTrainingId+"/"+fileName);
                    //同时上传到publishedalgorithm桶和algmodel桶
                    MinIoUtils.uploadFileByInputStream(inputStream,fileSize,"publishedalgorithm","algorithm"+algorithmTrainingId+"/"+fileName);
                    MinIoUtils.copyFile("algmodel","model"+modelId+"/"+fileName,"publishedalgorithm","algorithm"+algorithmTrainingId+"/"+fileName);
                    inputStream.close();
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    inputStream.close();
                }

            }
        }


        List<FileTest> fileTestList=MinIoUtils.listFiles("algorithm","alg"+algTrain.getAlgorithmId()+"/"+"version"+algTrain.getVersionId());
        for(FileTest file:fileTestList){
            if(file.getFilename().substring(file.getFilename().lastIndexOf(".")).equals(".csv")){
                MinIoUtils.copyFile("algmodel","model"+modelId+"/"+file.getFilename(),"algorithm","alg"+algTrain.getAlgorithmId()+"/"+"version"+algTrain.getVersionId()+"/"+file.getFilename());
            }
        }
        //发布完成后，将任务状态改为已申请发布
        algTrain.setMissStatus((byte) 5);
        algTrainService.update(algTrain);
        return R.ok();
    }

    /**
     * Description:删除任务，目前为删除容器及存在数据库中的任务信息，后续要修改
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/deleteById")
    @Transactional
    public R update(String algorithmTrainingId) throws DockerException, InterruptedException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        DockerClientUtils.deleteContainer(algTrain.getContainerId());//首先将该容器删除
        FTPUtils.removeDir("algTrain"+algorithmTrainingId);//其次将存储卷删除
        algTrainService.removeById(Long.parseLong(algorithmTrainingId));//数据库中删除
        String port=algTrain.getIpAddress().substring(algTrain.getIpAddress().length()-5);
        ServerPort serverPort=new ServerPort(Long.parseLong(port),0);
        serverPortService.updateServerPort(serverPort);//将端口释放
        return R.ok();
    }

    /**
     * Description:根据algorithmTrainingId获得algId及versionId
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/getAlgIdVersionId")
    public R getAlgIdVersionId(String algorithmTrainingId){
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        return R.ok().put("algorithmNameToVersion",algTrain.getAlgorithmId()).put("verisionToFile",algTrain.getVersionId());
    }

    /**
     * Description:暂停训练任务
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/pauseMiss")
    @Transactional
    public R pauseMiss(String algorithmTrainingId) throws DockerException, InterruptedException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        DockerClientUtils.pauseContainer(algTrain.getContainerId());
        algTrain.setMissStatus((byte) 7);
        algTrainService.update(algTrain);
        return R.ok();
    }

    /**
     * Description:回复已暂停的训练任务
     * @param algorithmTrainingId
     * @return
     */
    @GetMapping("/unpauseMiss")
    public R unpauseMiss(String algorithmTrainingId) throws DockerException, InterruptedException {
        AlgTrain algTrain=algTrainService.selectByPrimaryKey(Long.parseLong(algorithmTrainingId));
        DockerClientUtils.unpauseContainer(algTrain.getContainerId());
        algTrain.setMissStatus((byte) 2);
        algTrainService.update(algTrain);
        return R.ok();
    }

    /**
     * Description 根据algId和versionId查找训练任务对应的文件(包含代码和数据集)
     * @param params
     * @return
     */
    @GetMapping("/listFiles")
    public R listFiles(@RequestParam Map<String,Object> params) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidResponseException, ErrorResponseException, XmlParserException, InvalidBucketNameException, InternalException {
        String algorithmNameToVersion=String.valueOf(params.get("algorithmNameToVersion"));
        String verisionToFile=String.valueOf(params.get("verisionToFile"));

        List<FileTest> fileList= MinIoUtils.listFiles("algorithm","alg"+algorithmNameToVersion+"/version"+verisionToFile);
        List<FileTest> pythonFiles=new ArrayList<>();
        List<FileTest> datasetFiles=new ArrayList<>();
        for(FileTest file:fileList){
            String suffix=file.getFilename().substring(file.getFilename().lastIndexOf("."));
            if(suffix.equals(".py")){
                pythonFiles.add(file);
            }else if(suffix.equals(".csv")){
                datasetFiles.add(file);
            }
        }
        return R.ok().put("pythonFiles",pythonFiles).put("datasetFiles",datasetFiles);
    }

    /**
     * 不允许修改任务
     * 此方法不可用，需要增加权限
     * 修改任务
     */
    @SysLog("修改任务")
    @PostMapping("/update")
    @RequiresPermissions("train:update")
    public R update(@RequestBody AlgTrain algTrain){
        ValidatorUtils.validateEntity(algTrain, UpdateGroup.class);

//        model.setCreateUserId(getUserId());
        algTrainService.update(algTrain);

        return R.ok();
    }


    /**
     * 批量删除，暂时不用
     * 不允许使用
     * 需要增加权限
     * 删除任务
     */
    @SysLog("删除任务")
    @PostMapping("/delete")
    @RequiresPermissions("train:delete")
    public R delete(@RequestBody Long[] algTrainIds){
        algTrainService.deleteBatch(algTrainIds);

        return R.ok();
    }

    /**
     * Description:获得容器宿主机的ip
     * @return
     */
    @GetMapping("/getHost")
    public R getHost(){
        return R.ok().put("host",remoteDocker);
    }

    /**
     * Description:用来删除训练任务对比的容器
     * @param containerId
     * @return
     */
    @GetMapping("/deleteContainer")
    public R deleteContainer(String containerId,String port) throws DockerException, InterruptedException {
        DockerClientUtils.deleteContainer(containerId);
        ServerPort serverPort=new ServerPort(Long.parseLong(port),0);
        serverPortService.updateServerPort(serverPort);//将端口释放
        return R.ok();
    }

}
