|
|
@@ -140,12 +140,13 @@ class Config(dict): |
|
|
|
raise InvalidConfig('Invalid web port') |
|
|
|
if 'channels' in obj: |
|
|
|
seenChannels = {} |
|
|
|
seenPaths = {} |
|
|
|
for key, channel in obj['channels'].items(): |
|
|
|
if not isinstance(key, str) or not key: |
|
|
|
raise InvalidConfig(f'Invalid channel key {key!r}') |
|
|
|
if not isinstance(channel, collections.abc.Mapping): |
|
|
|
raise InvalidConfig(f'Invalid channel for {key!r}') |
|
|
|
if any(x not in ('ircchannel', 'auth', 'active') for x in channel): |
|
|
|
if any(x not in ('ircchannel', 'path', 'auth', 'active') for x in channel): |
|
|
|
raise InvalidConfig(f'Unknown key(s) found in channel {key!r}') |
|
|
|
|
|
|
|
if 'ircchannel' not in channel: |
|
|
@@ -162,6 +163,18 @@ class Config(dict): |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} IRC channel: collides with channel {seenWebPaths[channel["ircchannel"]]!r}') |
|
|
|
seenChannels[channel['ircchannel']] = key |
|
|
|
|
|
|
|
if 'path' not in channel: |
|
|
|
channel['path'] = key |
|
|
|
if not isinstance(channel['path'], str): |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} path: not a string') |
|
|
|
if '/' in channel['path'] or '\\' in channel['path']: #TODO Anything else? |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} path: contains forward or backward slashes') |
|
|
|
if channel['path'] == 'general': |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} path: cannot be "general"') |
|
|
|
if channel['path'] in seenPaths: |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} path: collides with channel {seenPaths[channel["path"]]!r}') |
|
|
|
seenPaths[channel['path']] = key |
|
|
|
|
|
|
|
if 'auth' in channel: |
|
|
|
if channel['auth'] is not False and not isinstance(channel['auth'], str): |
|
|
|
raise InvalidConfig(f'Invalid channel {key!r} auth: must be false or a string') |
|
|
@@ -582,6 +595,7 @@ class Storage: |
|
|
|
def __init__(self, messageQueue, config): |
|
|
|
self.messageQueue = messageQueue |
|
|
|
self.config = config |
|
|
|
self.paths = {} # channel -> path from channels config |
|
|
|
self.files = {} # channel|None -> (filename, fileobj); None = general raw log |
|
|
|
|
|
|
|
def update_config(self, config): |
|
|
@@ -589,6 +603,7 @@ class Storage: |
|
|
|
channelsNew = {channel['ircchannel'] for channel in config['channels'].values()} |
|
|
|
channelsRemoved = channelsOld - channelsNew |
|
|
|
self.config = config |
|
|
|
self.paths = {channel['ircchannel']: channel['path'] for channel in self.config['channels'].values()} |
|
|
|
|
|
|
|
for channel in channelsRemoved: |
|
|
|
if channel in self.files: |
|
|
@@ -601,7 +616,7 @@ class Storage: |
|
|
|
return |
|
|
|
if channel in self.files: |
|
|
|
self.files[channel][1].close() |
|
|
|
dn = channel if channel is not None else 'general' |
|
|
|
dn = self.paths[channel] if channel is not None else 'general' |
|
|
|
mode = 'a' if channel is not None else 'ab' |
|
|
|
os.makedirs(os.path.join(self.config['storage']['path'], dn), exist_ok = True) |
|
|
|
self.files[channel] = (fn, open(os.path.join(self.config['storage']['path'], dn, fn), mode)) |
|
|
|