77namespace realm ::c_api {
88namespace {
99
10+ // THis class represents the timer resource that is returned to the sync client from the
11+ // CAPI implementation details for canceling and deleting the timer resources.
1012struct CAPITimer : sync::SyncSocketProvider::Timer {
1113public:
1214 CAPITimer (realm_userdata_t userdata, int64_t delay_ms, realm_sync_socket_callback_t * handler,
1315 realm_sync_socket_create_timer_func_t create_timer_func,
1416 realm_sync_socket_timer_canceled_func_t cancel_timer_func,
1517 realm_sync_socket_timer_free_func_t free_timer_func)
1618 : m_handler(handler)
19+ , m_userdata(userdata)
1720 , m_timer_create(create_timer_func)
1821 , m_timer_cancel(cancel_timer_func)
1922 , m_timer_free(free_timer_func)
@@ -24,27 +27,65 @@ struct CAPITimer : sync::SyncSocketProvider::Timer {
2427 // / Cancels the timer and destroys the timer instance.
2528 ~CAPITimer ()
2629 {
30+ // Make sure the timer is stopped, if not already
2731 m_timer_cancel (m_userdata, m_timer);
2832 m_timer_free (m_userdata, m_timer);
2933 realm_release (m_handler);
3034 }
3135
32- // / Cancel the timer immediately.
36+ // Cancel the timer immediately - the CAPI implementation will need to call the
37+ // realm_sync_socket_timer_canceled function to notify the sync client that the
38+ // timer has been canceled and must be called in the same execution thread as
39+ // the timer complete.
3340 void cancel () override
3441 {
3542 m_timer_cancel (m_userdata, m_timer);
3643 }
3744
3845private:
46+ // A pointer to the CAPI implementation's timer instance. This is provided by the
47+ // CAPI implementation when the create_timer_func function is called.
3948 realm_sync_socket_timer_t m_timer = nullptr ;
4049
41- realm_userdata_t m_userdata = nullptr ;
50+ // A wrapped reference to the callback function to be called when the timer completes,
51+ // is canceled or an error occurs. This is provided by the Sync Client
4252 realm_sync_socket_callback_t * m_handler = nullptr ;
53+
54+ // These values were originally provided to the socket_provider instance by the CAPI
55+ // implementation when it was created
56+ realm_userdata_t m_userdata = nullptr ;
4357 realm_sync_socket_create_timer_func_t m_timer_create = nullptr ;
4458 realm_sync_socket_timer_canceled_func_t m_timer_cancel = nullptr ;
4559 realm_sync_socket_timer_free_func_t m_timer_free = nullptr ;
4660};
4761
62+ static void realm_sync_socket_op_complete (realm_sync_socket_callback* realm_callback, realm_errno_e status,
63+ const char * reason)
64+ {
65+ if (realm_callback->get () != nullptr ) {
66+ auto complete_status = status == realm_errno_e::RLM_ERR_NONE
67+ ? Status::OK ()
68+ : Status{static_cast <ErrorCodes::Error>(status), reason};
69+ (*(realm_callback->get ()))(complete_status);
70+ // Keep the container, but release the handler so it can't be called twice.
71+ realm_callback->reset ();
72+ }
73+ }
74+
75+ RLM_API void realm_sync_socket_timer_complete (realm_sync_socket_callback* timer_handler, realm_errno_e status,
76+ const char * reason)
77+ {
78+ realm_sync_socket_op_complete (timer_handler, status, reason);
79+ }
80+
81+ RLM_API void realm_sync_socket_timer_canceled (realm_sync_socket_callback* timer_handler)
82+ {
83+ realm_sync_socket_op_complete (timer_handler, RLM_ERR_OPERATION_ABORTED, " Timer canceled" );
84+ }
85+
86+ // This class represents a websocket instance provided by the CAPI implememtation for sending
87+ // and receiving data and connection state from the websocket. This class is used directly by
88+ // the sync client.
4889struct CAPIWebSocket : sync::WebSocketInterface {
4990public:
5091 CAPIWebSocket (realm_userdata_t userdata, realm_sync_socket_connect_func_t websocket_connect_func,
@@ -89,15 +130,24 @@ struct CAPIWebSocket : sync::WebSocketInterface {
89130 }
90131
91132private:
133+ // A pointer to the CAPI implementation's websocket instance. This is provided by
134+ // the m_websocket_connect() function when this websocket instance is created.
92135 realm_sync_socket_websocket_t m_socket = nullptr ;
136+
137+ // A wrapped reference to the websocket observer in the sync client that receives the
138+ // websocket status callbacks. This is provided by the Sync Client.
93139 realm_websocket_observer_t * m_observer = nullptr ;
94- realm_userdata_t m_userdata = nullptr ;
95140
141+ // These values were originally provided to the socket_provider instance by the CAPI
142+ // implementation when it was created.
143+ realm_userdata_t m_userdata = nullptr ;
96144 realm_sync_socket_connect_func_t m_websocket_connect = nullptr ;
97145 realm_sync_socket_websocket_async_write_func_t m_websocket_async_write = nullptr ;
98146 realm_sync_socket_websocket_free_func_t m_websocket_free = nullptr ;
99147};
100148
149+ // Represents the websocket observer in the sync client that receives websocket status
150+ // callbacks and passes them along to the WebSocketObserver object.
101151struct CAPIWebSocketObserver : sync::WebSocketObserver {
102152public:
103153 CAPIWebSocketObserver (std::unique_ptr<sync::WebSocketObserver> observer)
@@ -131,9 +181,13 @@ struct CAPIWebSocketObserver : sync::WebSocketObserver {
131181 std::unique_ptr<sync::WebSocketObserver> m_observer;
132182};
133183
184+ // This is the primary resource for providing event loop, timer and websocket
185+ // resources and synchronization for the Sync Client. The CAPI implementation
186+ // needs to implement the "funct_t" functions provided to this class for connecting
187+ // the implementation to the operations called by the Sync Client.
134188struct CAPISyncSocketProvider : sync::SyncSocketProvider {
135189 realm_userdata_t m_userdata = nullptr ;
136- realm_free_userdata_func_t m_free = nullptr ;
190+ realm_free_userdata_func_t m_userdata_free = nullptr ;
137191 realm_sync_socket_post_func_t m_post = nullptr ;
138192 realm_sync_socket_create_timer_func_t m_timer_create = nullptr ;
139193 realm_sync_socket_timer_canceled_func_t m_timer_cancel = nullptr ;
@@ -145,7 +199,7 @@ struct CAPISyncSocketProvider : sync::SyncSocketProvider {
145199 CAPISyncSocketProvider () = default ;
146200 CAPISyncSocketProvider (CAPISyncSocketProvider&& other)
147201 : m_userdata(std::exchange(other.m_userdata, nullptr ))
148- , m_free (std::exchange(other.m_free , nullptr ))
202+ , m_userdata_free (std::exchange(other.m_userdata_free , nullptr ))
149203 , m_post(std::exchange(other.m_post, nullptr ))
150204 , m_timer_create(std::exchange(other.m_timer_create, nullptr ))
151205 , m_timer_cancel(std::exchange(other.m_timer_cancel, nullptr ))
@@ -154,7 +208,10 @@ struct CAPISyncSocketProvider : sync::SyncSocketProvider {
154208 , m_websocket_async_write(std::exchange(other.m_websocket_async_write, nullptr ))
155209 , m_websocket_free(std::exchange(other.m_websocket_free, nullptr ))
156210 {
157- REALM_ASSERT (m_free);
211+ // userdata_free can be null if userdata is not used
212+ if (m_userdata != nullptr ) {
213+ REALM_ASSERT (m_userdata_free);
214+ }
158215 REALM_ASSERT (m_post);
159216 REALM_ASSERT (m_timer_create);
160217 REALM_ASSERT (m_timer_cancel);
@@ -166,9 +223,14 @@ struct CAPISyncSocketProvider : sync::SyncSocketProvider {
166223
167224 ~CAPISyncSocketProvider ()
168225 {
169- m_free (m_userdata);
226+ if (m_userdata_free) {
227+ m_userdata_free (m_userdata);
228+ }
170229 }
171230
231+ // Create a websocket object that will be returned to the Sync Client, which is expected to
232+ // begin connecting to the endpoint as soon as the object is created. The state and any data
233+ // received is passed to the socket observer via the helper functions defined below this class.
172234 std::unique_ptr<sync::WebSocketInterface> connect (std::unique_ptr<sync::WebSocketObserver> observer,
173235 sync::WebSocketEndpoint&& endpoint) final
174236 {
@@ -206,7 +268,7 @@ RLM_API realm_sync_socket_t* realm_sync_socket_new(
206268 return wrap_err ([&]() {
207269 auto capi_socket_provider = std::make_shared<CAPISyncSocketProvider>();
208270 capi_socket_provider->m_userdata = userdata;
209- capi_socket_provider->m_free = userdata_free;
271+ capi_socket_provider->m_userdata_free = userdata_free;
210272 capi_socket_provider->m_post = post_func;
211273 capi_socket_provider->m_timer_create = create_timer_func;
212274 capi_socket_provider->m_timer_cancel = cancel_timer_func;
@@ -218,13 +280,18 @@ RLM_API realm_sync_socket_t* realm_sync_socket_new(
218280 });
219281}
220282
221- RLM_API void realm_sync_socket_callback_complete (realm_sync_socket_callback* realm_callback, realm_errno_e code,
222- const char * reason)
283+ RLM_API void realm_sync_socket_post_complete (realm_sync_socket_callback* post_handler, realm_errno_e status,
284+ const char * reason)
285+ {
286+ realm_sync_socket_op_complete (post_handler, status, reason);
287+ realm_release (post_handler);
288+ }
289+
290+ RLM_API void realm_sync_socket_write_complete (realm_sync_socket_callback_t * write_handler, realm_errno_e status,
291+ const char * reason)
223292{
224- auto complete_status =
225- code == realm_errno_e::RLM_ERR_NONE ? Status::OK () : Status{static_cast <ErrorCodes::Error>(code), reason};
226- (*(realm_callback->get ()))(complete_status);
227- realm_release (realm_callback);
293+ realm_sync_socket_op_complete (write_handler, status, reason);
294+ realm_release (write_handler);
228295}
229296
230297RLM_API void realm_sync_socket_websocket_connected (realm_websocket_observer_t * realm_websocket_observer,
@@ -245,10 +312,10 @@ RLM_API void realm_sync_socket_websocket_message(realm_websocket_observer_t* rea
245312}
246313
247314RLM_API void realm_sync_socket_websocket_closed (realm_websocket_observer_t * realm_websocket_observer, bool was_clean,
248- realm_web_socket_errno_e code , const char * reason)
315+ realm_web_socket_errno_e status , const char * reason)
249316{
250317 realm_websocket_observer->get ()->websocket_closed_handler (
251- was_clean, static_cast <sync::websocket::WebSocketError>(code ), reason);
318+ was_clean, static_cast <sync::websocket::WebSocketError>(status ), reason);
252319}
253320
254321RLM_API void realm_sync_client_config_set_sync_socket (realm_sync_client_config_t * config,
0 commit comments