150 lines
5.8 KiB
Python

# eventpy library
# Copyright (C) 2020 Wang Qi (wqking)
# Github: https://github.com/wqking/eventpy
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import eventpy.policy
import eventpy.lock as lock
import eventpy.eventdispatcher as eventdispatcher
import eventpy.internal.lockguard as lockguard
import time
class DisableQueueNotify :
def __init__(self, queue) :
self._queue = queue
def __enter__(self) :
self._queue._queueNotifyCounter += 1
return self
def __exit__(self, type, value, traceBack) :
self._queue._queueNotifyCounter -= 1
if self._queue._doCanNotifyQueueAvailable() and not self._queue.emptyQueue() :
with lockguard.LockGuard(self._queue._queueListMutex) :
self._queue._queueListConditionVariable.notify();
class QueuedEvent :
def __init__(self, event, args, kwargs) :
self.event = event
self.args = args
self.kwargs = kwargs
class EventQueue(eventdispatcher.EventDispatcher) :
def __init__(self, policy = eventpy.policy.defaultPolicy) :
super().__init__(policy)
self._policy = policy.clone()
self._queueListLock = self._policy.lockClass()
self._queueNotifyCounter = 0
self._queueEmptyCounter = 0
self._queueList = []
self._queueListMutex = self._policy.lockClass()
self._queueListConditionVariable = self._policy.conditionClass(self._queueListMutex)
def enqueue(self, *args, **kwargs) :
event = self._policy.getEvent(*args, **kwargs)
if self._policy.argumentPassingMode == eventpy.policy.argumentPassingExcludeEvent :
args = args[1:]
queuedEvent = QueuedEvent(event, args, kwargs)
with lockguard.LockGuard(self._queueListLock) :
self._queueList.append(queuedEvent)
if self._doCanProcess() :
with lockguard.LockGuard(self._queueListMutex) :
self._queueListConditionVariable.notify()
def emptyQueue(self) :
return (not self._queueList) and (self._queueEmptyCounter == 0)
def clearEvents(self) :
with lockguard.LockGuard(self._queueListLock) :
self._queueList = []
def process(self) :
if self._queueList :
with lockguard.LockGuard(self._queueListLock) :
tempList = self._queueList
self._queueList = []
if tempList :
for queuedEvent in tempList :
self.directDispatch(queuedEvent.event, *queuedEvent.args, **queuedEvent.kwargs)
return True
return False
def processOne(self) :
if self._queueList :
queuedEvent = None
with lockguard.LockGuard(self._queueListLock) :
if self._queueList :
queuedEvent = self._queueList[0]
self._queueList = self._queueList[1:]
if queuedEvent is not None :
self.directDispatch(queuedEvent.event, *queuedEvent.args, **queuedEvent.kwargs)
return True
return False
def processIf(self, func) :
if self._queueList :
with lockguard.LockGuard(self._queueListLock) :
tempList = self._queueList
self._queueList = []
if tempList :
for queuedEvent in tempList :
if func(*queuedEvent.args, **queuedEvent.kwargs) :
self.directDispatch(queuedEvent.event, *queuedEvent.args, **queuedEvent.kwargs)
else :
self._queueList.append(queuedEvent)
return True
return False
def wait(self) :
with lockguard.LockGuard(self._queueListMutex) :
while True :
self._queueListConditionVariable.wait(0.001)
if self._doCanProcess() :
break
def waitFor(self, seconds) :
with lockguard.LockGuard(self._queueListMutex) :
startSeconds = time.time()
while True :
self._queueListConditionVariable.wait(0.001)
if self._doCanProcess() :
return True
if time.time() - startSeconds >= seconds :
return False
def dispatchEvent(self, queuedEvent) :
self.directDispatch(queuedEvent.event, *queuedEvent.args, **queuedEvent.kwargs)
def peekEvent(self) :
if self._queueList :
with lockguard.LockGuard(self._queueListLock) :
if self._queueList :
return self._queueList[0]
return None
def takeEvent(self) :
if self._queueList :
with lockguard.LockGuard(self._queueListLock) :
if self._queueList :
queuedEvent = self._queueList[0]
self._queueList = self._queueList[1:]
return queuedEvent
return None
def _doCanProcess(self) :
return not self.emptyQueue() and self._doCanNotifyQueueAvailable()
def _doCanNotifyQueueAvailable(self) :
return self._queueNotifyCounter == 0