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 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(self, url, payload)
local req = request.new_from_uri(API_BASE..url)
req.headers:upsert(':method',payload and 'POST' or 'GET')
req.headers:upsert('authorization','Bot '..self.token)
req.headers:upsert('user-agent','wilson (https://g.gh0.pw/wilson/, v0.0)')
if payload then
req.headers:upsert('content-type','application/json')
req:set_body(assert(json.encode(payload))) end
local head,body = assert(req:go())
local status = head:get':status'
local bod = body:get_body_as_string()
assert(status:match"^2", 'status was '..status..' body '..bod)
local val, _, err = json.decode(bod)
if err then error(err) else return val end
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"users/@me"
self.bot_id = me.id
self.log('logged in as ',me.username)
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("channels/"..channel.descriptor.."/webhooks")
for _,wh in pairs(webhooks) do
if wh.application_id == self.bot_id then
self.log("Found existing webhook for channel",channel.descriptor)
self.channel_to_webhook[channel.descriptor] = wh
return
end
end
self.log("Making webhook for channel",channel.descriptor)
local wh = self:_req_post("channels/"..channel.descriptor.."/webhooks", {
name=self.name:gsub("discord",""):gsub("clyde","").." wilson hook" })
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)
self.log:debug(event.s, event.op, event.t)
if event.op ~= opcodes.dispatch then
self.log:debug(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,
})
elseif event.t == 'READY' then
self.log:debug(event.d)
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
|