Ϫf["dZddlmZddgZddlZddlmZddlmZm Z m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZmZmZmZmZmZmZmZdd lm Z dd l!m"Z"m#Z#dd l$m%Z%d d l&m'Z'dZ(d Z)dZ*Gdde'Z+ee Gdde#Z,ddZ-y)z A reactor for integrating with U{CFRunLoop}, the CoreFoundation main loop used by macOS. This is useful for integrating Twisted with U{PyObjC} applications. ) annotationsinstall CFReactorN) implementer) CFSocketCreateRunLoopSourceCFSocketCreateWithNativeCFSocketDisableCallBacksCFSocketEnableCallBacksCFSocketInvalidateCFSocketSetSocketFlags*kCFSocketAutomaticallyReenableReadCallBack+kCFSocketAutomaticallyReenableWriteCallBackkCFSocketConnectCallBackkCFSocketReadCallBackkCFSocketWriteCallBack) CFAbsoluteTimeGetCurrentCFRunLoopAddSourceCFRunLoopAddTimerCFRunLoopGetCurrentCFRunLoopRemoveSource CFRunLoopRun CFRunLoopStopCFRunLoopTimerCreateCFRunLoopTimerInvalidatekCFAllocatorDefaultkCFRunLoopCommonModes) IReactorFDSet) _NO_FILEDESCPosixReactorBase)log) _UnixWaker@c,eZdZdZfdZfdZxZS) _WakerPlusa The normal Twisted waker will simply wake up the main loop, which causes an iteration to run, which in turn causes L{ReactorBase.runUntilCurrent} to get invoked. L{CFReactor} has a slightly different model of iteration, though: rather than have each iteration process the thread queue, then timed calls, then file descriptors, each callback is run as it is dispatched by the CFRunLoop observer which triggered it. So this waker needs to not only unblock the loop, but also make sure the work gets done; so, it reschedules the invocation of C{runUntilCurrent} to be immediate (0 seconds from now) even if there is no timed call work to do. c0t|||_yN)super__init__reactor)selfr* __class__s !F ?)+G!!!$'r.ct|Sr')r%r+s r- _wakerFactoryzCFReactor._wakerFactorys $r.c |\}}|jvrtj|tyj|\}}  fd} t j | y)a The socket callback issued by CFRunLoop. This will issue C{doRead} or C{doWrite} calls to the L{IReadDescriptor} and L{IWriteDescriptor} registered with the file descriptor that we are being notified of. @param cfSocket: The C{CFSocket} which has got some activity. @param callbackType: The type of activity that we are being notified of. Either C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack}. @param ignoredAddress: Unused, because this is not used for either of the callback types we register for. @param ignoredData: Unused, because this is not used for either of the callback types we register for. @param context: The data associated with this callback by C{CFSocketCreateWithNative} (in C{CFReactor._watchFD}). A 2-tuple of C{(int, CFRunLoopSource)}. Nc`d}d} jdk(rt}n>tk(}|rtr*j }nt rj }|rj||yy#t$r.tjd}tjYMwxYw)NFr!) filenorr_READr0_WRITEdoWrite BaseExceptionsysexc_infor err_disconnectSelectable)whyisRead callbackTypereadWriteDescriptorrwr+s r-_drdwz(CFReactor._socketCallback.._drdwsCF &--/25&C)-BBFe9"5"<"<">Cf:"5"="="?C**+>VL! llnQ'  sAA664B-,B-)r;rr>rr callWithLogger) r+cfSocketrRignoredAddress ignoredDatacontextfd smugglesrcsrcsktrUrSrTs ` ` @@r-_socketCallbackzCFReactor._socketCallbacksa.#Z T[[  "$//:?T U ,0KKO)S%r M> .6r.c~|dk(r td||jvr|j|\}}}}ng}|j|tt|t t ztz|j|}t|ttztztt|d}|j|t|j|t t#|t t ztzddg}||j$t'|<||||f|j|<d||j)|<t+||y)a Register a file descriptor with the C{CFRunLoop}, or modify its state so that it's listening for both notifications (read and write) rather than just one; used to implement C{addReader} and C{addWriter}. @param fd: The file descriptor. @type fd: L{int} @param descr: the L{IReadDescriptor} or L{IWriteDescriptor} @param flag: the flag to register for callbacks on, either C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack} rFzInvalid file descriptor.rFTN) RuntimeErrorr;appendrrrrrr_r r r_preserveSOErrorrrr>rr r<id _flag2idxr ) r+r[descrflagr]cfsgotdescrrTctxs r-_watchFDzCFReactor._watchFDs9 89: :  %)[[_ "ChC JJrN*#%()*+$$C #:=>!! ..A3JC JJsO t5J K $%()*+  B%'DKK5 "!3r1DKKO#'4>>$  T*r.c4tttti|S)a- Convert a C{kCFSocket...} constant to an index into the read/write state list (C{_READ} or C{_WRITE}) (the 4th element of the value of C{self._fdmap}). @param flag: C{kCFSocketReadCallBack} or C{kCFSocketWriteCallBack} @return: C{_READ} or C{_WRITE} )rrHrrI)r+rgs r-rezCFReactor._flag2idxs&u.DfMdSSr.ct||jvry|dk(r|jt|}n|}|j|\}}}}t||d||j |<|t sT|t sJ|jt|=|j|=t|j|tt|yyy)a Unregister a file descriptor with the C{CFRunLoop}, or modify its state so that it's listening for only one notification (read or write) as opposed to both; used to implement C{removeReader} and C{removeWriter}. @param fd: a file descriptor @type fd: C{int} @param descr: an L{IReadDescriptor} or L{IWriteDescriptor} @param flag: C{kCFSocketWriteCallBack} C{kCFSocketReadCallBack} NrFF) rdr<r;r rerHrIrr>rr )r+r[rfrgrealfdr]rhrTs r- _unwatchFDzCFReactor._unwatchFDs e9DKK '  8[[E+FF"kk&1S% d+#(4>>$  %yF BuI& F# !$//38M N s # ",yr.cN|j|j|ty)z7 Implement L{IReactorFDSet.addReader}. N)rkrGrr+readers r- addReaderzCFReactor.addReader:s fmmov/DEr.cN|j|j|ty)z7 Implement L{IReactorFDSet.addWriter}. N)rkrGrr+writers r- addWriterzCFReactor.addWriter@s fmmov/EFr.cN|j|j|ty)z: Implement L{IReactorFDSet.removeReader}. N)rorGrrqs r- removeReaderzCFReactor.removeReaderFs  1FGr.cN|j|j|ty)z: Implement L{IReactorFDSet.removeWriter}. N)rorGrrus r- removeWriterzCFReactor.removeWriterLs  1GHr.c |jjDchc] \}}}}| }}}}}|t|jz}|D]$}|j ||j |&t |Scc}}}}w)z7 Implement L{IReactorFDSet.removeAll}. )r;valuesset_internalReadersryr{list)r+r]rhrfrTallDescdescs r- removeAllzCFReactor.removeAllRs59KK4F4F4HII0S#ub5II3t,,-- $D   d #   d # $G} JsA? c |jjDcgc]\}}}}|ts|c}}}}Scc}}}}w)z8 Implement L{IReactorFDSet.getReaders}. )r;r}rHr+r]rhrfrTs r- getReaderszCFReactor.getReaders]s7261C1C1ESS-#sE2ESSS> > c |jjDcgc]\}}}}|ts|c}}}}Scc}}}}w)z8 Implement L{IReactorFDSet.getWriters}. )r;r}rIrs r- getWriterszCFReactor.getWriterscs7261C1C1ETT-#sE2FTTTrcRtj||}|j|S)aw Override L{PosixReactorBase}'s implementation of L{IDelayedCall.reset} so that it will immediately reschedule. Normally C{_moveCallLaterSooner} depends on the fact that C{runUntilCurrent} is always run before the mainloop goes back to sleep, so this forces it to immediately recompute how long the loop needs to stay asleep. )r_moveCallLaterSoonerr1)r+tpler2s r-rzCFReactor._moveCallLaterSooneris'"66tTB   r.cHt|||jdy)z Start running the reactor, then kick off the timer that advances Twisted's clock to keep pace with CFRunLoop's. T)forceN)r( startRunningr1)r+installSignalHandlersr,s r-rzCFReactor.startRunningus& 23 T*r.Fc\jsdfd }d_jd|d} jr@|rjd}d_ j d_jr@j y#d_wxYw#j wxYw)z Run the runner (C{CFRunLoopRun} or something that calls it), which runs the run loop until C{crash()} is called. c&jyr')crashrBsr-docrashz#CFReactor.mainLoop..docrashs  r.TrFNreturnNone)_started callLaterr1 _inCFLoopr=_stopSimulating)r+ralreadys` r-mainLoopzCFReactor.mainLoops }} !DM NN1g &- #--.**,!%+LLN%*DNU--X  "&+DN  "s#'BB (B BBB+z object | None_currentSimulatorcV|jyt|jd|_y)zv If we have a CFRunLoopTimer registered with the CFRunLoop, invalidate it and set it to None. N)rrrBs r-rzCFReactor._stopSimulatings)  ! ! )  !7!78!%r.c jjsy|rdnj}|yt|z}fd}t t |ddd|dx}_tj|ty)aV Schedule a call to C{self.runUntilCurrent}. This will cancel the currently scheduled call if it is already scheduled. @param force: Even if there are no timed calls, make sure that C{runUntilCurrent} runs immediately (in a 0-seconds-from-now C{CFRunLoopTimer}). This is necessary for calls which need to trigger behavior of C{runUntilCurrent} other than running timed calls, such as draining the thread call queue or calling C{crash()} when the appropriate flags are set. @type force: C{bool} NgcTd_jjyr')rrunUntilCurrentr1)cftimerextrar+s r-simulatez-CFReactor._scheduleSimulate..simulates#%)D "  "  " " $r.r) rrtimeoutrrrrrr>r)r+rrfireDatercs` r-r1zCFReactor._scheduleSimulates~ }} #DLLN ? +-7 % &: 1aHd&  D " $//1.CDr.c\tj|||g|i|}|j|S)z6 Implement L{IReactorTime.callLater}. )rrr1)r+_seconds_fargskw delayedCalls r-rzCFReactor.callLater s4'00xQdQbQ   r.cPtj||jdy)z1 Implement L{IReactorCore.stop}. TN)rstopr1rBs r-rzCFReactor.stops  d# t$r.crtj||jsyt|jy)z1 Implement L{IReactorCore.crash} N)rrrrr>rBs r-rzCFReactor.crashs( t$~~ doo&r.cjd|_|jd|j|jy)z Emulate the behavior of C{iterate()} for things that want to call it, by letting the loop run for a little while and then scheduling a timed call to exit it. TrN)rrrr)r+delays r-iteratezCFReactor.iterate$s(   q$**% r.NN)rr%)T)rboolrrr)F)rrrr)r)r3r4r5r6r)rCr_rkrerorsrwryr{rrrrrrrr__annotations__rr1rrrrr7r8s@r-rr\s$L ( @7D9+v T$<F G H I T U +6IG#R(,}+&#EJ%'r.c<t||}ddlm}|||S)a6 Configure the twisted mainloop to be run inside CFRunLoop. @param runLoop: the run loop to use. @param runner: the function to call in order to actually invoke the main loop. This will default to C{CFRunLoopRun} if not specified. However, this is not an appropriate choice for GUI applications, as you need to run NSApplicationMain (or something like it). For example, to run the Twisted mainloop in a PyObjC application, your C{main.py} should look something like this:: from PyObjCTools import AppHelper from twisted.internet.cfreactor import install install(runner=AppHelper.runEventLoop) # initialize your application reactor.run() @return: The installed reactor. @rtype: C{CFReactor} )r?r@r)installReactor)rtwisted.internet.mainr)r?r@r*rs r-rr5s 07G47 Nr.r).r6 __future__r__all__rLzope.interfacer CFNetworkrrr r r r r rrrrCoreFoundationrrrrrrrrrrrtwisted.internet.interfacesrtwisted.internet.posixbaserrtwisted.pythonr _signalsr"rHrIrcr%rrr.r-rs # k " &        6E !  > ]U UUpr.