Connecting to a MongoDB Server#
This page will show how to asynchronously connect to a MongoDB server from a C program.
Including the amongoc
APIs#
To make all amongoc
APIs visible, include the everything-header:
1#include <amongoc/amongoc.h> // Make all APIs visible
2
3#include <stdio.h>
4#include <stdlib.h>
Creating an Event Loop#
The first thing to do before connecting to a program is to create an event loop.
amongoc
includes a basic default single-threaded event loop suitable for basic
programs:
9int main(void) {
10 amongoc_loop loop;
11 amongoc_status status = amongoc_default_loop_init(&loop);
12 amongoc_if_error (status, msg) {
13 fprintf(stderr, "Failed to prepare the event loop: %s\n", msg);
14 return 2;
15 }
Creating a Client#
A client is created and initialized asynchronously and is associated with an
event loop, done using amongoc_client_new()
:
18amongoc_emitter em = amongoc_client_new(&loop, "mongodb://localhost:27017");
Hint
The URI string above is a simple default for a locally-running server without TLS enabled. You should replace it with your own if your URI is running in a different location.
Create the Continuation#
An amongoc_emitter
object is not a client. Rather, it is an object that
represents an asynchronous operation. To get the client, we need to attach a
continuation:
7amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result);
amongoc_then()
#20em = amongoc_then(em, &on_connect);
The continuation function on_connect
looks like this:
30amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result) {
31 // We don't use the userdata
32 (void)userdata;
33 // Check for an error
34 amongoc_if_error (*status, msg) {
35 fprintf(stderr, "Error while connecting to server: %s\n", msg);
36 } else {
37 printf("Successfully connected!\n");
38 amongoc_client* client;
39 amongoc_box_take(client, result);
40 // `client` now stores a valid client. We don't do anything else, so just delete it:
41 amongoc_client_delete(client);
42 }
43 amongoc_box_destroy(result);
44 return amongoc_nil;
45}
Create the Operation State#
When we are done defining the entire asynchronous control flow, we need to
convert the amongoc_emitter
to an operation and enqueue it with the event
loop. There are several ways to do this, but the simplest is amongoc_detach_start()
:
22amongoc_detach_start(em);
This will enqueue the associated program with the event loop, and will automatically release resources associated with the operation when the operation completes.
Note
amongoc_detach_start()
will “consume” the emitter object. The em
emitter object is “poisoned” and cannot be manipulated further.
Run the Program#
The amongoc_detach_start()
call only enqueues the operation, but does not
execute it. We need to actually give control of the main thread to the event
loop. This is done using amongoc_default_loop_run()
:
23amongoc_default_loop_run(&loop);
Clean up the Event Loop#
After amongoc_default_loop_run()
returns, there is no more pending work in the
event loop, so we are done. Before returning, we need to destroy the event loop
object:
25amongoc_default_loop_destroy(&loop);
The Whole Program#
Here is the complete program:
connect.example.c
# 1#include <amongoc/amongoc.h> // Make all APIs visible
2
3#include <stdio.h>
4#include <stdlib.h>
5// end:headers
6
7amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result);
8
9int main(void) {
10 amongoc_loop loop;
11 amongoc_status status = amongoc_default_loop_init(&loop);
12 amongoc_if_error (status, msg) {
13 fprintf(stderr, "Failed to prepare the event loop: %s\n", msg);
14 return 2;
15 }
16
17 // Initiate a connection
18 amongoc_emitter em = amongoc_client_new(&loop, "mongodb://localhost:27017");
19 // Set the continuation
20 em = amongoc_then(em, &on_connect);
21 // Run the program
22 amongoc_detach_start(em);
23 amongoc_default_loop_run(&loop);
24 // Clean up
25 amongoc_default_loop_destroy(&loop);
26 return 0;
27}
28
29// on_connect def
30amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result) {
31 // We don't use the userdata
32 (void)userdata;
33 // Check for an error
34 amongoc_if_error (*status, msg) {
35 fprintf(stderr, "Error while connecting to server: %s\n", msg);
36 } else {
37 printf("Successfully connected!\n");
38 amongoc_client* client;
39 amongoc_box_take(client, result);
40 // `client` now stores a valid client. We don't do anything else, so just delete it:
41 amongoc_client_delete(client);
42 }
43 amongoc_box_destroy(result);
44 return amongoc_nil;
45}
46// on_connect end