add readme, some code refactoring

This commit is contained in:
Er2 2021-07-19 10:55:01 +03:00
parent 7f68524d5a
commit 49fa684f47
13 changed files with 162 additions and 80 deletions

View File

@ -1,4 +1,4 @@
zlib License
Zlib License
Copyright (c) 2021 Er2 <er2@dismail.de>

25
README.md Normal file
View File

@ -0,0 +1,25 @@
# Computer bot
This bot is a reborn of [this](https://github.com/Er2pkg/computer) bot,
but on Telegram.
Bot uses an OOP-style of lua
as [described on Wikipedia](https://is.gd/f0Vadk)
TODO: Rewrite core to C, [lua have C API](https://www.lua.org/manual/5.3/manual.html#4)
and C is faster.
# Installation
[Alpine Linux](https://alpinelinux.org), root:
* Enable community repo (in wiki)
* Install: `apk add sudo git lua5.3 luarocks openssl-dev`
* Install dependencies: `luarocks-5.3 install luasec`
* Create user: `adduser user`
setup sudo and login to user
* Get repo: `git clone https://github.com/Er2ch/comp-tg`
and `cd comp-tg`
* Change token and owner in `config.lua`
TODO: Use env instaed of config
* Run: `lua5.3 init.lua`

View File

@ -8,7 +8,7 @@
}
function rub:course(wants, fmt)
local resp, succ = (require'tg.tools').requ(self.url)
local resp, succ = (require'core.tools').requ(self.url)
if not succ then
return {}, '[ошибка]', {}
end
@ -61,4 +61,4 @@ return {
args = '[valute]...',
desc = 'ruble course',
run = rub.msg
}
}

View File

@ -1,14 +1,18 @@
-- API Library
--- (c) Er2 <er2@dismail.de>
--- Zlib License
--[[ API Library
-- (c) Er2 2021 <er2@dismail.de>
-- Zlib License
--]]
local tools = require 'tg.tools'
local json = require 'tg.json'
local api = {
request = function(self, ...) return tools.request(self.token, ...) end,
}
local tools =require 'core.tools'
local json = require 'core.json'
local events=require 'core.events'
local api = { _ev_ = {} }
api.__index = api -- Make class
events(api) -- inheritance
function api:request(...) return tools.request(self.token, ...) end
-- Getters without params
function api:getMe() return self:request 'getMe' end
@ -94,4 +98,4 @@ function api:setMyCommands(cmds)
return self:request('setMyCommands', { commands = json.encode(cmds) })
end
return api
return api

View File

@ -1,23 +1,19 @@
-- Core file
--- (c) Er2 <er2@dismail.de>
--- Zlib License
--[[ Core file
-- (c) Er2 2021 <er2@dismail.de>
-- Zlib License
--]]
local tools = require 'tg.tools'
local api = require 'tg.api'
api.__index = api -- Make class
local tools = require 'core.tools'
local api = require 'core.api'
api.__index = api
-- EVENT PROTOTYPES --
function api.onCommand(_) end
function api.onChannelPost(_) end
function api.onChannelPostEdit(_) end
function api.onMessage(_) end
function api.onMessageEdit(_) end
function api.onInlineResult(_) end
function api.onPoll(_) end
function api.onPollAnswer(_) end
function api.onReady(_) end
function api.onQuery(_) end
function api.onUpdate(_) end
function api:_ev(t, i, name, ...)
local v = t[i]
if v.name == name then
v.fn(self, ...)
if v.type == 'once' then table.remove(t, i) end
end
end
-- UPDATES --
function api:getUpdates(lim, offs, tout, allowed)
@ -31,7 +27,7 @@ function api:getUpdates(lim, offs, tout, allowed)
end
local function receiveUpdate(self, update)
if update then self:onUpdate(update) end
if update then self:emit('update', update) end
if update.message then
local txt = update.message.text
@ -43,26 +39,27 @@ local function receiveUpdate(self, update)
update.message.cmd = cmd
update.message.args = args
return self:onCommand(update.message, update.message.chat.type)
return self:emit('command', update.message)
elseif cmd then return end
self:onMessage(update.message, update.message.chat.type)
self:emit('message', update.message)
elseif update.edited_message then
self:onMessageEdit(update.edited_message, update.edited_message.chat.type)
self:emit('messageEdit', update.edited_message)
elseif update.channel_post then self:onChannelPost(update.channel_post)
elseif update.edited_channel_post then self:onChannelPostEdit(update.edited_channel_post)
elseif update.channel_post then self:emit('channelPost', update.channel_post)
elseif update.edited_channel_post then self:emit('channelPostEdit', update.edited_channel_post)
elseif update.poll then self:onPoll(update.poll)
elseif update.poll_answer then self:onPollAnswer(update.poll_answer)
elseif update.poll then self:emit('poll', update.poll)
elseif update.poll_answer then self:emit('pollAnswer', update.poll_answer)
elseif update.callback_query then self:onQuery('callback', update.callback_query)
elseif update.inline_query then self:onQuery('inline', update.inline_query)
elseif update.shipping_query then self:onQuery('shipping', update.shipping_query)
elseif update.pre_checkout_query then self:onQuery('preCheckout', update.pre_checkout_query)
elseif update.callback_query then self:emit('callbackQuery', update.callback_query)
elseif update.inline_query then self:emit('inlineQuery', update.inline_query)
elseif update.shipping_query then self:emit('shippingQuery', update.shipping_query)
elseif update.pre_checkout_query then self:emit('preCheckoutQuery', update.pre_checkout_query)
elseif update.chosen_inline_result then self:onInlineResult(update.chosen_inline_result)
elseif update.chosen_inline_result then self:emit('inlineResult', update.chosen_inline_result)
end
end
@ -91,7 +88,7 @@ function api:run(lim, offs, tout, al)
tout = tonumber(tout) or 0
self.runs = true
self:onReady()
self:emit('ready')
self.co = coroutine.create(api._loop)
coroutine.resume(self.co, self, lim, tout, offs, al)
@ -117,6 +114,7 @@ end
return function(opts)
if not token or type(token) ~= 'string' then token = nil end
local self = setmetatable({}, api)
if not opts then return self end
@ -124,4 +122,4 @@ return function(opts)
if opts.norun then self.nr = true end
return self
end
end

39
core/events.lua Normal file
View File

@ -0,0 +1,39 @@
--[[ Events library
-- (c) Er2 2021 <er2@dismail.de>
-- Zlib License
--]]
local events = {}
events.__index = events
function events:_add(t, n, f)
table.insert(self._ev_, {
type = t,
name = n,
fn = f,
})
end
function events:on(n,f) self:_add('on', n,f) end
function events:once(n,f) self:_add('once', n,f) end
function events:_ev(t, i, name, ...)
local v = t[i]
if v.name == name then
v.fn(...)
if v.type == 'once' then table.remove(t, i) end
end
end
function events:emit(name, ...)
local t = self._ev_
for i = 1, #t do
local v = t[i] or {}
if type(v) == 'table'
and type(v.type) == 'string'
and type(v.fn) == 'function'
then self:_ev(t, i, name, ...) end
end
end
return function(t) return setmetatable(t, events) end

1
core/init.lua Normal file
View File

@ -0,0 +1 @@
return require 'core.core'

View File

@ -1,5 +1,10 @@
--[[ Additional tools
-- (c) Er2 2021 <er2@dismail.de>
-- Zlib license
--]]
local tools = {
json = require 'tg.json',
json = require 'core.json',
}
local json = tools.json
@ -7,11 +12,9 @@ local https = require 'ssl.https'
local ltn12 = require 'ltn12'
function tools.fetchCmd(text)
local cmd = text:match '/[%w_]+'
local to = text:match '/[%w_]+(@[%w_]+)'
if to then to = to:sub(2) end
if cmd then cmd = cmd:sub(2) end
return cmd, to
return
text:match '/([%w_]+)', -- cmd
text:match '/[%w_]+@([%w_]+)' -- to
end
-- https://gist.github.com/liukun/f9ce7d6d14fa45fe9b924a3eed5c3d99
@ -23,7 +26,14 @@ function tools.urlencode(url)
return url
end
function tools.req(url)
function tools.req(url, par)
if type(par) == 'table' then
url = url .. '?'
for k,v in pairs(par) do
url = url ..'&'.. k ..'='.. tools.urlencode(tostring(v))
end
end
local resp = {}
local succ, res = https.request {
url = url,
@ -38,9 +48,9 @@ function tools.req(url)
return resp[1], true
end
function tools.requ(url, dbg)
local res, succ = tools.req(url)
if dbg then print(succ, res) end
function tools.requ(url, par, dbg)
local res, succ = tools.req(url, par)
if dbg then print(url, succ, res) end
res = json.decode(res or '{}')
if not succ or not res then return {}, false end
return res, true
@ -50,16 +60,11 @@ function tools.request(token, endpoint, param, dbg)
assert(token, 'Provide token!')
assert(endpoint, 'Provide endpoint!')
local params = ''
for k, v in pairs(param or {}) do
params = params .. '&' .. k .. '=' .. tools.urlencode(tostring(v))
end
local url = 'https://api.telegram.org/bot' .. token .. '/' .. endpoint
if #params > 1 then url = url .. '?' .. params:sub(2) end
local resp = tools.requ(url, dbg)
-- dbg = true
local resp = tools.requ(url, param, dbg)
return resp, resp.ok or false
end
return tools
return tools

4
db/.gitignore vendored
View File

@ -1,4 +1,4 @@
*
!.gitignore
!db.lua
!mp.lua
!init.lua
!mp.lua

View File

@ -1,8 +1,8 @@
local config = require 'config'
local Core = {
db = require 'db.db' ('db'),
tg = require 'tg',
db = require 'db' ('db'), -- db with name db
tg = require 'core',
tools = tools,
config = config,
cmds = {},
@ -14,33 +14,44 @@ function Core:load(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))
if not pcall(require, what .. '.' .. v) then print 'fail'; goto f end
local a = require(what .. '.' .. v)
if what == 'events' then
self.api['on' .. v:sub(1, 1):upper() .. v:sub(2)] = function(...)
local succ = pcall(a, self, ...)
if not succ then print('event ' .. v .. ' was failed') end
print(('Loading %s (%d / %d) %s...'):format(what:sub(0, -2), i, s, v))
-- Lint
if pcall(require, what ..'.'.. v) then
local a=require(what ..'.'.. v)
if what == 'events' then self.api:on(v, a)
elseif what == 'cmds' then self.cmds[v] = a
end
elseif what == 'cmds' then self.cmds[v] = a
end
::f::
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 = pcall(v.fn, self, ...)
if not succ then print('event "' .. name .. '" was failed') end
if v.type == 'once' then table.remove(t, i) end
end
end
function Core:init()
self.api = tg {norun = true}
print 'Client initialization...'
self.api._ev = function(s, t, i, name, ...)
-- print(s, t, i, name)
self:ev(t, i, name, s, ...)
end
self:load 'events'
self.api:login(config.token, function()
print('Logged on as @' .. self.api.info.username)
self.config.token = nil
self.api:onReady()
self.api:emit('ready')
end)
print 'Done!'
@ -61,4 +72,4 @@ function Core:init()
self.api:getUpdates(1, offs, 0)
end
Core:init()
Core:init()

View File

@ -1 +0,0 @@
return require 'tg.core'