@@ -54,38 +54,52 @@ defmodule Yex.Doc do
5454 """
5555 defmacro run_in_worker_process ( doc , do: block ) do
5656 quote do
57- case unquote ( doc ) . worker_pid do
58- pid when pid == self ( ) ->
59- unquote ( block )
60-
61- nil ->
62- raise RuntimeError , "Document has no worker process assigned"
63-
64- worker_pid ->
65- wrapped_fun = fn ->
66- try do
67- unquote ( block )
68- rescue
69- e ->
70- { Yex.Doc , :reraise , e , __STACKTRACE__ }
71- end
72- end
57+ Yex.Doc . run_in_worker_process_fn ( unquote ( doc ) , fn ->
58+ unquote ( block )
59+ end )
60+ end
61+ end
62+
63+ @ spec run_in_worker_process_fn (
64+ atom ( ) | % { : worker_pid => any ( ) , optional ( any ( ) ) => any ( ) } ,
65+ any ( )
66+ ) :: any ( )
67+ def run_in_worker_process_fn ( doc , fun ) do
68+ case doc . worker_pid do
69+ pid when pid == self ( ) ->
70+ result = fun . ( )
71+ handle_on_update_handler ( )
72+ result
7373
74- # When a Doc or SharedType operation is performed from a process different from the
75- # process that created the Doc, a message like {Yex.Doc, :run, fun} is sent to the
76- # creator process via GenServer.call and the processing is delegated to that process.
77- # If you encounter a GenServer.call timeout, this delegation mechanism may be the cause.
78- case GenServer . call (
79- worker_pid ,
80- { Yex.Doc , :run , wrapped_fun }
81- ) do
82- { Yex.Doc , :reraise , e , stacktrace } ->
83- reraise e , stacktrace
84-
85- result ->
86- result
74+ nil ->
75+ raise RuntimeError , "Document has no worker process assigned"
76+
77+ worker_pid ->
78+ wrapped_fun = fn ->
79+ try do
80+ result = fun . ( )
81+ handle_on_update_handler ( )
82+ result
83+ rescue
84+ e ->
85+ { Yex.Doc , :reraise , e , __STACKTRACE__ }
8786 end
88- end
87+ end
88+
89+ # When a Doc or SharedType operation is performed from a process different from the
90+ # process that created the Doc, a message like {Yex.Doc, :run, fun} is sent to the
91+ # creator process via GenServer.call and the processing is delegated to that process.
92+ # If you encounter a GenServer.call timeout, this delegation mechanism may be the cause.
93+ case GenServer . call (
94+ worker_pid ,
95+ { Yex.Doc , :run , wrapped_fun }
96+ ) do
97+ { Yex.Doc , :reraise , e , stacktrace } ->
98+ reraise e , stacktrace
99+
100+ result ->
101+ result
102+ end
89103 end
90104 end
91105
@@ -285,6 +299,82 @@ defmodule Yex.Doc do
285299 end
286300 end
287301
302+ def on_subdocs ( % __MODULE__ { } = doc , handler ) do
303+ result =
304+ run_in_worker_process ( doc ,
305+ do: Yex.Nif . doc_monitor_subdocs ( doc , self ( ) , { Yex.CallbackHandler , handler } )
306+ )
307+
308+ case result do
309+ { :ok , sub } ->
310+ { :ok , Yex.Subscription . register ( sub ) }
311+
312+ error ->
313+ error
314+ end
315+ end
316+
317+ @ spec on_update ( Yex.Doc . t ( ) , handler :: ( update :: binary ( ) , origin :: term ( ) -> nil ) ) :: any ( )
318+ def on_update ( % __MODULE__ { } = doc , handler ) do
319+ on_update_v1 ( doc , handler )
320+ end
321+
322+ @ spec on_update_v1 ( Yex.Doc . t ( ) , handler :: ( update :: binary ( ) , origin :: term ( ) -> nil ) ) ::
323+ any ( )
324+ def on_update_v1 ( % __MODULE__ { } = doc , handler ) do
325+ result =
326+ run_in_worker_process ( doc ,
327+ do: Yex.Nif . doc_monitor_update_v1 ( doc , self ( ) , { Yex.CallbackHandler , handler } )
328+ )
329+
330+ case result do
331+ { :ok , sub } ->
332+ { :ok , Yex.Subscription . register ( sub ) }
333+
334+ error ->
335+ error
336+ end
337+ end
338+
339+ @ spec on_update_v2 ( Yex.Doc . t ( ) , handler :: ( update :: binary ( ) , origin :: term ( ) -> nil ) ) ::
340+ any ( )
341+ def on_update_v2 ( % __MODULE__ { } = doc , handler ) do
342+ result =
343+ run_in_worker_process ( doc ,
344+ do: Yex.Nif . doc_monitor_update_v2 ( doc , self ( ) , { Yex.CallbackHandler , handler } )
345+ )
346+
347+ case result do
348+ { :ok , sub } ->
349+ { :ok , Yex.Subscription . register ( sub ) }
350+
351+ error ->
352+ error
353+ end
354+ end
355+
356+ defp handle_on_update_handler ( ) do
357+ receive do
358+ { _ , arg1 , { Yex.CallbackHandler , handler } } ->
359+ handler . ( arg1 )
360+ handle_on_update_handler ( )
361+
362+ { :subdocs , event , origin , { Yex.CallbackHandler , handler } } ->
363+ handler . ( event , origin )
364+ handle_on_update_handler ( )
365+
366+ { _ , arg1 , arg2 , { Yex.CallbackHandler , handler } } ->
367+ handler . ( arg1 , arg2 )
368+ handle_on_update_handler ( )
369+
370+ { _ , _ref , event , origin , { Yex.ObserveCallbackHandler , handler } } ->
371+ handler . ( event , origin )
372+ handle_on_update_handler ( )
373+ after
374+ 0 -> :ok
375+ end
376+ end
377+
288378 defp cur_txn ( % __MODULE__ { reference: ref } ) do
289379 Process . get ( ref , nil )
290380 end
0 commit comments