pEpObjCAdapter/PEPSync.m
author Dirk Zimmermann <dirk@pep-project.org>
Wed, 31 Oct 2018 16:38:25 +0100
branchIOSAD-103
changeset 755 97e5610f11df
parent 751 ac9e7fee47c2
child 756 7ce91e92472c
permissions -rw-r--r--
IOSAD-103 mind the margin
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@751
    19
#import "PEPSessionProvider.h"
dirk@751
    20
#import "PEPInternalSession.h"
dirk@686
    21
dirk@693
    22
// MARK: - Declare internals
dirk@693
    23
dirk@726
    24
typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
dirk@726
    25
typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
dirk@726
    26
dirk@691
    27
@interface PEPSync ()
dirk@691
    28
dirk@699
    29
+ (PEPSync * _Nullable)instance;
dirk@691
    30
dirk@732
    31
@property (nonatomic, nullable, weak) id<PEPSendMessageDelegate> sendMessageDelegate;
dirk@704
    32
@property (nonatomic, nullable, weak) id<PEPNotifyHandshakeDelegate> notifyHandshakeDelegate;
dirk@700
    33
@property (nonatomic, nonnull) PEPQueue *queue;
dirk@720
    34
@property (nonatomic, nullable) NSThread *syncThread;
dirk@736
    35
@property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
dirk@700
    36
dirk@726
    37
/**
dirk@726
    38
 @Return: The callback for message sending that should be used on every session init.
dirk@726
    39
 */
dirk@726
    40
+ (t_messageToSendCallback)messageToSendCallback;
dirk@726
    41
dirk@726
    42
/**
dirk@726
    43
 @Return: The callback for injectiong sync messages that should be used on every session init.
dirk@726
    44
 */
dirk@726
    45
+ (t_injectSyncCallback)injectSyncCallback;
dirk@726
    46
dirk@700
    47
- (int)injectSyncEvent:(SYNC_EVENT)event;
dirk@730
    48
dirk@730
    49
- (PEP_STATUS)notifyHandshake:(pEp_identity *)me
dirk@730
    50
                      partner:(pEp_identity *)partner
dirk@730
    51
                       signal:(sync_handshake_signal)signal;
dirk@730
    52
dirk@724
    53
- (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
dirk@692
    54
dirk@691
    55
@end
dirk@691
    56
dirk@728
    57
// MARK: - Callbacks called by the engine, used in session init
dirk@693
    58
dirk@740
    59
static PEP_STATUS s_messageToSendObjc(struct _message *msg)
dirk@682
    60
{
dirk@732
    61
    id<PEPSendMessageDelegate> delegate = [[PEPSync instance] sendMessageDelegate];
dirk@688
    62
    if (delegate) {
dirk@688
    63
        PEPMessage *theMessage = pEpMessageFromStruct(msg);
dirk@688
    64
        return [delegate sendMessage:theMessage];
dirk@689
    65
    } else {
dirk@689
    66
        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
dirk@688
    67
    }
dirk@682
    68
}
dirk@682
    69
dirk@740
    70
static int s_inject_sync_event(SYNC_EVENT ev, void *management)
dirk@682
    71
{
dirk@700
    72
    PEPSync *pEpSync = [PEPSync instance];
dirk@700
    73
dirk@700
    74
    if (pEpSync) {
dirk@700
    75
        return [pEpSync injectSyncEvent:ev];
dirk@700
    76
    } else {
dirk@700
    77
        return 1;
dirk@700
    78
    }
dirk@682
    79
}
dirk@682
    80
dirk@728
    81
// MARK: - Callbacks called by the engine, used in register_sync_callbacks
dirk@728
    82
dirk@734
    83
static PEP_STATUS s_notifyHandshake(pEp_identity *me,
dirk@734
    84
                                    pEp_identity *partner,
dirk@734
    85
                                    sync_handshake_signal signal)
dirk@729
    86
{
dirk@730
    87
    PEPSync *sync = [PEPSync instance];
dirk@730
    88
    return [sync notifyHandshake:me partner:partner signal:signal];
dirk@729
    89
}
dirk@729
    90
dirk@734
    91
static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
dirk@724
    92
{
dirk@733
    93
    PEPSync *sync = [PEPSync instance];
dirk@724
    94
    return [sync retrieveNextSyncEvent:threshold];
dirk@724
    95
}
dirk@724
    96
dirk@693
    97
// MARK: - Internal globals
dirk@693
    98
dirk@699
    99
static __weak PEPSync *s_pEpSync;
dirk@686
   100
dirk@720
   101
// MARK: - Public PEPSync class
dirk@693
   102
dirk@681
   103
@implementation PEPSync
dirk@681
   104
dirk@722
   105
+ (t_messageToSendCallback)messageToSendCallback
dirk@722
   106
{
dirk@740
   107
    return s_messageToSendObjc;
dirk@722
   108
}
dirk@722
   109
dirk@722
   110
+ (t_injectSyncCallback)injectSyncCallback
dirk@722
   111
{
dirk@740
   112
    return s_inject_sync_event;
dirk@722
   113
}
dirk@722
   114
dirk@725
   115
+ (PEP_SESSION)createSession:(NSError **)error
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@736
   183
- (void)syncThreadLoop:(id)object
dirk@736
   184
{
dirk@736
   185
    [self.conditionLockForJoiningSyncThread lock];
dirk@736
   186
dirk@751
   187
    PEPInternalSession *session = [PEPSessionProvider session];
dirk@727
   188
dirk@727
   189
    if (session) {
dirk@755
   190
        register_sync_callbacks(session.session, nil, s_notifyHandshake,
dirk@755
   191
                                s_retrieve_next_sync_event);
dirk@751
   192
        do_sync_protocol(session.session, nil);
dirk@751
   193
        unregister_sync_callbacks(session.session);
dirk@727
   194
    } else {
dirk@734
   195
        // indicate error, maybe through `object`?
dirk@727
   196
    }
dirk@727
   197
dirk@751
   198
    session = nil;
dirk@736
   199
dirk@736
   200
    [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
dirk@720
   201
}
dirk@720
   202
dirk@700
   203
- (int)injectSyncEvent:(SYNC_EVENT)event
dirk@700
   204
{
dirk@700
   205
    [self.queue enqueue:[NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)]];
dirk@700
   206
    return 0;
dirk@700
   207
}
dirk@700
   208
dirk@730
   209
- (PEP_STATUS)notifyHandshake:(pEp_identity *)me
dirk@730
   210
                      partner:(pEp_identity *)partner
dirk@730
   211
                       signal:(sync_handshake_signal)signal
dirk@730
   212
{
dirk@730
   213
    if (self.notifyHandshakeDelegate) {
dirk@730
   214
        PEPIdentity *meIdentity = PEP_identityFromStruct(me);
dirk@730
   215
        PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
dirk@732
   216
        return [self.notifyHandshakeDelegate notifyHandshake:NULL
dirk@730
   217
                                                          me:meIdentity
dirk@730
   218
                                                     partner:partnerIdentity
dirk@730
   219
                                                      signal:signal];
dirk@730
   220
    } else {
dirk@730
   221
        return PEP_SYNC_NO_NOTIFY_CALLBACK;
dirk@730
   222
    }
dirk@730
   223
}
dirk@730
   224
dirk@724
   225
- (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
dirk@724
   226
{
dirk@724
   227
    NSValue *value = [self.queue timedDequeue:&threshold];
dirk@724
   228
    if (value) {
dirk@724
   229
        SYNC_EVENT event;
dirk@724
   230
        [value getValue:&event];
dirk@724
   231
        return event;
dirk@724
   232
    } else {
dirk@724
   233
        return new_sync_timeout_event();
dirk@724
   234
    }
dirk@724
   235
}
dirk@724
   236
dirk@681
   237
@end