Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 736 | olof | 1 | ########################################################### |
| 2 | # |
||
| 3 | # Daemon configuration |
||
| 4 | # |
||
| 5 | ########################################################### |
||
| 6 | import logging as log |
||
| 7 | import pickle |
||
| 8 | import hashlib |
||
| 9 | import os |
||
| 10 | import imp |
||
| 11 | import re |
||
| 12 | from ConfigParser import ConfigParser |
||
| 13 | import filters |
||
| 14 | import statespaces |
||
| 749 | olof | 15 | from CanPktHandlerBase import CanPktHandlerBase |
| 16 | from CanPktHandler1 import CanPktHandler1 |
||
| 736 | olof | 17 | |
| 750 | olof | 18 | from NodeIfSerial import NodeIfSerial |
| 19 | from NodeIfTCP import NodeIfTCP |
||
| 20 | from NodeIfUDP import NodeIfUDP |
||
| 21 | from NodeIfTCPTLS import NodeIfTCPTLS |
||
| 22 | from NodeIfCanStim import NodeIfCanStim |
||
| 23 | |||
| 736 | olof | 24 | class DynamicModuleCfg: |
| 25 | """Dynamic module manager""" |
||
| 26 | |||
| 27 | modSubDir = None |
||
| 28 | CHECKSUM_FILE = 'checksums' |
||
| 29 | CHECKSUM_SECTION = 'SHA-1_CHECKSUMS' |
||
| 30 | |||
| 31 | def __init__(self, modSubDir): |
||
| 32 | self.modSubDir = modSubDir |
||
| 33 | self.checkSumFile = modSubDir + '/' + self.CHECKSUM_FILE |
||
| 738 | olof | 34 | if not os.path.exists(self.checkSumFile): |
| 35 | self.__createCsumsFile() |
||
| 736 | olof | 36 | |
| 37 | def loadModule(self, className): |
||
| 38 | pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p' |
||
| 39 | log.debug('Reading from ' + pFileName) |
||
| 40 | fp = open(pFileName, 'r') |
||
| 41 | p = pickle.Unpickler(fp) |
||
| 42 | loadedMod = p.load() |
||
| 43 | fp.close() |
||
| 44 | if not self.__verifyCheckSum(className, pFileName): |
||
| 45 | print 'Invalid checksum' |
||
| 46 | return None |
||
| 47 | else: |
||
| 48 | return loadedMod |
||
| 49 | |||
| 50 | |||
| 51 | def loadModules(self, config = None): |
||
| 52 | subDirFiles = os.listdir(os.getcwd() + '/' + self.modSubDir) |
||
| 53 | p = re.compile('.p$', re.IGNORECASE) |
||
| 54 | modFiles = [elem for elem in subDirFiles if p.search(elem) is not None] |
||
| 55 | modNames = [] |
||
| 56 | for mfName in modFiles: |
||
| 57 | modNames.append(mfName.split('.')[0]) |
||
| 58 | log.debug('Found modules: ' + str(modNames)) |
||
| 59 | myMods = {} |
||
| 60 | for mName in modNames: |
||
| 61 | classObj = self.loadModule(mName) |
||
| 62 | if classObj is not None: |
||
| 63 | myMods[mName] = classObj |
||
| 64 | return myMods |
||
| 65 | |||
| 66 | |||
| 67 | def saveModule(self, className, classObj): |
||
| 68 | pFileName = os.getcwd() + '/' + self.modSubDir + '/' + className + '.p' |
||
| 69 | log.debug('Writing to ' + pFileName) |
||
| 70 | fp = open(pFileName, 'w') |
||
| 71 | p = pickle.Pickler(fp) |
||
| 72 | p.dump(classObj) |
||
| 73 | fp.close() |
||
| 74 | self.__writeCheckSum(className, pFileName) |
||
| 75 | |||
| 76 | |||
| 77 | def __doCheckSum(self, filename): |
||
| 78 | f = open(filename, 'r') |
||
| 79 | data = f.read() |
||
| 80 | f.close() |
||
| 81 | hasher = hashlib.sha1() |
||
| 82 | hasher.update(data) |
||
| 83 | digest = hasher.hexdigest() |
||
| 84 | return digest |
||
| 85 | |||
| 86 | |||
| 738 | olof | 87 | def __createCsumsFile(self): |
| 88 | csumsfile = open(self.checkSumFile, 'w') |
||
| 89 | csumsfile.write('[' + self.CHECKSUM_SECTION + ']\n') |
||
| 90 | csumsfile.close() |
||
| 91 | |||
| 92 | |||
| 736 | olof | 93 | def __writeCheckSum(self, entryname, filename): |
| 94 | csumsfile = open(self.checkSumFile, 'r+') |
||
| 95 | csumcfg = ConfigParser() |
||
| 96 | csumcfg.readfp(csumsfile) |
||
| 97 | digest = self.__doCheckSum(filename) |
||
| 98 | csumcfg.set(self.CHECKSUM_SECTION, entryname, digest) |
||
| 99 | csumsfile.seek(0) |
||
| 100 | csumcfg.write(csumsfile) |
||
| 101 | |||
| 102 | |||
| 103 | def __verifyCheckSum(self, entryname, filename): |
||
| 104 | csumsfile = open(self.checkSumFile, 'r') |
||
| 105 | csumcfg = ConfigParser() |
||
| 106 | csumcfg.readfp(csumsfile) |
||
| 107 | digest = csumcfg.get(self.CHECKSUM_SECTION, entryname) |
||
| 108 | cur_digest = self.__doCheckSum(filename) |
||
| 109 | log.debug('Old checksum ' + digest + '\nNew checksum: ' + cur_digest) |
||
| 110 | if cur_digest == digest: |
||
| 111 | return True |
||
| 112 | return False |
||
| 113 | |||
| 114 | |||
| 115 | def importModule(self, className, requiredAttributes): |
||
| 116 | """Imports a given class from the module with the same name """ |
||
| 117 | |||
| 118 | codeFile = os.getcwd() + '/' + self.modSubDir + '/' + className + '.py' |
||
| 119 | mod = imp.load_source(self.modSubDir + '.' + className, codeFile) |
||
| 120 | newClass = eval('mod.' + className)() |
||
| 121 | |||
| 122 | for ra in requiredAttributes: |
||
| 123 | if not hasattr(newClass, ra): |
||
| 124 | print className, ': missing required symbol \"' + ra + '\"' |
||
| 125 | return None |
||
| 126 | |||
| 127 | self.saveModule(className, newClass) |
||
| 128 | return newClass |
||
| 129 | |||
| 130 | |||
| 131 | class FilterCfg: |
||
| 132 | """Filter resource manager""" |
||
| 133 | |||
| 134 | REQUIRED_ATTRIBUTES = ['ASSOCIATED_SPACES', 'DESCRIPTIVE_NAME', |
||
| 135 | 'attach', 'detach', 'filter'] |
||
| 136 | |||
| 137 | dynamicModuleCfg = None |
||
| 138 | FILTER_SUBDIR = 'filters' |
||
| 139 | filterModules = {} |
||
| 140 | |||
| 141 | def __init__(self): |
||
| 142 | self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR) |
||
| 143 | |||
| 144 | def loadFilter(self, name): |
||
| 145 | newFilt = self.dynamicModuleCfg.loadModule(name) |
||
| 146 | if newFilt is not None: |
||
| 748 | olof | 147 | self.filterModules[name] = newFilt |
| 736 | olof | 148 | return True |
| 149 | else: |
||
| 150 | return False |
||
| 151 | |||
| 152 | def loadFilters(self, config = None): |
||
| 153 | self.filterModules = self.dynamicModuleCfg.loadModules() |
||
| 154 | for fM in self.filterModules: |
||
| 155 | log.debug(fM) |
||
| 156 | |||
| 157 | def __saveFilter(self, className, classObj): |
||
| 158 | self.dynamicModuleCfg.saveModule(className, classObj) |
||
| 159 | |||
| 160 | def saveFilters(self): |
||
| 161 | for className in self.filterModules: |
||
| 162 | self.__saveFilter(className, self.filterModules[className]) |
||
| 163 | |||
| 164 | def importFilter(self, className): |
||
| 165 | """Imports a given filter definition """ |
||
| 166 | classObj = self.dynamicModuleCfg.importModule(className, self.REQUIRED_ATTRIBUTES) |
||
| 167 | if classObj is not None: |
||
| 168 | print 'Imported: ' + classObj.DESCRIPTIVE_NAME |
||
| 169 | return True |
||
| 170 | else: |
||
| 171 | return False |
||
| 172 | |||
| 173 | |||
| 174 | class StateSpaceCfg: |
||
| 175 | """State space resource manager""" |
||
| 176 | |||
| 748 | olof | 177 | REQUIRED_ATTRIBUTES = ['DESCRIPTIVE_NAME', 'RELATED_SPACES' |
| 736 | olof | 178 | 'load', 'reset', 'run', 'unload'] |
| 179 | |||
| 180 | dynamicModuleCfg = None |
||
| 181 | FILTER_SUBDIR = 'statespaces' |
||
| 182 | spaceModules = {} |
||
| 183 | |||
| 184 | def __init__(self): |
||
| 185 | self.dynamicModuleCfg = DynamicModuleCfg(self.FILTER_SUBDIR) |
||
| 186 | |||
| 187 | def loadSpace(self, name): |
||
| 188 | newSpace = self.dynamicModuleCfg.loadModule(name) |
||
| 189 | if newSpace is not None: |
||
| 748 | olof | 190 | self.spaceModules[name] = newFilt |
| 736 | olof | 191 | return True |
| 192 | else: |
||
| 193 | return False |
||
| 194 | |||
| 195 | def loadSpaces(self, config = None): |
||
| 196 | self.spaceModules = self.dynamicModuleCfg.loadModules() |
||
| 197 | for sM in self.spaceModules: |
||
| 198 | log.debug(sM) |
||
| 199 | |||
| 200 | def __saveSpace(self, className, classObj): |
||
| 201 | self.dynamicModuleCfg.saveModule(className, classObj) |
||
| 202 | |||
| 203 | def saveSpaces(self): |
||
| 204 | for className in self.spaceModules: |
||
| 205 | self.__saveSpace(className, self.spaceModules[className]) |
||
| 206 | |||
| 207 | def importSpace(self, name): |
||
| 208 | """Imports a given state space definition file """ |
||
| 209 | classObj = self.dynamicModuleCfg.importModule(name, self.REQUIRED_ATTRIBUTES) |
||
| 210 | if classObj is not None: |
||
| 211 | print 'Imported: ' + classObj.DESCRIPTIVE_NAME |
||
| 212 | return True |
||
| 213 | else: |
||
| 214 | return False |
||
| 215 | |||
| 216 | class DaemonConfig: |
||
| 217 | |||
| 218 | stateSpaceCfg = None |
||
| 219 | filterCfg = None |
||
| 749 | olof | 220 | pktHandler = None |
| 221 | |||
| 736 | olof | 222 | filterChain = [] |
| 749 | olof | 223 | nodeInterfaces = [] |
| 224 | nodeInterfaceMap = {} |
||
| 736 | olof | 225 | |
| 750 | olof | 226 | INTERFACE_TYPES = {'serial' : NodeIfSerial, 'tcp' : NodeIfTCP, |
| 227 | 'udp' : NodeIfUDP, 'sim' : NodeIfCanStim, |
||
| 228 | 'tcptls' : NodeIfTCPTLS} |
||
| 229 | |||
| 736 | olof | 230 | def __init__ (self): |
| 231 | self.filterCfg = FilterCfg() |
||
| 232 | self.stateSpaceCfg = StateSpaceCfg() |
||
| 750 | olof | 233 | self.pktHandler = CanPktHandler1(self) |
| 736 | olof | 234 | |
| 749 | olof | 235 | def load(self): |
| 236 | self.stateSpaceCfg.loadSpaces() |
||
| 750 | olof | 237 | self.filterCfg.loadFilters() |
| 238 | self.__setupFilterBindings() |
||
| 239 | self.__setupStateSpaceRelations() |
||
| 240 | self.__setupFilterChain() |
||
| 241 | |||
| 749 | olof | 242 | def save(self): |
| 243 | self.stateSpaceCfg.saveSpaces() |
||
| 244 | self.filterCfg.saveFilters() |
||
| 245 | |||
| 750 | olof | 246 | def addInterface(self, type, cfg = None): |
| 247 | """ addInterface |
||
| 248 | type - a valid interface type name |
||
| 249 | cfg - interface configuration |
||
| 250 | returns: True on success, False otherwise """ |
||
| 251 | |||
| 252 | if not self.INTERFACE_TYPES.has_key(type): |
||
| 253 | log.debug('addInterface called with invalid interface type') |
||
| 254 | return False |
||
| 255 | |||
| 256 | cfg = self.INTERFACE_TYPES[type].DEFAULT_CONFIG |
||
| 257 | print cfg |
||
| 258 | nodeIf = self.INTERFACE_TYPES[type](self.pktHandler, cfg) |
||
| 259 | print nodeIf |
||
| 260 | self.nodeInterfaces.append(nodeIf) |
||
| 261 | |||
| 262 | def remInterface(self, name): |
||
| 263 | pass |
||
| 264 | |||
| 749 | olof | 265 | def __setupFilterChain(self): |
| 736 | olof | 266 | self.filterChain = ['DefaultFilter'] |
| 267 | |||
| 749 | olof | 268 | def __setupFilterBindings(self): |
| 736 | olof | 269 | for f in self.filterCfg.filterModules.values(): |
| 270 | assocSpaces = [] |
||
| 271 | for s in f.ASSOCIATED_SPACES: |
||
| 272 | if self.stateSpaceCfg.spaceModules.has_key(s): |
||
| 273 | assocSpaces.append(self.stateSpaceCfg.spaceModules[s]) |
||
| 274 | else: |
||
| 275 | print 'WARNING: Reference to undefined state space: ' + s |
||
| 276 | setattr(f, '__ASSOCIATED_SPACES__', assocSpaces) |
||
| 748 | olof | 277 | |
| 750 | olof | 278 | def __setupStateSpaceRelations(self): |
| 748 | olof | 279 | for sm in self.stateSpaceCfg.spaceModules: |
| 280 | relatedSpaceNames = self.stateSpaceCfg.spaceModules[sm].RELATED_SPACES |
||
| 281 | relatedSpaces = {} |
||
| 282 | for rsname in relatedSpaceNames: |
||
| 283 | relatedSpaces[rsname] = self.stateSpaceCfg.spaceModules[rsname] |
||
| 750 | olof | 284 | setattr(self.stateSpaceCfg.spaceModules[sm], '__RELATED_SPACES__', relatedSpaces) |
| 285 |