📜 ⬆️ ⬇️

Own VPN client on JavaScript. 10 part - Combining all components

PS Each part is a part, by itself it does not make sense to get the necessary context and not to experience cognitive dissonance from the lack of so necessary blocks of text, start reading from part 1

Once all parts of the application have been developed, they can be combined into one large application. image
Once again, I will review the API of all components.

OpenVPN is the main component responsible for setting up and using a VPN connection.

API OpenVPN
const OpenVPN = require('./../../app/components/OpenVPN') const ovpn = new OpenVPN() //    ovpn.on(({ id, message }, other) => { if (id == 10 || id == 11) { //  ovpn.installer() } console.log(`id: ${id} | message: ${message}`) }) //  ovpn.connect(`${__dirname}/config.ovpn`, { reconnect: true }) setTimeout(() => { //  ovpn.disconnect() }, 30000) 


Configs - Component responsible for storing and loading OpenVPN 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 , NumVpnSessions: '-' // empty , Score: '-' // empty , Speed: 13311 // bit , Uptime: 3600000 // ms , TotalUsers: '-' // empty , TotalTraffic: '-' // empty }) console.log(` : ${search.length}`) }, () => { console.log(`  `) }) 


Electron components.

Vpn - The main control element of the application.

API Vpn
 const { app } = require('electron') , VPN = require('./../../app/components/vpn') app.on('ready', async() => { const Vpn = new VPN() //          await Vpn.ready() //   Vpn.show() //  Tray Vpn.showTray() //   Vpn.onConnect(() => { console.log('Connect') //     Vpn.setStatus('waiting', 'yellow') setTimeout(() => { console.log('Connected!') //     Vpn.setStatus('resolve', 'blue') }, 4000) }) //   Vpn.onDisconnect(() => { console.log('Disconnect') //     Vpn.setStatus('reject', 'red') }) Vpn.onContext(() => { console.log('Context menu') }) //     5    //     Vpn.stopReconnect() //   Vpn.reconnect(next => { console.log('Reconnect') next() }, 5000) //     //stopReconnect() //    Tray Vpn.onTrayClick(() => { //     if (!Vpn.status) { Vpn.connect() } else { Vpn.disconnect() } }) //       Tray Vpn.onTrayRightClick(() => { if (Vpn.isVisible()) { Vpn.hide() } else { Vpn.show() } }) }) 


Notify - Notification view element.

API Notify
 const { app } = require('electron') , VPN = require('./../../app/components/vpn') , NOTIFY = require('./../../app/components/notify') app.on('ready', async() => { const Vpn = new VPN() , Notify = new NOTIFY(Vpn.root) //          await Promise.all([ Notify.ready(), Vpn.ready() ]) Vpn.show() Vpn.showTray() const SASI_FSB = [{ title: '', return: ',  !' }, { title: '', return: false }] setTimeout(() => { //   "alert" Notify.alert('  !', 3000, () => { //   "confirm" Notify.confirm('    VPN', CONFIRN_FSB, data => { console.log(data) if (data == false) { //    Notify.setType('static') //   "confirm" Notify.confirm('   ?', SASI_FSB, data => { if (data != false) { app.quit() } }) } else { Vpn.setStatus('resolve', 'blue') } }) }) }, 2000) //    // Notify.setType('static') //   "alert" // Notify.alert('  !', 3000, () => {}) //   "confirm" //Notify.confirm('    VPN', SASI_FSB, console.log) 


Context - an element of navigation through the application.

API Context
 const { app } = require('electron') , VPN = require('./../../app/components/vpn') , CONTEXT = require('./../../app/components/context') app.on('ready', async() => { const Vpn = new VPN(), Context = new CONTEXT(Vpn.root) //          await Promise.all([ Context.ready(), Vpn.ready() ]) Vpn.show() Vpn.showTray() Vpn.onContext(() => Context.show()) //  Context.onCheckIP(() => { console.log(' IP') }) Context.onUpdate(() => { console.log(' ') }) Context.onSetting(() => { console.log('') }) Context.onCallback(() => { console.log(' ') }) Context.onHidden(() => { console.log('') }) Context.onExit(() => { console.log('') }) }) 


Setting - An application configuration item.

API Setting
 const { app } = require('electron') , SETTING = require('./../../app/components/setting') app.on('ready', async() => { const Setting = new SETTING() //          await Setting.ready() //   Setting.show() //   Setting.onSave(async () => { //   const vpn_setting = await Setting.get() console.log(vpn_setting) }) }) 


Callback - Feedback element.

API Callback
 const { app } = require('electron') , CALLBACK = require('./../../app/components/callback') app.on('ready', async() => { const Callback = new CALLBACK() await Callback.ready() //   Callback.show() }) 


It's time to see how really simple my approach to the development of multi-window applications on Electron is.

The main code, a small code with which the application development begins.

Code
 const { app, Menu } = require('electron') , ipify = require('ipify') , OPENVPN = require('./components/OpenVPN') , Configs = require('./components/configs') , NOTIFY = require('./components/notify') , CONTEXT = require('./components/context') , CALLBACK = require('./components/callback') , SETTING = require('./components/setting') , VPN = require('./components/vpn') app.on('ready', async() => { const Vpn = new VPN() , Notify = new NOTIFY(Vpn.root) , Context = new CONTEXT(Vpn.root) , Callback = new CALLBACK(Context.root) , Setting = new SETTING(Context.root) await Promise.all([ Notify.ready(), Context.ready(), Callback.ready(), Setting.ready(), Vpn.ready() ]) //        //         }) 


Base code clearly demonstrating how components interact with each other.

Code
 const { app, Menu } = require('electron') , ipify = require('ipify') , OPENVPN = require('./components/OpenVPN') , Configs = require('./components/configs') , NOTIFY = require('./components/notify') , CONTEXT = require('./components/context') , CALLBACK = require('./components/callback') , SETTING = require('./components/setting') , VPN = require('./components/vpn') //  const CONFIRM_BUTTON_CATEGORY = [{ title: '', return: true }, { title: '', return: false }], CONFIRM_BUTTON_CONNECT = [{ title: '.', return: true }, { title: '. .', return: false }] app.on('ready', async() => { const Vpn = new VPN() , Notify = new NOTIFY(Vpn.root) , Context = new CONTEXT(Vpn.root) , Callback = new CALLBACK(Context.root) , Setting = new SETTING(Context.root) await Promise.all([ Notify.ready(), Context.ready(), Callback.ready(), Setting.ready(), Vpn.ready() ]) //o//    //o// Context.onUpdate(() => ( Notify.alert(` ...`, 2000, () => Configs.load().then( length => Notify.alert(`: ${length} `), error => Notify.confirm(`VPN   .    ?`, CONFIRM_BUTTON_CATEGORY, reload => { reload && Context.update() }) ) ) )) Context.onCheckIP(() => Notify.alert(` IP ...`, 2000, () => ipify().then(ip => Notify.alert(`IP: ${ip}`)) ) ) Context.onSetting(() => Setting.show()) Context.onCallback(() => Callback.show()) Context.onHidden(() => { Vpn.hide() Context.hide() Callback.hide() Setting.hide() Notify.setType('static') }) Context.onExit(() => app.quit()) Vpn.onContext(() => Context.show()) Vpn.showTray() Vpn.show() }) 


The complete code for the main index.js file.

Code
 const { app, Menu } = require('electron') , ipify = require('ipify') , OPENVPN = require('./components/OpenVPN') , Configs = require('./components/configs') , NOTIFY = require('./components/notify') , CONTEXT = require('./components/context') , CALLBACK = require('./components/callback') , SETTING = require('./components/setting') , VPN = require('./components/vpn') const CONFIRM_BUTTON_CATEGORY = [{ title: '', return: true }, { title: '', return: false }], CONFIRM_BUTTON_CONNECT = [{ title: '.', return: true }, { title: '. .', return: false }] app.on('ready', async() => { const Vpn = new VPN() , Notify = new NOTIFY(Vpn.root) , Context = new CONTEXT(Vpn.root) , Callback = new CALLBACK(Context.root) , Setting = new SETTING(Context.root) await Promise.all([ Notify.ready(), Context.ready(), Callback.ready(), Setting.ready(), Vpn.ready() ]) //o//    //// Context.onUpdate(() => ( Notify.alert(` ...`, 2000, () => Configs.load().then( length => Notify.alert(`: ${length} `), error => Notify.confirm(`VPN   .    ?`, CONFIRM_BUTTON_CATEGORY, reload => { reload && Context.update() }) ) ) )) Context.onCheckIP(() => Notify.alert(` IP ...`, 2000, () => ipify().then(ip => Notify.alert(`IP: ${ip}`)) ) ) Context.onSetting(() => Setting.show()) Context.onCallback(() => Callback.show()) Context.onHidden(() => { Vpn.hide() Context.hide() Callback.hide() Setting.hide() Notify.setType('static') }) Context.onExit(() => app.quit()) Vpn.onContext(() => Context.show()) Vpn.showTray() Vpn.onTrayClick(() => { if (Vpn.status) { Vpn.disconnect() } else { Vpn.disconnect() Vpn.connect() } }) Vpn.onTrayRightClick(() => { if (!Vpn.isVisible()) { Vpn.show() Notify.setType('fly') return } Vpn.hide() Context.hide() Callback.hide() Setting.hide() Notify.setType('static') }) Setting.onSave(async() => { const vpn_setting = await Setting.get() const configs = Configs.get(vpn_setting) if (configs.length != 0) { Notify.alert(`: ${configs.length} `, 6000) } else { Notify.confirm('    .      ?', CONFIRM_BUTTON_CONNECT, config => { if (config) { Setting.show() } else { Context.update() } }) } }) const { AutoUpdate, Permutation, StartHidden } = await Setting.get() if (Permutation) { Vpn.center() } if (StartHidden) { Vpn.hide() Notify.setType('static') } else { Vpn.show() } if (AutoUpdate) { Context.update() } Configs.get({}).length == 0 && Context.update() //o//           //// const OpenVPN = new OPENVPN() OpenVPN.on(({ id, message }, { config_information, reconnect }) => { if (id == 1) { Vpn.setStatus('waiting', 'yellow') } if (id == 2) { Vpn.stopReconnect() Vpn.setStatus('resolve', 'blue') Notify.alert('VPN ', 2000, () => Notify.alert(config_information, 30000) ) } if (id == 3) { Vpn.setStatus('waiting', 'yellow') Notify.alert('  VPN', 4000) if (reconnect) { Vpn.reconnect(next => { Notify.alert('   ,   VPN ', 4000, () => { next() }) }) } } if (id == 4) { Vpn.setStatus('reject', 'red') reconnect && Vpn.reconnect(next => next()) } if (id == 5) { if (!Vpn.isReconnect) { Vpn.stopReconnect() Vpn.setStatus('reject', 'red') } } if (id == 6) { reconnect && Vpn.reconnect(next => { Notify.alert('   ,   VPN ', 4000, () => { next() }) }) } if (id == 7) { Notify.alert('TCP-  VPN  ', 4000, () => { Vpn.setStatus('reject', 'red') Vpn.disconnect() }) reconnect && Vpn.reconnect(next => next()) } if (id == 8) { reconnect && Vpn.reconnect(next => { Notify.alert('   ,   VPN ', 4000, () => { next() }) }) } if (id == 9) { Vpn.stopReconnect() Vpn.setStatus('waiting', 'orange') Notify.alert(' OpenVPN') } if (id == 10 || id == 11) { Notify.confirm('    OpenVPN,    ?', CONFIRM_BUTTON_CATEGORY, install => { if (install) { OpenVPN.installer() } else { Notify.confirm('  JS.VPN-Client ?', CONFIRM_BUTTON_CATEGORY, exit => exit && app.quit() ) } }) } if (id == 12) { Vpn.setStatus('reject', 'red') Notify.confirm('   TAP ,    ?', CONFIRM_BUTTON_CATEGORY, install => { if (install) { OpenVPN.installer() } else { Notify.confirm('  JS.VPN-Client ?', CONFIRM_BUTTON_CATEGORY, exit => exit && app.quit() ) } }) } if (id == 13) { Vpn.setStatus('reject', 'red') Notify.alert('  !') } if (id == 14) { Vpn.setStatus('reject', 'red') Notify.alert(' ') reconnect && Vpn.reconnect(next => next()) } console.log(`${id} | ${message}`) }) Vpn.onConnect(async() => { const vpn_setting = await Setting.get() const configs = Configs.get(vpn_setting), random_config = parseInt(Math.random() * (configs.length - 1)), conf = configs[random_config] if (!conf) { return Notify.confirm('    .      ?', CONFIRM_BUTTON_CONNECT, config => { if (config) { Setting.show() } else { Context.update() } }) } const config_information = `IP: ${conf.IP}<br>` + `: ${conf.CountryLong.length > 9 ? `${conf.CountryLong.slice(0, 9)}..` : conf.CountryLong}<br>` + `${conf.Ping != '-' && `Ping: ${conf.Ping}ms <br> `}` + `${(conf.Speed || conf.Speed != 0) ? `: ${(conf.Speed / 1024 / 1024).toFixed(2)}Mb <br> ` : ''}` + `${(conf.Uptime || conf.Speed != 0) ? `Uptime: ${parseUptime(conf.Uptime)} <br> ` : ''}` + `: ${conf.NumVpnSessions}` OpenVPN.connect(conf.path, { reconnect: vpn_setting.AutoReconnect, config_information }) }) Vpn.onDisconnect(vpn_setting => { OpenVPN.disconnect() }) }) ////     //// const declOfNum = (number, titles) => { cases = [2, 0, 1, 1, 1, 2]; return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]]; } const parseUptime = (l) => { const day = parseInt(l / 60000 / 60 / 24) const hours = parseInt(l / 60000 / 60) const min = parseInt(l / 60000) if (day) { return `${day} ${declOfNum(day, ['', '', ''])}` } if (hours) { return `${hours} ${declOfNum(hours, ['', '', ''])}` } if (min) { return `${min} ${declOfNum(min, ['', '', ''])}` } return ' ' } 


It remains only to run.

 electron . 

Part 11 - Building an Application for Windows


VPN   JavaScript by JSus

Source: https://habr.com/ru/post/429444/


All Articles