Compare commits
27 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ed6598b145 | ||
5a54bc1032 | |||
0b2a7ac8e5 | |||
daa848cecd | |||
6c0f8b437d | |||
14ba3d7a00 | |||
455869fa0c | |||
7e8b53a207 | |||
17f1727be1 | |||
b0f616fd32 | |||
7e26dfa38d | |||
6add3f5e6b | |||
8f538ba65a | |||
3bbccb94ab | |||
65b2f6eebc | |||
70da2d717e | |||
2b72d1c98d | |||
dffe9cc9b2 | |||
f50fe9e35b | |||
c7c2ccc664 | |||
18a36e169a | |||
1b498be1d6 | |||
8421b61a82 | |||
5dee01b07b | |||
9a9bd56b7d | |||
00b15b847b | |||
214b621cdf |
32 changed files with 2544 additions and 285 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.env
|
||||||
|
.gitignore
|
||||||
|
.git
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@
|
||||||
*~
|
*~
|
||||||
\#*#
|
\#*#
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -2,3 +2,6 @@
|
||||||
path = etc/api
|
path = etc/api
|
||||||
url = https://gitdab.com/er2/tg-api-lua
|
url = https://gitdab.com/er2/tg-api-lua
|
||||||
|
|
||||||
|
[submodule "etc/utf8"]
|
||||||
|
path = etc/utf8
|
||||||
|
url = https://github.com/Stepets/utf8.lua
|
||||||
|
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
FROM alpine AS build
|
||||||
|
|
||||||
|
RUN apk add luarocks5.1 libressl-dev gcc musl-dev lua5.1-dev \
|
||||||
|
&& luarocks-5.1 install luasec \
|
||||||
|
&& mkdir -p /dist/usr/local \
|
||||||
|
&& mkdir -p /dist/usr/local/lib/lua && cp -rpv /usr/local/lib/lua/* /dist/usr/local/lib/lua \
|
||||||
|
&& mkdir -p /dist/usr/local/share/lua && cp -rpv /usr/local/share/lua/* /dist/usr/local/share/lua
|
||||||
|
|
||||||
|
COPY run.sh /dist
|
||||||
|
COPY . /dist/app
|
||||||
|
|
||||||
|
FROM alpine
|
||||||
|
VOLUME ["/app"]
|
||||||
|
|
||||||
|
RUN apk add libressl luajit \
|
||||||
|
&& ln -sf $(which luajit) /usr/bin/lua \
|
||||||
|
&& adduser -D -h /app user
|
||||||
|
|
||||||
|
COPY --from=build /dist /
|
||||||
|
ENTRYPOINT ["/run.sh"]
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
return {
|
return {
|
||||||
token = 'atokenyanedam',
|
token = os.getenv 'TOKEN',
|
||||||
owner = 935626920 , -- hehe
|
owner = tonumber(os.getenv 'OWNER'),
|
||||||
cmds = {
|
cmds = {
|
||||||
'eval',
|
'eval',
|
||||||
|
'reload',
|
||||||
'ping',
|
'ping',
|
||||||
'rub',
|
'rub',
|
||||||
'start',
|
'start',
|
||||||
|
'shell',
|
||||||
},
|
},
|
||||||
events = {
|
events = {
|
||||||
'command',
|
'command',
|
||||||
'ready',
|
'ready',
|
||||||
|
'inlineQuery',
|
||||||
|
'message',
|
||||||
},
|
},
|
||||||
parts = {
|
parts = {
|
||||||
'locale',
|
'locale',
|
||||||
|
|
2
etc/api
2
etc/api
|
@ -1 +1 @@
|
||||||
Subproject commit 30f7203c5fe69e875dbd29a4da9fe0c5ab1ddc9b
|
Subproject commit faab5a7e6d0dc684d04cf5121b9735b786716aca
|
116
etc/class.lua
Normal file
116
etc/class.lua
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
-- Class library
|
||||||
|
-- (c) Er2 2022 <er2@dismail.de>
|
||||||
|
-- Zlib License
|
||||||
|
|
||||||
|
-- (Not) Virtual classes table
|
||||||
|
local vtable = {}
|
||||||
|
|
||||||
|
-- Metamethods
|
||||||
|
local cls = {}
|
||||||
|
cls.__index = cls
|
||||||
|
|
||||||
|
-- :__tostring() - Calls when using Lua tostring() or error occurs.
|
||||||
|
function cls:__tostring()
|
||||||
|
local str = 'Class <'.. self.__name ..'>'
|
||||||
|
while self.__super do
|
||||||
|
str = str.. ' inherits '.. self.__super.__name
|
||||||
|
self = self.__super
|
||||||
|
end
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :__call(table) - Calls when defining class body
|
||||||
|
function cls:__call(t)
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
self[k] = v
|
||||||
|
end
|
||||||
|
if self.__init
|
||||||
|
then self:__init()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :new(...) - Creates new instance of class. Please use new(...) function instead.
|
||||||
|
-- Can throw error if no constructor defined in class or subclasses.
|
||||||
|
function cls:new(...)
|
||||||
|
local cl = self
|
||||||
|
local cons
|
||||||
|
repeat cons = rawget(cl, 1) or rawget(cl, 'new')
|
||||||
|
cl = cl.__super
|
||||||
|
until cons or not cl
|
||||||
|
assert(cons, 'No constructor found in class')
|
||||||
|
|
||||||
|
--self.__index = self.__index or cls.__index
|
||||||
|
self = setmetatable({}, self)
|
||||||
|
cons(self, ...)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :super(...) - Call parent constructor.
|
||||||
|
function cls:super(...)
|
||||||
|
return cls.superM(self, 1, ...)
|
||||||
|
or cls.superM(self, 'new', ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :superM(method, ...) - Call method from parent class.
|
||||||
|
-- Can throw error if class is not inherited.
|
||||||
|
function cls:superM(meth, ...)
|
||||||
|
local cl = self.__super
|
||||||
|
local fn
|
||||||
|
while not fn and cl do
|
||||||
|
fn = cl[meth]
|
||||||
|
if cl.__sup then fn = nil end
|
||||||
|
cl = cl.__super
|
||||||
|
end
|
||||||
|
if not fn then return nil end
|
||||||
|
|
||||||
|
if cl then cl.__sup = true end
|
||||||
|
local v = {fn(self, ...)}
|
||||||
|
if cl then cl.__sup = nil end
|
||||||
|
return table.unpack(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :clone() - Make clone of class.
|
||||||
|
function cls:clone()
|
||||||
|
local cl = {}
|
||||||
|
for k, v in pairs(cls)
|
||||||
|
do cl[k] = v end
|
||||||
|
for k, v in pairs(self)
|
||||||
|
do cl[k] = v end
|
||||||
|
cl.__index = cl
|
||||||
|
cl.__super = self
|
||||||
|
return setmetatable(cl, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :inherits(className) - Make this class inherits from another.
|
||||||
|
-- Can throw error if class is already inherited.
|
||||||
|
function cls:inherits(name)
|
||||||
|
-- assert(self.__super, 'no')
|
||||||
|
local cl = vtable[name]
|
||||||
|
assert(cl, 'Class is not exists')
|
||||||
|
return setmetatable(self, cl:clone())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- :extends(className) - Same as :inherits(className).
|
||||||
|
cls.extends = cls.inherits
|
||||||
|
|
||||||
|
-- class(className) - Make new class.
|
||||||
|
-- Can throw error if class already exists with this name.
|
||||||
|
function class(name)
|
||||||
|
assert(not vtable[name], 'Cannot override defined class')
|
||||||
|
local cl = setmetatable({__name = name, __tostring = cls.__tostring}, cls)
|
||||||
|
cl.__index = cl
|
||||||
|
vtable[name] = cl
|
||||||
|
return cl
|
||||||
|
end
|
||||||
|
|
||||||
|
-- new(className) - Make new instance of class. Use this instead of :new(class).
|
||||||
|
-- Can throw error if class by name was not found.
|
||||||
|
function new(name)
|
||||||
|
local cl = vtable[name]
|
||||||
|
assert(cl, 'No class found')
|
||||||
|
return function(...)
|
||||||
|
return cls.new(cl, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
105
etc/events.lua
105
etc/events.lua
|
@ -1,43 +1,74 @@
|
||||||
--[[ Events library
|
-- Events library
|
||||||
-- (c) Er2 2021 <er2@dismail.de>
|
-- (c) Er2 2022 <er2@dismail.de>
|
||||||
-- Zlib License
|
-- Zlib License
|
||||||
--]]
|
|
||||||
|
|
||||||
local events = {}
|
require 'class'
|
||||||
events.__index = events
|
|
||||||
|
|
||||||
function events:_add(t, n, f)
|
class 'Events' {
|
||||||
table.insert(self._ev_, {
|
function(this)
|
||||||
type = t,
|
this._ev_ = {}
|
||||||
name = n,
|
end,
|
||||||
fn = f,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
function events:on(n,f) self:_add('on', n,f) end
|
_add = function(this, type, name, func)
|
||||||
function events:once(n,f) self:_add('once', n,f) end
|
table.insert(this._ev_, {
|
||||||
|
type = tostring(type),
|
||||||
|
name = tostring(name),
|
||||||
|
func = func,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
|
||||||
function events:_ev(t, i, name, ...)
|
on = function(this, name, func)
|
||||||
local v = t[i]
|
this:_add('on', name, func)
|
||||||
if v.name == name then
|
end,
|
||||||
v.fn(...)
|
|
||||||
if v.type == 'once' then table.remove(t, i) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function events:emit(name, ...)
|
once = function(this, name, func)
|
||||||
local t = self._ev_
|
this:_add('once', name, func)
|
||||||
for i = 1, #t do
|
end,
|
||||||
local v = t[i] or {}
|
|
||||||
if type(v) == 'table'
|
off = function(this, func)
|
||||||
and type(v.name) == 'string'
|
for k, v in pairs(this._ev_) do
|
||||||
and type(v.type) == 'string'
|
if v.func == func
|
||||||
and type(v.fn) == 'function'
|
then table.remove(this._ev_, k)
|
||||||
then self:_ev(t, i, name, ...) end
|
end
|
||||||
end
|
end
|
||||||
end
|
end,
|
||||||
|
|
||||||
|
_ev = function(this, t, i, name, ...)
|
||||||
|
local v = t[i]
|
||||||
|
if v.name == name then
|
||||||
|
v.func(...)
|
||||||
|
if v.type == 'once'
|
||||||
|
then table.remove(t, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
emit = function(this, name, ...)
|
||||||
|
local t = this._ev_
|
||||||
|
for i = 1, #t do
|
||||||
|
local v = t[i]
|
||||||
|
if type(v) == 'table'
|
||||||
|
and type(v.name) == 'string'
|
||||||
|
and type(v.type) == 'string'
|
||||||
|
and type(v.func) == 'function'
|
||||||
|
then this:_ev(t, i, name, ...)
|
||||||
|
else print 'Invalid event'
|
||||||
|
if v then print(v, v.name, v.type, v.func)
|
||||||
|
else print 'nil' end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
class 'EventsThis' : inherits 'Events' {
|
||||||
|
_ev = function(this, t, i, name, ...)
|
||||||
|
local v = t[i]
|
||||||
|
if v.name == name then
|
||||||
|
v.func(this, ...)
|
||||||
|
if v.type == 'once'
|
||||||
|
then table.remove(t, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
return function(t)
|
|
||||||
t._ev_ = {}
|
|
||||||
return setmetatable(t, events)
|
|
||||||
end
|
|
||||||
|
|
1
etc/utf8
Submodule
1
etc/utf8
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 17f4e009a22fb2f2e6ad316a05b2cca8e071fc3b
|
1860
etc/utf8data.lua
Normal file
1860
etc/utf8data.lua
Normal file
File diff suppressed because it is too large
Load diff
3
example.env
Normal file
3
example.env
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
TOKEN= # insert bot token here
|
||||||
|
OWNER= # insert owner ID here
|
||||||
|
|
2
init.lua
2
init.lua
|
@ -1,3 +1,3 @@
|
||||||
package.path = 'etc/?.lua;etc/?/init.lua;' .. package.path
|
package.path = 'etc/?.lua;etc/?/init.lua;?.lua;?/init.lua;' .. package.path
|
||||||
|
|
||||||
require 'src.parts.core'
|
require 'src.parts.core'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Zlib License
|
Zlib License
|
||||||
|
|
||||||
Copyright (c) 2021 Er2 <er2@dismail.de>
|
Copyright (c) 2022 Er2 <er2@dismail.de>
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
35
readme.org
35
readme.org
|
@ -1,38 +1,33 @@
|
||||||
* Computer bot
|
* Computer bot
|
||||||
|
|
||||||
Now, GitHub contains *mirror*, original is *[[https://gitdab.com/er2/comp-tg][here]]*.
|
Original is *[[https://gitdab.com/er2/comp-tg][here]]* and [[https://git.er2.tech/er2/comp-tg][here]].
|
||||||
|
Mirrors can update irregularly.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
This bot is a continue of [[https://github.com/Er2pkg/computer][my Discord bot]],
|
This is a bot for Telegram.
|
||||||
but on Telegram.
|
It haven't got much possibilities,
|
||||||
|
but this code can be used in other bots.
|
||||||
|
|
||||||
|
Bot can use locale of Telegram client (unlike much bots)
|
||||||
|
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]].
|
||||||
|
|
||||||
Also bot reads client language and automatically loads needing locale.
|
Maybe I will rewrite bot's core to C but here already so many Lua code.
|
||||||
|
|
||||||
Maybe I rewrite bot's core to C but there already so many Lua code.
|
|
||||||
|
|
||||||
* Installation
|
* Installation
|
||||||
|
|
||||||
[[https://alpinelinux.org][Alpine linux]], root:
|
Officially supported only [[https://docker.com][Docker]], but you can use it without Docker.
|
||||||
|
|
||||||
+ Enable community repo (described in wiki)
|
Docker installation:
|
||||||
|
|
||||||
+ Install lua and tools: ~apk add sudo git lua5.3 luarocks openssl-dev~
|
+ Clone repository with submodules: ~git clone --recursive https://gitdab.com/er2/comp-tg~
|
||||||
|
|
||||||
+ Install LuaSec for https requests: ~luarocks-5.3 install luasec~
|
and enter ~cd comp-tg~
|
||||||
|
|
||||||
+ Create user: ~adduser user~
|
+ Build image: ~docker build -t comp-tg .~
|
||||||
|
|
||||||
and login to this user
|
+ Start it: ~docker run -d -e .env --name comp-tg --restart always comp-tg~
|
||||||
|
|
||||||
+ Clone repo: ~git clone --recursive https://gitdab.com/er2/comp-tg~
|
|
||||||
|
|
||||||
and enter ~cd comp-tg~
|
|
||||||
|
|
||||||
+ Change token and owner in *config.lua*
|
|
||||||
|
|
||||||
+ Run: ~lua5.3 init.lua~
|
|
||||||
|
|
||||||
|
|
7
run.sh
Executable file
7
run.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
chown user:user -R /app 2> /dev/null
|
||||||
|
|
||||||
|
cd /app
|
||||||
|
su user -c "lua init.lua"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
local function prind(...)
|
local function prind(...)
|
||||||
local t = {...}
|
|
||||||
local s = ''
|
local s = ''
|
||||||
for i = 1, #t do
|
for _, v in pairs {...} do
|
||||||
if i > 1 then s = s..'\t' end
|
if #s > 0
|
||||||
s = s .. tostring(t[i] or 'nil')
|
then s = s .. '\t'
|
||||||
|
end
|
||||||
|
s = s .. tostring(v) or 'nil'
|
||||||
end
|
end
|
||||||
return s .. '\n'
|
return s ..'\n'
|
||||||
end
|
end
|
||||||
|
|
||||||
local env = {
|
local env = {
|
||||||
|
@ -19,11 +20,9 @@ local env = {
|
||||||
type = type,
|
type = type,
|
||||||
pcall = pcall,
|
pcall = pcall,
|
||||||
xpcall = xpcall,
|
xpcall = xpcall,
|
||||||
|
|
||||||
math = math,
|
math = math,
|
||||||
string = string,
|
string = string,
|
||||||
table = table,
|
table = table,
|
||||||
|
|
||||||
dump = dump,
|
dump = dump,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,17 +32,29 @@ return {
|
||||||
local s = ''
|
local s = ''
|
||||||
local t = {
|
local t = {
|
||||||
msg = msg,
|
msg = msg,
|
||||||
print = function(...) s = s .. prind(...) end,
|
print = function(...)
|
||||||
|
s = s .. prind(...)
|
||||||
|
end,
|
||||||
C = owner and C or nil,
|
C = owner and C or nil,
|
||||||
api = owner and C.api or nil,
|
api = owner and C.api or nil
|
||||||
}
|
}
|
||||||
for k,v in pairs(env) do t[k] = v end
|
|
||||||
local e, err = load(table.concat(msg.args, ' '), 'eval', 't', t)
|
for k, v in pairs(env)
|
||||||
xpcall(function()
|
do t[k] = v
|
||||||
if err then error(err) end
|
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 '...')
|
e = tostring(e() or '...')
|
||||||
end, function(err) e = err end)
|
end), function(err)
|
||||||
C.api:send(msg, s .. '\n' .. e)
|
e = err
|
||||||
|
end)
|
||||||
|
s = s ..'\n'.. e
|
||||||
|
s = s:gsub(C.api.token:escp(), '<TOKEN>')
|
||||||
|
C.api:reply(msg, s)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
return {
|
return {
|
||||||
run = function(C, msg)
|
run = function(C, msg)
|
||||||
C.api:send(msg, msg.loc.pat:format(os.time() - msg.date))
|
local t = os.time()
|
||||||
|
local ps, ls = t - msg.date, t - C.loaded
|
||||||
|
local lm = ls / 60
|
||||||
|
local lh = lm / 60
|
||||||
|
local ld = lh / 24
|
||||||
|
C.api:send(msg, msg.loc.pat:format(ps, ld, lh, lm, ls))
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
32
src/cmds/reload.lua
Normal file
32
src/cmds/reload.lua
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
return {
|
||||||
|
private = true,
|
||||||
|
run = function(C, msg)
|
||||||
|
local cat, sub, arg = 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
|
||||||
|
|
||||||
|
if arg == '-off'
|
||||||
|
then C.api:reply(msg, 'Turned off')
|
||||||
|
else
|
||||||
|
local suc, m = pcall(require, path)
|
||||||
|
if not suc
|
||||||
|
then return C.api:reply(msg, 'Reload failed. '.. m)
|
||||||
|
end
|
||||||
|
if cat == 'events'
|
||||||
|
then C.api:on(sub, m)
|
||||||
|
elseif cat == 'cmds'
|
||||||
|
then C.cmds[sub] = m
|
||||||
|
else m(C)
|
||||||
|
end
|
||||||
|
C.api:reply(msg, 'Reloaded. '.. tostring(m))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
126
src/cmds/rub.lua
126
src/cmds/rub.lua
|
@ -1,61 +1,91 @@
|
||||||
-- It uses data from central bank of Russia
|
class 'Rub' {
|
||||||
--- and external service to get json from xml
|
url = 'https://api.factmaven.com/xml-to-json/?xml=https://www.cbr.ru/scripts/XML_daily.asp',
|
||||||
-- Privacy and security is unknown
|
pat = '%d %s (%s) - %f ₽',
|
||||||
|
|
||||||
local rub = {
|
function(this)
|
||||||
url = 'https://api.factmaven.com/xml-to-json/?xml='
|
this.tools = require 'api.tools'
|
||||||
.. 'https://www.cbr.ru/scripts/XML_daily.asp',
|
end,
|
||||||
|
|
||||||
tools = require 'etc.api.tools',
|
getPat = function(this, val)
|
||||||
|
return this.pat:format(val.Nominal, val.Name, val.CharCode, val.Value:gsub(',', '.'))
|
||||||
|
end,
|
||||||
|
|
||||||
|
course = function(this, wants)
|
||||||
|
local res, ok = this.tools._req(this.url, 'GET')
|
||||||
|
if not ok
|
||||||
|
then return 'err'
|
||||||
|
end
|
||||||
|
res = this.tools.json.decode(res or '{}')
|
||||||
|
res = res.ValCurs
|
||||||
|
if not res
|
||||||
|
then return 'err'
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pseudo-valutes
|
||||||
|
table.insert(res.Valute, {
|
||||||
|
ID = 'R01000',
|
||||||
|
NumCode = '001',
|
||||||
|
CharCode = 'RUB',
|
||||||
|
Nominal = 1,
|
||||||
|
Name = 'Российский рубль',
|
||||||
|
Value = '1',
|
||||||
|
})
|
||||||
|
local uah = table.findV(res.Valute, {CharCode = 'UAH'})
|
||||||
|
assert(uah, 'No UAH found')
|
||||||
|
table.insert(res.Valute, {
|
||||||
|
ID = 'R02000',
|
||||||
|
NumCode = '200',
|
||||||
|
CharCode = 'SHT',
|
||||||
|
Nominal = 1,
|
||||||
|
Name = 'Штаны',
|
||||||
|
Value = ('%f'):format(tonumber(uah.Value:gsub(',', '.'), nil) / uah.Nominal * 40), -- 40 UAH
|
||||||
|
})
|
||||||
|
|
||||||
|
local r, founds = {}, {}
|
||||||
|
if table.find(wants, 'ALL') then
|
||||||
|
for _, v in pairs(res.Valute)
|
||||||
|
do table.insert(r, this:getPat(v))
|
||||||
|
end
|
||||||
|
return r, res.Date, wants -- string, date, found
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, v in pairs(res.Valute) do
|
||||||
|
if table.find(wants, v.CharCode) then
|
||||||
|
table.insert(founds, v.CharCode)
|
||||||
|
table.insert(r, this:getPat(v))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r, res.Date, founds --
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
function rub:course(wants)
|
local rub = new 'Rub' ()
|
||||||
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'
|
|
||||||
})
|
|
||||||
|
|
||||||
wants = type(wants) == 'table' and wants or {}
|
|
||||||
local r, founds = {}, {}
|
|
||||||
|
|
||||||
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 {
|
return {
|
||||||
run = function(C, msg)
|
run = function(self, msg)
|
||||||
local wants = {'USD', 'EUR', table.unpack(msg.args)}
|
local wants = {
|
||||||
for i = 1, #wants do wants[i] = wants[i]:upper() end -- uppercase
|
'USD',
|
||||||
|
'EUR',
|
||||||
|
table.unpack(msg.args)
|
||||||
|
}
|
||||||
|
for i = 1, #wants do
|
||||||
|
wants[i] = wants[i]:upper()
|
||||||
|
end
|
||||||
local v, d, f = rub:course(wants)
|
local v, d, f = rub:course(wants)
|
||||||
if v == 'error' then
|
if v == 'err' then
|
||||||
return C.api:reply(msg, C.locale:get('error', 'req_err', msg.l))
|
return self.api:reply(msg, self.locale:get('error', 'req_err', msg.l))
|
||||||
end
|
end
|
||||||
|
local nf = { }
|
||||||
local nf = {}
|
|
||||||
for _, i in pairs(wants) do
|
for _, i in pairs(wants) do
|
||||||
if not table.find(f, i) then table.insert(nf, i) end
|
if not table.find(f, i) then
|
||||||
|
table.insert(nf, i)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local s = msg.loc.cur:format(d, table.concat(v, '\n'))
|
local s = msg.loc.cur:format(d, table.concat(v, '\n'))
|
||||||
if #nf > 0 then s = s .. msg.loc.notf .. table.concat(nf, ',') end
|
if #nf > 0 then
|
||||||
|
s = s .. msg.loc.notf .. table.concat(nf, ',')
|
||||||
C.api:reply(msg, s .. msg.loc.prov)
|
end
|
||||||
|
self.api:reply(msg, s .. msg.loc.prov)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/cmds/shell.lua
Normal file
16
src/cmds/shell.lua
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
return {
|
||||||
|
private = true,
|
||||||
|
run = function(C, msg)
|
||||||
|
local file = io.popen(C.api.unparseArgs(msg.args))
|
||||||
|
if file then
|
||||||
|
local r = file:read '*a'
|
||||||
|
file:close()
|
||||||
|
if #r == 0
|
||||||
|
then r = '...'
|
||||||
|
end
|
||||||
|
C.api:reply(msg, r)
|
||||||
|
else return C.api:reply(msg, 'error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
return {
|
return {
|
||||||
hide = true,
|
hide = true,
|
||||||
run = function(C, msg)
|
run = function(C, msg)
|
||||||
C.api:reply(msg, 'TODO!')
|
C.api:reply(msg, msg.loc.msg)
|
||||||
end
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
return function(C, api, msg)
|
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
|
local l = msg.from.language_code
|
||||||
|
local owner = msg.from.id == C.config.owner
|
||||||
|
local cmd = C.cmds[msg.cmd]
|
||||||
msg.l = l
|
msg.l = l
|
||||||
|
|
||||||
if cmd == nil then
|
if not cmd
|
||||||
api:send(msg, C.locale:get('error', 'inv_cmd', l))
|
then api:send(msg, C.locale:get('error', 'inv_cmd', l))
|
||||||
|
|
||||||
elseif type(cmd.run) ~= 'function' then
|
elseif type(cmd.run) ~= 'function'
|
||||||
api:send(msg, C.locale:get('error', 'cmd_run', l))
|
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))
|
|
||||||
|
|
||||||
|
elseif cmd.private and not owner
|
||||||
|
then api:send(msg, C.locale:get('error', 'adm_cmd', l))
|
||||||
else
|
else
|
||||||
|
if cmd.useQArgs
|
||||||
|
then msg.args = api.parseArgs(api.unparseArgs(msg.args))
|
||||||
|
end
|
||||||
msg.loc = C.locale:get('cmds', msg.cmd, l)
|
msg.loc = C.locale:get('cmds', msg.cmd, l)
|
||||||
local succ, err = pcall(cmd.run, C, msg, owner)
|
local suc, err = pcall(cmd.run, C, msg, owner)
|
||||||
if not succ then
|
if not suc then
|
||||||
print(err)
|
print(err)
|
||||||
local cid = C.config.owner
|
api:forward(C.config.owner, msg, msg.message_id, false)
|
||||||
api:forward(cid, msg.chat.id, msg.message_id, false)
|
api:send(C.config.owner, err)
|
||||||
api:send(cid, err)
|
|
||||||
api:reply(msg, C.locale:get('error', 'not_suc', l))
|
api:reply(msg, C.locale:get('error', 'not_suc', l))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
return function(C, api, q)
|
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'))
|
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',
|
||||||
|
api.inline.result('photo', '2',
|
||||||
|
'https://cdn.discordapp.com/attachments/710425649449402408/1002915343116795914/unknown.png'
|
||||||
|
):thumb 'https://cdn.discordapp.com/attachments/710425649449402408/1002915343116795914/unknown.png',
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
22
src/events/message.lua
Normal file
22
src/events/message.lua
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
local stick = {
|
||||||
|
{
|
||||||
|
'AgADwAADcpO1DQ',
|
||||||
|
'редебало',
|
||||||
|
'CAACAgIAAx0CUY2umQACFItiHHUg6w_MPu6Vs8k76cwn4OIHNQACwAADcpO1DVbNTDlmHOWMIwQ'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return function(C, api, msg)
|
||||||
|
if msg.from.is_premium then
|
||||||
|
api:reply(msg, 'Премак юзер, надо бы забанить. TODO БЛЯТЬ')
|
||||||
|
end
|
||||||
|
if msg.sticker then
|
||||||
|
for k, v in pairs(stick) do
|
||||||
|
if msg.sticker.file_unique_id == v[1] then
|
||||||
|
if math.random() <= 0.5
|
||||||
|
then api:reply(msg, v[2])
|
||||||
|
else api:sendSticker(msg, v[3])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,46 +1,78 @@
|
||||||
function table.indexOf(t, w)
|
-- Standard Library in bot
|
||||||
|
|
||||||
|
-- table.indexOf(table, value) - Get value of inverter value-key table.
|
||||||
|
function table.indexOf(t, val)
|
||||||
local i = {}
|
local i = {}
|
||||||
for k,v in pairs(t) do i[v] = k end
|
for k, v in pairs(t) do
|
||||||
return i[w]
|
i[v] = k
|
||||||
|
end
|
||||||
|
return i[val]
|
||||||
end
|
end
|
||||||
|
|
||||||
function table.find(t, w)
|
-- table.find(table, value) - Return index if value matches.
|
||||||
local i
|
function table.find(t, val)
|
||||||
for k,v in pairs(t) do
|
for k, v in pairs(t) do
|
||||||
if v == w then
|
if v == val then
|
||||||
i = k
|
return k
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return i
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- table.findV(table, value) - return value in table matching value table
|
||||||
|
function table.findV(t, val)
|
||||||
|
local b = nil
|
||||||
|
for _, v in pairs(t) do
|
||||||
|
for k, x in pairs(val) do
|
||||||
|
if x ~= v[k] then
|
||||||
|
b = 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if b then
|
||||||
|
b = nil
|
||||||
|
else
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- string.escp(string) - Escape reserved regex values
|
||||||
|
function string.escp(s)
|
||||||
|
return s:gsub('[%^%$%%%(%)%.%[%]%*%+%-%?]', '%%%0')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- dump(table, depth?) - Return string that shows table contents.
|
||||||
function dump(t, d)
|
function dump(t, d)
|
||||||
if not tonumber(d) or d < 0 then d = 0 end
|
if not tonumber(d) or d < 0 then
|
||||||
|
d = 0
|
||||||
|
end
|
||||||
local c = ''
|
local c = ''
|
||||||
for k,v in pairs(t) do
|
for k, v in pairs(t) do
|
||||||
if type(v) == 'table' then v = '\n' .. dump(v, d + 1) end
|
if type(v) == 'table' then
|
||||||
c = c .. string.format('%s%s = %s\n', (' '):rep(d), k, v)
|
v = '\n' .. dump(v, d + 1)
|
||||||
|
elseif type(v) == 'userdata' then
|
||||||
|
v = '<USERDATA>'
|
||||||
|
end
|
||||||
|
c = c .. ('%s%s = %s\n'):format((' '):rep(d), k, v)
|
||||||
end
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
|
||||||
return function(C, api)
|
return function(C, api)
|
||||||
C:load 'cmds'
|
C:load 'cmds'
|
||||||
local a = {}
|
|
||||||
for k, v in pairs(C.cmds) do
|
|
||||||
if not (v.private or v.hide) then
|
|
||||||
local cmd = C.locale:get('cmds', k) 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)
|
|
||||||
|
|
||||||
a = {'levels', }
|
for _, lang in pairs(C.locale.list) do
|
||||||
for i = 1, #a do
|
local a = {}
|
||||||
if not C.db[a[i]] then C.db[a[i]] = {} end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
40
src/locales/ar.json
Normal file
40
src/locales/ar.json
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"error": {
|
||||||
|
"inv_cmd": "تم تحديد أمر غير معروف.",
|
||||||
|
"adm_cmd": "لا يمكنك تنفيذ أوامر المسؤول!",
|
||||||
|
"cmd_run": "لا يمكن تنفيذ هذا الأمر الآن.",
|
||||||
|
"not_suc": "حدث خطأ وتم إرساله إلى المنشئ.",
|
||||||
|
"unk_err": "خطأ غير معروف.",
|
||||||
|
"req_err": "فشل الطلب."
|
||||||
|
},
|
||||||
|
"cmds": {
|
||||||
|
"not_des": "بدون وصف",
|
||||||
|
|
||||||
|
"eval": {
|
||||||
|
"args": "<الرمز>",
|
||||||
|
"desc": "ينفذ الكود"
|
||||||
|
},
|
||||||
|
"shell": {
|
||||||
|
"args": "<الرمز>",
|
||||||
|
"desc": "ينفذ التعليمات البرمجية في غلاف يونكس"
|
||||||
|
},
|
||||||
|
"ping": {
|
||||||
|
"desc": "بينج بونج",
|
||||||
|
|
||||||
|
"pat": "بونغ! %d ثانية. الجهوزية: %.1f يوم (%.1f ساعة ، %.1f دقيقة)"
|
||||||
|
},
|
||||||
|
"rub": {
|
||||||
|
"args": "[عملة]...",
|
||||||
|
"desc": "سعر صرف الروبل",
|
||||||
|
|
||||||
|
"cur": "متوجها %s:\n%s",
|
||||||
|
"notf": "\n لا يوجد لا تجد: ",
|
||||||
|
"prov": "\n البيانات مقدمة من البنك المركزي لروسيا."
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"desc": "بداية العمل",
|
||||||
|
|
||||||
|
"msg": "يا! أنا Computer - بوت مفتوح المصدر.\n إذا كنت تبحث عن مصادر: https://gitdab.com/er2/comp-tg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,10 +14,14 @@
|
||||||
"args": "<code>",
|
"args": "<code>",
|
||||||
"desc": "executes code"
|
"desc": "executes code"
|
||||||
},
|
},
|
||||||
|
"shell": {
|
||||||
|
"args": "<code>",
|
||||||
|
"desc": "executes code in Unix shell"
|
||||||
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"desc": "ping pong",
|
"desc": "ping pong",
|
||||||
|
|
||||||
"pat": "Pong! %ds"
|
"pat": "Pong! %ds. Uptime: %.1f days (%.1fh, %.1fm.)"
|
||||||
},
|
},
|
||||||
"rub": {
|
"rub": {
|
||||||
"args": "[valute]...",
|
"args": "[valute]...",
|
||||||
|
@ -26,6 +30,11 @@
|
||||||
"cur": "Currency at %s:\n%s",
|
"cur": "Currency at %s:\n%s",
|
||||||
"notf": "\nNot found: ",
|
"notf": "\nNot found: ",
|
||||||
"prov": "\nData provided from central bank of Russia."
|
"prov": "\nData provided from central bank of Russia."
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"desc": "getting started",
|
||||||
|
|
||||||
|
"msg": "Hi! I'm Computer - an open-source bot.\nIf you looking for source code: https://gitdab.com/er2/comp-tg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,14 @@
|
||||||
"args": "<код>",
|
"args": "<код>",
|
||||||
"desc": "исполняет код"
|
"desc": "исполняет код"
|
||||||
},
|
},
|
||||||
|
"shell": {
|
||||||
|
"args": "<код>",
|
||||||
|
"desc": "исполняет код в Unix shell"
|
||||||
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
"desc": "пинг-понг",
|
"desc": "пинг-понг",
|
||||||
|
|
||||||
"pat": "Понг! %d секунд"
|
"pat": "Понг! %dс. В сети: %.1f дней (%.1fч, %.1fм.)"
|
||||||
},
|
},
|
||||||
"rub": {
|
"rub": {
|
||||||
"args": "[валюта]...",
|
"args": "[валюта]...",
|
||||||
|
@ -26,6 +30,11 @@
|
||||||
"cur": "Курс на %s:\n%s",
|
"cur": "Курс на %s:\n%s",
|
||||||
"notf": "\nНе нашлось: ",
|
"notf": "\nНе нашлось: ",
|
||||||
"prov": "\nДанные предоставлены центральным банком России."
|
"prov": "\nДанные предоставлены центральным банком России."
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"desc": "начало работы",
|
||||||
|
|
||||||
|
"msg": "Привет! Я Computer - бот с открытым исходным кодом.\nЕсли ты ищешь исходники: https://gitdab.com/er2/comp-tg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,29 @@
|
||||||
local tg = require 'etc.api'
|
require 'etc.api'
|
||||||
|
|
||||||
return function(Core)
|
|
||||||
local self = Core
|
|
||||||
|
|
||||||
self.api = tg { norun = true }
|
|
||||||
self.cmds = {}
|
|
||||||
|
|
||||||
|
return function(C)
|
||||||
|
C.api = new 'API' {
|
||||||
|
norun = true,
|
||||||
|
}
|
||||||
print 'Client initialization...'
|
print 'Client initialization...'
|
||||||
|
C.api._ev = function(_, t, i, name, ...)
|
||||||
function Core._ev(ev, ...) self:ev(...) end
|
return C:_ev(t, i, name, C.api, ...)
|
||||||
function self.api._ev(_, t, i, n, ...)
|
|
||||||
self._ev(_, t, i, n, self.api, ...)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self:load 'events'
|
C:load 'events'
|
||||||
|
|
||||||
self.api:login(self.config.token, function()
|
C.api:login(C.config.token, function()
|
||||||
print('Logged on as @' .. self.api.info.username)
|
print('Logged on as @'.. C.api.info.username)
|
||||||
self.config.token = nil
|
C.config.token = nil
|
||||||
self.api:emit 'ready'
|
C.api:emit 'ready'
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local offs, o = 0
|
local offset = 0
|
||||||
self.api.runs = true
|
C.api.runs = true
|
||||||
self:on('ready', function()
|
C:on('ready', function()
|
||||||
while self.api.runs do
|
while C.api.runs do
|
||||||
self:emit 'tick'
|
C:emit 'tick'
|
||||||
|
offset = C.api:recvUpdate(1, offset, 0)
|
||||||
o = self.api:_getUpd(1, offs, 0)
|
|
||||||
offs = o and o or offs
|
|
||||||
end
|
end
|
||||||
self.api:getUpdates(1, offs, 0)
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,62 @@
|
||||||
local config = require 'config'
|
local config = require 'config'
|
||||||
|
require 'etc.events'
|
||||||
|
require 'class'
|
||||||
|
|
||||||
local Core = {
|
class 'Core' : inherits 'EventsThis' {
|
||||||
config = config,
|
config = config,
|
||||||
}
|
loaded = 0,
|
||||||
(require 'etc.events')(Core) -- add events
|
cmds = {},
|
||||||
|
|
||||||
function Core:load(what)
|
function(this)
|
||||||
local c = config[what]
|
this:super()
|
||||||
local s = #c
|
this:load 'parts'
|
||||||
for i = 1, s do
|
utf8 = require 'etc.utf8'
|
||||||
local v = c[i]
|
require 'etc.utf8data'
|
||||||
|
utf8.config = {
|
||||||
|
conversion = {
|
||||||
|
uc_lc = utf8_uc_lc,
|
||||||
|
lc_uc = utf8_lc_uc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utf8:init()
|
||||||
|
print 'Done!'
|
||||||
|
this:emit 'ready'
|
||||||
|
end,
|
||||||
|
|
||||||
print(('Loading %s (%d / %d) %s...'):format(what:sub(0, -2), i, s, v))
|
stop = function(this)
|
||||||
-- Lint
|
this.api:destroy()
|
||||||
if true then
|
print 'Stopped'
|
||||||
--pcall(require, 'src.'.. what ..'.'.. v) then
|
print('Uptime: ' .. (os.time() - self.loaded) .. ' seconds')
|
||||||
local a=require('src.'.. what ..'.'.. v)
|
end,
|
||||||
if what == 'events' then self.api:on(v, a)
|
|
||||||
elseif what == 'cmds' then self.cmds[v] = a
|
load = function(this, what)
|
||||||
elseif what == 'parts' then a(self)
|
local c = config[what]
|
||||||
|
for i = 1, #c do
|
||||||
|
local v = c[i]
|
||||||
|
print('Loading ' .. what:sub(0, -2) ..' (' .. i ..' / '.. #c ..') ' .. v ..'...')
|
||||||
|
|
||||||
|
-- Lint?
|
||||||
|
local e, a = pcall(require, 'src.' .. what ..'.'.. v)
|
||||||
|
print(e, a)
|
||||||
|
|
||||||
|
if e then
|
||||||
|
if what == 'events'
|
||||||
|
then this.api:on(v, a)
|
||||||
|
|
||||||
|
elseif what == 'cmds'
|
||||||
|
then this.cmds[v] = a
|
||||||
|
|
||||||
|
elseif what == 'parts'
|
||||||
|
then a(this)
|
||||||
|
end
|
||||||
|
|
||||||
|
else print 'fail'
|
||||||
end
|
end
|
||||||
else print 'fail' end
|
|
||||||
end
|
|
||||||
print(('Loaded %d %s'):format(s, what))
|
|
||||||
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
|
end
|
||||||
if v.type == 'once' then table.remove(t, i) end
|
print('Loaded '.. #c ..' '.. what)
|
||||||
end
|
this.loaded = os.time()
|
||||||
end
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
function Core:init()
|
local core = new 'Core' ()
|
||||||
self:load 'parts'
|
|
||||||
|
|
||||||
print 'Done!'
|
|
||||||
self:emit 'ready'
|
|
||||||
end
|
|
||||||
|
|
||||||
Core:init()
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
return function(Core)
|
|
||||||
local path = 'etc/db' -- from root
|
|
||||||
local time = 60 * 5 -- 5min
|
|
||||||
|
|
||||||
Core.db = require 'etc.db' (path)
|
|
||||||
|
|
||||||
local t = os.time()
|
|
||||||
Core:on('tick', function()
|
|
||||||
if os.time() - t >= time then
|
|
||||||
t = os.time()
|
|
||||||
print 'saving...'
|
|
||||||
Core.db:save()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,33 +1,36 @@
|
||||||
local Locale = {
|
class 'Locale' {
|
||||||
|
__newindex = function() end,
|
||||||
list = {
|
list = {
|
||||||
'en',
|
'en',
|
||||||
'ru'
|
'ru',
|
||||||
|
'ar',
|
||||||
},
|
},
|
||||||
main = 'en',
|
main = 'en',
|
||||||
|
|
||||||
__newindex = function()end -- ro
|
__init = function(this)
|
||||||
|
local json = require 'etc.json'
|
||||||
|
for i = 1, #this.list do
|
||||||
|
local n = this.list[i]
|
||||||
|
local f = io.open('src/locales/'.. n ..'.json')
|
||||||
|
this[n] = json.decode(f:read 'a')
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
function(this, C)
|
||||||
|
C.locale = this
|
||||||
|
end,
|
||||||
|
|
||||||
|
get = function(this, category, key, lang)
|
||||||
|
assert(category, 'Category not provided')
|
||||||
|
assert(key, 'Key not provided')
|
||||||
|
lang = lang or this.main
|
||||||
|
local v = (this[lang] or {})[category]
|
||||||
|
if not v
|
||||||
|
then return this[this.main][category][key] or ''
|
||||||
|
else return v[key] or ''
|
||||||
|
end
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
Locale.__index = Locale
|
|
||||||
|
|
||||||
function Locale:get(cat, k, lang)
|
return new 'Locale'
|
||||||
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
|
|
||||||
|
|
Loading…
Reference in a new issue