libgnunetchat

library for GNUnet Messenger
Log | Files | Refs | README | LICENSE

gnunet_chat_discourse.c (4828B)


      1 /*
      2    This file is part of GNUnet.
      3    Copyright (C) 2024 GNUnet e.V.
      4 
      5    GNUnet is free software: you can redistribute it and/or modify it
      6    under the terms of the GNU Affero General Public License as published
      7    by the Free Software Foundation, either version 3 of the License,
      8    or (at your option) any later version.
      9 
     10    GNUnet is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    Affero General Public License for more details.
     14 
     15    You should have received a copy of the GNU Affero General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18    SPDX-License-Identifier: AGPL3.0-or-later
     19  */
     20 /*
     21  * @author Tobias Frisch
     22  * @file gnunet_chat_discourse.c
     23  */
     24 
     25 #include "gnunet_chat_discourse.h"
     26 
     27 #include <gnunet/gnunet_common.h>
     28 #include <gnunet/gnunet_scheduler_lib.h>
     29 #include <gnunet/gnunet_time_lib.h>
     30 
     31 #include <unistd.h>
     32 
     33 #include "gnunet_chat_discourse_intern.c"
     34 
     35 struct GNUNET_CHAT_Discourse*
     36 discourse_create (struct GNUNET_CHAT_Context *context,
     37                   const struct GNUNET_CHAT_DiscourseId *id)
     38 {
     39   GNUNET_assert((context) && (id));
     40 
     41   struct GNUNET_CHAT_Discourse *discourse = GNUNET_new(struct GNUNET_CHAT_Discourse);
     42 
     43   discourse->context = context;
     44 
     45   GNUNET_memcpy(&(discourse->id), id, sizeof(struct GNUNET_CHAT_DiscourseId));
     46 
     47   if (0 != pipe(discourse->pipe))
     48   {
     49     discourse->pipe[0] = -1;
     50     discourse->pipe[1] = -1;
     51   }
     52 
     53   discourse->head = NULL;
     54   discourse->tail = NULL;
     55 
     56   discourse->pipe_task = GNUNET_SCHEDULER_add_now(
     57     cb_reinit_discourse_pipe, discourse
     58   );
     59 
     60   discourse->user_pointer = NULL;
     61 
     62   return discourse;
     63 }
     64 
     65 static void
     66 discourse_remove_subscription (void *cls)
     67 {
     68   struct GNUNET_CHAT_DiscourseSubscription *sub = cls;
     69   struct GNUNET_CHAT_Discourse *discourse = sub->discourse;
     70 
     71   GNUNET_CONTAINER_DLL_remove(
     72     discourse->head,
     73     discourse->tail,
     74     sub
     75   );
     76 
     77   GNUNET_free(sub);
     78 }
     79 
     80 void
     81 discourse_destroy (struct GNUNET_CHAT_Discourse *discourse)
     82 {
     83   GNUNET_assert(discourse);
     84 
     85   while (discourse->head)
     86   {
     87     struct GNUNET_CHAT_DiscourseSubscription *sub = discourse->head;
     88 
     89     if (sub->task)
     90       GNUNET_SCHEDULER_cancel(sub->task);
     91 
     92     discourse_remove_subscription(sub);
     93   }
     94 
     95   if (discourse->pipe_task)
     96     GNUNET_SCHEDULER_cancel(discourse->pipe_task);
     97 
     98   if (-1 != discourse->pipe[0])
     99     close(discourse->pipe[0]);
    100   if (-1 != discourse->pipe[1])
    101     close(discourse->pipe[1]);
    102 
    103   GNUNET_free(discourse);
    104 }
    105 
    106 enum GNUNET_GenericReturnValue
    107 discourse_subscribe (struct GNUNET_CHAT_Discourse *discourse,
    108                      struct GNUNET_CHAT_Contact *contact,
    109                      const struct GNUNET_TIME_Absolute timestamp,
    110                      const struct GNUNET_TIME_Relative time)
    111 {
    112   GNUNET_assert((discourse) && (contact));
    113 
    114   const struct GNUNET_TIME_Absolute end = GNUNET_TIME_absolute_add(
    115     timestamp,
    116     time
    117   );
    118 
    119   if (GNUNET_TIME_absolute_cmp(end, <, GNUNET_TIME_absolute_get()))
    120     return GNUNET_SYSERR;
    121 
    122   struct GNUNET_CHAT_DiscourseSubscription *sub;
    123   for (sub = discourse->head; sub; sub = sub->next)
    124     if (sub->contact == contact)
    125       break;
    126   
    127   const enum GNUNET_GenericReturnValue update = (
    128     sub? GNUNET_YES : GNUNET_NO
    129   );
    130 
    131   if (!sub)
    132   {
    133     sub = GNUNET_new(struct GNUNET_CHAT_DiscourseSubscription);
    134 
    135     sub->prev = NULL;
    136     sub->next = NULL;
    137 
    138     sub->discourse = discourse;
    139     sub->contact = contact;
    140 
    141     GNUNET_CONTAINER_DLL_insert(
    142       discourse->head,
    143       discourse->tail,
    144       sub
    145     );
    146   }
    147   else if (sub->task)
    148     GNUNET_SCHEDULER_cancel(sub->task);
    149 
    150   sub->start = timestamp;
    151   sub->end = end;
    152 
    153   sub->task = GNUNET_SCHEDULER_add_at(
    154     end,
    155     discourse_remove_subscription,
    156     sub
    157   );
    158 
    159   return update;
    160 }
    161 
    162 void
    163 discourse_unsubscribe (struct GNUNET_CHAT_Discourse *discourse,
    164                        struct GNUNET_CHAT_Contact *contact,
    165                        const struct GNUNET_TIME_Absolute timestamp,
    166                        const struct GNUNET_TIME_Relative delay)
    167 {
    168   GNUNET_assert((discourse) && (contact));
    169 
    170   struct GNUNET_CHAT_DiscourseSubscription *sub;
    171   for (sub = discourse->head; sub; sub = sub->next)
    172     if (sub->contact == contact)
    173       break;
    174 
    175   if ((!sub) || (GNUNET_TIME_absolute_cmp(sub->start, >, timestamp)))
    176     return;
    177 
    178   const struct GNUNET_TIME_Absolute exit = GNUNET_TIME_absolute_add(
    179     timestamp, delay
    180   );
    181 
    182   if (GNUNET_TIME_absolute_cmp(exit, <, sub->end))
    183     sub->end = exit;
    184 
    185   if (sub->task)
    186     GNUNET_SCHEDULER_cancel(sub->task);
    187 
    188   if (GNUNET_TIME_absolute_cmp(sub->end, <, GNUNET_TIME_absolute_get()))
    189     discourse_remove_subscription(sub);
    190   else
    191     sub->task = GNUNET_SCHEDULER_add_at(
    192       sub->end,
    193       discourse_remove_subscription,
    194       sub
    195     );
    196 }