settings.py (11101B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\util\settings.py 2 import blue 3 import log 4 import os 5 import signals 6 import types 7 import yaml 8 import traceback 9 import uthread 10 import uthread2 11 from carbon.common.script.util.timerstuff import AutoTimer 12 from carbonui.util.settingsYamlLoader import UnicodeConvertingYamlLoader 13 from carbonui.util.bunch import Bunch 14 from carbonui.util.various_unsorted import GetAttrs 15 from carbonui.util import defaultsetting 16 from copy import deepcopy 17 18 class SettingSection(): 19 20 def __init__(self, name, filepath, autoStoreInterval, service): 21 self._name = name 22 self._filepath = filepath 23 self._dirty = False 24 self._service = service 25 self.datastore = {} 26 self.timeoutTimer = None 27 self._scatterSettingsChangedThreads = {} 28 self._messenger = signals.Messenger() 29 self.LoadFromFile(filepath, autoStoreInterval) 30 31 def __str__(self): 32 return '%s\nSetting section, %s; holding %s groups.\nFileLocation: %s' % ('-' * 60, 33 self._name, 34 len(self.datastore), 35 repr(self._filepath)) 36 37 def __repr__(self): 38 s = self.__str__() + '\n' 39 for groupName, groupValue in self.datastore.iteritems(): 40 s += '%s:\n' % groupName 41 for settingName, settingValue in groupValue.iteritems(): 42 s += ' %s: %s\n' % (settingName, settingValue) 43 44 return s 45 46 class Group(dict): 47 48 def __init__(self, name, section): 49 self.__dict__['name'] = name 50 self.__dict__['section'] = section 51 52 def __getattr__(self, attrName): 53 if hasattr(self, 'section'): 54 return self.section.Get(self.name, attrName) 55 56 def Get(self, attrName, defValue = None): 57 retVal = self.__getattr__(attrName) 58 if retVal is None: 59 return defValue 60 return retVal 61 62 def __setattr__(self, attrName, value): 63 if hasattr(self, 'section'): 64 self.section.Set(self.name, attrName, value) 65 66 Set = __setattr__ 67 68 def Release(self): 69 self.section = None 70 71 def HasKey(self, attrName): 72 return self.section.HasKey(self.name, attrName) 73 74 def Delete(self, attrName): 75 self.section.Delete(self.name, attrName) 76 77 def GetValues(self): 78 return self.section.GetValues(self.name) 79 80 def LoadFromFile(self, filepath, autoStoreInterval): 81 data = None 82 try: 83 fn = blue.paths.ResolvePath(filepath) 84 data = blue.AtomicFileRead(fn) 85 except: 86 pass 87 88 if data: 89 try: 90 self.datastore = blue.marshal.Load(data) 91 for k, v in self.datastore.iteritems(): 92 self.CreateGroup(k) 93 94 except Exception: 95 log.LogException('Error loading settings data file') 96 97 self.timeoutTimer = AutoTimer(autoStoreInterval * 1000, self.WriteToDisk) 98 99 def GetValues(self, groupName): 100 return self.datastore[groupName] 101 102 def Get(self, groupName, settingName): 103 if groupName not in self.datastore: 104 self.CreateGroup(groupName) 105 if settingName in self.datastore[groupName]: 106 value = self.datastore[groupName][settingName][1] 107 self.datastore[groupName][settingName] = (blue.os.GetWallclockTime(), value) 108 return value 109 else: 110 n = settingName 111 if type(n) == types.UnicodeType: 112 n = n.encode('UTF-8') 113 return GetAttrs(defaultsetting, self._name, groupName, n) 114 115 def HasKey(self, groupName, settingName): 116 return settingName in self.datastore[groupName] 117 118 def Delete(self, groupName, settingName): 119 if self.HasKey(groupName, settingName): 120 del self.datastore[groupName][settingName] 121 self._ScatterSettingsChanged(groupName, settingName) 122 123 def Set(self, groupName, settingName, value): 124 if groupName not in self.datastore: 125 self.CreateGroup(groupName) 126 self.datastore[groupName][settingName] = (blue.os.GetWallclockTime(), value) 127 self.FlagDirty() 128 self._ScatterSettingsChanged(groupName, settingName) 129 130 def Remove(self, groupName, settingName = None): 131 if groupName in self.datastore: 132 group = self.datastore[groupName] 133 if settingName: 134 if settingName in group: 135 del group[settingName] 136 else: 137 del self.datastore[groupName] 138 self.FlagDirty() 139 140 def HasGroup(self, groupName): 141 return groupName in self.__dict__ and groupName in self.datastore 142 143 def DuplicateGroup(self, oldGroupName, newGroupName): 144 if not self.HasGroup(oldGroupName) or self.HasGroup(newGroupName): 145 return 146 self.CreateGroup(newGroupName) 147 self.datastore[newGroupName] = deepcopy(self.datastore[oldGroupName]) 148 self.FlagDirty() 149 150 def RenameGroup(self, oldGroupName, newGroupName): 151 if not self.HasGroup(oldGroupName): 152 return 153 self.CreateGroup(newGroupName) 154 self.datastore[newGroupName] = deepcopy(self.datastore[oldGroupName]) 155 del self.__dict__[oldGroupName] 156 del self.datastore[oldGroupName] 157 self.FlagDirty() 158 159 def RemoveGroup(self, groupName): 160 if not self.HasGroup(groupName): 161 return 162 del self.__dict__[groupName] 163 del self.datastore[groupName] 164 self.FlagDirty() 165 166 def ClearGroup(self, groupName): 167 if not self.HasGroup(groupName): 168 return 169 self.datastore[groupName] = {} 170 self.FlagDirty() 171 172 def CreateGroup(self, groupName): 173 if groupName not in self.__dict__: 174 self.__dict__[groupName] = self.Group(groupName, self) 175 if groupName not in self.datastore: 176 self.datastore[groupName] = {} 177 178 def FlagDirty(self): 179 self._dirty = True 180 181 def WriteToDiskImmediate(self): 182 self.WriteToDisk() 183 184 def WriteToDisk(self): 185 if self._dirty: 186 self._dirty = False 187 fn = blue.paths.ResolvePathForWriting(self._filepath) 188 try: 189 if os.access(fn, os.F_OK) and not os.access(fn, os.W_OK): 190 os.chmod(fn, 438) 191 k = blue.marshal.Save(self.datastore) 192 blue.AtomicFileWrite(fn, k) 193 except Exception as e: 194 log.LogError('Failed writing to disk', str(self), '-', repr(e)) 195 196 def Unload(self): 197 self.timeoutTimer = None 198 self.FlushOldEntries() 199 self.WriteToDisk() 200 201 def Save(self): 202 self.FlushOldEntries() 203 self.WriteToDisk() 204 205 def FlushOldEntries(self): 206 lastModified = blue.os.GetWallclockTime() - const.WEEK * 6 207 for k, v in self.datastore.iteritems(): 208 for key in v.keys(): 209 if v[key][0] <= lastModified: 210 del v[key] 211 212 self.FlagDirty() 213 214 def SetDatastore(self, datastore): 215 self.datastore = datastore 216 217 def GetDatastore(self): 218 return self.datastore 219 220 def KillTimer(self): 221 if self.timeoutTimer is not None: 222 self.timeoutTimer.KillTimer() 223 self.timeoutTimer = None 224 225 def Subscribe(self, groupName, settingName, handler): 226 self._messenger.SubscribeToMessage(u'{}.{}'.format(groupName, settingName), handler) 227 228 def Unsubscribe(self, groupName, settingName, handler): 229 self._messenger.UnsubscribeFromMessage(u'{}.{}'.format(groupName, settingName), handler) 230 231 def _ScatterSettingsChanged(self, groupName, settingName): 232 self._messenger.SendMessage(u'{}.{}'.format(groupName, settingName)) 233 settingsID = (groupName, settingName) 234 if settingsID not in self._scatterSettingsChangedThreads: 235 self._scatterSettingsChangedThreads[settingsID] = uthread2.start_tasklet(self._ScatterSettingsChangedThread, groupName, settingName) 236 237 def _ScatterSettingsChangedThread(self, groupName, settingName): 238 uthread2.Sleep(0.1) 239 self._scatterSettingsChangedThreads.pop((groupName, settingName), None) 240 sm.ScatterEvent('OnClientSettingsChanged', self._name, groupName, settingName) 241 242 243 class YAMLSettingSection(SettingSection): 244 245 def __init__(self, name, filepath, autoStoreInterval, service): 246 SettingSection.__init__(self, name, filepath, autoStoreInterval, service) 247 248 def LoadFromFile(self, filepath, autoStoreInterval): 249 data = None 250 try: 251 fn = blue.paths.ResolvePath(filepath) 252 data = blue.AtomicFileRead(fn) 253 except: 254 pass 255 256 if data: 257 try: 258 self.datastore = yaml.load(data, Loader=UnicodeConvertingYamlLoader) 259 for k, v in self.datastore.iteritems(): 260 self.CreateGroup(k) 261 262 except: 263 log.LogError('Error loading settings data file -- ', traceback.format_exc()) 264 265 self.timeoutTimer = AutoTimer(autoStoreInterval * 1000, self.WriteToDisk) 266 267 def WriteToDisk(self): 268 uthread.new(self._WriterThreadFunc) 269 270 def WriteToDiskImmediate(self): 271 self._WriterThreadFunc() 272 273 def _WriterThreadFunc(self): 274 if self._dirty: 275 self._dirty = False 276 fn = blue.paths.ResolvePathForWriting(self._filepath) 277 try: 278 if os.access(fn, os.F_OK) and not os.access(fn, os.W_OK): 279 os.chmod(fn, 438) 280 k = yaml.dump(self.datastore, Dumper=yaml.CSafeDumper) 281 blue.AtomicFileWrite(fn, k) 282 except Exception as e: 283 log.LogError('Failed writing to disk', str(self), '-', repr(e)) 284 285 286 def LoadBaseSettings(): 287 import __builtin__ 288 if not hasattr(__builtin__, 'settings'): 289 __builtin__.settings = Bunch() 290 sections = (('user', session.userid, 'dat'), ('char', session.charid, 'dat'), ('public', None, 'yaml')) 291 292 def _LoadSettingsIntoBuiltins(sectionName, identifier, settingsClass, extension): 293 key = '%s%s' % (sectionName, identifier) 294 filePath = blue.paths.ResolvePathForWriting(u'settings:/core_%s_%s.%s' % (sectionName, identifier or '_', extension)) 295 section = settingsClass(sectionName, filePath, 62, service=None) 296 __builtin__.settings.Set(sectionName, section) 297 298 for sectionName, identifier, format in sections: 299 _LoadSettingsIntoBuiltins(sectionName, identifier, SettingSection, 'dat') 300 301 settings.public.CreateGroup('generic') 302 settings.public.CreateGroup('device') 303 settings.public.CreateGroup('ui') 304 settings.public.CreateGroup('audio') 305 settings.user.CreateGroup('tabgroups') 306 settings.user.CreateGroup('windows') 307 settings.user.CreateGroup('suppress') 308 settings.user.CreateGroup('ui') 309 settings.user.CreateGroup('cmd') 310 settings.user.CreateGroup('localization') 311 settings.char.CreateGroup('windows') 312 settings.char.CreateGroup('ui') 313 settings.char.CreateGroup('zaction')