summaryrefslogtreecommitdiff
path: root/main.lua
blob: 1df9730e1899f99aa305c4fe64085cdac66f6563 (plain)
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
local cqueues = require'cqueues'
local signal = require'cqueues.signal'
local class = require'r.class'
local rtable = require'r.table'
local pprint = require'pprint'

local config = require'config'
local Thing = require'thing'
local Log = require 'log'
local Store = require 'store'

local pylon_classes = {
	irc = require'irc.pylon',
	xmpp = require'xmpp.pylon',
	discord = require'discord.pylon',
	nanochat = require'nanochat.pylon',
	quaddle = require'quaddle.pylon',
}

local Wilson = class()
function Wilson.make(cls, conf)
	local tlc = conf.top.level or {}
	local self = setmetatable({
		pylons={},
		busses={},
		cq = cqueues.new(),
		log = Log('(toplevel)',tlc.loglevel or 'info'),
		store = Store(),
	}, Wilson)
	for name, pylon_conf in pairs(conf.pylon) do
		pylon_conf.name = name
		local pylon_class = pylon_classes[pylon_conf.type]
		assert(pylon_class, "no such pylon type "..pylon_conf.type)
		self.pylons[name] = pylon_class:make(self, pylon_conf)
		self.log("constructed pylon",name,pylon_conf.type)
	end
	for name, bus_conf in pairs(conf.bus) do
		local bus = {}
		for _, item in ipairs(bus_conf) do
			local pylon_name, channel_id = item[1], item[2]
			local pylon = self.pylons[pylon_name]
			assert(pylon,"no such pylon named "..pylon_name)
			table.insert(bus, Thing(pylon, channel_id))
		end
		self.log("constructed bus  ",name,'with '..#bus_conf..' channels')
		self.busses[name] = bus
	end
	return self
end

function Wilson.add_channels_for(self, pylon)
	if not pylon.channels then return end
	for busname, bus in pairs(busses) do
		for _, channel in ipairs(bus) do
			if  channel.pylon == pylon
				and not pylon.channels[channel.id]
			then
				pylon:add_channel(channel)
end end end end

function Wilson.load_config(self, conf)
	local pneed,phave = rtable.keydiff(conf.pylon, self.pylons)
	if next(phave) then error"don't know how to remove pylons yet" end

	for pname,p in pairs(conf.pylons) do if self.pylons[pname] then
		for k,v in pairs(p) do if v ~= self.pylons[pname][k] then
			error("different field "..k.." on "..pname) end end end end

	-- loop thru buses, form list of channels we need to care about
	-- don't know how to remove channels yet
	-- then for pylons need to be constructed, pass them the list of channels to connect to
	-- verify pylon names are valid here too
	local ch4p = {} for k in pairs(conf.pylon) do ch4p[k] = {} end
	for busname,b in pairs(conf.bus) do for i,item in ipairs(b) do
		local pname,cid = item[1],item[2]
		if not ch4p[pname] then error("no such pylon "..pname) end
		table.insert(ch4p[pname], cid) end end

	for pname,p in pairs(conf.pylon) do
		p.name = pname
		if self.pylons[pname] then
			self.pylons[pname]:sync_channels(ch4p[pname])
		else
			local cls = assert(pylon_class[p.type], "no such pylon type "..p.type)
			self.pylon[name] = cls(self, p, ch4p[pname])
		end
	end

end


	


-- find bus containing given channel
function Wilson._find_bus(self, channel)
	for name, bus in pairs(self.busses) do
		for _, q in ipairs(bus) do if q == channel then return bus end end
	end
	self.log:warn("unfound bus for",channel) end
function Wilson.deliver(self, message)
	local bus = self:_find_bus(assert(message.channel))
	if bus then
		self.store:store(message)
		for _, dest_channel in ipairs(bus) do
			if message.channel ~= dest_channel then
				self.log:debug(message.channel, "-->", dest_channel, message)
				dest_channel.pylon:post(dest_channel, message)
end end end end
function Wilson.run(self)
	for pylonname, pylon in pairs(self.pylons) do
		self.cq:wrap(pylon.run, pylon)
		self.log("now running pylon", pylonname)
	end
	self.cq:wrap(self.store.run, self.store)
	self.cq:wrap(self.hup, self)
	self.log:loop(self.cq)
end

function Wilson.hup(self)
	signal.block(signal.SIGHUP)
	local sl = signal.listen(signal.SIGHUP)
	while true do
		local s = sl:wait()
		self:reload_config()
	end
end

local config_file = assert(io.open("wilson.ini","r"))
local conf = config.parse(config_file)
config_file:close()
local wilson = Wilson:make(conf)
wilson:run()