[web] Added an option to show execution time on the front end, and improved server.js
This commit is contained in:
parent
95031f508b
commit
8ecf309791
|
@ -11,6 +11,7 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"ffi-napi": "^4.0.3"
|
"ffi-napi": "^4.0.3",
|
||||||
|
"yargs": "^17.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ascii-art {
|
.ascii-art {
|
||||||
|
@ -400,6 +400,17 @@
|
||||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timing-checkbox {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #abb2bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timing-checkbox input {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -449,8 +460,11 @@ println(x);</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button id="runBtn" onclick="runCode()">Run Code</button>
|
<button id="runBtn" onclick="runCode()">Run</button>
|
||||||
<button id="clearBtn" onclick="clearOutput()">Clear Output</button>
|
<button onclick="clearOutput()">Clear Output</button>
|
||||||
|
<label class="timing-checkbox">
|
||||||
|
<input type="checkbox" id="showTime"> Show execution time
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="examples">
|
<div class="examples">
|
||||||
|
@ -557,6 +571,7 @@ for(var i = 0; i <= 5; i += 1) {
|
||||||
const runBtn = document.getElementById('runBtn');
|
const runBtn = document.getElementById('runBtn');
|
||||||
const output = document.getElementById('output');
|
const output = document.getElementById('output');
|
||||||
const status = document.getElementById('status');
|
const status = document.getElementById('status');
|
||||||
|
const showTime = document.getElementById('showTime').checked;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runBtn.disabled = true;
|
runBtn.disabled = true;
|
||||||
|
@ -567,7 +582,10 @@ for(var i = 0; i <= 5; i += 1) {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ code })
|
body: JSON.stringify({
|
||||||
|
code,
|
||||||
|
showTime
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const ffi = require('ffi-napi');
|
const ffi = require('ffi-napi');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const yargs = require('yargs/yargs');
|
||||||
|
const { hideBin } = require('yargs/helpers');
|
||||||
|
|
||||||
|
// Parse command line arguments
|
||||||
|
const argv = yargs(hideBin(process.argv))
|
||||||
|
.usage('Usage: $0 [options]')
|
||||||
|
.option('verbose', {
|
||||||
|
alias: 'v',
|
||||||
|
type: 'boolean',
|
||||||
|
description: 'Run with verbose logging'
|
||||||
|
})
|
||||||
|
.option('port', {
|
||||||
|
alias: 'p',
|
||||||
|
type: 'number',
|
||||||
|
description: 'Port to run the server on',
|
||||||
|
default: 3000
|
||||||
|
})
|
||||||
|
.option('host', {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Host to run the server on',
|
||||||
|
default: 'localhost'
|
||||||
|
})
|
||||||
|
.help()
|
||||||
|
.alias('help', 'h')
|
||||||
|
.version()
|
||||||
|
.argv;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
@ -10,41 +36,48 @@ app.use(express.static('public'));
|
||||||
const nasalLib = ffi.Library(path.join(__dirname, '../module/libnasal-web'), {
|
const nasalLib = ffi.Library(path.join(__dirname, '../module/libnasal-web'), {
|
||||||
'nasal_init': ['pointer', []],
|
'nasal_init': ['pointer', []],
|
||||||
'nasal_cleanup': ['void', ['pointer']],
|
'nasal_cleanup': ['void', ['pointer']],
|
||||||
'nasal_eval': ['string', ['pointer', 'string']],
|
'nasal_eval': ['string', ['pointer', 'string', 'int']],
|
||||||
'nasal_get_error': ['string', ['pointer']]
|
'nasal_get_error': ['string', ['pointer']]
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/eval', (req, res) => {
|
app.post('/eval', (req, res) => {
|
||||||
const { code } = req.body;
|
const { code, showTime = false } = req.body;
|
||||||
if (!code) {
|
if (!code) {
|
||||||
return res.status(400).json({ error: 'No code provided' });
|
return res.status(400).json({ error: 'No code provided' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argv.verbose) {
|
||||||
|
console.log('Received code evaluation request:', code);
|
||||||
|
console.log('Show time:', showTime);
|
||||||
|
}
|
||||||
|
|
||||||
const ctx = nasalLib.nasal_init();
|
const ctx = nasalLib.nasal_init();
|
||||||
try {
|
try {
|
||||||
const result = nasalLib.nasal_eval(ctx, code);
|
const result = nasalLib.nasal_eval(ctx, code, showTime ? 1 : 0);
|
||||||
const error = nasalLib.nasal_get_error(ctx);
|
const error = nasalLib.nasal_get_error(ctx);
|
||||||
|
|
||||||
// Check if there's an error first
|
if (error && error !== 'null') {
|
||||||
if (error && error !== 'null' && error.trim() !== '') {
|
if (argv.verbose) console.log('Nasal error:', error);
|
||||||
console.log('Nasal error:', error); // For debugging
|
|
||||||
res.json({ error: error });
|
res.json({ error: error });
|
||||||
} else if (result && result.trim() !== '') {
|
} else if (result && result.trim() !== '') {
|
||||||
console.log('Nasal output:', result); // For debugging
|
if (argv.verbose) console.log('Nasal output:', result);
|
||||||
res.json({ result: result });
|
res.json({ result: result });
|
||||||
} else {
|
} else {
|
||||||
|
if (argv.verbose) console.log('No output or error returned');
|
||||||
res.json({ error: 'No output or error returned' });
|
res.json({ error: 'No output or error returned' });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Server error:', err); // For debugging
|
if (argv.verbose) console.error('Server error:', err);
|
||||||
res.status(500).json({ error: err.message });
|
res.status(500).json({ error: err.message });
|
||||||
} finally {
|
} finally {
|
||||||
|
if (argv.verbose) console.log('Cleaning up Nasal context');
|
||||||
nasalLib.nasal_cleanup(ctx);
|
nasalLib.nasal_cleanup(ctx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = argv.port || 3000;
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`Server running on port ${PORT}`);
|
console.log(`Server running on port ${PORT}`);
|
||||||
console.log(`Visit http://localhost:${PORT} to use the Nasal interpreter`);
|
console.log(`Visit http://localhost:${PORT} to use the Nasal interpreter`);
|
||||||
|
if (argv.verbose) console.log('Verbose logging enabled');
|
||||||
});
|
});
|
Loading…
Reference in New Issue