[clean] clean code

This commit is contained in:
Wu Han 2021-01-07 16:44:03 +00:00
parent e0ed0f8f5b
commit a224613c2b
28 changed files with 442 additions and 1416 deletions

View File

@ -1 +1,3 @@
sudo ln -s /mnt/f/COM2014/server/uploads /uploads
docker container run -d -p 80:8080 -v /var/run/docker.sock:/var/run/docker.sock -v /uploads/:/app/uploads/ -v /output/:/app/output/ com2014-server docker container run -d -p 80:8080 -v /var/run/docker.sock:/var/run/docker.sock -v /uploads/:/app/uploads/ -v /output/:/app/output/ com2014-server

View File

@ -1,25 +1,22 @@
version: '3' version: '3'
services: services:
com2014: tsp:
image: com2014-server image: com2014-server
networks: networks:
- traefik-public - traefik-public
deploy: deploy:
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.com2014.rule=Host(`com2014.trustai.uk`)" - "traefik.http.routers.tsp.rule=Host(`tsp.trustai.uk`)"
- "traefik.http.routers.com2014.entrypoints=web" - "traefik.http.routers.tsp.entrypoints=web"
- "traefik.http.services.com2014.loadbalancer.server.port=80" - "traefik.http.services.tsp.loadbalancer.server.port=8080"
# TLS # TLS
- "traefik.http.routers.com2014s.rule=Host(`com2014.trustai.uk`)" - "traefik.http.routers.tsps.rule=Host(`tsp.trustai.uk`)"
- "traefik.http.routers.com2014s.entrypoints=websecure" - "traefik.http.routers.tsps.entrypoints=websecure"
- "traefik.http.routers.com2014s.tls.certresolver=myhttpchallenge" - "traefik.http.routers.tsps.tls.certresolver=myhttpchallenge"
# Redirect # Redirect
- "traefik.http.routers.com2014.middlewares=https_redirect" - "traefik.http.routers.tsp.middlewares=https_redirect"
- "traefik.http.middlewares.https_redirect.redirectscheme.scheme=https" - "traefik.http.middlewares.https_redirect.redirectscheme.scheme=https"
placement:
constraints:
- node.role == worker
networks: networks:
traefik-public: traefik-public:
external: true external: true

1
leaderboard.json.empty Normal file
View File

@ -0,0 +1 @@
{"ulysses16":[],"att48":[],"st70":[],"a280":[],"pcb442":[],"dsj1000":[]}

8
output/.gitignore vendored
View File

@ -1,8 +1,4 @@
# .gitignore sample # Ignore everything in this directory
###################
# Ignore all files in this dir...
* *
# Except this file
# ... except for this one.
!.gitignore !.gitignore

974
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,8 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"express": "^4.16.3", "express": "^4.16.3",
"line-reader": "^0.4.0",
"multer": "^1.3.0", "multer": "^1.3.0",
"node-docker-api": "^1.1.22", "node-docker-api": "^1.1.22",
"readline-sync": "^1.4.10",
"socket.io": "^3.0.4", "socket.io": "^3.0.4",
"strip-ansi": "^6.0.0" "strip-ansi": "^6.0.0"
} }

View File

@ -143,14 +143,14 @@ body::after {
margin-top: 10%; margin-top: 10%;
margin-left: 40%; margin-left: 40%;
width: 80%; width: 80%;
content:url("/static/img/exeter.png"); content:url("/img/exeter.png");
} }
.russell { .russell {
margin-top: 5%; margin-top: 5%;
margin-left: 40%; margin-left: 40%;
width: 80%; width: 80%;
content:url("/static/img/russell.png"); content:url("/img/russell.png");
} }
#main-footer { #main-footer {

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -26,15 +26,15 @@
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/5.1.3/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" /> <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/5.1.3/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/5.1.3/js/fileinput.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/5.1.3/js/fileinput.min.js"></script>
<script src="/static/themes/fas/theme.js" type="text/javascript"></script> <script src="/themes/fas/theme.js" type="text/javascript"></script>
<script src="/static/themes/explorer-fas/theme.js" type="text/javascript"></script> <script src="/themes/explorer-fas/theme.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu+Mono" /> <link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Ubuntu+Mono" />
<!-- My Script --> <!-- My Script -->
<link rel="stylesheet" href="/static/css/style.css"> <link rel="stylesheet" href="/css/style.css">
<script src="/static/js/postrequest.js"></script> <script src="/js/script.js"></script>
<script src="/static/js/getrequest.js"></script> <script src="/js/socket_script.js"></script>
</head> </head>
@ -73,7 +73,7 @@
<div class="row mb-5"> <div class="row mb-5">
<div class="col-12"> <div class="col-12">
<div class="embed-responsive embed-responsive-16by9 box-shadow"> <div class="embed-responsive embed-responsive-16by9 box-shadow">
<iframe class="embed-responsive-item" src="/static/preview.html" allowfullscreen></iframe> <iframe class="embed-responsive-item" src="/preview.html" allowfullscreen></iframe>
</div> </div>
</div> </div>
</div> </div>

236
resources/js/script.js Normal file
View File

@ -0,0 +1,236 @@
$( document ).ready( () => {
// warn the user when leaving
window.onbeforeunload = function(){
return "Make sure to save your graph locally before leaving";
};
$('body').scrollspy({ target: '#main-nav', offset: 130 })
$('#fullpage').fullpage({
// anchors: ['underPage', 'gradPage', 'phdPage'],
sectionsColor: ['#ffffff', '#f8f8f8'],
autoScrolling: false,
css3: true,
fitToSection: false,
afterLoad: function(anchorLink, index) {
// history.pushState(null, null, "");
// console.log(anchorLink);
}
});
// Initialize Console
ConsoleLogHTML.connect(document.getElementById("console")); // Redirect log messages
// ConsoleLogHTML.disconnect(); // Stop redirecting
// Navbar click scroll
$(".navbar a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
var offset = 0;
if (hash === "#home")
{
offset = -100;
}
else {
offset = -60;
}
$('html, body').animate({
scrollTop: ($(hash).offset().top + offset)
}, 1000, function(){
// Add hash (#) to URL when done scrolling (default click behavior)
// window.location.hash = hash;
});
}
});
$('#submission_info').hide();
$('#ulysses16_submit').hide();
$('#att48_submit').hide();
$('#st70_submit').hide();
$('#a280_submit').hide();
$('#pcb442_submit').hide();
$('#dsj1000_submit').hide();
$( "#ulysses16_submit" ).click(function() {
upload_leaderboard('ulysses16');
$('#ulysses16_submit').removeClass('btn-primary');
$('#ulysses16_submit').text('Submitted');
$('#ulysses16_submit').prop('disabled', true);
});
$( "#att48_submit" ).click(function() {
upload_leaderboard('att48');
$('#att48_submit').removeClass('btn-primary');
$('#att48_submit').text('Submitted');
$('#att48_submit').prop('disabled', true);
});
$( "#st70_submit" ).click(function() {
upload_leaderboard('st70');
$('#st70_submit').removeClass('btn-primary');
$('#st70_submit').text('Submitted');
$('#st70_submit').prop('disabled', true);
});
$( "#a280_submit" ).click(function() {
upload_leaderboard('a280');
$('#a280_submit').removeClass('btn-primary');
$('#a280_submit').text('Submitted');
$('#a280_submit').prop('disabled', true);
});
$( "#pcb442_submit" ).click(function() {
upload_leaderboard('pcb442');
$('#pcb442_submit').removeClass('btn-primary');
$('#pcb442_submit').text('Submitted');
$('#pcb442_submit').prop('disabled', true);
});
$( "#dsj1000_submit" ).click(function() {
upload_leaderboard('dsj1000');
$('#dsj1000_submit').removeClass('btn-primary');
$('#dsj1000_submit').text('Submitted');
$('#dsj1000_submit').prop('disabled', true);
});
// Initialize file uploader
// initialize with defaults
// $("#uploadfile").fileinput();
// with plugin options
$("#uploadfile").fileinput({
// theme: "fa",
'theme': 'fas',
showUpload:false,
previewFileType:'py',
maxFileCount: 1,
allowedFileExtensions: ["py"]
});
var url = window.location;
// GET REQUEST
$("#btnGetFiles").click( (event) => {
event.preventDefault();
ajaxGet();
});
// DO GET
function ajaxGet(){
$.ajax({
type : "GET",
url : "/api/files/getall",
success: (data) => {
// clear old data
$("#listFiles").html("");
// render list of files
$("#listFiles").append('<ul>');
$.each(data, (index, filename) => {
$("#listFiles").append('<li><a href=' + url + 'api/files/' + filename +'>' + filename + '</a></li>');
});
$("#listFiles").append('</ul>');
},
error : (err) => {
$("#listFiles").html(err.responseText);
}
});
}
// Upload File
$('#uploadfile').change(function(e){
if(e.target.files[0])
{
var fileName = e.target.files[0].name;
if(fileName !== "my_model.py")
{
alert('Please upload my_model.py');
$('#btnSubmit').prop('disabled', true);
}
else
{
$('#btnSubmit').prop('disabled', false);
}
}
});
// Submit results
$("#btnSubmit").click((event) => {
// stop submit the form, we will post it manually.
event.preventDefault();
doAjax();
});
})
function upload_leaderboard(name) {
obj = {}
obj.name = name;
data = {}
if(name === 'ulysses16') {
data.fitness = my_res.ulysses16.fitness;
}
else if (name === 'att48') {
data.fitness = my_res.att48.fitness;
}
else if (name === 'st70') {
data.fitness = my_res.st70.fitness;
}
else if (name === 'a280') {
data.fitness = my_res.a280.fitness;
}
else if (name === 'pcb442') {
data.fitness = my_res.pcb442.fitness;
}
else if (name === 'dsj1000') {
data.fitness = my_res.dsj1000.fitness;
}
data.name = $('#submit_name').val();
data.desc = $('#submit_desc').val()
data.time = Date.now()
obj.data = data;
socket.emit('submit', obj);
}
function doAjax() {
// Get form
var form = $('#fileUploadForm')[0];
var data = new FormData(form);
var file = data.get('uploadfile');
var renameFile =new File([file], window.id + '.py' ,{type:file.type});
var formdata = new FormData();
formdata.append('uploadfile', renameFile);
if(window.id) {
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/api/files/upload",
data: formdata,
processData: false, //prevent jQuery from automatically transforming the data into a query string
contentType: false,
cache: false,
success: (data) => {
console.log('Emit build request')
socket.emit('build', {});
},
error: (e) => {
$("#listFiles").text(e.responseText);
}
});
}
else
{
alert('Failed to connect to server');
}
}

View File

@ -1,7 +1,3 @@
// warn the user when leaving
window.onbeforeunload = function(){
return "Make sure to save your graph locally before leaving";
};
var my_res = {}; var my_res = {};
my_res.ulysses16 = {} my_res.ulysses16 = {}
@ -20,28 +16,32 @@ my_res.dsj1000.fitness = -1;
var socket = io(); var socket = io();
// User connected
socket.on('connect', () => { socket.on('connect', () => {
$("#status").removeClass('badge-secondary'); $("#status").removeClass('badge-secondary');
$("#status").addClass('badge-primary'); $("#status").addClass('badge-primary');
window.id = socket.id window.id = socket.id
console.log('Session Id: ', socket.id); // an alphanumeric id... console.log('Session Id: ', socket.id);
}); });
// User disconnected
socket.on('disconnect', () => { socket.on('disconnect', () => {
$("#status").removeClass('badge-primary'); $("#status").removeClass('badge-primary');
$("#status").addClass('badge-secondary'); $("#status").addClass('badge-secondary');
$("#status").text('offline'); $("#status").text('offline');
}); });
// Update online users
socket.on('users_count', (clients) => { socket.on('users_count', (clients) => {
$("#status").text(clients + ' online'); $("#status").text(clients + ' online');
}); });
// Server running algorithms
socket.on('start', () => { socket.on('start', () => {
console.log('Building start'); console.log('Building start');
}); });
// Update Leaderboard Table
socket.on('leaderboard', (obj) => { socket.on('leaderboard', (obj) => {
console.log(obj); console.log(obj);
$(".leaderboard-table").find("tr:not(:first):not(:last)").remove(); $(".leaderboard-table").find("tr:not(:first):not(:last)").remove();
@ -88,7 +88,8 @@ socket.on('leaderboard', (obj) => {
}); });
socket.on('update', (msg) => { // Log info in console
socket.on('info', (msg) => {
// var msg = msg.replace(/\x1b[[0-9;]*[a-zA-Z]/g, ''); // var msg = msg.replace(/\x1b[[0-9;]*[a-zA-Z]/g, '');
msg = msg.replace(/[^\x20-\x7E]/g, '') msg = msg.replace(/[^\x20-\x7E]/g, '')
if(msg[1] == '[') { if(msg[1] == '[') {
@ -97,130 +98,52 @@ socket.on('update', (msg) => {
console.log(msg); console.log(msg);
}); });
// Update personal result
socket.on('result', (res) => { socket.on('result', (res) => {
// console.log(res)
res = JSON.parse(res); res = JSON.parse(res);
$('#submission_info').show(); $('#submission_info').show();
res.forEach(e => { res.forEach(e => {
if(e.name === "ulysses16.txt") { if(e.name === "ulysses16.txt") {
my_res.ulysses16.fitness = e.fitness my_res.ulysses16.fitness = e.fitness
$("#ulysses16_your").text(e.fitness); $("#ulysses16_your").text(e.fitness);
if(e.fitness > 0) {
$('#ulysses16_submit').show(); $('#ulysses16_submit').show();
} }
}
if(e.name === "att48.txt") { if(e.name === "att48.txt") {
my_res.att48.fitness = e.fitness my_res.att48.fitness = e.fitness
$("#att48_your").text(e.fitness); $("#att48_your").text(e.fitness);
if(e.fitness > 0) {
$('#att48_submit').show(); $('#att48_submit').show();
} }
}
if(e.name === "st70.txt") { if(e.name === "st70.txt") {
my_res.st70.fitness = e.fitness my_res.st70.fitness = e.fitness
$("#st70_your").text(e.fitness) $("#st70_your").text(e.fitness)
if(e.fitness > 0) {
$('#st70_submit').show(); $('#st70_submit').show();
} }
}
if(e.name === "a280.txt") { if(e.name === "a280.txt") {
my_res.a280.fitness = e.fitness my_res.a280.fitness = e.fitness
$("#a280_your").text(e.fitness) $("#a280_your").text(e.fitness)
if(e.fitness > 0) {
$('#a280_submit').show(); $('#a280_submit').show();
} }
}
if(e.name === "pcb442.txt") { if(e.name === "pcb442.txt") {
my_res.pcb442.fitness = e.fitness my_res.pcb442.fitness = e.fitness
$("#pcb442_your").text(e.fitness) $("#pcb442_your").text(e.fitness)
if(e.fitness > 0) {
$('#pcb442_submit').show(); $('#pcb442_submit').show();
} }
}
if(e.name === "dsj1000.txt") { if(e.name === "dsj1000.txt") {
my_res.dsj1000.fitness = e.fitness my_res.dsj1000.fitness = e.fitness
$("#dsj1000_your").text(e.fitness) $("#dsj1000_your").text(e.fitness)
if(e.fitness > 0) {
$('#dsj1000_submit').show(); $('#dsj1000_submit').show();
} }
});
});
$(document).ready( () => {
$("#btnSubmit").click((event) => {
//stop submit the form, we will post it manually.
event.preventDefault();
doAjax();
});
$('#uploadfile').change(function(e){
if(e.target.files[0])
{
var fileName = e.target.files[0].name;
if(fileName !== "my_model.py")
{
alert('Please upload my_model.py');
$('#btnSubmit').prop('disabled', true);
}
else
{
$('#btnSubmit').prop('disabled', false);
}
} }
}); });
}); });
function upload_loaderboard(name) {
obj = {}
obj.name = name;
data = {}
if(name === 'ulysses16') {
data.fitness = my_res.ulysses16.fitness;
}
else if (name === 'att48') {
data.fitness = my_res.att48.fitness;
}
else if (name === 'st70') {
data.fitness = my_res.st70.fitness;
}
else if (name === 'a280') {
data.fitness = my_res.a280.fitness;
}
else if (name === 'pcb442') {
data.fitness = my_res.pcb442.fitness;
}
else if (name === 'dsj1000') {
data.fitness = my_res.dsj1000.fitness;
}
data.name = $('#submit_name').val();
data.desc = $('#submit_desc').val()
data.time = Date.now()
obj.data = data;
socket.emit('submit', obj);
}
function doAjax() {
// Get form
var form = $('#fileUploadForm')[0];
var data = new FormData(form);
var file = data.get('uploadfile');
var renameFile =new File([file], window.id + '.py' ,{type:file.type});
var formdata = new FormData();
formdata.append('uploadfile', renameFile);
// console.log(formdata.get('uploadfile'))
if(window.id) {
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/api/files/upload",
data: formdata,
processData: false, //prevent jQuery from automatically transforming the data into a query string
contentType: false,
cache: false,
success: (data) => {
// $("#listFiles").text(data);
console.log('Emit build request')
socket.emit('build', {});
},
error: (e) => {
$("#listFiles").text(e.responseText);
}
});
}
else
{
alert('Failed to connect to server');
}
}

View File

@ -1,26 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<title>Document</title>
</head>
<body>
<div class="container">
<h1>Hello</h1>
<div class="ratio ratio-16x9">
<iframe src="preview.html" title="YouTube video" allowfullscreen></iframe>
</div>
</div>
<section>
<div class="container">
<div class="row">
<h1>Leader</h1>
<label for="formFileLg" class="form-label">Large file input example</label>
<input class="form-control form-control-lg" id="formFileLg" type="file" />
</div>
</div>
</section>
</body>
</html>

View File

@ -1,142 +0,0 @@
$( document ).ready( () => {
$('body').scrollspy({ target: '#main-nav', offset: 130 })
$('#fullpage').fullpage({
// anchors: ['underPage', 'gradPage', 'phdPage'],
sectionsColor: ['#ffffff', '#f8f8f8'],
autoScrolling: false,
css3: true,
fitToSection: false,
afterLoad: function(anchorLink, index) {
// history.pushState(null, null, "");
// console.log(anchorLink);
}
});
$(".navbar a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
var offset = 0;
if (hash === "#home")
{
offset = -100;
}
else {
offset = -60;
}
$('html, body').animate({
scrollTop: ($(hash).offset().top + offset)
}, 1000, function(){
// Add hash (#) to URL when done scrolling (default click behavior)
// window.location.hash = hash;
});
}
});
$('#submission_info').hide();
$('#ulysses16_submit').hide();
$('#att48_submit').hide();
$('#st70_submit').hide();
$('#a280_submit').hide();
$('#pcb442_submit').hide();
$('#dsj1000_submit').hide();
$( "#ulysses16_submit" ).click(function() {
upload_loaderboard('ulysses16');
$('#ulysses16_submit').removeClass('btn-primary');
$('#ulysses16_submit').text('Submitted');
$('#ulysses16_submit').prop('disabled', true);
});
$( "#att48_submit" ).click(function() {
upload_loaderboard('att48');
$('#att48_submit').removeClass('btn-primary');
$('#att48_submit').text('Submitted');
$('#att48_submit').prop('disabled', true);
});
$( "#st70_submit" ).click(function() {
upload_loaderboard('st70');
$('#st70_submit').removeClass('btn-primary');
$('#st70_submit').text('Submitted');
$('#st70_submit').prop('disabled', true);
});
$( "#a280_submit" ).click(function() {
upload_loaderboard('a280');
$('#a280_submit').removeClass('btn-primary');
$('#a280_submit').text('Submitted');
$('#a280_submit').prop('disabled', true);
});
$( "#pcb442_submit" ).click(function() {
upload_loaderboard('pcb442');
$('#pcb442_submit').removeClass('btn-primary');
$('#pcb442_submit').text('Submitted');
$('#pcb442_submit').prop('disabled', true);
});
$( "#dsj1000_submit" ).click(function() {
upload_loaderboard('dsj1000');
$('#dsj1000_submit').removeClass('btn-primary');
$('#dsj1000_submit').text('Submitted');
$('#dsj1000_submit').prop('disabled', true);
});
// initialize with defaults
// $("#uploadfile").fileinput();
// with plugin options
$("#uploadfile").fileinput({
// theme: "fa",
'theme': 'fas',
showUpload:false,
previewFileType:'py',
maxFileCount: 1,
allowedFileExtensions: ["py"]
});
ConsoleLogHTML.connect(document.getElementById("console")); // Redirect log messages
// ConsoleLogHTML.disconnect(); // Stop redirecting
var url = window.location;
// GET REQUEST
$("#btnGetFiles").click( (event) => {
event.preventDefault();
ajaxGet();
});
// DO GET
function ajaxGet(){
$.ajax({
type : "GET",
url : "/api/files/getall",
success: (data) => {
//clear old data
$("#listFiles").html("");
/*
render list of files
*/
$("#listFiles").append('<ul>');
$.each(data, (index, filename) => {
$("#listFiles").append('<li><a href=' + url + 'api/files/' + filename +'>' + filename + '</a></li>');
});
$("#listFiles").append('</ul>');
},
error : (err) => {
$("#listFiles").html(err.responseText);
}
});
}
})

View File

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

219
server.js
View File

@ -1,28 +1,32 @@
const fs = require('fs') const fs = require('fs')
// Web Server
var express = require('express') var express = require('express')
var app = express() var app = express()
var router = express.Router() var router = express.Router()
// Upload Files
var upload = require('./app/config/multer.config.js') var upload = require('./app/config/multer.config.js')
const {Docker} = require('node-docker-api') // Static Website
const { time } = require('console')
const lineReader = require('line-reader');
const docker = new Docker({ socketPath: '/var/run/docker.sock' })
const stripAnsi = require('strip-ansi');
global.__basedir = __dirname
app.use(express.static('resources')) app.use(express.static('resources'))
var http = require('http').createServer(app) var http = require('http').createServer(app)
var io = require('socket.io')(http) var io = require('socket.io')(http)
var readlineSync = require('readline-sync'); // Docker Container
const {Docker} = require('node-docker-api')
const docker = new Docker({ socketPath: '/var/run/docker.sock' })
const path = require('path'); // Console Log
const stripAnsi = require('strip-ansi')
// Set up directories
global.__basedir = __dirname
const path = require('path')
current_path = process.cwd() current_path = process.cwd()
// Initialize Leaderboard
var leaderboard = {} var leaderboard = {}
leaderboard.ulysses16 = [] leaderboard.ulysses16 = []
leaderboard.att48 = [] leaderboard.att48 = []
@ -31,7 +35,31 @@ leaderboard.a280 = []
leaderboard.pcb442 = [] leaderboard.pcb442 = []
leaderboard.dsj1000 = [] leaderboard.dsj1000 = []
var write_leaderboard = () => {
fs.writeFile('leaderboard.json', JSON.stringify(leaderboard), (err) => {
if (err) throw err
console.log('Data written to file')
})
}
// Read from JSON file first if exists
try {
if (fs.existsSync('leaderboard.json')) {
//file exists
console.log("Existed leaderboard")
leaderboard = require('./leaderboard.json')
console.log(leaderboard)
}
else {
write_leaderboard()
}
}
catch(err) {
console.error(err)
}
var update_leaderboard = (obj) => { var update_leaderboard = (obj) => {
// Update each TSP entry
if(obj.name === 'ulysses16') { if(obj.name === 'ulysses16') {
leaderboard.ulysses16.push(obj.data) leaderboard.ulysses16.push(obj.data)
} }
@ -50,6 +78,8 @@ var update_leaderboard = (obj) => {
else if (obj.name === 'dsj1000') { else if (obj.name === 'dsj1000') {
leaderboard.dsj1000.push(obj.data) leaderboard.dsj1000.push(obj.data)
} }
// Only accept top 10 results
leaderboard.ulysses16.sort(function(a, b){return a.fitness - b.fitness}) leaderboard.ulysses16.sort(function(a, b){return a.fitness - b.fitness})
leaderboard.ulysses16 = leaderboard.ulysses16.slice(0,10) leaderboard.ulysses16 = leaderboard.ulysses16.slice(0,10)
@ -68,69 +98,45 @@ var update_leaderboard = (obj) => {
leaderboard.dsj1000.sort(function(a, b){return a.fitness - b.fitness}) leaderboard.dsj1000.sort(function(a, b){return a.fitness - b.fitness})
leaderboard.dsj1000 = leaderboard.dsj1000.slice(0,10) leaderboard.dsj1000 = leaderboard.dsj1000.slice(0,10)
// Write to json file
write_leaderboard() write_leaderboard()
} }
var write_leaderboard = () => { // Get submission results
fs.writeFile('leaderboard.json', JSON.stringify(leaderboard), (err) => {
if (err) throw err;
console.log('Data written to file');
});
}
try {
if (fs.existsSync('leaderboard.json')) {
//file exists
leaderboard = require('./leaderboard.json');
console.log(leaderboard);
}
else {
write_leaderboard();
}
}
catch(err) {
console.error(err)
}
var res = [];
var update_submission = (socket, sessionID) => { var update_submission = (socket, sessionID) => {
console.log('check result')
var output_dir = current_path.toString() + '/output/' + sessionID + '/' var output_dir = current_path.toString() + '/output/' + sessionID + '/'
console.log(output_dir) console.log(output_dir)
if (output_dir.length != 0) if (output_dir.length != 0)
{ {
res = [] var res = []
socket.emit('update', 'Got output') socket.emit('info', 'Got output')
// Read output dir
fs.readdir(output_dir, (err, files) => { fs.readdir(output_dir, (err, files) => {
if (err) { if (err) {
console.log(err); console.log(err)
return; return
} }
console.log('iterate')
// Read each result in txt file
files.forEach(file => { files.forEach(file => {
console.log(file)
console.log(path.extname(file))
if (path.extname(file) === '.txt') { if (path.extname(file) === '.txt') {
var i = 0 var i = 0
// Result object
var obj = {} var obj = {}
obj.name = file obj.name = file
console.log(output_dir + file)
try { try {
// read contents of the file // read contents of the file
const data = fs.readFileSync(output_dir + file, 'UTF-8'); const data = fs.readFileSync(output_dir + file, 'UTF-8')
// split the contents by new line // split the contents by new line
const lines = data.split(/\r?\n/); const lines = data.split(/\r?\n/)
// print all lines
lines.forEach((line) => { lines.forEach((line) => {
console.log(line)
i = i + 1 i = i + 1
// console.log(line) // The first line is the fitness
if(i == 1) { if(i == 1) {
var fitness = parseFloat(line) var fitness = parseFloat(line)
if(fitness < 0) { if(fitness < 0) {
@ -140,11 +146,13 @@ var update_submission = (socket, sessionID) => {
obj.fitness = fitness obj.fitness = fitness
} }
} }
// The second line is the path
else if (i == 2) { else if (i == 2) {
// Only read when there is no error
if(obj.fitness > 0) { if(obj.fitness > 0) {
solution_array = line.split(","); solution_array = line.split(",")
for(var j = 0; j < solution_array.length; j++) { for(var j = 0; j < solution_array.length; j++) {
solution_array[i] = parseInt(solution_array[i], 10); solution_array[i] = parseInt(solution_array[i], 10)
} }
obj.solution = solution_array obj.solution = solution_array
} }
@ -152,21 +160,20 @@ var update_submission = (socket, sessionID) => {
obj.solution = [] obj.solution = []
} }
} }
}); })
} catch (err) { } catch (err) {
console.error(err); console.error(err)
} }
res.push(obj) res.push(obj)
} }
}); })
// console.log(res)
socket.emit('result', JSON.stringify(res)) socket.emit('result', JSON.stringify(res))
}); })
} }
else { else {
console.log('no result') console.log('no result')
} }
}; }
var docker_build = (socket, sessionID) => { var docker_build = (socket, sessionID) => {
@ -174,41 +181,10 @@ var docker_build = (socket, sessionID) => {
socket.emit('start') socket.emit('start')
fs.mkdir(current_path + '/output/' + sessionID.toString(), () => { fs.mkdir(current_path + '/output/' + sessionID.toString(), () => {
socket.emit('update', 'Output directort created.') socket.emit('info', 'Output directort created.')
socket.emit('update', 'Test started, this may take a while.') socket.emit('info', 'Test started, this may take a while.')
}) })
{
if (fs.existsSync(current_path.toString() + '/uploads/' + sessionID.toString() + '/requirements.txt'))
{
//file exists
docker.container.create({
Image: 'com2014-tsp',
HostConfig: {
Binds: [
'/uploads/' + sessionID.toString() + '/requirements.txt:/tsp/requirements.txt',
'/uploads/' + sessionID.toString() + '/my_model.py:/tsp/model/my_model.py',
"/output/" + sessionID.toString() + "/:/output/"
]
}
})
.then( (container) => {
container_id = container.data.Id
socket.emit('update','Container Id: ' + container_id)
return container.start()
})
.then(container => container.logs({
follow: true,
stdout: true,
stderr: true
}))
.then(stream => {
stream.on('data', info => socket.emit('update', new Buffer.from(info).toString('ascii')))
stream.on('error', err => console.log(err))
})
.catch(error => console.log(error))
}
else
{
docker.container.create({ docker.container.create({
Image: 'com2014-tsp', Image: 'com2014-tsp',
HostConfig: { HostConfig: {
@ -219,8 +195,9 @@ var docker_build = (socket, sessionID) => {
} }
}) })
.then( (container) => { .then( (container) => {
// Start container
container_id = container.data.Id container_id = container.data.Id
socket.emit('update','Container Id: ' + container_id) socket.emit('info','Container Id: ' + container_id)
return container.start() return container.start()
}) })
.then(container => container.logs({ .then(container => container.logs({
@ -229,76 +206,92 @@ var docker_build = (socket, sessionID) => {
stderr: true stderr: true
})) }))
.then(stream => { .then(stream => {
// Write container logs to client
stream.on('data', (info) => { stream.on('data', (info) => {
console.log(stripAnsi(new Buffer.from(info).toString())) console.log(stripAnsi(new Buffer.from(info).toString()))
socket.emit('update', stripAnsi(new Buffer.from(info).toString('ascii'))) socket.emit('info', stripAnsi(new Buffer.from(info).toString('ascii')))
}), }),
stream.on('error', err => console.log(err)) stream.on('error', (err) => {
console.log(err)
socket.emit('info', stripAnsi(new Buffer.from(err).toString('ascii')))
})
}) })
.catch(error => console.log(error)) .catch(error => console.log(error))
}
var intervalObj; // Check if container is still running
var timeoutObj; var intervalObj
// Timeout (each container runs only for 60s at most)
var timeoutObj
var finished = false
// Check if container is still running
intervalObj = setInterval(() => { intervalObj = setInterval(() => {
if(!finished) if(!finished)
{ {
docker.container.list({all:true}) docker.container.list({all:true})
// Inspect
.then((containers) => { .then((containers) => {
containers.forEach(container => { containers.forEach(container => {
if(container.data.Id == container_id) { if(container.data.Id == container_id) {
socket.emit('update', 'Container Status: ' + container.data.State) socket.emit('info', 'Container Status: ' + container.data.State)
if(container.data.State === 'exited') if(container.data.State === 'exited')
{ {
finished = true; // Finished Running
clearInterval(intervalObj); finished = true
clearTimeout(timeoutObj); clearInterval(intervalObj)
socket.emit('update', 'Test end') clearTimeout(timeoutObj)
update_submission(socket, sessionID); socket.emit('info', 'Container exited')
// Get submission results
update_submission(socket, sessionID)
} }
} }
}); })
}) })
.catch(error => console.log(error)) .catch(error => console.log(error))
} }
}, 2000); }, 2000)
var finished = false // Timeout (each container runs only for 60s at most)
// call the rest of the code and have it execute after 3 seconds
timeoutObj = setTimeout(() => { timeoutObj = setTimeout(() => {
console.log('end') console.log('end')
if(!finished) if(!finished)
{ {
clearInterval(intervalObj); clearInterval(intervalObj)
socket.emit('update', 'timeout') socket.emit('info', 'timeout')
}
}, 20000)
} }
}, 60000)
} }
var clients = 0 var clients = 0
io.on('connection', (socket) => { io.on('connection', (socket) => {
// New client connected
const sessionID = socket.id const sessionID = socket.id
console.log('[client][connection]', sessionID) console.log('[client][connection]', sessionID)
// Update client number
clients = clients + 1 clients = clients + 1
io.sockets.emit('users_count', clients) io.sockets.emit('users_count', clients)
console.log(leaderboard)
// Inform new client the leaderboard
// console.log(leaderboard)
socket.emit('leaderboard', leaderboard) socket.emit('leaderboard', leaderboard)
// Client disconnected
socket.on('disconnect', () => { socket.on('disconnect', () => {
clients = clients - 1 clients = clients - 1
console.log('[client][disconnect]', sessionID) console.log('[client][disconnect]', sessionID)
io.sockets.emit('users_count', clients) io.sockets.emit('users_count', clients)
}) })
// Client request a build
socket.on('build', () => { socket.on('build', () => {
console.log('[client][build]', sessionID) console.log('[client][build]', sessionID)
docker_build(socket, sessionID) docker_build(socket, sessionID)
}) })
// Client submited a new result
socket.on('submit', (obj) => { socket.on('submit', (obj) => {
console.log('[client][submit]', sessionID) console.log('[client][submit]', sessionID)
update_leaderboard(obj) update_leaderboard(obj)