Skip to content

Commit d6e91e1

Browse files
mp.input: remove and mitigate race conditions from input.terminate()
This commit ensures that `input.terminate()` can only close input requests made by the same script, and adds a new argument to the input.terminate()` function which allows specifying the specific input request to cancel. Previosuly, there was no way to guarantee that the input request being terminated was the one intended; the asynchronous nature of the API meant that it was always possible (though unlikely) that another client may have activated its own input request while the termination request was in transit. This commit removes the race condition between different scripts calling `input.terminate()` by sending the script name alongside the termination message, and provides a backwards compatible way to terminate specific requests, which removes the race condition for different input requests within the same script. Now, `input.get()` and `input.select()` return an opaque id object, which can be optionally passed into `input.terminate()` to specify which input request should be terminated. One advantage of this approach is that it is backwards compatible; a script passing id values will work without issue on older versions of mpv as `input.terminate()` previously ignored all of its arguments. This approach is based on the behaviour of `mp.command_native_async` and `mp.abort_async_command`.
1 parent 103df92 commit d6e91e1

File tree

5 files changed

+69
-11
lines changed

5 files changed

+69
-11
lines changed

DOCS/man/javascript.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ meta-paths like ``~~/foo`` (other JS file functions do expand meta paths).
196196
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
197197
string/boolean/number)
198198

199-
``mp.input.get(obj)``
199+
``id = mp.input.get(obj)``
200200

201-
``mp.input.select(obj)``
201+
``id = mp.input.select(obj)``
202202

203-
``mp.input.terminate()``
203+
``mp.input.terminate([id])``
204204

205205
``mp.input.log(message, style)``
206206

DOCS/man/lua.rst

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,42 @@ REPL.
975975
among the ones stored for ``input.get()`` calls. Defaults to the calling
976976
script name with ``prompt`` appended.
977977

978-
``input.terminate()``
979-
Close the console.
978+
Returns a table with undefined contents, which can be used as argument for
979+
``input.terminate()``.
980+
981+
``input.terminate([t])``
982+
Closes any currently active input request. This will not close
983+
requests made by other scripts.
984+
985+
If the return value of an ``input.get()`` or ``input.select()``
986+
request is passed in as the first argument, then only that specific request
987+
will be closed, preventing race conditions for scripts that make multiple
988+
requests.
989+
990+
Example:
991+
992+
::
993+
994+
local id, timer
995+
id = input.get({
996+
prompt = "Open File:\n",
997+
history_path = "~~state/open-file-history",
998+
opened = function()
999+
timer = mp.add_timeout(20, function()
1000+
input.terminate(id)
1001+
end)
1002+
end,
1003+
edited = function()
1004+
timer:kill()
1005+
timer:resume()
1006+
end,
1007+
submit = function(path)
1008+
mp.commandv("loadfile", path)
1009+
end,
1010+
closed = function()
1011+
timer:kill()
1012+
end,
1013+
})
9801014

9811015
``input.log(message, style, terminal_style)``
9821016
Add a line to the log buffer. ``style`` can contain additional ASS tags to
@@ -1027,6 +1061,9 @@ REPL.
10271061
``keep_open``
10281062
Whether to keep the console open on submit. Defaults to ``false``.
10291063

1064+
Returns a table with undefined contents, which can be used as argument for
1065+
``input.terminate()``.
1066+
10301067
Example:
10311068

10321069
::

player/javascript/defaults.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,16 @@ mp.input = {
684684

685685
mp.commandv("script-message-to", "console", "get-input",
686686
mp.script_name, handler_id, JSON.stringify(t));
687+
688+
return {
689+
handler_id: handler_id
690+
}
687691
},
688-
terminate: function () {
689-
mp.commandv("script-message-to", "console", "disable");
692+
terminate: function (t) {
693+
mp.commandv("script-message-to", "console", "disable", JSON.stringify({
694+
script_name: mp.script_name,
695+
handler_id: t ? t.handler_id : undefined,
696+
}));
690697
},
691698
log: function (message, style, terminal_style) {
692699
mp.commandv("script-message-to", "console", "log", JSON.stringify({

player/lua/console.lua

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,8 +1659,15 @@ set_active = function (active)
16591659
render()
16601660
end
16611661

1662-
mp.register_script_message("disable", function()
1663-
set_active(false)
1662+
mp.register_script_message("disable", function(message)
1663+
message = utils.parse_json(message)
1664+
1665+
if not message
1666+
or not message.handler_id and message.script_name == input_caller
1667+
or message.script_name == input_caller and message.handler_id == input_caller_handler
1668+
then
1669+
set_active(false)
1670+
end
16641671
end)
16651672

16661673
mp.register_script_message("get-input", function (script_name, handler_id, args)

player/lua/input.lua

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,19 @@ function input.get(t)
6161
local handler_id = register_event_handler(t)
6262
mp.commandv("script-message-to", "console", "get-input",
6363
mp.get_script_name(), handler_id, utils.format_json(get_non_callbacks(t)))
64+
65+
return {
66+
handler_id = handler_id
67+
}
6468
end
6569

6670
input.select = input.get
6771

68-
function input.terminate()
69-
mp.commandv("script-message-to", "console", "disable")
72+
function input.terminate(t)
73+
mp.commandv("script-message-to", "console", "disable", utils.format_json({
74+
script_name = mp.get_script_name(),
75+
handler_id = t and t.handler_id
76+
}))
7077
end
7178

7279
function input.log(message, style, terminal_style)

0 commit comments

Comments
 (0)