Initial YakPanel commit
This commit is contained in:
87
YakPanel/static/build/addons/zmodem/demo/app.js
Normal file
87
YakPanel/static/build/addons/zmodem/demo/app.js
Normal file
@@ -0,0 +1,87 @@
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var expressWs = require('express-ws')(app);
|
||||
var os = require('os');
|
||||
var pty = require('node-pty');
|
||||
|
||||
var terminals = {},
|
||||
logs = {};
|
||||
|
||||
app.use('/build', express.static(__dirname + '/../../../../build'));
|
||||
app.use('/demo', express.static(__dirname + '/../../../../demo'));
|
||||
app.use('/zmodemjs', express.static(__dirname + '/../../../../node_modules/zmodem.js/dist'));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.sendFile(__dirname + '/index.html');
|
||||
});
|
||||
|
||||
app.get('/style.css', function(req, res){
|
||||
res.sendFile(__dirname + '/style.css');
|
||||
});
|
||||
|
||||
app.get('/main.js', function(req, res){
|
||||
res.sendFile(__dirname + '/main.js');
|
||||
});
|
||||
|
||||
app.post('/terminals', function (req, res) {
|
||||
var cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
encoding: null,
|
||||
name: 'xterm-color',
|
||||
cols: cols || 80,
|
||||
rows: rows || 24,
|
||||
cwd: process.env.PWD,
|
||||
env: process.env
|
||||
});
|
||||
|
||||
console.log('Created terminal with PID: ' + term.pid);
|
||||
terminals[term.pid] = term;
|
||||
logs[term.pid] = '';
|
||||
term.on('data', function(data) {
|
||||
logs[term.pid] += data;
|
||||
});
|
||||
res.send(term.pid.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.post('/terminals/:pid/size', function (req, res) {
|
||||
var pid = parseInt(req.params.pid),
|
||||
cols = parseInt(req.query.cols),
|
||||
rows = parseInt(req.query.rows),
|
||||
term = terminals[pid];
|
||||
|
||||
term.resize(cols, rows);
|
||||
console.log('Resized terminal ' + pid + ' to ' + cols + ' cols and ' + rows + ' rows.');
|
||||
res.end();
|
||||
});
|
||||
|
||||
app.ws('/terminals/:pid', function (ws, req) {
|
||||
var term = terminals[parseInt(req.params.pid)];
|
||||
console.log('Connected to terminal ' + term.pid);
|
||||
ws.send(logs[term.pid]);
|
||||
|
||||
term.on('data', function(data) {
|
||||
try {
|
||||
ws.send(data);
|
||||
} catch (ex) {
|
||||
// The WebSocket is not open, ignore
|
||||
}
|
||||
});
|
||||
ws.on('message', function(msg) {
|
||||
term.write(msg);
|
||||
});
|
||||
ws.on('close', function () {
|
||||
term.kill();
|
||||
console.log('Closed terminal ' + term.pid);
|
||||
// Clean things up
|
||||
delete terminals[term.pid];
|
||||
delete logs[term.pid];
|
||||
});
|
||||
});
|
||||
|
||||
var port = process.env.PORT || 3000,
|
||||
host = os.platform() === 'win32' ? '127.0.0.1' : '0.0.0.0';
|
||||
|
||||
console.log('App listening to http://' + host + ':' + port);
|
||||
app.listen(port, host);
|
||||
128
YakPanel/static/build/addons/zmodem/demo/index.html
Normal file
128
YakPanel/static/build/addons/zmodem/demo/index.html
Normal file
@@ -0,0 +1,128 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>xterm.js demo</title>
|
||||
<link rel="stylesheet" href="/build/xterm.css" />
|
||||
<link rel="stylesheet" href="/build/addons/fullscreen/fullscreen.css" />
|
||||
<link rel="stylesheet" href="/demo/style.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
|
||||
<script src="/build/xterm.js" ></script>
|
||||
|
||||
<script src="/build/addons/attach/attach.js" ></script>
|
||||
<script src="/zmodemjs/zmodem.js"></script>
|
||||
<script src="/build/addons/zmodem/zmodem.js" ></script>
|
||||
|
||||
<script src="/build/addons/fit/fit.js" ></script>
|
||||
<script src="/build/addons/fullscreen/fullscreen.js" ></script>
|
||||
<script src="/build/addons/search/search.js" ></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>xterm.js: xterm, in the browser</h1>
|
||||
|
||||
<div id="terminal-container"></div>
|
||||
|
||||
<div id="zmodem_controls">
|
||||
<form id="zm_start" style="display: none" action="javascript:void(0)">
|
||||
ZMODEM detected: Start ZMODEM session?
|
||||
<label><input id="zmstart_yes" name="zmstart" type=radio checked value="1"> Yes</label>
|
||||
|
||||
<label><input name="zmstart" type=radio value=""> No</label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<form id="zm_offer" style="display: none" action="javascript:void(0)">
|
||||
<p>ZMODEM File offered!</p>
|
||||
|
||||
<label><input id="zmaccept_yes" name="zmaccept" type=radio checked value="1"> Accept</label>
|
||||
|
||||
<label><input name="zmaccept" type=radio value=""> Skip</label>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<div id="zm_file" style="display: none">
|
||||
<div>Name: <span id="name"></span></div>
|
||||
<div>Size: <span id="size"></span></div>
|
||||
<div>Last modified: <span id="mtime"></span></div>
|
||||
<div>Mode: <span id="mode"></span></div>
|
||||
<br>
|
||||
<div>Conversion: <span id="zfile_conversion"></span></div>
|
||||
<div>Management: <span id="zfile_management"></span></div>
|
||||
<div>Transport: <span id="zfile_transport"></span></div>
|
||||
<div>Sparse? <span id="zfile_sparse"></span></div>
|
||||
<br>
|
||||
<div>Files remaining in batch: <span id="files_remaining"></span></div>
|
||||
<div>Bytes remaining in batch: <span id="bytes_remaining"></span></div>
|
||||
</div>
|
||||
|
||||
<form id="zm_progress" style="display: none" action="javascript:void(0)">
|
||||
<div><span id="percent_received"></span>% (<span id="bytes_received"></span> bytes) received</div>
|
||||
<button id="zm_progress_skipper" type="button" onclick="skip_current_file();">Skip File</button>
|
||||
</form>
|
||||
|
||||
<form id="zm_choose" style="display: none" action="javascript:void(0)">
|
||||
<label>Choose file(s): <input id="zm_files" type="file" multiple></label>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Actions</h2>
|
||||
<p>
|
||||
<label>Find next <input id="find-next"/></label>
|
||||
<label>Find previous <input id="find-previous"/></label>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Options</h2>
|
||||
<p>
|
||||
<label><input type="checkbox" id="option-cursor-blink"> cursorBlink</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" checked id="zmodem-auto"> Accept all ZMODEM prompts<sup>*</sup></label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
cursorStyle
|
||||
<select id="option-cursor-style">
|
||||
<option value="block">block</option>
|
||||
<option value="underline">underline</option>
|
||||
<option value="bar">bar</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
bellStyle
|
||||
<select id="option-bell-style">
|
||||
<option value="">none</option>
|
||||
<option value="sound">sound</option>
|
||||
<option value="visual">visual</option>
|
||||
<option value="both">both</option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>scrollback <input type="number" id="option-scrollback" value="1000" /></label>
|
||||
</p>
|
||||
<p>
|
||||
<label>tabStopWidth <input type="number" id="option-tabstopwidth" value="8" /></label>
|
||||
</p>
|
||||
<div>
|
||||
<h3>Size</h3>
|
||||
<div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="cols">Columns</label>
|
||||
<input type="number" id="cols" />
|
||||
</div>
|
||||
<div style="display: inline-block; margin-right: 16px;">
|
||||
<label for="rows">Rows</label>
|
||||
<input type="number" id="rows" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p><strong>Attention:</strong> The demo is a barebones implementation and is designed for xterm.js evaluation purposes only. Exposing the demo to the public as is would introduce security risks for the host.</p>
|
||||
<p><sup>*</sup> ZMODEM file transfers are supported via an addon. To try it out, install <a href="https://ohse.de/uwe/software/lrzsz.html"><code>lrzsz</code></a> onto the remote peer, then run <code>rz</code> to send from your browser or <code>sz <file></code> to send from the remote peer.</p>
|
||||
<script src="main.js" defer ></script>
|
||||
</body>
|
||||
</html>
|
||||
383
YakPanel/static/build/addons/zmodem/demo/main.js
Normal file
383
YakPanel/static/build/addons/zmodem/demo/main.js
Normal file
@@ -0,0 +1,383 @@
|
||||
"use strict";
|
||||
|
||||
var term,
|
||||
protocol,
|
||||
socketURL,
|
||||
socket,
|
||||
pid;
|
||||
|
||||
var terminalContainer = document.getElementById('terminal-container'),
|
||||
actionElements = {
|
||||
findNext: document.querySelector('#find-next'),
|
||||
findPrevious: document.querySelector('#find-previous')
|
||||
},
|
||||
optionElements = {
|
||||
cursorBlink: document.querySelector('#option-cursor-blink'),
|
||||
cursorStyle: document.querySelector('#option-cursor-style'),
|
||||
scrollback: document.querySelector('#option-scrollback'),
|
||||
tabstopwidth: document.querySelector('#option-tabstopwidth'),
|
||||
bellStyle: document.querySelector('#option-bell-style')
|
||||
},
|
||||
colsElement = document.getElementById('cols'),
|
||||
rowsElement = document.getElementById('rows');
|
||||
|
||||
function setTerminalSize() {
|
||||
var cols = parseInt(colsElement.value, 10);
|
||||
var rows = parseInt(rowsElement.value, 10);
|
||||
var viewportElement = document.querySelector('.xterm-viewport');
|
||||
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
|
||||
var width = (cols * term.charMeasure.width + 20 /*room for scrollbar*/).toString() + 'px';
|
||||
var height = (rows * term.charMeasure.height).toString() + 'px';
|
||||
|
||||
terminalContainer.style.width = width;
|
||||
terminalContainer.style.height = height;
|
||||
term.resize(cols, rows);
|
||||
}
|
||||
|
||||
colsElement.addEventListener('change', setTerminalSize);
|
||||
rowsElement.addEventListener('change', setTerminalSize);
|
||||
|
||||
actionElements.findNext.addEventListener('keypress', function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
term.findNext(actionElements.findNext.value);
|
||||
}
|
||||
});
|
||||
actionElements.findPrevious.addEventListener('keypress', function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
term.findPrevious(actionElements.findPrevious.value);
|
||||
}
|
||||
});
|
||||
|
||||
optionElements.cursorBlink.addEventListener('change', function () {
|
||||
term.setOption('cursorBlink', optionElements.cursorBlink.checked);
|
||||
});
|
||||
optionElements.cursorStyle.addEventListener('change', function () {
|
||||
term.setOption('cursorStyle', optionElements.cursorStyle.value);
|
||||
});
|
||||
optionElements.bellStyle.addEventListener('change', function () {
|
||||
term.setOption('bellStyle', optionElements.bellStyle.value);
|
||||
});
|
||||
optionElements.scrollback.addEventListener('change', function () {
|
||||
term.setOption('scrollback', parseInt(optionElements.scrollback.value, 10));
|
||||
});
|
||||
optionElements.tabstopwidth.addEventListener('change', function () {
|
||||
term.setOption('tabStopWidth', parseInt(optionElements.tabstopwidth.value, 10));
|
||||
});
|
||||
|
||||
createTerminal();
|
||||
|
||||
function createTerminal() {
|
||||
// Clean terminal
|
||||
while (terminalContainer.children.length) {
|
||||
terminalContainer.removeChild(terminalContainer.children[0]);
|
||||
}
|
||||
term = new Terminal({
|
||||
cursorBlink: optionElements.cursorBlink.checked,
|
||||
scrollback: parseInt(optionElements.scrollback.value, 10),
|
||||
tabStopWidth: parseInt(optionElements.tabstopwidth.value, 10)
|
||||
});
|
||||
term.on('resize', function (size) {
|
||||
if (!pid) {
|
||||
return;
|
||||
}
|
||||
var cols = size.cols,
|
||||
rows = size.rows,
|
||||
url = '/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows;
|
||||
|
||||
fetch(url, {method: 'POST'});
|
||||
});
|
||||
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
|
||||
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
|
||||
|
||||
term.open(terminalContainer);
|
||||
term.fit();
|
||||
|
||||
// fit is called within a setTimeout, cols and rows need this.
|
||||
setTimeout(function () {
|
||||
colsElement.value = term.cols;
|
||||
rowsElement.value = term.rows;
|
||||
|
||||
// Set terminal size again to set the specific dimensions on the demo
|
||||
setTerminalSize();
|
||||
|
||||
fetch('/terminals?cols=' + term.cols + '&rows=' + term.rows, {method: 'POST'}).then(function (res) {
|
||||
|
||||
res.text().then(function (pid) {
|
||||
window.pid = pid;
|
||||
socketURL += pid;
|
||||
socket = new WebSocket(socketURL);
|
||||
socket.onopen = runRealTerminal;
|
||||
socket.onclose = runFakeTerminal;
|
||||
socket.onerror = runFakeTerminal;
|
||||
|
||||
term.zmodemAttach(socket, {
|
||||
noTerminalWriteOutsideSession: true,
|
||||
} );
|
||||
|
||||
term.on("zmodemRetract", () => {
|
||||
start_form.style.display = "none";
|
||||
start_form.onsubmit = null;
|
||||
});
|
||||
|
||||
term.on("zmodemDetect", (detection) => {
|
||||
function do_zmodem() {
|
||||
term.detach();
|
||||
let zsession = detection.confirm();
|
||||
|
||||
var promise;
|
||||
|
||||
if (zsession.type === "receive") {
|
||||
promise = _handle_receive_session(zsession);
|
||||
}
|
||||
else {
|
||||
promise = _handle_send_session(zsession);
|
||||
}
|
||||
|
||||
promise.catch( console.error.bind(console) ).then( () => {
|
||||
term.attach(socket);
|
||||
} );
|
||||
}
|
||||
|
||||
if (_auto_zmodem()) {
|
||||
do_zmodem();
|
||||
}
|
||||
else {
|
||||
start_form.style.display = "";
|
||||
start_form.onsubmit = function(e) {
|
||||
start_form.style.display = "none";
|
||||
|
||||
if (document.getElementById("zmstart_yes").checked) {
|
||||
do_zmodem();
|
||||
}
|
||||
else {
|
||||
detection.deny();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// UI STUFF
|
||||
|
||||
function _show_file_info(xfer) {
|
||||
var file_info = xfer.get_details();
|
||||
|
||||
document.getElementById("name").textContent = file_info.name;
|
||||
document.getElementById("size").textContent = file_info.size;
|
||||
document.getElementById("mtime").textContent = file_info.mtime;
|
||||
document.getElementById("files_remaining").textContent = file_info.files_remaining;
|
||||
document.getElementById("bytes_remaining").textContent = file_info.bytes_remaining;
|
||||
|
||||
document.getElementById("mode").textContent = "0" + file_info.mode.toString(8);
|
||||
|
||||
var xfer_opts = xfer.get_options();
|
||||
["conversion", "management", "transport", "sparse"].forEach( (lbl) => {
|
||||
document.getElementById(`zfile_${lbl}`).textContent = xfer_opts[lbl];
|
||||
} );
|
||||
|
||||
document.getElementById("zm_file").style.display = "";
|
||||
}
|
||||
function _hide_file_info() {
|
||||
document.getElementById("zm_file").style.display = "none";
|
||||
}
|
||||
|
||||
function _save_to_disk(xfer, buffer) {
|
||||
return Zmodem.Browser.save_to_disk(buffer, xfer.get_details().name);
|
||||
}
|
||||
|
||||
var skipper_button = document.getElementById("zm_progress_skipper");
|
||||
var skipper_button_orig_text = skipper_button.textContent;
|
||||
|
||||
function _show_progress() {
|
||||
skipper_button.disabled = false;
|
||||
skipper_button.textContent = skipper_button_orig_text;
|
||||
|
||||
document.getElementById("bytes_received").textContent = 0;
|
||||
document.getElementById("percent_received").textContent = 0;
|
||||
|
||||
document.getElementById("zm_progress").style.display = "";
|
||||
}
|
||||
|
||||
function _update_progress(xfer) {
|
||||
var total_in = xfer.get_offset();
|
||||
|
||||
document.getElementById("bytes_received").textContent = total_in;
|
||||
|
||||
var percent_received = 100 * total_in / xfer.get_details().size;
|
||||
document.getElementById("percent_received").textContent = percent_received.toFixed(2);
|
||||
}
|
||||
|
||||
function _hide_progress() {
|
||||
document.getElementById("zm_progress").style.display = "none";
|
||||
}
|
||||
|
||||
var start_form = document.getElementById("zm_start");
|
||||
|
||||
function _auto_zmodem() {
|
||||
return document.getElementById("zmodem-auto").checked;
|
||||
}
|
||||
|
||||
// END UI STUFF
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
function _handle_receive_session(zsession) {
|
||||
zsession.on("offer", function(xfer) {
|
||||
current_receive_xfer = xfer;
|
||||
|
||||
_show_file_info(xfer);
|
||||
|
||||
var offer_form = document.getElementById("zm_offer");
|
||||
|
||||
function on_form_submit() {
|
||||
offer_form.style.display = "none";
|
||||
|
||||
//START
|
||||
//if (offer_form.zmaccept.value) {
|
||||
if (_auto_zmodem() || document.getElementById("zmaccept_yes").checked) {
|
||||
_show_progress();
|
||||
|
||||
var FILE_BUFFER = [];
|
||||
xfer.on("input", (payload) => {
|
||||
_update_progress(xfer);
|
||||
FILE_BUFFER.push( new Uint8Array(payload) );
|
||||
});
|
||||
xfer.accept().then(
|
||||
() => {
|
||||
_save_to_disk(xfer, FILE_BUFFER);
|
||||
},
|
||||
console.error.bind(console)
|
||||
);
|
||||
}
|
||||
else {
|
||||
xfer.skip();
|
||||
}
|
||||
//END
|
||||
}
|
||||
|
||||
if (_auto_zmodem()) {
|
||||
on_form_submit();
|
||||
}
|
||||
else {
|
||||
offer_form.onsubmit = on_form_submit;
|
||||
offer_form.style.display = "";
|
||||
}
|
||||
} );
|
||||
|
||||
var promise = new Promise( (res) => {
|
||||
zsession.on("session_end", () => {
|
||||
_hide_file_info();
|
||||
_hide_progress();
|
||||
res();
|
||||
} );
|
||||
} );
|
||||
|
||||
zsession.start();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function _handle_send_session(zsession) {
|
||||
var choose_form = document.getElementById("zm_choose");
|
||||
choose_form.style.display = "";
|
||||
|
||||
var file_el = document.getElementById("zm_files");
|
||||
|
||||
var promise = new Promise( (res) => {
|
||||
file_el.onchange = function(e) {
|
||||
choose_form.style.display = "none";
|
||||
|
||||
var files_obj = file_el.files;
|
||||
|
||||
Zmodem.Browser.send_files(
|
||||
zsession,
|
||||
files_obj,
|
||||
{
|
||||
on_offer_response(obj, xfer) {
|
||||
if (xfer) _show_progress();
|
||||
//console.log("offer", xfer ? "accepted" : "skipped");
|
||||
},
|
||||
on_progress(obj, xfer) {
|
||||
_update_progress(xfer);
|
||||
},
|
||||
on_file_complete(obj) {
|
||||
//console.log("COMPLETE", obj);
|
||||
_hide_progress();
|
||||
},
|
||||
}
|
||||
).then(_hide_progress).then(
|
||||
zsession.close.bind(zsession),
|
||||
console.error.bind(console)
|
||||
).then( () => {
|
||||
_hide_file_info();
|
||||
_hide_progress();
|
||||
res();
|
||||
} );
|
||||
};
|
||||
} );
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
//This is here to allow canceling of an in-progress ZMODEM transfer.
|
||||
var current_receive_xfer;
|
||||
|
||||
//Called from HTML directly.
|
||||
function skip_current_file() {
|
||||
current_receive_xfer.skip();
|
||||
|
||||
skipper_button.disabled = true;
|
||||
skipper_button.textContent = "Waiting for server to acknowledge skip …";
|
||||
}
|
||||
|
||||
function runRealTerminal() {
|
||||
term.attach(socket);
|
||||
|
||||
term._initialized = true;
|
||||
}
|
||||
|
||||
function runFakeTerminal() {
|
||||
if (term._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
term._initialized = true;
|
||||
|
||||
var shellprompt = '$ ';
|
||||
|
||||
term.prompt = function () {
|
||||
term.write('\r\n' + shellprompt);
|
||||
};
|
||||
|
||||
term.writeln('Welcome to xterm.js');
|
||||
term.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
|
||||
term.writeln('Type some keys and commands to play around.');
|
||||
term.writeln('');
|
||||
term.prompt();
|
||||
|
||||
term.on('key', function (key, ev) {
|
||||
var printable = (
|
||||
!ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
|
||||
);
|
||||
|
||||
if (ev.keyCode == 13) {
|
||||
term.prompt();
|
||||
} else if (ev.keyCode == 8) {
|
||||
// Do not delete the prompt
|
||||
if (term.x > 2) {
|
||||
term.write('\b \b');
|
||||
}
|
||||
} else if (printable) {
|
||||
term.write(key);
|
||||
}
|
||||
});
|
||||
|
||||
term.on('paste', function (data, ev) {
|
||||
term.write(data);
|
||||
});
|
||||
}
|
||||
108
YakPanel/static/build/addons/zmodem/zmodem.js
Normal file
108
YakPanel/static/build/addons/zmodem/zmodem.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
*
|
||||
* Allow xterm.js to handle ZMODEM uploads and downloads.
|
||||
*
|
||||
* This addon is a wrapper around zmodem.js. It adds the following to the
|
||||
* Terminal class:
|
||||
*
|
||||
* - function `zmodemAttach(<WebSocket>, <Object>)` - creates a Zmodem.Sentry
|
||||
* on the passed WebSocket object. The Object passed is optional and
|
||||
* can contain:
|
||||
* - noTerminalWriteOutsideSession: Suppress writes from the Sentry
|
||||
* object to the Terminal while there is no active Session. This
|
||||
* is necessary for compatibility with, for example, the
|
||||
* `attach.js` addon.
|
||||
*
|
||||
* - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback.
|
||||
* Passes the zmodem.js Detection object.
|
||||
*
|
||||
* - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback.
|
||||
*
|
||||
* You’ll need to provide logic to handle uploads and downloads.
|
||||
* See zmodem.js’s documentation for more details.
|
||||
*
|
||||
* **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have
|
||||
* used the `attach` or `terminado` addons, you’ll need to suspend their
|
||||
* operation for the duration of the ZMODEM session. (The demo does this
|
||||
* via `detach()` and a re-`attach()`.)
|
||||
*/
|
||||
(function (addon) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = addon(require('../../Terminal').Terminal);
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], addon);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
addon(window.Terminal);
|
||||
}
|
||||
})(function _zmodemAddon(Terminal) {
|
||||
Object.assign(
|
||||
Terminal.prototype,
|
||||
{
|
||||
zmodemAttach: function zmodemAttach(ws, opts) {
|
||||
var term = this;
|
||||
|
||||
if (!opts) opts = {};
|
||||
|
||||
var senderFunc = function _ws_sender_func(octets) {
|
||||
ws.send( new Uint8Array(octets) );
|
||||
};
|
||||
|
||||
var zsentry;
|
||||
|
||||
function _shouldWrite() {
|
||||
return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession;
|
||||
}
|
||||
|
||||
zsentry = new Zmodem.Sentry( {
|
||||
to_terminal: function _to_terminal(octets) {
|
||||
if (_shouldWrite()) {
|
||||
term.write(
|
||||
String.fromCharCode.apply(String, octets)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
sender: senderFunc,
|
||||
|
||||
on_retract: function _on_retract() {
|
||||
term.emit("zmodemRetract");
|
||||
},
|
||||
|
||||
on_detect: function _on_detect(detection) {
|
||||
term.emit("zmodemDetect", detection);
|
||||
},
|
||||
} );
|
||||
|
||||
function handleWSMessage(evt) {
|
||||
|
||||
//In testing with xterm.js’s demo the first message was
|
||||
//always text even if the rest were binary. While that
|
||||
//may be specific to xterm.js’s demo, ultimately we
|
||||
//should reject anything that isn’t binary.
|
||||
if (typeof evt.data === "string") {
|
||||
if (_shouldWrite()) {
|
||||
term.write(evt.data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
zsentry.consume(evt.data);
|
||||
}
|
||||
}
|
||||
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.addEventListener("message", handleWSMessage);
|
||||
},
|
||||
|
||||
zmodemBrowser: Zmodem.Browser,
|
||||
}
|
||||
);
|
||||
});
|
||||
1
YakPanel/static/build/addons/zmodem/zmodem.min.js
vendored
Normal file
1
YakPanel/static/build/addons/zmodem/zmodem.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).zmodem=e()}}(function(){return function i(f,u,d){function a(n,e){if(!u[n]){if(!f[n]){var t="function"==typeof require&&require;if(!e&&t)return t(n,!0);if(s)return s(n,!0);var r=new Error("Cannot find module '"+n+"'");throw r.code="MODULE_NOT_FOUND",r}var o=u[n]={exports:{}};f[n][0].call(o.exports,function(e){return a(f[n][1][e]||e)},o,o.exports,i,f,u,d)}return u[n].exports}for(var s="function"==typeof require&&require,e=0;e<d.length;e++)a(d[e]);return a}({1:[function(e,n,t){"use strict";var i;function r(n,e){void 0===e&&(e={});var t,r=this;function o(){return!!t.get_confirmed_session()||!e.noTerminalWriteOutsideSession}t=new i.Sentry({to_terminal:function(e){o()&&r.write(String.fromCharCode.apply(String,e))},sender:function(e){return n.send(new Uint8Array(e))},on_retract:function(){return r.emit("zmodemRetract")},on_detect:function(e){return r.emit("zmodemDetect",e)}}),n.binaryType="arraybuffer",n.addEventListener("message",function(e){"string"==typeof e.data?o()&&r.write(e.data):t.consume(e.data)})}Object.defineProperty(t,"__esModule",{value:!0}),t.apply=function(e){i="object"==typeof window?window.Zmodem:{Browser:null},e.prototype.zmodemAttach=r,e.prototype.zmodemBrowser=i.Browser}},{}]},{},[1])(1)});
|
||||
Reference in New Issue
Block a user