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