Skip to content

Commit d6547fc

Browse files
committed
patch 7.4.1483
Problem: A one-time callback is not used for a raw channel. Solution: Use a one-time callback when it exists.
1 parent da94fdf commit d6547fc

4 files changed

Lines changed: 101 additions & 17 deletions

File tree

src/channel.c

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,23 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv)
13901390
}
13911391
}
13921392

1393+
static void
1394+
invoke_one_time_callback(
1395+
channel_T *channel,
1396+
cbq_T *cbhead,
1397+
cbq_T *item,
1398+
typval_T *argv)
1399+
{
1400+
ch_logs(channel, "Invoking one-time callback %s",
1401+
(char *)item->cq_callback);
1402+
/* Remove the item from the list first, if the callback
1403+
* invokes ch_close() the list will be cleared. */
1404+
remove_cb_node(cbhead, item);
1405+
invoke_callback(channel, item->cq_callback, argv);
1406+
vim_free(item->cq_callback);
1407+
vim_free(item);
1408+
}
1409+
13931410
/*
13941411
* Invoke a callback for "channel"/"part" if needed.
13951412
* Return TRUE when a message was handled, there might be another one.
@@ -1402,14 +1419,19 @@ may_invoke_callback(channel_T *channel, int part)
14021419
typval_T argv[CH_JSON_MAX_ARGS];
14031420
int seq_nr = -1;
14041421
ch_mode_T ch_mode = channel->ch_part[part].ch_mode;
1422+
cbq_T *cbhead = &channel->ch_part[part].ch_cb_head;
1423+
cbq_T *cbitem = cbhead->cq_next;
14051424
char_u *callback = NULL;
14061425
buf_T *buffer = NULL;
14071426

14081427
if (channel->ch_nb_close_cb != NULL)
14091428
/* this channel is handled elsewhere (netbeans) */
14101429
return FALSE;
14111430

1412-
if (channel->ch_part[part].ch_callback != NULL)
1431+
/* use a message-specific callback, part callback or channel callback */
1432+
if (cbitem != NULL)
1433+
callback = cbitem->cq_callback;
1434+
else if (channel->ch_part[part].ch_callback != NULL)
14131435
callback = channel->ch_part[part].ch_callback;
14141436
else
14151437
callback = channel->ch_callback;
@@ -1525,27 +1547,18 @@ may_invoke_callback(channel_T *channel, int part)
15251547

15261548
if (seq_nr > 0)
15271549
{
1528-
cbq_T *head = &channel->ch_part[part].ch_cb_head;
1529-
cbq_T *item = head->cq_next;
15301550
int done = FALSE;
15311551

15321552
/* invoke the one-time callback with the matching nr */
1533-
while (item != NULL)
1553+
while (cbitem != NULL)
15341554
{
1535-
if (item->cq_seq_nr == seq_nr)
1555+
if (cbitem->cq_seq_nr == seq_nr)
15361556
{
1537-
ch_logs(channel, "Invoking one-time callback %s",
1538-
(char *)item->cq_callback);
1539-
/* Remove the item from the list first, if the callback
1540-
* invokes ch_close() the list will be cleared. */
1541-
remove_cb_node(head, item);
1542-
invoke_callback(channel, item->cq_callback, argv);
1543-
vim_free(item->cq_callback);
1544-
vim_free(item);
1557+
invoke_one_time_callback(channel, cbhead, cbitem, argv);
15451558
done = TRUE;
15461559
break;
15471560
}
1548-
item = item->cq_next;
1561+
cbitem = cbitem->cq_next;
15491562
}
15501563
if (!done)
15511564
ch_logn(channel, "Dropping message %d without callback", seq_nr);
@@ -1599,11 +1612,18 @@ may_invoke_callback(channel_T *channel, int part)
15991612
}
16001613
}
16011614
}
1615+
16021616
if (callback != NULL)
16031617
{
1604-
/* invoke the channel callback */
1605-
ch_logs(channel, "Invoking channel callback %s", (char *)callback);
1606-
invoke_callback(channel, callback, argv);
1618+
if (cbitem != NULL)
1619+
invoke_one_time_callback(channel, cbhead, cbitem, argv);
1620+
else
1621+
{
1622+
/* invoke the channel callback */
1623+
ch_logs(channel, "Invoking channel callback %s",
1624+
(char *)callback);
1625+
invoke_callback(channel, callback, argv);
1626+
}
16071627
}
16081628
}
16091629
else

src/testdir/test_channel.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ def handle(self):
6262
if decoded[1] == 'hello!':
6363
# simply send back a string
6464
response = "got it"
65+
elif decoded[1].startswith("echo "):
66+
# send back the argument
67+
response = decoded[1][5:]
6568
elif decoded[1] == 'make change':
6669
# Send two ex commands at the same time, before
6770
# replying to the request.

src/testdir/test_channel.vim

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ func Test_server_crash()
257257
call s:run_server('s:server_crash')
258258
endfunc
259259

260+
"""""""""
261+
260262
let s:reply = ""
261263
func s:Handler(chan, msg)
262264
unlet s:reply
@@ -290,6 +292,61 @@ func Test_channel_handler()
290292
unlet s:chopt.callback
291293
endfunc
292294

295+
"""""""""
296+
297+
let s:reply1 = ""
298+
func s:HandleRaw1(chan, msg)
299+
unlet s:reply1
300+
let s:reply1 = a:msg
301+
endfunc
302+
303+
let s:reply2 = ""
304+
func s:HandleRaw2(chan, msg)
305+
unlet s:reply2
306+
let s:reply2 = a:msg
307+
endfunc
308+
309+
let s:reply3 = ""
310+
func s:HandleRaw3(chan, msg)
311+
unlet s:reply3
312+
let s:reply3 = a:msg
313+
endfunc
314+
315+
func s:raw_one_time_callback(port)
316+
let handle = ch_open('localhost:' . a:port, s:chopt)
317+
if ch_status(handle) == "fail"
318+
call assert_false(1, "Can't open channel")
319+
return
320+
endif
321+
call ch_setoptions(handle, {'mode': 'raw'})
322+
323+
" The message are sent raw, we do our own JSON strings here.
324+
call ch_sendraw(handle, "[1, \"hello!\"]", {'callback': 's:HandleRaw1'})
325+
sleep 10m
326+
call assert_equal("[1, \"got it\"]", s:reply1)
327+
call ch_sendraw(handle, "[2, \"echo something\"]", {'callback': 's:HandleRaw2'})
328+
call ch_sendraw(handle, "[3, \"wait a bit\"]", {'callback': 's:HandleRaw3'})
329+
sleep 10m
330+
call assert_equal("[2, \"something\"]", s:reply2)
331+
" wait for up to 500 msec for the 200 msec delayed reply
332+
for i in range(50)
333+
sleep 10m
334+
if s:reply3 != ''
335+
break
336+
endif
337+
endfor
338+
call assert_equal("[3, \"waited\"]", s:reply3)
339+
endfunc
340+
341+
func Test_raw_one_time_callback()
342+
call ch_logfile('channellog', 'w')
343+
call ch_log('Test_raw_one_time_callback()')
344+
call s:run_server('s:raw_one_time_callback')
345+
call ch_logfile('')
346+
endfunc
347+
348+
"""""""""
349+
293350
" Test that trying to connect to a non-existing port fails quickly.
294351
func Test_connect_waittime()
295352
call ch_log('Test_connect_waittime()')
@@ -325,6 +382,8 @@ func Test_connect_waittime()
325382
endtry
326383
endfunc
327384

385+
"""""""""
386+
328387
func Test_raw_pipe()
329388
if !has('job')
330389
return

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,8 @@ static char *(features[]) =
743743

744744
static int included_patches[] =
745745
{ /* Add new patch number below this line */
746+
/**/
747+
1483,
746748
/**/
747749
1482,
748750
/**/

0 commit comments

Comments
 (0)