pEpObjCAdapter/PEPSync.m
author Dirk Zimmermann <dirk@pep-project.org>
Wed, 31 Oct 2018 16:38:25 +0100
branchIOSAD-103
changeset 748 eb3b7b15414d
parent 746 dbb0deb87940
child 750 c29db2e0851e
permissions -rw-r--r--
IOSAD-103 NO DEBUG NSLOG
     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 
    20 // MARK: - Declare internals
    21 
    22 typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
    23 typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
    24 
    25 @interface PEPSync ()
    26 
    27 + (PEPSync * _Nullable)instance;
    28 
    29 @property (nonatomic, nullable, weak) id<PEPSendMessageDelegate> sendMessageDelegate;
    30 @property (nonatomic, nullable, weak) id<PEPNotifyHandshakeDelegate> notifyHandshakeDelegate;
    31 @property (nonatomic, nonnull) PEPQueue *queue;
    32 @property (nonatomic, nullable) NSThread *syncThread;
    33 @property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
    34 
    35 /**
    36  @Return: The callback for message sending that should be used on every session init.
    37  */
    38 + (t_messageToSendCallback)messageToSendCallback;
    39 
    40 /**
    41  @Return: The callback for injectiong sync messages that should be used on every session init.
    42  */
    43 + (t_injectSyncCallback)injectSyncCallback;
    44 
    45 - (int)injectSyncEvent:(SYNC_EVENT)event;
    46 
    47 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
    48                       partner:(pEp_identity *)partner
    49                        signal:(sync_handshake_signal)signal;
    50 
    51 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
    52 
    53 @end
    54 
    55 // MARK: - Callbacks called by the engine, used in session init
    56 
    57 static PEP_STATUS s_messageToSendObjc(struct _message *msg)
    58 {
    59     id<PEPSendMessageDelegate> delegate = [[PEPSync instance] sendMessageDelegate];
    60     if (delegate) {
    61         PEPMessage *theMessage = pEpMessageFromStruct(msg);
    62         return [delegate sendMessage:theMessage];
    63     } else {
    64         return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
    65     }
    66 }
    67 
    68 static int s_inject_sync_event(SYNC_EVENT ev, void *management)
    69 {
    70     PEPSync *pEpSync = [PEPSync instance];
    71 
    72     if (pEpSync) {
    73         return [pEpSync injectSyncEvent:ev];
    74     } else {
    75         return 1;
    76     }
    77 }
    78 
    79 // MARK: - Callbacks called by the engine, used in register_sync_callbacks
    80 
    81 static PEP_STATUS s_notifyHandshake(pEp_identity *me,
    82                                     pEp_identity *partner,
    83                                     sync_handshake_signal signal)
    84 {
    85     PEPSync *sync = [PEPSync instance];
    86     return [sync notifyHandshake:me partner:partner signal:signal];
    87 }
    88 
    89 static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
    90 {
    91     PEPSync *sync = [PEPSync instance];
    92     return [sync retrieveNextSyncEvent:threshold];
    93 }
    94 
    95 // MARK: - Internal globals
    96 
    97 static __weak PEPSync *s_pEpSync;
    98 
    99 // MARK: - Public PEPSync class
   100 
   101 @implementation PEPSync
   102 
   103 + (t_messageToSendCallback)messageToSendCallback
   104 {
   105     return s_messageToSendObjc;
   106 }
   107 
   108 + (t_injectSyncCallback)injectSyncCallback
   109 {
   110     return s_inject_sync_event;
   111 }
   112 
   113 + (PEP_SESSION)createSession:(NSError **)error
   114 {
   115     [PEPSync setupTrustWordsDB];
   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     self.syncThread = theSyncThread;
   163     [theSyncThread start];
   164 }
   165 
   166 - (void)shutdown
   167 {
   168     if (self.syncThread) {
   169         [self injectSyncEvent:nil];
   170         [self.conditionLockForJoiningSyncThread lockWhenCondition:YES];
   171         [self.conditionLockForJoiningSyncThread unlock];
   172     }
   173     self.conditionLockForJoiningSyncThread = nil;
   174 }
   175 
   176 // MARK: - Private
   177 
   178 + (PEPSync * _Nullable)instance
   179 {
   180     return s_pEpSync;
   181 }
   182 
   183 + (void)setupTrustWordsDB
   184 {
   185     static dispatch_once_t once;
   186     dispatch_once(&once, ^{
   187         [PEPObjCAdapter setupTrustWordsDB:[NSBundle bundleForClass:[self class]]];
   188     });
   189 }
   190 
   191 - (void)syncThreadLoop:(id)object
   192 {
   193     [self.conditionLockForJoiningSyncThread lock];
   194 
   195     NSError *error = nil;
   196     PEP_SESSION session = [PEPSync createSession:&error];
   197 
   198     if (session) {
   199         register_sync_callbacks(session, nil, s_notifyHandshake, s_retrieve_next_sync_event);
   200         do_sync_protocol(session, nil);
   201         unregister_sync_callbacks(session);
   202     } else {
   203         // indicate error, maybe through `object`?
   204     }
   205 
   206     [PEPSync releaseSession:session];
   207 
   208     [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
   209 }
   210 
   211 - (int)injectSyncEvent:(SYNC_EVENT)event
   212 {
   213     [self.queue enqueue:[NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)]];
   214     return 0;
   215 }
   216 
   217 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
   218                       partner:(pEp_identity *)partner
   219                        signal:(sync_handshake_signal)signal
   220 {
   221     if (self.notifyHandshakeDelegate) {
   222         PEPIdentity *meIdentity = PEP_identityFromStruct(me);
   223         PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
   224         return [self.notifyHandshakeDelegate notifyHandshake:NULL
   225                                                           me:meIdentity
   226                                                      partner:partnerIdentity
   227                                                       signal:signal];
   228     } else {
   229         return PEP_SYNC_NO_NOTIFY_CALLBACK;
   230     }
   231 }
   232 
   233 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
   234 {
   235     NSValue *value = [self.queue timedDequeue:&threshold];
   236     if (value) {
   237         SYNC_EVENT event;
   238         [value getValue:&event];
   239         return event;
   240     } else {
   241         return new_sync_timeout_event();
   242     }
   243 }
   244 
   245 @end