95 lines
3.1 KiB
Python
95 lines
3.1 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
import asyncio
|
||
|
import logging
|
||
|
import warnings
|
||
|
|
||
|
from jnius import PythonJavaClass
|
||
|
|
||
|
from ...exc import BleakError
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class AsyncJavaCallbacks(PythonJavaClass):
|
||
|
__javacontext__ = "app"
|
||
|
|
||
|
def __init__(self, loop: asyncio.AbstractEventLoop):
|
||
|
self._loop = loop
|
||
|
self.states = {}
|
||
|
self.futures = {}
|
||
|
|
||
|
@staticmethod
|
||
|
def _if_expected(result, expected):
|
||
|
if result[: len(expected)] == expected[:]:
|
||
|
return result[len(expected) :]
|
||
|
else:
|
||
|
return None
|
||
|
|
||
|
async def perform_and_wait(
|
||
|
self,
|
||
|
dispatchApi,
|
||
|
dispatchParams,
|
||
|
resultApi,
|
||
|
resultExpected=(),
|
||
|
unless_already=False,
|
||
|
return_indicates_status=True,
|
||
|
):
|
||
|
result2 = None
|
||
|
if unless_already:
|
||
|
if resultApi in self.states:
|
||
|
result2 = self._if_expected(self.states[resultApi][1:], resultExpected)
|
||
|
result1 = True
|
||
|
|
||
|
if result2 is not None:
|
||
|
logger.debug(
|
||
|
f"Not waiting for android api {resultApi} because found {resultExpected}"
|
||
|
)
|
||
|
else:
|
||
|
logger.debug(f"Waiting for android api {resultApi}")
|
||
|
|
||
|
state = self._loop.create_future()
|
||
|
self.futures[resultApi] = state
|
||
|
result1 = dispatchApi(*dispatchParams)
|
||
|
if return_indicates_status and not result1:
|
||
|
del self.futures[resultApi]
|
||
|
raise BleakError(f"api call failed, not waiting for {resultApi}")
|
||
|
data = await state
|
||
|
result2 = self._if_expected(data, resultExpected)
|
||
|
if result2 is None:
|
||
|
raise BleakError("Expected", resultExpected, "got", data)
|
||
|
|
||
|
logger.debug(f"{resultApi} succeeded {result2}")
|
||
|
|
||
|
if return_indicates_status:
|
||
|
return result2
|
||
|
else:
|
||
|
return (result1, *result2)
|
||
|
|
||
|
def _result_state_unthreadsafe(self, failure_str, source, data):
|
||
|
logger.debug(f"Java state transfer {source} error={failure_str} data={data}")
|
||
|
self.states[source] = (failure_str, *data)
|
||
|
future = self.futures.get(source, None)
|
||
|
if future is not None and not future.done():
|
||
|
if failure_str is None:
|
||
|
future.set_result(data)
|
||
|
else:
|
||
|
future.set_exception(BleakError(source, failure_str, *data))
|
||
|
else:
|
||
|
if failure_str is not None:
|
||
|
# an error happened with nothing waiting for it
|
||
|
exception = BleakError(source, failure_str, *data)
|
||
|
namedfutures = [
|
||
|
namedfuture
|
||
|
for namedfuture in self.futures.items()
|
||
|
if not namedfuture[1].done()
|
||
|
]
|
||
|
if len(namedfutures):
|
||
|
# send it on existing requests
|
||
|
for name, future in namedfutures:
|
||
|
warnings.warn(f"Redirecting error without home to {name}")
|
||
|
future.set_exception(exception)
|
||
|
else:
|
||
|
# send it on the event thread
|
||
|
raise exception
|