add better support for ports: `open_port`, `port_command`, & others?
port_command/2 / port_command/3
and a probably better-formed receive for ffi purposes, my understanding is currently process.receive does no type validation and you have to hope that it matches the shape you're expecting, which is fine when it's only used for inter-gleam RPC but I'm trying to represent these pieces of data erlang's open_port might send:
{Port, {data, Data}}
{Port, {exit_status, Status}}
{Port, eof}
{Port, closed}
{Port, {data, {eol | noeol, Line}}} ???
and maybe others. it's kind of hard to find docs for what open_port subprocesses send back up. going off of https://runebook.dev/en/docs/erlang/doc/reference_manual/ports "Messages Received From a Port" a bit.
and, to be clear, these are very representable in gleam. They just require a decode.run() step on an arbitrary piece of data returned by receive, which it's not doing right now and the Subject(Type) api implies an amount of safety that doesn't exist right now. I guess Subject(Dynamic) is what I want?
semi-related to #28, specifically regarding:
As far as the shape of that solution, I'm not really sure. It feels like there should be an "escape hatch" (even if you have to write some Erlang) for when you want to receive some non-Gleam messages with potentially any shape, but still take advantage of Actors and Subjects. Maybe this is possible already and I just haven't figured it out yet.
got an MVP design in #90
Hello! I agree, it would be really fab to have bindings to the ports API in the Gleam ecosystem.
This package doesn't aim to directly expose Erlang APIs as-is, instead we craft APIs more suited to Gleam that take advantage of types and some glue code, to improve the developer experience and to remove any foot-guns and sharp edges. The design in the attached PR takes the faithful-to-Erlang approach and makes it easy to fall victim to the common problems, so it's not ideal for here.
They could be good to have in package you own and publish, and that would be a good place to experiment and explore Gleam-y designs that improve on the Erlang API.
If you are interested in running OS subprocesses generally the existing packages may be sufficient for your needs:
- https://hexdocs.pm/shellout
- https://hexdocs.pm/gleamyshell There may be others too that I'm not aware of.
Hi! Thanks for the feedback
The design in the attached PR takes the faithful-to-Erlang approach and makes it easy to fall victim to the common problems, so it's not ideal for here.
I'm very open to feedback, will take a look at some other code within the repo to try to figure out what you're talking about, but can appreciate pointers too. It looks like the biggest thing that's being done with this lib's wrapper within ffi is regarding errors, which I've updated.
some other things I could consider that would make things more gleam-like:
- representing mutually exclusive args with sum types, a-la
Packet(Int)vsStreamvsLine(Int)oruse_stdiovsnouse_stdio(even though erlang's not raising an error when I use both of these together??) - somehow representing bounded number types within the type system?
Packet(Int)only accepts 1, 2, or 4 - split up args into types dependent on
PortName. a lot of args are only valid underspawn_executable(args,arg0), or bothspawn_executableandspawn(exit_status,cd,env,use_stdio,nouse_stdio, - maybe we just don't allow
spawnentirely, deferring tospawn_driverorspawn_executabledepending on what you want. makes things easier. I guessspawnis doing a few other things, like PATH lookup and argument separation. - maybe just ignore
fdfor now until a usecase comes along. - maybe use a builder style for construction the objects. a-la
.use_stdio(true),message_format(Packet(Int) | Stream | Line(Int))
They could be good to have in package you own and publish, and that would be a good place to experiment and explore Gleam-y designs that improve on the Erlang API.
I appreciate it, I'm mostly just working on this code as a necessity for a greater project and don't really care to go down the path of publishing my own things, putting it in here / in the PR for others to use. I'm using the gleam package fork support with erlang = { git= "https://github.com/mjsir911/erlang.git", ref="main" }, and invite others to do the same, although it's going to be annoying and outdated because the preference is definitely upstreaming it into the canonical gleam <-> erlang library
doubly so when I want to depend on things like gleam_erlang_ffi:identity and test how the open_port stuff interacts with a lot of the process tooling like receive and maybe select*
If you wouldn't like to give me pointers about creating a PR that "crafts APIs more suited to Gleam", we can close both this issue and the PR and then I can come back later with a fully written out proposal?
Cheers,
One of the main things I'd like to fix is how easy it is to accidentally create orphaned processes, as it's one of the most common problems people face when using ports. Elixir's documentation has some good information here: https://hexdocs.pm/elixir/main/Port.html#module-orphan-operating-system-processes
All your ideas there sound like things worth exploring!