pEpObjCAdapter/PEPSessionProvider.m
author buff <andreas@pep-project.org>
Wed, 24 Jul 2019 10:04:00 +0200
changeset 1098 7e325f306580
parent 1072 a5b4592a4748
permissions -rw-r--r--
rm needles __strong
     1 //
     2 //  PEPSessionProvider.m
     3 //  pEpObjCAdapter
     4 //
     5 //  Created by Andreas Buff on 09.10.17.
     6 //  Copyright © 2017 p≡p. All rights reserved.
     7 //
     8 
     9 #import "PEPSessionProvider.h"
    10 
    11 #import "PEPObjCAdapter+Internal.h"
    12 #import "PEPInternalSession.h"
    13 #import "PEPCopyableThread.h"
    14 
    15 @implementation PEPSessionProvider
    16 
    17 static NSLock *s_sessionForThreadLock = nil;
    18 static NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *s_sessionForThreadDict;
    19 
    20 /** We have to conform to the Engines rule: "The first session has to be created on the main thread and kept
    21  alive until all sessiopns created afterwards have been teared down."
    22  Here we hold it.
    23  */
    24 static PEPInternalSession *s_sessionForMainThread = nil;
    25 
    26 #pragma mark - Public API
    27 
    28 + (PEPInternalSession * _Nonnull)session
    29 {
    30     // Assure a session for the main thread exists and is kept alive before anyother session is created.
    31     [self assureSessionForMainThreadExists];
    32 
    33     if ([NSThread isMainThread]) {
    34         [self configureSession:s_sessionForMainThread];
    35         return s_sessionForMainThread;
    36     }
    37 
    38     [[self sessionForThreadLock] lock];
    39     NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
    40     PEPCopyableThread *currentThread = [[PEPCopyableThread alloc] initWithThread:[NSThread currentThread]];
    41     PEPInternalSession *newOrExistingSession = dict[currentThread];
    42     if (!newOrExistingSession) {
    43         newOrExistingSession = [PEPInternalSession new];
    44         dict[currentThread] = newOrExistingSession;
    45     }
    46 
    47     // configuration
    48     [self configureSession:newOrExistingSession];
    49 
    50     [self nullifySessionsOfFinishedThreads];
    51 
    52     [[self sessionForThreadLock] unlock];
    53 
    54     return newOrExistingSession;
    55 }
    56 
    57 + (void)cleanup
    58 {
    59     [[self sessionForThreadLock] lock];
    60 
    61     [self cleanupInternal];
    62 
    63     [[self sessionForThreadLock] unlock];
    64 }
    65 
    66 #pragma mark - Life Cycle
    67 
    68 + (void)initialize
    69 {
    70     s_sessionForThreadLock = [NSLock new];
    71     s_sessionForThreadDict = [NSMutableDictionary new];
    72 }
    73 
    74 #pragma mark - Lock
    75 
    76 + (NSLock *)sessionForThreadLock
    77 {
    78     return s_sessionForThreadLock;
    79 }
    80 
    81 + (NSMutableDictionary *)sessionForThreadDict
    82 {
    83     return s_sessionForThreadDict;
    84 }
    85 
    86 #pragma mark - configuration
    87 
    88 + (void)configureSession:(PEPInternalSession *)session
    89 {
    90     [self setConfigUnEncryptedSubjectOnSession:session];
    91     [self setPassiveModeOnSession:session];
    92 }
    93 
    94 + (void)setConfigUnEncryptedSubjectOnSession:(PEPInternalSession *)session
    95 {
    96     BOOL unEncryptedSubjectEnabled = [PEPObjCAdapter unEncryptedSubjectEnabled];
    97     [session configUnEncryptedSubjectEnabled:unEncryptedSubjectEnabled];
    98 }
    99 
   100 + (void)setPassiveModeOnSession:(PEPInternalSession *)session
   101 {
   102     BOOL passiveModeEnabled = [PEPObjCAdapter passiveModeEnabled];
   103     [session configurePassiveModeEnabled:passiveModeEnabled];
   104 }
   105 
   106 #pragma mark -
   107 
   108 /**
   109  Assures a session for the main thread is set.
   110  */
   111 + (void)assureSessionForMainThreadExists
   112 {
   113     // shared code to set global configuration every time
   114     void (^configurationBlock)(void) = ^{
   115         [[self sessionForThreadLock] lock];
   116         [self configureSession:s_sessionForMainThread];
   117         [[self sessionForThreadLock] unlock];
   118     };
   119 
   120     if (s_sessionForMainThread) {
   121         return;
   122     }
   123 
   124     // shared code that is executed in any case, either on the main thread or in the background
   125     void (^creationBlock)(void) = ^{
   126         if (s_sessionForMainThread) {
   127             return;
   128         }
   129         [[self sessionForThreadLock] lock];
   130         s_sessionForMainThread = [PEPInternalSession new];
   131         [[self sessionForThreadLock] unlock];
   132         configurationBlock();
   133     };
   134 
   135 
   136     if ([NSThread isMainThread]) {
   137         creationBlock();
   138     } else {
   139         dispatch_sync(dispatch_get_main_queue(), creationBlock);
   140     }
   141 }
   142 
   143 + (void)cleanupInternal
   144 {
   145     NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
   146 
   147     for (PEPCopyableThread *thread in dict.allKeys) {
   148         [self nullifySessionForThread:thread];
   149     }
   150     s_sessionForMainThread = nil;
   151     [dict removeAllObjects];
   152 }
   153 
   154 /**
   155  Tears down all sessions that belong to a thread that has finish executing forever.
   156  */
   157 + (void)nullifySessionsOfFinishedThreads
   158 {
   159     NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
   160     for (PEPCopyableThread *thread in dict.allKeys) {
   161         if (thread.isFinished) {
   162             // The session has been created to run on the one and only thread.
   163             // As this thread did finish executing forever, we can be sure the session can not be
   164             // accessed anymore, thus it is OK to nullify it on another thread as the one it has been
   165             // created for.
   166             [self nullifySessionForThread:thread];
   167         }
   168     }
   169 }
   170 
   171 + (void)nullifySessionForThread:(PEPCopyableThread *)thread
   172 {
   173     NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
   174     dict[thread] = nil;
   175 }
   176 
   177 @end