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…
	
	Add table
		Add a link
		
	
		Reference in a new issue