Changes
16 changed files (+369/-155)
-
-
@@ -44,7 +44,8 @@ ((last.imageKey == nil) != (item.imageKey == nil))|| ((last.subtitle == nil) != (item.subtitle == nil)) if isProbablyDifferentItemKind { groups.append(.init(title: currentTitle, items: currentItems)) groups.append( .init(title: currentTitle, items: currentItems)) currentTitle = nil currentItems = [] }
-
@@ -53,7 +54,8 @@switch item.hint { case .header: if currentTitle != nil || currentItems.count > 0 { groups.append(.init(title: currentTitle, items: currentItems)) groups.append( .init(title: currentTitle, items: currentItems)) } currentItems = []
-
@@ -162,7 +164,8 @@self.loading = Task { rootPage = .loading do { logger.debug("Moving browse cursor to root on \(hierarchy.rawValue)") logger.debug( "Moving browse cursor to root on \(hierarchy.rawValue)") let browse = try BrowseService.BrowseResponse( try await conn.request(
-
@@ -253,22 +256,28 @@switch browse.action { case .list: guard let list = browse.list else { logger.warning("Roon server returned list action without payload") logger.warning( "Roon server returned list action without payload" ) return } let item = stack.last do { logger.debug("Updating the new current page after pop") logger.debug( "Updating the new current page after pop") let load = try BrowseService.LoadResponse( try await conn.request( Moo( load: .init( hierarchy: hierarchy, multiSessionKey: id.uuidString, hierarchy: hierarchy, multiSessionKey: id .uuidString, level: list.level, count: UInt(UInt16.max) count: UInt( UInt16.max) ) ) )
-
@@ -277,16 +286,20 @@if let item = item { pages[item] = .loaded( load.list, BrowseItemGroup.groupInto(items: load.items) BrowseItemGroup.groupInto( items: load.items) ) } else { rootPage = .loaded( load.list, BrowseItemGroup.groupInto(items: load.items) BrowseItemGroup.groupInto( items: load.items) ) } } catch { logger.error("Unable to load topmost page after pop: \(error)") logger.error( "Unable to load topmost page after pop: \(error)" ) } default: // TODO: Handle other cases
-
-
-
@@ -121,7 +121,8 @@ version: "1.0.0",publisher: "Shota FUJI", email: "pockawoooh@gmail.com", requiredServices: [ TransportService.id, BrowseService.id, ImageService.id, TransportService.id, BrowseService.id, ImageService.id, ], token: token, )
-
@@ -152,7 +153,8 @@ if let self = self {state = .waitingToReconnect } Logger().debug("Connection closed, reconnecting after interval") Logger().debug( "Connection closed, reconnecting after interval") try await Task.sleep( for: Self.reconnectionWindow
-
@@ -170,7 +172,9 @@ ),Connection.ConnectError.connectionNotReady( NWError.posix(.ECONNABORTED) ): Logger().info("Connection refused, retrying after 3 seconds") Logger().info( "Connection refused, retrying after 3 seconds" ) if let self = self { state = .waitingToReconnect
-
-
-
@@ -123,11 +123,15 @@Task { do { let res = try await self.conn.request( .init(control: .init(zoneID: zone.id, control: .play)) .init( control: .init( zoneID: zone.id, control: .play)) ) _ = try TransportService.ControlResponse.init(res) } catch { Logger().warning("Failed to send play request: \(error)") Logger().warning( "Failed to send play request: \(error)") } }
-
@@ -143,11 +147,15 @@Task { do { let res = try await self.conn.request( .init(control: .init(zoneID: zone.id, control: .pause)) .init( control: .init( zoneID: zone.id, control: .pause)) ) _ = try TransportService.ControlResponse.init(res) } catch { Logger().warning("Failed to send pause request: \(error)") Logger().warning( "Failed to send pause request: \(error)") } }
-
@@ -163,11 +171,16 @@Task { do { let res = try await self.conn.request( .init(control: .init(zoneID: zone.id, control: .previous)) .init( control: .init( zoneID: zone.id, control: .previous)) ) _ = try TransportService.ControlResponse.init(res) } catch { Logger().warning("Failed to send prev track request: \(error)") Logger().warning( "Failed to send prev track request: \(error)" ) } }
-
@@ -183,11 +196,16 @@Task { do { let res = try await self.conn.request( .init(control: .init(zoneID: zone.id, control: .next)) .init( control: .init( zoneID: zone.id, control: .next)) ) _ = try TransportService.ControlResponse.init(res) } catch { Logger().warning("Failed to send next track request: \(error)") Logger().warning( "Failed to send next track request: \(error)" ) } }
-
@@ -200,7 +218,8 @@ guard let zone = self.zone else {return .deviceNotFound } guard let event = event as? MPChangePlaybackPositionCommandEvent else { guard let event = event as? MPChangePlaybackPositionCommandEvent else { return .commandFailed }
-
@@ -210,14 +229,16 @@ let res = try await self.conn.request(.init( seek: .init( zoneID: zone.id, seconds: Int64(event.positionTime), seconds: Int64( event.positionTime), mode: .absolute ) ) ) _ = try TransportService.SeekResponse.init(res) } catch { Logger().warning("Failed to send seek request: \(error)") Logger().warning( "Failed to send seek request: \(error)") } }
-
@@ -255,7 +276,8 @@ commandCenter.nextTrackCommand.removeTarget(nextHandler)} if let seekHandler = seekHandler { commandCenter.changePlaybackPositionCommand.removeTarget(seekHandler) commandCenter.changePlaybackPositionCommand.removeTarget( seekHandler) } #endif }
-
@@ -346,7 +368,8 @@ height: UInt(size.height)) ) guard let url = url, let data = try? Data(contentsOf: url), guard let url = url, let data = try? Data(contentsOf: url), let image = NSImage(data: data) else { return NSImage(size: size)
-
-
-
@@ -41,7 +41,10 @@ Button {model?.model = nil } label: { Label { Text(String(localized: "Menu.Disconnect", defaultValue: "Disconnect")) Text( String( localized: "Menu.Disconnect", defaultValue: "Disconnect")) } icon: { Image(systemName: "powercode") }
-
@@ -133,7 +136,8 @@ }) }, onCancel: { self.model.model = ConnectionDataModel(cancelling: model) self.model.model = ConnectionDataModel( cancelling: model) } ) .focusedSceneValue(self.model)
-
-
-
@@ -55,7 +55,8 @@ } description: {Text( String( localized: "Browser.Error.Description", defaultValue: "An error occurred when loading the page." defaultValue: "An error occurred when loading the page." ) ) } actions: {
-
@@ -63,7 +64,9 @@ Button {model.reload() } label: { Text( String(localized: "Browser.Error.Retry", defaultValue: "Retry") String( localized: "Browser.Error.Retry", defaultValue: "Retry") ) } }
-
@@ -71,24 +74,40 @@ case .some(.loaded(let list, let groups)):List { ForEach(groups) { group in Section { ForEach(group.items, id: \.itemKey) { item in ForEach(group.items, id: \.itemKey) { item in switch item.hint { case .list, .actionList: NavigationLink(value: item) { NavigationLink(value: item) { Row(item) } case .action: Button { model.loadPage(item: item) model.loadPage( item: item) } label: { Row(item) .frame(maxWidth: .infinity, alignment: .leading) .frame( maxWidth: .infinity, alignment: .leading ) if model.pages[item]?.isLoading() ?? false { if model.pages[ item]? .isLoading() ?? false { ProgressView() // Row height in macOS is way shorter than other platforms. #if os(macOS) .controlSize(.small) #if os( macOS ) .controlSize( .small ) #endif } }
-
@@ -96,9 +115,13 @@ .buttonStyle(.borderless)// ".borderless" on macOS somehow renders in gray foreground color, // which looks like the button is disabled. #if os(macOS) .foregroundStyle(.foreground) .foregroundStyle( .foreground) #endif .disabled(model.pages[item]?.isLoading() ?? false) .disabled( model.pages[item]? .isLoading() ?? false) default: Row(item) }
-
-
-
@@ -67,63 +67,72 @@ switch hierarchy {case .browse: Text( String( localized: "ConnectedScene.Category.Explore", localized: "ConnectedScene.Category.Explore", defaultValue: "Explore" ) ) case .playlists: Text( String( localized: "ConnectedScene.Category.Playlists", localized: "ConnectedScene.Category.Playlists", defaultValue: "Playlists" ) ) case .settings: Text( String( localized: "ConnectedScene.Category.Settings", localized: "ConnectedScene.Category.Settings", defaultValue: "Settings" ) ) case .albums: Text( String( localized: "ConnectedScene.Category.Albums", localized: "ConnectedScene.Category.Albums", defaultValue: "Albums" ) ) case .artists: Text( String( localized: "ConnectedScene.Category.Artists", localized: "ConnectedScene.Category.Artists", defaultValue: "Artists" ) ) case .genres: Text( String( localized: "ConnectedScene.Category.Genres", localized: "ConnectedScene.Category.Genres", defaultValue: "Genres" ) ) case .composers: Text( String( localized: "ConnectedScene.Category.Composers", localized: "ConnectedScene.Category.Composers", defaultValue: "Composers" ) ) case .search: Text( String( localized: "ConnectedScene.Category.Search", localized: "ConnectedScene.Category.Search", defaultValue: "Search" ) ) case .internetRadio: Text( String( localized: "ConnectedScene.Category.InternetRadio", localized: "ConnectedScene.Category.InternetRadio", defaultValue: "Internet Radios" ) )
-
@@ -133,7 +142,9 @@ } detail: {if browsing.hierarchy != nil { NavigationStack(path: $browsing.stack) { Browser(model: browsing) .navigationDestination(for: BrowseService.Item.self) { item in .navigationDestination( for: BrowseService.Item.self ) { item in Browser(model: browsing, item: item) } }
-
-
-
@@ -43,16 +43,20 @@ Loading(onCancel: {onCancel() }) case .connected(let conn): ConnectedScreen(conn: conn, host: self.conn.host, port: self.conn.port) .environment( ImageURLBuilderDataModel(host: self.conn.host, port: self.conn.port) ) ConnectedScreen( conn: conn, host: self.conn.host, port: self.conn.port ) .environment( ImageURLBuilderDataModel( host: self.conn.host, port: self.conn.port) ) case .failed(RoonKit.ServerLookupError.notFound): ContentUnavailableView { Label { Text( String( localized: "ConnectionScreen.NotFound.Heading", localized: "ConnectionScreen.NotFound.Heading", defaultValue: "Server not found" ) )
-
@@ -62,7 +66,8 @@ }} description: { Text( String( localized: "ConnectionScreen.NotFound.Description", localized: "ConnectionScreen.NotFound.Description", defaultValue: "Server \(self.conn.serverID ?? "\(self.conn.host):\(self.conn.port)") does not found on network." )
-
@@ -73,9 +78,11 @@ onDisconnect()} label: { Text( String( localized: "ConnectionScreen.Disconnect", localized: "ConnectionScreen.Disconnect", defaultValue: "Close", comment: "Button label for aborting connection process." comment: "Button label for aborting connection process." ) ) }
-
@@ -85,7 +92,8 @@ onReconnect()} label: { Text( String( localized: "ConnectionScreen.Reconnect", localized: "ConnectionScreen.Reconnect", defaultValue: "Reconnect", comment: "Button label for connecting to Roon server from non-connected state."
-
@@ -98,7 +106,8 @@ ContentUnavailableView {Label { Text( String( localized: "ConnectionScreen.Cancelled.Heading", localized: "ConnectionScreen.Cancelled.Heading", defaultValue: "Connection cancelled" ) )
-
@@ -108,8 +117,10 @@ }} description: { Text( String( localized: "ConnectionScreen.Cancelled.Description", defaultValue: "Cancelled connecting to Roon server." localized: "ConnectionScreen.Cancelled.Description", defaultValue: "Cancelled connecting to Roon server." ) ) } actions: {
-
@@ -130,7 +141,8 @@ ContentUnavailableView {Label { Text( String( localized: "ConnectionScreen.Error.Heading", localized: "ConnectionScreen.Error.Heading", defaultValue: "Failed to connect" ) )
-
@@ -140,8 +152,10 @@ }} description: { Text( String( localized: "ConnectionScreen.Error.Description", defaultValue: "Failed to connect due to an error." localized: "ConnectionScreen.Error.Description", defaultValue: "Failed to connect due to an error." ) ) } actions: {
-
-
-
@@ -63,9 +63,11 @@ } label: {Label { Text( String( localized: "PlaybackBar.Previous", localized: "PlaybackBar.Previous", defaultValue: "Previous", comment: "A label for a previous button." comment: "A label for a previous button." ) ) } icon: {
-
@@ -85,9 +87,12 @@ } label: {Label { Text( String( localized: "PlaybackBar.Pause", defaultValue: "Pause", comment: "A label for a pause button." localized: "PlaybackBar.Pause", defaultValue: "Pause", comment: "A label for a pause button." ) ) } icon: {
-
@@ -107,9 +112,12 @@ } label: {Label { Text( String( localized: "PlaybackBar.Play", defaultValue: "Play", comment: "A label for a play button." localized: "PlaybackBar.Play", defaultValue: "Play", comment: "A label for a play button." ) ) } icon: {
-
@@ -130,9 +138,11 @@ } label: {Label { Text( String( localized: "PlaybackBar.Next", localized: "PlaybackBar.Next", defaultValue: "Next", comment: "A label for a next button." comment: "A label for a next button." ) ) } icon: {
-
@@ -166,16 +176,39 @@ model.suppressSeekUpdates = true} else { Task { do { let msg = try await model.conn.request( try Moo( seek: .init(zoneID: zone.id, seconds: Int64(model.seek)) ), timeout: .seconds(2) ) let msg = try await model.conn .request( try Moo( seek: .init( zoneID: zone .id, seconds: Int64( model .seek ) ) ), timeout: .seconds( 2 ) ) _ = try TransportService.SeekResponse(msg) _ = try TransportService .SeekResponse( msg) } catch { Logger().warning("Failed to seek: \(error)") Logger().warning( "Failed to seek: \(error)" ) } // If we resume accepting seek change events before seek request,
-
@@ -184,7 +217,8 @@ // then seek request updates seek then an event after that moves// seekbar position. From user's perspective, this is "seekbar // jumps to previous position then jumps again to the dragged // position". That's not good UX. model.suppressSeekUpdates = false model.suppressSeekUpdates = false } } }
-
@@ -210,7 +244,8 @@ } label: {Label { Text( String( localized: "PlaybackBar.ZonePanel.Label", localized: "PlaybackBar.ZonePanel.Label", defaultValue: "Zone" ) )
-
@@ -224,14 +259,20 @@ .sheet(isPresented: $isOutputPanelVisible) {NavigationStack { ZoneOptionsPanel(model: model) .toolbar { ToolbarItem(placement: .confirmationAction) { ToolbarItem( placement: .confirmationAction ) { Button { isOutputPanelVisible = false isOutputPanelVisible = false } label: { Text( String( localized: "PlaybackBar.ZonePanel.Close", defaultValue: "Done" localized: "PlaybackBar.ZonePanel.Close", defaultValue: "Done" ) ) }
-
@@ -302,8 +343,11 @@ Moo(verb: "CONTINUE", service: "idk", headers: [ "Content-Type": "application/json", "Content-Length": String(body.utf8.count, radix: 10), "Content-Type": "application/json", "Content-Length": String( body.utf8.count, radix: 10), ], body: body.data(using: .utf8)! )
-
-
-
@@ -49,7 +49,8 @@ Section {TextField(text: $host) { Text( String( localized: "ServerAddressForm.Host.Label", localized: "ServerAddressForm.Host.Label", defaultValue: "IPv4 address" ) )
-
@@ -59,7 +60,8 @@TextField(value: $port, formatter: portFormatter) { Text( String( localized: "ServerAddressForm.Port.Label", localized: "ServerAddressForm.Port.Label", defaultValue: "HTTP port" ) )
-
@@ -76,7 +78,8 @@ } footer: {if let resolvedHost = resolvedHost { Text( String( localized: "ServerAddressForm.Description", localized: "ServerAddressForm.Description", defaultValue: "By tapping Connect, Plac will open a HTTP connection to \("\(resolvedHost):\(port)")" )
-
@@ -84,8 +87,10 @@ )} else { Text( String( localized: "ServerAddressForm.InvalidHost.Description", defaultValue: "\"\(host)\" is not a valid IPv4 address." localized: "ServerAddressForm.InvalidHost.Description", defaultValue: "\"\(host)\" is not a valid IPv4 address." ) ) }
-
@@ -109,14 +114,16 @@ onConnectAction?(resolvedHost, port)} label: { Text( String( localized: "ServerAddressForm.Connect", localized: "ServerAddressForm.Connect", defaultValue: "Connect" ) ) } .alert( String( localized: "ServerAddressForm.InvalidHost.Title", localized: "ServerAddressForm.InvalidHost.Title", defaultValue: "Fill valid IPv4 address" ), isPresented: $isInvalidHost
-
@@ -126,7 +133,8 @@ isInvalidHost = false} label: { Text( String( localized: "ServerAddressForm.InvalidHost.Close", localized: "ServerAddressForm.InvalidHost.Close", defaultValue: "Close" ) )
-
@@ -134,8 +142,10 @@ }} message: { Text( String( localized: "ServerAddressForm.InvalidHost.Description", defaultValue: "\"\(host)\" is not a valid IPv4 address." localized: "ServerAddressForm.InvalidHost.Description", defaultValue: "\"\(host)\" is not a valid IPv4 address." ) ) }
-
-
-
@@ -106,9 +106,12 @@ onConnectAction?(server)} label: { Text( String( localized: "ServerDiscovery.Open", defaultValue: "Open", comment: "Label for a button that starts a connection." localized: "ServerDiscovery.Open", defaultValue: "Open", comment: "Label for a button that starts a connection." ) ) }
-
@@ -118,9 +121,11 @@VStack(alignment: .leading) { Text( String( localized: "ServerDiscovery.Version", localized: "ServerDiscovery.Version", defaultValue: "Version", comment: "A label for server version field." comment: "A label for server version field." ) ) .font(.headline)
-
@@ -132,15 +137,20 @@VStack(alignment: .leading) { Text( String( localized: "ServerDiscovery.Host", localized: "ServerDiscovery.Host", defaultValue: "IP Address", comment: "A label for server host field." comment: "A label for server host field." ) ) .font(.headline) Text(verbatim: "\(server.host):\(String(server.port, radix: 10))") .font(.subheadline) Text( verbatim: "\(server.host):\(String(server.port, radix: 10))" ) .font(.subheadline) } Spacer()
-
@@ -155,7 +165,8 @@ Text(String( localized: "ServerDiscovery.Title", defaultValue: "Servers", comment: "Title of server discovery scene. Not visible on macOS." comment: "Title of server discovery scene. Not visible on macOS." ) ) )
-
@@ -169,21 +180,28 @@ } label: {Label { Text( String( localized: "ServerDiscovery.Refresh", localized: "ServerDiscovery.Refresh", defaultValue: "Refresh", comment: "Icon label for refresh button." comment: "Icon label for refresh button." ) ) } icon: { Image(systemName: "arrow.trianglehead.clockwise") Image( systemName: "arrow.trianglehead.clockwise" ) } } .help( Text( String( localized: "ServerDiscovery.RefreshHelp", localized: "ServerDiscovery.RefreshHelp", defaultValue: "Refresh server list", comment: "Help tooltip text for refresh button." comment: "Help tooltip text for refresh button." ) ) )
-
@@ -197,7 +215,8 @@ ContentUnavailableView {Label { Text( String( localized: "ServerDiscovery.Loading.Heading", localized: "ServerDiscovery.Loading.Heading", defaultValue: "Scanning" ) )
-
@@ -208,8 +227,10 @@ .symbolEffect(.variableColor)} description: { Text( String( localized: "ServerDiscovery.Loading.Description", defaultValue: "Scanning Roon servers on local network." localized: "ServerDiscovery.Loading.Description", defaultValue: "Scanning Roon servers on local network." ) ) }
-
@@ -219,8 +240,10 @@ ContentUnavailableView {Label { Text( String( localized: "ServerDiscovery.Empty.Heading", defaultValue: "No server found" localized: "ServerDiscovery.Empty.Heading", defaultValue: "No server found" ) ) } icon: {
-
@@ -229,8 +252,10 @@ }} description: { Text( String( localized: "ServerDiscovery.Empty.Description", defaultValue: "No Roon server found on local network." localized: "ServerDiscovery.Empty.Description", defaultValue: "No Roon server found on local network." ) ) }
-
@@ -239,7 +264,8 @@ Text(String( localized: "ServerDiscovery.Placeholder", defaultValue: "Select server from list", comment: "Placeholder text for server details view." comment: "Placeholder text for server details view." ) ) }
-
@@ -251,7 +277,8 @@ ContentUnavailableView {Label { Text( String( localized: "ServerDiscovery.NetworkError.Heading", localized: "ServerDiscovery.NetworkError.Heading", defaultValue: "Scan failed" ) )
-
@@ -261,7 +288,8 @@ }} description: { Text( String( localized: "ServerDiscovery.NetworkError.Description", localized: "ServerDiscovery.NetworkError.Description", defaultValue: "Failed to scan Roon servers due to network error." )
-
@@ -272,18 +300,24 @@ ContentUnavailableView {Label { Text( String( localized: "ServerDiscovery.Error.Heading", localized: "ServerDiscovery.Error.Heading", defaultValue: "Scan failed" ) ) } icon: { Image(systemName: "exclamationmark.magnifyingglass") Image( systemName: "exclamationmark.magnifyingglass" ) } } description: { Text( String( localized: "ServerDiscovery.Error.Description", defaultValue: "An error occurred during a scan." localized: "ServerDiscovery.Error.Description", defaultValue: "An error occurred during a scan." ) ) }
-
-
-
@@ -70,7 +70,8 @@ Stepper(label: { Text( String( localized: "ZoneOptionsPanel.StepVolumeLabel", localized: "ZoneOptionsPanel.StepVolumeLabel", defaultValue: "Volume Control" ) )
-
@@ -88,9 +89,13 @@ )) ) _ = try TransportService.ChangeVolumeResponse(res) _ = try TransportService .ChangeVolumeResponse(res) } catch { logger.warning("Failed to increment volume: \(error)") logger.warning( "Failed to increment volume: \(error)" ) } } },
-
@@ -107,9 +112,13 @@ )) ) _ = try TransportService.ChangeVolumeResponse(res) _ = try TransportService .ChangeVolumeResponse(res) } catch { logger.warning("Failed to decrement volume: \(error)") logger.warning( "Failed to decrement volume: \(error)" ) } } }
-
@@ -167,9 +176,12 @@ )) ) _ = try TransportService.ChangeVolumeResponse(res) _ = try TransportService .ChangeVolumeResponse(res) } catch { logger.warning("Failed to change volume: \(error)") logger.warning( "Failed to change volume: \(error)") } } }
-
-
-
@@ -22,7 +22,7 @@ let package = Package(name: "RoonKit", platforms: [ .macOS(.v14), .iOS(.v16) .iOS(.v16), ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages.
-
-
-
@@ -162,7 +162,8 @@try await withTaskCancellationHandler { do { logger.debug("Querying server info") let res = try await request(Moo(info: .init()), timeout: .seconds(3)) let res = try await request( Moo(info: .init()), timeout: .seconds(3)) let info = try RegistryService.InfoResponse(res) if let serverID = serverID { guard info.coreId == serverID else {
-
@@ -226,15 +227,21 @@ }switch metadata.opcode { case .binary, .text: guard let msg = Moo.init(String(data: data, encoding: .utf8)!) guard let msg = Moo.init( String(data: data, encoding: .utf8)! ) else { logger.warning("Received invalid MOO message") logger.warning( "Received invalid MOO message") continue } if msg.service == PingService.Ping.service { Task { [weak self] in var res = Moo(verb: "COMPLETE", service: "Success") var res = Moo( verb: "COMPLETE", service: "Success") res.requestId = msg.requestId guard let self = self else {
-
@@ -246,11 +253,13 @@ }continue } for (_, continuation) in await messageContinuations { for (_, continuation) in await messageContinuations { continuation.yield(msg) } case .close: logger.info("Connection closed, releasing resources") logger.info( "Connection closed, releasing resources") return default: break
-
@@ -259,7 +268,8 @@ } catch {switch error { case NWError.posix(.ENODATA): if let self = self { logger.warning("Stream closed, disconnecting") logger.warning( "Stream closed, disconnecting") await self.disconnect() return }
-
-
-
@@ -178,7 +178,8 @@ state = .schemaVersion(found: "")break } state = .signature(expecting: next, remaining: remaining.dropFirst()) state = .signature( expecting: next, remaining: remaining.dropFirst()) break case .schemaVersion(let found): if char.isWhitespace && !char.isNewline {
-
@@ -233,7 +234,9 @@ if found == "" {throw .malformedHeaderLine } state = .headers(parsing: .beforeValue(key: found), parsed: parsed) state = .headers( parsing: .beforeValue(key: found), parsed: parsed) break }
-
@@ -264,12 +267,14 @@ case .value(let key, let found):if char.isNewline { var parsed = parsed _ = parsed.updateValue(found, forKey: key) state = .headers(parsing: .key(found: ""), parsed: parsed) state = .headers( parsing: .key(found: ""), parsed: parsed) break } state = .headers( parsing: .value(key: key, found: found + String(char)), parsing: .value( key: key, found: found + String(char)), parsed: parsed ) break
-
-
-
@@ -71,7 +71,8 @@ .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1).bind(host: "0.0.0.0", port: 0) { channel in channel.eventLoop.makeCompletedFuture { return try NIOAsyncChannel< AddressedEnvelope<ByteBuffer>, AddressedEnvelope<ByteBuffer> AddressedEnvelope<ByteBuffer>, AddressedEnvelope<ByteBuffer> >( wrappingChannelSynchronously: channel, )
-
-
-
@@ -117,7 +117,8 @@ state = .kindbreak } state = .signature(expecting: next, remaining: remaining.dropFirst()) state = .signature( expecting: next, remaining: remaining.dropFirst()) break case .kind: guard let char = String(bytes: [byte], encoding: .ascii) else {
-
@@ -144,7 +145,9 @@ let read = read + [byte]if remainingBytes > 1 { state = .properties( kind, parsing: .key(read: read, remainingBytes: remainingBytes - 1), parsing: .key( read: read, remainingBytes: remainingBytes - 1), parsed: parsed ) break
-
@@ -170,11 +173,13 @@ breakcase .valueSizeLo(let key, let hi): let hi = UInt16(hi) let lo = UInt16(byte) let size = UInt16(bigEndian: (hi.bigEndian << 8) | lo.bigEndian) let size = UInt16( bigEndian: (hi.bigEndian << 8) | lo.bigEndian) state = .properties( kind, parsing: .value(key: key, read: [], remainingBytes: size), parsing: .value( key: key, read: [], remainingBytes: size), parsed: parsed ) break
-
@@ -193,7 +198,8 @@ )break } guard let value = String(bytes: read, encoding: .utf8) else { guard let value = String(bytes: read, encoding: .utf8) else { throw .invalidPropertyValue }
-