no message

This commit is contained in:
Peter
2015-07-16 02:20:03 +03:00
parent 6fdee4c6b3
commit 13f3951ddd
6 changed files with 499 additions and 22 deletions

View File

@@ -28,6 +28,7 @@
D0D224F21B4D6ABD0085E26D /* Functions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D224ED1B4D6ABD0085E26D /* Functions.swift */; };
D0D224F31B4D6ABD0085E26D /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D224EE1B4D6ABD0085E26D /* Query.swift */; };
D0D224F41B4D6ABD0085E26D /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D224EF1B4D6ABD0085E26D /* Schema.swift */; };
D0D225261B4D84930085E26D /* PeerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D225251B4D84930085E26D /* PeerView.swift */; };
D0E3A7501B28A7E300A402D9 /* Postbox.h in Headers */ = {isa = PBXBuildFile; fileRef = D0E3A74F1B28A7E300A402D9 /* Postbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
D0E3A7561B28A7E300A402D9 /* Postbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0E3A74A1B28A7E300A402D9 /* Postbox.framework */; };
D0E3A75D1B28A7E300A402D9 /* PostboxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A75C1B28A7E300A402D9 /* PostboxTests.swift */; };
@@ -71,6 +72,7 @@
D0D224ED1B4D6ABD0085E26D /* Functions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Functions.swift; path = submodules/sqlite.swift/SQLite/Functions.swift; sourceTree = SOURCE_ROOT; };
D0D224EE1B4D6ABD0085E26D /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Query.swift; path = submodules/sqlite.swift/SQLite/Query.swift; sourceTree = SOURCE_ROOT; };
D0D224EF1B4D6ABD0085E26D /* Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = submodules/sqlite.swift/SQLite/Schema.swift; sourceTree = SOURCE_ROOT; };
D0D225251B4D84930085E26D /* PeerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerView.swift; sourceTree = "<group>"; };
D0E3A74A1B28A7E300A402D9 /* Postbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Postbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D0E3A74E1B28A7E300A402D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D0E3A74F1B28A7E300A402D9 /* Postbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Postbox.h; sourceTree = "<group>"; };
@@ -180,6 +182,7 @@
D0E3A79D1B28B50400A402D9 /* Message.swift */,
D0E3A7A11B28B7DC00A402D9 /* Media.swift */,
D003E4E51B38DBDB00C22CBC /* MessageView.swift */,
D0D225251B4D84930085E26D /* PeerView.swift */,
D0E3A7811B28ADD000A402D9 /* Postbox.swift */,
D0E3A74D1B28A7E300A402D9 /* Supporting Files */,
);
@@ -342,6 +345,7 @@
D07516791B2EC90400AE42E0 /* SQLite-Bridging.m in Sources */,
D0D224F21B4D6ABD0085E26D /* Functions.swift in Sources */,
D07516711B2EC7FE00AE42E0 /* Statement.swift in Sources */,
D0D225261B4D84930085E26D /* PeerView.swift in Sources */,
D0E3A7841B28AE0900A402D9 /* Peer.swift in Sources */,
D075166A1B2EC7FE00AE42E0 /* Database.swift in Sources */,
D0D224F41B4D6ABD0085E26D /* Schema.swift in Sources */,

View File

@@ -175,7 +175,6 @@ public final class MutableMessageView: Printable {
}
self.later.removeAll(keepCapacity: true)
if anchorIndex + 1 < addedMessages.count {
for namespace in self.namespaces {
var i = anchorIndex + 1

View File

@@ -1,11 +1,11 @@
import Foundation
public struct PeerId: Hashable, Printable {
public struct PeerId: Hashable, Printable, Comparable {
public typealias Namespace = Int32
public typealias Id = Int32
let namespace: Namespace
let id: Id
public let namespace: Namespace
public let id: Id
public init(namespace: Namespace, id: Id) {
self.namespace = namespace
@@ -53,6 +53,18 @@ public func ==(lhs: PeerId, rhs: PeerId) -> Bool {
return lhs.id == rhs.id && lhs.namespace == rhs.namespace
}
public func <(lhs: PeerId, rhs: PeerId) -> Bool {
if lhs.namespace != rhs.namespace {
return lhs.namespace < rhs.namespace
}
if lhs.id != rhs.id {
return lhs.id < rhs.id
}
return false
}
public protocol Peer: Coding {
var id: PeerId { get }
}

278
Postbox/PeerView.swift Normal file
View File

@@ -0,0 +1,278 @@
import Foundation
public class PeerViewEntry {
public let peer: Peer
public let message: Message
public init(peer: Peer, message: Message) {
self.peer = peer
self.message = message
}
}
public struct PeerViewEntryIndex: Equatable, Comparable {
public let peerId: PeerId
public let messageIndex: MessageIndex
public init(_ entry: PeerViewEntry) {
self.peerId = entry.peer.id
self.messageIndex = MessageIndex(entry.message)
}
public init(peerId: PeerId, messageIndex: MessageIndex) {
self.peerId = peerId
self.messageIndex = messageIndex
}
public func earlier() -> PeerViewEntryIndex {
return PeerViewEntryIndex(peerId: self.peerId, messageIndex: MessageIndex(id: MessageId(peerId: self.messageIndex.id.peerId, namespace: self.messageIndex.id.namespace, id: self.messageIndex.id.id - 1), timestamp: self.messageIndex.timestamp))
}
public func later() -> PeerViewEntryIndex {
return PeerViewEntryIndex(peerId: self.peerId, messageIndex: MessageIndex(id: MessageId(peerId: self.messageIndex.id.peerId, namespace: self.messageIndex.id.namespace, id: self.messageIndex.id.id + 1), timestamp: self.messageIndex.timestamp))
}
}
public func ==(lhs: PeerViewEntryIndex, rhs: PeerViewEntryIndex) -> Bool {
return lhs.peerId == rhs.peerId && lhs.messageIndex == rhs.messageIndex
}
public func <(lhs: PeerViewEntryIndex, rhs: PeerViewEntryIndex) -> Bool {
if lhs.messageIndex != rhs.messageIndex {
return lhs.messageIndex < rhs.messageIndex
}
return lhs.peerId < rhs.peerId
}
public final class MutablePeerView: Printable {
public struct RemoveContext {
var invalidEarlier = false
var invalidLater = false
var removedEntries = false
}
let tags: [Int32]
let count: Int
var earlier: PeerViewEntry?
var later: PeerViewEntry?
var entries: [PeerViewEntry]
public init(tags: [Int32], count: Int, earlier: PeerViewEntry?, entries: [PeerViewEntry], later: PeerViewEntry?) {
self.tags = tags
self.count = count
self.earlier = earlier
self.entries = entries
self.later = later
}
public func removeEntry(context: RemoveContext?, peerId: PeerId) -> RemoveContext {
var invalidationContext = context ?? RemoveContext()
if let earlier = self.earlier {
if peerId == earlier.peer.id {
invalidationContext.invalidEarlier = true
}
}
if let later = self.later {
if peerId == later.peer.id {
invalidationContext.invalidLater = true
}
}
var i = 0
while i < self.entries.count {
if self.entries[i].peer.id == peerId {
self.entries.removeAtIndex(i)
invalidationContext.removedEntries = true
break
}
i++
}
return invalidationContext
}
public func addEntry(entry: PeerViewEntry) {
if self.entries.count == 0 {
self.entries.append(entry)
} else {
var first = PeerViewEntryIndex(self.entries[self.entries.count - 1])
var last = PeerViewEntryIndex(self.entries[0])
let index = PeerViewEntryIndex(entry)
var next: PeerViewEntryIndex?
if let later = self.later {
next = PeerViewEntryIndex(later)
}
if index < last {
let earlierEntry = self.earlier
if earlierEntry == nil || PeerViewEntryIndex(earlierEntry!) < index {
if self.entries.count < self.count {
self.entries.insert(entry, atIndex: 0)
} else {
self.earlier = entry
}
}
} else if index > first {
if next != nil && index > next! {
let laterEntry = self.later
if laterEntry == nil || PeerViewEntryIndex(laterEntry!) > index {
if self.entries.count < self.count {
self.entries.append(entry)
} else {
self.later = entry
}
}
} else {
self.entries.append(entry)
if self.entries.count > self.count {
let earliest = self.entries[0]
self.earlier = earliest
self.entries.removeAtIndex(0)
}
}
} else if index != last && index != first {
var i = self.entries.count
while i >= 1 {
if PeerViewEntryIndex(self.entries[i - 1]) < index {
break
}
i--
}
self.entries.insert(entry, atIndex: i)
if self.entries.count > self.count {
let earliest = self.entries[0]
self.earlier = earliest
self.entries.removeAtIndex(0)
}
}
}
}
public func complete(context: RemoveContext, fetchEarlier: (PeerViewEntryIndex?, Int) -> [PeerViewEntry], fetchLater: (PeerViewEntryIndex?, Int) -> [PeerViewEntry]) {
if context.removedEntries && self.entries.count != self.count {
var addedEntries: [PeerViewEntry] = []
var latestAnchor: PeerViewEntryIndex?
if self.entries.count != 0 {
latestAnchor = PeerViewEntryIndex(self.entries[self.entries.count - 1])
} else if let later = self.later {
latestAnchor = PeerViewEntryIndex(later)
}
if let later = self.later {
addedEntries += fetchLater(PeerViewEntryIndex(later).earlier(), self.count)
}
if let earlier = self.earlier {
addedEntries += fetchEarlier(PeerViewEntryIndex(earlier).later(), self.count)
}
addedEntries += self.entries
addedEntries.sort({ PeerViewEntryIndex($0) < PeerViewEntryIndex($1) })
var i = addedEntries.count - 1
while i >= 1 {
if PeerViewEntryIndex(addedEntries[i]) == PeerViewEntryIndex(addedEntries[i - 1]) {
addedEntries.removeAtIndex(i)
}
i--
}
self.entries = []
var anchorIndex = addedEntries.count - 1
if let latestAnchor = latestAnchor {
var i = addedEntries.count - 1
while i >= 0 {
if PeerViewEntryIndex(addedEntries[i]) <= latestAnchor {
anchorIndex = i
break
}
i--
}
}
self.later = nil
if anchorIndex + 1 < addedEntries.count {
var i = anchorIndex + 1
while i < addedEntries.count {
self.later = addedEntries[i]
break
}
}
i = anchorIndex
while i >= 0 && i > anchorIndex - self.count {
self.entries.insert(addedEntries[i], atIndex: 0)
i--
}
self.earlier = nil
if anchorIndex - self.count >= 0 {
i = anchorIndex - self.count
while i >= 0 {
self.earlier = addedEntries[i]
break
}
}
} else {
var earlyIndex: PeerViewEntryIndex?
if self.entries.count != 0 {
earlyIndex = PeerViewEntryIndex(self.entries[0])
}
let earlierEntries = fetchEarlier(earlyIndex, 1)
if earlierEntries.count == 0 {
self.earlier = nil
} else {
self.earlier = earlierEntries[0]
}
var lateIndex: PeerViewEntryIndex?
if self.entries.count != 0 {
lateIndex = PeerViewEntryIndex(self.entries[self.entries.count - 1])
}
let laterEntries = fetchLater(lateIndex, 1)
if laterEntries.count == 0 {
self.later = nil
} else {
self.later = laterEntries[0]
}
}
}
public var description: String {
var string = ""
if let earlier = self.earlier {
string += "more("
string += "(p \(earlier.peer.id.namespace):\(earlier.peer.id.id), m \(earlier.message.id.namespace):\(earlier.message.id.id)\(earlier.message.timestamp)"
string += ") "
}
string += "["
var first = true
for entry in self.entries {
if first {
first = false
} else {
string += ", "
}
string += "(p \(entry.peer.id.namespace):\(entry.peer.id.id), m \(entry.message.id.namespace):\(entry.message.id.id)\(entry.message.timestamp))"
}
string += "]"
if let later = self.later {
string += " more("
string += "(p \(later.peer.id.namespace):\(later.peer.id.id), m \(later.message.id.namespace):\(later.message.id.id)\(later.message.timestamp)"
string += ")"
}
return string
}
}

View File

@@ -3,6 +3,8 @@ import Foundation
import SwiftSignalKit
public final class Postbox {
static let PeerTagGeneral = 0
public class Modifier {
private unowned var postbox: Postbox
@@ -20,7 +22,6 @@ public final class Postbox {
}
private let basePath: String
private let ownerId: PeerId
private let messageNamespaces: [MessageId.Namespace]
private let queue = SwiftSignalKit.Queue()
@@ -28,9 +29,8 @@ public final class Postbox {
private var peerMessageViews: [PeerId : Bag<(MutableMessageView, Pipe<MessageView>)>] = [:]
public init(basePath: String, ownerId: PeerId, messageNamespaces: [MessageId.Namespace]) {
public init(basePath: String, messageNamespaces: [MessageId.Namespace]) {
self.basePath = basePath
self.ownerId = ownerId
self.messageNamespaces = messageNamespaces
self.openDatabase()
}
@@ -51,17 +51,12 @@ public final class Postbox {
}
private func createSchema() {
self.database.transaction()
//state
self.database.execute("CREATE TABLE state (key INTEGER PRIMARY KEY, data BLOB)")
//peer_messages
self.database.execute("CREATE TABLE peer_messages (peerId INTEGER, namespace INTEGER, id INTEGER, data BLOB, associatedMediaIds BLOB, timestamp INTEGER, PRIMARY KEY(peerId, namespace, id))")
//peer_maxread
self.database.execute("CREATE TABLE peer_maxread (peerId INTEGER, namespace INTEGER, id INTEGER)")
//peer_media
self.database.execute("CREATE TABLE peer_media (peerId INTEGER, mediaNamespace INTEGER, messageNamespace INTEGER, messageId INTEGER, PRIMARY KEY (peerId, mediaNamespace, messageNamespace, messageId))")
self.database.execute("CREATE INDEX peer_media_peerId_messageNamespace_messageId ON peer_media (peerId, messageNamespace, messageId)")
@@ -72,21 +67,97 @@ public final class Postbox {
//media_cleanup
self.database.execute("CREATE TABLE media_cleanup (namespace INTEGER, id INTEGER, data BLOB, PRIMARY KEY(namespace, id))")
//messages_readstate
self.database.execute("CREATE TABLE messages_readstate (peerId INTEGER, namespace INTEGER, maxUnreadIncomingId INTEGER, maxUnreadOutgoingId INTEGER, incomingUnreadCount INTEGER, PRIMARY KEY (peerId, namespace))")
//top_messages
self.database.execute("CREATE TABLE top_messages (peerId INTEGER PRIMARY KEY, timestamp INTEGER)")
//peer_entries
self.database.execute("CREATE TABLE peer_entries (entry BLOB)")
self.database.execute("CREATE INDEX peer_entries_entry on peer_entries (entry)")
//peers
self.database.execute("CREATE TABLE peers (peerId INTEGER PRIMARY KEY, data BLOB)")
}
public func _testBlobsPrepare(range: Int) {
self.database.execute("CREATE TABLE test_blobs (number INTEGER, data BLOB)")
self.database.execute("CREATE INDEX test_blobs_index_data ON test_blobs (data)")
//user_statuses
self.database.execute("CREATE TABLE user_statuses (id INTEGER PRIMARY KEY, data BLOB)")
self.database.transaction()
let insert = self.database.prepare("INSERT INTO test_blobs (number, data) VALUES (?, ?)")
for i in 0 ..< range {
var value = Int32(bigEndian: Int32(i))
let blob = Blob(bytes: &value, length: 4)
insert.run(Int64(i), blob)
}
self.database.commit()
}
public func _testBlobsTest(range: Int) {
let select = self.database.prepare("SELECT number FROM test_blobs WHERE data < ? ORDER BY data DESC LIMIT 1")
for i in 1 ..< 1000 {
var value = 1 + Int32(arc4random_uniform(UInt32(range - 1)))
var binary = Int32(bigEndian: value)
var found = false
for row in select.run(Blob(bytes: &binary, length: 4)) {
found = true
let selected = Int32(row[0] as! Int64)
if selected != value - 1 {
assertionFailure("invalid value \(selected) != \(value - 1)")
}
break
}
if !found {
assertionFailure("value not found for \(value - 1)")
}
}
}
private class func peerViewEntryIndexForBlob(blob: Blob) -> PeerViewEntryIndex {
let buffer = ReadBuffer(memory: UnsafeMutablePointer(blob.data.bytes), length: blob.data.length, freeWhenDone: false)
var offset: Int = 0
var timestamp: Int32 = 0
buffer.read(&timestamp, offset: offset, length: 4)
timestamp = Int32(bigEndian: timestamp)
offset += 4
var namespace: Int32 = 0
buffer.read(&namespace, offset: offset, length: 4)
namespace = Int32(bigEndian: namespace)
offset += 4
var id: Int32 = 0
buffer.read(&id, offset: offset, length: 4)
id = Int32(bigEndian: id)
offset += 4
var peerIdRepresentation: Int64 = 0
buffer.read(&peerIdRepresentation, offset: offset, length: 8)
peerIdRepresentation = Int64(bigEndian: peerIdRepresentation)
offset += 8
let peerId = PeerId(peerIdRepresentation)
return PeerViewEntryIndex(peerId: peerId, messageIndex: MessageIndex(id: MessageId(peerId:peerId, namespace: namespace, id: id), timestamp: timestamp))
}
private class func blobForPeerViewEntryIndex(index: PeerViewEntryIndex) -> Blob {
let buffer = WriteBuffer()
var timestamp = Int32(bigEndian: index.messageIndex.timestamp)
buffer.write(&timestamp, offset: 0, length: 4)
var namespace = Int32(bigEndian: index.messageIndex.id.namespace)
buffer.write(&namespace, offset: 0, length: 4)
var id = Int32(bigEndian: index.messageIndex.id.id)
buffer.write(&id, offset: 0, length: 4)
var peerIdRepresentation = Int64(bigEndian: index.peerId.toInt64())
buffer.write(&peerIdRepresentation, offset: 0, length: 8)
return Blob(data: buffer.makeData())
}
private class func messageIdsGroupedByNamespace(ids: [MessageId]) -> [MessageId.Namespace : [MessageId]] {
var grouped: [MessageId.Namespace : [MessageId]] = [:]

View File

@@ -16,6 +16,22 @@ enum TestMediaNamespace: MediaId.Namespace {
case Test = 0
}
class TestPeer: Peer {
var id: PeerId
init(id: PeerId) {
self.id = id
}
required init(decoder: Decoder) {
self.id = PeerId(decoder.decodeInt64ForKey("id"))
}
func encode(encoder: Encoder) {
encoder.encodeInt64(self.id.toInt64(), forKey: "id")
}
}
class TestMessage: Message {
var id: MessageId
var authorId: PeerId
@@ -97,7 +113,7 @@ class PostboxTests: XCTestCase {
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespace])
let postbox = Postbox(basePath: basePath, messageNamespaces: [messageNamespace])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
for i in 0 ..< 10 {
@@ -586,7 +602,7 @@ class PostboxTests: XCTestCase {
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespace])
let postbox = Postbox(basePath: basePath, messageNamespaces: [messageNamespace])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
@@ -626,7 +642,7 @@ class PostboxTests: XCTestCase {
let basePath = "/tmp/postboxtest"
NSFileManager.defaultManager().removeItemAtPath(basePath, error: nil)
let postbox = Postbox(basePath: basePath, ownerId: ownerId, messageNamespaces: [messageNamespaceCloud, messageNamespaceLocal])
let postbox = Postbox(basePath: basePath, messageNamespaces: [messageNamespaceCloud, messageNamespaceLocal])
postbox.modify { state in
let testMedia = TestMedia(id: MediaId(namespace: TestMediaNamespace.Test.rawValue, id: 1))
@@ -660,4 +676,101 @@ class PostboxTests: XCTestCase {
postbox._sync()
}
func testPeerView() {
let view = MutablePeerView(tags: [], count: 3, earlier: nil, entries: [], later: nil)
let messageNamespaceCloud = TestMessageNamespace.Cloud.rawValue
let otherId = PeerId(namespace: TestPeerNamespace.User.rawValue, id: 2000)
var entries: [PeerViewEntry] = []
func print(entries: [PeerViewEntry]) {
var string = ""
string += "["
var first = true
for entry in entries {
if first {
first = false
} else {
string += ", "
}
string += "(p \(entry.peer.id.namespace):\(entry.peer.id.id), m \(entry.message.id.namespace):\(entry.message.id.id)\(entry.message.timestamp))"
}
string += "]"
println("\(string)")
}
func add(entry: PeerViewEntry) {
entries.append(entry)
entries.sort({ PeerViewEntryIndex($0) < PeerViewEntryIndex($1) })
view.addEntry(entry)
println("\n\(view)")
print(entries)
}
func remove(peerId: PeerId, context: MutablePeerView.RemoveContext? = nil) -> MutablePeerView.RemoveContext {
entries = entries.filter({ $0.peer.id != peerId })
return view.removeEntry(context, peerId: peerId)
}
func fetchEarlier(entries: [PeerViewEntry])(index: PeerViewEntryIndex?, count: Int) -> [PeerViewEntry] {
var filtered: [PeerViewEntry] = []
var i = entries.count - 1
while i >= 0 && filtered.count < count {
if index == nil || PeerViewEntryIndex(entries[i]) < index! {
filtered.append(entries[i])
}
i--
}
return filtered
}
func fetchLater(entries: [PeerViewEntry])(index: PeerViewEntryIndex?, count: Int) -> [PeerViewEntry] {
var filtered: [PeerViewEntry] = []
var i = 0
while i < entries.count && filtered.count < count {
if index == nil || PeerViewEntryIndex(entries[i]) > index! {
filtered.append(entries[i])
}
i++
}
return filtered
}
func complete(context: MutablePeerView.RemoveContext) {
view.complete(context, fetchEarlier: fetchEarlier(entries), fetchLater: fetchLater(entries))
}
println("\(view)")
for i in 1 ..< 10 {
let messageId = MessageId(peerId: otherId, namespace: messageNamespaceCloud, id: Int32(i * 2 * 100))
let message = TestMessage(id: messageId, authorId: otherId, date: Int32(i * 2 * 100), text: "\(i)", referencedMediaIds: [])
add(PeerViewEntry(peer: TestPeer(id: PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(i * 2))), message: message))
}
if true {
let i = 15
let messageId = MessageId(peerId: otherId, namespace: messageNamespaceCloud, id: Int32(i * 100))
let message = TestMessage(id: messageId, authorId: otherId, date: Int32(i * 100), text: "\(i)", referencedMediaIds: [])
add(PeerViewEntry(peer: TestPeer(id: PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(i))), message: message))
}
if true {
var context = remove(PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(15)))
context = remove(PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(14)), context: context)
context = remove(PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(16)), context: context)
context = remove(PeerId(namespace: TestPeerNamespace.User.rawValue, id: Int32(18)), context: context)
println("\n\(view)")
print(entries)
complete(context)
println("\(view)")
}
}
}