Browse Source

feat: add Filter support

master
dnomd343 2 years ago
parent
commit
15a7ac72d5
  1. 109
      Basis/Filter.py
  2. 12
      Filter/Shadowsocks.py
  3. 7
      demo.py

109
Basis/Filter.py

@ -1,85 +1,120 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import copy
filterObject = {
'optional': {
'type': bool,
'optional': True, # `optional` is not force require
'default': False, # disable `optional` option in default
'allowNone': False, # `optional` couldn't be None
'type': bool,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `optional` key'
},
'default': {
'type': any, # skip type check
'optional': True, # `default` is not force require
'default': None,
'allowNone': True, # `default` can be None
'type': any, # skip type check
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `default` key'
},
'allowNone': {
'type': bool,
'optional': True, # `allowNone` is not force require
'default': False, # disable `allowNone` option in default
'allowNone': False, # `allowNone` couldn't be None
'type': bool,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `allowNone` key'
},
'type': {
'type': [any, type, list, dict],
'optional': False, # `type` is force require
'allowNone': False, # `type` couldn't be None
'type': [any, type, list, dict],
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `type` key'
},
'multiSub': {
'type': bool,
'optional': True, # `multiSub` is not force require
'default': False, # disable `multiSub` option in default
'allowNone': False, # `multiSub` couldn't be None
'type': bool,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `multiSub` key'
},
'indexKey': {
'type': str,
'optional': True, # `indexKey` is not force require
'default': 'type',
'allowNone': False, # `indexKey` couldn't be None
'type': str,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `indexKey` key'
},
'format': {
'type': any,
'optional': True, # `format` is not force require
'default': lambda x: x, # don't change anything
'allowNone': False, # `format` couldn't be None
'type': any,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `format` key'
},
'filter': {
'type': any,
'optional': True, # `filter` is not force require
'default': lambda x: True, # always pass filter
'allowNone': False, # `filter` couldn't be None
'type': any,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `filter` key'
},
'errMsg': {
'type': str,
'optional': True, # `errMsg` is not force require
'default': 'filter error',
'allowNone': False, # `errMsg` couldn't be None
'type': str,
'format': lambda x: x, # return same value
'filter': lambda b: True, # always return True
'errMsg': 'Invalid `errMsg` key'
},
}
}
for field in filterObject:
filterObject[field]['errMsg'] = 'Invalid `%s` key' % field
filterObject[field]['format'] = filterObject['format']['default'] # return same value
filterObject[field]['filter'] = filterObject['filter']['default'] # always return True
def Filter(raw: dict, rules: dict) -> dict:
if type(raw) != dict:
raise RuntimeError('Invalid input for filter')
data = {}
raw = copy.deepcopy(raw)
rules = copy.deepcopy(rules)
for key, rule in rules.items():
# pretreatment process (raw --[copy / default value]--> data)
if key not in raw: # key not exist
if not rule['optional']: # force require key not exist
raise RuntimeError('Miss `%s` field' % key)
data[key] = rule['default'] # set default value
else: # key exist
data[key] = raw[key]
# format process (data --[format]--> data)
try:
data[key] = rule['format'](data[key]) # run format
except:
raise RuntimeError(rule['errMsg']) # format error
if data[key] is None: # key content is None
if not rule['allowNone']: # key is not allow None
raise RuntimeError('Field `%s` shouldn\'t be None' % key)
continue # skip following process
# filter process (data --[type check (& filter check)]--> pass / non-pass)
if type(rule['type']) == type: # str / int / bool / ...
rule['type'] = [rule['type']] # str -> [str] / int -> [int] / ...
if type(rule['type']) == list: # [str, int, bool, ...]
if data[key] == any and any in rule['type']: # special case -> skip type filter
pass
elif type(data[key]) not in rule['type']: # type not in allow list
raise RuntimeError('Invalid `%s` field' % key)
elif type(rule['type']) == dict: # check subObject
if not rule['multiSub']: # single subObject
data[key] = Filter(data[key], rule['type'])
else: # multi subObject
# TODO: multi sub filter
pass
continue
elif rule['type'] != any: # type == any -> skip type filter
raise RuntimeError('Unknown `type` in rules')
if not rule['filter'](data[key]): # run filter
raise RuntimeError(rule['errMsg'])
return data
def rulesFilter(rules: dict) -> dict:
result = {}
for key, rule in rules.items(): # filter by basic rules
result[key] = Filter(rule, filterObject)
return result
filterObject = rulesFilter(filterObject) # format itself

12
Filter/Shadowsocks.py

@ -4,9 +4,10 @@
from Filter.Plugin import pluginFormat
from Basis.Functions import toInt, toStr
from Basis.Functions import isHost, isPort
from Basis.Filter import Filter, rulesFilter
from Basis.Constant import ssMethods, pluginClients
pluginObject = {
pluginObject = rulesFilter({
'type': {
'type': str,
'format': lambda s: pluginFormat(toStr(s).strip().lower()),
@ -20,9 +21,9 @@ pluginObject = {
'format': toStr,
'errMsg': 'Invalid SIP003 param'
}
}
})
ssObject = {
ssObject = rulesFilter({
'server': {
'type': str,
'format': toStr,
@ -53,4 +54,7 @@ ssObject = {
'type': pluginObject,
'errMsg': 'Invalid pluginObject'
}
}
})
from pprint import pprint
pprint(ssObject, sort_dicts = False)

7
demo.py

@ -0,0 +1,7 @@
#!/usr/bin/env python
import Filter.Shadowsocks
# from pprint import pprint
# from Basis.Filter import filterObject
# pprint(filterObject, sort_dicts = False)
Loading…
Cancel
Save