Skip to content

Instantly share code, notes, and snippets.

@dakom
Last active February 27, 2018 16:51
Show Gist options
  • Save dakom/9dd56c6c1f16c43e91fd08be386cc624 to your computer and use it in GitHub Desktop.
Save dakom/9dd56c6c1f16c43e91fd08be386cc624 to your computer and use it in GitHub Desktop.
Sodium loaders (wrapping loader-helpers)
//Copied from https://github.com/dakom/sodium-loaders
import {
loadXhrFactory, LoaderXhr, LoaderXhrRequest, LoaderXhrResponse, LOADER_TYPE_XHR,
loadImageFactory, LoaderImage, LoaderImageRequest, LoaderImageResponse, LOADER_TYPE_IMAGE,
loadTextureFactory, LoaderTexture, LoaderTextureRequest, LoaderTextureResponse, LOADER_TYPE_TEXTURE,
LoaderResponseAny,
LoaderRequestAny,
LoaderCallbackAny,
LoaderAny,
isLoaderXhr
} from "loader-helpers";
import {Cell, Stream, StreamSink} from "sodiumjs";
import { Maybe, S, Either } from '../sanctuary/Sanctuary';
//types for consistency
export type MaybeStreamOrCellRequest<A> = Cell<Maybe<A>> | Stream<Maybe<A>>;
export type StreamOrCellRequest<A> = Cell<A> | Stream<A>;
export type MultiMaybeStreamOrCellRequest<I, A> = Cell<{ id: I, mReq: Maybe<A> }> | Stream<{ id: I, mReq: Maybe<A> }>
export type MultiStreamOrCellRequest<I, A> = Cell<{ id: I, req: A }> | Stream<{ id: I, req: A }>
export type SodiumLoader<A> = {close: () => void, sResponse: Stream<Maybe<Either<A>>>};
export type SodiumMultiLoader<I, A> = {close: (id:I) => void, sResponse: Stream<{ id: I, mResp: Maybe<Either<A>> }>};
//generic helper/utils
const requestToMaybe = <A>(request: StreamOrCellRequest<A>) => (request as any).map(S.Just) as MaybeStreamOrCellRequest<A>;
const multiRequestToMaybe = <I, A>(request: MultiStreamOrCellRequest<I, A>) => (request as any).map(({id, req}) => ({id, mReq: S.Just(req)})) as MultiMaybeStreamOrCellRequest<I, A>;
const closeLoader = (ldr: LoaderAny) => {
if (isLoaderXhr(ldr)) {
ldr.close();
}
}
/*
Generic functions are internal only. Exported versions are specific
*/
const _baseSingle = <A, B>
(loadFactory: (req: A, callback: LoaderCallbackAny) => LoaderAny) =>
(cache: Map<A, Either<B>>) =>
(scRequest: MaybeStreamOrCellRequest<A>): SodiumLoader<B> => {
const sResponse = new StreamSink<Maybe<Either<B>>>();
let mLdr: Maybe<LoaderAny> = S.Nothing;
const doClose = () => {
S.map(closeLoader)(mLdr)
mLdr = S.Nothing;
}
scRequest.listen(mReq => {
doClose();
//listen->send must push to the next callstack
setTimeout(() => S.maybe_
(() => sResponse.send(S.Nothing))
(req => {
if (cache && cache.has(req)) {
sResponse.send(S.Just(cache.get(req)));
} else {
sResponse.send(S.Nothing);
//loading inherently will be on the next stack, or at worst as a microtask
mLdr = S.Just(
loadFactory(req, eResponse => {
if (cache) {
cache.set(req, eResponse);
}
sResponse.send(S.Just(eResponse));
doClose();
})
);
}
})
(mReq)
, 0);
});
return {close: doClose, sResponse};
}
const _baseMulti = <I, A, B>
(loadFactory: (req: A, callback: LoaderCallbackAny) => LoaderAny) =>
(cache: Map<A, Either<B>>) =>
(scRequest: MultiMaybeStreamOrCellRequest<I, A>): SodiumMultiLoader<I,B> => {
const sResponse = new StreamSink<{ id: I, mResp: Maybe<Either<B>> }>()
const loaderMap = new Map<I, LoaderAny>();
const doClose = (id: I) => {
if (loaderMap.has(id)) {
closeLoader(loaderMap.get(id));
loaderMap.delete(id);
}
}
scRequest.listen(request => {
const { id, mReq } = request;
//listen->send must push to the next callstack
setTimeout(() => S.maybe_
(() => sResponse.send({ id, mResp: S.Nothing }))
(req => {
if (cache && cache.has(req)) {
sResponse.send({ id, mResp: S.Just(cache.get(req)) });
} else {
sResponse.send({ id, mResp: S.Nothing });
//loading inherently will be on the next stack, or at worst as a microtask
doClose(id);
loaderMap.set(id, loadFactory(req, eResponse => {
if (cache) {
cache.set(req, eResponse);
}
sResponse.send({ id, mResp: S.Just(eResponse) });
doClose(id);
}))
}
})
(mReq)
, 0);
});
return {close: doClose, sResponse};
}
//Style: Single, Maybe: Yes, Cache: Yes
export const createSodiumMaybeLoaderCacheTexture =
(cache: Map<LoaderTextureRequest, Either<LoaderTextureResponse>>) =>
(scRequest: MaybeStreamOrCellRequest<LoaderTextureRequest>) =>
_baseSingle<LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (cache) (scRequest);
export const createSodiumMaybeLoaderCacheImage =
(cache: Map<LoaderImageRequest, Either<LoaderImageResponse>>) =>
(scRequest: MaybeStreamOrCellRequest<LoaderImageRequest>) =>
_baseSingle<LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (cache) (scRequest);
export const createSodiumMaybeLoaderCacheXhr =
(cache: Map<LoaderXhrRequest, Either<LoaderXhrResponse>>) =>
(scRequest: MaybeStreamOrCellRequest<LoaderXhrRequest>) =>
_baseSingle<LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (cache) (scRequest);
//Style: Single, Maybe: No, Cache: Yes
export const createSodiumLoaderCacheTexture=
(cache: Map<LoaderTextureRequest, Either<LoaderTextureResponse>>) =>
(scRequest: StreamOrCellRequest<LoaderTextureRequest>) =>
_baseSingle<LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (cache) (requestToMaybe(scRequest));
export const createSodiumLoaderCacheImage =
(cache: Map<LoaderImageRequest, Either<LoaderImageResponse>>) =>
(scRequest: StreamOrCellRequest<LoaderImageRequest>) =>
_baseSingle<LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (cache) (requestToMaybe(scRequest));
export const createSodiumLoaderCacheXhr =
(cache: Map<LoaderXhrRequest, Either<LoaderXhrResponse>>) =>
(scRequest: StreamOrCellRequest<LoaderXhrRequest>) =>
_baseSingle<LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (cache) (requestToMaybe(scRequest));
//Style: Single, Maybe: Yes, Cache: No
export const createSodiumMaybeLoaderTexture =
(scRequest: MaybeStreamOrCellRequest<LoaderTextureRequest>) =>
_baseSingle<LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (null) (scRequest);
export const createSodiumMaybeLoaderImage =
(scRequest: MaybeStreamOrCellRequest<LoaderImageRequest>) =>
_baseSingle<LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (null) (scRequest);
export const createSodiumMaybeLoaderXhr =
(scRequest: MaybeStreamOrCellRequest<LoaderXhrRequest>) =>
_baseSingle<LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (null) (scRequest);
//Style: Single, Maybe: No, Cache: No
export const createSodiumLoaderTexture =
(scRequest: StreamOrCellRequest<LoaderTextureRequest>) =>
_baseSingle<LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (null) (requestToMaybe(scRequest));
export const createSodiumLoaderImage =
(scRequest: StreamOrCellRequest<LoaderImageRequest>) =>
_baseSingle<LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (null) (requestToMaybe(scRequest));
export const createSodiumLoaderXhr =
(scRequest: StreamOrCellRequest<LoaderXhrRequest>) =>
_baseSingle<LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (null) (requestToMaybe(scRequest));
///------------
//Style: Multi, Maybe: Yes, Cache: Yes
export const createMultiSodiumMaybeLoaderCacheTexture = <I>
(cache: Map<LoaderTextureRequest, Either<LoaderTextureResponse>>) =>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderTextureRequest>) =>
_baseMulti<I, LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (cache) (scRequest);
export const createMultiSodiumMaybeLoaderCacheImage = <I>
(cache: Map<LoaderImageRequest, Either<LoaderImageResponse>>) =>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderImageRequest>) =>
_baseMulti<I, LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (cache) (scRequest);
export const createMultiSodiumMaybeLoaderCacheXhr = <I>
(cache: Map<LoaderXhrRequest, Either<LoaderXhrResponse>>) =>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderXhrRequest>) =>
_baseMulti<I, LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (cache) (scRequest);
//Style: Multi, Maybe: No, Cache: Yes
export const createMultiSodiumLoaderCacheTexture= <I>
(cache: Map<LoaderTextureRequest, Either<LoaderTextureResponse>>) =>
(scRequest: MultiStreamOrCellRequest<I, LoaderTextureRequest>) =>
_baseMulti<I, LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (cache) (multiRequestToMaybe(scRequest));
export const createMultiSodiumLoaderCacheImage = <I>
(cache: Map<LoaderImageRequest, Either<LoaderImageResponse>>) =>
(scRequest: MultiStreamOrCellRequest<I, LoaderImageRequest>) =>
_baseMulti<I, LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (cache) (multiRequestToMaybe(scRequest));
export const createMultiSodiumLoaderCacheXhr = <I>
(cache: Map<LoaderXhrRequest, Either<LoaderXhrResponse>>) =>
(scRequest: MultiStreamOrCellRequest<I, LoaderXhrRequest>) =>
_baseMulti<I, LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (cache) (multiRequestToMaybe(scRequest));
//Style: Multi, Maybe: Yes, Cache: No
export const createMultiSodiumMaybeLoaderTexture = <I>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderTextureRequest>) =>
_baseMulti<I, LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (null) (scRequest);
export const createMultiSodiumMaybeLoaderImage = <I>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderImageRequest>) =>
_baseMulti<I, LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (null) (scRequest);
export const createMultiSodiumMaybeLoaderXhr = <I>
(scRequest: MultiMaybeStreamOrCellRequest<I, LoaderXhrRequest>) =>
_baseMulti<I, LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (null) (scRequest);
//Style: Multi, Maybe: No, Cache: No
export const createMultiSodiumLoaderTexture = <I>
(scRequest: MultiStreamOrCellRequest<I, LoaderTextureRequest>) =>
_baseMulti<I, LoaderTextureRequest, LoaderTextureResponse>(loadTextureFactory) (null) (multiRequestToMaybe(scRequest));
export const createMultiSodiumLoaderImage = <I>
(scRequest: MultiStreamOrCellRequest<I, LoaderImageRequest>) =>
_baseMulti<I, LoaderImageRequest, LoaderImageResponse>(loadImageFactory) (null) (multiRequestToMaybe(scRequest));
export const createMultiSodiumLoaderXhr = <I>
(scRequest: MultiStreamOrCellRequest<I, LoaderXhrRequest>) =>
_baseMulti<I, LoaderXhrRequest, LoaderXhrResponse>(loadXhrFactory) (null) (multiRequestToMaybe(scRequest));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment