mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-22 06:42:44 +00:00
See ChangeLog
Monotone-Parent: 99ca451495fc28364e0d775f0a4b950f0df4164d Monotone-Revision: 740d7bf9e85e6faf504cb29387d81a224a6a92e9 Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2009-08-03T15:46:02 Monotone-Branch: ca.inverse.sogo
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
2009-08-03 Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
|
||||
* Dropped the current caching subsystem based on
|
||||
GNUstep's DO and replaced it with memcached. This
|
||||
is much more efficient and scalable than DO and will
|
||||
also prevent obscure libffi/libffcall crashes on
|
||||
various platforms.
|
||||
|
||||
2009-08-03 Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* UI/Scheduler/UIxCalView.m ([UIxCalView -setCurrentView:]): avoid
|
||||
|
||||
@@ -128,6 +128,7 @@ endif
|
||||
ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
|
||||
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
|
||||
ADDITIONAL_LDFLAGS += -lmemcached
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
ifneq ($(FHS_INSTALL_ROOT),)
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSString.h>
|
||||
@@ -309,7 +308,7 @@ static NSLock *lock = nil;
|
||||
if (!currentUser)
|
||||
{
|
||||
currentUser = [NSMutableDictionary dictionary];
|
||||
[[SOGoCache sharedCache] cacheAttributes: currentUser forLogin: login];
|
||||
[[SOGoCache sharedCache] cacheValues: currentUser ofType: @"attributes" forLogin: login];
|
||||
}
|
||||
[currentUser setObject: password forKey: @"password"];
|
||||
}
|
||||
@@ -417,34 +416,18 @@ static NSLock *lock = nil;
|
||||
#endif
|
||||
key = [newUser objectForKey: @"c_uid"];
|
||||
if (key)
|
||||
[[SOGoCache sharedCache] cacheAttributes: newUser forLogin: key];
|
||||
{
|
||||
[[SOGoCache sharedCache] cacheValues: newUser ofType: @"attributes" forLogin: key];
|
||||
}
|
||||
|
||||
emails = [[newUser objectForKey: @"emails"] objectEnumerator];
|
||||
while ((key = [emails nextObject]))
|
||||
{
|
||||
[[SOGoCache sharedCache] cacheAttributes: newUser forLogin: key];
|
||||
[[SOGoCache sharedCache] cacheValues: newUser ofType: @"attributes" forLogin: key];
|
||||
}
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
|
||||
// We propagate the loaded LDAP attributes to other sogod instances
|
||||
// which will cache them in SOGoCache (excluding for the instance
|
||||
// that actually posts the notification)
|
||||
if ([newUser objectForKey: @"c_uid"])
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
|
||||
d = [NSMutableDictionary dictionary];
|
||||
[d setObject: newUser forKey: @"values"];
|
||||
[d setObject: [newUser objectForKey: @"c_uid"]
|
||||
forKey: @"uid"];
|
||||
|
||||
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
|
||||
postNotificationName: @"SOGoUserAttributesHaveLoaded"
|
||||
object: nil
|
||||
userInfo: d
|
||||
deliverImmediately: YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* NSDictionary+DAV.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2008 Inverse inc.
|
||||
* Copyright (C) 2008-2009 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
|
||||
@@ -255,9 +255,12 @@ NSString *jsonNullString = @"null";
|
||||
|
||||
- (BOOL)scanJSONNumber:(NSNumber **)number
|
||||
{
|
||||
NSDecimal decimal;
|
||||
BOOL result = [self scanDecimal:&decimal];
|
||||
*number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
|
||||
//NSDecimal decimal;
|
||||
//BOOL result = [self scanDecimal:&decimal];
|
||||
//*number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
|
||||
int value;
|
||||
BOOL result = [self scanInt: &value];
|
||||
*number = [NSNumber numberWithInt: value];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include <libmemcached/memcached.h>
|
||||
|
||||
@class NSMutableDictionary;
|
||||
@class NSString;
|
||||
@class NSTimer;
|
||||
@@ -39,6 +41,8 @@
|
||||
{
|
||||
@private
|
||||
NSTimer *_cleanupTimer;
|
||||
memcached_server_st *servers;
|
||||
memcached_st *handle;
|
||||
}
|
||||
|
||||
+ (NSTimeInterval) cleanupInterval;
|
||||
@@ -54,15 +58,13 @@
|
||||
- (void) registerUser: (SOGoUser *) user;
|
||||
- (id) userNamed: (NSString *) name;
|
||||
|
||||
- (void) cacheAttributes: (NSDictionary *) theAttributes
|
||||
forLogin: (NSString *) theLogin;
|
||||
- (NSMutableDictionary *) userAttributesForLogin: (NSString *) theLogin;
|
||||
- (SOGoUserDefaults *) userDefaultsForLogin: (NSString *) theLogin;
|
||||
- (SOGoUserDefaults *) userSettingsForLogin: (NSString *) theLogin;
|
||||
- (NSDictionary *) userDefaultsForLogin: (NSString *) theLogin;
|
||||
- (NSDictionary *) userSettingsForLogin: (NSString *) theLogin;
|
||||
|
||||
- (void) setDefaults: (SOGoUserDefaults *) theDefaults
|
||||
forLogin: (NSString *) theLogin
|
||||
key: (NSString *) theKey;
|
||||
- (void) cacheValues: (NSDictionary *) theAttributes
|
||||
ofType: (NSString *) theType
|
||||
forLogin: (NSString *) theLogin;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -22,26 +22,16 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* [ Structure ]
|
||||
* users: key = user ID value = NSMutableDictionary instance
|
||||
* value: key = @"user" value = SOGOUser instance
|
||||
* key = @"cleanupDate" value = NSDate instance
|
||||
* key = @"defaults" value = SOGoUserDefaults instance
|
||||
* key = @"settings" value = SOGoUserDefaults instance
|
||||
* key = @"attributes" value = NSDictionary instance (attributes from LDAP)
|
||||
* [ Cache Structure ]
|
||||
*
|
||||
* [ Workflows - processes A and B ]
|
||||
*
|
||||
* A cache user defaults and posts the notification
|
||||
* B ....
|
||||
*
|
||||
* B crashes
|
||||
* B receives a notificaion update
|
||||
* users value = instances of SOGoUser > flushed after the completion of every SOGo requests
|
||||
* <uid>+defaults value = NSDictionary instance > user's defaults
|
||||
* <uid>+settings value = NSDictionary instance > user's settings
|
||||
* <uid>+attributes value = NSMutableDictionary instance > user's LDAP attributes
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSLock.h>
|
||||
#import <Foundation/NSString.h>
|
||||
@@ -57,6 +47,8 @@
|
||||
|
||||
#import "SOGoCache.h"
|
||||
|
||||
#import "NSDictionary+BSJSONAdditions.h"
|
||||
|
||||
// We define the default value for cleaning up cached
|
||||
// users' preferences. This value should be relatively
|
||||
// high to avoid useless database calls.
|
||||
@@ -65,6 +57,8 @@ static NSTimeInterval cleanupInterval = 300;
|
||||
static NSMutableDictionary *cache = nil;
|
||||
static NSMutableDictionary *users = nil;
|
||||
|
||||
static NSString *memcachedServerName = @"localhost";
|
||||
|
||||
static SOGoCache *sharedCache = nil;
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
@@ -91,7 +85,7 @@ static NSLock *lock;
|
||||
[lock lock];
|
||||
#endif
|
||||
if (!sharedCache)
|
||||
sharedCache = [self new];
|
||||
sharedCache = [[self alloc] init];
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
@@ -105,6 +99,10 @@ static NSLock *lock;
|
||||
[lock lock];
|
||||
#endif
|
||||
[cache removeAllObjects];
|
||||
|
||||
// This is essential for refetching the cached values in case something has changed
|
||||
// accross various sogod processes
|
||||
[users removeAllObjects];
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
@@ -115,41 +113,11 @@ static NSLock *lock;
|
||||
if ((self = [super init]))
|
||||
{
|
||||
NSString *cleanupSetting;
|
||||
|
||||
memcached_return error;
|
||||
|
||||
cache = [[NSMutableDictionary alloc] init];
|
||||
users = [[NSMutableDictionary alloc] init];
|
||||
|
||||
// We register ourself for notifications
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_userAttributesHaveLoaded:)
|
||||
name: @"SOGoUserAttributesHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_userDefaultsHaveLoaded:)
|
||||
name: @"SOGoUserDefaultsHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_userDefaultsHaveChanged:)
|
||||
name: @"SOGoUserDefaultsHaveChanged"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_userSettingsHaveLoaded:)
|
||||
name: @"SOGoUserSettingsHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
addObserver: self
|
||||
selector: @selector(_userSettingsHaveChanged:)
|
||||
name: @"SOGoUserSettingsHaveChanged"
|
||||
object: nil];
|
||||
|
||||
// We fire our timer that will cleanup cache entries
|
||||
cleanupSetting = [[NSUserDefaults standardUserDefaults]
|
||||
objectForKey: @"SOGoCacheCleanupInterval"];
|
||||
@@ -157,13 +125,16 @@ static NSLock *lock;
|
||||
if (cleanupSetting && [cleanupSetting doubleValue] > 0.0)
|
||||
cleanupInterval = [cleanupSetting doubleValue];
|
||||
|
||||
_cleanupTimer = [NSTimer scheduledTimerWithTimeInterval: cleanupInterval
|
||||
target: self
|
||||
selector: @selector(_cleanupSources)
|
||||
userInfo: nil
|
||||
repeats: YES];
|
||||
[self logWithFormat: @"Cache cleanup interval set every %f seconds",
|
||||
[self logWithFormat: @"Cache cleanup interval set every %f seconds for memcached",
|
||||
cleanupInterval];
|
||||
|
||||
handle = memcached_create(NULL);
|
||||
|
||||
if (handle)
|
||||
{
|
||||
servers = memcached_server_list_append(NULL, [memcachedServerName UTF8String], 11211, &error);
|
||||
error = memcached_server_push(handle, servers);
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -171,31 +142,8 @@ static NSLock *lock;
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: @"SOGoUserAttributesHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: @"SOGoUserDefaultsHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: @"SOGoUserDefaultsHaveChanged"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: @"SOGoUserSettingsHaveLoaded"
|
||||
object: nil];
|
||||
|
||||
[[NSDistributedNotificationCenter defaultCenter]
|
||||
removeObserver: self
|
||||
name: @"SOGoUserSettingsHaveChanged"
|
||||
object: nil];
|
||||
|
||||
memcached_server_free(servers);
|
||||
memcached_free(handle);
|
||||
[cache release];
|
||||
[users release];
|
||||
[super dealloc];
|
||||
@@ -269,21 +217,10 @@ static NSLock *lock;
|
||||
|
||||
- (void) registerUser: (SOGoUser *) user
|
||||
{
|
||||
NSData *cleanupDate;
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
[lock lock];
|
||||
#endif
|
||||
|
||||
cleanupDate = [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]];
|
||||
|
||||
if (![users objectForKey: [user login]])
|
||||
[users setObject: [NSMutableDictionary dictionary] forKey: [user login]];
|
||||
|
||||
[[users objectForKey: [user login]] setObject: user forKey: @"user"];
|
||||
[[users objectForKey: [user login]] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
|
||||
[users setObject: user forKey: [user login]];
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
@@ -291,260 +228,92 @@ static NSLock *lock;
|
||||
|
||||
- (id) userNamed: (NSString *) name
|
||||
{
|
||||
return [[users objectForKey: name] objectForKey: @"user"];
|
||||
return [users objectForKey: name];
|
||||
}
|
||||
|
||||
- (void) cacheAttributes: (NSDictionary *) theAttributes
|
||||
forLogin: (NSString *) theLogin
|
||||
//
|
||||
// For non-blocking cache method, see memcached_behavior_set and MEMCACHED_BEHAVIOR_NO_BLOCK
|
||||
// memcached is thread-safe so no need to lock here.
|
||||
//
|
||||
- (void) cacheValues: (NSDictionary *) theAttributes
|
||||
ofType: (NSString *) theType
|
||||
forLogin: (NSString *) theLogin
|
||||
{
|
||||
if (![users objectForKey: theLogin])
|
||||
[users setObject: [NSMutableDictionary dictionary] forKey: theLogin];
|
||||
memcached_return error;
|
||||
const char *key, *value;
|
||||
unsigned int len, vlen;
|
||||
|
||||
[[users objectForKey: theLogin] setObject: theAttributes forKey: @"attributes"];
|
||||
[[users objectForKey: theLogin] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
key = [[NSString stringWithFormat: @"%@+%@", theLogin, theType] UTF8String];
|
||||
len = strlen(key);
|
||||
|
||||
value = [[theAttributes jsonStringValue] UTF8String];
|
||||
vlen = strlen(value);
|
||||
|
||||
error = memcached_set(handle, key, len, value, vlen, cleanupInterval, 0);
|
||||
|
||||
if (error != MEMCACHED_SUCCESS)
|
||||
[self logWithFormat: @"memcached error: unable to cache values with subtype %@ for user %@", theType, theLogin];
|
||||
//else
|
||||
//[self logWithFormat: @"memcached: cached values (%s) with subtype %@ for user %@", value, theType, theLogin];
|
||||
}
|
||||
|
||||
- (NSDictionary *) _valuesOfType: (NSString *) theType
|
||||
forLogin: (NSString *) theLogin
|
||||
{
|
||||
NSDictionary *d;
|
||||
|
||||
memcached_return rc;
|
||||
const char *key;
|
||||
char *s;
|
||||
unsigned int len, vlen, flags;
|
||||
|
||||
if (!handle)
|
||||
return nil;
|
||||
|
||||
key = [[NSString stringWithFormat: @"%@+%@", theLogin, theType] UTF8String];
|
||||
len = strlen(key);
|
||||
d = nil;
|
||||
|
||||
s = memcached_get(handle, key, len, &vlen, &flags, &rc);
|
||||
|
||||
if (rc == MEMCACHED_SUCCESS && s)
|
||||
{
|
||||
NSString *v;
|
||||
|
||||
v = [NSString stringWithUTF8String: s];
|
||||
d = [NSDictionary dictionaryWithJSONString: v];
|
||||
//[self logWithFormat: @"read values (%@) for subtype %@ for user %@", [d description], theType, theLogin];
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
- (NSMutableDictionary *) userAttributesForLogin: (NSString *) theLogin
|
||||
{
|
||||
return [[users objectForKey: theLogin] objectForKey: @"attributes"];
|
||||
id o;
|
||||
|
||||
o = [self _valuesOfType: @"attributes" forLogin: theLogin];
|
||||
|
||||
if (o)
|
||||
return [NSMutableDictionary dictionaryWithDictionary: o];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (SOGoUserDefaults *) userDefaultsForLogin: (NSString *) theLogin
|
||||
- (NSDictionary *) userDefaultsForLogin: (NSString *) theLogin
|
||||
{
|
||||
return [[users objectForKey: theLogin] objectForKey: @"defaults"];
|
||||
return [self _valuesOfType: @"defaults" forLogin: theLogin];
|
||||
}
|
||||
|
||||
- (SOGoUserDefaults *) userSettingsForLogin: (NSString *) theLogin
|
||||
- (NSDictionary *) userSettingsForLogin: (NSString *) theLogin
|
||||
{
|
||||
return [[users objectForKey: theLogin] objectForKey: @"settings"];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) setDefaults: (SOGoUserDefaults *) theDefaults
|
||||
forLogin: (NSString *) theLogin
|
||||
key: (NSString *) theKey
|
||||
{
|
||||
if (![users objectForKey: theLogin])
|
||||
[users setObject: [NSMutableDictionary dictionary] forKey: theLogin];
|
||||
|
||||
[[users objectForKey: theLogin] setObject: theDefaults forKey: theKey];
|
||||
[[users objectForKey: theLogin] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
|
||||
//NSLog(@"Set %@ to %@", theKey, [users objectForKey: theLogin]);
|
||||
}
|
||||
|
||||
//
|
||||
// Notification callbacks.
|
||||
//
|
||||
- (void) _cacheValues: (NSDictionary *) theValues
|
||||
login: (NSString *) theLogin
|
||||
url: (NSString *) theURL
|
||||
key: (NSString *) theKey
|
||||
{
|
||||
SOGoUserDefaults *defaults;
|
||||
NSURL *url;
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
[lock lock];
|
||||
#endif
|
||||
url = [[[NSURL alloc] initWithString: theURL] autorelease];
|
||||
|
||||
defaults = [[[SOGoUserDefaults alloc] initWithTableURL: url
|
||||
uid: theLogin
|
||||
fieldName: [NSString stringWithFormat: @"c_%@", theKey]
|
||||
shouldPropagate: YES]
|
||||
autorelease];
|
||||
[defaults setValues: theValues];
|
||||
[self setDefaults: defaults forLogin: theLogin key: theKey];
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _userAttributesHaveLoaded: (NSNotification *) theNotification
|
||||
{
|
||||
NSString *uid;
|
||||
|
||||
uid = [[theNotification userInfo] objectForKey: @"uid"];
|
||||
//NSLog(@"Caching user attributes for UID: %@", uid);
|
||||
if (![self userAttributesForLogin: uid])
|
||||
{
|
||||
NSEnumerator *emails;
|
||||
NSDictionary *values;
|
||||
NSString *key;
|
||||
|
||||
if (![users objectForKey: uid])
|
||||
[users setObject: [NSMutableDictionary dictionary] forKey: uid];
|
||||
|
||||
values = [[theNotification userInfo] objectForKey: @"values"];
|
||||
[self cacheAttributes: values forLogin: uid];
|
||||
|
||||
emails = [[values objectForKey: @"emails"] objectEnumerator];
|
||||
while ((key = [emails nextObject]))
|
||||
{
|
||||
[self cacheAttributes: values forLogin: key];
|
||||
}
|
||||
|
||||
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _userDefaultsHaveLoaded: (NSNotification *) theNotification
|
||||
{
|
||||
NSString *uid;
|
||||
|
||||
uid = [[theNotification userInfo] objectForKey: @"uid"];
|
||||
//NSLog(@"Loading user defaults for UID: %@", uid);
|
||||
if (![self userDefaultsForLogin: uid])
|
||||
{
|
||||
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
|
||||
login: uid
|
||||
url: [[theNotification userInfo] objectForKey: @"url"]
|
||||
key: @"defaults"];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _userDefaultsHaveChanged: (NSNotification *) theNotification
|
||||
{
|
||||
SOGoUser *user;
|
||||
SOGoUserDefaults *defaults;
|
||||
NSString *uid;
|
||||
|
||||
uid = [[theNotification userInfo] objectForKey: @"uid"];
|
||||
|
||||
// When the user defaults changed, we must invalidate the
|
||||
// ivar language for the user object.
|
||||
user = [self userNamed: uid];
|
||||
if (user)
|
||||
[user invalidateLanguage];
|
||||
|
||||
//NSLog(@"Updating user defaults for UID: %@", uid);
|
||||
defaults = (SOGoUserDefaults *)[self userDefaultsForLogin: uid];
|
||||
if (defaults)
|
||||
{
|
||||
#if defined(THREADSAFE)
|
||||
[lock lock];
|
||||
#endif
|
||||
[defaults setValues: [[theNotification userInfo] objectForKey: @"values"]];
|
||||
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
|
||||
login: uid
|
||||
url: [[theNotification userInfo] objectForKey: @"url"]
|
||||
key: @"defaults"];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _userSettingsHaveLoaded: (NSNotification *) theNotification
|
||||
{
|
||||
NSString *uid;
|
||||
|
||||
uid = [[theNotification userInfo] objectForKey: @"uid"];
|
||||
//NSLog(@"Loading user settings for UID: %@", uid);
|
||||
if (![self userSettingsForLogin: uid])
|
||||
{
|
||||
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
|
||||
login: uid
|
||||
url: [[theNotification userInfo] objectForKey: @"url"]
|
||||
key: @"settings"];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _userSettingsHaveChanged: (NSNotification *) theNotification
|
||||
{
|
||||
SOGoUserDefaults *settings;
|
||||
NSString *uid;
|
||||
|
||||
uid = [[theNotification userInfo] objectForKey: @"uid"];
|
||||
//NSLog(@"Updating user settings for UID: %@", uid);
|
||||
settings = (SOGoUserDefaults *)[self userSettingsForLogin: uid];
|
||||
if (settings)
|
||||
{
|
||||
#if defined(THREADSAFE)
|
||||
[lock lock];
|
||||
#endif
|
||||
[settings setValues: [[theNotification userInfo] objectForKey: @"values"]];
|
||||
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
|
||||
forKey: @"cleanupDate"];
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
|
||||
login: uid
|
||||
url: [[theNotification userInfo] objectForKey: @"url"]
|
||||
key: @"settings"];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _cleanupSources
|
||||
{
|
||||
NSDictionary *currentEntry;
|
||||
NSEnumerator *userIDs;
|
||||
NSString *currentID;
|
||||
NSDate *now;
|
||||
|
||||
unsigned int count;
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
[lock lock];
|
||||
#endif
|
||||
|
||||
now = [NSDate date];
|
||||
|
||||
// We cleanup the user cache
|
||||
userIDs = [[users allKeys] objectEnumerator];
|
||||
count = 0;
|
||||
while ((currentID = [userIDs nextObject]))
|
||||
{
|
||||
currentEntry = [users objectForKey: currentID];
|
||||
|
||||
if ([now earlierDate: [currentEntry objectForKey: @"cleanupDate"]] == now)
|
||||
{
|
||||
[users removeObjectForKey: currentID];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
[self logWithFormat: @"cleaned %d users records from users cache",
|
||||
count];
|
||||
|
||||
#if defined(THREADSAFE)
|
||||
[lock unlock];
|
||||
#endif
|
||||
return [self _valuesOfType: @"settings" forLogin: theLogin];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -64,6 +64,7 @@ extern NSString *SOGoWeekStartFirstFullWeek;
|
||||
|
||||
@interface SOGoUser : SoUser
|
||||
{
|
||||
SOGoUserDefaults *_defaults, *_settings;
|
||||
SOGoUserFolder *homeFolder;
|
||||
NSString *currentPassword;
|
||||
NSString *language;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
@@ -257,6 +256,9 @@ _timeValue (NSString *key)
|
||||
{
|
||||
LDAPUserManager *um;
|
||||
NSString *realUID;
|
||||
|
||||
_defaults = nil;
|
||||
_settings = nil;
|
||||
|
||||
// We propagate the cache if we do NOT trust the login names.
|
||||
// When trusting login names, we 'assume' we're dealing with a
|
||||
@@ -300,6 +302,8 @@ _timeValue (NSString *key)
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[_defaults release];
|
||||
[_settings release];
|
||||
[allEmails release];
|
||||
[currentPassword release];
|
||||
[cn release];
|
||||
@@ -454,7 +458,6 @@ _timeValue (NSString *key)
|
||||
uid: login
|
||||
fieldName: @"c_defaults"
|
||||
shouldPropagate: propagateCache];
|
||||
[o autorelease];
|
||||
|
||||
return o;
|
||||
}
|
||||
@@ -467,113 +470,91 @@ _timeValue (NSString *key)
|
||||
uid: login
|
||||
fieldName: @"c_settings"
|
||||
shouldPropagate: propagateCache];
|
||||
[o autorelease];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (NSUserDefaults *) userDefaults
|
||||
{
|
||||
SOGoUserDefaults *defaults;
|
||||
NSDictionary *values;
|
||||
NSMutableDictionary *d;
|
||||
|
||||
defaults = [[SOGoCache sharedCache] userDefaultsForLogin: login];
|
||||
|
||||
if (!defaults)
|
||||
if (!_defaults)
|
||||
{
|
||||
defaults = [self primaryUserDefaults];
|
||||
if (defaults)
|
||||
_defaults = [self primaryUserDefaults];
|
||||
if (_defaults)
|
||||
{
|
||||
[defaults fetchProfile];
|
||||
values = [defaults values];
|
||||
|
||||
values = [[SOGoCache sharedCache] userDefaultsForLogin: login];
|
||||
|
||||
if (values)
|
||||
{
|
||||
// See explanation in -language
|
||||
[self invalidateLanguage];
|
||||
|
||||
// Required parameters for the Web interface. This will trigger the
|
||||
// preferences to load so it's important to leave those calls here.
|
||||
if (![[defaults stringForKey: @"ReplyPlacement"] length])
|
||||
[defaults setObject: defaultReplyPlacement forKey: @"ReplyPlacement"];
|
||||
if (![[defaults stringForKey: @"SignaturePlacement"] length])
|
||||
[defaults setObject: defaultSignaturePlacement forKey: @"SignaturePlacement"];
|
||||
if (![[defaults stringForKey: @"MessageForwarding"] length])
|
||||
[defaults setObject: defaultMessageForwarding forKey: @"MessageForwarding"];
|
||||
if (![[defaults stringForKey: @"MessageCheck"] length])
|
||||
[defaults setObject: defaultMessageCheck forKey: @"MessageCheck"];
|
||||
|
||||
// We propagate the loaded user defaults to other sogod instances
|
||||
// which will cache them in SOGoCache (including for the instance
|
||||
// that actually posts the notification)
|
||||
d = [NSMutableDictionary dictionary];
|
||||
[d setObject: values forKey: @"values"];
|
||||
[d setObject: login forKey: @"uid"];
|
||||
[d setObject: [SOGoProfileURL absoluteString] forKey: @"url"];
|
||||
|
||||
[[SOGoCache sharedCache] setDefaults: defaults
|
||||
forLogin: login key: @"defaults"];
|
||||
|
||||
if (propagateCache)
|
||||
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
|
||||
postNotificationName: @"SOGoUserDefaultsHaveLoaded"
|
||||
object: nil
|
||||
userInfo: d
|
||||
deliverImmediately: YES];
|
||||
[_defaults setValues: values];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_defaults fetchProfile];
|
||||
values = [_defaults values];
|
||||
|
||||
if (values)
|
||||
{
|
||||
// Required parameters for the Web interface. This will trigger the
|
||||
// preferences to load so it's important to leave those calls here.
|
||||
if (![[_defaults stringForKey: @"ReplyPlacement"] length])
|
||||
[_defaults setObject: defaultReplyPlacement forKey: @"ReplyPlacement"];
|
||||
if (![[_defaults stringForKey: @"SignaturePlacement"] length])
|
||||
[_defaults setObject: defaultSignaturePlacement forKey: @"SignaturePlacement"];
|
||||
if (![[_defaults stringForKey: @"MessageForwarding"] length])
|
||||
[_defaults setObject: defaultMessageForwarding forKey: @"MessageForwarding"];
|
||||
if (![[_defaults stringForKey: @"MessageCheck"] length])
|
||||
[_defaults setObject: defaultMessageCheck forKey: @"MessageCheck"];
|
||||
|
||||
[[SOGoCache sharedCache] cacheValues: [_defaults values] ofType: @"defaults" forLogin: login];
|
||||
}
|
||||
}
|
||||
|
||||
// See explanation in -language
|
||||
[self invalidateLanguage];
|
||||
}
|
||||
}
|
||||
//else
|
||||
// NSLog(@"User defaults cache hit for %@", login);
|
||||
|
||||
return (NSUserDefaults *) defaults;
|
||||
return (NSUserDefaults *) _defaults;
|
||||
}
|
||||
|
||||
- (NSUserDefaults *) userSettings
|
||||
{
|
||||
SOGoUserDefaults *settings;
|
||||
NSDictionary *values;
|
||||
|
||||
settings = [[SOGoCache sharedCache] userSettingsForLogin: login];
|
||||
|
||||
if (!settings)
|
||||
if (!_settings)
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
|
||||
settings = [self primaryUserSettings];
|
||||
if (settings)
|
||||
_settings = [self primaryUserSettings];
|
||||
if (_settings)
|
||||
{
|
||||
[settings fetchProfile];
|
||||
values = [settings values];
|
||||
values = [[SOGoCache sharedCache] userSettingsForLogin: login];
|
||||
|
||||
if (values)
|
||||
{
|
||||
// See explanation in -language
|
||||
[self invalidateLanguage];
|
||||
|
||||
// We propagate the loaded user settings to other sogod instances
|
||||
// which will cache them in SOGoCache (including for the instance
|
||||
// that actually posts the notification)
|
||||
d = [NSMutableDictionary dictionary];
|
||||
[d setObject: values forKey: @"values"];
|
||||
[d setObject: login forKey: @"uid"];
|
||||
[d setObject: [SOGoProfileURL absoluteString] forKey: @"url"];
|
||||
|
||||
[[SOGoCache sharedCache] setDefaults: settings forLogin: login key: @"settings"];
|
||||
|
||||
if (propagateCache)
|
||||
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
|
||||
postNotificationName: @"SOGoUserSettingsHaveLoaded"
|
||||
object: nil
|
||||
userInfo: d
|
||||
deliverImmediately: YES];
|
||||
[_settings setValues: values];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_settings fetchProfile];
|
||||
values = [_settings values];
|
||||
|
||||
if (values)
|
||||
{
|
||||
[[SOGoCache sharedCache] cacheValues: values ofType: @"settings" forLogin: login];
|
||||
}
|
||||
}
|
||||
|
||||
// See explanation in -language
|
||||
[self invalidateLanguage];
|
||||
}
|
||||
}
|
||||
//else
|
||||
// NSLog(@"User settings cache hit for %@", login);
|
||||
|
||||
return (NSUserDefaults *) settings;
|
||||
return (NSUserDefaults *) _settings;
|
||||
}
|
||||
|
||||
- (void) invalidateLanguage
|
||||
@@ -586,7 +567,7 @@ _timeValue (NSString *key)
|
||||
if (![language length])
|
||||
{
|
||||
language = [[self userDefaults] stringForKey: @"Language"];
|
||||
// This is a hack until we handle the connection errors to the db a
|
||||
// This is a workaround until we handle the connection errors to the db in a
|
||||
// better way. It enables us to avoid retrieving the userDefaults too
|
||||
// many times when the DB is down, causing a huge delay.
|
||||
if (![language length])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright (C) 2005 SKYRIX Software AG
|
||||
Copyright (C) 2008-2009 Inverse inc.
|
||||
Copyright (C) 2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOGo.
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
NSURL *url;
|
||||
NSString *uid;
|
||||
NSString *fieldName;
|
||||
NSCalendarDate *lastFetch;
|
||||
NSMutableDictionary *values;
|
||||
BOOL propagateCache;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDistributedNotificationCenter.h>
|
||||
#import <Foundation/NSPropertyList.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
@@ -74,7 +73,6 @@ static NSString *uidColumnName = @"c_uid";
|
||||
- (void) dealloc
|
||||
{
|
||||
[values release];
|
||||
[lastFetch release];
|
||||
[url release];
|
||||
[uid release];
|
||||
[fieldName release];
|
||||
@@ -160,7 +158,6 @@ static NSString *uidColumnName = @"c_uid";
|
||||
[values addEntriesFromDictionary: v];
|
||||
}
|
||||
|
||||
ASSIGN(lastFetch, [NSCalendarDate date]);
|
||||
defFlags.modified = NO;
|
||||
rc = YES;
|
||||
}
|
||||
@@ -295,25 +292,10 @@ static NSString *uidColumnName = @"c_uid";
|
||||
|
||||
if (rc)
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
|
||||
d = [NSMutableDictionary dictionary];
|
||||
[d setObject: values forKey: @"values"];
|
||||
[d setObject: uid forKey: @"uid"];
|
||||
[d setObject: [url absoluteString] forKey: @"url"];
|
||||
|
||||
[[SOGoCache sharedCache] setDefaults: self
|
||||
forLogin: uid
|
||||
key: ([fieldName isEqualToString: @"c_defaults"] ? @"defaults" : @"settings")];
|
||||
|
||||
if (propagateCache)
|
||||
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
|
||||
postNotificationName: ([fieldName isEqualToString: @"c_defaults"]
|
||||
? @"SOGoUserDefaultsHaveChanged"
|
||||
: @"SOGoUserSettingsHaveChanged")
|
||||
object: nil
|
||||
userInfo: d
|
||||
deliverImmediately: YES];
|
||||
[[SOGoCache sharedCache] cacheValues: values
|
||||
ofType: ([fieldName isEqualToString: @"c_defaults"] ? @"defaults" : @"settings")
|
||||
forLogin: uid];
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -344,7 +326,6 @@ static NSString *uidColumnName = @"c_uid";
|
||||
|
||||
values = [[NSMutableDictionary alloc] init];
|
||||
[values addEntriesFromDictionary: theValues];
|
||||
ASSIGN(lastFetch, [NSCalendarDate date]);
|
||||
defFlags.modified = NO;
|
||||
defFlags.isNew = NO;
|
||||
}
|
||||
@@ -429,8 +410,6 @@ static NSString *uidColumnName = @"c_uid";
|
||||
- (void) flush
|
||||
{
|
||||
[values removeAllObjects];
|
||||
[lastFetch release];
|
||||
lastFetch = nil;
|
||||
defFlags.modified = NO;
|
||||
defFlags.isNew = NO;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ Group: Productivity/Groupware
|
||||
Source: SOGo-%{sogo_version}.tar.gz
|
||||
Prefix: %{sogo_prefix}
|
||||
AutoReqProv: off
|
||||
Requires: gnustep-base sope%{sope_major_version}%{sope_minor_version}-core httpd sope%{sope_major_version}%{sope_minor_version}-core sope%{sope_major_version}%{sope_minor_version}-appserver sope%{sope_major_version}%{sope_minor_version}-ldap sope%{sope_major_version}%{sope_minor_version}-cards sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore
|
||||
Requires: gnustep-base sope%{sope_major_version}%{sope_minor_version}-core httpd sope%{sope_major_version}%{sope_minor_version}-core sope%{sope_major_version}%{sope_minor_version}-appserver sope%{sope_major_version}%{sope_minor_version}-ldap sope%{sope_major_version}%{sope_minor_version}-cards sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore memcached libmemcached
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
|
||||
BuildPreReq: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel
|
||||
BuildPreReq: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel libmemcached-devel
|
||||
%description
|
||||
SOGo is a groupware server built around OpenGroupware.org (OGo) and
|
||||
the SOPE application server. It focuses on scalability.
|
||||
|
||||
Reference in New Issue
Block a user