Files
start-os/frontend/projects/ui/src/app/util/rxjs.util.ts
Alex Inkin 4f3223d3ad refactor: isolate network toast and login redirect to separate services (#1412)
* refactor: isolate network toast and login redirect to separate services

* chore: remove accidentally committed sketch of a service

* chore: tidying things up

* feat: add `GlobalModule` encapsulating all global subscription services

* remove angular build cache when building deps

* chore: fix more issues found while testing

* chore: fix issues reported by testing

* chore: fix template error

* chore: fix server-info

* chore: fix server-info

* fix: switch to Observable to fix race conditions

* fix embassy name display on load

* update patchdb

* clean up patch data watch

Co-authored-by: Lucy Cifferello <12953208+elvece@users.noreply.github.com>
2022-05-26 16:56:47 -06:00

97 lines
2.5 KiB
TypeScript

import {
Observable,
from,
interval,
race,
OperatorFunction,
Observer,
combineLatest,
} from 'rxjs'
import { take, map } from 'rxjs/operators'
export function fromAsync$<S, T>(
async: (s: S) => Promise<T>,
s: S,
): Observable<T>
export function fromAsync$<T>(async: () => Promise<T>): Observable<T>
export function fromAsync$<S, T>(
async: (s: S) => Promise<T>,
s?: S,
): Observable<T> {
return from(async(s as S))
}
export function fromAsyncP<T>(async: () => Promise<T>): Promise<T>
export function fromAsyncP<S, T>(
async: (s: S) => Promise<T>,
s?: S,
): Promise<T> {
return async(s as S)
}
// emits + completes after ms
export function emitAfter$(ms: number): Observable<number> {
return interval(ms).pipe(take(1))
}
// throws unless source observable emits withing timeout
export function throwIn<T>(timeout: number): OperatorFunction<T, T> {
return o =>
race(
o,
emitAfter$(timeout).pipe(
map(() => {
throw new Error('timeout')
}),
),
)
}
// o.pipe(squash) : Observable<void> regardless of o emission type.
export const squash = map(() => {})
/*
The main purpose of fromSync$ is to normalize error handling during a sequence
of actions beginning with a standard synchronous action and followed by a pipe.
For example, imagine we have `f(s: S): T` which might throw, and we wish to define the following:
```
function observableF(t: T): Observable<any> {
const s = f(t)
return someFunctionReturningAnObservable(s)
}
```
For the caller, `observableF(t).pipe(...).subscribe({ error: e => console.error('observable errored!') })`
might throw an error from `f` which does not result in 'observable errored!' being logged.
We could fix this with...
```
function observableF(t: T): Observable<any> {
try {
const s = f(t)
return someFunctionReturningAnObservable(s)
} catch(e) {
return throwError(e)
}
}
```
or we could use fromSync as below
```
function observableF(t: T): Observable<any> {
return fromSync$(f, t).concatMap(someFunctionReturningAnObservable)
}
```
*/
export function fromSync$<S, T>(sync: (s: S) => T, s: S): Observable<T>
export function fromSync$<T>(sync: () => T): Observable<T>
export function fromSync$<S, T>(sync: (s: S) => T, s?: S): Observable<T> {
return new Observable((subscriber: Observer<T>) => {
try {
subscriber.next(sync(s as S))
subscriber.complete()
} catch (e) {
subscriber.error(e)
}
})
}