Loading Kinetic.xcodeproj/project.pbxproj +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 3E07EA7F1B78E3B500DAB3F1 /* Kinetic.proto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */; }; 3EA070371B846C3800E4821E /* KeyRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA070361B846C3800E4821E /* KeyRange.swift */; }; 3ED681EB1B7CEA0600AFDF79 /* Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */; }; 3EDAAB411B66D32D00F30808 /* Kinetic.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EDAAB401B66D32D00F30808 /* Kinetic.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3EDAAB481B66D32D00F30808 /* Kinetic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */; }; Loading Loading @@ -40,6 +41,7 @@ 382D1C00FC0EC4F1BF676411 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Kinetic.proto.swift; sourceTree = "<group>"; }; 3E386E6A1B7F85720040D363 /* Example 2 - Basics.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 2 - Basics.playground"; sourceTree = "<group>"; }; 3EA070361B846C3800E4821E /* KeyRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyRange.swift; sourceTree = "<group>"; }; 3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encoding.swift; sourceTree = "<group>"; }; 3ED681EE1B7D0EC600AFDF79 /* Example 3 - Async.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 3 - Async.playground"; sourceTree = "<group>"; }; 3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kinetic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; Loading Loading @@ -158,6 +160,7 @@ 3EFB7F1D1B7A6A9800988886 /* Put.swift */, 3EFB7F261B7AA45A00988886 /* Get.swift */, 3EFB7F281B7AB06800988886 /* Delete.swift */, 3EA070361B846C3800E4821E /* KeyRange.swift */, ); path = Commands; sourceTree = "<group>"; Loading Loading @@ -327,6 +330,7 @@ 3EFB7F221B7A7A8000988886 /* Utils.swift in Sources */, 3EFB7F251B7A977500988886 /* Common.swift in Sources */, 3EFB7F2F1B7BB4E700988886 /* Authentication.swift in Sources */, 3EA070371B846C3800E4821E /* KeyRange.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; Loading Kinetic/Commands/Common.swift +4 −2 Original line number Diff line number Diff line Loading @@ -21,23 +21,25 @@ // @author: Ignacio Corderi public struct NoResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public static func parse(raw: RawResponse) -> NoResponse { public static func parse(raw: RawResponse, context: Void) -> NoResponse { return NoResponse(success: raw.command.status.code == .Success, error: KineticRemoteError.fromStatus(raw.command.status)) } } public struct ValueResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public let value: Bytes? public let exists: Bool public var hasValue: Bool { return value != nil && value!.count > 0 } public static func parse(raw: RawResponse) -> ValueResponse { public static func parse(raw: RawResponse, context: Void) -> ValueResponse { switch raw.command.status.code { case .Success: return ValueResponse(success: true, error: nil, value: raw.value, exists: true) Loading Kinetic/Commands/Delete.swift +5 −4 Original line number Diff line number Diff line Loading @@ -31,23 +31,24 @@ public class DeleteCommand : ChannelCommand { } public convenience init(key: String) { self.init(key: key.toNSData()) self.init(key: key.toData()) } public func build(builder: Builder) -> Builder { public func build(builder: Builder, device: KineticDevice) { builder.header.messageType = .Delete builder.keyValue.key = self.key return builder } } public struct EmptyResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public let exists: Bool public static func parse(raw: RawResponse) -> EmptyResponse { public static func parse(raw: RawResponse, context: Void) -> EmptyResponse { switch raw.command.status.code { case .Success: return EmptyResponse(success: true, error: nil, exists: true) Loading Kinetic/Commands/Get.swift +5 −10 Original line number Diff line number Diff line Loading @@ -24,20 +24,15 @@ public class GetCommand : ChannelCommand { public typealias ResponseType = ValueResponse public let key: NSData public let key: KeyType public init(key: NSData) { public init(key: KeyType) { self.key = key } public convenience init(key: String) { self.init(key: key.toNSData()) } public func build(builder: Builder) -> Builder { public func build(builder: Builder, device: KineticDevice) { builder.header.messageType = .Get builder.keyValue.key = self.key return builder builder.keyValue.key = self.key.toData() } } Loading @@ -45,7 +40,7 @@ public class GetCommand : ChannelCommand { extension GetCommand: CustomStringConvertible { public var description: String { get { return "Get (key: \(self.key.toUtf8()))" return "Get (key: \(self.key))" } } } Loading Kinetic/Commands/KeyRange.swift 0 → 100644 +169 −0 Original line number Diff line number Diff line // Copyright (c) 2015 Seagate Technology // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // @author: Ignacio Corderi public enum Range<K : KeyType> : CustomStringConvertible{ case FromTo(K, K, Bool, Bool) case From(K, Bool) case To(K, Bool) case Prefix(K) internal func build(builder: Builder, device: KineticDevice) { switch self { case FromTo(let from, let to, let fromInclusive, let toInclusive): builder.range.startKey = from.toData() builder.range.startKeyInclusive = fromInclusive builder.range.endKey = to.toData() builder.range.endKeyInclusive = toInclusive case From(let key, let inclusive): builder.range.startKey = key.toData() builder.range.startKeyInclusive = inclusive let bs = Bytes(count: Int(device.limits.maxKeySize), repeatedValue: UInt8(0xFF)) builder.range.endKey = NSData(bytes: bs, length: bs.count) builder.range.endKeyInclusive = true case To(let key, let inclusive): builder.range.startKey = NSData(bytes: [], length: 0) builder.range.startKeyInclusive = true builder.range.endKey = key.toData() builder.range.endKeyInclusive = inclusive case Prefix(let prefix): let p = prefix.toData() builder.range.startKey = p builder.range.startKeyInclusive = true if p.length > 0 { var bs = p.arrayOfBytes() bs[bs.count-1] += 1 builder.range.endKey = NSData(bytes: bs, length: p.length) builder.range.endKeyInclusive = false } } } public var description: String { switch self { case FromTo(let from, let to, true, true): return "Range ['\(from)'..'\(to)']" case FromTo(let from, let to, true, false): return "Range ['\(from)'..'\(to)')" case FromTo(let from, let to, false, true): return "Range ('\(from)'..'\(to)']" case FromTo(let from, let to, false, false): return "Range ('\(from)'..'\(to)')" case From(let key, true): return "Range ['\(key)'..)" case From(let key, false): return "Range ('\(key)'..)" case To(let key, true): return "Range [..'\(key)']" case To(let key, false): return "Range [..'\(key)')" case Prefix(let prefix): return "Prefix '\(prefix)'" } } } public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { public typealias ResponseType = KeyRangeResponse public let range: Range<K> public let reverse: Bool public let maxReturned: Int? public init(_ range: Range<K>, reverse: Bool=false, maxReturned: Int?=nil) { self.range = range self.reverse = reverse self.maxReturned = maxReturned } public func build(builder: Builder, device: KineticDevice) -> Int { builder.header.messageType = .Getkeyrange self.range.build(builder, device: device) builder.range.reverse = self.reverse var max: Int32 = 0 if (self.maxReturned != nil) { // TODO: verify that it's <= than the limit max = Int32(self.maxReturned!) } else { max = Int32(device.limits.maxKeyRangeCount) } builder.range.maxReturned = max return Int(max) } } public struct KeyRangeResponse: ChannelResponse { public typealias ContextType = Int public let success: Bool public let error: KineticRemoteError? public let keys: [NSData] public let hasMore: Bool public static func parse(raw: RawResponse, context: Int) -> KeyRangeResponse { switch raw.command.status.code { case .Success: var keys: [NSData] = [] /* It might be possible that some implementation of the device is not returning anyhting at all when the resulting range is empty. It might be considered an implementation flaw. */ if raw.command.hasBody && raw.command.body.hasRange { keys = raw.command.body.range.keys } return KeyRangeResponse(success: true, error: nil, keys: keys, hasMore: keys.count == context) default: return KeyRangeResponse(success: false, error: KineticRemoteError.fromStatus(raw.command.status), keys: [], hasMore: false) } } } extension KeyRangeResponse: CustomStringConvertible { public var description: String { if self.success { return "Success (length: \(self.keys.count))" } else if self.error!.message.isEmpty { return "\(self.error!.code)" } else { return "\(self.error!.code): \(self.error!.message)" } } } extension GetKeyRangeCommand: CustomStringConvertible { public var description: String { return "GetKeyRange \(self.range)" } } public extension KineticSession { func getKeyRange<K>(range: Range<K>, reverse: Bool = false) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: nil) return try cmd.sendTo(self) } func getKeyRange<K>(range: Range<K>, reverse: Bool, maxReturned: Int) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: maxReturned) return try cmd.sendTo(self) } } No newline at end of file Loading
Kinetic.xcodeproj/project.pbxproj +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 3E07EA7F1B78E3B500DAB3F1 /* Kinetic.proto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */; }; 3EA070371B846C3800E4821E /* KeyRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA070361B846C3800E4821E /* KeyRange.swift */; }; 3ED681EB1B7CEA0600AFDF79 /* Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */; }; 3EDAAB411B66D32D00F30808 /* Kinetic.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EDAAB401B66D32D00F30808 /* Kinetic.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3EDAAB481B66D32D00F30808 /* Kinetic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */; }; Loading Loading @@ -40,6 +41,7 @@ 382D1C00FC0EC4F1BF676411 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E07EA7E1B78E3B500DAB3F1 /* Kinetic.proto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Kinetic.proto.swift; sourceTree = "<group>"; }; 3E386E6A1B7F85720040D363 /* Example 2 - Basics.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 2 - Basics.playground"; sourceTree = "<group>"; }; 3EA070361B846C3800E4821E /* KeyRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyRange.swift; sourceTree = "<group>"; }; 3ED681EA1B7CEA0600AFDF79 /* Encoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Encoding.swift; sourceTree = "<group>"; }; 3ED681EE1B7D0EC600AFDF79 /* Example 3 - Async.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Example 3 - Async.playground"; sourceTree = "<group>"; }; 3EDAAB3D1B66D32D00F30808 /* Kinetic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kinetic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; Loading Loading @@ -158,6 +160,7 @@ 3EFB7F1D1B7A6A9800988886 /* Put.swift */, 3EFB7F261B7AA45A00988886 /* Get.swift */, 3EFB7F281B7AB06800988886 /* Delete.swift */, 3EA070361B846C3800E4821E /* KeyRange.swift */, ); path = Commands; sourceTree = "<group>"; Loading Loading @@ -327,6 +330,7 @@ 3EFB7F221B7A7A8000988886 /* Utils.swift in Sources */, 3EFB7F251B7A977500988886 /* Common.swift in Sources */, 3EFB7F2F1B7BB4E700988886 /* Authentication.swift in Sources */, 3EA070371B846C3800E4821E /* KeyRange.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; Loading
Kinetic/Commands/Common.swift +4 −2 Original line number Diff line number Diff line Loading @@ -21,23 +21,25 @@ // @author: Ignacio Corderi public struct NoResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public static func parse(raw: RawResponse) -> NoResponse { public static func parse(raw: RawResponse, context: Void) -> NoResponse { return NoResponse(success: raw.command.status.code == .Success, error: KineticRemoteError.fromStatus(raw.command.status)) } } public struct ValueResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public let value: Bytes? public let exists: Bool public var hasValue: Bool { return value != nil && value!.count > 0 } public static func parse(raw: RawResponse) -> ValueResponse { public static func parse(raw: RawResponse, context: Void) -> ValueResponse { switch raw.command.status.code { case .Success: return ValueResponse(success: true, error: nil, value: raw.value, exists: true) Loading
Kinetic/Commands/Delete.swift +5 −4 Original line number Diff line number Diff line Loading @@ -31,23 +31,24 @@ public class DeleteCommand : ChannelCommand { } public convenience init(key: String) { self.init(key: key.toNSData()) self.init(key: key.toData()) } public func build(builder: Builder) -> Builder { public func build(builder: Builder, device: KineticDevice) { builder.header.messageType = .Delete builder.keyValue.key = self.key return builder } } public struct EmptyResponse : ChannelResponse { public typealias ContextType = Void public let success: Bool public let error: KineticRemoteError? public let exists: Bool public static func parse(raw: RawResponse) -> EmptyResponse { public static func parse(raw: RawResponse, context: Void) -> EmptyResponse { switch raw.command.status.code { case .Success: return EmptyResponse(success: true, error: nil, exists: true) Loading
Kinetic/Commands/Get.swift +5 −10 Original line number Diff line number Diff line Loading @@ -24,20 +24,15 @@ public class GetCommand : ChannelCommand { public typealias ResponseType = ValueResponse public let key: NSData public let key: KeyType public init(key: NSData) { public init(key: KeyType) { self.key = key } public convenience init(key: String) { self.init(key: key.toNSData()) } public func build(builder: Builder) -> Builder { public func build(builder: Builder, device: KineticDevice) { builder.header.messageType = .Get builder.keyValue.key = self.key return builder builder.keyValue.key = self.key.toData() } } Loading @@ -45,7 +40,7 @@ public class GetCommand : ChannelCommand { extension GetCommand: CustomStringConvertible { public var description: String { get { return "Get (key: \(self.key.toUtf8()))" return "Get (key: \(self.key))" } } } Loading
Kinetic/Commands/KeyRange.swift 0 → 100644 +169 −0 Original line number Diff line number Diff line // Copyright (c) 2015 Seagate Technology // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // @author: Ignacio Corderi public enum Range<K : KeyType> : CustomStringConvertible{ case FromTo(K, K, Bool, Bool) case From(K, Bool) case To(K, Bool) case Prefix(K) internal func build(builder: Builder, device: KineticDevice) { switch self { case FromTo(let from, let to, let fromInclusive, let toInclusive): builder.range.startKey = from.toData() builder.range.startKeyInclusive = fromInclusive builder.range.endKey = to.toData() builder.range.endKeyInclusive = toInclusive case From(let key, let inclusive): builder.range.startKey = key.toData() builder.range.startKeyInclusive = inclusive let bs = Bytes(count: Int(device.limits.maxKeySize), repeatedValue: UInt8(0xFF)) builder.range.endKey = NSData(bytes: bs, length: bs.count) builder.range.endKeyInclusive = true case To(let key, let inclusive): builder.range.startKey = NSData(bytes: [], length: 0) builder.range.startKeyInclusive = true builder.range.endKey = key.toData() builder.range.endKeyInclusive = inclusive case Prefix(let prefix): let p = prefix.toData() builder.range.startKey = p builder.range.startKeyInclusive = true if p.length > 0 { var bs = p.arrayOfBytes() bs[bs.count-1] += 1 builder.range.endKey = NSData(bytes: bs, length: p.length) builder.range.endKeyInclusive = false } } } public var description: String { switch self { case FromTo(let from, let to, true, true): return "Range ['\(from)'..'\(to)']" case FromTo(let from, let to, true, false): return "Range ['\(from)'..'\(to)')" case FromTo(let from, let to, false, true): return "Range ('\(from)'..'\(to)']" case FromTo(let from, let to, false, false): return "Range ('\(from)'..'\(to)')" case From(let key, true): return "Range ['\(key)'..)" case From(let key, false): return "Range ('\(key)'..)" case To(let key, true): return "Range [..'\(key)']" case To(let key, false): return "Range [..'\(key)')" case Prefix(let prefix): return "Prefix '\(prefix)'" } } } public class GetKeyRangeCommand<K : KeyType> : ChannelCommand { public typealias ResponseType = KeyRangeResponse public let range: Range<K> public let reverse: Bool public let maxReturned: Int? public init(_ range: Range<K>, reverse: Bool=false, maxReturned: Int?=nil) { self.range = range self.reverse = reverse self.maxReturned = maxReturned } public func build(builder: Builder, device: KineticDevice) -> Int { builder.header.messageType = .Getkeyrange self.range.build(builder, device: device) builder.range.reverse = self.reverse var max: Int32 = 0 if (self.maxReturned != nil) { // TODO: verify that it's <= than the limit max = Int32(self.maxReturned!) } else { max = Int32(device.limits.maxKeyRangeCount) } builder.range.maxReturned = max return Int(max) } } public struct KeyRangeResponse: ChannelResponse { public typealias ContextType = Int public let success: Bool public let error: KineticRemoteError? public let keys: [NSData] public let hasMore: Bool public static func parse(raw: RawResponse, context: Int) -> KeyRangeResponse { switch raw.command.status.code { case .Success: var keys: [NSData] = [] /* It might be possible that some implementation of the device is not returning anyhting at all when the resulting range is empty. It might be considered an implementation flaw. */ if raw.command.hasBody && raw.command.body.hasRange { keys = raw.command.body.range.keys } return KeyRangeResponse(success: true, error: nil, keys: keys, hasMore: keys.count == context) default: return KeyRangeResponse(success: false, error: KineticRemoteError.fromStatus(raw.command.status), keys: [], hasMore: false) } } } extension KeyRangeResponse: CustomStringConvertible { public var description: String { if self.success { return "Success (length: \(self.keys.count))" } else if self.error!.message.isEmpty { return "\(self.error!.code)" } else { return "\(self.error!.code): \(self.error!.message)" } } } extension GetKeyRangeCommand: CustomStringConvertible { public var description: String { return "GetKeyRange \(self.range)" } } public extension KineticSession { func getKeyRange<K>(range: Range<K>, reverse: Bool = false) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: nil) return try cmd.sendTo(self) } func getKeyRange<K>(range: Range<K>, reverse: Bool, maxReturned: Int) throws -> GetKeyRangeCommand<K>.ResponseType { let cmd = GetKeyRangeCommand(range, reverse: reverse, maxReturned: maxReturned) return try cmd.sendTo(self) } } No newline at end of file