Skip to content

Commit fdba94d

Browse files
Merge pull request #16 from PeerPrep/ajay/download-src
Compile and execute code
2 parents faf7b59 + 1801c7d commit fdba94d

File tree

12 files changed

+408
-10
lines changed

12 files changed

+408
-10
lines changed

.vscode/c_cpp_properties.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"includePath": [
66
"${workspaceFolder}/executor/libs/cppevent-base/src",
77
"${workspaceFolder}/executor/libs/cppevent-net/src",
8-
"${workspaceFolder}/executor/libs/cppevent-fcgi/src"
8+
"${workspaceFolder}/executor/libs/cppevent-fcgi/src",
9+
"${workspaceFolder}/executor/src"
910
],
1011
"defines": [],
1112
"compilerPath": "/usr/bin/gcc",

.vscode/settings.json

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,63 @@
11
{
22
"files.associations": {
3-
"iosfwd": "cpp"
3+
"iosfwd": "cpp",
4+
"string_view": "cpp",
5+
"array": "cpp",
6+
"atomic": "cpp",
7+
"bit": "cpp",
8+
"*.tcc": "cpp",
9+
"cctype": "cpp",
10+
"charconv": "cpp",
11+
"chrono": "cpp",
12+
"clocale": "cpp",
13+
"cmath": "cpp",
14+
"compare": "cpp",
15+
"concepts": "cpp",
16+
"coroutine": "cpp",
17+
"cstdarg": "cpp",
18+
"cstddef": "cpp",
19+
"cstdint": "cpp",
20+
"cstdio": "cpp",
21+
"cstdlib": "cpp",
22+
"cstring": "cpp",
23+
"ctime": "cpp",
24+
"cwchar": "cpp",
25+
"cwctype": "cpp",
26+
"deque": "cpp",
27+
"map": "cpp",
28+
"string": "cpp",
29+
"unordered_map": "cpp",
30+
"vector": "cpp",
31+
"exception": "cpp",
32+
"algorithm": "cpp",
33+
"functional": "cpp",
34+
"iterator": "cpp",
35+
"memory": "cpp",
36+
"memory_resource": "cpp",
37+
"numeric": "cpp",
38+
"optional": "cpp",
39+
"random": "cpp",
40+
"ratio": "cpp",
41+
"system_error": "cpp",
42+
"tuple": "cpp",
43+
"type_traits": "cpp",
44+
"utility": "cpp",
45+
"format": "cpp",
46+
"fstream": "cpp",
47+
"initializer_list": "cpp",
48+
"iomanip": "cpp",
49+
"iostream": "cpp",
50+
"istream": "cpp",
51+
"limits": "cpp",
52+
"new": "cpp",
53+
"numbers": "cpp",
54+
"ostream": "cpp",
55+
"span": "cpp",
56+
"sstream": "cpp",
57+
"stdexcept": "cpp",
58+
"streambuf": "cpp",
59+
"typeinfo": "cpp",
60+
"variant": "cpp"
461
},
562
"cmake.sourceDirectory": "${workspaceFolder}/executor",
663
"cmake.buildDirectory": "${workspaceFolder}/executor/build"

executor/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
build
1+
build
2+
result
3+
executor
4+
code_*

executor/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ add_subdirectory(libs/cppevent-fcgi)
1414

1515
add_executable(executor
1616
src/exec_endpoint.cpp
17+
src/child_process.cpp
18+
src/util.cpp
1719
src/main.cpp
1820
)
1921

executor/shell.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mkShell {
66
];
77

88
shellHook = ''
9-
cd result/bin
9+
cp result/bin/executor executor
1010
./executor
1111
'';
1212

executor/src/child_process.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "child_process.hpp"
2+
3+
#include <cppevent_base/event_loop.hpp>
4+
#include <cppevent_base/event_listener.hpp>
5+
#include <cppevent_base/util.hpp>
6+
7+
#include <sys/syscall.h>
8+
#include <sys/wait.h>
9+
10+
class pid_listener {
11+
private:
12+
cppevent::event_listener* const listener;
13+
public:
14+
pid_listener(cppevent::event_loop& e_loop, int fd): listener(e_loop.get_io_listener(fd)) {
15+
}
16+
17+
~pid_listener() {
18+
listener->detach();
19+
}
20+
21+
cppevent::read_awaiter wait_signal() {
22+
return cppevent::read_awaiter { *listener };
23+
}
24+
};
25+
26+
cppevent::awaitable_task<bool> executor::await_child_process(int pid_fd,
27+
cppevent::event_loop& e_loop) {
28+
pid_listener listener(e_loop, pid_fd);
29+
30+
siginfo_t info = {};
31+
while (waitid(P_PIDFD, pid_fd, &info, WEXITED) == -1) {
32+
if (errno == EAGAIN) {
33+
co_await listener.wait_signal();
34+
continue;
35+
}
36+
cppevent::throw_error("Error waiting for pid");
37+
}
38+
39+
co_return info.si_status == 0;
40+
}

executor/src/child_process.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef EXECUTOR_CHILD_PID_HPP
2+
#define EXECUTOR_CHILD_PID_HPP
3+
4+
#include <cppevent_base/task.hpp>
5+
6+
namespace cppevent {
7+
8+
class event_loop;
9+
10+
}
11+
12+
namespace executor {
13+
14+
cppevent::awaitable_task<bool> await_child_process(int pid_fd, cppevent::event_loop& e_loop);
15+
16+
}
17+
18+
#endif

executor/src/exec_endpoint.cpp

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,117 @@
11
#include "exec_endpoint.hpp"
22

3-
#include <sstream>
3+
#include "util.hpp"
4+
5+
#include <cerrno>
6+
#include <cstring>
7+
#include <cstdlib>
8+
9+
#include <array>
10+
#include <algorithm>
11+
#include <unordered_map>
12+
#include <string_view>
13+
#include <stdexcept>
14+
15+
#include <cppevent_base/util.hpp>
16+
17+
#include <unistd.h>
18+
#include <fcntl.h>
19+
20+
constexpr long BUF_LEN = 1024;
21+
constexpr long MAX_RESPONSE_SIZE = 10 * 1024;
22+
23+
constexpr std::string_view COMPILE_ERR = "compile_err.out";
24+
constexpr std::string_view RUN_STDOUT = "run.out";
25+
26+
executor::exec_endpoint::exec_endpoint(cppevent::event_loop& e_loop): m_loop(e_loop) {
27+
}
28+
29+
cppevent::awaitable_task<void> download(long content_len,
30+
cppevent::stream& s_stdin,
31+
int fd) {
32+
std::array<uint8_t, BUF_LEN> buffer;
33+
while (content_len > 0) {
34+
long download_size = std::min(BUF_LEN, content_len);
35+
co_await s_stdin.read(buffer.data(), download_size, true);
36+
cppevent::throw_if_error(write(fd, buffer.data(), download_size), "Failed to download: ");
37+
content_len -= download_size;
38+
}
39+
}
40+
41+
template <long BUFFER_SIZE>
42+
bool read_to_buffer(std::array<uint8_t, BUFFER_SIZE>& buffer, long& read_size, int fd) {
43+
read_size = read(fd, buffer.data(), BUFFER_SIZE);
44+
return read_size > 0;
45+
}
46+
47+
cppevent::awaitable_task<void> upload(std::string_view dir, std::string_view name,
48+
cppevent::output& o_stdout) {
49+
int fd = executor::open_file(dir, name, O_RDONLY);
50+
std::array<uint8_t, BUF_LEN> buffer;
51+
long response_size = 0;
52+
long read_size;
53+
while (response_size < MAX_RESPONSE_SIZE && read_to_buffer<BUF_LEN>(buffer, read_size, fd)) {
54+
co_await o_stdout.write(buffer.data(), read_size);
55+
response_size += read_size;
56+
}
57+
close(fd);
58+
}
59+
60+
const std::unordered_map<std::string_view, std::string_view> source_file_names = {
61+
{ "cpp", "source.cpp" },
62+
{ "java", "Source.java" },
63+
{ "python", "source.py" }
64+
};
465

566
cppevent::awaitable_task<void> executor::exec_endpoint::process(const cppevent::context& cont,
667
cppevent::stream& s_stdin,
768
cppevent::output& o_stdout) {
869
auto lang_opt = cont.get_path_segment("lang");
970
auto& lang = lang_opt.value();
10-
std::stringstream ss;
11-
ss << "content-length: " << 6 + lang.size() << "\ncontent-type: text/plain\n\n";
12-
ss << "hello " << lang;
13-
co_await o_stdout.write(ss.str());
71+
long content_len = cont.get_content_len();
72+
auto it = source_file_names.find(lang);
73+
if (it == source_file_names.end() || content_len == 0) {
74+
co_await o_stdout.write("status: 400\ncontent-length: 16\n\nunknown language");
75+
co_return;
76+
}
77+
char dir_name[12];
78+
strcpy(dir_name, "code_XXXXXX");
79+
if (mkdtemp(dir_name) == NULL) {
80+
co_await o_stdout.write("status: 500\ncontent-type: text/plain\n\n");
81+
co_await o_stdout.write(strerror(errno));
82+
co_return;
83+
}
84+
85+
const std::string_view& source_file_name = it->second;
86+
const int source_fd = open_file(dir_name, source_file_name, O_WRONLY | O_CREAT);
87+
co_await download(content_len, s_stdin, source_fd);
88+
close(source_fd);
89+
90+
const int compile_err_fd = open_file(dir_name, COMPILE_ERR, O_WRONLY | O_CREAT);
91+
bool compiled_success = co_await await_compile(compile_err_fd, m_loop, dir_name, lang);
92+
close(compile_err_fd);
93+
94+
if (!compiled_success) {
95+
co_await o_stdout.write("status: 200\nx-exec-status: compile_error\ncontent-type: text/plain\n\n");
96+
co_await upload(dir_name, COMPILE_ERR, o_stdout);
97+
co_return;
98+
}
99+
100+
const int run_out_fd = open_file(dir_name, RUN_STDOUT, O_WRONLY | O_CREAT);
101+
CODE_EXEC_STATUS run_status = co_await await_run(run_out_fd, m_loop, dir_name, lang);
102+
close(run_out_fd);
103+
104+
switch (run_status) {
105+
case CODE_EXEC_STATUS::RUN_ERROR:
106+
co_await o_stdout.write("status: 200\nx-exec-status: run_error\ncontent-type: text/plain\n\n");
107+
break;
108+
case CODE_EXEC_STATUS::RUN_TIMEOUT:
109+
co_await o_stdout.write("status: 200\nx-exec-status: timeout\ncontent-type: text/plain\n\n");
110+
break;
111+
case CODE_EXEC_STATUS::RUN_SUCCESS:
112+
co_await o_stdout.write("status: 200\nx-exec-status: success\ncontent-type: text/plain\n\n");
113+
break;
114+
}
115+
116+
co_await upload(dir_name, RUN_STDOUT, o_stdout);
14117
}

executor/src/exec_endpoint.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@
33

44
#include <cppevent_fcgi/endpoint.hpp>
55

6+
#include <string_view>
7+
8+
namespace cppevent {
9+
10+
class event_loop;
11+
12+
}
13+
614
namespace executor {
715

816
class exec_endpoint : public cppevent::endpoint {
17+
private:
18+
cppevent::event_loop& m_loop;
919
public:
20+
exec_endpoint(cppevent::event_loop& e_loop);
21+
1022
cppevent::awaitable_task<void> process(const cppevent::context& cont,
1123
cppevent::stream& s_stdin,
1224
cppevent::output& o_stdout);

executor/src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
int main() {
1111
cppevent::event_loop e_loop;
1212
cppevent::router routes;
13-
executor::exec_endpoint exec;
13+
executor::exec_endpoint exec(e_loop);
1414
routes.post("/api/v1/execute/{lang}", exec);
1515
cppevent::fcgi_server server("0.0.0.0", "9000", e_loop, routes);
1616
std::cout << "Starting executor service" << std::endl;

0 commit comments

Comments
 (0)