Skip to content

Commit

Permalink
Merge pull request #21 from cs01/cs01/cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
cs01 authored Aug 11, 2021
2 parents 8cc4fb2 + 4fa5785 commit af4da0c
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 115 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## 0.5.0.0

* Update dependencies xtermjs and socketio
* Turn off flask's logging
* Update setup.py to install from pinned dependencies in requirements.tx
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include README.md LICENSE
include README.md LICENSE requirements.txt
recursive-include pyxtermjs *
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,36 @@ This is a
There are a few ways to install and run.

### Clone & Run Locally
Clone this repository, enter the `pyxtermjs` directory, then run:
Clone this repository, enter the `pyxtermjs` directory.

If you have [nox](https://github.com/theacodes/nox) you can run the following.
```
> nox -s run
```
Nox takes care of setting up a virtual environment and running the right command for you. You can pass arguments to the server like this
```
> python -m venv venv # must be python3.6+
> venv/bin/pip install -r requirements.txt
> venv/bin/python -m pyxtermjs
serving on http://127.0.0.1:5000
> nox -s run -- --debug
```

### Install or Run latest version on PyPI
You can use [pipx](https://github.com/pipxproject/pipx) to try it out.
If you don't have nox, you can run the following from inside a virtual environment.
```
> pipx run pyxtermjs
serving on http://127.0.0.1:5000
> pip install -r requirements.txt
> python -m pyxtermjs
> python -m pyxtermjs --debug
```

You can also and have `pyxtermjs` installed in an isolated environment, yet available on your $PATH with
### Install
You can install with [pipx](https://github.com/pipxproject/pipx) (recommended) or pip.
```
> pipx install pyxtermjs
> pyxtermjs
```

### Run from GitHub source
Use [pipx](https://github.com/pipxproject/pipx) for this as well.
Or you can try run latest version on PyPI
```
> pipx run --spec git+https://github.com/cs01/pyxtermjs.git pyxtermjs
serving on http://127.0.0.1:5000
> pipx run pyxtermjs
```


## API
```
> pyxtermjs --help
Expand Down
6 changes: 6 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
nox.options.reuse_existing_virtualenvs = True


@nox.session()
def run(session):
session.install(".")
session.run("python", "-m", "pyxtermjs", *session.posargs)


def has_changes():
status = (
subprocess.run(
Expand Down
34 changes: 25 additions & 9 deletions pyxtermjs/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
import struct
import fcntl
import shlex
import logging
import sys

logging.getLogger("werkzeug").setLevel(logging.ERROR)

__version__ = "0.4.0.2"
__version__ = "0.5.0.0"

app = Flask(__name__, template_folder=".", static_folder=".", static_url_path="")
app.config["SECRET_KEY"] = "secret!"
Expand All @@ -22,6 +25,7 @@


def set_winsize(fd, row, col, xpix=0, ypix=0):
logging.debug("setting window size with termios")
winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)

Expand Down Expand Up @@ -49,20 +53,21 @@ def pty_input(data):
terminal.
"""
if app.config["fd"]:
# print("writing to ptd: %s" % data["input"])
os.write(app.config["fd"], data["input"]["key"].encode())
logging.debug("received input from browser: %s" % data["input"])
os.write(app.config["fd"], data["input"].encode())


@socketio.on("resize", namespace="/pty")
def resize(data):
if app.config["fd"]:
logging.debug(f"Resizing window to {data['rows']}x{data['cols']}")
set_winsize(app.config["fd"], data["rows"], data["cols"])


@socketio.on("connect", namespace="/pty")
def connect():
"""new client connected"""

logging.info("new client connected")
if app.config["child_pid"]:
# already started child process, don't start another
return
Expand All @@ -81,13 +86,16 @@ def connect():
app.config["child_pid"] = child_pid
set_winsize(fd, 50, 50)
cmd = " ".join(shlex.quote(c) for c in app.config["cmd"])
print("child pid is", child_pid)
print(
# logging/print statements must go after this because... I have no idea why
# but if they come before the background task never starts
socketio.start_background_task(target=read_and_forward_pty_output)

logging.info("child pid is " + child_pid)
logging.info(
f"starting background task with command `{cmd}` to continously read "
"and forward pty output to client"
)
socketio.start_background_task(target=read_and_forward_pty_output)
print("task started")
logging.info("task started")


def main():
Expand Down Expand Up @@ -118,8 +126,16 @@ def main():
if args.version:
print(__version__)
exit(0)
print(f"serving on http://127.0.0.1:{args.port}")
app.config["cmd"] = [args.command] + shlex.split(args.cmd_args)
green = "\033[92m"
end = "\033[0m"
log_format = green + "pyxtermjs > " + end + "%(levelname)s (%(funcName)s:%(lineno)s) %(message)s"
logging.basicConfig(
format=log_format,
stream=sys.stdout,
level=logging.DEBUG if args.debug else logging.INFO,
)
logging.info(f"serving on http://127.0.0.1:{args.port}")
socketio.run(app, debug=args.debug, port=args.port, host=args.host)


Expand Down
158 changes: 82 additions & 76 deletions pyxtermjs/index.html
Original file line number Diff line number Diff line change
@@ -1,93 +1,99 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>pyxterm.js</title>
<style>
html {
font-family: arial;
}
</style>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/xterm.css" />
</head>
<body>
<head>
<meta charset="utf-8" />
<title>pyxterm.js</title>
<style>
html {
font-family: arial;
}
</style>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/css/xterm.css"
/>
</head>
<body>
<span style="font-size: 1.4em">pyxterm.js</span>&nbsp;&nbsp;&nbsp;
<span style="font-size: small"
>status:
<span style="font-size: small" id="status">connecting...</span></span
>

<span style="font-size: 1.4em;">pyxterm.js</span>&nbsp;&nbsp;&nbsp;
<span style="font-size: small;">status: <span style="font-size: small;" id="status">connecting...</span></span>
<div style="width: 100%; height: calc(100% - 50px)" id="terminal"></div>

<div style="width: 100%; height: calc(100% - 50px);" id="terminal"></div>

<p style="text-align: right; font-size: small;">
built by <a href="https://grassfedcode.com">Chad Smith</a> <a href="https://github.com/cs01">GitHub</a>
</p>
<!-- xterm -->
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-fit.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-web-links.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-sear
<p style="text-align: right; font-size: small">
built by <a href="https://chadsmith.dev">Chad Smith</a>
<a href="https://github.com/cs01">GitHub</a>
</p>
<!-- xterm -->
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-fit.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-web-links.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-sear
ch.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>

<script>
const term = new Terminal({
<script>
const term = new Terminal({
cursorBlink: true,
macOptionIsMeta: true,
scrollback: true,
});
// https://github.com/xtermjs/xterm.js/issues/2941
const fit = new FitAddon.FitAddon();
term.loadAddon(fit);
term.loadAddon(new WebLinksAddon.WebLinksAddon());
term.loadAddon(new SearchAddon.SearchAddon());

term.open(document.getElementById('terminal'));
fit.fit()
term.resize(15, 50)
console.log(`size: ${term.cols} columns, ${term.rows} rows`)
fit.fit()
term.write("Welcome to pyxterm.js!\nhttps://github.com/cs01/pyxterm.js\n")
term.onKey((key, ev) => {
console.log("pressed key", key)
console.log("event", ev)
socket.emit("pty-input", {"input": key})
});

const socket = io.connect('/pty');
const status = document.getElementById("status")

socket.on("pty-output", function(data){
console.log("new output", data)
term.write(data.output)
})
});
// https://github.com/xtermjs/xterm.js/issues/2941
const fit = new FitAddon.FitAddon();
term.loadAddon(fit);
term.loadAddon(new WebLinksAddon.WebLinksAddon());
term.loadAddon(new SearchAddon.SearchAddon());

socket.on("connect", () => {
fitToscreen()
status.innerHTML = '<span style="background-color: lightgreen;">connected</span>'
}
)
term.open(document.getElementById("terminal"));
fit.fit();
term.resize(15, 50);
console.log(`size: ${term.cols} columns, ${term.rows} rows`);
fit.fit();
term.writeln("Welcome to pyxterm.js!");
term.writeln("https://github.com/cs01/pyxterm.js");
term.onData((data) => {
console.log("key pressed in browser:", data);
socket.emit("pty-input", { input: data });
});

socket.on("disconnect", () => {
status.innerHTML = '<span style="background-color: #ff8383;">disconnected</span>'
})
const socket = io.connect("/pty");
const status = document.getElementById("status");

function fitToscreen(){
fit.fit()
socket.emit("resize", {"cols": term.cols, "rows": term.rows})
}
socket.on("pty-output", function (data) {
console.log("new output received from server:", data.output);
term.write(data.output);
});

function debounce(func, wait_ms) {
let timeout
return function(...args) {
const context = this
clearTimeout(timeout)
timeout = setTimeout(() => func.apply(context, args), wait_ms)
}
}
socket.on("connect", () => {
fitToscreen();
status.innerHTML =
'<span style="background-color: lightgreen;">connected</span>';
});

const wait_ms = 50;
window.onresize = debounce(fitToscreen, wait_ms)
socket.on("disconnect", () => {
status.innerHTML =
'<span style="background-color: #ff8383;">disconnected</span>';
});

function fitToscreen() {
fit.fit();
const dims = { cols: term.cols, rows: term.rows };
console.log("sending new dimensions to server's pty", dims);
socket.emit("resize", dims);
}

</script>
function debounce(func, wait_ms) {
let timeout;
return function (...args) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait_ms);
};
}

</body>
const wait_ms = 50;
window.onresize = debounce(fitToscreen, wait_ms);
</script>
</body>
</html>
1 change: 1 addition & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
flask-socketio==5.1.1
24 changes: 12 additions & 12 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
#
# This file is autogenerated by pip-compile
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
#
# pip-compile
# pip-compile requirements.in
#
bidict==0.21.2
# via python-socketio
click==7.1.2
click==8.0.1
# via flask
flask-socketio==5.0.1
# via pyxtermjs (setup.py)
flask==1.1.2
flask==2.0.1
# via flask-socketio
itsdangerous==1.1.0
flask-socketio==5.1.1
# via -r requirements.in
itsdangerous==2.0.1
# via flask
jinja2==2.11.3
jinja2==3.0.1
# via flask
markupsafe==1.1.1
markupsafe==2.0.1
# via jinja2
python-engineio==4.1.0
python-engineio==4.2.1
# via python-socketio
python-socketio==5.2.1
python-socketio==5.4.0
# via flask-socketio
werkzeug==1.0.1
werkzeug==2.0.1
# via flask
Loading

0 comments on commit af4da0c

Please sign in to comment.