New protocol and configuration from Tony
The uri_matcher now makes a proper relay over stdio to the dataspace shared with xdg_open. Fix ehmry/xdg_open_ng#3
This commit is contained in:
parent
8d08655758
commit
a959565fb5
|
@ -4,6 +4,8 @@ An `xdg-open` replacement that uses Syndicate and PCRE pattern matching to open
|
||||||
|
|
||||||
There are two utilites, `uri_runner` and `xdg-open`; both expect to be able to connect to a shared Syndicate dataspace via a UNIX socket at `$SYNDICATE_SOCK` otherwise `$XDG_RUNTIME_DIR/dataspace`. The `xdg-open` component has no other configuration. The `uri_runner` component is intended to be managed by the [Syndicate server](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs) thru which it receives configuration, see [uri_runner.pr](./uri_runner.pr) as an example.
|
There are two utilites, `uri_runner` and `xdg-open`; both expect to be able to connect to a shared Syndicate dataspace via a UNIX socket at `$SYNDICATE_SOCK` otherwise `$XDG_RUNTIME_DIR/dataspace`. The `xdg-open` component has no other configuration. The `uri_runner` component is intended to be managed by the [Syndicate server](https://git.syndicate-lang.org/syndicate-lang/syndicate-rs) thru which it receives configuration, see [uri_runner.pr](./uri_runner.pr) as an example.
|
||||||
|
|
||||||
|
The [protocol.nim](./src/protocol.nim) file is generated from the [protocol.prs](./protocol.prs) schema, a [Tupfile](https://gittup.org/tup/) file is provided to do this.
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Pattern back-references in commands
|
- Pattern back-references in commands
|
||||||
- Fallback commands?
|
- Fallback commands?
|
||||||
|
|
|
@ -2,8 +2,6 @@ version 1 .
|
||||||
|
|
||||||
XdgOpen = <xdg-open @uris [string ...]> .
|
XdgOpen = <xdg-open @uris [string ...]> .
|
||||||
|
|
||||||
Action = [@pat string @cmd [string ...] ] .
|
UriRunnerConfig = ListenOn / ActionHandler .
|
||||||
|
ListenOn = <listen-on @dataspace #!any> .
|
||||||
Attrs = { actions: [Action ...] } .
|
ActionHandler = <action-handler @pat string @cmd [string ...]> .
|
||||||
|
|
||||||
UriRunnerConfig = <config @attrs Attrs> .
|
|
||||||
|
|
|
@ -4,26 +4,34 @@ import
|
||||||
|
|
||||||
type
|
type
|
||||||
XdgOpen* {.preservesRecord: "xdg-open".} = object
|
XdgOpen* {.preservesRecord: "xdg-open".} = object
|
||||||
`data`*: seq[string]
|
`uris`*: seq[string]
|
||||||
|
|
||||||
Attrs*[E] {.preservesDictionary.} = ref object
|
UriRunnerConfigKind* {.pure.} = enum
|
||||||
`actions`*: seq[Action]
|
`ListenOn`, `ActionHandler`
|
||||||
|
`UriRunnerConfig`*[E] {.preservesOr.} = ref object
|
||||||
|
case orKind*: UriRunnerConfigKind
|
||||||
|
of UriRunnerConfigKind.`ListenOn`:
|
||||||
|
`listenon`*: ListenOn[E]
|
||||||
|
|
||||||
UriRunnerConfig*[E] {.preservesRecord: "config".} = ref object
|
of UriRunnerConfigKind.`ActionHandler`:
|
||||||
`attrs`*: Attrs[E]
|
`actionhandler`*: ActionHandler
|
||||||
|
|
||||||
Action* {.preservesTuple.} = object
|
|
||||||
|
ListenOn*[E] {.preservesRecord: "listen-on".} = ref object
|
||||||
|
`dataspace`*: Preserve[E]
|
||||||
|
|
||||||
|
ActionHandler* {.preservesRecord: "action-handler".} = object
|
||||||
`pat`*: string
|
`pat`*: string
|
||||||
`cmd`*: seq[string]
|
`cmd`*: seq[string]
|
||||||
|
|
||||||
proc `$`*[E](x: Attrs[E] | UriRunnerConfig[E]): string =
|
proc `$`*[E](x: UriRunnerConfig[E] | ListenOn[E]): string =
|
||||||
`$`(toPreserve(x, E))
|
`$`(toPreserve(x, E))
|
||||||
|
|
||||||
proc encode*[E](x: Attrs[E] | UriRunnerConfig[E]): seq[byte] =
|
proc encode*[E](x: UriRunnerConfig[E] | ListenOn[E]): seq[byte] =
|
||||||
encode(toPreserve(x, E))
|
encode(toPreserve(x, E))
|
||||||
|
|
||||||
proc `$`*(x: XdgOpen | Action): string =
|
proc `$`*(x: XdgOpen | ActionHandler): string =
|
||||||
`$`(toPreserve(x))
|
`$`(toPreserve(x))
|
||||||
|
|
||||||
proc encode*(x: XdgOpen | Action): seq[byte] =
|
proc encode*(x: XdgOpen | ActionHandler): seq[byte] =
|
||||||
encode(toPreserve(x))
|
encode(toPreserve(x))
|
||||||
|
|
|
@ -1,37 +1,27 @@
|
||||||
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[asyncdispatch, deques, re, streams, strutils, os, osproc]
|
import std/[asyncdispatch, deques, re, streams, strutils, osproc]
|
||||||
import preserves
|
import preserves
|
||||||
import syndicate, syndicate/capabilities
|
import syndicate
|
||||||
import ./protocol
|
import ./protocol
|
||||||
|
|
||||||
proc unixSocketPath: string =
|
bootDataspace("main") do (root: Ref; turn: var Turn):
|
||||||
result = getEnv("SYNDICATE_SOCK")
|
|
||||||
if result == "":
|
|
||||||
result = getEnv("XDG_RUNTIME_DIR", "/run/user/1000") / "dataspace"
|
|
||||||
|
|
||||||
proc mintCap: SturdyRef =
|
|
||||||
var key: array[16, byte]
|
|
||||||
mint(key, "syndicate")
|
|
||||||
|
|
||||||
bootDataspace("main") do (ds: Ref; turn: var Turn):
|
|
||||||
var
|
var
|
||||||
actions: seq[tuple[regex: Regex; cmd: string; args: seq[string]]]
|
actions: seq[tuple[regex: Regex; cmd: string; args: seq[string]]]
|
||||||
children: Deque[Process]
|
children: Deque[Process]
|
||||||
|
|
||||||
connectStdio(ds, turn)
|
connectStdio(root, turn)
|
||||||
|
|
||||||
onPublish(turn, ds, ?UriRunnerConfig[Ref]) do (cfg: seq[Action]):
|
onPublish(turn, root, ?ActionHandler) do (pat: string; cmd: seq[string]):
|
||||||
actions.setLen 0
|
# TODO: during
|
||||||
for act in cfg:
|
if cmd.len < 2:
|
||||||
if act.cmd.len < 2:
|
stderr.writeLine "ignoring ", $cmd, " for ", pat
|
||||||
stderr.writeLine "ignoring ", act
|
else:
|
||||||
else:
|
var act = (re(pat, {reIgnoreCase, reStudy}), cmd[0], cmd[1..cmd.high],)
|
||||||
actions.add (re(act.pat, {reIgnoreCase, reStudy}), act.cmd[0], act.cmd[1..act.cmd.high])
|
actions.add act
|
||||||
stderr.writeLine "actions updated"
|
|
||||||
|
|
||||||
connectUnix(turn, unixSocketPath(), mintCap()) do (turn: var Turn; a: Assertion) -> TurnAction:
|
onPublish(turn, root, ?ListenOn[Ref]) do (a: Assertion):
|
||||||
let ds = unembed a
|
let ds = unembed a
|
||||||
onMessage(turn, ds, ?XdgOpen) do (uris: seq[string]):
|
onMessage(turn, ds, ?XdgOpen) do (uris: seq[string]):
|
||||||
while children.len > 0 and not children.peekFirst.running:
|
while children.len > 0 and not children.peekFirst.running:
|
||||||
|
@ -52,6 +42,6 @@ bootDataspace("main") do (ds: Ref; turn: var Turn):
|
||||||
command = act.cmd, args = args, options = {})
|
command = act.cmd, args = args, options = {})
|
||||||
children.addLast child
|
children.addLast child
|
||||||
if not matched:
|
if not matched:
|
||||||
stderr.writeLine "no patterns matched for ", uri
|
stderr.writeLine "no actions matched for ", uri
|
||||||
|
|
||||||
runForever()
|
runForever()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
# SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway
|
||||||
# SPDX-License-Identifier: Unlicense
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[asyncdispatch, os]
|
import std/[asyncdispatch, os]
|
||||||
|
@ -15,14 +15,12 @@ proc mintCap: SturdyRef =
|
||||||
var key: array[16, byte]
|
var key: array[16, byte]
|
||||||
mint(key, "syndicate")
|
mint(key, "syndicate")
|
||||||
|
|
||||||
type XdgOpen {.preservesRecord: "xdg-open".} = object
|
|
||||||
args: seq[string]
|
|
||||||
|
|
||||||
bootDataspace("main") do (ds: Ref; turn: var Turn):
|
bootDataspace("main") do (ds: Ref; turn: var Turn):
|
||||||
let mainFacet = turn.facet
|
let mainFacet = turn.facet
|
||||||
connectUnix(turn, unixSocketPath(), mintCap()) do (turn: var Turn; a: Assertion) -> TurnAction:
|
connectUnix(turn, unixSocketPath(), mintCap()) do (turn: var Turn; a: Assertion) -> TurnAction:
|
||||||
let ds = unembed a
|
let ds = unembed a
|
||||||
message(turn, ds, XdgOpen(args: commandLineParams()))
|
message(turn, ds, XdgOpen(uris: commandLineParams()))
|
||||||
|
stop(turn, mainFacet)
|
||||||
|
|
||||||
for i in 0..7: poll(20)
|
for i in 0..7: poll(20)
|
||||||
# A hack to exit
|
# A hack to exit
|
||||||
|
|
|
@ -11,10 +11,11 @@ let ?root_ds = dataspace
|
||||||
}>
|
}>
|
||||||
|
|
||||||
? <service-object <daemon uri_runner> ?cap> [
|
? <service-object <daemon uri_runner> ?cap> [
|
||||||
$cap <config { actions: [
|
$cap [
|
||||||
["gemini://.*|file:///.*.gmi", ["/run/current-system/sw/bin/kristall" "\\1"]]
|
<listen-on $root_ds>
|
||||||
["http://.*|https://.*|.*html", ["/run/current-system/sw/bin/firefox" "\\1"]]
|
<action-handler "gemini://.*|file:///.*.gmi" ["/run/current-system/sw/bin/kristall" "\\1"]>
|
||||||
["tox:.*|uri:tox:.*", ["/run/current-system/sw/bin/qtox" "\\1"]]
|
<action-handler "http://.*|https://.*|.*html", ["/run/current-system/sw/bin/librewolf" "\\1"]>
|
||||||
[".*\\.avi|.*\\.mp4|.*mkv", ["/run/current-system/sw/bin/mpv" "\\1"]]
|
<action-handler "tox:.*|uri:tox:.*", ["/run/current-system/sw/bin/qtox" "\\1"]>
|
||||||
] } >
|
<action-handler ".*\\.avi|.*\\.mkv|.*\\.mp4", ["/run/current-system/sw/bin/mpv" "\\1"]>
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
author = "Emery"
|
author = "Emery"
|
||||||
description = "A better xdg-open"
|
description = "A better xdg-open"
|
||||||
license = "Unlicense"
|
license = "Unlicense"
|
||||||
|
|
Loading…
Reference in New Issue