mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-08-30 17:10:56 +00:00
Cleanup
This commit is contained in:
parent
07bf521414
commit
14666070e5
@ -2,65 +2,31 @@ import Foundation
|
||||
import OSLog
|
||||
import SecretKit
|
||||
|
||||
public struct Session: Sendable {
|
||||
|
||||
public let messages: AsyncStream<Data>
|
||||
public let provenance: SigningRequestProvenance
|
||||
|
||||
private let fileHandle: FileHandle
|
||||
private let continuation: AsyncStream<Data>.Continuation
|
||||
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Session")
|
||||
|
||||
init(fileHandle: FileHandle) {
|
||||
self.fileHandle = fileHandle
|
||||
provenance = SigningRequestTracer().provenance(from: fileHandle)
|
||||
(messages, continuation) = AsyncStream.makeStream()
|
||||
Task { [continuation, logger] in
|
||||
await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor()
|
||||
for await _ in NotificationCenter.default.notifications(named: .NSFileHandleDataAvailable, object: fileHandle) {
|
||||
let data = fileHandle.availableData
|
||||
guard !data.isEmpty else {
|
||||
logger.debug("Socket controller received empty data, ending continuation.")
|
||||
continuation.finish()
|
||||
try fileHandle.close()
|
||||
return
|
||||
}
|
||||
continuation.yield(data)
|
||||
logger.debug("Socket controller yielded data.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func write(_ data: Data) async throws {
|
||||
try fileHandle.write(contentsOf: data)
|
||||
await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor()
|
||||
}
|
||||
|
||||
public func close() throws {
|
||||
logger.debug("Session closed.")
|
||||
continuation.finish()
|
||||
try fileHandle.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// A controller that manages socket configuration and request dispatching.
|
||||
public struct SocketController {
|
||||
|
||||
/// The active SocketPort.
|
||||
/// A stream of Sessions. Each session represents one connection to a class communicating with the socket. Multiple Sessions may be active simultaneously.
|
||||
public let sessions: AsyncStream<Session>
|
||||
|
||||
/// A continuation to create new sessions.
|
||||
private let sessionsContinuation: AsyncStream<Session>.Continuation
|
||||
|
||||
/// The active SocketPort. Must be retained to be kept valid.
|
||||
private let port: SocketPort
|
||||
|
||||
/// The FileHandle for the main socket.
|
||||
private let fileHandle: FileHandle
|
||||
|
||||
/// Logger for the socket controller.
|
||||
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "SocketController")
|
||||
private let requestTracer = SigningRequestTracer()
|
||||
|
||||
public let sessions: AsyncStream<Session>
|
||||
public let continuation: AsyncStream<Session>.Continuation
|
||||
/// Tracer which determines who originates a socket connection.
|
||||
private let requestTracer = SigningRequestTracer()
|
||||
|
||||
/// Initializes a socket controller with a specified path.
|
||||
/// - Parameter path: The path to use as a socket.
|
||||
public init(path: String) {
|
||||
(sessions, continuation) = AsyncStream<Session>.makeStream()
|
||||
(sessions, sessionsContinuation) = AsyncStream<Session>.makeStream()
|
||||
logger.debug("Socket controller setting up at \(path)")
|
||||
if let _ = try? FileManager.default.removeItem(atPath: path) {
|
||||
logger.debug("Socket controller removed existing socket")
|
||||
@ -70,12 +36,12 @@ public struct SocketController {
|
||||
logger.debug("Socket controller path is clear")
|
||||
port = SocketPort(path: path)
|
||||
fileHandle = FileHandle(fileDescriptor: port.socket, closeOnDealloc: true)
|
||||
Task { [fileHandle, continuation, logger] in
|
||||
Task { [fileHandle, sessionsContinuation, logger] in
|
||||
for await notification in NotificationCenter.default.notifications(named: .NSFileHandleConnectionAccepted) {
|
||||
logger.debug("Socket controller accepted connection")
|
||||
guard let new = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { continue }
|
||||
let session = Session(fileHandle: new)
|
||||
continuation.yield(session)
|
||||
sessionsContinuation.yield(session)
|
||||
await fileHandle.acceptConnectionInBackgroundAndNotifyOnMainActor()
|
||||
}
|
||||
}
|
||||
@ -85,8 +51,68 @@ public struct SocketController {
|
||||
|
||||
}
|
||||
|
||||
extension FileHandle {
|
||||
extension SocketController {
|
||||
|
||||
/// A session represents a connection that has been established between the two ends of the socket.
|
||||
public struct Session: Sendable {
|
||||
|
||||
/// Data received by the socket.
|
||||
public let messages: AsyncStream<Data>
|
||||
|
||||
/// The provenance of the process that established the session.
|
||||
public let provenance: SigningRequestProvenance
|
||||
|
||||
/// A FileHandle used to communicate with the socket.
|
||||
private let fileHandle: FileHandle
|
||||
|
||||
/// A continuation for issuing new messages.
|
||||
private let messagesContinuation: AsyncStream<Data>.Continuation
|
||||
|
||||
/// A logger for the session.
|
||||
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Session")
|
||||
|
||||
/// Initializes a new Session.
|
||||
/// - Parameter fileHandle: The FileHandle used to communicate with the socket.
|
||||
init(fileHandle: FileHandle) {
|
||||
self.fileHandle = fileHandle
|
||||
provenance = SigningRequestTracer().provenance(from: fileHandle)
|
||||
(messages, messagesContinuation) = AsyncStream.makeStream()
|
||||
Task { [messagesContinuation, logger] in
|
||||
await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor()
|
||||
for await _ in NotificationCenter.default.notifications(named: .NSFileHandleDataAvailable, object: fileHandle) {
|
||||
let data = fileHandle.availableData
|
||||
guard !data.isEmpty else {
|
||||
logger.debug("Socket controller received empty data, ending continuation.")
|
||||
messagesContinuation.finish()
|
||||
try fileHandle.close()
|
||||
return
|
||||
}
|
||||
messagesContinuation.yield(data)
|
||||
logger.debug("Socket controller yielded data.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes new data to the socket.
|
||||
/// - Parameter data: The data to write.
|
||||
public func write(_ data: Data) async throws {
|
||||
try fileHandle.write(contentsOf: data)
|
||||
await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor()
|
||||
}
|
||||
|
||||
/// Closes the socket and cleans up resources.
|
||||
public func close() throws {
|
||||
logger.debug("Session closed.")
|
||||
messagesContinuation.finish()
|
||||
try fileHandle.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension FileHandle {
|
||||
|
||||
/// Ensures waitForDataInBackgroundAndNotify will be called on the main actor.
|
||||
@MainActor func waitForDataInBackgroundAndNotifyOnMainActor() {
|
||||
waitForDataInBackgroundAndNotify()
|
||||
@ -101,7 +127,7 @@ extension FileHandle {
|
||||
|
||||
}
|
||||
|
||||
extension SocketPort {
|
||||
private extension SocketPort {
|
||||
|
||||
convenience init(path: String) {
|
||||
var addr = sockaddr_un()
|
||||
|
Loading…
Reference in New Issue
Block a user