Configs — Компонент, отвечающий за хранение и загрузку OpenVPN конфигов.

Структура папок.

configs
¦ 
¦   configs.json // Хранит метаданные о конфигах
¦   get.js
¦   index.js
¦   load.js
¦   parse-configs.js
¦
L---base // В этой папке хранятся конфиги аки файлы типа ovpn
        empty.file // Пустой файл нужен для того чтобы при сборке пустая папка не удалялась


parse-configs.js — Функция для парсинга конфигов из API.

Пример

Думаю, приглядевшись, вы поймёте, что логика сортировки очевидна.

const body = 'Яблоки,Груши,Лук,3,4,6,8,9,6'

const configs = parseConfigs(body)

configs /* [{
 "Яблоки": 3,
 "Груши": 4,
 "Лук": 6
}, {
 "Яблоки": 8,
 "Груши": 9,
 "Лук": 6
}] */

Cодержимое файла parse-configs.js.

Код
module.exports = body =>
    body
    .replace(/[^#]+/, '')
    .replace(/#/, '')
    .replace(/\r\n/gi, ',') // Очистка от всякого мусора
    .split(',') // Преобразование строки в массив

    .reduce((ctx, elem, index) => {

        if (index > 14) {
            // Черная магия
            const key = ctx.name_tmp[ctx.config_name_index]
            ctx.config_tmp[key] = elem
            ctx.config_name_index++
            if (ctx.config_name_index > 14) {
                ctx.configs.push(ctx.config_tmp)
                ctx.config_tmp = {}
                ctx.config_name_index = 0
            }
        } else {
            // Первые 14 позиций это информация о сервере например: ping, страна, etc
            ctx.name_tmp.push(elem)
        }
    
        return ctx
    }, {
        name_tmp: [],
        config_name_index: 0,
        config_tmp: {},
        configs: []
    }).configs


load.js — Функция для обращения к API и создания файлов конфигов.

Cодержимое файла load.js.

Код
const request       = require('request')
    , fs            = require('fs')
    , Base64        = require(`js-base64`).Base64
    , parseConfigs  = require('./parse-configs')

module.exports = () => 
  new Promise((resolve, reject) => {
    request(`http://130.158.6.57/api/iphone/`, (err, res, body) => {
      
      if (err || res.statusCode != 200) {
        return reject()
      }

      const configs = parseConfigs(body).map(config => {
         // Сам конфиг передается закодированным в base64, его нужно раскодировать  
        const decode_config = Base64.decode(config.OpenVPN_ConfigData_Base64)
                                    .replace(/dev tun/g, `dev tap`)
            , path = `${__dirname}/base/${config.HostName}.ovpn`
        fs.writeFileSync(path, decode_config)
        delete config.OpenVPN_ConfigData_Base64
        config.path = path
        return config
      })

      fs.writeFileSync(`${__dirname}/configs.json`, JSON.stringify(configs))
      // Возвращаем общее количество загруженных конфигов
      resolve(configs.length)
    })
  })


get.js — Функция для поиска среди загруженных конфигов.

Cодержимое файла get.js.

Код
const fs      = require('fs')
    , Base64  = require(`js-base64`).Base64

module.exports = ({
    CountryLong = '-'
  , Ping = '-'
  , NumVpnSessions = '-'
  , Score = '-'
  , Speed = '-'
  , Uptime = '-'
  , TotalUsers = '-'
  , TotalTraffic = '-'
}) => {
    try {
        // Загружаем метаданные
        const configs = fs.readFileSync(`${__dirname}/configs.json`, {
            encoding: 'utf8'
        }) 

        // Тут произошел поиск, этот код не такой сложный каким 
        // может показаться на первый взгляд, тут просто 
        // конфиги проходят через множество условий
        return JSON.parse(configs)
            .filter(conf =>
                (conf.CountryLong == CountryLong || CountryLong == '-') &&
                (parseInt(conf.Ping) < parseInt(Ping) || Ping == '-') &&
                (parseInt(conf.NumVpnSessions) > parseInt(NumVpnSessions) || NumVpnSessions == '-') &&
                (parseInt(conf.Score) > parseInt(Score) || Score == '-') &&
                (parseInt(conf.Speed) > parseInt(Speed) || Speed == '-') &&
                (parseInt(conf.Uptime) > parseInt(Uptime) || Uptime == '-') &&
                (parseInt(conf.TotalUsers) > parseInt(TotalUsers) || TotalUsers == '-') &&
                (parseInt(conf.TotalTraffic) > parseInt(TotalTraffic) || TotalTraffic == '-')
            )
    } catch (e) {
        return []
    }
}


index.js — Объект с методами get и load.

Cодержимое файла index.js.

Код
module.exports = {
    load: require('./load'),
    get: require('./get')
}



Application
Использование в приложении: /app/Configs.

API

Интерфейс компонента Configs.

const Configs = require('./../../app/components/configs')

Configs.load().then(length => {
    console.log(`Загружено конфигов: ${length}`)
    
    const search = Configs.get({
        CountryLong: 'Japan'
      , Ping: 22 // 1-22 ms
      , NumVpnSessions: '-' // empty
      , Score: '-' // empty
      , Speed: 13311 // bit
      , Uptime: 3600000 // ms
      , TotalUsers: '-' // empty
      , TotalTraffic: '-' // empty
    })

    console.log(`Найдено конфигов: ${search.length}`)
}, () => {
    console.log(`Ошибка загрузки конфигов`)
})

Test
Версия для тестирования: /app_test/Configs.

image

Объект поиска конфигов.
Ключ Тип Описание
CountryLong String Страна VPN сервера
Ping Number Время доставления информации (в миллисекундах)
NumVpnSessions Number Активных сессий
Score Number Качество соединения
Speed Number Скорость соединения (в байтах)
Uptime Number Время бесперебойной работы сервера (в миллисекундах)
TotalUsers Number Всего подключений за время работы
TotalTraffic Number Общий трафик на сервере за время работы (в байтах)

5 часть — Vpn компонент


Собственный VPN клиент на JavaScript by JSus

Комментарии (1)


  1. ThisMan
    27.11.2018 12:02
    +3

    Складывается ощущение, что вам не стоило разбивать ваш рассказ на маленькие статьи. Лучше было бы все объединить в одну, пусть она была бы больше средней, но так легче искать какую-то определенную часть + полная картинка будет складываться лучше