- Update
This commit is contained in:
1 parent
d281d765ea
commit
5b074a5176
1261 files changed
+199158
-7303
No files matched your search
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
#import "XMPPCapabilities.h"
|
||||
#import "XMPPCoreDataStorage.h"
|
||||
|
||||
/**
|
||||
* This class is an example implementation of XMPPCapabilitiesStorage using core data.
|
||||
* You are free to substitute your own storage class.
|
||||
**/
|
||||
|
||||
@interface XMPPCapabilitiesCoreDataStorage : XMPPCoreDataStorage <XMPPCapabilitiesStorage>
|
||||
{
|
||||
/* Inherited protected variables from XMPPCoreDataStorage
|
||||
|
||||
NSString *databaseFileName;
|
||||
NSUInteger saveThreshold;
|
||||
|
||||
dispatch_queue_t storageQueue;
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* XEP-0115 provides a mechanism for hashing a list of capabilities.
|
||||
* Clients then broadcast this hash instead of the entire list to save bandwidth.
|
||||
* Because the hashing is standardized, it is safe to persistently store the linked hash & capabilities.
|
||||
*
|
||||
* For this reason, it is recommended you use this sharedInstance across all your xmppStreams.
|
||||
* This way all streams can shared a knowledgebase concerning known hashes.
|
||||
*
|
||||
* All other aspects of capabilities handling (such as JID's, lookup failures, etc) are kept separate between streams.
|
||||
**/
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
|
||||
/* Inherited from XMPPCoreDataStorage
|
||||
* Please see the XMPPCoreDataStorage header file for extensive documentation.
|
||||
|
||||
- (id)initWithDatabaseFilename:(NSString *)databaseFileName storeOptions:(NSDictionary *)storeOptions;
|
||||
- (id)initWithInMemoryStore;
|
||||
|
||||
@property (readonly) NSString *databaseFileName;
|
||||
|
||||
@property (readwrite) NSUInteger saveThreshold;
|
||||
|
||||
@property (readonly) NSManagedObjectModel *managedObjectModel;
|
||||
@property (readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
|
||||
|
||||
@property (readonly) NSManagedObjectContext *mainThreadManagedObjectContext;
|
||||
|
||||
*/
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,587 @@
|
||||
#import "XMPPCapabilitiesCoreDataStorage.h"
|
||||
#import "XMPPCapsCoreDataStorageObject.h"
|
||||
#import "XMPPCapsResourceCoreDataStorageObject.h"
|
||||
#import "XMPP.h"
|
||||
#import "XMPPCoreDataStorageProtected.h"
|
||||
#import "XMPPLogging.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
// Log levels: off, error, warn, info, verbose
|
||||
#if DEBUG
|
||||
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN; // | XMPP_LOG_FLAG_TRACE;
|
||||
#else
|
||||
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
|
||||
#endif
|
||||
|
||||
@implementation XMPPCapabilitiesCoreDataStorage
|
||||
|
||||
static XMPPCapabilitiesCoreDataStorage *sharedInstance;
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
||||
sharedInstance = [[XMPPCapabilitiesCoreDataStorage alloc] initWithDatabaseFilename:nil storeOptions:nil];
|
||||
});
|
||||
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (void)commonInit
|
||||
{
|
||||
XMPPLogTrace();
|
||||
[super commonInit];
|
||||
|
||||
autoRecreateDatabaseFile = YES;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Setup
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)configureWithParent:(XMPPCapabilities *)aParent queue:(dispatch_queue_t)queue
|
||||
{
|
||||
return [super configureWithParent:aParent queue:queue];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Utilities
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (XMPPCapsResourceCoreDataStorageObject *)resourceForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
NSAssert(dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace2(@"%@: %@ %@", THIS_FILE, THIS_METHOD, jid);
|
||||
|
||||
if (jid == nil) return nil;
|
||||
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPCapsResourceCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
|
||||
NSPredicate *predicate;
|
||||
if (stream == nil)
|
||||
predicate = [NSPredicate predicateWithFormat:@"jidStr == %@", [jid full]];
|
||||
else
|
||||
predicate = [NSPredicate predicateWithFormat:@"jidStr == %@ AND streamBareJidStr == %@",
|
||||
[jid full], [[self myJIDForXMPPStream:stream] bare]];
|
||||
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setPredicate:predicate];
|
||||
[fetchRequest setFetchLimit:1];
|
||||
|
||||
NSArray *results = [[self managedObjectContext] executeFetchRequest:fetchRequest error:nil];
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [results lastObject];
|
||||
|
||||
XMPPLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, resource);
|
||||
return resource;
|
||||
}
|
||||
|
||||
- (XMPPCapsCoreDataStorageObject *)capsForHash:(NSString *)hash algorithm:(NSString *)hashAlg
|
||||
{
|
||||
NSAssert(dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace2(@"%@: capsForHash:%@ algorithm:%@", THIS_FILE, hash, hashAlg);
|
||||
|
||||
if (hash == nil) return nil;
|
||||
if (hashAlg == nil) return nil;
|
||||
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPCapsCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"hashStr == %@ AND hashAlgorithm == %@",
|
||||
hash, hashAlg];
|
||||
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setPredicate:predicate];
|
||||
[fetchRequest setFetchLimit:1];
|
||||
|
||||
NSArray *results = [[self managedObjectContext] executeFetchRequest:fetchRequest error:nil];
|
||||
|
||||
XMPPCapsCoreDataStorageObject *caps = [results lastObject];
|
||||
|
||||
XMPPLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, caps);
|
||||
return caps;
|
||||
}
|
||||
|
||||
- (void)_clearAllNonPersistentCapabilitiesForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
NSAssert(dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPCapsResourceCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setFetchBatchSize:saveThreshold];
|
||||
|
||||
if (stream)
|
||||
{
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@",
|
||||
[[self myJIDForXMPPStream:stream] bare]];
|
||||
|
||||
[fetchRequest setPredicate:predicate];
|
||||
}
|
||||
|
||||
NSArray *results = [[self managedObjectContext] executeFetchRequest:fetchRequest error:nil];
|
||||
|
||||
NSUInteger unsavedCount = [self numberOfUnsavedChanges];
|
||||
|
||||
for (XMPPCapsResourceCoreDataStorageObject *resource in results)
|
||||
{
|
||||
NSString *hash = resource.hashStr;
|
||||
NSString *hashAlg = resource.hashAlgorithm;
|
||||
|
||||
BOOL nonPersistentCapabilities = ((hash == nil) || (hashAlg == nil));
|
||||
|
||||
if (nonPersistentCapabilities)
|
||||
{
|
||||
XMPPCapsCoreDataStorageObject *caps = resource.caps;
|
||||
if (caps)
|
||||
{
|
||||
[[self managedObjectContext] deleteObject:caps];
|
||||
}
|
||||
}
|
||||
|
||||
[[self managedObjectContext] deleteObject:resource];
|
||||
|
||||
if (++unsavedCount >= saveThreshold)
|
||||
{
|
||||
[self save];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Overrides
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)didCreateManagedObjectContext
|
||||
{
|
||||
// This method is overriden from the XMPPCoreDataStore superclass.
|
||||
|
||||
[self _clearAllNonPersistentCapabilitiesForXMPPStream:nil];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Protocol Public API
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)areCapabilitiesKnownForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
__block BOOL result;
|
||||
|
||||
[self executeBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
result = (resource.caps != nil);
|
||||
|
||||
}];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSXMLElement *)capabilitiesForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
return [self capabilitiesForJID:jid ext:nil xmppStream:stream];
|
||||
}
|
||||
|
||||
- (NSXMLElement *)capabilitiesForJID:(XMPPJID *)jid ext:(NSString **)extPtr xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
// By design this method should not be invoked from the storageQueue.
|
||||
NSAssert(!dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
__block NSXMLElement *result = nil;
|
||||
__block NSString *ext = nil;
|
||||
|
||||
[self executeBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
|
||||
if (resource)
|
||||
{
|
||||
result = [[resource caps] capabilities];
|
||||
ext = [resource ext];
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
if (extPtr)
|
||||
*extPtr = ext;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Protocol Private API
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)setCapabilitiesNode:(NSString *)node
|
||||
ver:(NSString *)ver
|
||||
ext:(NSString *)ext
|
||||
hash:(NSString *)hash
|
||||
algorithm:(NSString *)hashAlg
|
||||
forJID:(XMPPJID *)jid
|
||||
xmppStream:(XMPPStream *)stream
|
||||
andGetNewCapabilities:(NSXMLElement **)newCapabilitiesPtr
|
||||
{
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
__block BOOL result = NO;
|
||||
__block NSXMLElement *newCapabilities = nil;
|
||||
|
||||
[self executeBlock:^{
|
||||
|
||||
BOOL hashChange = NO;
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
if (resource)
|
||||
{
|
||||
resource.node = node;
|
||||
resource.ver = ver;
|
||||
resource.ext = ext;
|
||||
|
||||
if (![hash isEqual:[resource hashStr]])
|
||||
{
|
||||
hashChange = YES;
|
||||
resource.hashStr = hash;
|
||||
}
|
||||
|
||||
if (![hashAlg isEqual:[resource hashAlgorithm]])
|
||||
{
|
||||
hashChange = YES;
|
||||
resource.hashAlgorithm = hashAlg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resource = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPCapsResourceCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
|
||||
resource.jidStr = [jid full];
|
||||
resource.streamBareJidStr = [[self myJIDForXMPPStream:stream] bare];
|
||||
|
||||
resource.node = node;
|
||||
resource.ver = ver;
|
||||
resource.ext = ext;
|
||||
|
||||
resource.hashStr = hash;
|
||||
resource.hashAlgorithm = hashAlg;
|
||||
|
||||
hashChange = ((hash != nil) || (hashAlg != nil));
|
||||
}
|
||||
|
||||
if (hashChange)
|
||||
{
|
||||
resource.caps = [self capsForHash:hash algorithm:hashAlg];
|
||||
|
||||
newCapabilities = resource.caps.capabilities;
|
||||
}
|
||||
|
||||
// Return whether or not the capabilities are known for the given jid
|
||||
|
||||
result = (resource.caps != nil);
|
||||
|
||||
}];
|
||||
|
||||
|
||||
if (newCapabilitiesPtr)
|
||||
*newCapabilitiesPtr = newCapabilities;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL)getCapabilitiesHash:(NSString **)hashPtr
|
||||
algorithm:(NSString **)hashAlgPtr
|
||||
forJID:(XMPPJID *)jid
|
||||
xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
// By design this method should not be invoked from the storageQueue.
|
||||
NSAssert(!dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
__block BOOL result = NO;
|
||||
__block NSString *hash = nil;
|
||||
__block NSString *hashAlg = nil;
|
||||
|
||||
[self executeBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
if (resource)
|
||||
{
|
||||
hash = resource.hashStr;
|
||||
hashAlg = resource.hashAlgorithm;
|
||||
|
||||
result = (hash && hashAlg);
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = nil;
|
||||
hashAlg = nil;
|
||||
|
||||
result = NO;
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
|
||||
if (hashPtr)
|
||||
*hashPtr = hash;
|
||||
|
||||
if (hashAlgPtr)
|
||||
*hashAlgPtr = hashAlg;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)clearCapabilitiesHashAndAlgorithmForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
if (resource)
|
||||
{
|
||||
BOOL clearCaps = NO;
|
||||
|
||||
NSString *hash = resource.hashStr;
|
||||
NSString *hashAlg = resource.hashAlgorithm;
|
||||
|
||||
if (hash && hashAlg)
|
||||
{
|
||||
clearCaps = YES;
|
||||
}
|
||||
|
||||
resource.hashStr = nil;
|
||||
resource.hashAlgorithm = nil;
|
||||
|
||||
if (clearCaps)
|
||||
{
|
||||
resource.caps = nil;
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getCapabilitiesKnown:(BOOL *)areCapabilitiesKnownPtr
|
||||
failed:(BOOL *)haveFailedFetchingBeforePtr
|
||||
node:(NSString **)nodePtr
|
||||
ver:(NSString **)verPtr
|
||||
ext:(NSString **)extPtr
|
||||
hash:(NSString **)hashPtr
|
||||
algorithm:(NSString **)hashAlgPtr
|
||||
forJID:(XMPPJID *)jid
|
||||
xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
// By design this method should not be invoked from the storageQueue.
|
||||
NSAssert(!dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
__block BOOL areCapabilitiesKnown = NO;
|
||||
__block BOOL haveFailedFetchingBefore = NO;
|
||||
__block NSString *node = nil;
|
||||
__block NSString *ver = nil;
|
||||
__block NSString *ext = nil;
|
||||
__block NSString *hash = nil;
|
||||
__block NSString *hashAlg = nil;
|
||||
|
||||
[self executeBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
|
||||
if (resource == nil)
|
||||
{
|
||||
// We don't know anything about the given jid
|
||||
|
||||
areCapabilitiesKnown = NO;
|
||||
haveFailedFetchingBefore = NO;
|
||||
|
||||
node = nil;
|
||||
ver = nil;
|
||||
ext = nil;
|
||||
hash = nil;
|
||||
hashAlg = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
areCapabilitiesKnown = (resource.caps != nil);
|
||||
haveFailedFetchingBefore = resource.haveFailed;
|
||||
|
||||
node = resource.node;
|
||||
ver = resource.ver;
|
||||
ext = resource.ext;
|
||||
hash = resource.hashStr;
|
||||
hashAlg = resource.hashAlgorithm;
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
if (areCapabilitiesKnownPtr) *areCapabilitiesKnownPtr = areCapabilitiesKnown;
|
||||
if (haveFailedFetchingBeforePtr) *haveFailedFetchingBeforePtr = haveFailedFetchingBefore;
|
||||
|
||||
if (nodePtr) *nodePtr = node;
|
||||
if (verPtr) *verPtr = ver;
|
||||
if (extPtr) *extPtr = ext;
|
||||
if (hashPtr) *hashPtr = hash;
|
||||
if (hashAlgPtr) *hashAlgPtr = hashAlg;
|
||||
}
|
||||
|
||||
- (void)setCapabilities:(NSXMLElement *)capabilities forHash:(NSString *)hash algorithm:(NSString *)hashAlg
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
if (hash == nil) return;
|
||||
if (hashAlg == nil) return;
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
XMPPCapsCoreDataStorageObject *caps = [self capsForHash:hash algorithm:hashAlg];
|
||||
if (caps)
|
||||
{
|
||||
caps.capabilities = capabilities;
|
||||
}
|
||||
else
|
||||
{
|
||||
caps = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPCapsCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
caps.hashStr = hash;
|
||||
caps.hashAlgorithm = hashAlg;
|
||||
|
||||
caps.capabilities = capabilities;
|
||||
}
|
||||
|
||||
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPCapsResourceCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
|
||||
NSPredicate *predicate;
|
||||
predicate = [NSPredicate predicateWithFormat:@"hashStr == %@ AND hashAlgorithm == %@", hash, hashAlg];
|
||||
|
||||
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setPredicate:predicate];
|
||||
[fetchRequest setFetchBatchSize:saveThreshold];
|
||||
|
||||
NSArray *results = [[self managedObjectContext] executeFetchRequest:fetchRequest error:nil];
|
||||
|
||||
NSUInteger unsavedCount = [self numberOfUnsavedChanges];
|
||||
|
||||
for (XMPPCapsResourceCoreDataStorageObject *resource in results)
|
||||
{
|
||||
resource.caps = caps;
|
||||
|
||||
if (++unsavedCount >= saveThreshold)
|
||||
{
|
||||
[self save];
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setCapabilities:(NSXMLElement *)capabilities forJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
// By design this method should not be invoked from the storageQueue.
|
||||
NSAssert(!dispatch_get_specific(storageQueueTag), @"Invoked on incorrect queue");
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
if (jid == nil) return;
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
XMPPCapsCoreDataStorageObject *caps;
|
||||
caps = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPCapsCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
caps.capabilities = capabilities;
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
|
||||
if (resource == nil)
|
||||
{
|
||||
resource = [NSEntityDescription insertNewObjectForEntityForName:@"XMPPCapsResourceCoreDataStorageObject"
|
||||
inManagedObjectContext:[self managedObjectContext]];
|
||||
resource.jidStr = [jid full];
|
||||
resource.streamBareJidStr = [[self myJIDForXMPPStream:stream] bare];
|
||||
}
|
||||
|
||||
resource.caps = caps;
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setCapabilitiesFetchFailedForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
resource.haveFailed = YES;
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)clearAllNonPersistentCapabilitiesForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
// This method is called for the protocol,
|
||||
// but is also called when we first load the database file from disk.
|
||||
|
||||
XMPPLogTrace();
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
[self _clearAllNonPersistentCapabilitiesForXMPPStream:stream];
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)clearNonPersistentCapabilitiesForJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
|
||||
[self scheduleBlock:^{
|
||||
|
||||
XMPPCapsResourceCoreDataStorageObject *resource = [self resourceForJID:jid xmppStream:stream];
|
||||
|
||||
if (resource != nil)
|
||||
{
|
||||
NSString *hash = resource.hashStr;
|
||||
NSString *hashAlg = resource.hashAlgorithm;
|
||||
|
||||
if (hash && hashAlg)
|
||||
{
|
||||
// The associated capabilities are persistent
|
||||
}
|
||||
else
|
||||
{
|
||||
XMPPCapsCoreDataStorageObject *caps = resource.caps;
|
||||
if (caps)
|
||||
{
|
||||
[[self managedObjectContext] deleteObject:caps];
|
||||
}
|
||||
}
|
||||
|
||||
[[self managedObjectContext] deleteObject:resource];
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "DDXML.h"
|
||||
#endif
|
||||
|
||||
@class XMPPCapsResourceCoreDataStorageObject;
|
||||
|
||||
|
||||
@interface XMPPCapsCoreDataStorageObject : NSManagedObject
|
||||
|
||||
@property (nonatomic, strong) NSXMLElement *capabilities;
|
||||
|
||||
@property (nonatomic, strong) NSString * hashStr;
|
||||
@property (nonatomic, strong) NSString * hashAlgorithm;
|
||||
@property (nonatomic, strong) NSString * capabilitiesStr;
|
||||
|
||||
@property (nonatomic, strong) NSSet * resources;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface XMPPCapsCoreDataStorageObject (CoreDataGeneratedAccessors)
|
||||
|
||||
- (void)addResourcesObject:(XMPPCapsResourceCoreDataStorageObject *)value;
|
||||
- (void)removeResourcesObject:(XMPPCapsResourceCoreDataStorageObject *)value;
|
||||
- (void)addResources:(NSSet *)value;
|
||||
- (void)removeResources:(NSSet *)value;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
#import "XMPPCapsCoreDataStorageObject.h"
|
||||
#import "XMPPCapsResourceCoreDataStorageObject.h"
|
||||
#import "XMPP.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
|
||||
@implementation XMPPCapsCoreDataStorageObject
|
||||
|
||||
@dynamic capabilities;
|
||||
|
||||
@dynamic hashStr;
|
||||
@dynamic hashAlgorithm;
|
||||
@dynamic capabilitiesStr;
|
||||
|
||||
@dynamic resources;
|
||||
|
||||
- (NSXMLElement *)capabilities
|
||||
{
|
||||
return [[NSXMLElement alloc] initWithXMLString:[self capabilitiesStr] error:nil];
|
||||
}
|
||||
|
||||
- (void)setCapabilities:(NSXMLElement *)caps
|
||||
{
|
||||
self.capabilitiesStr = [caps compactXMLString];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
@class XMPPCapsCoreDataStorageObject;
|
||||
|
||||
|
||||
@interface XMPPCapsResourceCoreDataStorageObject : NSManagedObject
|
||||
|
||||
@property (nonatomic, strong) NSString * jidStr;
|
||||
@property (nonatomic, strong) NSString * streamBareJidStr;
|
||||
|
||||
@property (nonatomic, assign) BOOL haveFailed;
|
||||
@property (nonatomic, strong) NSNumber * failed;
|
||||
|
||||
@property (nonatomic, strong) NSString * node;
|
||||
@property (nonatomic, strong) NSString * ver;
|
||||
@property (nonatomic, strong) NSString * ext;
|
||||
|
||||
@property (nonatomic, strong) NSString * hashStr;
|
||||
@property (nonatomic, strong) NSString * hashAlgorithm;
|
||||
|
||||
@property (nonatomic, strong) XMPPCapsCoreDataStorageObject * caps;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,36 @@
|
||||
#import "XMPPCapsResourceCoreDataStorageObject.h"
|
||||
#import "XMPPCapsCoreDataStorageObject.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
|
||||
@implementation XMPPCapsResourceCoreDataStorageObject
|
||||
|
||||
@dynamic jidStr;
|
||||
@dynamic streamBareJidStr;
|
||||
|
||||
@dynamic haveFailed;
|
||||
@dynamic failed;
|
||||
|
||||
@dynamic node;
|
||||
@dynamic ver;
|
||||
@dynamic ext;
|
||||
|
||||
@dynamic hashStr;
|
||||
@dynamic hashAlgorithm;
|
||||
|
||||
@dynamic caps;
|
||||
|
||||
- (BOOL)haveFailed
|
||||
{
|
||||
return [[self failed] boolValue];
|
||||
}
|
||||
|
||||
- (void)setHaveFailed:(BOOL)flag
|
||||
{
|
||||
self.failed = @(flag);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user