split api
This commit is contained in:
		
							parent
							
								
									2b27291cfc
								
							
						
					
					
						commit
						f2db621150
					
				
					 9 changed files with 7 additions and 697 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | [submodule "etc/api"] | ||||||
|  | 	path = etc/api | ||||||
|  | 	url = https://gitdab.com/er2/tg-api-lua | ||||||
|  | 
 | ||||||
							
								
								
									
										1
									
								
								etc/api
									
										
									
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								etc/api
									
										
									
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | Subproject commit 30f7203c5fe69e875dbd29a4da9fe0c5ab1ddc9b | ||||||
							
								
								
									
										137
									
								
								etc/api/api.lua
									
										
									
									
									
								
							
							
						
						
									
										137
									
								
								etc/api/api.lua
									
										
									
									
									
								
							|  | @ -1,137 +0,0 @@ | ||||||
| --[[ API Library |  | ||||||
|   -- (c) Er2 2021 <er2@dismail.de> |  | ||||||
|   -- Zlib License |  | ||||||
| --]] |  | ||||||
| 
 |  | ||||||
| local tools  = require 'etc.api.tools' |  | ||||||
| local json   = require 'etc.json' |  | ||||||
| local events = require 'etc.events' |  | ||||||
| local api    = { |  | ||||||
|   request    = function(s, ...) return tools.request(s.token, ...) end |  | ||||||
| } |  | ||||||
| api.__index = api -- Make class |  | ||||||
| events(api)       -- inheritance |  | ||||||
| 
 |  | ||||||
| -- parse arguments |  | ||||||
| local function argp(cid, rmp, pmod, dwp) |  | ||||||
|   return |  | ||||||
|     type(cid) == 'table' and cid.chat.id or cid, |  | ||||||
|     type(rmp) == 'table' and json.encode(rmp) or rmp, |  | ||||||
|     (type(pmod) == 'boolean' and pmod == true) and 'MarkdownV2' or pmod, |  | ||||||
|     dwp == nil and true or dwp |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| -- Getters without params |  | ||||||
| 
 |  | ||||||
| function api:getMe() return self:request 'getMe' end |  | ||||||
| function api:getMyCommands() return self:request 'getMyCommands' end |  | ||||||
| 
 |  | ||||||
| -- Getters with params |  | ||||||
| 
 |  | ||||||
| function api:getChat(cid) return self:request('getChat', {chat_id = cid}) end |  | ||||||
| 
 |  | ||||||
| -- Setters |  | ||||||
| 
 |  | ||||||
| function api:send(msg, txt, pmod, dwp, dnot, rtmid, rmp) |  | ||||||
|   msg, rmp, pmod, dwp = argp(msg, rmp, pmod, dwp) |  | ||||||
| 
 |  | ||||||
|   if txt and #txt >= 4096 then |  | ||||||
|     txt = txt:sub(0, 4092) .. '...' |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   return self:request('sendMessage', { |  | ||||||
|     chat_id = msg, |  | ||||||
|     text = txt, |  | ||||||
|     parse_mode = pmod, |  | ||||||
|     disable_web_page_preview = dwp, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     reply_to_message_id = rtmid, |  | ||||||
|     reply_markup = rmp, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:reply(msg, txt, pmod, dwp, rmp, dnot) |  | ||||||
|   _, rmp, pmod, dwp = argp(msg, rmp, pmod, dwp) |  | ||||||
|   return self:request('sendMessage', { |  | ||||||
|     chat_id = msg.chat.id, |  | ||||||
|     text = txt, |  | ||||||
|     parse_mode = pmod, |  | ||||||
|     disable_web_page_preview = dwp, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     reply_to_message_id = msg.message_id, |  | ||||||
|     reply_markup = rmp, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:forward(cid, frcid, mid, dnot) |  | ||||||
|   return self:request('forwardMessage', { |  | ||||||
|     chat_id = cid, |  | ||||||
|     from_chat_id = frcid, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     message_id = mid, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:sendPhoto(cid, f, cap, pmod, dnot, rtmid, rmp) |  | ||||||
|   cid, rmp, pmod = argp(cid, rmp, pmod) |  | ||||||
|   return self:request('sendPhoto', { |  | ||||||
|     chat_id = cid, |  | ||||||
|     caption = cap, |  | ||||||
|     parse_mode = pmod, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     reply_to_message_id = rtmid, |  | ||||||
|     reply_markup = rmp, |  | ||||||
|   }, { photo = f }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:sendDocument(cid, f, cap, pmod, dnot, rtmid, rmp) |  | ||||||
|   cid, rmp, pmod = argp(cid, rmp, pmod) |  | ||||||
|   return self:request('sendDocument', { |  | ||||||
|     chat_id = cid, |  | ||||||
|     caption = cap, |  | ||||||
|     parse_mode = pmod, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     reply_to_message_id = rtmid, |  | ||||||
|     reply_markup = rmp, |  | ||||||
|   }, { document = f }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:sendPoll(cid, q, opt, anon, ptype, mansw, coptid, expl, pmode, oper, cdate, closed, dnot, rtmid, rmp) |  | ||||||
|   cid, rmp, pmode = argp(cid, rmp, pmode) |  | ||||||
|   opt = type(opt) == 'string' and opt or json.encode(opt) |  | ||||||
|   anon = type(anon) == 'boolean' and anon or false |  | ||||||
|   mansw = type(mansw) == 'boolean' and mansw or false |  | ||||||
|   return self:request('sendPoll', { |  | ||||||
|     chat_id = cid, |  | ||||||
|     question = q, |  | ||||||
|     options = opt, |  | ||||||
|     is_anonymous = anon, |  | ||||||
|     type = ptype, |  | ||||||
|     allows_multiple_answers = mansw, |  | ||||||
|     correct_option_id = coptid, |  | ||||||
|     explanation = expl, |  | ||||||
|     explanation_parse_mode = pmode, |  | ||||||
|     open_period = oper, |  | ||||||
|     close_date = cdate, |  | ||||||
|     is_closed = closed, |  | ||||||
|     disable_notification = dnot, |  | ||||||
|     reply_to_message_id = rtmid, |  | ||||||
|     reply_markup = rmp, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:answerCallback(id, txt, alrt, url, ctime) |  | ||||||
|   return self:request('answerCallbackQuery', { |  | ||||||
|     callback_query_id = id, |  | ||||||
|     text = txt, |  | ||||||
|     show_alert = alrt, |  | ||||||
|     url = url, |  | ||||||
|     cache_time = ctime, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:setMyCommands(cmds) |  | ||||||
|   return self:request('setMyCommands', { commands = json.encode(cmds) }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return api |  | ||||||
							
								
								
									
										133
									
								
								etc/api/core.lua
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								etc/api/core.lua
									
										
									
									
									
								
							|  | @ -1,133 +0,0 @@ | ||||||
| --[[ Core file |  | ||||||
|   -- (c) Er2 2021 <er2@dismail.de> |  | ||||||
|   -- Zlib License |  | ||||||
| --]] |  | ||||||
| 
 |  | ||||||
| local tools = require 'etc.api.tools' |  | ||||||
| local api = require 'etc.api.api' |  | ||||||
| api.__index = api |  | ||||||
| 
 |  | ||||||
| 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) |  | ||||||
|   allowed = type(allowed) == 'table' and tools.json.encode(allowed) or allowed |  | ||||||
|   return self:request('getUpdates', { |  | ||||||
|     timeout = tout, |  | ||||||
|     offset = offs, |  | ||||||
|     limit = lim, |  | ||||||
|     allowed_updates = allowed |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function receiveUpdate(self, update) |  | ||||||
|   if update.message then |  | ||||||
|     local msg = update.message |  | ||||||
|     local cmd, to = tools.fetchCmd(msg.text or '') |  | ||||||
|     if cmd and (not to or to == self.info.username) then |  | ||||||
|       -- need /cmd@bot in groups |  | ||||||
|       if (msg.chat.type == 'group' or msg.chat.type == 'supergroup') |  | ||||||
|        and not to then return end |  | ||||||
| 
 |  | ||||||
|       local args = {} |  | ||||||
|       msg.text = msg.text:sub(#cmd + #(to or '') + 3) |  | ||||||
|       for s in msg.text:gmatch '%S+' do table.insert(args, s) end |  | ||||||
| 
 |  | ||||||
|       msg.cmd  = cmd |  | ||||||
|       msg.args = args |  | ||||||
| 
 |  | ||||||
|       return self:emit('command', msg) |  | ||||||
|     elseif cmd then return end |  | ||||||
| 
 |  | ||||||
|     self:emit('message', msg) |  | ||||||
| 
 |  | ||||||
|   elseif update.edited_message then |  | ||||||
|     self:emit('messageEdit', update.edited_message) |  | ||||||
| 
 |  | ||||||
|   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:emit('poll', update.poll) |  | ||||||
|   elseif update.poll_answer then self:emit('pollAnswer', update.poll_answer) |  | ||||||
| 
 |  | ||||||
|   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:emit('inlineResult', update.chosen_inline_result) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:_getUpd(lim, offs, ...) |  | ||||||
|   local u, ok = self:getUpdates(lim, offs, ...) |  | ||||||
|   if not ok or not u or (u and type(u) ~= 'table') or not u.result then return end |  | ||||||
|   for _, v in pairs(u.result) do |  | ||||||
|     offs = v.update_id + 1 |  | ||||||
|     if type(v) == 'table' then |  | ||||||
|       self:emit('update', v) |  | ||||||
|       receiveUpdate(self, v) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   return offs |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:_loop(lim, offs, ...) |  | ||||||
|   while api.runs do |  | ||||||
|     local o = self:_getUpd(lim, offs, ...) |  | ||||||
|     offs = o and o or offs |  | ||||||
|   end |  | ||||||
|   self:getUpdates(lim, offs, ...) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| -- RUN -- |  | ||||||
| function api:run(lim, offs, tout, al) |  | ||||||
|   lim = tonumber(lim) or 1 |  | ||||||
|   offs = tonumber(offs) or 0 |  | ||||||
|   tout = tonumber(tout) or 0 |  | ||||||
| 
 |  | ||||||
|   self.runs = true |  | ||||||
|   self:emit 'ready' |  | ||||||
| 
 |  | ||||||
|   self.co = coroutine.create(api._loop) |  | ||||||
|   coroutine.resume(self.co, self, lim, tout, offs, al) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function api:destroy() self.runs = false end |  | ||||||
| 
 |  | ||||||
| function api:login(token, thn) |  | ||||||
|   self.token = assert(token or self.token, 'Provide token!') |  | ||||||
| 
 |  | ||||||
|   repeat |  | ||||||
|     local r, o = self:getMe() |  | ||||||
|     if o and r then self.info = r end |  | ||||||
|   until (self.info or {}).result |  | ||||||
| 
 |  | ||||||
|   self.info = self.info.result |  | ||||||
|   self.info.name = self.info.first_name |  | ||||||
| 
 |  | ||||||
|   if type(thn) == 'function' then thn(self) end |  | ||||||
| 
 |  | ||||||
|   if not self.nr then self:run() end |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return function(opts) |  | ||||||
|   if not token or type(token) ~= 'string' then token = nil end |  | ||||||
| 
 |  | ||||||
|   local self = setmetatable({}, api) |  | ||||||
|   if type(opts) == 'table' then |  | ||||||
|     if opts.token then self.token = opts.token end |  | ||||||
|     if opts.norun then self.nr = true end |  | ||||||
|     if not opts.noinl then |  | ||||||
|       self.inline = require('etc.api.inline')(self) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   return self |  | ||||||
| end |  | ||||||
|  | @ -1 +0,0 @@ | ||||||
| return require 'etc.api.core' |  | ||||||
|  | @ -1,156 +0,0 @@ | ||||||
| --[[ Inline query library |  | ||||||
|   -- (c) Er2 2021 <er2@dismail.de> |  | ||||||
|   -- Zlib License |  | ||||||
| --]] |  | ||||||
| 
 |  | ||||||
| local inline = {} |  | ||||||
| inline.__index = inline -- Make class |  | ||||||
| 
 |  | ||||||
| function inline.query(id, from, q, off, ct, loc) |  | ||||||
|   return { |  | ||||||
|     id = tostring(id), |  | ||||||
|     from = from, |  | ||||||
|     query = q, |  | ||||||
|     offset = off, |  | ||||||
|     chat_type = ct, |  | ||||||
|     location = loc, |  | ||||||
|   } |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function inline.result(type, id, ...) |  | ||||||
|   type = tostring(type) |  | ||||||
|   local t = setmetatable({ |  | ||||||
|     type = type, |  | ||||||
|     id = tostring(tonumber(id) or 1), |  | ||||||
|   }, inline) |  | ||||||
|   local a = {...} |  | ||||||
|   if t.type == 'article' then t.title, t.url, t.hide_url, t.description = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'photo' then |  | ||||||
|     t.photo_url, t.photo_width, t.photo_height, t.title, t.description, |  | ||||||
|     t.caption, t.parse_mode, t.caption_entities |  | ||||||
|       = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'gif' or t.type == 'mpeg4_gif' then |  | ||||||
|     local url, width, height, duration |  | ||||||
|     url, width, height, duration, t.title, t.caption, t.parse_mode, t.caption_entities |  | ||||||
|       = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|     if t.type == 'gif' then |  | ||||||
|       t.gif_url, t.gif_width, t.gif_height, t.gif_duration |  | ||||||
|       = url, width, height, duration |  | ||||||
|     else |  | ||||||
|       t.mpeg4_url, t.mpeg4_width, t.mpeg4_height, t.mpeg4_duration |  | ||||||
|       = url, width, height, duration |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'video' then |  | ||||||
|     t.video_url, t.mime_type, t.title, t.caption, t.parse_mode, |  | ||||||
|     t.caption_entities, t.video_width, t.video_height, t.video_duration, t.description |  | ||||||
|       = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'audio' or t.type == 'voice' then |  | ||||||
|     t.title, t.caption, t.parse_mode, t.caption_entities = table.unpack(a, 2) |  | ||||||
| 
 |  | ||||||
|     if t.type == 'audio' then |  | ||||||
|       t.audio_url, t.performer, t.audio_duration = a[1], a[6], a[7] |  | ||||||
|     else |  | ||||||
|       t.voice_url, t.voice_duration = a[1], a[6] |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'document' then |  | ||||||
|     t.title, t.caption, t.parse_mode, t.caption_entities, t.document_url, |  | ||||||
|     t.mime_type, t.description = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'location' or t.type == 'venue' then |  | ||||||
|     t.latitude, t.longitude, t.title = table.unpack(a, 1, 3) |  | ||||||
| 
 |  | ||||||
|     if t.type ~= 'venue' then |  | ||||||
|       t.horizontal_accurancy, t.live_period, t.heading, t.proximity_alert_radius |  | ||||||
|       = table.unpack(a, 4, 7) |  | ||||||
|     else |  | ||||||
|       t.address, t.foursquare_id, t.foursquare_type, t.google_place_id, t.google_place_type |  | ||||||
|       = table.unpack(a, 4, 8) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'contact' then |  | ||||||
|     t.phone_number, t.first_name, t.last_name, t.vcard, |  | ||||||
|     t.reply_markup, t.input_message_content |  | ||||||
|       = table.unpack(a) |  | ||||||
| 
 |  | ||||||
|   elseif t.type == 'game' then t.game_short_name = a[1] |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   return t |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function inline:thumb(url, width, height, mime) |  | ||||||
|   if self.type == 'audio' |  | ||||||
|   or self.type == 'voice' |  | ||||||
|   or self.type == 'game' |  | ||||||
|   then return self end |  | ||||||
| 
 |  | ||||||
|   self.thumb_url = tostring(url) |  | ||||||
| 
 |  | ||||||
|   if  width and height and ( |  | ||||||
|      self.type == 'article' |  | ||||||
|   or self.type == 'document' |  | ||||||
|   or self.type == 'contact' |  | ||||||
|   or self.type == 'location' |  | ||||||
|   or self.type == 'venue' |  | ||||||
|   ) then |  | ||||||
|     self.thumb_width  = tonumber(width) |  | ||||||
|     self.thumb_height = tonumber(height) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   if mime and ( |  | ||||||
|      self.type == 'gif' |  | ||||||
|   or self.type == 'mpeg4_gif' |  | ||||||
|   ) then self.thumb_mime_type = mime end |  | ||||||
| 
 |  | ||||||
|   return self |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function inline:keyboard(...) |  | ||||||
|   if not self.type then return self end |  | ||||||
|   local k = {} |  | ||||||
| 
 |  | ||||||
|   for _, v in pairs {...} do |  | ||||||
|     if type(v) == 'table' then |  | ||||||
|       table.insert(k, v) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   self.reply_markup = k |  | ||||||
| 
 |  | ||||||
|   return self |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| -- Author itself not understands why this funciton needed |  | ||||||
| -- so not recommends to use it |  | ||||||
| function inline:messCont(a) |  | ||||||
|   if self.type == 'game' or self.type == 'article' then |  | ||||||
|     self.input_message_content = a |  | ||||||
|   end |  | ||||||
|   return self |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function inline:answer(id, res, ctime, per, noff, pmt, pmp) |  | ||||||
|    print(dump(res)) |  | ||||||
|   if res.id then res = {res} end  |  | ||||||
|   return self:request('answerInlineQuery', { |  | ||||||
|     inline_query_id = id, |  | ||||||
|     results = res, |  | ||||||
|     cache_time = ctime, |  | ||||||
|     is_personal = per, |  | ||||||
|     next_offset = noff, |  | ||||||
|     switch_pm_text = pmt, |  | ||||||
|     switch_pm_parameter = pmp, |  | ||||||
|   }) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return function(api) |  | ||||||
|   local self = setmetatable({ |  | ||||||
|     request = function(_, ...) api:request(...) end |  | ||||||
|   }, inline) |  | ||||||
|   return self |  | ||||||
| end |  | ||||||
|  | @ -1,103 +0,0 @@ | ||||||
| --[[ Additional tools |  | ||||||
|   -- (c) Er2 2021 <er2@dismail.de> |  | ||||||
|   -- Zlib license |  | ||||||
| --]] |  | ||||||
| 
 |  | ||||||
| local tools = { |  | ||||||
|   json = require 'etc.json', |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| local json  = tools.json |  | ||||||
| local https = require 'ssl.https' |  | ||||||
| local ltn12 = require 'ltn12' |  | ||||||
| local mp    = require 'etc.multipart' |  | ||||||
| 
 |  | ||||||
| function tools.fetchCmd(text) |  | ||||||
|   return |  | ||||||
|     text:match '/([%w_]+)',       -- cmd |  | ||||||
|     text:match '/[%w_]+@([%w_]+)' -- to |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function tools._req(url, meth, data, ctype) |  | ||||||
|   assert(url,  'Provide URL!') |  | ||||||
|   assert(meth, 'Provide method!') |  | ||||||
| 
 |  | ||||||
|   local resp = {} |  | ||||||
|   local head = { |  | ||||||
|     url      = url, |  | ||||||
|     method   = meth, |  | ||||||
|     headers  = { |  | ||||||
|       ['Content-Type']   = ctype, |  | ||||||
|       ['Content-Length'] = #(data or ''), |  | ||||||
|     }, |  | ||||||
|     source   = ltn12.source.string(data), |  | ||||||
|     sink     = ltn12.sink.table(resp), |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   local succ, res = https.request(head) |  | ||||||
|   if not succ then |  | ||||||
|     print('Connection error [' .. res .. ']') |  | ||||||
|     return nil, false |  | ||||||
|   end |  | ||||||
|   return resp[1], true |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function tools.preq(url, par) |  | ||||||
|   par = par or {} |  | ||||||
| 
 |  | ||||||
|   local body, bound = mp.encode(par) |  | ||||||
|   return tools._req( |  | ||||||
|     url, |  | ||||||
|     'POST', |  | ||||||
|     body, |  | ||||||
|     'multipart/form-data; boundary=' .. bound |  | ||||||
|   ) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function tools.greq(url, par, f) |  | ||||||
|   par = json.encode(par) |  | ||||||
|   return tools._req(url, 'GET', par, 'application/json') |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function tools.req(url, par, f, dbg) |  | ||||||
|   local res, succ |  | ||||||
|   par = par or {} |  | ||||||
| 
 |  | ||||||
|   -- files |  | ||||||
|   if f and next(f) ~= nil then |  | ||||||
|     par = par or {} |  | ||||||
|     for k, v in pairs(par) do par[k] = tostring(v) end |  | ||||||
|     local ft, fn = next(f) |  | ||||||
|     local fr = io.open(fn, 'r') |  | ||||||
|     if fr then |  | ||||||
|       par[ft] = { |  | ||||||
|         filename = fn, |  | ||||||
| 	data = fr:read '*a' |  | ||||||
|       } |  | ||||||
|       fr:close() |  | ||||||
|     else par[ft] = fn end |  | ||||||
|     res, succ = tools.preq(url, par) |  | ||||||
|   else -- text |  | ||||||
|     res, succ = tools.greq(url, par) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   if dbg then print(url, succ, res, par) |  | ||||||
|     -- dump(par)) |  | ||||||
|   end |  | ||||||
|   res = json.decode(res or '{}') |  | ||||||
|   if not succ or not res then return {}, false end |  | ||||||
|   return res, true |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function tools.request(token, endpoint, param, f) |  | ||||||
|   assert(token, 'Provide token!') |  | ||||||
|   assert(endpoint, 'Provide endpoint!') |  | ||||||
| 
 |  | ||||||
|   local url = 'https://api.telegram.org/bot' ..token.. '/' ..endpoint |  | ||||||
| 
 |  | ||||||
|   dbg = true |  | ||||||
|   local resp = tools.req(url, param, f, dbg) |  | ||||||
|   return resp, resp.ok or false |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return tools |  | ||||||
|  | @ -1,167 +0,0 @@ | ||||||
| -- based on https://github.com/catwell/lua-multipart-post |  | ||||||
| -- MIT License |  | ||||||
| 
 |  | ||||||
| local ltn12 = require 'ltn12' |  | ||||||
| local mp = { |  | ||||||
|   CHARSET  = 'UTF-8', |  | ||||||
|   LANGUAGE = '' |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| -- https://gist.github.com/liukun/f9ce7d6d14fa45fe9b924a3eed5c3d99 |  | ||||||
| local function urlencode(url) |  | ||||||
|   if url == nil then return end |  | ||||||
|   url = url:gsub("\n", "\r\n") |  | ||||||
|   url = url:gsub("([^%w_%- . ~])", function(c) return string.format("%%%02X", string.byte(c)) end) |  | ||||||
|   url = url:gsub(" ", "+") |  | ||||||
|   return url |  | ||||||
| end |  | ||||||
| mp.urlencode = urlencode |  | ||||||
| 
 |  | ||||||
| local function fmt(p, ...) |  | ||||||
|   if select('#', ...) == 0 then |  | ||||||
|     return p |  | ||||||
|   end |  | ||||||
|   return string.format(p, ...) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function tprintf(t, p, ...) |  | ||||||
|   t[#t+1] = fmt(p, ...) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function section_header(r, k, extra) |  | ||||||
|   tprintf(r, 'content-disposition: form-data; name="%s"', k) |  | ||||||
|   if extra.filename then |  | ||||||
|     tprintf(r, '; filename="%s"', extra.filename) |  | ||||||
|     tprintf( |  | ||||||
|       r, "; filename*=%s'%s'%s", |  | ||||||
|       mp.CHARSET, mp.LANGUAGE, urlencode(extra.filename) |  | ||||||
|     ) |  | ||||||
|   end |  | ||||||
|   if extra.content_type then |  | ||||||
|     tprintf(r, '\r\ncontent-type: %s', extra.content_type) |  | ||||||
|   end |  | ||||||
|   if extra.content_transfer_encoding then |  | ||||||
|     tprintf( |  | ||||||
|       r, '\r\ncontent-transfer-encoding: %s', |  | ||||||
|       extra.content_transfer_encoding |  | ||||||
|     ) |  | ||||||
|   end |  | ||||||
|   tprintf(r, '\r\n\r\n') |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| function mp.boundary() |  | ||||||
|   local t = {"BOUNDARY-"} |  | ||||||
|   for i=2,17 do t[i] = string.char(math.random(65, 90)) end |  | ||||||
|   t[18] = "-BOUNDARY" |  | ||||||
|   return table.concat(t) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function encode_header_to_table(r, k, v, boundary) |  | ||||||
|   local _t = type(v) |  | ||||||
| 
 |  | ||||||
|   tprintf(r, "--%s\r\n", boundary) |  | ||||||
|   if _t == "string" then |  | ||||||
|     section_header(r, k, {}) |  | ||||||
|   elseif _t == "table" then |  | ||||||
|     assert(v.data, "invalid input") |  | ||||||
|     local extra = { |  | ||||||
|       filename = v.filename or v.name, |  | ||||||
|       content_type = v.content_type or v.mimetype |  | ||||||
|         or "application/octet-stream", |  | ||||||
|       content_transfer_encoding = v.content_transfer_encoding |  | ||||||
|         or "binary", |  | ||||||
|     } |  | ||||||
|     section_header(r, k, extra) |  | ||||||
|   else |  | ||||||
|     error(string.format("unexpected type %s", _t)) |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function encode_header_as_source(k, v, boundary, ctx) |  | ||||||
|   local r = {} |  | ||||||
|   encode_header_to_table(r, k, v, boundary, ctx) |  | ||||||
|   local s = table.concat(r) |  | ||||||
|   if ctx then |  | ||||||
|     ctx.headers_length = ctx.headers_length + #s |  | ||||||
|   end |  | ||||||
|   return ltn12.source.string(s) |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function data_len(d) |  | ||||||
|   local _t = type(d) |  | ||||||
| 
 |  | ||||||
|   if _t == "string" then |  | ||||||
|     return string.len(d) |  | ||||||
|   elseif _t == "table" then |  | ||||||
|     if type(d.data) == "string" then |  | ||||||
|       return string.len(d.data) |  | ||||||
|     end |  | ||||||
|     if d.len then return d.len end |  | ||||||
|     error("must provide data length for non-string datatypes") |  | ||||||
|   end |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function content_length(t, boundary, ctx) |  | ||||||
|   local r = ctx and ctx.headers_length or 0 |  | ||||||
|   for k, v in pairs(t) do |  | ||||||
|     if not ctx then |  | ||||||
|       local tmp = {} |  | ||||||
|       encode_header_to_table(tmp, k, v, boundary) |  | ||||||
|       r = r + #table.concat(tmp) |  | ||||||
|     end |  | ||||||
|     r = r + data_len(v) + 2 -- `\r\n` |  | ||||||
|   end |  | ||||||
|   return r + #boundary + 6 -- `--BOUNDARY--\r\n` |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function get_data_src(v) |  | ||||||
|   local _t = type(v) |  | ||||||
|   if v.source then |  | ||||||
|     return v.source |  | ||||||
|   elseif _t == "string" then |  | ||||||
|     return ltn12.source.string(v) |  | ||||||
|   elseif _t == "table" then |  | ||||||
|     _t = type(v.data) |  | ||||||
|     if _t == "string" then |  | ||||||
|       return ltn12.source.string(v.data) |  | ||||||
|     elseif _t == "table" then |  | ||||||
|       return ltn12.source.table(v.data) |  | ||||||
|     elseif _t == "userdata" then |  | ||||||
|       return ltn12.source.file(v.data) |  | ||||||
|     elseif _t == "function" then |  | ||||||
|       return v.data |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   error("invalid input") |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| local function set_ltn12_blksz(sz) |  | ||||||
|   assert(type(sz) == "number", "set_ltn12_blksz expects a number") |  | ||||||
|   ltn12.BLOCKSIZE = sz |  | ||||||
| end |  | ||||||
| mp.set_ltn12_blksz = set_ltn12_blksz |  | ||||||
| 
 |  | ||||||
| local function source(t, boundary, ctx) |  | ||||||
|   local sources, n = {}, 1 |  | ||||||
|   for k, v in pairs(t) do |  | ||||||
|     sources[n] = encode_header_as_source(k, v, boundary, ctx) |  | ||||||
|     sources[n+1] = get_data_src(v) |  | ||||||
|     sources[n+2] = ltn12.source.string("\r\n") |  | ||||||
|     n = n + 3 |  | ||||||
|   end |  | ||||||
|   sources[n] = ltn12.source.string(string.format("--%s--\r\n", boundary)) |  | ||||||
|   return ltn12.source.cat(table.unpack(sources)) |  | ||||||
| end |  | ||||||
| mp.source = source |  | ||||||
| 
 |  | ||||||
| function mp.encode(t, boundary) |  | ||||||
|   boundary = boundary or mp.boundary() |  | ||||||
|   local r = {} |  | ||||||
|   assert(ltn12.pump.all( |  | ||||||
|     (source(t, boundary)), |  | ||||||
|     (ltn12.sink.table(r)) |  | ||||||
|   )) |  | ||||||
|   return table.concat(r), boundary |  | ||||||
| end |  | ||||||
| 
 |  | ||||||
| return mp |  | ||||||
							
								
								
									
										2
									
								
								init.lua
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								init.lua
									
										
									
									
									
								
							|  | @ -1 +1,3 @@ | ||||||
|  | package.path = 'etc/?.lua;etc/?/init.lua;' .. package.path | ||||||
|  | 
 | ||||||
| require 'src.parts.core' | require 'src.parts.core' | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue