Skip to content

Instantly share code, notes, and snippets.

@lcsmuller
Last active June 8, 2022 17:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lcsmuller/b5137e66d534a57e0075f9d838c9170e to your computer and use it in GitHub Desktop.
Save lcsmuller/b5137e66d534a57e0075f9d838c9170e to your computer and use it in GitHub Desktop.
This gist describes the steps necessary to migrate from Orca to Concord 2.0.0

Migrating Orca to Concord 2.0.0

Symbol replacement

Replace orca references with ccord

Example

orca

...
ORCAcode code = ORCA_OK;
printf("%s\n", orca_strerror(code));
orca_global_init();
orca_global_cleanup();

concord

...
CCORDcode code = CCORD_OK;
printf("%s\n", ccord_strerror(code));
ccord_global_init();
ccord_global_cleanup();

Custom types have been shortened and no longer take _t suffixing

_t suffixing is usually "reserved" for the C standard.

Example

orca

u64_snowflake_t channel_id;
u64_unix_ms_t time_ms;
u64_bitmask_t bitmask;

concord

u64snowflake channel_id;
u64unix_ms time_ms;
u64bitmask bitmask;

Remove _params suffixing

All instances of _params suffixing have been removed from the codebase:

Example

orca

...
struct discord_create_message_params params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, NULL);

concord

...
struct discord_create_message params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, NULL);

Wrap callback parameters in structs

Callback parameters have been wrapped in structs to reduce the user complexity of having to match a specific callback-signature with many parameters, and also allow them to take ownership of the struct so its not automatically cleaned-up.

Example

orca

void on_ready(struct discord *client)
{
  printf("Bot %s is ready!", discord_self(client)->username);
}

void done_create_message(struct discord *client, struct discord_async_ret *ret)
{
  char *nick = ret->data;
  printf("Reaction has been sent by %s\n", nick);
}

void fail_create_message(struct discord *client, struct discord_async_err *err)
{
  printf("%s\n", discord_strerror(err->code, client));
}

void on_reaction_add(struct discord *client,
                    u64snowflake user_id,
                    u64snowflake channel_id,
                    u64snowflake message_id,
                    u64snowflake guild_id,
                    const struct discord_guild_member *member,
                    const struct discord_emoji *emoji)
{
  printf("Received emoji %s", emoji->name);
  
  struct discord_create_message_params params = { .content = "Received a reaction!" };
  discord_async_next(client, &(struct discord_async_attr){
                                .done = &done_create_message,
                                .fail = &fail_create_message,
                                .data = strdup(member->nick),
                                .cleanup = free
                             });
  discord_create_message(client, &params, NULL);
}

int main(void)
{
  struct discord *client = discord_init(BOT_TOKEN);
  discord_set_on_ready(client, &on_ready);
  discord_set_on_message_reaction_add(client, &on_reaction_add);
}

concord

void on_ready(struct discord *client, const struct discord_ready *event)
{
  printf("Bot %s is ready!", event->user->username);
}

void done_create_message(struct discord *client,
                         struct discord_response *resp,
                         const struct discord_message *msg)
{
  const struct discord_message_reaction_add *event = resp->keep;
  printf("Reaction has been sent by %s\n", event->member->nick);
}

void fail_create_message(struct discord *client, struct discord_response *resp)
{
  printf("%s\n", discord_strerror(resp->code, client));
}

void on_reaction_add(struct discord *client, const struct discord_message_reaction_add *event)
{
  printf("Received emoji %s", event->emoji->name);
  
  struct discord_create_message params = { .content = "Received a reaction!" };
  discord_create_message(client, &params, &(struct discord_ret_message){
                                            .done = &done_create_message,
                                            .fail = &fail_create_message,
                                            .keep = event // ensures event is kept and sent to callbacks
                                          });
}

int main(void)
{
  struct discord *client = discord_init(BOT_TOKEN);
  discord_set_on_ready(client, &on_ready);
  discord_set_on_message_reaction_add(client, &on_reaction_add);
}

Feature replacement

Null-terminated-lists replaced with carray.h implementation

Null-terminated lists were neither begginner friendly or intuitive, there were two common scenarios that would lead to a segfault:

...
// assuming list is a NTL, if it is NULL, then 'list[i]' will lead to a segfault
for (int i = 0; list[i]; ++i)
  printf("%d\n", i);

// if NULL is left out, it will lead to a segfault
int **integers = (int *[]){
  &(int){ 0 },
  &(int){ 2 },
  // NULL
};

Example

orca

...
struct discord_embed **embeds = {
  &(struct discord_embed){
    .title = "First embed"
  },
  &(struct discord_embed){
    .title = "Second embed"
  },
  NULL
};

for (int i = 0; embeds[i]; ++i)
  printf("%s\n", embeds[i]->title);

concord

...
struct discord_embeds embeds = {
  .size = 2,
  .array = (struct discord_embed []){
    {
      .title = "First embed"
    },
    {
      .title = "Second embed"
    }
  }
};

for (int i = 0; i < embeds->size; ++i)
  printf("%s\n", embeds->array[i].title);

Async requests are now the default behavior

This removes discord_async_next(), and adds a parameter at the end of each request function where user can assign their callbacks to.

Example 1

A asynchronous request that doesn't care about capturing the request response

orca

...
discord_async_next(client, NULL);
struct discord_create_message_params params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, NULL);

concord

...
struct discord_create_message params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, NULL);

Example 2

A asynchronous request that captures request response

orca

void done_create_message(struct discord *client, struct discord_async_ret *ret)
{
  const struct discord_message *msg = ret->ret;
  printf("Message has been sent (by %s)\n", msg->author->username);
}

void fail_create_message(struct discord *client, struct discord_async_err *err)
{
  printf("%s\n", discord_strerror(err->code, client));
}
...
discord_async_next(client, &(struct discord_async_attr){
                             .done = &done_create_message,
                             .fail = &fail_create_message
                           });
struct discord_create_message_params params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, NULL);

concord

void done_create_message(struct discord *client, struct discord_response *resp, const struct discord_message *msg)
{
  printf("Message has been sent (by %s)\n", msg->author->username);
}

void fail_create_message(struct discord *client, struct discord_response *resp)
{
  printf("%s\n", discord_strerror(resp->code, client));
}
...
struct discord_create_message params = { .content = "Hi" };
discord_create_message(client, channel_id, &params, &(struct discord_ret_message){
                                                      .done = &done_create_message,
                                                      .fail = &fail_create_message
                                                    });

Example 3

A synchronous (blocking) request that doesn't care about capturing the request response

orca

...
struct discord_create_message_params params = { .content = "Hi" };
ORCAcode code = discord_create_message(client, channel_id, &params, NULL);
if (code == ORCA_OK)
  printf("Message has been sent\n");
else
  printf("%s\n", discord_strerror(code, client));

concord

...
struct discord_create_message params = { .content = "Hi" };
CCORDcode code = discord_create_message(client, channel_id, &params, &(struct discord_ret_message){
                                                                       .sync = DISCORD_SYNC_FLAG // enable blocking request
                                                                      });
if (code == CCORD_OK)
  printf("Message has been sent\n");
else
  printf("%s\n", discord_strerror(code, client));

Example 4

A synchronous (blocking) request that captures request response

orca

...
struct discord_message msg = { 0 };

struct discord_create_message_params params = { .content = "Hi" };
ORCAcode code = discord_create_message(client, channel_id, &params, &msg);
if (code == ORCA_OK) {
  printf("Message has been sent (by %s)\n", msg.author->username);
  discord_message_cleanup(&msg);
}
else {
  printf("%s\n", discord_strerror(code, client));
}

concord

...
struct discord_message msg = { 0 };

struct discord_create_message params = { .content = "Hi" };
CCORDcode code = discord_create_message(client, channel_id, &params, &(struct discord_ret_message){
                                                                       .sync = &msg // enable blocking request
                                                                      });
if (code == CCORD_OK) {
  printf("Message has been sent (by %s)\n", msg.author->username);
  discord_message_cleanup(&msg);
}
else {
  printf("%s\n", discord_strerror(code, client));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment