Guest User

Untitled

a guest
Apr 13th, 2018
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.54 KB | None | 0 0
  1. interface LoginRequest {
  2. kind: "LoginRequest";
  3. username: string;
  4. password: string;
  5. }
  6.  
  7. interface LoginSuccess {
  8. kind: "LoginSuccess";
  9. username: string;
  10. }
  11.  
  12. interface LoginError {
  13. kind: "LoginError";
  14. error: string;
  15. }
  16.  
  17. interface Logout {
  18. kind: "Logout";
  19. }
  20.  
  21. interface State {
  22. username?: string;
  23. }
  24.  
  25. type Action = LoginRequest | LoginSuccess | LoginError | Logout;
  26.  
  27. type AffectorFn = <S, A>(
  28. s: S,
  29. a: A,
  30. s$: Observable<S>,
  31. a$: Observable<A>
  32. ) => [S, Observable<A>];
  33.  
  34. function affector(
  35. s: State,
  36. a: Action,
  37. s$: Observable<State>,
  38. a$: Observable<Action>
  39. ): [State, Observable<Action>] {
  40. switch (a.kind) {
  41. case "LoginRequest":
  42. // the LoginRequest is cancellable if it sees another Login or Logout action while executing
  43. return [
  44. s,
  45. of<Action>({ kind: "LoginSuccess", username: a.username }).pipe(
  46. delay(1500),
  47. takeUntil(
  48. a$.pipe(
  49. filter(a => {
  50. switch (a.kind) {
  51. case "LoginSuccess":
  52. case "LoginRequest":
  53. case "Logout":
  54. return true;
  55. }
  56. return false;
  57. })
  58. )
  59. )
  60. )
  61. ];
  62. case "LoginSuccess":
  63. return [{ ...s, username: a.username }, empty()];
  64. case "Logout":
  65. return [{ ...s, username: null }, empty()];
  66. }
  67. return [s, empty()];
  68. }
  69.  
  70. const affect = (
  71. affector: AffectorFn | any,
  72. init: State,
  73. action$$: Subject<Observable<Action>>
  74. ): Observable<State> => {
  75. const state$ = new Observable(observer => {
  76. console.log("creating observable");
  77. let current = init;
  78. const action$ = action$$.pipe(flatMap(a$ => a$));
  79. observer.next(current);
  80. const sub = action$
  81. .pipe(
  82. tap(a => {
  83. console.log("running action", a);
  84. }),
  85. map(a => {
  86. return affector(current, a, state$, action$);
  87. })
  88. )
  89. .subscribe(tuple => {
  90. current = tuple[0];
  91. observer.next(current);
  92. action$$.next(tuple[1]);
  93. });
  94. return () => {
  95. sub.unsubscribe();
  96. };
  97. });
  98. // TODO figure out how to turn into a publishBehavior here in rxjs6
  99. return state$;
  100. };
  101.  
  102. const action$$ = new Subject<Observable<Action>>();
  103. const state$ = affect(affector, {}, action$$);
  104.  
  105. console.log("subscribing");
  106. state$.subscribe(state => {
  107. console.log(state);
  108. });
  109.  
  110. // push a couple of actions
  111. action$$.next(
  112. of<Action>({
  113. kind: "LoginRequest",
  114. username: "supershabam",
  115. password: "poop"
  116. })
  117. );
  118. action$$.next(of<Action>({ kind: "Logout" }));
Add Comment
Please, Sign In to add comment