Skip to content

Commit 2aa727b

Browse files
CogentRedTesterkasper93
authored andcommitted
mp.input: send buffer ids with logs to avoid race conditions
This commit modifies the log methods in mp.input to always send the id of the latest `input.get()` request with log entries. Previously, the log methods applied to whichever input request happened to be open when the log message was received. Even when scripts used these methods correctly, there was the risk of sending a log to the wrong log buffer if the active input request changed while the log message was in transit; a race condition. Now the id of the latest `input.get()` request is sent alongside the log messages, preventing data races between scripts while also preventing those logs from being discarded.
1 parent 3ed9b79 commit 2aa727b

4 files changed

Lines changed: 72 additions & 31 deletions

File tree

DOCS/man/lua.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -980,16 +980,18 @@ REPL.
980980
requests made by other scripts.
981981

982982
``input.log(message, style, terminal_style)``
983-
Add a line to the log buffer. ``style`` can contain additional ASS tags to
984-
apply to ``message``, and ``terminal_style`` can contain escape sequences
985-
that are used when the console is displayed in the terminal.
983+
Add a line to the log buffer of the latest ``input.get()`` request.
984+
``style`` can contain additional ASS tags to apply to ``message``,
985+
and ``terminal_style`` can contain escape sequences that are used
986+
when the console is displayed in the terminal.
986987

987988
``input.log_error(message)``
988-
Helper to add a line to the log buffer with the same color as the one used
989+
Helper to add an error line to the log buffer of the latest ``input.get()``
990+
request. The line is styled with the same color as the one used
989991
for commands that error. Useful when the user submits invalid input.
990992

991993
``input.set_log(log)``
992-
Replace the entire log buffer.
994+
Replace the entire log buffer of the latest ``input.get()`` request.
993995

994996
``log`` is a table of strings, or tables with ``text``, ``style`` and
995997
``terminal_style`` keys.

player/javascript/defaults.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ mp.options = { read_options: read_options };
655655
*********************************************************************/
656656
var input_handle_counter = 0;
657657
var latest_handler_id;
658+
var latest_log_id;
658659

659660
function register_event_handler(t) {
660661
var handler_id = "input-event/" + input_handle_counter++;
@@ -686,13 +687,19 @@ function register_event_handler(t) {
686687
return handler_id;
687688
}
688689

690+
function input_request(t) {
691+
t.has_completions = t.complete !== undefined;
692+
t.client_name = mp.script_name;
693+
t.handler_id = register_event_handler(t);
694+
695+
mp.commandv("script-message-to", "console", "get-input", JSON.stringify(t));
696+
}
697+
689698
mp.input = {
690699
get: function(t) {
691-
t.has_completions = t.complete !== undefined;
692-
t.client_name = mp.script_name;
693-
t.handler_id = register_event_handler(t);
694-
695-
mp.commandv("script-message-to", "console", "get-input", JSON.stringify(t));
700+
t.id = t.id || mp.script_name + (t.prompt || "");
701+
latest_log_id = t.id;
702+
return input_request(t);
696703
},
697704
terminate: function () {
698705
mp.commandv("script-message-to", "console", "disable", JSON.stringify({
@@ -701,21 +708,27 @@ mp.input = {
701708
},
702709
log: function (message, style, terminal_style) {
703710
mp.commandv("script-message-to", "console", "log", JSON.stringify({
711+
log_id: latest_log_id,
704712
text: message,
705713
style: style,
706714
terminal_style: terminal_style,
707715
}));
708716
},
709717
log_error: function (message) {
710-
mp.commandv("script-message-to", "console", "log",
711-
JSON.stringify({ text: message, error: true }));
718+
mp.commandv("script-message-to", "console", "log", JSON.stringify({
719+
log_id: latest_log_id,
720+
text: message,
721+
error: true,
722+
}));
712723
},
713724
set_log: function (log) {
714-
mp.commandv("script-message-to", "console", "set-log",
715-
JSON.stringify(log));
725+
if (latest_log_id) {
726+
mp.commandv("script-message-to", "console", "set-log",
727+
latest_log_id, JSON.stringify(log));
728+
}
716729
}
717730
}
718-
mp.input.select = mp.input.get
731+
mp.input.select = input_request;
719732

720733
/**********************************************************************
721734
* various

player/lua/console.lua

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ mp.register_script_message("get-input", function (args)
17101710
else
17111711
selectable_items = nil
17121712
unbind_mouse()
1713-
id = args.id or args.client_name .. prompt
1713+
id = args.id
17141714
log_offset = 0
17151715
completion_buffer = {}
17161716
autoselect_completion = args.autoselect_completion
@@ -1740,8 +1740,13 @@ end)
17401740

17411741
-- Add a line to the log buffer
17421742
mp.register_script_message("log", function (message)
1743-
local log_buffer = log_buffers[id]
1744-
message = utils.parse_json(message)
1743+
message = utils.parse_json(message or "")
1744+
if not message or not message.log_id then
1745+
return
1746+
end
1747+
1748+
local log_buffer = log_buffers[message.log_id]
1749+
if not log_buffer then return end
17451750

17461751
log_buffer[#log_buffer + 1] = {
17471752
text = message.text,
@@ -1754,7 +1759,7 @@ mp.register_script_message("log", function (message)
17541759
table.remove(log_buffer, 1)
17551760
end
17561761

1757-
if not open then
1762+
if not open or message.log_id ~= id then
17581763
return
17591764
end
17601765

@@ -1770,9 +1775,13 @@ mp.register_script_message("log", function (message)
17701775
end
17711776
end)
17721777

1773-
mp.register_script_message("set-log", function (log)
1778+
mp.register_script_message("set-log", function (log_id, log)
1779+
if not log_id or not log then
1780+
return
1781+
end
1782+
17741783
log = utils.parse_json(log)
1775-
log_buffers[id] = {}
1784+
log_buffers[log_id] = {}
17761785

17771786
for i = 1, #log do
17781787
if type(log[i]) == "table" then
@@ -1789,7 +1798,9 @@ mp.register_script_message("set-log", function (log)
17891798
end
17901799
end
17911800

1792-
render()
1801+
if log_id == id then
1802+
render()
1803+
end
17931804
end)
17941805

17951806
mp.register_script_message("complete", function (message)

player/lua/input.lua

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ local input = {}
2020

2121
local handle_counter = 0
2222
local latest_handler_id
23+
local latest_log_id
2324

2425
local function get_non_callbacks(t)
2526
local non_callbacks = {}
@@ -67,7 +68,7 @@ local function register_event_handler(t)
6768
return handler_id
6869
end
6970

70-
function input.get(t)
71+
local function input_request(t)
7172
t.has_completions = t.complete ~= nil
7273
t.client_name = mp.get_script_name()
7374
t.handler_id = register_event_handler(t)
@@ -76,7 +77,14 @@ function input.get(t)
7677
utils.format_json(get_non_callbacks(t)))
7778
end
7879

79-
input.select = input.get
80+
function input.get(t)
81+
-- input.select does not support log buffers, so cannot override the latest id.
82+
t.id = t.id or mp.get_script_name()..(t.prompt or "")
83+
latest_log_id = t.id
84+
return input_request(t)
85+
end
86+
87+
input.select = input_request
8088

8189
function input.terminate()
8290
mp.commandv("script-message-to", "console", "disable", utils.format_json({
@@ -86,19 +94,26 @@ end
8694

8795
function input.log(message, style, terminal_style)
8896
mp.commandv("script-message-to", "console", "log", utils.format_json({
89-
text = message,
90-
style = style,
91-
terminal_style = terminal_style,
92-
}))
97+
log_id = latest_log_id,
98+
text = message,
99+
style = style,
100+
terminal_style = terminal_style,
101+
}))
93102
end
94103

95104
function input.log_error(message)
96-
mp.commandv("script-message-to", "console", "log",
97-
utils.format_json({ text = message, error = true }))
105+
mp.commandv("script-message-to", "console", "log", utils.format_json({
106+
log_id = latest_log_id,
107+
text = message,
108+
error = true,
109+
}))
98110
end
99111

100112
function input.set_log(log)
101-
mp.commandv("script-message-to", "console", "set-log", utils.format_json(log))
113+
if latest_log_id then
114+
mp.commandv("script-message-to", "console", "set-log",
115+
latest_log_id, utils.format_json(log))
116+
end
102117
end
103118

104119
return input

0 commit comments

Comments
 (0)