Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nested static request #4175

Merged
merged 3 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ Changed:
`nan != x` is always `true`. Use `float.is_nan` to test if a float is `nan`.
- BREAKING: `replaygain` no longer takes `ebu_r128` parameter (#3438).
- BREAKING: assume `replaygain_track_gain` always stores volume in _dB_ (#3438).
- BREAKING: protocols can now check for nested static uri. Typically, this means
that requests for an uri of the form: `annotate:key="value",...:/path/to/file.mp3`
is now considered infallible if `/path/to/file.mp3` can be decoded.
- Added `parents` option of `file.mkdir` (#3600, #3601).
- Added `forced_major_collections` record field to the result of `runtime.gc.stat()` and
`runtime.gc.quick_stat()` (#3783).
Expand Down
16 changes: 16 additions & 0 deletions doc/content/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ for more details.
However, EBU R128 data is now extracted directly from metadata when available.
So `replaygain` cannot control the gain type via this parameter anymore.

### Static requests

Static requests detection can now work with nested requests.

Typically, a request for this URI: `annotate:key="value",...:/path/to/file.mp3` will be
considered static if `/path/to/file.mp3` can be decoded.

Practically, this means that more source will now be considered infallible, for instance
a `single` using the above uri.

In most cases, this should improve the user experience when building new scripts and streaming
systems.

In rare cases where you actually wanted a fallible source, you can still pass `fallible=true` to e.g.
the `single` operator or use the `fallible:` protocol.

### String functions

Some string functions have been updated to account for string encoding. In particular, `string.length` and `string.sub` now assume that their
Expand Down
15 changes: 10 additions & 5 deletions src/core/builtins/builtins_resolvers.ml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ let _ =
{ Playlist_parser.strict; Playlist_parser.parser = fn };
Lang.unit)

let default_static =
Lang.eval ~cache:false ~typecheck:false ~stdlib:`Disabled "fun (_) -> false"

let _ =
let log_p = [("", "", None)] in
let log_t = Lang.fun_t [(false, "", Lang.string_t)] Lang.unit_t in
Expand All @@ -153,11 +156,12 @@ let _ =
Some (Lang.bool false),
Some "if true, file is removed when it is finished." );
( "static",
Lang.bool_t,
Some (Lang.bool false),
Lang.fun_t [(false, "", Lang.string_t)] Lang.bool_t,
Some default_static,
Some
"if true, then requests can be resolved once and for all. Typically, \
static protocols can be used to create infallible sources." );
"When given an uri for the protocol, if it returns `true`, then \
requests can be resolved once and for all. Typically, static \
protocols can be used to create infallible sources." );
( "syntax",
Lang.string_t,
Some (Lang.string "Undocumented"),
Expand Down Expand Up @@ -185,7 +189,8 @@ let _ =
let name = Lang.to_string (Lang.assoc "" 1 p) in
let f = Lang.assoc "" 2 p in
let temporary = Lang.to_bool (List.assoc "temporary" p) in
let static = Lang.to_bool (List.assoc "static" p) in
let static = List.assoc "static" p in
let static s = Lang.to_bool (Lang.apply static [("", Lang.string s)]) in
let doc = Lang.to_string (List.assoc "doc" p) in
let syntax = Lang.to_string (List.assoc "syntax" p) in
Lang.add_protocol ~syntax ~doc ~static name (fun arg ~log timeout ->
Expand Down
21 changes: 21 additions & 0 deletions src/core/doc.ml
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
include Liquidsoap_lang.Doc

(** Documentation for protocols. *)
module Protocol = struct
type t = { name : string; description : string; syntax : string }

let db = ref []

let add ~name ~doc ~syntax =
let p = { name; description = doc; syntax } in
db := p :: !db

let db () = List.sort compare !db
let count () = db () |> List.length

let print_md print =
List.iter
(fun p ->
Printf.ksprintf print "### %s\n\n%s\n\nThe syntax is `%s`.\n\n" p.name
p.description p.syntax)
(db ())
end
3 changes: 1 addition & 2 deletions src/core/lang.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
include Liquidsoap_lang.Lang
include Lang_source
include Lang_encoder.L
module Doc = Liquidsoap_lang.Doc
module Flags = Liquidsoap_lang.Flags
module Http = Liq_http

Expand All @@ -11,7 +10,7 @@ let () = Hooks_implementations.register ()
(** Helpers for defining protocols. *)

let add_protocol ~syntax ~doc ~static name resolver =
Doc.Protocol.add ~name ~doc ~syntax ~static;
Doc.Protocol.add ~name ~doc ~syntax;
let spec = { Request.static; resolve = resolver } in
Plug.register Request.protocols ~doc name spec

Expand Down
2 changes: 1 addition & 1 deletion src/core/lang.mli
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ val apply : ?pos:Liquidsoap_lang.Pos.t list -> value -> env -> value
val add_protocol :
syntax:string ->
doc:string ->
static:bool ->
static:(string -> bool) ->
string ->
Request.resolver ->
unit
Expand Down
7 changes: 6 additions & 1 deletion src/core/protocols/annotate.ml
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,10 @@ let annotate s ~log _ =

let () =
Lang.add_protocol ~doc:"Add metadata to a request"
~syntax:"annotate:key=\"val\",key2=\"val2\",...:uri" ~static:false
~syntax:"annotate:key=\"val\",key2=\"val2\",...:uri"
~static:(fun uri ->
try
let _, uri = parse uri in
Request.is_static uri
with _ -> false)
"annotate" annotate
4 changes: 3 additions & 1 deletion src/core/protocols/mpd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,6 @@ let mpd s ~log _ =
let () =
Lang.add_protocol
~doc:"Finds all files with a tag equal to a given value using mpd."
~syntax:"mpd:tag=value" ~static:false "mpd" mpd
~syntax:"mpd:tag=value"
~static:(fun _ -> false)
"mpd" mpd
6 changes: 3 additions & 3 deletions src/core/request.ml
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ let get_decoder ~ctype r =
(** Plugins registration. *)

type resolver = string -> log:(string -> unit) -> float -> indicator option
type protocol = { resolve : resolver; static : bool }
type protocol = { resolve : resolver; static : string -> bool }

let protocols_doc =
"Methods to get a file. They are the first part of URIs: 'protocol:args'."
Expand All @@ -621,9 +621,9 @@ let is_static s =
if file_exists (home_unrelate s) then true
else (
match parse_uri s with
| Some (proto, _) -> (
| Some (proto, uri) -> (
match Plug.get protocols proto with
| Some handler -> handler.static
| Some handler -> handler.static uri
| None -> false)
| None -> false)

Expand Down
2 changes: 1 addition & 1 deletion src/core/request.mli
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ val from_id : int -> t option
type resolver = string -> log:(string -> unit) -> float -> indicator option

(** A protocol, which can resolve associated URIs. *)
type protocol = { resolve : resolver; static : bool }
type protocol = { resolve : resolver; static : string -> bool }

(** A static request [r] is such that every resolving leads to the same file.
Sometimes, it allows removing useless destroy/create/resolve. *)
Expand Down
27 changes: 0 additions & 27 deletions src/lang/doc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -62,33 +62,6 @@ module Plug = struct
let print_string = print_md
end

(** Documentation for protocols. *)
module Protocol = struct
type t = {
name : string;
description : string;
syntax : string;
static : bool;
}

let db = ref []

let add ~name ~doc ~syntax ~static =
let p = { name; description = doc; syntax; static } in
db := p :: !db

let db () = List.sort compare !db
let count () = db () |> List.length

let print_md print =
List.iter
(fun p ->
let static = if p.static then " This protocol is static." else "" in
Printf.ksprintf print "### %s\n\n%s\n\nThe syntax is `%s`.%s\n\n" p.name
p.description p.syntax static)
(db ())
end

(** Documenentation for values. *)
module Value = struct
(** Documentation flags. *)
Expand Down
37 changes: 27 additions & 10 deletions src/libs/protocols.liq
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,23 @@ protocol.add(
syntax="tmp:uri"
)

# Register fallible
# @flag hidden
def protocol.fallible(~rlog=_, ~maxtime=_, arg) =
arg
end

protocol.add(
"fallible",
protocol.fallible,
doc=
"Mark the given uri as being fallible. This can be used to prevent a request \
or source from being resolved once and for all and considered infallible \
for the duration of the script, typically when debugging.",
static=fun (_) -> false,
syntax="fallible:uri"
)

let settings.protocol.ffmpeg = settings.make.protocol("FFmpeg")
let settings.protocol.ffmpeg.path =
settings.make(
Expand Down Expand Up @@ -651,7 +668,7 @@ def protocol.stereo(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
temporary=true,
"stereo",
protocol.stereo,
Expand All @@ -671,7 +688,7 @@ def protocol.copy(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"copy",
protocol.copy,
doc=
Expand Down Expand Up @@ -699,7 +716,7 @@ def protocol.text2wave(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"text2wave",
protocol.text2wave,
doc=
Expand Down Expand Up @@ -736,7 +753,7 @@ def protocol.pico2wave(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"pico2wave",
protocol.pico2wave,
doc=
Expand Down Expand Up @@ -781,7 +798,7 @@ def protocol.gtts(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"gtts",
protocol.gtts,
doc=
Expand Down Expand Up @@ -819,7 +836,7 @@ def protocol.macos_say(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"macos_say",
protocol.macos_say,
doc=
Expand All @@ -846,7 +863,7 @@ def protocol.say(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"say",
protocol.say,
doc=
Expand Down Expand Up @@ -993,7 +1010,7 @@ def polly_protocol(~rlog=_, ~maxtime=_, text) =
end

protocol.add(
static=true,
static=fun (_) -> true,
"polly",
polly_protocol,
doc=
Expand Down Expand Up @@ -1070,7 +1087,7 @@ def synth_protocol(~rlog=_, ~maxtime=_, text) =
end

protocol.add(
static=true,
static=fun (_) -> true,
temporary=true,
"synth",
synth_protocol,
Expand Down Expand Up @@ -1101,7 +1118,7 @@ def file_protocol(~rlog=_, ~maxtime=_, arg) =
end

protocol.add(
static=true,
static=fun (_) -> true,
temporary=false,
"file",
file_protocol,
Expand Down
1 change: 0 additions & 1 deletion src/runtime/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
*****************************************************************************)

module Runtime = Liquidsoap_lang.Runtime
module Doc = Liquidsoap_lang.Doc
module Environment = Liquidsoap_lang.Environment
module Profiler = Liquidsoap_lang.Profiler
module Queue = Liquidsoap_lang.Queues.Queue
Expand Down
Loading