|
|
|
@ -0,0 +1,344 @@
|
|
|
|
|
package com.sztzjy.resource_center.controller.new_module.stu;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.convert.Convert;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import com.sztzjy.resource_center.annotation.AnonymousAccess;
|
|
|
|
|
import com.sztzjy.resource_center.util.ResultEntity;
|
|
|
|
|
import io.swagger.annotations.Api;
|
|
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
|
|
import io.swagger.annotations.ApiParam;
|
|
|
|
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
|
|
import org.apache.http.client.methods.HttpPut;
|
|
|
|
|
import org.apache.http.entity.StringEntity;
|
|
|
|
|
import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
|
|
import org.apache.http.impl.client.HttpClients;
|
|
|
|
|
import org.apache.http.util.EntityUtils;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @author 17803
|
|
|
|
|
* @date 2024-07-19 13:21
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@RestController
|
|
|
|
|
@Api(tags = "jupyter相关")
|
|
|
|
|
@RequestMapping("api/stu/jupyter")
|
|
|
|
|
public class StuJupyterController {
|
|
|
|
|
|
|
|
|
|
@Value("${tch.serverAddress}")
|
|
|
|
|
String JUPYTER_URL;
|
|
|
|
|
|
|
|
|
|
@Value("${tch.token}")
|
|
|
|
|
String TOKEN;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//获取最新token
|
|
|
|
|
@ApiOperation("教师端获取token")
|
|
|
|
|
@GetMapping("/tokenTch")
|
|
|
|
|
@AnonymousAccess
|
|
|
|
|
public ResultEntity getBlockResources(@ApiParam("参数为:jupytertch/jupyterstu") String type) throws IOException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
String[] command = {"docker", "exec", type, "jupyter", "server", "list"};
|
|
|
|
|
|
|
|
|
|
Map map = connectdocker(command);
|
|
|
|
|
Object o = map.get("exitCode");
|
|
|
|
|
System.out.println(o);
|
|
|
|
|
Integer exitCode = Convert.toInt(o);
|
|
|
|
|
System.out.println(exitCode);
|
|
|
|
|
|
|
|
|
|
if (exitCode == 0) {
|
|
|
|
|
Object out = map.get("output");
|
|
|
|
|
String output = Convert.toStr(out);
|
|
|
|
|
// String s="Currently running servers: http://27fedcc1ea32:8888/?token=0201325a5e218f35db24f90b8a4c23373ec86987ce9d0a56 :: /home/jovyan/work";
|
|
|
|
|
int i = output.toString().indexOf("=");
|
|
|
|
|
int i1 = output.toString().lastIndexOf("::");
|
|
|
|
|
String substring = output.toString().substring(i + 1, i1 - 1);
|
|
|
|
|
System.out.println(substring);
|
|
|
|
|
//todo 保存数据库 每半小时执行一次更新token ,如果相同就变换,否则就不变
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK, type + "token为:", substring);
|
|
|
|
|
} else {
|
|
|
|
|
// 执行失败,输出错误信息
|
|
|
|
|
Object err = map.get("errors");
|
|
|
|
|
String errors = Convert.toStr(err);
|
|
|
|
|
System.err.println("Error executing Python code:\n" + errors.toString());
|
|
|
|
|
return new ResultEntity(HttpStatus.OK, errors.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//文件格式转换
|
|
|
|
|
@ApiOperation("发布之后格式转换")
|
|
|
|
|
@GetMapping("/convertToObj")
|
|
|
|
|
@AnonymousAccess
|
|
|
|
|
public ResultEntity convertToObj(@ApiParam("参数为:案例名") String name) throws IOException, InterruptedException {
|
|
|
|
|
|
|
|
|
|
String caseName = "/home/jovyan/work/" + name + ".ipynb";
|
|
|
|
|
String[] command = {"docker", "exec", "jupytertch", "sudo", "jupyter", "nbconvert", "--to", "markdown", caseName};
|
|
|
|
|
|
|
|
|
|
Map map = connectdocker(command);
|
|
|
|
|
Object o = map.get("exitCode");
|
|
|
|
|
Integer exitCode = Convert.toInt(o);
|
|
|
|
|
|
|
|
|
|
if (exitCode == 0) {
|
|
|
|
|
Object out = map.get("output");
|
|
|
|
|
String output = Convert.toStr(out);
|
|
|
|
|
System.out.println(output);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//文件移动
|
|
|
|
|
String path = "/usr/local/tianzeProject/jupyter/tch/" + name + ".md";
|
|
|
|
|
String toPath = "/usr/local/tianzeProject/jupyter/html";
|
|
|
|
|
|
|
|
|
|
String[] commandMove = {"sudo", "mv", path, toPath};
|
|
|
|
|
Process process = Runtime.getRuntime().exec(commandMove);
|
|
|
|
|
// 获取进程的输入流
|
|
|
|
|
BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
|
|
|
|
|
|
|
// 获取进程的输出流
|
|
|
|
|
BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
|
|
|
|
|
|
|
|
|
// 等待进程执行完成
|
|
|
|
|
int exitCodeInfo = process.waitFor();
|
|
|
|
|
if (exitCodeInfo == 0) {
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK, "导出成功");
|
|
|
|
|
} else {
|
|
|
|
|
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "导出失败!请联系管理员");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// 执行失败,输出错误信息
|
|
|
|
|
Object err = map.get("errors");
|
|
|
|
|
String errors = Convert.toStr(err);
|
|
|
|
|
System.err.println("Error executing Python code:\n" + errors.toString());
|
|
|
|
|
return new ResultEntity(HttpStatus.OK, errors.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//文件查询 ,判断有无文件
|
|
|
|
|
@ApiOperation("发布时候判断文件是否存在")
|
|
|
|
|
@GetMapping("/filesIfExist")
|
|
|
|
|
@AnonymousAccess
|
|
|
|
|
public ResultEntity filesIfExist(@ApiParam("参数为:案例名") String name) throws InterruptedException, IOException {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String path = "/usr/local/tianzeProject/jupyter/tch";
|
|
|
|
|
|
|
|
|
|
// 创建表示该目录的 File 对象
|
|
|
|
|
File directory = new File(path);
|
|
|
|
|
|
|
|
|
|
// 获取目录中的所有文件和子目录
|
|
|
|
|
File[] filesList = directory.listFiles();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (filesList != null) {
|
|
|
|
|
// 使用流查找目标文件
|
|
|
|
|
Optional<File> targetFile = Arrays.stream(filesList)
|
|
|
|
|
.filter(file -> file.getName().equals(name))
|
|
|
|
|
.findFirst();
|
|
|
|
|
|
|
|
|
|
if (targetFile.isPresent()) {
|
|
|
|
|
System.out.println("找到了目标文件: " + targetFile.get().getPath());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//文件复制
|
|
|
|
|
// String pathFile = "/usr/local/tianzeProject/jupyter/tch/"+name+".ipynb";
|
|
|
|
|
String toPath = "/usr/local/tianzeProject/jupyter/stu";
|
|
|
|
|
|
|
|
|
|
String[] commandMove = {"sudo", "cp", "-f", targetFile.get().getPath(), toPath};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Process process = Runtime.getRuntime().exec(commandMove);
|
|
|
|
|
// 获取进程的输入流
|
|
|
|
|
BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
|
|
|
|
|
|
|
// 获取进程的输出流
|
|
|
|
|
BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
|
|
|
|
|
|
|
|
|
// 等待进程执行完成
|
|
|
|
|
int exitCodeInfo = process.waitFor();
|
|
|
|
|
System.out.println(exitCodeInfo);
|
|
|
|
|
if (exitCodeInfo == 0) {
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK, "复制成功", true);
|
|
|
|
|
} else {
|
|
|
|
|
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "复制失败!请联系管理员", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK, "文件不存在!", false);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("该目录不存在或不是一个目录");
|
|
|
|
|
return new ResultEntity<>(HttpStatus.BAD_REQUEST, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ApiOperation("后端根据名字创建notebook")
|
|
|
|
|
@GetMapping("/createNoteBook")
|
|
|
|
|
@AnonymousAccess
|
|
|
|
|
public ResultEntity createNoteBook(@ApiParam("参数为:案例名") String name) {
|
|
|
|
|
|
|
|
|
|
//判断有无这个案例
|
|
|
|
|
//
|
|
|
|
|
// String path = "/usr/local/tianzeProject/jupyter/tch";
|
|
|
|
|
//
|
|
|
|
|
// // 创建表示该目录的 File 对象
|
|
|
|
|
// File directory = new File(path);
|
|
|
|
|
//
|
|
|
|
|
// // 获取目录中的所有文件和子目录
|
|
|
|
|
// File[] filesList = directory.listFiles();
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// if (filesList != null) {
|
|
|
|
|
// // 使用流查找目标文件
|
|
|
|
|
// Optional<File> targetFile = Arrays.stream(filesList)
|
|
|
|
|
// .filter(file -> file.getName().equals(name))
|
|
|
|
|
// .findFirst();
|
|
|
|
|
//
|
|
|
|
|
// if (targetFile.isPresent()) {
|
|
|
|
|
// return new ResultEntity<>(HttpStatus.OK,"文件已存在");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
//没有就创建
|
|
|
|
|
|
|
|
|
|
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
|
|
|
|
String notebookContent = "{"
|
|
|
|
|
+ "\"cells\": ["
|
|
|
|
|
+ "{"
|
|
|
|
|
+ "\"cell_type\": \"code\","
|
|
|
|
|
+ "\"execution_count\": null,"
|
|
|
|
|
+ "\"metadata\": {},"
|
|
|
|
|
+ "\"outputs\": [],"
|
|
|
|
|
+ "\"source\": [\"print('Hello, world!')\"]"
|
|
|
|
|
+ "},"
|
|
|
|
|
+ "{"
|
|
|
|
|
+ "\"cell_type\": \"raw\","
|
|
|
|
|
+ "\"execution_count\": null,"
|
|
|
|
|
+ "\"metadata\": {},"
|
|
|
|
|
+ "\"outputs\": [],"
|
|
|
|
|
+ "\"source\": [\"print('This is text!')\"]"
|
|
|
|
|
+ "},"
|
|
|
|
|
+ "{"
|
|
|
|
|
+ "\"cell_type\": \"markdown\","
|
|
|
|
|
+ "\"metadata\": {},"
|
|
|
|
|
+ "\"source\": [\"# Markdown Cell\\n\", \"This is a markdown cell.\"]"
|
|
|
|
|
+ "}"
|
|
|
|
|
+ "],"
|
|
|
|
|
+ "\"metadata\": {"
|
|
|
|
|
+ " \"kernelspec\": {"
|
|
|
|
|
+ " \"display_name\": \"Python 3\","
|
|
|
|
|
+ " \"language\": \"python\","
|
|
|
|
|
+ " \"name\": \"python3\""
|
|
|
|
|
+ " }"
|
|
|
|
|
+ "},"
|
|
|
|
|
+ "\"nbformat\": 4,"
|
|
|
|
|
+ "\"nbformat_minor\": 2"
|
|
|
|
|
+ "}";
|
|
|
|
|
|
|
|
|
|
// 在根目录下创建新的笔记本
|
|
|
|
|
HttpPut createNotebookRequest = new HttpPut(JUPYTER_URL + "/api/contents/"+name+".ipynb");
|
|
|
|
|
createNotebookRequest.addHeader("Authorization", "token " + TOKEN);
|
|
|
|
|
createNotebookRequest.addHeader("Content-Type", "application/json");
|
|
|
|
|
createNotebookRequest.setEntity(new StringEntity("{\"type\": \"notebook\", \"content\": " + notebookContent + "}"));
|
|
|
|
|
|
|
|
|
|
try (CloseableHttpResponse createNotebookResponse = client.execute(createNotebookRequest)) {
|
|
|
|
|
int statusCode = createNotebookResponse.getStatusLine().getStatusCode();
|
|
|
|
|
if (statusCode == 201) {
|
|
|
|
|
System.out.println("Notebook created successfully!");
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK,"创建成功!");
|
|
|
|
|
} else {
|
|
|
|
|
String responseBody = EntityUtils.toString(createNotebookResponse.getEntity());
|
|
|
|
|
System.out.println("Failed to create notebook: " + responseBody);
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK,"已经存在,不用重复创建");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 导入ipynb文件
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//打开页面创建一个uuid文本,返回名字给前端,前端拼接路径打开保存文件就行 保存之后重命名为案例名称
|
|
|
|
|
|
|
|
|
|
// 两套系统,一套教师能看到,一套学生能看到 ,老师发布后学生能看到
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Map connectdocker(String[] command) throws IOException, InterruptedException {
|
|
|
|
|
// 创建一个新的进程来执行Python代码
|
|
|
|
|
Process process = Runtime.getRuntime().exec(command);
|
|
|
|
|
|
|
|
|
|
// 获取进程的输入流
|
|
|
|
|
BufferedReader inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
|
|
|
|
|
|
|
// 获取进程的输出流
|
|
|
|
|
BufferedReader errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 读取Python代码的输出
|
|
|
|
|
String line;
|
|
|
|
|
StringBuilder output = new StringBuilder();
|
|
|
|
|
while ((line = inputStream.readLine()) != null) {
|
|
|
|
|
output.append(line).append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取Python代码的错误信息
|
|
|
|
|
StringBuilder errors = new StringBuilder();
|
|
|
|
|
while ((line = errorStream.readLine()) != null) {
|
|
|
|
|
errors.append(line).append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 等待进程执行完成
|
|
|
|
|
int exitCode = process.waitFor();
|
|
|
|
|
|
|
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
map.put("exitCode", String.valueOf(exitCode));
|
|
|
|
|
map.put("output", output.toString());
|
|
|
|
|
map.put("errors", errors.toString());
|
|
|
|
|
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//新增notebook可用
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
|
createNotebookAndExecuteCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void createNotebookAndExecuteCode() throws IOException {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|