// Copyright 2024 The NATS Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import Foundation extension Data { private static let cr = UInt8(ascii: "\r") private static let lf = UInt8(ascii: "\n") private static let crlf = Data([cr, lf]) private static var currentNum = 0 private static var errored = false internal static let versionLinePrefix = "NATS/1.0" func removePrefix(_ prefix: Data) -> Data { guard self.starts(with: prefix) else { return self } return self.dropFirst(prefix.count) } func split( separator: Data, maxSplits: Int = .max, omittingEmptySubsequences: Bool = true ) -> [Data] { var chunks: [Data] = [] var start = startIndex var end = startIndex var splitsCount = 0 while end < count { if splitsCount >= maxSplits { break } if self[start.. NatsOperation? { guard self.count > 2 else { return nil } for operation in NatsOperation.allOperations() { if self.starts(with: operation.rawBytes) { return operation } } return nil } func starts(with bytes: [UInt8]) -> Bool { guard self.count >= bytes.count else { return false } return self.prefix(bytes.count).elementsEqual(bytes) } internal mutating func prepend(_ other: Data) { self = other + self } internal func parseOutMessages() throws -> (ops: [ServerOp], remainder: Data?) { var serverOps = [ServerOp]() var startIndex = self.startIndex var remainder: Data? while startIndex < self.endIndex { var nextLineStartIndex: Int var lineData: Data if let range = self[startIndex...].range(of: Data.crlf) { let lineEndIndex = range.lowerBound nextLineStartIndex = self.index(range.upperBound, offsetBy: 0, limitedBy: self.endIndex) ?? self.endIndex lineData = self[startIndex.. endIndex { remainder = self[startIndex.. msg.headersLength { payload = Data() } var headers = NatsHeaderMap() // if the whole msg length (including training crlf) is longer // than the remaining chunk, break and return the remainder if payloadEndIndex + Data.crlf.count > endIndex { remainder = self[startIndex..