提交 ecf2bdd6 编写于 作者: 6 635677437d755007c09848d3

relase 0.1

上级 bfe643d9
# 快速开始
进入web ide: https://idegitcode.net/cloud-ide/1024
首次启动,python镜像会被首先创建,可直接使用。其他语言会在后台异步创建,创建完成后即可使用。
**首次启动 相关依赖和镜像视网络情况,加载时间未知**
# 项目介绍
基于docker的在线代码编辑运行工具,目前支持的语言有:
- python
- golang
- java
各语言环境通过docker容器实现,整体项目比较简单,前端不太熟悉做的也比较简陋,代码是周末两天完成的,还有许多功能没有实现。 例如:
- 未支持标准输入
- stdout和stderr分开等等
# 如何添加语言支持
添加新语言支持仅需2步
1.`config`目录下创建该语言的Dockerfile以及example文件作为编辑器初始化代码
2. 在common.py中增加该语言的名字、代码文件生成命令、代码运行命令、前端编辑器模式
```python
language_list = [
Language("python",
"python -u run.py",
"cat > run.py << EOF\n",
"python"),
Language("golang",
"go run run.go",
"cat > run.go << EOF\n",
"golang"),
Language("java",
"javac Example.java && java Example",
"cat > Example.java << EOF\n",
"java")
]
```
......@@ -5,7 +5,7 @@ fi
if [ ! -f /usr/bin/docker ]; then
apt update
apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
apt update
apt-get -y install docker-ce
......@@ -17,9 +17,8 @@ EOF
service docker start
fi
# 其他镜像在python中异步创建
docker build -f config/python/Dockerfile -t webcode_python:1.0 .
docker build -f config/golang/Dockerfile -t webcode_golang:1.0 .
pip install -r requirements -i https://mirrors.aliyun.com/pypi/simple/
python router.py
\ No newline at end of file
python router.py
import logging
import os.path
from typing import Dict
TAG_STR = "webcode_{}:1.0"
DOCKER_CONFIG_DIR = "config/{}"
from docker import APIClient
low_level_client = APIClient(base_url='unix://var/run/docker.sock')
logger = logging.getLogger(__name__)
class Language:
image = None
def __init__(self, name, run_way, file_way, editor_mode="python"):
"""
:param name: 语言名,和dockerfile目录名一致
......@@ -13,28 +21,59 @@ class Language:
:param file_way: 代码文件生成命令
:param editor_mode: 代码编辑器模式名
"""
self.name = name
self.run_way = run_way
self.file_way = file_way
dir = "config/" + name
self.editor_mode = editor_mode
dir = DOCKER_CONFIG_DIR.format(name)
if os.path.isdir(dir):
for f in os.listdir(dir):
if os.path.isfile(dir + "/" + f) and f.startswith("example"):
with open("config/" + name + "/" + f) as f:
with open(dir + "/" + f) as f:
self.default_code = f.read()
self.editor_mode = editor_mode
self.image = None
def set_image(self, image):
self.image = image
def build_image(self):
try:
print(self.name, "正在创建镜像")
generator = low_level_client.build(path=DOCKER_CONFIG_DIR.format(self.name),
tag=TAG_STR.format(self.name),
rm=True, decode=True)
while True:
# 打印日志,防止build太久看不到进度条
try:
output = generator.__next__()
for k in ["stream", "status", "progress"]:
if k in output:
break
else:
continue
print(output.get("stream", ""), output.get("status", ""), output.get("progress", ""))
except StopIteration:
print("Docker image build complete.")
return True
except ValueError as e:
print("Error parsing output from docker image build")
except Exception as e:
print(e)
return False
language_list = [
Language("python",
"python -u run.py",
"cat > run.py << EOF\n",
"python"),
Language("golang",
"go run run.go",
"cat > run.go << EOF\n",
"golang"),
Language("java",
"javac Example.java && java Example",
"cat > Example.java << EOF\n",
"java")
]
Languages: Dict[str, Language] = {
"python": Language("python",
"python -u run.py",
"cat > run.py << EOF\n",
"python"),
"golang": Language("golang",
"go run run.go",
"cat > run.go << EOF\n",
"golang")
}
Languages: Dict[str, Language] = {v.name: v for v in language_list}
package main
import "fmt"
func fib(n uint64) uint64 {
......
FROM openjdk:20-jdk-slim
\ No newline at end of file
import java.util.*;
// 不要修改class name
public class Example {
static long fib(long n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
public static void main(String[] args) {
System.out.print(fib(15) + " via java");
}
}
\ No newline at end of file
import json
import threading
import common
import server
from flask import Flask, request, make_response, jsonify, render_template
......@@ -16,7 +16,7 @@ def execute():
try:
output = server.execute(data.get("code"), data.get("type").lower())
except Exception as e:
return make_response(jsonify({"code": 10000, "output": e}))
return make_response(jsonify({"code": 10000, "output": str(e)}))
return make_response(jsonify({"code": 0, "output": output}))
......@@ -30,5 +30,6 @@ def index():
if __name__ == "__main__":
server.init_image()
t = threading.Thread(target=server.load)
t.start()
app.run("0.0.0.0", 3000, debug=False)
import docker
import os
import json
import logging
from func_timeout import func_set_timeout, exceptions
from docker.errors import ImageNotFound
import time
import threading
import common
from common import *
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.DEBUG)
client = docker.from_env()
def init_image():
"""
初始化各语言镜像
"""
def get_and_set_image(name):
if Languages[name].image:
return Languages[name].image
try:
image = client.images.get(TAG_STR.format(name))
Languages[name].set_image(image)
return image
except ImageNotFound:
logger.error("找不到%s的镜像", name)
return None
def load():
for name, value in Languages.items():
tag = TAG_STR.format(name)
try:
image = client.images.get(tag)
value.set_image(image)
except ImageNotFound:
path = DOCKER_CONFIG_DIR.format(name)
if os.path.isdir(path):
print("正在初始化 ", name, "镜像...")
image = client.images.build(path=path, tag=tag, quiet=False)
value.set_image(image)
else:
logger.error("找不到%s的镜像", name)
logger.info("初始化镜像完成")
if get_and_set_image(name) is None:
value.build_image()
get_and_set_image(name)
def execute(code, _type):
if _type not in Languages:
raise Exception("不支持的语言")
if _type not in Languages or Languages[_type].image is None:
raise Exception("找不到运行环境,请等待后台创建")
result = ""
try:
code += "\nEOF\n"
......@@ -61,6 +66,4 @@ def execute(code, _type):
if __name__ == "__main__":
init_image()
code = "import time\nprint(2)"
print(execute(code, PYTHON))
pass
......@@ -31,8 +31,6 @@
<div class="wrapper2">
<div class="wrapper" style="margin-left: 0.625rem; margin-top: 0.625rem">
<div class="box1"><select id="code_type" class="selectpicker" data-live-search="true">
<option>python</option>
<option>golang</option>
</select>
</div>
<div class="box1">
......@@ -63,6 +61,10 @@
var all_default = {{ code_default }}
var mode = {{ mode }}
{% endautoescape %}
for (let v of Object.keys(all_default)) {
$('#code_type').append(new Option(v, v))
}
var editor = ace.edit("editor", {
theme:"ace/theme/one_dark",
autoScrollEditorIntoView: true,
......@@ -97,7 +99,11 @@
contentType: 'application/json',
complete: function(data) {
$("#executor").removeAttr("disabled")
$("#output").val(data.responseJSON.output)
if (data == undefined || data.responseJSON == undefined || data.responseJSON.output == undefined) {
$("#output").val("系统错误")
} else {
$("#output").val(data.responseJSON.output)
}
},
});
})
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册