Я создаю уровень абстракции для веб-расширения keepassxc. Он использует каналы Redux-Saga, чтобы синхронизировать обмен сообщениями в Chrome. Он работает (не)на удивление хорошо. Однако я хочу полностью абстрагировать редукс-сагу, чтобы она выглядела как обычная функция, возвращающая Promise.
тл;др
KeePassXC-browser будет расширением для браузера, которое позволит получать пароли, хранящиеся в приложении KeePassXC, из браузера. Возможны два протокола связи: HTTP и NativeClient. Поэтому я решил использовать интерфейс машинописного текста, и в зависимости от протокола связи будет два класса, реализующих этот интерфейс.
Интерфейс:
interface Keepass {
getDatabaseHash(): Promise<string>;
getCredentials(origin: string, formUrl: string): Promise<KeepassCredentials[]>;
associate(): Promise<KeepassAssociation>;
isAssociated(dbHash: string): Promise<boolean>;
}
Первая реализация, представляющая протокол связи HTTP использует fetch API, который уже основан на Promise, поэтому реализация проста и на 100% соответствует этому интерфейсу.
Вторая реализация, представляющая протокол NativeClient, используя redux-saga (эффекты и каналы), чтобы асинхронный обмен сообщениями выглядел как синхронный вызов функции. Это немного сложно, но работает довольно хорошо и охватывает крайние случаи, с которыми было бы трудно справиться любым другим способом, потому что встроенный обмен сообщениями — это протокол, основанный на стандартных потоках ввода и вывода, поэтому запросы и ответы могут чередоваться, не по порядку и т. д.
Настоящая проблема, которую я не могу решить, заключается в том, что вторая реализация не реализует интерфейс, потому что это генераторы, а не промисы.
В основном хотелось бы преобразовать (обернуть) функцию итератора саги с функцией, возвращающей Promise. Существует хорошая co библиотека, которая в основном делает это для обычных генераторов. Но, похоже, не работает с редукционной сагой.
function* someGenerator() {
const state = yield select(); // execution freeze here when called from wrapper
const result = yield call(someEffect);
return result;
}
function wrapper() {
return co(someGenerator); // returns Promise
}
Это возможно? Если да, то что я делаю не так?