Compare commits
2 commits
7e8b53a207
...
14ba3d7a00
Author | SHA1 | Date | |
---|---|---|---|
14ba3d7a00 | |||
455869fa0c |
26 changed files with 394 additions and 417 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
*~
|
*~
|
||||||
\#*#
|
\#*#
|
||||||
|
|
||||||
|
src/*/*.lua
|
||||||
|
|
|
@ -15,6 +15,8 @@ and use it or fallback to English.
|
||||||
Bot uses an OOP-style of Lua
|
Bot uses an OOP-style of Lua
|
||||||
as [[https://is.gd/f0Vadk][described on Wikipedia]].
|
as [[https://is.gd/f0Vadk][described on Wikipedia]].
|
||||||
|
|
||||||
|
For more readability bot's userland written in MoonScript.
|
||||||
|
|
||||||
Maybe I will rewrite bot's core to C but here already so many Lua code.
|
Maybe I will rewrite bot's core to C but here already so many Lua code.
|
||||||
|
|
||||||
* Installation
|
* Installation
|
||||||
|
@ -27,6 +29,8 @@ Maybe I will rewrite bot's core to C but here already so many Lua code.
|
||||||
|
|
||||||
+ Install LuaSec for https requests: ~luarocks-5.3 install luasec~
|
+ Install LuaSec for https requests: ~luarocks-5.3 install luasec~
|
||||||
|
|
||||||
|
+ Install MoonScript: ~luarocks-5.1 install moonscript~
|
||||||
|
|
||||||
+ Create user: ~adduser user~
|
+ Create user: ~adduser user~
|
||||||
|
|
||||||
setup it (add to doas) and login to this user
|
setup it (add to doas) and login to this user
|
||||||
|
@ -37,6 +41,8 @@ Maybe I will rewrite bot's core to C but here already so many Lua code.
|
||||||
|
|
||||||
+ Change token and owner in *config.lua*
|
+ Change token and owner in *config.lua*
|
||||||
|
|
||||||
|
+ Compile bot: ~moonc src/~
|
||||||
|
|
||||||
+ Add service ~doas cp bot.rc /etc/init.d/mybot && doas chmod +x /etc/init.d/mybot~
|
+ Add service ~doas cp bot.rc /etc/init.d/mybot && doas chmod +x /etc/init.d/mybot~
|
||||||
|
|
||||||
+ Configure it ~doas vi /etc/init.d/mybot~ (change user)
|
+ Configure it ~doas vi /etc/init.d/mybot~ (change user)
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
local function prind(...)
|
|
||||||
local t = {...}
|
|
||||||
local s = ''
|
|
||||||
for i = 1, #t do
|
|
||||||
if i > 1 then s = s..'\t' end
|
|
||||||
s = s .. tostring(t[i] or 'nil')
|
|
||||||
end
|
|
||||||
return s .. '\n'
|
|
||||||
end
|
|
||||||
|
|
||||||
local env = {
|
|
||||||
assert = assert,
|
|
||||||
error = error,
|
|
||||||
ipairs = ipairs,
|
|
||||||
pairs = pairs,
|
|
||||||
next = next,
|
|
||||||
tonumber = tonumber,
|
|
||||||
tostring = tostring,
|
|
||||||
type = type,
|
|
||||||
pcall = pcall,
|
|
||||||
xpcall = xpcall,
|
|
||||||
|
|
||||||
math = math,
|
|
||||||
string = string,
|
|
||||||
table = table,
|
|
||||||
|
|
||||||
dump = dump,
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
private = true,
|
|
||||||
run = function(C, msg, owner)
|
|
||||||
local s = ''
|
|
||||||
local t = {
|
|
||||||
msg = msg,
|
|
||||||
print = function(...) s = s .. prind(...) end,
|
|
||||||
|
|
||||||
C = owner and C or nil,
|
|
||||||
api = owner and C.api or nil,
|
|
||||||
}
|
|
||||||
for k,v in pairs(env) do t[k] = v end
|
|
||||||
local e, err = load(C.api.unparseArgs(msg.args), 'eval', 'bt', t)
|
|
||||||
xpcall(function()
|
|
||||||
if err then error(err) end
|
|
||||||
e = tostring(e() or '...')
|
|
||||||
end, function(err) e = err end)
|
|
||||||
s = s ..'\n'.. e
|
|
||||||
s = s:gsub(C.api.token:escp(), '<TOKEN>')
|
|
||||||
C.api:reply(msg, s)
|
|
||||||
end
|
|
||||||
}
|
|
54
src/cmds/eval.moon
Normal file
54
src/cmds/eval.moon
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
prind = (...) ->
|
||||||
|
t = {...}
|
||||||
|
s = ''
|
||||||
|
for i = 1, #t
|
||||||
|
if i > 1
|
||||||
|
s ..= '\t'
|
||||||
|
s ..= tostring t[i] or 'nil'
|
||||||
|
s .. '\n'
|
||||||
|
|
||||||
|
env =
|
||||||
|
assert: assert
|
||||||
|
error: error
|
||||||
|
ipairs: ipairs
|
||||||
|
pairs: pairs
|
||||||
|
next: next
|
||||||
|
tonumber: tonumber
|
||||||
|
tostring: tostring
|
||||||
|
type: type
|
||||||
|
pcall: pcall
|
||||||
|
xpcall: xpcall
|
||||||
|
|
||||||
|
math: math
|
||||||
|
string: string
|
||||||
|
table: table
|
||||||
|
|
||||||
|
dump: dump
|
||||||
|
|
||||||
|
{
|
||||||
|
private: true
|
||||||
|
run: (msg, owner) =>
|
||||||
|
s = ''
|
||||||
|
t =
|
||||||
|
msg: msg
|
||||||
|
print: (...) -> s ..= prind ...
|
||||||
|
|
||||||
|
C: owner and @ or nil
|
||||||
|
api: owner and @api or nil
|
||||||
|
|
||||||
|
for k, v in pairs env
|
||||||
|
t[k] = v
|
||||||
|
|
||||||
|
e, err = load @api.unparseArgs(msg.args), 'eval', 'bt', t
|
||||||
|
|
||||||
|
xpcall (->
|
||||||
|
error err if err
|
||||||
|
e = tostring e! or '...'
|
||||||
|
), (err) -> e = err
|
||||||
|
|
||||||
|
s ..= '\n'.. e
|
||||||
|
s = s\gsub @api.token\escp!, '<TOKEN>'
|
||||||
|
|
||||||
|
@api\reply msg, s
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
return {
|
|
||||||
run = function(C, msg)
|
|
||||||
local t = os.time()
|
|
||||||
local ps, ls, lm, lh, ld
|
|
||||||
ps, ls = t - msg.date, t - C.loaded
|
|
||||||
lm = ls / 60
|
|
||||||
lh = lm / 60
|
|
||||||
ld = lh / 24
|
|
||||||
C.api:send(msg, msg.loc.pat:format(ps, ld, lh, lm, ls))
|
|
||||||
end
|
|
||||||
}
|
|
10
src/cmds/ping.moon
Normal file
10
src/cmds/ping.moon
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
run: (msg) =>
|
||||||
|
t = os.time!
|
||||||
|
ps, ls = t - msg.date, t - @loaded
|
||||||
|
lm = ls / 60
|
||||||
|
lh = lm / 60
|
||||||
|
ld = lh / 24
|
||||||
|
@api\send msg, msg.loc.pat\format ps, ld, lh, lm, ls
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
return {
|
|
||||||
private = true,
|
|
||||||
run = function(C, msg)
|
|
||||||
local cat, sub = table.unpack(msg.args)
|
|
||||||
if not (cat and sub) then
|
|
||||||
return C.api:reply(msg, '/reload cmds ping')
|
|
||||||
end
|
|
||||||
|
|
||||||
local path = 'src.'..cat..'.'..sub
|
|
||||||
C.api:off(package.loaded[path])
|
|
||||||
package.loaded[path] = nil
|
|
||||||
local suc, m = pcall(require, path)
|
|
||||||
|
|
||||||
if not suc then return C.api:reply(msg, 'Reload failed. ' .. m)
|
|
||||||
elseif cat == 'events' then C.api:on(sub, m)
|
|
||||||
elseif cat == 'cmds' then C.cmds[sub] = m
|
|
||||||
elseif cat == 'parts' then m(C)
|
|
||||||
end
|
|
||||||
|
|
||||||
C.api:reply(msg, 'Reloaded. ' .. tostring(m))
|
|
||||||
end
|
|
||||||
}
|
|
23
src/cmds/reload.moon
Normal file
23
src/cmds/reload.moon
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
private: true
|
||||||
|
run: (msg) =>
|
||||||
|
cat, sub = table.unpack msg.args
|
||||||
|
if not (cat and sub)
|
||||||
|
return @api\reply msg, '/reload cmds ping'
|
||||||
|
|
||||||
|
path = "src.#{cat}.#{sub}"
|
||||||
|
|
||||||
|
@api\off package.loaded[path]
|
||||||
|
package.loaded[path] = nil
|
||||||
|
|
||||||
|
suc, m = pcall require, path
|
||||||
|
|
||||||
|
if not suc then return @api\reply msg, 'Reload failed. '.. m
|
||||||
|
else switch cat
|
||||||
|
when 'events' then @api\on sub, m
|
||||||
|
when 'cmds' then @cmds[sub] = m
|
||||||
|
when 'parts' then m @
|
||||||
|
|
||||||
|
@api\reply msg, "Reloaded. #{m}"
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,79 +0,0 @@
|
||||||
-- It uses data from central bank of Russia
|
|
||||||
--- and external service to get json from xml
|
|
||||||
-- Privacy and security is unknown
|
|
||||||
|
|
||||||
local rub = {
|
|
||||||
url = 'https://api.factmaven.com/xml-to-json/?xml='
|
|
||||||
.. 'https://www.cbr.ru/scripts/XML_daily.asp',
|
|
||||||
|
|
||||||
tools = require 'etc.api.tools',
|
|
||||||
}
|
|
||||||
|
|
||||||
function rub:course(wants)
|
|
||||||
local resp, succ = self.tools._req(self.url, 'GET')
|
|
||||||
if not succ then return 'err' end
|
|
||||||
resp = self.tools.json.decode(resp or '{}')
|
|
||||||
|
|
||||||
resp = resp.ValCurs
|
|
||||||
table.insert(resp.Valute, {
|
|
||||||
ID = 'R01000',
|
|
||||||
NumCode = '001',
|
|
||||||
CharCode = 'RUB',
|
|
||||||
Nominal = 1,
|
|
||||||
Name = 'Российский рубль',
|
|
||||||
Value = '1'
|
|
||||||
})
|
|
||||||
local uah = table.findV(resp.Valute, {CharCode = 'UAH'})
|
|
||||||
table.insert(resp.Valute, {
|
|
||||||
ID = 'R02000',
|
|
||||||
NumCode = '200',
|
|
||||||
CharCode = 'SHT',
|
|
||||||
Nominal = 1,
|
|
||||||
Name = 'Штаны',
|
|
||||||
Value = ('%f'):format(tonumber(uah.Value:gsub(',', '.'), nil) / uah.Nominal * 40)
|
|
||||||
})
|
|
||||||
|
|
||||||
wants = type(wants) == 'table' and wants or {}
|
|
||||||
local r, founds = {}, {}
|
|
||||||
|
|
||||||
if table.find(wants, 'HELP')
|
|
||||||
or table.find(wants, 'ALL')
|
|
||||||
then
|
|
||||||
for _, v in pairs(resp.Valute) do
|
|
||||||
table.insert(r, ('%d %s (%s) = %f Руб.'):format(v.Nominal, v.Name, v.CharCode, v.Value:gsub(',', '.')))
|
|
||||||
end
|
|
||||||
return r, resp.Date, wants
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, #resp.Valute do
|
|
||||||
local v = resp.Valute[i]
|
|
||||||
if table.find(wants, v.CharCode) then
|
|
||||||
table.insert(founds, v.CharCode)
|
|
||||||
table.insert(r, ('%d %s (%s) - %f ₽'):format(v.Nominal, v.Name, v.CharCode, v.Value:gsub(',', '.')))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return r, resp.Date, founds
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
run = function(C, msg)
|
|
||||||
local wants = {'USD', 'EUR', table.unpack(msg.args)}
|
|
||||||
for i = 1, #wants do wants[i] = wants[i]:upper() end -- uppercase
|
|
||||||
|
|
||||||
local v, d, f = rub:course(wants)
|
|
||||||
if v == 'error' then
|
|
||||||
return C.api:reply(msg, C.locale:get('error', 'req_err', msg.l))
|
|
||||||
end
|
|
||||||
|
|
||||||
local nf = {}
|
|
||||||
for _, i in pairs(wants) do
|
|
||||||
if not table.find(f, i) then table.insert(nf, i) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local s = msg.loc.cur:format(d, table.concat(v, '\n'))
|
|
||||||
if #nf > 0 then s = s .. msg.loc.notf .. table.concat(nf, ',') end
|
|
||||||
|
|
||||||
C.api:reply(msg, s .. msg.loc.prov)
|
|
||||||
end
|
|
||||||
}
|
|
74
src/cmds/rub.moon
Normal file
74
src/cmds/rub.moon
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
-- It uses data from central bank of Russia
|
||||||
|
--- and external service to get json from xml
|
||||||
|
-- Privacy and security is unknown
|
||||||
|
|
||||||
|
rub =
|
||||||
|
url: 'https://api.factmaven.com/xml-to-json/?xml=https://www.cbr.ru/scripts/XML_daily.asp'
|
||||||
|
|
||||||
|
tools: require 'etc.api.tools'
|
||||||
|
|
||||||
|
pat: '%d %s (%s) - %f ₽'
|
||||||
|
|
||||||
|
getPat: (val) =>
|
||||||
|
@pat\format val.Nominal, val.Name, val.CharCode, val.Value\gsub ',', '.'
|
||||||
|
|
||||||
|
course: (wants) =>
|
||||||
|
res, suc = @tools._req @url, 'GET'
|
||||||
|
return 'err' if not suc
|
||||||
|
res = @tools.json.decode res or '{}'
|
||||||
|
|
||||||
|
res = res.ValCurs
|
||||||
|
table.insert res.Valute, {
|
||||||
|
ID: 'R01000'
|
||||||
|
NumCode: '001'
|
||||||
|
CharCode: 'RUB'
|
||||||
|
Nominal: 1
|
||||||
|
Name: 'Российский рубль',
|
||||||
|
Value: '1'
|
||||||
|
}
|
||||||
|
uah = table.findV res.Valute, CharCode: 'UAH'
|
||||||
|
table.insert res.Valute, {
|
||||||
|
ID: 'R02000'
|
||||||
|
NumCode: '200'
|
||||||
|
CharCode: 'SHT'
|
||||||
|
Nominal: 1
|
||||||
|
Name: 'Штаны'
|
||||||
|
Value: ('%f')\format tonumber(uah.Value\gsub(',', '.'), nil) / uah.Nominal * 40
|
||||||
|
}
|
||||||
|
|
||||||
|
wants = type(wants) == 'table' and wants or {}
|
||||||
|
r, founds = {}, {}
|
||||||
|
|
||||||
|
if table.find wants, 'ALL'
|
||||||
|
for _, v in pairs res.Valute
|
||||||
|
table.insert r, @getPat v
|
||||||
|
return r, res.Date, wants
|
||||||
|
|
||||||
|
for _, v in pairs res.Valute
|
||||||
|
if table.find wants, v.CharCode
|
||||||
|
table.insert founds, v.CharCode
|
||||||
|
table.insert r, @getPat v
|
||||||
|
|
||||||
|
return r, res.Date, founds
|
||||||
|
|
||||||
|
{
|
||||||
|
run: (msg) =>
|
||||||
|
wants = {'USD', 'EUR', table.unpack msg.args}
|
||||||
|
for i = 1, #wants
|
||||||
|
wants[i] = wants[i]\upper!
|
||||||
|
|
||||||
|
v, d, f = rub\course wants
|
||||||
|
if v == 'error'
|
||||||
|
return @api\reply msg, @locale\get 'error', 'req_err', msg.l
|
||||||
|
|
||||||
|
nf = {}
|
||||||
|
for _, i in pairs wants
|
||||||
|
table.insert nf, i if not table.find f, i
|
||||||
|
|
||||||
|
s = msg.loc.cur\format d, table.concat v, '\n'
|
||||||
|
if #nf > 0
|
||||||
|
s = s .. msg.loc.notf.. table.concat nf, ','
|
||||||
|
|
||||||
|
@api\reply msg, s.. msg.loc.prov
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
return {
|
|
||||||
hide = true,
|
|
||||||
run = function(C, msg)
|
|
||||||
C.api:reply(msg, msg.loc.msg)
|
|
||||||
end
|
|
||||||
}
|
|
6
src/cmds/start.moon
Normal file
6
src/cmds/start.moon
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
hide: true
|
||||||
|
run: (msg) =>
|
||||||
|
@api\reply msg, msg.loc.msg
|
||||||
|
return
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
return function(C, api, msg)
|
|
||||||
local cmd = C.cmds[msg.cmd]
|
|
||||||
local owner = msg.from.id == C.config.owner
|
|
||||||
local l = msg.from.language_code
|
|
||||||
|
|
||||||
msg.l = l
|
|
||||||
|
|
||||||
if cmd == nil then
|
|
||||||
api:send(msg, C.locale:get('error', 'inv_cmd', l))
|
|
||||||
|
|
||||||
elseif type(cmd.run) ~= 'function' then
|
|
||||||
api:send(msg, C.locale:get('error', 'cmd_run', l))
|
|
||||||
|
|
||||||
elseif cmd.private and not owner then
|
|
||||||
api:send(msg, C.locale:get('error', 'adm_cmd', l))
|
|
||||||
|
|
||||||
else
|
|
||||||
if cmd.useQArgs then msg.args = api.parseArgs(api.unparseArgs(msg.args)) end
|
|
||||||
msg.loc = C.locale:get('cmds', msg.cmd, l)
|
|
||||||
local succ, err = pcall(cmd.run, C, msg, owner)
|
|
||||||
if not succ then
|
|
||||||
print(err)
|
|
||||||
local cid = C.config.owner
|
|
||||||
api:forward(cid, msg.chat.id, msg.message_id, false)
|
|
||||||
api:send(cid, err)
|
|
||||||
api:reply(msg, C.locale:get('error', 'not_suc', l))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
28
src/events/command.moon
Normal file
28
src/events/command.moon
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
(api, msg) =>
|
||||||
|
l = msg.from.language_code
|
||||||
|
owner = msg.from.id == @config.owner
|
||||||
|
cmd = @cmds[msg.cmd]
|
||||||
|
|
||||||
|
msg.l = l
|
||||||
|
|
||||||
|
if not cmd
|
||||||
|
api\send msg, @locale\get 'error', 'inv_cmd', l
|
||||||
|
|
||||||
|
elseif type(cmd.run) ~= 'function'
|
||||||
|
api\send msg, @locale\get 'error', 'cmd_run', l
|
||||||
|
|
||||||
|
elseif cmd.private and not owner
|
||||||
|
api\send msg, @locale\get 'error', 'adm_cmd', l
|
||||||
|
|
||||||
|
else
|
||||||
|
msg.args = api.parseArgs api.unparseArgs msg.args if cmd.useQArgs
|
||||||
|
msg.loc = @locale\get 'cmds', msg.cmd, l
|
||||||
|
|
||||||
|
suc, err = pcall cmd.run, @, msg, owner
|
||||||
|
if not suc
|
||||||
|
-- whoops
|
||||||
|
print err
|
||||||
|
api\forward @config.owner, msg.chat.id, msg.message_id, false
|
||||||
|
api\send @config.owner, err
|
||||||
|
api\reply msg, @locale\get 'error', 'not_suc', l
|
||||||
|
return
|
|
@ -1,8 +0,0 @@
|
||||||
return function(C, api, q)
|
|
||||||
api.inline
|
|
||||||
:answer(q.id, api.inline.result(
|
|
||||||
'photo', '1',
|
|
||||||
'https://cdn.discordapp.com/attachments/871474214270554124/876506659311202395/unknown.png'
|
|
||||||
):thumb 'https://cdn.discordapp.com/attachments/871474214270554124/876506659311202395/unknown.png'
|
|
||||||
)
|
|
||||||
end
|
|
6
src/events/inlineQuery.moon
Normal file
6
src/events/inlineQuery.moon
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(api, q) =>
|
||||||
|
api.inline\answer q.id, api.inline.result(
|
||||||
|
'photo', '1',
|
||||||
|
'https://cdn.discordapp.com/attachments/871474214270554124/876506659311202395/unknown.png'
|
||||||
|
)\thumb 'https://cdn.discordapp.com/attachments/871474214270554124/876506659311202395/unknown.png'
|
||||||
|
return
|
|
@ -1,25 +0,0 @@
|
||||||
local reg = {
|
|
||||||
{'эх', 'хуех'}, -- надоели эхать
|
|
||||||
{'мета', 'хуета'},
|
|
||||||
{'meta', 'xueta'},
|
|
||||||
{'цукерберг', 'цукерхуй'},
|
|
||||||
{'zuckerberg', 'zuckerhui'},
|
|
||||||
{'whatsapp', 'вадзад'},
|
|
||||||
{'tiktok', 'деградация'},
|
|
||||||
{'.*че%?*$', 'пиши ё, грамотей'},
|
|
||||||
{'.*чё%?*$', 'ничё'}
|
|
||||||
}
|
|
||||||
|
|
||||||
return function(C, api, msg)
|
|
||||||
if msg.text then
|
|
||||||
msg.text = utf8.lower(msg.text)
|
|
||||||
local t = ''
|
|
||||||
for _, v in pairs(reg) do
|
|
||||||
if msg.text:match(v[1])
|
|
||||||
then t = t.. v[2] ..' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if t ~= ''
|
|
||||||
then api:reply(msg, t) end
|
|
||||||
end
|
|
||||||
end
|
|
22
src/events/message.moon
Normal file
22
src/events/message.moon
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
reg = {
|
||||||
|
{'эх', 'хуех'} -- надоели эхать
|
||||||
|
{'мета', 'хуета'}
|
||||||
|
{'meta', 'xueta'}
|
||||||
|
{'цукерберг', 'цукерхуй'}
|
||||||
|
{'zuckerberg', 'zuckerhui'}
|
||||||
|
{'whatsapp', 'вадзад'}
|
||||||
|
{'tiktok', 'деградация'}
|
||||||
|
{'.*че%?*$', 'пиши ё, грамотей'}
|
||||||
|
{'.*чё%?*$', 'ничё'}
|
||||||
|
}
|
||||||
|
|
||||||
|
(api, msg) =>
|
||||||
|
if msg.text
|
||||||
|
msg.text = utf8.lower msg.text
|
||||||
|
t = ''
|
||||||
|
for _, v in pairs reg
|
||||||
|
if msg.text\match v[1]
|
||||||
|
t ..= "#{v[2]} "
|
||||||
|
|
||||||
|
api\reply msg, t if t ~= ''
|
||||||
|
return
|
|
@ -1,61 +0,0 @@
|
||||||
function table.indexOf(t, w)
|
|
||||||
local i = {}
|
|
||||||
for k,v in pairs(t) do i[v] = k end
|
|
||||||
return i[w]
|
|
||||||
end
|
|
||||||
|
|
||||||
function table.find(t, w)
|
|
||||||
for _,v in pairs(t) do
|
|
||||||
if v == w then return v end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function table.findV(t, w)
|
|
||||||
local b
|
|
||||||
for _,v in pairs(t) do
|
|
||||||
for k,x in pairs(w) do
|
|
||||||
if x ~= v[k] then b=1; break end
|
|
||||||
end
|
|
||||||
if b then b = nil
|
|
||||||
else return v end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.escp(s)
|
|
||||||
return s:gsub('[%^%$%%%(%)%.%[%]%*%+%-%?]', '%%%0')
|
|
||||||
end
|
|
||||||
|
|
||||||
function dump(t, d)
|
|
||||||
if not tonumber(d) or d < 0 then d = 0 end
|
|
||||||
local c = ''
|
|
||||||
for k,v in pairs(t) do
|
|
||||||
if type(v) == 'table' then v = '\n' .. dump(v, d + 1) end
|
|
||||||
c = c .. string.format('%s%s = %s\n', (' '):rep(d), k, v)
|
|
||||||
end
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(C, api)
|
|
||||||
C:load 'cmds'
|
|
||||||
local a
|
|
||||||
for _, lang in pairs(C.locale.list) do
|
|
||||||
a = {}
|
|
||||||
for k, v in pairs(C.cmds) do
|
|
||||||
if not (v.private or v.hide) then
|
|
||||||
local cmd = C.locale:get('cmds', k, lang) or {}
|
|
||||||
table.insert(a, {
|
|
||||||
command = k,
|
|
||||||
description = (cmd.args and cmd.args .. ' - ' or '') .. (cmd.desc or C.locale:get('cmds', 'not_des'))
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
api:setMyCommands(a, lang)
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
a = {'levels', }
|
|
||||||
for i = 1, #a do
|
|
||||||
if not C.db[a[i] ] then C.db[a[i] ] = {} end
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
end
|
|
50
src/events/ready.moon
Normal file
50
src/events/ready.moon
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
table.indexOf = (t, w) ->
|
||||||
|
i = {}
|
||||||
|
for k, v in pairs t
|
||||||
|
i[v] = k
|
||||||
|
i[w]
|
||||||
|
|
||||||
|
table.find = (t, w) ->
|
||||||
|
for _, v in pairs t
|
||||||
|
return v if v == w
|
||||||
|
|
||||||
|
table.findV = (t, w) ->
|
||||||
|
b = nil
|
||||||
|
for _, v in pairs t
|
||||||
|
for k, x in pairs w
|
||||||
|
if x ~= v[k]
|
||||||
|
b = 1
|
||||||
|
break
|
||||||
|
if b then b = nil -- continue
|
||||||
|
else return v
|
||||||
|
|
||||||
|
string.escp = (s) ->
|
||||||
|
s\gsub '[%^%$%%%(%)%.%[%]%*%+%-%?]', '%%%0'
|
||||||
|
|
||||||
|
export dump = (t, d) ->
|
||||||
|
d = 0 if not tonumber(d) or d < 0
|
||||||
|
c = ''
|
||||||
|
for k, v in pairs t
|
||||||
|
if type(v) == 'table'
|
||||||
|
v = '\n'.. dump v, d + 1
|
||||||
|
|
||||||
|
elseif type(v) == 'userdata'
|
||||||
|
v = '<USERDATA>'
|
||||||
|
|
||||||
|
c ..= ('%s%s = %s\n')\format (' ')\rep d, k, v
|
||||||
|
c
|
||||||
|
|
||||||
|
(api) =>
|
||||||
|
@\load 'cmds'
|
||||||
|
|
||||||
|
for _, lang in pairs @locale.list
|
||||||
|
a = {}
|
||||||
|
for k, v in pairs @cmds
|
||||||
|
if not (v.private or v.hide)
|
||||||
|
cmd = @locale\get 'cmds', k, lang or {}
|
||||||
|
table.insert a, {command: k,
|
||||||
|
description: (cmd.args and cmd.args .. ' - ' or '') .. (cmd.desc or @locale\get 'cmds', 'not_des')
|
||||||
|
}
|
||||||
|
api\setMyCommands a, lang
|
||||||
|
return
|
|
@ -1,35 +0,0 @@
|
||||||
local tg = require 'etc.api'
|
|
||||||
|
|
||||||
return function(Core)
|
|
||||||
local self = Core
|
|
||||||
|
|
||||||
self.api = tg { norun = true }
|
|
||||||
self.cmds = {}
|
|
||||||
|
|
||||||
print 'Client initialization...'
|
|
||||||
|
|
||||||
function Core._ev(ev, ...) self:ev(...) end
|
|
||||||
function self.api._ev(_, t, i, n, ...)
|
|
||||||
self._ev(_, t, i, n, self.api, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
self:load 'events'
|
|
||||||
|
|
||||||
self.api:login(self.config.token, function()
|
|
||||||
print('Logged on as @' .. self.api.info.username)
|
|
||||||
self.config.token = nil
|
|
||||||
self.api:emit 'ready'
|
|
||||||
end)
|
|
||||||
|
|
||||||
local offs, o = 0
|
|
||||||
self.api.runs = true
|
|
||||||
self:on('ready', function()
|
|
||||||
while self.api.runs do
|
|
||||||
self:emit 'tick'
|
|
||||||
|
|
||||||
o = self.api:_getUpd(1, offs, 0)
|
|
||||||
offs = o and o or offs
|
|
||||||
end
|
|
||||||
self.api:getUpdates(1, offs, 0)
|
|
||||||
end)
|
|
||||||
end
|
|
32
src/parts/client.moon
Normal file
32
src/parts/client.moon
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
tg = require 'etc.api'
|
||||||
|
|
||||||
|
=>
|
||||||
|
@api = tg { norun: true }
|
||||||
|
@cmds = {}
|
||||||
|
|
||||||
|
print 'Client initialization...'
|
||||||
|
|
||||||
|
@_ev = (ev, ...) -> @\ev ...
|
||||||
|
@api._ev = (_, t, i, n, ...) ->
|
||||||
|
@._ev _, t, i, n, @api, ...
|
||||||
|
|
||||||
|
@\load 'events'
|
||||||
|
|
||||||
|
@api\login @config.token, ->
|
||||||
|
print "Logged on as @#{@api.info.username}"
|
||||||
|
@config.token = nil
|
||||||
|
@api\emit 'ready'
|
||||||
|
return
|
||||||
|
|
||||||
|
offs, o = 0
|
||||||
|
@api.runs = true
|
||||||
|
@\on 'ready', ->
|
||||||
|
while @api.runs
|
||||||
|
@\emit 'tick'
|
||||||
|
|
||||||
|
o = @api\_getUpd 1, offs, 0
|
||||||
|
offs = o and o or offs
|
||||||
|
|
||||||
|
@api\getUpdates 1, offs, 0
|
||||||
|
return
|
||||||
|
return
|
|
@ -1,57 +0,0 @@
|
||||||
local config = require 'config'
|
|
||||||
|
|
||||||
local Core = {
|
|
||||||
config = config,
|
|
||||||
loaded = 0,
|
|
||||||
}
|
|
||||||
(require 'etc.events')(Core) -- add events
|
|
||||||
|
|
||||||
function Core:load(what)
|
|
||||||
local c = config[what]
|
|
||||||
local s = #c
|
|
||||||
for i = 1, s do
|
|
||||||
local v = c[i]
|
|
||||||
|
|
||||||
print(('Loading %s (%d / %d) %s...'):format(what:sub(0, -2), i, s, v))
|
|
||||||
-- Lint
|
|
||||||
local e, a = pcall(require, 'src.'.. what ..'.'.. v)
|
|
||||||
print(e, a)
|
|
||||||
if e then
|
|
||||||
if what == 'events' then self.api:on(v, a)
|
|
||||||
elseif what == 'cmds' then self.cmds[v] = a
|
|
||||||
elseif what == 'parts' then a(self)
|
|
||||||
end
|
|
||||||
else print 'fail' end
|
|
||||||
end
|
|
||||||
print(('Loaded %d %s'):format(s, what))
|
|
||||||
self.loaded = os.time()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Core:ev(t, i, name, ...)
|
|
||||||
local v = t[i]
|
|
||||||
if v.name == name then
|
|
||||||
local succ, err = pcall(v.fn, self, ...)
|
|
||||||
if not succ then
|
|
||||||
print('event "' .. name .. '" was failed')
|
|
||||||
print(err)
|
|
||||||
end
|
|
||||||
if v.type == 'once' then table.remove(t, i) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Core:init()
|
|
||||||
self:load 'parts'
|
|
||||||
|
|
||||||
utf8 = require 'etc.utf8'
|
|
||||||
|
|
||||||
print 'Done!'
|
|
||||||
self:emit 'ready'
|
|
||||||
end
|
|
||||||
|
|
||||||
function Core:stop()
|
|
||||||
self.api:destroy()
|
|
||||||
print 'Stopped'
|
|
||||||
print('Uptime: '.. os.time() - self.loaded.. ' seconds')
|
|
||||||
end
|
|
||||||
|
|
||||||
Core:init()
|
|
52
src/parts/core.moon
Normal file
52
src/parts/core.moon
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
config = require 'config'
|
||||||
|
|
||||||
|
Core =
|
||||||
|
config: config
|
||||||
|
loaded: 0
|
||||||
|
|
||||||
|
load: (what) =>
|
||||||
|
c = config[what]
|
||||||
|
|
||||||
|
for i = 1, #c
|
||||||
|
v = c[i]
|
||||||
|
|
||||||
|
print "Loading #{what\sub 0, -2} (#{i} / #{#c}) #{v}..."
|
||||||
|
-- Lint
|
||||||
|
e, a = pcall require, "src.#{what}.#{v}"
|
||||||
|
print e, a
|
||||||
|
if e
|
||||||
|
switch what
|
||||||
|
when 'events' then @api\on v, a
|
||||||
|
when 'cmds' then @cmds[v] = a
|
||||||
|
when 'parts' then a @
|
||||||
|
else print 'fail'
|
||||||
|
print "Loaded #{#c} #{what}"
|
||||||
|
@loaded = os.time!
|
||||||
|
|
||||||
|
ev: (t, i, name, ...) =>
|
||||||
|
v = t[i]
|
||||||
|
if v.name == name
|
||||||
|
suc, err = pcall v.fn, @, ...
|
||||||
|
if not suc
|
||||||
|
print "event \"#{name}\" was failed"
|
||||||
|
print err
|
||||||
|
table.remove t, i if v.type == 'once'
|
||||||
|
|
||||||
|
init: =>
|
||||||
|
@\load 'parts'
|
||||||
|
|
||||||
|
export utf8 = require 'etc.utf8'
|
||||||
|
|
||||||
|
print 'Done!'
|
||||||
|
@\emit 'ready'
|
||||||
|
return
|
||||||
|
|
||||||
|
stop: =>
|
||||||
|
@api\destroy!
|
||||||
|
print 'Stopped'
|
||||||
|
print "Uptime: #{os.time! - @loaded} seconds"
|
||||||
|
return
|
||||||
|
|
||||||
|
require('etc.events')(Core) -- add events
|
||||||
|
Core\init!
|
||||||
|
return
|
|
@ -1,33 +0,0 @@
|
||||||
local Locale = {
|
|
||||||
list = {
|
|
||||||
'en',
|
|
||||||
'ru'
|
|
||||||
},
|
|
||||||
main = 'en',
|
|
||||||
|
|
||||||
__newindex = function()end -- ro
|
|
||||||
}
|
|
||||||
Locale.__index = Locale
|
|
||||||
|
|
||||||
function Locale:get(cat, k, lang)
|
|
||||||
assert(cat, 'Give category')
|
|
||||||
assert(k, 'Give key')
|
|
||||||
lang = lang or self.main
|
|
||||||
|
|
||||||
local v = (self[lang] or {})[cat]
|
|
||||||
if not v then
|
|
||||||
return self[self.main][cat][k]
|
|
||||||
else return v[k] end
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(C)
|
|
||||||
local json = require 'etc.json'
|
|
||||||
|
|
||||||
for i = 1, #Locale.list do
|
|
||||||
local n = Locale.list[i]
|
|
||||||
local f = io.open(('src/locales/%s.json'):format(n))
|
|
||||||
Locale[n] = json.decode(f:read 'a')
|
|
||||||
end
|
|
||||||
|
|
||||||
C.locale = setmetatable({}, Locale)
|
|
||||||
end
|
|
30
src/parts/locale.moon
Normal file
30
src/parts/locale.moon
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Locale =
|
||||||
|
__newindex: -> -- ro
|
||||||
|
|
||||||
|
list: {
|
||||||
|
'en'
|
||||||
|
'ru'
|
||||||
|
}
|
||||||
|
main: 'en'
|
||||||
|
|
||||||
|
get: (cat, k, lang) =>
|
||||||
|
assert cat, 'Give category'
|
||||||
|
assert k, 'Give key'
|
||||||
|
lang or= @main
|
||||||
|
|
||||||
|
v = (@[lang] or {})[cat]
|
||||||
|
if not v
|
||||||
|
@[@main][cat][k] or {}
|
||||||
|
else v[k] or {}
|
||||||
|
|
||||||
|
Locale.__index = Locale
|
||||||
|
|
||||||
|
(C) ->
|
||||||
|
json = require 'etc.json'
|
||||||
|
|
||||||
|
for i = 1, #Locale.list
|
||||||
|
n = Locale.list[i]
|
||||||
|
f = io.open "src/locales/#{n}.json"
|
||||||
|
Locale[n] = json.decode f\read 'a'
|
||||||
|
|
||||||
|
C.locale = setmetatable {}, Locale
|
Loading…
Reference in a new issue