pEpObjCAdapter/PEPSync.m
author Dirk Zimmermann <dirk@pep-project.org>
Fri, 02 Nov 2018 16:27:42 +0100
branchIOSAD-103
changeset 756 7ce91e92472c
parent 755 97e5610f11df
child 757 297e87c90165
permissions -rw-r--r--
IOSAD-103 naming sync thread
     1 //
     2 //  PEPSync.m
     3 //  pEpObjCAdapter
     4 //
     5 //  Created by Dirk Zimmermann on 04.10.18.
     6 //  Copyright © 2018 p≡p. All rights reserved.
     7 //
     8 
     9 #import "PEPSync.h"
    10 
    11 #import "PEPSendMessageDelegate.h"
    12 #import "PEPNotifyHandshakeDelegate.h"
    13 #import "PEPMessageUtil.h"
    14 #import "PEPMessage.h"
    15 #import "PEPQueue.h"
    16 #import "PEPLock.h"
    17 #import "PEPObjCAdapter.h"
    18 #import "NSError+PEP.h"
    19 #import "PEPSessionProvider.h"
    20 #import "PEPInternalSession.h"
    21 
    22 // MARK: - Declare internals
    23 
    24 typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
    25 typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
    26 
    27 @interface PEPSync ()
    28 
    29 + (PEPSync * _Nullable)instance;
    30 
    31 @property (nonatomic, nullable, weak) id<PEPSendMessageDelegate> sendMessageDelegate;
    32 @property (nonatomic, nullable, weak) id<PEPNotifyHandshakeDelegate> notifyHandshakeDelegate;
    33 @property (nonatomic, nonnull) PEPQueue *queue;
    34 @property (nonatomic, nullable) NSThread *syncThread;
    35 @property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
    36 
    37 /**
    38  @Return: The callback for message sending that should be used on every session init.
    39  */
    40 + (t_messageToSendCallback)messageToSendCallback;
    41 
    42 /**
    43  @Return: The callback for injectiong sync messages that should be used on every session init.
    44  */
    45 + (t_injectSyncCallback)injectSyncCallback;
    46 
    47 - (int)injectSyncEvent:(SYNC_EVENT)event;
    48 
    49 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
    50                       partner:(pEp_identity *)partner
    51                        signal:(sync_handshake_signal)signal;
    52 
    53 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
    54 
    55 @end
    56 
    57 // MARK: - Callbacks called by the engine, used in session init
    58 
    59 static PEP_STATUS s_messageToSendObjc(struct _message *msg)
    60 {
    61     id<PEPSendMessageDelegate> delegate = [[PEPSync instance] sendMessageDelegate];
    62     if (delegate) {
    63         PEPMessage *theMessage = pEpMessageFromStruct(msg);
    64         return [delegate sendMessage:theMessage];
    65     } else {
    66         return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
    67     }
    68 }
    69 
    70 static int s_inject_sync_event(SYNC_EVENT ev, void *management)
    71 {
    72     PEPSync *pEpSync = [PEPSync instance];
    73 
    74     if (pEpSync) {
    75         return [pEpSync injectSyncEvent:ev];
    76     } else {
    77         return 1;
    78     }
    79 }
    80 
    81 // MARK: - Callbacks called by the engine, used in register_sync_callbacks
    82 
    83 static PEP_STATUS s_notifyHandshake(pEp_identity *me,
    84                                     pEp_identity *partner,
    85                                     sync_handshake_signal signal)
    86 {
    87     PEPSync *sync = [PEPSync instance];
    88     return [sync notifyHandshake:me partner:partner signal:signal];
    89 }
    90 
    91 static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
    92 {
    93     PEPSync *sync = [PEPSync instance];
    94     return [sync retrieveNextSyncEvent:threshold];
    95 }
    96 
    97 // MARK: - Internal globals
    98 
    99 static __weak PEPSync *s_pEpSync;
   100 
   101 // MARK: - Public PEPSync class
   102 
   103 @implementation PEPSync
   104 
   105 + (t_messageToSendCallback)messageToSendCallback
   106 {
   107     return s_messageToSendObjc;
   108 }
   109 
   110 + (t_injectSyncCallback)injectSyncCallback
   111 {
   112     return s_inject_sync_event;
   113 }
   114 
   115 + (PEP_SESSION)createSession:(NSError **)error
   116 {
   117     PEP_SESSION session = NULL;
   118 
   119     [PEPLock lockWrite];
   120     PEP_STATUS status = init(&session,
   121                              [PEPSync messageToSendCallback],
   122                              [PEPSync injectSyncCallback]);
   123     [PEPLock unlockWrite];
   124 
   125     if (status != PEP_STATUS_OK) {
   126         if (error) {
   127             *error = [NSError errorWithPEPStatus:status];
   128         }
   129         return nil;
   130     }
   131 
   132     return session;
   133 }
   134 
   135 + (void)releaseSession:(PEP_SESSION)session
   136 {
   137     [PEPLock lockWrite];
   138     release(session);
   139     [PEPLock unlockWrite];
   140 }
   141 
   142 - (instancetype)initWithSendMessageDelegate:(id<PEPSendMessageDelegate>
   143                                              _Nonnull)sendMessageDelegate
   144                     notifyHandshakeDelegate:(id<PEPNotifyHandshakeDelegate>
   145                                              _Nonnull)notifyHandshakeDelegate
   146 {
   147     if (self = [super init]) {
   148         _sendMessageDelegate = sendMessageDelegate;
   149         _notifyHandshakeDelegate = notifyHandshakeDelegate;
   150         _queue = [PEPQueue new];
   151         s_pEpSync = self;
   152     }
   153     return self;
   154 }
   155 
   156 - (void)startup
   157 {
   158     self.conditionLockForJoiningSyncThread = [[NSConditionLock alloc] initWithCondition:NO];
   159     NSThread *theSyncThread = [[NSThread alloc] initWithTarget:self
   160                                                       selector:@selector(syncThreadLoop:)
   161                                                         object:nil];
   162     theSyncThread.name = @"pEp-sync-loop";
   163     self.syncThread = theSyncThread;
   164     [theSyncThread start];
   165 }
   166 
   167 - (void)shutdown
   168 {
   169     if (self.syncThread) {
   170         [self injectSyncEvent:nil];
   171         [self.conditionLockForJoiningSyncThread lockWhenCondition:YES];
   172         [self.conditionLockForJoiningSyncThread unlock];
   173     }
   174     self.conditionLockForJoiningSyncThread = nil;
   175 }
   176 
   177 // MARK: - Private
   178 
   179 + (PEPSync * _Nullable)instance
   180 {
   181     return s_pEpSync;
   182 }
   183 
   184 - (void)syncThreadLoop:(id)object
   185 {
   186     [self.conditionLockForJoiningSyncThread lock];
   187 
   188     PEPInternalSession *session = [PEPSessionProvider session];
   189 
   190     if (session) {
   191         register_sync_callbacks(session.session, nil, s_notifyHandshake,
   192                                 s_retrieve_next_sync_event);
   193         do_sync_protocol(session.session, nil);
   194         unregister_sync_callbacks(session.session);
   195     } else {
   196         // indicate error, maybe through `object`?
   197     }
   198 
   199     session = nil;
   200 
   201     [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
   202 }
   203 
   204 - (int)injectSyncEvent:(SYNC_EVENT)event
   205 {
   206     [self.queue enqueue:[NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)]];
   207     return 0;
   208 }
   209 
   210 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
   211                       partner:(pEp_identity *)partner
   212                        signal:(sync_handshake_signal)signal
   213 {
   214     if (self.notifyHandshakeDelegate) {
   215         PEPIdentity *meIdentity = PEP_identityFromStruct(me);
   216         PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
   217         return [self.notifyHandshakeDelegate notifyHandshake:NULL
   218                                                           me:meIdentity
   219                                                      partner:partnerIdentity
   220                                                       signal:signal];
   221     } else {
   222         return PEP_SYNC_NO_NOTIFY_CALLBACK;
   223     }
   224 }
   225 
   226 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
   227 {
   228     NSValue *value = [self.queue timedDequeue:&threshold];
   229     if (value) {
   230         SYNC_EVENT event;
   231         [value getValue:&event];
   232         return event;
   233     } else {
   234         return new_sync_timeout_event();
   235     }
   236 }
   237 
   238 @end