This is for running "tidal-as-a-service" (for collaborative editors) in a somewhat safer way.
This package contains a library (safe-tidal
)
and an executable (safe-tidal-cli
).
The indented use case is with https://github.com/munshkr/flok :
node packages/repl/bin/flok-repl.js -H ws://localhost:3000 -s <token> -n tidal -- safe-tidal-cli
cabal install tidal safe-tidal --lib # installs libraries
cabal install safe-tidal --constraint 'tidal==1.4.9' # installs executable
beware of cabal env-file hell, cf. #5
The executable safe-tidal-cli
aims to provide
- the essential subset of the functionality
of a
ghci
session withBootTidal
loaded, - while being extra resilient to improper input.
safe-tidal-cli
will connect to SuperDirt
on startup.
Then it accepts text blocks on stdin
where blocks are separated by empty lines.
In the intended use case, a block will be sent
by the flok
server each time a client hits Ctrl-Enter
.
Each block contains one expression, e.g., d1 $ s "bd"
,
which safe-tidal-cli
will evaluate (by the embedded ghci
).
The resulting value is an action that gets executed
(by the embedded tidal
). The execution involves
communication with the SuperDirt
/SuperCollider
back-end.
These expressions appear to be of type IO ()
but actually we have re-defined d1
etc.
to use a safe wrapper
that only allows Tidal's top-level operators
(cf. #8)
and probibits any other form of IO
.
You can write any expression of that type, e.g.,
d1 $ s "bd"
let x = .. in do { d1 $ ... ; d2 $ ... }
hush
safe-tidal-cli
will reject any expression of any other type,
in particular, of type IO a
,
so no-one can execute readFile "/etc/passwd"
.
It will also reject harmless expressions like 1+2
.
We may want to allow that.
safe-tidal-cli
rejects all non-expressions.
That means you cannot interact with the state
of the ghci
session. You cannot write
- imports (
import System.IO.Unsafe
), - definitions (
let foo = bar
), - queries (
:type
,:info
,:doc
).
We may lift the latter restriction.
safe-tidal-cli
will exit when stdin
is closed
and all blocks are processed.
The idea of using the GHC API (via hint
) for tidal
is not new,
cf. https://github.com/tidalcycles/tidali/blob/master/src/Main.hs
The idea of wrapping IO
to make it safe,
is also not new (TODO: references?).
Perhaps the combination is new.