summaryrefslogtreecommitdiff
path: root/async.h
blob: 527efa6e27a225010f232895fc833b04851f625f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
 * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
 *
 * SPDX-FileCopyrightText: 2024 Hiredict Contributors
 * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo <antirez at gmail dot com>
 * SPDX-FileCopyrightText: 2024 Pieter Noordhuis <pcnoordhuis at gmail dot com>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 * SPDX-License-Identifier: LGPL-3.0-or-later
 *
 */

#ifndef __HIREDICT_ASYNC_H
#define __HIREDICT_ASYNC_H
#include "hiredict.h"

#ifdef __cplusplus
extern "C" {
#endif

struct redictAsyncContext; /* need forward declaration of redictAsyncContext */
struct dict; /* dictionary header is included in async.c */

/* Reply callback prototype and container */
typedef void (redictCallbackFn)(struct redictAsyncContext*, void*, void*);
typedef struct redictCallback {
    struct redictCallback *next; /* simple singly linked list */
    redictCallbackFn *fn;
    int pending_subs;
    int unsubscribe_sent;
    void *privdata;
} redictCallback;

/* List of callbacks for either regular replies or pub/sub */
typedef struct redictCallbackList {
    redictCallback *head, *tail;
} redictCallbackList;

/* Connection callback prototypes */
typedef void (redictDisconnectCallback)(const struct redictAsyncContext*, int status);
typedef void (redictConnectCallback)(const struct redictAsyncContext*, int status);
typedef void (redictConnectCallbackNC)(struct redictAsyncContext*, int status);
typedef void (redictTimerCallback)(void *timer, void *privdata);

/* Context for an async connection to Redict */
typedef struct redictAsyncContext {
    /* Hold the regular context, so it can be realloc'ed. */
    redictContext c;

    /* Setup error flags so they can be used directly. */
    int err;
    char *errstr;

    /* Not used by hiredict */
    void *data;
    void (*dataCleanup)(void *privdata);

    /* Event library data and hooks */
    struct {
        void *data;

        /* Hooks that are called when the library expects to start
         * reading/writing. These functions should be idempotent. */
        void (*addRead)(void *privdata);
        void (*delRead)(void *privdata);
        void (*addWrite)(void *privdata);
        void (*delWrite)(void *privdata);
        void (*cleanup)(void *privdata);
        void (*scheduleTimer)(void *privdata, struct timeval tv);
    } ev;

    /* Called when either the connection is terminated due to an error or per
     * user request. The status is set accordingly (REDICT_OK, REDICT_ERR). */
    redictDisconnectCallback *onDisconnect;

    /* Called when the first write event was received. */
    redictConnectCallback *onConnect;
    redictConnectCallbackNC *onConnectNC;

    /* Regular command callbacks */
    redictCallbackList replies;

    /* Address used for connect() */
    struct sockaddr *saddr;
    size_t addrlen;

    /* Subscription callbacks */
    struct {
        redictCallbackList replies;
        struct dict *channels;
        struct dict *patterns;
        int pending_unsubs;
    } sub;

    /* Any configured RESP3 PUSH handler */
    redictAsyncPushFn *push_cb;
} redictAsyncContext;

/* Functions that proxy to hiredict */
redictAsyncContext *redictAsyncConnectWithOptions(const redictOptions *options);
redictAsyncContext *redictAsyncConnect(const char *ip, int port);
redictAsyncContext *redictAsyncConnectBind(const char *ip, int port, const char *source_addr);
redictAsyncContext *redictAsyncConnectBindWithReuse(const char *ip, int port,
                                                  const char *source_addr);
redictAsyncContext *redictAsyncConnectUnix(const char *path);
int redictAsyncSetConnectCallback(redictAsyncContext *ac, redictConnectCallback *fn);
int redictAsyncSetConnectCallbackNC(redictAsyncContext *ac, redictConnectCallbackNC *fn);
int redictAsyncSetDisconnectCallback(redictAsyncContext *ac, redictDisconnectCallback *fn);

redictAsyncPushFn *redictAsyncSetPushCallback(redictAsyncContext *ac, redictAsyncPushFn *fn);
int redictAsyncSetTimeout(redictAsyncContext *ac, struct timeval tv);
void redictAsyncDisconnect(redictAsyncContext *ac);
void redictAsyncFree(redictAsyncContext *ac);

/* Handle read/write events */
void redictAsyncHandleRead(redictAsyncContext *ac);
void redictAsyncHandleWrite(redictAsyncContext *ac);
void redictAsyncHandleTimeout(redictAsyncContext *ac);
void redictAsyncRead(redictAsyncContext *ac);
void redictAsyncWrite(redictAsyncContext *ac);

/* Command functions for an async context. Write the command to the
 * output buffer and register the provided callback. */
int redictvAsyncCommand(redictAsyncContext *ac, redictCallbackFn *fn, void *privdata, const char *format, va_list ap);
int redictAsyncCommand(redictAsyncContext *ac, redictCallbackFn *fn, void *privdata, const char *format, ...);
int redictAsyncCommandArgv(redictAsyncContext *ac, redictCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
int redictAsyncFormattedCommand(redictAsyncContext *ac, redictCallbackFn *fn, void *privdata, const char *cmd, size_t len);

#ifdef __cplusplus
}
#endif

#endif