2020-01-21 18:16:56 +00:00
|
|
|
import _ from 'lodash'
|
|
|
|
|
2020-01-08 07:38:56 +00:00
|
|
|
export const checkPartialUpdate = (settings, updatedSettings, description) => {
|
|
|
|
return Object.keys(updatedSettings).reduce((acc, group) => {
|
|
|
|
acc[group] = Object.keys(updatedSettings[group]).reduce((acc, key) => {
|
|
|
|
if (!partialUpdate(group, key)) {
|
|
|
|
const updated = Object.keys(settings[group][key]).reduce((acc, settingName) => {
|
|
|
|
const setting = description
|
|
|
|
.find(element => element.group === group && element.key === key).children
|
|
|
|
.find(child => child.key === settingName)
|
|
|
|
const type = setting ? setting.type : ''
|
|
|
|
acc[settingName] = [type, settings[group][key][settingName]]
|
|
|
|
return acc
|
|
|
|
}, {})
|
|
|
|
acc[key] = updated
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
acc[key] = updatedSettings[group][key]
|
|
|
|
return acc
|
|
|
|
}, {})
|
|
|
|
return acc
|
|
|
|
}, {})
|
|
|
|
}
|
|
|
|
|
2020-01-21 18:16:56 +00:00
|
|
|
const getCurrentValue = (type, value, path) => {
|
|
|
|
if (type === 'state') {
|
|
|
|
return _.get(value, path)
|
|
|
|
} else {
|
|
|
|
const [firstSettingName, ...restKeys] = path
|
|
|
|
const firstSegment = value[firstSettingName]
|
|
|
|
if (restKeys.length === 0 || !firstSegment) {
|
|
|
|
return firstSegment || false
|
|
|
|
} else {
|
|
|
|
const secondSegment = (value, keys) => {
|
|
|
|
const [element, ...rest] = keys
|
|
|
|
return keys.length === 0 ? value : secondSegment(value[1][element], rest)
|
|
|
|
}
|
|
|
|
return secondSegment(firstSegment, restKeys)
|
|
|
|
}
|
2020-01-01 10:37:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 14:00:32 +00:00
|
|
|
const getValueWithoutKey = (key, [type, value]) => {
|
|
|
|
if (type === 'atom' && value.length > 1) {
|
|
|
|
return `:${value}`
|
|
|
|
} else if (key === ':backends') {
|
|
|
|
const index = value.findIndex(el => el === ':ex_syslogger')
|
|
|
|
const updatedArray = value.slice()
|
|
|
|
if (index !== -1) {
|
|
|
|
updatedArray[index] = { 'tuple': ['ExSyslogger', ':ex_syslogger'] }
|
|
|
|
}
|
|
|
|
return updatedArray
|
2019-12-28 21:47:50 +00:00
|
|
|
} else if (key === ':types') {
|
|
|
|
return Object.keys(value).reduce((acc, key) => { return { ...acc, [key]: value[key][1] } }, {})
|
2019-12-24 14:00:32 +00:00
|
|
|
}
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
2019-12-23 23:12:41 +00:00
|
|
|
export const parseNonTuples = (key, value) => {
|
|
|
|
if (key === ':backends') {
|
2019-12-24 14:00:32 +00:00
|
|
|
const index = value.findIndex(el => typeof el === 'object' && el.tuple.includes(':ex_syslogger'))
|
2019-12-23 23:12:41 +00:00
|
|
|
const updated = value.map((el, i) => i === index ? ':ex_syslogger' : el)
|
2020-01-03 10:00:20 +00:00
|
|
|
return updated
|
2019-12-23 23:12:41 +00:00
|
|
|
}
|
2020-01-03 10:00:20 +00:00
|
|
|
if (key === ':args') {
|
|
|
|
const index = value.findIndex(el => typeof el === 'object' && el.tuple.includes('implode'))
|
|
|
|
const updated = value.map((el, i) => i === index ? 'implode' : el)
|
|
|
|
return updated
|
|
|
|
}
|
|
|
|
return value
|
2019-12-23 23:12:41 +00:00
|
|
|
}
|
2019-08-09 16:45:25 +00:00
|
|
|
// REFACTOR
|
|
|
|
export const parseTuples = (tuples, key) => {
|
|
|
|
return tuples.reduce((accum, item) => {
|
2019-12-25 23:02:30 +00:00
|
|
|
if (key === ':rate_limit') {
|
|
|
|
accum[item.tuple[0]] = Array.isArray(item.tuple[1])
|
|
|
|
? item.tuple[1].map(el => el.tuple)
|
|
|
|
: item.tuple[1].tuple
|
2019-12-13 23:06:52 +00:00
|
|
|
} else if (item.tuple[0] === ':mascots') {
|
|
|
|
accum[item.tuple[0]] = item.tuple[1].reduce((acc, mascot) => {
|
|
|
|
return [...acc, { [mascot.tuple[0]]: { ...mascot.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
|
|
|
|
}, [])
|
2020-03-04 16:46:31 +00:00
|
|
|
} else if (
|
|
|
|
item.tuple[0] === ':groups' ||
|
|
|
|
item.tuple[0] === ':replace' ||
|
|
|
|
item.tuple[0] === ':retries' ||
|
|
|
|
item.tuple[0] === ':crontab'
|
|
|
|
) {
|
2019-12-13 19:11:29 +00:00
|
|
|
accum[item.tuple[0]] = item.tuple[1].reduce((acc, group) => {
|
|
|
|
return [...acc, { [group.tuple[0]]: { value: group.tuple[1], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
|
|
|
|
}, [])
|
2019-12-20 20:17:39 +00:00
|
|
|
} else if (item.tuple[0] === ':match_actor') {
|
|
|
|
accum[item.tuple[0]] = Object.keys(item.tuple[1]).reduce((acc, regex) => {
|
|
|
|
return [...acc, { [regex]: { value: item.tuple[1][regex], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }}]
|
|
|
|
}, [])
|
2019-12-15 18:37:55 +00:00
|
|
|
} else if (item.tuple[0] === ':icons') {
|
|
|
|
accum[item.tuple[0]] = item.tuple[1].map(icon => {
|
|
|
|
return Object.keys(icon).map(name => {
|
|
|
|
return { key: name, value: icon[name], id: `f${(~~(Math.random() * 1e8)).toString(16)}` }
|
|
|
|
})
|
|
|
|
}, [])
|
2019-12-21 21:52:42 +00:00
|
|
|
} else if (item.tuple[0] === ':prune') {
|
|
|
|
accum[item.tuple[0]] = item.tuple[1] === ':disabled' ? [item.tuple[1]] : item.tuple[1].tuple
|
2019-12-17 19:43:40 +00:00
|
|
|
} else if (item.tuple[0] === ':proxy_url') {
|
|
|
|
accum[item.tuple[0]] = parseProxyUrl(item.tuple[1])
|
2020-01-03 10:00:20 +00:00
|
|
|
} else if (item.tuple[0] === ':args') {
|
|
|
|
accum[item.tuple[0]] = parseNonTuples(item.tuple[0], item.tuple[1])
|
2019-08-09 16:45:25 +00:00
|
|
|
} else if (Array.isArray(item.tuple[1]) &&
|
2019-11-11 13:47:54 +00:00
|
|
|
(typeof item.tuple[1][0] === 'object' && !Array.isArray(item.tuple[1][0])) && item.tuple[1][0]['tuple']) {
|
2019-12-09 15:40:33 +00:00
|
|
|
accum[item.tuple[0]] = parseTuples(item.tuple[1], item.tuple[0])
|
2019-11-17 14:06:31 +00:00
|
|
|
} else if (Array.isArray(item.tuple[1])) {
|
2020-01-06 05:05:51 +00:00
|
|
|
accum[item.tuple[0]] = item.tuple[1]
|
2019-11-11 13:47:54 +00:00
|
|
|
} else if (item.tuple[0] === ':ip') {
|
|
|
|
accum[item.tuple[0]] = item.tuple[1].tuple.join('.')
|
2019-08-21 17:48:30 +00:00
|
|
|
} else if (item.tuple[1] && typeof item.tuple[1] === 'object') {
|
2020-01-06 05:05:51 +00:00
|
|
|
accum[item.tuple[0]] = parseObject(item.tuple[1])
|
2019-08-09 16:45:25 +00:00
|
|
|
} else {
|
2019-12-06 06:50:23 +00:00
|
|
|
accum[item.tuple[0]] = item.tuple[1]
|
2019-08-09 16:45:25 +00:00
|
|
|
}
|
|
|
|
return accum
|
|
|
|
}, {})
|
|
|
|
}
|
|
|
|
|
2019-12-09 15:40:33 +00:00
|
|
|
const parseObject = object => {
|
|
|
|
return Object.keys(object).reduce((acc, item) => {
|
|
|
|
acc[item] = object[item]
|
|
|
|
return acc
|
|
|
|
}, {})
|
2019-08-09 16:45:25 +00:00
|
|
|
}
|
|
|
|
|
2019-12-17 19:43:40 +00:00
|
|
|
const parseProxyUrl = value => {
|
2019-12-18 19:56:18 +00:00
|
|
|
if (value && !Array.isArray(value) &&
|
|
|
|
typeof value === 'object' &&
|
|
|
|
value.tuple.length === 3 &&
|
|
|
|
value.tuple[0] === ':socks5') {
|
2019-12-17 19:43:40 +00:00
|
|
|
const [, host, port] = value.tuple
|
|
|
|
return { socks5: true, host, port }
|
|
|
|
} else if (typeof value === 'string') {
|
|
|
|
const [host, port] = value.split(':')
|
|
|
|
return { socks5: false, host, port }
|
|
|
|
}
|
|
|
|
return { socks5: false, host: null, port: null }
|
|
|
|
}
|
|
|
|
|
2020-01-08 07:38:56 +00:00
|
|
|
const partialUpdate = (group, key) => {
|
2020-01-25 12:01:13 +00:00
|
|
|
return !(group === ':auto_linker' && key === ':opts')
|
2019-12-10 21:24:43 +00:00
|
|
|
}
|
|
|
|
|
2020-01-01 10:37:27 +00:00
|
|
|
export const processNested = (valueForState, valueForUpdatedSettings, group, parentKey, parents, settings, updatedSettings) => {
|
|
|
|
const [{ key, type }, ...otherParents] = parents
|
2020-01-03 06:31:07 +00:00
|
|
|
const path = [group, parentKey, ...parents.reverse().map(parent => parent.key).slice(0, -1)]
|
2020-01-01 10:37:27 +00:00
|
|
|
|
2020-01-21 18:16:56 +00:00
|
|
|
let updatedValueForState = valueExists('state', settings, path)
|
|
|
|
? { ...getCurrentValue('state', settings[group][parentKey], parents.map(el => el.key).slice(0, -1)),
|
2020-01-01 10:37:27 +00:00
|
|
|
...{ [key]: valueForState }}
|
|
|
|
: { [key]: valueForState }
|
2020-01-21 18:16:56 +00:00
|
|
|
let updatedValueForUpdatedSettings = valueExists('updatedSettings', updatedSettings, path)
|
|
|
|
? { ...getCurrentValue('updatedSettings', updatedSettings[group][parentKey], parents.map(el => el.key).slice(0, -1))[1],
|
2020-01-01 10:37:27 +00:00
|
|
|
...{ [key]: [type, valueForUpdatedSettings] }}
|
|
|
|
: { [key]: [type, valueForUpdatedSettings] }
|
|
|
|
|
2020-01-03 07:30:41 +00:00
|
|
|
if (group === ':mime' && parents[0].key === ':types') {
|
2020-01-21 18:16:56 +00:00
|
|
|
updatedValueForState = settings[group][parents[0].key]
|
|
|
|
? { ...settings[group][parents[0].key].value, ...updatedValueForState }
|
|
|
|
: updatedValueForState
|
|
|
|
updatedValueForUpdatedSettings = settings[group][parents[0].key]
|
|
|
|
? { ...Object.keys(settings[group][parents[0].key].value)
|
2020-01-03 07:30:41 +00:00
|
|
|
.reduce((acc, el) => {
|
|
|
|
return { ...acc, [el]: [type, settings[group][parents[0].key].value[el]] }
|
|
|
|
}, {}),
|
2020-01-21 18:16:56 +00:00
|
|
|
...updatedValueForUpdatedSettings }
|
|
|
|
: updatedValueForUpdatedSettings
|
2020-01-03 07:30:41 +00:00
|
|
|
}
|
|
|
|
|
2020-01-01 10:37:27 +00:00
|
|
|
return otherParents.length === 1
|
|
|
|
? { valueForState: updatedValueForState, valueForUpdatedSettings: updatedValueForUpdatedSettings, setting: otherParents[0] }
|
|
|
|
: processNested(updatedValueForState, updatedValueForUpdatedSettings, group, parentKey, otherParents, settings, updatedSettings)
|
|
|
|
}
|
|
|
|
|
2020-01-21 18:16:56 +00:00
|
|
|
const valueExists = (type, value, path) => {
|
|
|
|
if (type === 'state') {
|
|
|
|
return _.get(value, path)
|
|
|
|
} else {
|
|
|
|
const [group, key, firstSettingName, ...restKeys] = path
|
|
|
|
const firstSegment = _.get(value, [group, key, firstSettingName])
|
|
|
|
if (restKeys.length === 0 || !firstSegment) {
|
|
|
|
return firstSegment || false
|
|
|
|
} else {
|
|
|
|
const secondSegment = (value, keys) => {
|
|
|
|
if (keys.length === 0) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
const [element, ...rest] = keys
|
|
|
|
return value[1][element] ? secondSegment(value[1][element], rest) : false
|
|
|
|
}
|
|
|
|
return secondSegment(firstSegment, restKeys)
|
|
|
|
}
|
2020-01-01 10:37:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-09 16:45:25 +00:00
|
|
|
export const valueHasTuples = (key, value) => {
|
2019-12-24 14:00:32 +00:00
|
|
|
const valueIsArrayOfNonObjects = Array.isArray(value) && value.length > 0 && value.every(el => typeof el !== 'object')
|
2019-11-08 12:39:22 +00:00
|
|
|
return key === ':meta' ||
|
|
|
|
key === ':types' ||
|
2019-12-24 14:00:32 +00:00
|
|
|
key === ':backends' ||
|
2019-11-08 12:39:22 +00:00
|
|
|
key === ':compiled_template_engines' ||
|
|
|
|
key === ':compiled_format_encoders' ||
|
2019-08-09 16:45:25 +00:00
|
|
|
typeof value === 'string' ||
|
|
|
|
typeof value === 'number' ||
|
|
|
|
typeof value === 'boolean' ||
|
2019-11-08 12:39:22 +00:00
|
|
|
value === null ||
|
2019-08-09 16:45:25 +00:00
|
|
|
valueIsArrayOfNonObjects
|
|
|
|
}
|
|
|
|
|
2019-12-19 16:21:44 +00:00
|
|
|
export const wrapUpdatedSettings = (group, settings, currentState) => {
|
2019-12-03 16:19:46 +00:00
|
|
|
return Object.keys(settings).map((key) => {
|
2019-12-24 14:00:32 +00:00
|
|
|
return settings[key]._value
|
|
|
|
? { group, key, value: getValueWithoutKey(key, settings[key]._value) }
|
|
|
|
: { group, key, value: wrapValues(settings[key], currentState[group][key]) }
|
2019-12-03 16:19:46 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-12-19 16:21:44 +00:00
|
|
|
const wrapValues = (settings, currentState) => {
|
2019-12-03 16:19:46 +00:00
|
|
|
return Object.keys(settings).map(setting => {
|
2020-01-03 10:00:20 +00:00
|
|
|
const [type, value] = settings[setting]
|
2020-03-04 16:46:31 +00:00
|
|
|
if (
|
|
|
|
type === 'keyword' ||
|
|
|
|
type.includes('keyword') ||
|
|
|
|
type.includes('tuple') && type.includes('list') ||
|
|
|
|
setting === ':replace'
|
|
|
|
) {
|
2019-12-22 00:46:06 +00:00
|
|
|
return { 'tuple': [setting, wrapValues(value, currentState)] }
|
2019-12-18 19:56:18 +00:00
|
|
|
} else if (type === 'atom' && value.length > 0) {
|
2019-12-04 14:17:05 +00:00
|
|
|
return { 'tuple': [setting, `:${value}`] }
|
2020-01-03 06:31:07 +00:00
|
|
|
} else if (type.includes('tuple') && (type.includes('string') || type.includes('atom'))) {
|
2020-01-05 05:30:16 +00:00
|
|
|
return typeof value === 'string'
|
|
|
|
? { 'tuple': [setting, value] }
|
|
|
|
: { 'tuple': [setting, { 'tuple': value }] }
|
2020-03-04 16:46:31 +00:00
|
|
|
} else if (type === 'reversed_tuple') {
|
|
|
|
return { 'tuple': [value, setting] }
|
2019-12-06 08:30:17 +00:00
|
|
|
} else if (type === 'map') {
|
2019-12-19 16:21:44 +00:00
|
|
|
const mapValue = Object.keys(value).reduce((acc, key) => {
|
2019-12-20 20:17:39 +00:00
|
|
|
acc[key] = setting === ':match_actor' ? value[key] : value[key][1]
|
2019-12-06 08:30:17 +00:00
|
|
|
return acc
|
|
|
|
}, {})
|
2019-12-20 20:17:39 +00:00
|
|
|
const mapCurrentState = setting === ':match_actor'
|
|
|
|
? currentState[setting].reduce((acc, element) => {
|
|
|
|
return { ...acc, ...{ [Object.keys(element)[0]]: Object.values(element)[0].value }}
|
|
|
|
}, {})
|
|
|
|
: currentState[setting]
|
|
|
|
return { 'tuple': [setting, { ...mapCurrentState, ...mapValue }] }
|
2019-12-06 06:50:23 +00:00
|
|
|
} else if (setting === ':ip') {
|
|
|
|
const ip = value.split('.').map(s => parseInt(s, 10))
|
|
|
|
return { 'tuple': [setting, { 'tuple': ip }] }
|
2020-01-03 10:00:20 +00:00
|
|
|
} else if (setting === ':args') {
|
|
|
|
const index = value.findIndex(el => el === 'implode')
|
|
|
|
const updatedArray = value.slice()
|
|
|
|
if (index !== -1) {
|
|
|
|
updatedArray[index] = { 'tuple': ['implode', '1'] }
|
|
|
|
}
|
|
|
|
return { 'tuple': [setting, updatedArray] }
|
2019-12-03 16:19:46 +00:00
|
|
|
} else {
|
|
|
|
return { 'tuple': [setting, value] }
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|