I am programming a terminal application using xterm.js in frontend and django at backend. Everything works fine but when I try to save the input from the user using onData I get it is not a function error. If you have another approach please tell me. I tried getting current line but run into problems if user press backspace or delete.
index html:
<!doctype html>
<html style="height: calc(100% - 50px)">
<head>
<link rel="stylesheet" href="https://unpkg.com/xterm@3.6.0/dist/xterm.css" />
<script src="https://unpkg.com/xterm@3.6.0/dist/xterm.js"></script>
<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fit/fit.js"></script>
<script src="https://unpkg.com/xterm@3.6.0/dist/addons/fullscreen/fullscreen.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.4.0/socket.io.js"></script>
</head>
<body style="height: 100%">
<div style="background: white; padding-bottom: 5px;">
<span style="font-size: small;">Status: <span style="font-size: small;" id="status">connecting...</span></span>
<button id="button" ; type="button" ; onclick="myFunction()" ;>Connect</button>
</div>
<div style=" width: 100%; height:100%;" id="terminal"></div>
<script>
Terminal.applyAddon(fit)
var socket = io.connect({ transports: ["websocket", "polling"] });
const status = document.getElementById("status")
const button = document.getElementById("button")
var term = new Terminal({
cursorBlink: true,
});
term.open(document.getElementById('terminal'));
term.onData(data => {
console.log("Data received:", data);
socket.emit("pty_input", { "input": data });
});
socket.on("pty_output", function (output) {
term.write(output["output"])
})
socket.on("connect", () => {
status.innerHTML = '<span style="background-color: lightgreen;">connected</span>'
button.innerHTML = 'Disconnect'
})
socket.on("disconnect", () => {
status.innerHTML = '<span style="background-color: #ff8383;">disconnected</span>'
button.innerHTML = 'Connect'
})
function myFunction() {
if (button.innerHTML == 'Connect') {
location.reload();
}
else if (button.innerHTML == "Disconnect") {
socket.emit("disconnect_request")
}
}
function resize() {
term.fit()
socket.emit("resize", { "cols": term.cols, "rows": term.rows })
}
window.onresize = resize
window.onload = resize
</script>
</body>
</html>
views py:
async_mode = "eventlet"
sio = socketio.Server(async_mode=async_mode)
fd = None
child_pid = None
def index(request):
return render(request, "index.html")
def set_winsize(fd, row, col, xpix=0, ypix=0):
winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
def read_and_forward_pty_output():
global fd
max_read_bytes = 1024 * 20
while True:
sio.sleep(0.01)
if fd:
timeout_sec = 0
(data_ready, _, _) = select.select([fd], [], [], timeout_sec)
if data_ready:
output = os.read(fd, max_read_bytes).decode()
sio.emit("pty_output", {"output": output})
else:
print("process killed")
return
@sio.event
def resize(sid, message):
if fd:
set_winsize(fd, message["rows"], message["cols"])
@sio.event
def pty_input(sid, message):
if fd:
os.write(fd, message["input"].encode())
@sio.event
def disconnect_request(sid):
sio.disconnect(sid)
@sio.event
def connect(sid, environ):
global fd
global child_pid
if child_pid:
os.write(fd, "\n".encode())
return
(child_pid, fd) = pty.fork()
if child_pid == 0:
subprocess.run("bash")
else:
print()
sio.start_background_task(target=read_and_forward_pty_output)
@sio.event
def disconnect(sid):
global fd
global child_pid
os.kill(child_pid, signal.SIGKILL)
os.wait()
fd = None
child_pid = None
print("Client disconnected")
I can only assume it might be a version problem.
I tried updating the version to 5.2.1
var socket = io.connect({ transports: ["websocket", "polling"] });
const status = document.getElementById("status")
const button = document.getElementById("button")
const fit = new FitAddon.FitAddon();
var term = new Terminal({
cursorBlink: true,
});
term.loadAddon(fit);
term.open(document.getElementById('terminal'));
fit.fit();
term.onData(data => {
console.log("Data received:", data);
socket.emit("pty_input", { "input": data });
});
socket.on("pty_output", function (output) {
term.write(output["output"])
})
socket.on("connect", () => {
status.innerHTML = '<span style="background-color: lightgreen;">connected</span>'
button.innerHTML = 'Disconnect'
})
socket.on("disconnect", () => {
status.innerHTML = '<span style="background-color: #ff8383;">disconnected</span>'
button.innerHTML = 'Connect'
})
function myFunction() {
if (button.innerHTML == 'Connect') {
location.reload();
}
else if (button.innerHTML == "Disconnect") {
socket.emit("disconnect_request")
}
}
function resize() {
socket.emit("resize", { "cols": term.cols, "rows": term.rows })
}
window.onresize = resize
window.onload = resize
<!doctype html>
<html style="height: calc(100% - 50px)">
<head>
<link rel="stylesheet" href="https://unpkg.com/xterm@5.2.1/css/xterm.css" />
<script src="https://unpkg.com/xterm@5.2.1/lib/xterm.js"></script>
<script src="https://unpkg.com/xterm-addon-fit@0.7.0/lib/xterm-addon-fit.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.4.0/socket.io.js"></script>
</head>
<body style="height: 100%">
<div style="background: white; padding-bottom: 5px;">
<span style="font-size: small;">Status: <span style="font-size: small;" id="status">connecting...</span></span>
<button id="button" ; type="button" ; onclick="myFunction()" ;>Connect</button>
</div>
<div style=" width: 100%; height:100%;" id="terminal"></div>
</body>
</html>
You'll see I changed the unpkg links to
<link rel="stylesheet" href="https://unpkg.com/xterm@5.2.1/css/xterm.css" />
<script src="https://unpkg.com/xterm@5.2.1/lib/xterm.js"></script>
<script src="https://unpkg.com/xterm-addon-fit@0.7.0/lib/xterm-addon-fit.js"></script>
The fullscreen module I couldn't find.