File size: 10,335 Bytes
af5a34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

import YAML from 'yaml'
import chokidar from 'chokidar'
import fs from 'node:fs'
import YamlReader from './YamlReader.js'
import cfg from '../../../lib/config/config.js'
import _ from 'lodash'
import { modifyWebSocket } from './WebSocket.js'
import { cfgSchema } from '../config/system/cfg_system.js'

const Path = process.cwd()
const Plugin_Name = 'ws-plugin'
const Plugin_Path = `${Path}/plugins/${Plugin_Name}`
class Config {
  constructor() {
    this.config = {}
    this.oldConfig = {}
    /** 监听文件 */
    this.watcher = { config: {}, defSet: {} }

    this.initCfg()
  }

  /** 初始化配置 */
  initCfg() {
    let path = `${Plugin_Path}/config/config/`
    if (!fs.existsSync(path)) fs.mkdirSync(path)
    let pathDef = `${Plugin_Path}/config/default_config/`
    const files = fs.readdirSync(pathDef).filter(file => file.endsWith('.yaml'))
    for (let file of files) {
      if (!fs.existsSync(`${path}${file}`)) {
        fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
      }
      this.watch(`${path}${file}`, file.replace('.yaml', ''), 'config')
    }
  }

  /** 主人QQ */
  get masterQQ() {
    return cfg.masterQQ
  }

  /** Bot账号:[主人帐号] */
  get master() {
    return cfg.master
  }

  /** 云崽黑名单群 */
  get blackGroup() {
    return cfg.getOther().blackGroup
  }

  /** 云崽白名单群 */
  get whiteGroup() {
    return cfg.getOther().whiteGroup
  }

  /** 心跳 */
  get heartbeatInterval() {
    return this.getDefOrConfig('ws-config').heartbeatInterval
  }

  /** 数据上报类型 */
  get messagePostFormat() {
    return this.getDefOrConfig('ws-config').messagePostFormat
  }

  /** 连接列表 */
  get servers() {
    return this.getDefOrConfig('ws-config').servers
  }

  get noMsgStart() {
    return this.getDefOrConfig('msg-config').noMsgStart
  }

  get noMsgInclude() {
    return this.getDefOrConfig('msg-config').noMsgInclude
  }

  get howToMaster() {
    return this.getDefOrConfig('msg-config').howToMaster
  }

  /**掉线时否通知主人 */
  get disconnectToMaster() {
    return this.getDefOrConfig('msg-config').disconnectToMaster
  }

  /**重连成功时是否通知主人 */
  get reconnectToMaster() {
    return this.getDefOrConfig('msg-config').reconnectToMaster
  }

  /**首次连接成功时是否通知主人 */
  get firstconnectToMaster() {
    return this.getDefOrConfig('msg-config').firstconnectToMaster
  }

  /**消息存储时间 */
  get msgStoreTime() {
    return this.getDefOrConfig('msg-config').msgStoreTime
  }

  /**禁用群聊列表 */
  get noGroup() {
    return this.getDefOrConfig('msg-config').noGroup
  }

  /** 白名单群聊 */
  get yesGroup() {
    return this.getDefOrConfig('msg-config').yesGroup
  }

  /** 禁言拦截 */
  get muteStop() {
    return this.getDefOrConfig('msg-config').muteStop
  }

  /** red 发送伪造转发消息方式 */
  get redSendForwardMsgType(){
    return this.getDefOrConfig('msg-config').redSendForwardMsgType
  }

  /**群管理员变动是否上报 */
  get groupAdmin() {
    return this.getDefOrConfig('notice-config').groupAdmin
  }

  /**群成员减少是否上报 */
  get groupDecrease() {
    return this.getDefOrConfig('notice-config').groupDecrease
  }

  /**群成员增加是否上报 */
  get groupIncrease() {
    return this.getDefOrConfig('notice-config').groupIncrease
  }

  /**群禁言是否上报 */
  get groupBan() {
    return this.getDefOrConfig('notice-config').groupBan
  }

  /**好友添加是否上报 */
  get friendIncrease() {
    return this.getDefOrConfig('notice-config').friendIncrease
  }

  /**群消息撤回是否上报 */
  get groupRecall() {
    return this.getDefOrConfig('notice-config').groupRecall
  }

  /**好友消息撤回是否上报 */
  get friendRecall() {
    return this.getDefOrConfig('notice-config').friendRecall
  }

  /**群内戳一戳是否上报 */
  get groupPoke() {
    return this.getDefOrConfig('notice-config').groupPoke
  }

  /** 好友申请是否上报 */
  get friendAdd() {
    return this.getDefOrConfig('request-config').friendAdd
  }

  /** 群聊邀请是否上报 (邀请机器人入群) */
  get groupInvite() {
    return this.getDefOrConfig('request-config').groupInvite
  }

  /** 群聊申请是否上报 (申请加入群聊) */
  get groupAdd() {
    return this.getDefOrConfig('request-config').groupAdd
  }

  /** 默认配置和用户配置 */
  getDefOrConfig(name) {
    let def = this.getdefSet(name)
    let config = this.getConfig(name)
    return { ...def, ...config }
  }

  /** 默认配置 */
  getdefSet(name) {
    return this.getYaml('default_config', name)
  }

  /** 用户配置 */
  getConfig(name) {
    return this.getYaml('config', name)
  }

  /**
   * 获取配置yaml
   * @param type 默认跑配置-defSet,用户配置-config
   * @param name 名称
   */
  getYaml(type, name) {
    let file = `${Plugin_Path}/config/${type}/${name}.yaml`
    let key = `${type}.${name}`

    if (this.config[key]) return this.config[key]

    this.config[key] = YAML.parse(
      fs.readFileSync(file, 'utf8')
    )

    this.watch(file, name, type)

    return this.config[key]
  }

  /** 监听配置文件 */
  watch(file, name, type = 'default_config') {
    let key = `${type}.${name}`
    if (!this.oldConfig[key]) this.oldConfig[key] = _.cloneDeep(this.config[key])
    if (this.watcher[key]) return

    const watcher = chokidar.watch(file)
    watcher.on('change', path => {
      delete this.config[key]
      if (typeof Bot == 'undefined') return
      logger.mark(`[ws-plugin][修改配置文件][${type}][${name}]`)

      if (name == 'ws-config') {
        const oldConfig = this.oldConfig[key]
        delete this.oldConfig[key]
        const newConfig = this.getYaml(type, name)
        const object = this.findDifference(oldConfig, newConfig)
        // console.log(object);
        for (const key in object) {
          if (Object.hasOwnProperty.call(object, key)) {
            const value = object[key];
            const arr = key.split('.')
            if (arr[0] !== 'servers') continue
            let data = newConfig.servers[arr[1]]
            if (typeof data === 'undefined') data = oldConfig.servers[arr[1]]
            const target = {
              type: null,
              data
            }
            if (typeof value['newValue'] === 'object' && typeof value['oldValue'] === 'undefined') {
              target.type = 'add'
            }
            else if (typeof value['newValue'] === 'undefined' && typeof value['oldValue'] === 'object') {
              target.type = 'del'
            }
            else if (value['newValue'] === true && (value['oldValue'] === false || typeof value['oldValue'] === 'undefined')) {
              target.type = 'close'
            }
            else if (value['newValue'] === false && (value['oldValue'] === true || typeof value['oldValue'] === 'undefined')) {
              target.type = 'open'
            }
            modifyWebSocket(target)
          }
        }

      }
    })

    this.watcher[key] = watcher
  }

  getCfgSchemaMap() {
    let ret = {}
    _.forEach(cfgSchema, (cfgGroup) => {
      _.forEach(cfgGroup.cfg, (cfgItem, cfgKey) => {
        ret[cfgItem.key] = cfgItem
        cfgItem.cfgKey = cfgKey
      })
    })
    return ret
  }

  getCfgSchema() {
    return cfgSchema
  }

  getCfg() {
    let wsconfig = this.getDefOrConfig('ws-config')
    let msgconfig = this.getDefOrConfig('msg-config')
    let noticeconfig = this.getDefOrConfig('notice-config')
    let requestconfig = this.getDefOrConfig('request-config')
    return {
      ...wsconfig,
      ...msgconfig,
      ...noticeconfig,
      ...requestconfig
    }
  }

  /**
   * @description: 修改设置
   * @param {String} name 文件名
   * @param {String} key 修改的key值
   * @param {String|Number} value 修改的value值
   * @param {'config'|'default_config'} type 配置文件或默认
   */
  modify(name, key, value, type = 'config') {
    let path = `${Plugin_Path}/config/${type}/${name}.yaml`
    new YamlReader(path).set(key, value)
    this.oldConfig[key] = _.cloneDeep(this.config[key])
    delete this.config[`${type}.${name}`]
  }

  /**
   * @description: 修改配置数组
   * @param {String} name 文件名
   * @param {String|Number} key key值
   * @param {String|Number} value value
   * @param {'add'|'del'} category 类别 add or del
   * @param {'config'|'default_config'} type 配置文件或默认
   */
  modifyarr(name, key, value, category = 'add', type = 'config') {
    let path = `${Plugin_Path}/config/${type}/${name}.yaml`
    let yaml = new YamlReader(path)
    if (category == 'add') {
      yaml.addIn(key, value)
    } else {
      let index = yaml.jsonData[key].indexOf(value)
      yaml.delete(`${key}.${index}`)
    }
  }

  setArr(name, key, item, value, type = 'config') {
    let path = `${Plugin_Path}/config/${type}/${name}.yaml`
    let yaml = new YamlReader(path)
    let arr = yaml.get(key).slice();
    arr[item] = value
    yaml.set(key, arr)
  }

  delServersArr(value, name = 'ws-config', type = 'config') {
    let path = `${Plugin_Path}/config/${type}/${name}.yaml`
    let yaml = new YamlReader(path)
    let key = 'servers'
    // let index = yaml.jsonData[key].indexOf(value)
    let index = yaml.jsonData[key].findIndex(item => item.name === value);
    yaml.delete(`${key}.${index}`)
  }

  /**
   * @description 对比两个对象不同的值
   * @param {*} oldObj 
   * @param {*} newObj 
   * @param {*} parentKey 
   * @returns 
   */
  findDifference(obj1, obj2, parentKey = '') {
    const result = {};
    for (const key in obj1) {
      const fullKey = parentKey ? `${parentKey}.${key}` : key;
      if (_.isObject(obj1[key]) && _.isObject(obj2[key])) {
        const diff = this.findDifference(obj1[key], obj2[key], fullKey);
        if (!_.isEmpty(diff)) {
          Object.assign(result, diff);
        }
      } else if (!_.isEqual(obj1[key], obj2[key])) {
        result[fullKey] = { oldValue: obj1[key], newValue: obj2[key] };
      }
    }
    for (const key in obj2) {
      if (!obj1.hasOwnProperty(key)) {
        const fullKey = parentKey ? `${parentKey}.${key}` : key;
        result[fullKey] = { oldValue: undefined, newValue: obj2[key] };
      }
    }
    return result;
  }
}
export default new Config()