diff --git a/Projects/Core/StreamListener/Interface/AnyStreamContinuation.swift b/Projects/Core/StreamListener/Interface/AnyStreamContinuation.swift deleted file mode 100644 index 5fb3814..0000000 --- a/Projects/Core/StreamListener/Interface/AnyStreamContinuation.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -public class AnyStreamContinuation { - private let _yield: (Any) -> Void - - public init(_ continuation: AsyncStream.Continuation) { - self._yield = { value in - guard let value = value as? T else { return } - continuation.yield(value) - } - } - - public func yield(_ value: Any) { - _yield(value) - } -} diff --git a/Projects/Core/StreamListener/Interface/StreamContinuation.swift b/Projects/Core/StreamListener/Interface/StreamContinuation.swift new file mode 100644 index 0000000..c010b8a --- /dev/null +++ b/Projects/Core/StreamListener/Interface/StreamContinuation.swift @@ -0,0 +1,25 @@ +import Foundation + +public class StreamContinuation { + private let _yield: (any StreamType) -> Void + private let _finish: () -> Void + + public init(_ continuation: AsyncStream.Continuation) { + self._yield = { value in + guard let value = value as? T else { return } + continuation.yield(value) + } + + self._finish = { + continuation.finish() + } + } + + public func yield(_ value: any StreamType) { + _yield(value) + } + + public func finish() { + _finish() + } +} diff --git a/Projects/Core/StreamListener/Interface/StreamListenerInterface.swift b/Projects/Core/StreamListener/Interface/StreamListenerInterface.swift index 3b8a473..16f0b82 100644 --- a/Projects/Core/StreamListener/Interface/StreamListenerInterface.swift +++ b/Projects/Core/StreamListener/Interface/StreamListenerInterface.swift @@ -10,9 +10,19 @@ import Foundation import Dependencies import DependenciesMacros +// MARK: - Stream releated Protocol + +public typealias StreamKey = String + +public protocol StreamType: Hashable { + static var key: StreamKey { get } +} + +// MARK: - StreamListener + public protocol StreamListenerProtocol { - func send(_ state: T) async - func receive(_ type: T.Type) -> AsyncStream + func send(_ state: T) async + func receive(_ type: T.Type) -> AsyncStream } @DependencyClient @@ -30,8 +40,8 @@ extension StreamListener: TestDependencyKey { } private struct StreamListenerTestImpl: StreamListenerProtocol { - func send(_ state: T) async {} - func receive(_ type: T.Type) -> AsyncStream { .never } + func send(_ state: T) async {} + func receive(_ type: T.Type) -> AsyncStream { .never } } /* diff --git a/Projects/Core/StreamListener/Interface/Streams.swift b/Projects/Core/StreamListener/Interface/Streams.swift deleted file mode 100644 index 8e8be2f..0000000 --- a/Projects/Core/StreamListener/Interface/Streams.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -// MARK: StreamType - -public protocol StreamTypeProtocol: Hashable { - static var key: StreamType { get } -} - -public enum StreamType: Hashable { - case serverState - case retry - case toast -} - -public enum ServerState: StreamTypeProtocol { - public static var key: StreamType { .serverState } - case requestStarted - case requestCompleted - case errorOccured - case networkDisabled -} diff --git a/Projects/Core/StreamListener/Sources/StreamListener.swift b/Projects/Core/StreamListener/Sources/StreamListener.swift index 6eaf6f4..7ccd2b1 100644 --- a/Projects/Core/StreamListener/Sources/StreamListener.swift +++ b/Projects/Core/StreamListener/Sources/StreamListener.swift @@ -22,11 +22,11 @@ extension StreamListener: DependencyKey { final class StreamListenerImpl: StreamListenerProtocol { private let actor = StreamActor() - func send(_ state: T) async { - await actor.yield(type: T.key, value: T.self) + func send(_ state: T) async { + await actor.yield(key: T.key, value: state) } - func receive(_ type: T.Type) -> AsyncStream { + func receive(_ type: T.Type) -> AsyncStream { let (stream, continuation) = AsyncStream.makeStream() Task { await actor.register(key: T.key, continuation: continuation) @@ -36,18 +36,24 @@ final class StreamListenerImpl: StreamListenerProtocol { } private actor StreamActor { - private var streams: [StreamType: AnyStreamContinuation] = [:] - - func register(key: StreamType, continuation: AsyncStream.Continuation) { - streams[key] = AnyStreamContinuation(continuation) + private var streams: [StreamKey: [StreamContinuation]] = [:] + + func register(key: StreamKey, continuation: AsyncStream.Continuation) { + let newContinuation = StreamContinuation(continuation) + if streams[key] == nil { + streams[key] = [newContinuation] + } else { + streams[key]?.append(newContinuation) + } } - func yield(type: StreamType, value: T.Type) { - guard let continuation = streams[type] else { return } - continuation.yield(value) + func yield(key: StreamKey, value: T) { + guard let continuations = streams[key] else { return } + continuations.forEach { $0.yield(value) } } - func remove(type: StreamType) { - streams[type] = nil + func remove(key: StreamKey) { + streams[key]?.forEach { $0.finish() } + streams[key] = nil } } diff --git a/Projects/Domain/AppService/Sources/ServerStateStream.swift b/Projects/Domain/AppService/Sources/ServerStateStream.swift new file mode 100644 index 0000000..97a9742 --- /dev/null +++ b/Projects/Domain/AppService/Sources/ServerStateStream.swift @@ -0,0 +1,22 @@ +// +// ServerStateStream.swift +// AppService +// +// Created by 김지현 on 12/25/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import StreamListenerInterface + +public enum ServerState: StreamType { + public static var key: StreamKey { "serverState" } + case requestStarted + case requestCompleted + case errorOccured + case networkDisabled +} + +public struct RetryState: StreamType { + public static var key: StreamKey { "retryState" } + public var retry: Int? +} diff --git a/Projects/Feature/CatFeature/Sources/NamingCat/NamingCatCore.swift b/Projects/Feature/CatFeature/Sources/NamingCat/NamingCatCore.swift index cb52bb6..28bff8b 100644 --- a/Projects/Feature/CatFeature/Sources/NamingCat/NamingCatCore.swift +++ b/Projects/Feature/CatFeature/Sources/NamingCat/NamingCatCore.swift @@ -13,6 +13,7 @@ import DesignSystem import UserServiceInterface import DatabaseClientInterface import StreamListenerInterface +import AppService import ComposableArchitecture import RiveRuntime