🍩

ブラウザ上でコードを書いて実行

2021/12/30に公開

アドカレです。ごめんなさい🙇
cistLT Advent Calendar 2021
https://adventar.org/calendars/6520
LOCAL Students Advent Calendar 2021
https://adventar.org/calendars/6552

つくったもの

プログラミング言語をブラウザから実行できるアプリケーションを作りました。

https://github.com/OHMORIYUSUKE/play-langs

参考
https://qiita.com/tttamaki/items/2b009aa957cfa4895d50

アプリについて

言語を選択し、コードを入力、入力がある場合は入力与え、実行ボタンを押すと実行され、結果が表示されます。また、入力された処理が3秒以上かかるものは、強制終了するようにしています。

以下の9種類の言語を実行できます。

c
cpp
shell
ruby
haskell
python
java
go
javascript

使用技術

フロントエンド

  • React
  • material ui
  • react-monaco-editor

バックエンド

  • Python
  • flask
  • uwsgi

Dockerを用いて開発しており、バックエンドコンテナのDebian環境で9種類の言語を実行しています。

仕組み

簡単な図

バックエンドはdebianにPythonとuwsgi,flask,その他言語をインストールする。

backend/Dockerfile
FROM debian

RUN apt-get update && apt-get install -y -q sudo 

########################################################################
# Cの環境構築
RUN sudo apt-get install -y -q gcc
# Javaの環境構築
RUN sudo apt-get install -y -q default-jre
RUN sudo apt install -y -q default-jdk
# goの環境構築
RUN sudo apt-get install -y -q golang-go
# rubyの環境構築
RUN sudo apt-get install -y -q ruby 
# nodeの環境構築
RUN sudo apt-get install -y -q nodejs
# Haskellの環境構築
RUN sudo apt-get install -y -q haskell-platform
# Pythonの環境構築
RUN sudo apt-get install -y -q python3
#######################################################################
# pip3コマンドをインストール
RUN sudo apt install -y -q python3-pip

# 文字コード
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

# uwsgiでPythonのアプリケーションを配置するディレクトリ
COPY ./python /var/www

# 作業ディレクトリ
WORKDIR /var/www/
RUN pip3 install --upgrade pip

RUN pip3 install -r requirements.txt

# uwsgiを実行するコマンド
CMD ["uwsgi","--ini","/var/www/uwsgi.ini"]

フロントエンドからPOSTされた実行したいコードのデータをhoge.pyに書き込み、以下のコードを実行すると、python3 hoge.py < input.inが実行することができる。input.inには、フロントエンドからPOSTされた入力データを書き込んでおく。

backend/main.py
proc = subprocess.run("python3 hoge.py < input.in", timeout=3, shell=True, stdout=PIPE, stderr=PIPE, text=True)
out = proc.stdout #実行結果
err = proc.stderr #エラー内容

https://docs.python.org/ja/3/library/subprocess.html

苦戦したところ

何か挙動がおかしかった。

POSTされた実行プログラムのデータをファイルに書き込む -> プログラムファイルをsubprocessで実行する。 -> proc.stdoutがnull

ダメなコード

@app.route("/api/v1/play", methods=['GET','POST'])
def main():
  write_posted_code()
  run_posted_code()

想定した挙動のコード

  • write_posted_code()の実行が終了したら、run_posted_code()が実行される。
POSTされた実行プログラムのデータをファイルに書き込む -(完了)-> プログラムファイルをsubprocessで実行する。 -> proc.stdoutにstring
@app.route("/api/v1/play", methods=['GET','POST'])
def main():
  loop = asyncio.get_event_loop()
  loop.create_task(write_posted_code())
  result = loop.run_until_complete(run_posted_code())

おそらく、ファイルに書き込みが終了する前に、subprocessでshellが実行されてしまったため、空のファイルを実行し、nullが返ったと思う。多分。

https://docs.python.org/ja/3.10/library/asyncio-eventloop.html

Dockerがインストールされていれば、動作するので、遊んでください。

https://github.com/OHMORIYUSUKE/play-langs

Discussion