Compare commits
	
		
			No commits in common. "14ba3d7a003b5a52de970bc06fd55ccff7062250" and "7e8b53a20735fddf7305ddefc02226986be4b684" have entirely different histories.
		
	
	
		
			14ba3d7a00
			...
			7e8b53a207
		
	
		
					 26 changed files with 417 additions and 394 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -2,4 +2,3 @@ | |||
| *~ | ||||
| \#*# | ||||
| 
 | ||||
| src/*/*.lua | ||||
|  |  | |||
|  | @ -15,8 +15,6 @@ and use it or fallback to English. | |||
| Bot uses an OOP-style of Lua | ||||
| 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. | ||||
| 
 | ||||
| * Installation | ||||
|  | @ -29,8 +27,6 @@ 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 MoonScript: ~luarocks-5.1 install moonscript~ | ||||
| 
 | ||||
|   + Create user: ~adduser user~ | ||||
| 
 | ||||
|     setup it (add to doas) and login to this user | ||||
|  | @ -41,8 +37,6 @@ Maybe I will rewrite bot's core to C but here already so many Lua code. | |||
| 
 | ||||
|   + 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~ | ||||
| 
 | ||||
|   + Configure it ~doas vi /etc/init.d/mybot~ (change user) | ||||
|  |  | |||
							
								
								
									
										51
									
								
								src/cmds/eval.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/cmds/eval.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | |||
| 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 | ||||
| } | ||||
|  | @ -1,54 +0,0 @@ | |||
| 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 | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/cmds/ping.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/cmds/ping.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| 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 | ||||
| } | ||||
|  | @ -1,10 +0,0 @@ | |||
| { | ||||
|   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 | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/cmds/reload.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/cmds/reload.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | |||
| 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 | ||||
| } | ||||
|  | @ -1,23 +0,0 @@ | |||
| { | ||||
|   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 | ||||
| } | ||||
							
								
								
									
										79
									
								
								src/cmds/rub.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/cmds/rub.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| -- 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 | ||||
| } | ||||
|  | @ -1,74 +0,0 @@ | |||
| -- 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 | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/cmds/start.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/cmds/start.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| return { | ||||
|   hide = true, | ||||
|   run = function(C, msg) | ||||
|     C.api:reply(msg, msg.loc.msg) | ||||
|   end | ||||
| } | ||||
|  | @ -1,6 +0,0 @@ | |||
| { | ||||
|   hide: true | ||||
|   run: (msg) => | ||||
|     @api\reply msg, msg.loc.msg | ||||
|     return | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/events/command.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/events/command.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| 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 | ||||
|  | @ -1,28 +0,0 @@ | |||
| (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 | ||||
							
								
								
									
										8
									
								
								src/events/inlineQuery.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/events/inlineQuery.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| 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 | ||||
|  | @ -1,6 +0,0 @@ | |||
| (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 | ||||
							
								
								
									
										25
									
								
								src/events/message.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/events/message.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| 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 | ||||
|  | @ -1,22 +0,0 @@ | |||
| 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 | ||||
							
								
								
									
										61
									
								
								src/events/ready.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/events/ready.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| 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 | ||||
|  | @ -1,50 +0,0 @@ | |||
| 
 | ||||
| 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 | ||||
							
								
								
									
										35
									
								
								src/parts/client.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/parts/client.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| 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 | ||||
|  | @ -1,32 +0,0 @@ | |||
| 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 | ||||
							
								
								
									
										57
									
								
								src/parts/core.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/parts/core.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,57 @@ | |||
| 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() | ||||
|  | @ -1,52 +0,0 @@ | |||
| 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 | ||||
							
								
								
									
										33
									
								
								src/parts/locale.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/parts/locale.lua
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| 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 | ||||
|  | @ -1,30 +0,0 @@ | |||
| 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue