improved javascript bridge
This commit is contained in:
parent
7bfa591536
commit
69a1760a11
|
@ -150,7 +150,6 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
'still faster than Windows update',
|
'still faster than Windows update',
|
||||||
'loading a microlinux',
|
'loading a microlinux',
|
||||||
'figuring out meaning of life',
|
'figuring out meaning of life',
|
||||||
'asking LLM why men have nipples',
|
|
||||||
'Aligning your chakras now',
|
'Aligning your chakras now',
|
||||||
'Breathing in good vibes',
|
'Breathing in good vibes',
|
||||||
'Finding inner peace soon',
|
'Finding inner peace soon',
|
||||||
|
@ -181,11 +180,41 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
"com/isoterminal/mnt/prompt",
|
"com/isoterminal/mnt/prompt",
|
||||||
"com/isoterminal/mnt/alert",
|
"com/isoterminal/mnt/alert",
|
||||||
"com/isoterminal/mnt/hook",
|
"com/isoterminal/mnt/hook",
|
||||||
|
"com/isoterminal/mnt/xrsh",
|
||||||
"com/isoterminal/mnt/profile",
|
"com/isoterminal/mnt/profile",
|
||||||
|
"com/isoterminal/mnt/profile.xrsh",
|
||||||
"com/isoterminal/mnt/profile.js",
|
"com/isoterminal/mnt/profile.js",
|
||||||
"com/isoterminal/mnt/motd",
|
"com/isoterminal/mnt/motd",
|
||||||
|
"com/isoterminal/mnt/v86pipe"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const redirectConsole = (handler) => {
|
||||||
|
const log = console.log;
|
||||||
|
const dir = console.dir;
|
||||||
|
const err = console.error;
|
||||||
|
const warn = console.warn;
|
||||||
|
console.log = (...args)=>{
|
||||||
|
const textArg = args[0];
|
||||||
|
handler(textArg+'\n');
|
||||||
|
log.apply(log, args);
|
||||||
|
};
|
||||||
|
console.error = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler( textArg+'\n', '\x1b[31merror\x1b[0m');
|
||||||
|
err.apply(log, args);
|
||||||
|
};
|
||||||
|
console.dir = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler( JSON.stringify(textArg,null,2)+'\n');
|
||||||
|
dir.apply(log, args);
|
||||||
|
};
|
||||||
|
console.warn = (...args)=>{
|
||||||
|
const textArg = args[0].message?args[0].message:args[0];
|
||||||
|
handler(textArg+'\n','\x1b[38;5;208mwarn\x1b[0m');
|
||||||
|
err.apply(log, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
emulator.bus.register("emulator-started", async () => {
|
emulator.bus.register("emulator-started", async () => {
|
||||||
emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
|
emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
|
||||||
emulator.serial_adapter.term.clear()
|
emulator.serial_adapter.term.clear()
|
||||||
|
@ -197,6 +226,17 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
cat > /dev/null
|
cat > /dev/null
|
||||||
`))
|
`))
|
||||||
|
|
||||||
|
redirectConsole( (str,prefix) => {
|
||||||
|
if( emulator.log_to_tty ){
|
||||||
|
prefix = prefix ? prefix+' ' : ' '
|
||||||
|
str.trim().split("\n").map( (line) => {
|
||||||
|
emulator.serial_adapter.term.write( '\r\x1b[38;5;165m/dev/browser: \x1b[0m'+prefix+line+'\n' )
|
||||||
|
})
|
||||||
|
emulator.serial_adapter.term.write( '\r' )
|
||||||
|
}
|
||||||
|
emulator.create_file( "console", this.toUint8Array( str ) )
|
||||||
|
})
|
||||||
|
|
||||||
let p = files.map( (f) => fetch(f) )
|
let p = files.map( (f) => fetch(f) )
|
||||||
Promise.all(p)
|
Promise.all(p)
|
||||||
.then( (files) => {
|
.then( (files) => {
|
||||||
|
@ -267,15 +307,23 @@ AFRAME.registerComponent('isoterminal', {
|
||||||
const buf = await emulator.read_file("dev/browser/js")
|
const buf = await emulator.read_file("dev/browser/js")
|
||||||
const script = decoder.decode(buf)
|
const script = decoder.decode(buf)
|
||||||
try{
|
try{
|
||||||
let res = (new Function(`return ${script}`))()
|
let res = (new Function(`${script}`))()
|
||||||
if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2)
|
if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2)
|
||||||
emulator.create_file( "dev/browser/js", this.toUint8Array( res || '' ) )
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
console.dir(e)
|
console.error(e)
|
||||||
emulator.create_file("dev/browser/js", this.toUint8Array( `[e] `+String(e.stack) ) )
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// enable/disable logging file (echo 1 > mnt/console.tty)
|
||||||
|
emulator.add_listener("9p-write-end", async (opts) => {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
if ( opts[0] == 'console.tty' ){
|
||||||
|
const buf = await emulator.read_file("console.tty")
|
||||||
|
const val = decoder.decode(buf)
|
||||||
|
emulator.log_to_tty = ( String(val).trim() == '1')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo "$(printf "\033[0m")[i] [38;5;165m$1 $(printf "\033[0m")"
|
title=$1
|
||||||
|
shift
|
||||||
|
msg="$*"
|
||||||
|
echo "[38;5;165m$title $(printf "\033[0m")$msg"
|
||||||
|
hook alert $title "$msg"
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
test -z $1 && { echo "usage: hook <cmd_or_jsfunction> [args]"; exit 0; }
|
test -z $1 && { echo "usage: hook <cmd_or_jsfunction> [args]"; exit 0; }
|
||||||
|
|
||||||
cmd=$1
|
cmd=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
test -d ~/hook.d/$cmd && {
|
test -d ~/hook.d/$cmd && {
|
||||||
chmod +x ~/hook.d/$cmd/*
|
|
||||||
find ~/hook.d/$cmd/ -type f -executable | while read hook; do
|
find ~/hook.d/$cmd/ -type f -executable | while read hook; do
|
||||||
$hook "$@" || true
|
{ $hook "$@" || true; } | awk '{ gsub(/\/root\/\//,"",$1); $1 = sprintf("%-40s", $1)} 1'
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
#test $BROWSER = 1 && {
|
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
test -z $1 && { echo "Usage: js 'somefunction(1)'"; exit 0; }
|
test -z "$1" && { echo "Usage: js 'somefunction(1)'"; exit 0; }
|
||||||
|
|
||||||
|
test -n "$BROWSER" || { alert warning "/dev/browser not active (are you running outside of v86?)"; }
|
||||||
javascript="$*"
|
javascript="$*"
|
||||||
|
|
||||||
# if we are run as shebang, use the file as input
|
# if we are run as shebang, use the file as input
|
||||||
case "$1" in
|
case "$1" in
|
||||||
*/*) javascript="$(cat $1 | tail +2)"
|
*/*) javascript="args = String('$*').split(' '); $(cat $1 | tail +2)"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
echo -n "$javascript" > /dev/browser/js
|
||||||
|
|
||||||
flock /dev/browser/js -c "echo '$javascript' > /dev/browser/js; sleep 0.5; cat /dev/browser/js"
|
# should we use flock, an awesome way to make processes read/write the same file
|
||||||
|
# while preventing 1001 concurrency issues?
|
||||||
# we use flock, an awesome way to make processes read/write the same file
|
# attempt:
|
||||||
# while preventing 1001 concurrency issues
|
#
|
||||||
|
# flock /dev/browser/js -c "echo \"$javascript\" > /dev/browser/js"
|
||||||
|
|
|
@ -20,18 +20,23 @@ to_js(){
|
||||||
}
|
}
|
||||||
|
|
||||||
# run argument as js
|
# run argument as js
|
||||||
test -z $1 || {
|
test -z "$1" || {
|
||||||
func=$(to_js "$@")
|
func=$(to_js "$@")
|
||||||
func=${func/,)/)}
|
func=${func/,)/)}
|
||||||
js "$func"
|
js "$func"
|
||||||
|
hook "$@"
|
||||||
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# otherwise start repl
|
# otherwise start repl
|
||||||
|
echo "jsh> type 'exit' or CTRL-C to quit"
|
||||||
|
echo "jsh> HINT: to run alert('foo') outside this REPL, run 'jsh alert foo'"
|
||||||
|
echo "jsh>"
|
||||||
while true; do
|
while true; do
|
||||||
echo -n "$(printf "\033[0m")jsh> $(printf "\033[0m")"
|
echo -n -e "\r$(printf "\033[0m")jsh> $(printf "\033[0m")"
|
||||||
read input
|
read line
|
||||||
test $input = exit && exit
|
test "$line" = exit && exit
|
||||||
js "$input"
|
js "$line"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,50 +1,15 @@
|
||||||
install_xrsh(){
|
# install xrsh env
|
||||||
|
source /mnt/profile.xrsh
|
||||||
setup_binaries(){
|
|
||||||
for bin in /mnt/prompt /mnt/alert /mnt/confirm /mnt/hook /mnt/js*; do
|
|
||||||
chmod +x $bin
|
|
||||||
ln -s $bin /bin/.
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_browser_dev(){
|
|
||||||
mkdir -p /mnt/dev/browser
|
|
||||||
touch /mnt/dev/browser/js
|
|
||||||
touch /mnt/dev/browser/html
|
|
||||||
touch /mnt/dev/browser/console
|
|
||||||
ln -s /mnt/dev/browser /dev/browser
|
|
||||||
test -f /etc/profile && rm /etc/profile
|
|
||||||
ln -s /mnt/profile /etc/profile
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_hook_dirs(){ # see /mnt/hook for usage
|
|
||||||
mkdir -p ~/hook.d/alert
|
|
||||||
mkdir -p ~/hook.d/confirm
|
|
||||||
mkdir -p ~/hook.d/prompt
|
|
||||||
echo -e "#!/bin/sh\necho yo" > ~/hook.d/alert/yo
|
|
||||||
echo -e "#!/bin/js\nalert('yo')" > ~/hook.d/alert/yo.js
|
|
||||||
echo -e "#!/usr/bin/lua\nalert('yo')" > ~/hook.d/alert/yo.lua
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_binaries
|
|
||||||
setup_browser_dev
|
|
||||||
setup_hook_dirs
|
|
||||||
}
|
|
||||||
|
|
||||||
test -d /dev/browser || install_xrsh
|
|
||||||
|
|
||||||
test -f /mnt/V86 && {
|
|
||||||
mount -a
|
|
||||||
udhcpc 1>>/var/log/network.log 2>>/var/log/network.log &
|
|
||||||
echo 0 > /proc/sys/kernel/printk
|
|
||||||
}
|
|
||||||
|
|
||||||
## forward not-found commands to javascript (via jsh)
|
## forward not-found commands to javascript (via jsh)
|
||||||
command_not_found_handle(){
|
command_not_found_handle(){
|
||||||
echo "$1 not found"
|
echo "$1 not found, did you mean $1(...) (javascript?)"
|
||||||
alert "did you mean $1(...) (javascript?)"
|
alert '[XRSH TIPS]'
|
||||||
alert "TIP: run 'jsh $1 hello' to run $1('hello')"
|
alert 'js console: ' "type 'jsh'"
|
||||||
alert " or simply 'jsh' for a js console"
|
alert 'js shellfunction:' "type 'alias $1=\"jsh $1\"' to run '$1 yo' as $1('yo')"
|
||||||
|
alert 'js logging: ' "type 'echo 0 > /dev/browser/console.tty' to disable"
|
||||||
|
alert 'js capture log: ' "type 'tail -f /dev/browser/console'"
|
||||||
|
alert 'jsh<->sh hooks: ' "type 'chmod +x ~/hook.d/alert/* && alert helloworld'"
|
||||||
}
|
}
|
||||||
|
|
||||||
# source javascript functions
|
# source javascript functions
|
||||||
|
@ -55,4 +20,3 @@ resize
|
||||||
cat /mnt/motd
|
cat /mnt/motd
|
||||||
export PATH=$PATH:/mnt
|
export PATH=$PATH:/mnt
|
||||||
export PS1="\n[38;5;57mx[38;5;93mr[38;5;129ms[38;5;165mh [38;5;201m# \033[0m"
|
export PS1="\n[38;5;57mx[38;5;93mr[38;5;129ms[38;5;165mh [38;5;201m# \033[0m"
|
||||||
export BROWSER=0 # running inside v86 (wasm) will set this to 1
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test -d /dev/browser || {
|
||||||
|
|
||||||
|
setup_binaries(){
|
||||||
|
for bin in /mnt/prompt /mnt/alert /mnt/confirm /mnt/hook /mnt/js* /mnt/v86pipe /mnt/xrsh; do
|
||||||
|
chmod +x $bin
|
||||||
|
ln -s $bin /bin/.
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_browser_dev(){
|
||||||
|
mkdir -p /mnt/dev/browser
|
||||||
|
touch /mnt/dev/browser/js
|
||||||
|
touch /mnt/dev/browser/html
|
||||||
|
touch /mnt/console.tty
|
||||||
|
ln -s /mnt/dev/browser /dev/browser
|
||||||
|
# setup console goodies
|
||||||
|
ln -s /mnt/console.tty /dev/browser/console.tty # emulator.write_file() only writes to /mnt/. :(
|
||||||
|
echo 1 > /dev/browser/console.tty # should be in /proc, but v86 gives 'no such file or dir' when creating it there
|
||||||
|
v86pipe /mnt/console /dev/browser/console &
|
||||||
|
|
||||||
|
test -f /etc/profile && rm /etc/profile
|
||||||
|
ln -s /mnt/profile /etc/profile
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_hook_dirs(){ # see /mnt/hook for usage
|
||||||
|
mkdir -p ~/hook.d/alert
|
||||||
|
mkdir -p ~/hook.d/confirm
|
||||||
|
mkdir -p ~/hook.d/prompt
|
||||||
|
echo -e "#!/bin/sh\necho hook.d/alert/yo: yo \$*" > ~/hook.d/alert/yo
|
||||||
|
echo -e "#!/bin/js\nalert(\"hook.d/alert/yo.js \"+args.slice(1).join(' '))" > ~/hook.d/alert/yo.js
|
||||||
|
echo -e "#!/usr/bin/lua\nprint(\"hook.d/alert/yo.lua: yo \" .. arg[1])" > ~/hook.d/alert/yo.lua
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_network(){
|
||||||
|
test -n "$BROWSER" || return 0
|
||||||
|
mount -a
|
||||||
|
udhcpc 1>>/var/log/network.log 2>>/var/log/network.log &
|
||||||
|
echo 0 > /proc/sys/kernel/printk
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_binaries
|
||||||
|
setup_browser_dev
|
||||||
|
setup_hook_dirs
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# this daemon allows 'tail -f' on v86 files (which don't persist inode when updated
|
||||||
|
# via javascript)
|
||||||
|
# more info see: https://github.com/copy/v86/issues/1140
|
||||||
|
#
|
||||||
|
# Hopefully as V86 (or my understanding of it) matures, this will be no longer needed
|
||||||
|
|
||||||
|
test -z $2 && { echo "usage: v86pipe <logfile> <namedpipe>"; exit 0; }
|
||||||
|
|
||||||
|
# Start reading from the last line in the log file
|
||||||
|
last_size=0
|
||||||
|
LOG_FILE=$1
|
||||||
|
LOG_PIPE=$2
|
||||||
|
|
||||||
|
test -f $LOG_FILE || touch $LOG_FILE
|
||||||
|
test -p $LOG_PIPE || mkfifo $LOG_PIPE
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
# Get the current size of the file using wc -c (count bytes)
|
||||||
|
current_size=$(wc -c < $LOG_FILE)
|
||||||
|
test $current_size = $last_size || {
|
||||||
|
cat $LOG_FILE > $LOG_PIPE
|
||||||
|
truncate -s 0 $LOG_FILE
|
||||||
|
}
|
||||||
|
last_size=$current_size
|
||||||
|
|
||||||
|
# Sleep for a moment to avoid excessive CPU usage
|
||||||
|
sleep 0.2
|
||||||
|
done
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# a minimalistic terminal muxer
|
||||||
|
|
||||||
|
# Save the original stdout and stderr file descriptors for later restoration
|
||||||
|
exec 3>&1 4>&2
|
||||||
|
|
||||||
|
# Function to check if a session is already running on the given VT
|
||||||
|
is_session_running() {
|
||||||
|
vt_number=$1
|
||||||
|
|
||||||
|
# Check if any process is running on /dev/tty<vt_number>
|
||||||
|
fuser /dev/tty"$vt_number" >/dev/null 2>&1
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to mute the output of a session
|
||||||
|
mute_session() {
|
||||||
|
vt_number=$1
|
||||||
|
if is_session_running "$vt_number"; then
|
||||||
|
# Redirect stdout and stderr of the session to /dev/null
|
||||||
|
exec > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to unmute the current session (restore stdout and stderr)
|
||||||
|
unmute_session() {
|
||||||
|
exec 1>&3 2>&4 # Restore stdout and stderr from file descriptors 3 and 4
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to start a new session if not already running
|
||||||
|
start_or_switch_session() {
|
||||||
|
vt_number=$1
|
||||||
|
|
||||||
|
# Mute all other sessions except the one we're switching to
|
||||||
|
for vt in $(seq 1 12); do # Assuming you have up to 12 VTs, adjust as needed
|
||||||
|
if [ "$vt" != "$vt_number" ]; then
|
||||||
|
mute_session "$vt"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if is_session_running "$vt_number"; then
|
||||||
|
echo "Switching to existing session on VT$vt_number"
|
||||||
|
unmute_session # Unmute the session we're switching to
|
||||||
|
chvt "$vt_number"
|
||||||
|
else
|
||||||
|
echo "Starting a new session on VT$vt_number"
|
||||||
|
openvt -c "$vt_number" -- /bin/sh &
|
||||||
|
sleep 1 # Give the session a moment to start
|
||||||
|
unmute_session # Unmute the new session
|
||||||
|
chvt "$vt_number"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure a session number is provided
|
||||||
|
if [ "$#" -ne 1 ]; then
|
||||||
|
echo "Usage: $0 <session_number>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start or switch to the session
|
||||||
|
start_or_switch_session $1
|
Loading…
Reference in New Issue