Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tutorial: Simple Connection #2

Merged
merged 14 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ if(BUILD_TESTING)
include(GenURITests)
target_sources(amongoc-test PRIVATE ${URITest_SOURCES})

# Add compile-time tests for generic function signatures
target_sources(amongoc-test PRIVATE
tests/sigcheck.test.cpp
tests/sigcheck.test.c
tests/sigcheck.test.h
)

# Don't add the testproject tests if we are already building as a test project
if(NOT DEFINED HOST_PROJECT_CMAKE_SOURCE_DIR)
include(TestProject)
Expand Down
14 changes: 14 additions & 0 deletions docs/_static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,18 @@ dl[class].cpp {
a.reference.external::after {
content: '⭧';
font-size: 80%;
}

.highlight {

/* Separate line numbers visually */
.linenos {
border-right: 1px solid var(--pst-color-border);
margin-right: 10px;
}

/* Italicize comments */
.c1 {
font-style: italic;
}
}
8 changes: 5 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,16 @@ def merge_domaindata(self, docnames: list[str], otherdata: dict[str, Any]) -> No
*(
f"amongoc_{f}"
for f in (
"detach_start",
"detach",
"is_error",
"just",
"let",
"schedule_later",
"start",
"tie",
"then",
"tie",
"timeout",
"schedule_later",
"is_error",
)
),
*(
Expand Down
4 changes: 1 addition & 3 deletions docs/dev/guidelines.rst
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,7 @@ portion of the file. These should be simple wrappers around the C types (e.g.
==============================================

This can create a semantic ambiguity when a C struct is constructed in a C
header. If you really need it, make sure that all calls to that constructor
within C headers are syntactically valid and semantically equivalent when
compiled in C and C++ modes (See: `amongoc_status`).
header.

**Instead, prefer** to use the named-constructor idiom: Use |static| member
functions that construct instances of the object (e.g. `amongoc_status::from`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ amongoc_emitter after_connect_say_hello(amongoc_box state_ptr, amongoc_status, a
bson_view_from(mut));
bson_delete(doc);

em = amongoc_then(em,
amongoc_async_forward_errors,
mlib_default_allocator,
state_ptr,
after_hello);
em = amongoc_then(em, amongoc_async_forward_errors, state_ptr, after_hello);
return em;
}
// end.
Expand All @@ -89,7 +85,6 @@ int main(int argc, char const* const* argv) {

em = amongoc_let(em,
amongoc_async_forward_errors,
mlib_default_allocator,
amongoc_box_pointer(&state),
after_connect_say_hello);

Expand Down
40 changes: 20 additions & 20 deletions docs/how-to/connect.rst → docs/how-to/communicate.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
###################
Connect to a Server
###################
###########################
Communicating with a Server
###########################

This how-to guide will walk through the follow example program:

.. literalinclude:: connect.example.c
:caption: ``connect.example.c``
.. literalinclude:: communicate.example.c
:caption: ``communicate.example.c``
:linenos:

Headers
#######

We first include the "everything" library header:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:caption: Header file inclusions
:lineno-match:
:start-at: #include
Expand All @@ -29,7 +29,7 @@ Command-Line Arguments

The first action we perform in ``main()`` is checking our arguments:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:caption: Argument checking
:lineno-match:
:start-at: int main
Expand All @@ -43,7 +43,7 @@ Initializing the Loop

The first "interesting" code will declare and initialize the default event loop:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: loop;
:end-at: );
Expand All @@ -62,7 +62,7 @@ Declare the App State
We use a type ``app_state`` to store some state that is shared across the
application:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: struct app_state
:end-at: } app_state;
Expand All @@ -71,7 +71,7 @@ This state needs to be stored in a way that it outlives the scope of each
sub-operation in the program. For this reason, we declare the instance in
``main()``:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: struct app_state state =
:end-at: struct app_state state =
Expand All @@ -89,7 +89,7 @@ Create a Client with a Timeout
We create a connect operation using `amongoc_client_new`, and then attach a
timeout using `amongoc_timeout`

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: client_new
:end-at: amongoc_timeout
Expand All @@ -102,7 +102,7 @@ and preferred for building composed asynchronous operations.
Attach the First Continuation
#############################

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: amongoc_let
:end-at: say_hello);
Expand All @@ -122,7 +122,7 @@ The First Continuation
The first step, after connecting to a server, is ``after_connect_say_hello``, a
continuation function given to `amongoc_let`:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: ** after_connect
:end-at: ) {
Expand All @@ -138,7 +138,7 @@ Upon success, the operation from `amongoc_client_new` will resolve with an
`amongoc_client` in its boxed result value. We move the connection by-value
from the box and store it in our application state:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: after_connect_say_hello(amongoc_box
:end-at: take
Expand All @@ -150,7 +150,7 @@ object that was owned by the box is now owned by the storage destination.

.. rubric:: Build and Prepare a Command

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: Create a "hello" command
:end-at: bson_delete
Expand All @@ -163,7 +163,7 @@ in ``em``.

.. rubric:: Attach the Second Continuation

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: em = amongoc_then(
:end-at: after_hello);
Expand All @@ -184,7 +184,7 @@ The Second Continuation
The second continuation after we receive a response from the server is very
simple:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: after_hello()
:end-before: end.
Expand All @@ -202,7 +202,7 @@ Going back to ``main()``, after our call to `amongoc_let` in which we attached
the first continuation, we use `amongoc_tie` to convert the emitter to an
`amongoc_operation`:

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: fin_status
:end-at: amongoc_tie
Expand All @@ -217,7 +217,7 @@ final result value will be (in a successful case, this would just be the
Start the Operation, Run the Loop, and Clean Up
###############################################

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: amongoc_start
:end-at: default_loop_destroy
Expand All @@ -241,7 +241,7 @@ Finally, we are done with the event loop, and we can destroy it with
Print the Final Result
######################

.. literalinclude:: connect.example.c
.. literalinclude:: communicate.example.c
:lineno-match:
:start-at: is_error
:end-before: end.
Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ How-to Guides
:caption: Guides
:maxdepth: 2

connect
communicate
looping
12 changes: 3 additions & 9 deletions docs/how-to/looping.example.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,16 @@ amongoc_emitter loop_step(amongoc_box state_ptr, amongoc_status prev_status, amo
fprintf(stderr, "%d seconds remain, current value: %lu\n", s->countdown, cur);
// Check if we are done
if (s->countdown == 0) {
// No more looping to do. Return a final null result
return amongoc_just(amongoc_okay,
amongoc_box_uint64(cur),
amongoc_loop_get_allocator(s->loop));
// No more looping to do. Return a final result
return amongoc_just(amongoc_box_uint64(cur));
}
// Decrement the counter and start a sleep of one second
--s->countdown;
struct timespec dur = {.tv_sec = 1};
amongoc_emitter em = amongoc_schedule_later(s->loop, dur);
// Connect the sleep to this function so that we will be called again after
// the delay has elapsed. Return this as the new operation for the loop.
return amongoc_let(em,
amongoc_async_forward_errors,
amongoc_loop_get_allocator(s->loop),
state_ptr,
loop_step);
return amongoc_let(em, amongoc_async_forward_errors, state_ptr, loop_step);
}
// end.

Expand Down
6 changes: 3 additions & 3 deletions docs/how-to/looping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ countdown reaches zero.
:end-at: }

The `amongoc_just` function creates a pseudo-async operation that resolves
immediately with the given result. Here, we create a successful status with
`amongoc_okay` and use `amongoc_box_uint64` to create a box that stores the
final calculation. This result value box will appear at the end of our loop.
immediately with the given result. Here, we use `amongoc_box_uint64` to create a
box that stores the final calculation. This result value box will appear at the
end of our loop.


Starting a Timer
Expand Down
44 changes: 44 additions & 0 deletions docs/learn/connect.example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <amongoc/amongoc.h> // Make all APIs visible

#include <stdio.h>
#include <stdlib.h>
// end:headers

amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result);

int main(void) {
amongoc_loop loop;
amongoc_default_loop_init(&loop);

// Initiate a connection
amongoc_emitter em = amongoc_client_new(&loop, "mongodb://localhost:27017");
// Set the continuation
em = amongoc_then(em, &on_connect);
// Run the program
amongoc_detach_start(em);
amongoc_default_loop_run(&loop);
// Clean up
amongoc_default_loop_destroy(&loop);
return 0;
}

// on_connect def
amongoc_box on_connect(amongoc_box userdata, amongoc_status* status, amongoc_box result) {
// We don't use the userdata
(void)userdata;
// Check for an error
if (amongoc_is_error(*status)) {
char* msg = amongoc_status_strdup_message(*status);
fprintf(stderr, "Error while connecting to server: %s\n", msg);
free(msg);
} else {
printf("Successfully connected!\n");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest disabling the default enabled tracing. This example currently prints the full OPMSG sent and received:

send OP_MSG #0 (135 bytes)
  Section #1 body: {
    "hello": 1:i32,
    "$db": "admin",
    "client": {
      "driver": {
        "name": "amongoc",
        "version": "experimental-dev",
      },
      "os": { "type": "Linux" },
    },
  }

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how that got in. Oop.

amongoc_client* client;
amongoc_box_take(client, result);
// `cl` now stores a valid client. We don't do anything else, so just delete it:
amongoc_client_delete(client);
}
amongoc_box_destroy(result);
return amongoc_nil;
}
// on_connect end
Loading