Skip to content

Commit

Permalink
Fix duplicate statistics when calling multiple times (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
leonovk authored Jul 29, 2024
1 parent 2c27665 commit 56c1c7a
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
--format documentation
--require spec_helper
--order rand
--format progress
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.6.6
v1.7.-1
2 changes: 1 addition & 1 deletion lib/utils/config_file_builder.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Utils
# class that from Jason's config creates a ready-made config for the end user
# class that from JSON config creates a ready-made config for the end user
class ConfigFileBuilder
def self.build(config)
new(config).build
Expand Down
19 changes: 15 additions & 4 deletions lib/wire_guard/config_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module WireGuard
# the class dumps the resulting configuration file
# and reboots the WireGuard server
# This class updates the config file of the server itself and not the clients.
# And it is needed mainly to reboot the server after adding new clients (or deleting them)
class ConfigUpdater
WG_CONF_PATH = "#{Settings.wg_path}/wg0.conf".freeze
WG_PORT = Settings.wg_port
Expand All @@ -13,7 +15,7 @@ class ConfigUpdater

def initialize
@json_config = JSON.parse(File.read(WireGuard::Server::WG_JSON_PATH))
Kernel.system('wg-quick down wg0') if File.exist?(WG_CONF_PATH)
@first_start = !File.exist?(WG_CONF_PATH)
end

def self.update
Expand All @@ -25,19 +27,28 @@ def update
new_config_build << base_config

json_config['configs'].except('last_id', 'last_address').each_value do |config|
# NOTE: We simply skip the config and do not add it to the initial configuration,
# if the 'enable == false'
next if config['enable'] == false

new_config_build << build_client(config)
end

dump_wireguard_config(new_config_build)

Kernel.system('wg-quick up wg0')
start_server
end

private

attr_reader :json_config
attr_reader :json_config, :first_start

def start_server
if first_start
Kernel.system('wg-quick up wg0')
else
Kernel.system('wg syncconf wg0 <(wg-quick strip wg0)')
end
end

def dump_wireguard_config(new_config_build)
File.write(WG_CONF_PATH, new_config_build.join("\n"))
Expand Down
57 changes: 6 additions & 51 deletions lib/wire_guard/server_stat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ServerStat

def initialize
@last_stat_data = initialize_last_stat_data
@new_stat_data = parse(StatGenerator.show)
@new_stat_data = StatParser.new.parse
@wg_stat = aggregate_data
dump_stat(@wg_stat)
end
Expand Down Expand Up @@ -48,67 +48,22 @@ def aggregate_data
last_stat_data
end

def increment_data(new_data, last_data)
def increment_data(new_data, _last_data)
{
last_online: new_data[:last_online],
traffic: increment_traffic(new_data[:traffic], last_data['traffic'])
traffic: increment_traffic(new_data[:traffic])
}
end

def increment_traffic(new_traffic, last_traffic)
def increment_traffic(new_traffic)
{
received: calculate_traffic(new_traffic[:received], last_traffic['received']),
sent: calculate_traffic(new_traffic[:sent], last_traffic['sent'])
received: new_traffic[:received],
sent: new_traffic[:sent]
}
end

def dump_stat(wg_stat)
File.write(WG_STAT_PATH, JSON.pretty_generate(wg_stat))
end

def parse(wg_stat)
return {} if wg_stat.nil? or wg_stat.empty?

parse_data(wg_stat.split("\n"))

@result
end

def parse_data(data)
@result = {}

data.each do |line|
peer_data = line.strip.split
parse_wg_line(peer_data)
end
end

def parse_wg_line(peer_data)
case peer_data.first
when 'peer:'
@result[peer_data.last] = {}
@last_peer = peer_data.last
when 'latest'
@result[last_peer][:last_online] = build_latest_data(peer_data)
when 'transfer:'
@result[last_peer][:traffic] = build_traffic_data(peer_data)
end
end

def build_latest_data(data)
data[-3..]&.join(' ')
end

def build_traffic_data(data)
{
received: data[-6..-5]&.join(' '),
sent: data[-3..-2]&.join(' ')
}
end

def calculate_traffic(new_t, old_t)
result = new_t.to_unit + old_t.to_unit
result.convert_to('GiB').round(2).to_s
end
end
end
2 changes: 2 additions & 0 deletions lib/wire_guard/stat_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module WireGuard
# wg show
# In fact, the class calls only one command
# and was created so that this command would be convenient to mock in tests.
class StatGenerator
def self.show
`wg show`
Expand Down
53 changes: 53 additions & 0 deletions lib/wire_guard/stat_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# frozen_string_literal: true

module WireGuard
# This class returns current data on WG server statistics
class StatParser
def initialize
@raw_data = StatGenerator.show
@result = {}
end

def parse
return {} if raw_data.nil? or raw_data.empty?

parse_data(raw_data.split("\n"))

result
end

private

attr_reader :raw_data, :result

def parse_data(data)
data.each do |line|
peer_data = line.strip.split
parse_wg_line(peer_data)
end
end

def parse_wg_line(peer_data)
case peer_data.first
when 'peer:'
result[peer_data.last] = {}
@last_peer = peer_data.last
when 'latest'
result[@last_peer][:last_online] = build_latest_data(peer_data)
when 'transfer:'
result[@last_peer][:traffic] = build_traffic_data(peer_data)
end
end

def build_latest_data(data)
data[-3..]&.join(' ')
end

def build_traffic_data(data)
{
received: data[-6..-5]&.join(' '),
sent: data[-3..-2]&.join(' ')
}
end
end
end
4 changes: 2 additions & 2 deletions spec/app/clients_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@
endpoint: '2.2.2.2:51820',
last_online: '13 seconds ago',
traffic: {
received: '0.12 GiB',
sent: '6.42 GiB'
received: '62.44 MiB',
sent: '3.21 GiB'
},
data: {}
}
Expand Down
28 changes: 14 additions & 14 deletions spec/lib/wire_guard/server_stat_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,22 @@
'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=' => {
last_online: '25 seconds ago',
traffic: {
received: '0.11 GiB',
sent: '2.7 GiB'
received: '56.28 MiB',
sent: '1.35 GiB'
}
},
'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=' => {
last_online: '30 seconds ago',
traffic: {
received: '0.39 GiB',
sent: '1.41 GiB'
received: '199.29 MiB',
sent: '722.39 MiB'
}
},
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '0.12 GiB',
sent: '6.42 GiB'
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
Expand Down Expand Up @@ -156,8 +156,8 @@
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '0.12 GiB',
sent: '6.42 GiB'
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
Expand Down Expand Up @@ -188,8 +188,8 @@
'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=' => {
last_online: '25 seconds ago',
traffic: {
received: '0.11 GiB',
sent: '2.7 GiB'
received: '56.28 MiB',
sent: '1.35 GiB'
}
},
'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=' => {
Expand All @@ -202,8 +202,8 @@
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '0.12 GiB',
sent: '6.42 GiB'
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
Expand Down Expand Up @@ -238,8 +238,8 @@
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '0.12 GiB',
sent: '6.42 GiB'
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
Expand Down
63 changes: 63 additions & 0 deletions spec/lib/wire_guard/stat_parser_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

RSpec.describe WireGuard::StatParser do
subject(:parse) { described_class.new.parse }

before do
allow(WireGuard::StatGenerator).to receive_messages(show: wg_show_stub)
end

context 'when all data is present' do
let(:wg_show_stub) { File.read('spec/fixtures/stat.txt') }
let(:expected_result) do
{
'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=' => {
last_online: '25 seconds ago',
traffic: {
received: '56.28 MiB',
sent: '1.35 GiB'
}
},
'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=' => {
last_online: '30 seconds ago',
traffic: {
received: '199.29 MiB',
sent: '722.39 MiB'
}
},
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
end

it 'returns the expected result' do
expect(parse).to eq(expected_result)
end
end

context 'when data is not available for all clients' do
let(:wg_show_stub) { File.read('spec/fixtures/stat_with_empty.txt') }
let(:expected_result) do
{
'LiXk4UOfnScgf4UnkcYNcz4wWeqTOW1UrHKRVhZ1OXg=' => {},
'hvIyIW2o8JROVKuY2yYFdUn0oA+43aLuT8KCy0YbORE=' => {},
'bPKBg66uC1J2hlkE31Of5wnkg+IjowVXgoLcjcLn0js=' => {
last_online: '13 seconds ago',
traffic: {
received: '62.44 MiB',
sent: '3.21 GiB'
}
}
}
end

it 'returns the expected result' do
expect(parse).to eq(expected_result)
end
end
end
3 changes: 0 additions & 3 deletions tasks/clear_stats.rake
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# frozen_string_literal: true

require 'fileutils'
require 'json'

desc 'clear stats'
task :clear_stats do
path = "#{Settings.wg_path}/wg0_stat.json"
Expand Down

0 comments on commit 56c1c7a

Please sign in to comment.