/** * Tae Won Ha - http://taewon.de - @hataewon * See LICENSE */ import Foundation import RxSwift class StateContext { let stateSource: Observable let actionEmitter = Emitter() init() { self.stateSource = self.stateSubject.asObservable() let actionSource = self.actionEmitter.observable self.httpServerService = HttpServerService(port: NetUtils.openPort()) Observable .of( actionSource .mapOmittingNil { $0 as? AppDelegate.Action } .map { StateActionPair(state: self.appState, action: $0, modified: false) } .transform(by: self.appDelegateTransformer) .filter { $0.modified } .map { $0.state }, actionSource .mapOmittingNil { $0 as? UuidAction } .map { StateActionPair(state: self.appState, action: $0, modified: false) } .transform(by: self.uiRootTransformer) .filter { $0.modified } .map { $0.state } ) .merge() .subscribe(onNext: { state in self.appState = state self.stateSubject.onNext(self.appState) }) .addDisposableTo(self.disposeBag) actionSource .mapOmittingNil { $0 as? UuidAction } .mapOmittingNil { action in guard let mainWindowState = self.appState.mainWindows[action.uuid] else { return nil } return StateActionPair(state: UuidState(uuid: action.uuid, state: mainWindowState), action: action.payload, modified: false) } .transform(by: self.mainWindowTransformer) .transform(by: self.previewTransformer) .filter { $0.modified } .map { $0.state } .applyState(to: self.httpServerService) .subscribe(onNext: { state in self.appState.mainWindows[state.uuid] = state.payload self.stateSubject.onNext(self.appState) }) .addDisposableTo(self.disposeBag) actionSource.debug().subscribe().addDisposableTo(self.disposeBag) stateSource.debug().subscribe().addDisposableTo(self.disposeBag) } fileprivate let stateSubject = PublishSubject() fileprivate let scheduler = SerialDispatchQueueScheduler(qos: .userInitiated) fileprivate let disposeBag = DisposeBag() fileprivate var appState = AppState.default fileprivate let appDelegateTransformer = AppDelegateTransformer() fileprivate let uiRootTransformer = UiRootTransformer() fileprivate let mainWindowTransformer = MainWindowTransformer() fileprivate let previewTransformer = PreviewTransformer() fileprivate let httpServerService: HttpServerService } extension Observable { fileprivate func transform(by transformer: T) -> Observable where T.Element == Element { return transformer.transform(self) } fileprivate func applyState(to service: S) -> Observable where S.StateType == Element { return service.apply(self) } }