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
134
135
136
137
138
139
140
141
142
143
144
145
|
local cqueues = require 'cqueues'
local websocket = require'http.websocket'
local request = require'http.request'
local json = require 'dkjson'
local pprint = require 'pprint'
local class = require 'r.class'
local BasePylon = require 'pylon'
local Channel = require 'channel'
local consts = require 'discord.consts'
local opcodes = consts.opcodes
local exec_webhook = require'discord.the'
local API_BASE = "https://discord.com/api/v10/"
local Discord = class.extend(BasePylon)
function Discord.init(self)
self:_check_fields "token"
self.channel_to_webhook = {}
end
local function identify_payload(token)
local I = consts.intents return json.encode{
op = opcodes.identify, d = {
properties = {os="wilson",browser="wilson",device="wilson"},
intents = I.guilds + I.guild_messages + I.message_content,
token = token } } end
function Discord._req_get(self, url)
local req = request.new_from_uri(API_BASE..url)
req.headers:upsert('accept','application/json')
req.headers:upsert(':method','GET')
req.headers:upsert('authorization','Bot '..self.token)
req.headers:upsert('user-agent','wilson (https://g.gh0.pw/wilson/, v0.0)')
local head,body = assert(req:go())
local status = head:get':status'
local bod = body:get_body_as_string()
assert(status:sub(1,1)=='2','status was '..status.." body: "..bod)
print(bod)
return assert(json.decode(bod))
end
function Discord._req_post(self, url, payload)
local req = request.new_from_uri(API_BASE..url)
req:set_body(assert(json.encode(payload)))
req.headers:upsert(':method','POST')
req.headers:upsert('content-type','application/json')
req.headers:upsert('authorization','Bot '..self.token)
req.headers:upsert('user-agent','wilson (https://g.gh0.pw/wilson/, v0.0)')
local head,body = assert(req:go())
local status = head:get':status'
local bod = body:get_body_as_string()
assert(status:sub(1,1)=='2','status was '..status.." body: "..bod)
print(bod)
return assert(json.decode(bod))
end
function Discord._connect(self)
local uri = "wss://gateway.discord.gg/?v=10&encoding=json"
self.ws = websocket.new_from_uri(uri)
assert(self.ws:connect())
self.ws:send(identify_payload(self.token), 'text')
local me = self:_req_get"users/@me"
self.bot_id = me.id
pprint('I AM ',me)
for busname, bus in pairs(self.wilson.busses) do
for _, channel in ipairs(bus) do
if channel.pylon == self then
self:add_channel(channel)
end
end
end
end
function Discord.add_channel(self, channel)
local webhooks = self:_req_get("channels/"..channel.descriptor.."/webhooks")
pprint("webhooks",webhooks)
for _,wh in pairs(webhooks) do
if wh.application_id == self.bot_id then
print("Found existing webhook for channel "..channel.descriptor)
self.channel_to_webhook[channel.descriptor] = wh
return
end
end
print("Making webhook for channel "..channel.descriptor)
local wh = self:_req_post("channels/"..channel.descriptor.."/webhooks", { name=self.name:gsub("discord",""):gsub("clyde","").." wilson hook" })
pprint(wh)
self.channel_to_webhook[channel.descriptor] = wh
end
function Discord._heartbeating(self, interval_ms)
local interval = interval_ms / 1000
cqueues.sleep(interval * math.random())
while true do
self.ws:send(json.encode{
op = opcodes.heartbeat,
d = self.sequence_number,
})
cqueues.sleep(interval)
end
end
function Discord.recving(self)
for packet in self.ws:each() do
local event = json.decode(packet)
print(event.s, event.op, event.t)
if event.op ~= opcodes.dispatch then
pprint(event.d)
end
if event.s then self.sequence_number = event.s end
if event.op == opcodes.hello then
self.cq:wrap(self._heartbeating, self, event.d.heartbeat_interval)
elseif event.op == opcodes.dispatch then
self:handle_dispatch(event)
end
end
end
function Discord.handle_dispatch(self, event)
local d = event.d
if event.t == 'MESSAGE_CREATE' then
if d.author.id == self.channel_to_webhook[d.channel_id].id then return end
if d.author.id == self.bot_id then return end
self.wilson:deliver(Channel(self, d.channel_id), {
body = d.content,
sender = '[d]' .. d.author.username,
})
end
end
function Discord.sending(self)
for dest_channel, message in self.inbox:iter() do
print('DDD',dest_channel,message.sender,message.body)
exec_webhook(self.channel_to_webhook[dest_channel.descriptor].url, {
username = message.sender,
content = message.body,
})
end
end
return Discord
|