Skip to content

Commit

Permalink
Fix some bugs and problems in gossip (#3527)
Browse files Browse the repository at this point in the history
* Allow configuration of debugOutput to be performed

* don't send to own IP or update own data

* Use same socket to send and receive. Avoid problems in many opened and closed sockets to send

* Add callback for REMOVEed hosts

* Send broascast messages if seedList is empty

* Adapt yeelink to new luacheck rules

* Fix building of luac.cross for win to win2019 and VS 2019
  • Loading branch information
HHHartmann authored Jul 10, 2022
1 parent 27dbe11 commit 193fe35
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:

build_luac_cross_win:

runs-on: windows-latest
runs-on: windows-2019

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ uz_zip

# ignore VS Code files
.vscode/**
# ignore VS files
.vs/**

# ignore IDEA files
.idea
Expand Down
2 changes: 1 addition & 1 deletion docs/lua-modules/gossip.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ gossip.setConfig(config)

Sets the configuration for gossip. The available options are:

`seedList` : the list of seeds gossip will start with; this will be updated as new nodes are discovered. Note that it's enough for all nodes to start with the same IP in the seedList, as once they have one seed in common, the data will propagate
`seedList` : the list of seeds gossip will start with; this will be updated as new nodes are discovered. Note that it's enough for all nodes to start with the same IP in the seedList, as once they have one seed in common, the data will propagate. If the seedList is empty a broadcast is sent, so this can be used for automatic discovery of nodes.

`roundInterval`: interval in milliseconds at which gossip will pick a random node from the seed list and send a `SYN` request

Expand Down
53 changes: 34 additions & 19 deletions lua_modules/gossip/gossip.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@ end

utils.debug = function(message)
if gossip.config.debug then
if gossip.config.debugOutput then
gossip.config.debugOutput(message);
else
print(message);
end
gossip.config.debugOutput(message);
end
end

Expand Down Expand Up @@ -105,15 +101,23 @@ state.start = function()
return;
end

-- sending to own IP makes no sense
for index, value in ipairs(gossip.config.seedList) do
if value == gossip.ip then
table.remove(gossip.config.seedList, index)
utils.debug('removing own ip from seed list')
end
end

gossip.networkState[gossip.ip] = {};
local localState = gossip.networkState[gossip.ip];
localState.revision = state.setRev();
localState.heartbeat = tmr.time();
localState.state = constants.nodeState.UP;

gossip.inboundSocket = net.createUDPSocket();
gossip.inboundSocket:listen(gossip.config.comPort);
gossip.inboundSocket:on('receive', network.receiveData);
gossip.socket = net.createUDPSocket();
gossip.socket:listen(gossip.config.comPort);
gossip.socket:on('receive', network.receiveData);

gossip.started = true;

Expand All @@ -128,27 +132,38 @@ end
state.tickNodeState = function(ip)
if gossip.networkState[ip] then
local nodeState = gossip.networkState[ip].state;
local oldNodeState = nodeState;
if nodeState < constants.nodeState.REMOVE then
nodeState = nodeState + constants.nodeState.TICK;
gossip.networkState[ip].state = nodeState;
end
if oldNodeState == constants.nodeState.DOWN then
if gossip.updateCallback then gossip.updateCallback(gossip.networkState[ip]); end
end
end
end

-- Network
network.broadcastIp = "255.255.255.255"

network.pushGossip = function(data, ip)
if not gossip.started then
utils.debug('Gossip not started.');
return;
end
gossip.networkState[gossip.ip].data = data;
network.sendSyn(nil, ip);
end

network.updateNetworkState = function(updateData)
if gossip.updateCallback then gossip.updateCallback(updateData); end
for ip, data in pairs(updateData) do
if not utils.contains(gossip.config.seedList, ip) then
if not utils.contains(gossip.config.seedList, ip) and ip ~= network.broadcastIp and ip ~= gossip.ip then
table.insert(gossip.config.seedList, ip);
end
gossip.networkState[ip] = data;
if ip ~= gossip.ip then
gossip.networkState[ip] = data;
end
end
end

Expand All @@ -170,17 +185,16 @@ network.pickRandomNode = function()
return gossip.config.seedList[randomListPick];
end
utils.debug(
'Seedlist is empty. Please provide one or wait for node to be contacted.');
return nil;
'Seedlist is empty. Using broadcast IP '..network.broadcastIp..' to discover.');
return network.broadcastIp;
end

network.sendData = function(ip, data, sendType)
local outboundSocket = net.createUDPSocket();
data.type = sendType;
local dataToSend = sjson.encode(data);
data.type = nil;
outboundSocket:send(gossip.config.comPort, ip, dataToSend);
outboundSocket:close();
data.type = sendType
local dataToSend = sjson.encode(data)
data.type = nil
gossip.socket:send(gossip.config.comPort, ip, dataToSend)
utils.debug("Sent "..#dataToSend.." bytes")
end

network.receiveSyn = function(ip, synData)
Expand Down Expand Up @@ -235,7 +249,8 @@ constants.defaultConfig = {
seedList = {},
roundInterval = 15000,
comPort = 5000,
debug = false
debug = false,
debugOutput = print
};

constants.comparisonFields = {'revision', 'heartbeat', 'state'};
Expand Down
20 changes: 13 additions & 7 deletions lua_modules/gossip/gossip_tests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ file.putcontents = dummy

local Ip_1 = '192.168.0.1';
local Ip_2 = '192.168.0.2';
local Ip_own = '192.168.0.3';

-- test runner

Expand Down Expand Up @@ -186,20 +187,19 @@ function Test.utils_getMinus()
state = constants.nodeState.SUSPECT;
};

--local diff1 = utils.getMinus(data1, data2);
local diff1 = utils.getMinus(data1, data2);
local diff2 = utils.getMinus(data2, data1);

--assert(diff1[Ip_1] ~= nil and diff1[Ip_2] == nil);
assert(diff1[Ip_1] ~= nil and diff1[Ip_2] == nil);
assert(diff2[Ip_1] == nil and diff2[Ip_2] ~= nil);

end

-- state

function Test.state_setRev()
gossip.ip = Ip_1;
gossip.networkState[Ip_1] = {};
gossip.networkState[Ip_1].revision = -1;
gossip.ip = Ip_own;
gossip.networkState[Ip_own] = {};
gossip.networkState[Ip_own].revision = -1;
assert(state.setRev() == 0, 'Revision not initialized to 0.');
end

Expand All @@ -223,6 +223,7 @@ end
-- network

function Test.network_updateNetworkState_no_callback()
gossip.ip = Ip_own;
local updateData = {}
updateData[Ip_1] = {
revision = 1,
Expand All @@ -232,7 +233,12 @@ function Test.network_updateNetworkState_no_callback()
updateData[Ip_2] = {
revision = 1,
heartbeat = 700,
state = constants.nodeState.UP
state = constants.nodeState.DOWN
};
updateData[Ip_own] = {
revision = 1,
heartbeat = 800,
state = constants.nodeState.DOWN
};
network.updateNetworkState(updateData);
-- send duplicate data
Expand Down
12 changes: 6 additions & 6 deletions lua_modules/yeelink/yeelink_lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ end)
-- apikey must be -> string <-
-- e.g. xxx.init(00000,00000,"123j12b3jkb12k4b23bv54i2b5b3o4")
--========================================
function M.init(_device, _sensor, _apikey)
device = tostring(_device)
sensor = tostring(_sensor)
apikey = _apikey
function M.init(device_, sensor_, apikey_)
device = tostring(device_)
sensor = tostring(sensor_)
apikey = apikey_
if dns == "0.0.0.0" then
tmr.create():alarm(5000,tmr.ALARM_AUTO,function ()
if dns == "0.0.0.0" then
Expand Down Expand Up @@ -90,9 +90,9 @@ end
--
--e.g. xxx.update(233.333)
--============================================================
function M.update(_datapoint)
function M.update(datapoint_)

datapoint = tostring(_datapoint)
datapoint = tostring(datapoint_)

sk:on("connection", function()

Expand Down

0 comments on commit 193fe35

Please sign in to comment.