aboutsummaryrefslogtreecommitdiff
path: root/src/config.js
blob: 9ee6338c0c9dfa0926f2cf1aae17c6ab0815744a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const fs = require('fs')
const ini = require('ini')
const {isNumeric} = require('./util')

let workerConfig = {
    targets: {},
}
let masterConfig = {}

function readFile(file) {
    if (!fs.existsSync(file))
        throw new Error(`file ${file} not found`)

    return ini.parse(fs.readFileSync(file, 'utf-8'))
}

function processScheme(source, scheme) {
    const result = {}
    
    for (let key in scheme) {
        let opts = scheme[key]
        let ne = !(key in source) || !source[key]
        if (opts.required === true && ne)
            throw new Error(`'${key}' is not defined`)

        let value = source[key] ?? opts.default ?? null

        switch (opts.type) {
            case 'int':
                if (!isNumeric(value))
                    throw new Error(`'${key}' must be an integer`)
                value = parseInt(value, 10)
                break

            case 'float':
                if (!isNumeric(value))
                    throw new Error(`'${key}' must be a float`)
                value = parseFloat(value)
                break
        }

        result[key] = value
    }
    
    return result
}

function parseWorkerConfig(file) {
    const raw = readFile(file)

    const scheme = {
        host:     {required: true},
        port:     {required: true, type: 'int'},
        password: {},

        master_host: {},
        master_port: {type: 'int', default: 0},
        master_reconnect_timeout: {type: 'int', default: 10},

        log_file:          {},
        log_level_file:    {default: 'warn'},
        log_level_console: {default: 'warn'},

        mysql_host:        {required: true},
        mysql_port:        {required: true, type: 'int'},
        mysql_user:        {required: true},
        mysql_password:    {required: true},
        mysql_database:    {required: true},
        mysql_table:       {required: true, default: 'jobs'},
        mysql_fetch_limit: {default: 100, type: 'int'},

        launcher:          {required: true},
        max_output_buffer: {default: 1024*1024, type: 'int'},
    }
    Object.assign(workerConfig, processScheme(raw, scheme))

    // targets
    for (let target in raw) {
        if (target === 'null')
            throw new Error('word \'null\' is reserved, please don\'t use it as a target name')

        if (typeof raw[target] !== 'object')
            continue

        workerConfig.targets[target] = {slots: {}}
        for (let slotName in raw[target]) {
            let slotLimit = parseInt(raw[target][slotName], 10)
            if (slotLimit < 1)
                throw new Error(`${target}: slot ${slotName} has invalid limit`)
            workerConfig.targets[target].slots[slotName] = slotLimit
        }
    }
}

function parseMasterConfig(file) {
    const raw = readFile(file)

    const scheme = {
        host:     {required: true},
        port:     {required: true, type: 'int'},
        password: {},

        ping_interval:          {default: 30, type: 'int'},
        poke_throttle_interval: {default: 0.5, type: 'float'},

        log_file:          {},
        log_level_file:    {default: 'warn'},
        log_level_console: {default: 'warn'},
    }
    Object.assign(masterConfig, processScheme(raw, scheme))
}

module.exports = {
    parseWorkerConfig,
    parseMasterConfig,

    workerConfig,
    masterConfig
}