Advertisement
Aadvert

TrollMart!

Feb 12th, 2012
718
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.26 KB | None | 0 0
  1. --#filename:tmart
  2. --#version:0.5
  3. --#author:Advert
  4. -- tmart (formerly pget) 0.5 'TrollMart'
  5. -- (C) 2012 User 'Advert' at http://www.computercraft.info/forums2/
  6. -- X11/mit licence (use/modify at your will, but please, leave credit where due)
  7.  
  8.  
  9.  
  10. if not http then
  11.     error("plib requires http! Enable it in your config file!")
  12. end
  13. local plib = {}
  14. -- Configuration:
  15. local dConf = {}
  16. do -- dConf settings.
  17. dConf["sMasterLink"] = "rb7LSHsJ" -- This is where we get all the other "paste repositories"
  18.             -- if sMasterLink starts with "http:", then that should indicate it's a full url; e.g "http://computercraft.info/pget_master.txt" or something.
  19. dConf["sBaseURL"] = "http://pastebin.com/raw.php?i=%s"
  20. dConf["sPoweredBy"] = "Powered by pastebin.com (http://pastebin.com)"
  21. dConf["sPoweredBySplash"] = {  -- Comment this out to prevent splash.
  22. [[    _____           _ _                   _   ]],
  23. [[   /__   \_ __ ___ | | | /\/\   ____ _ __| |_ ]],
  24. [[     / /\/ '__/ _ \| | |/    \ / _, | '__| __|]],
  25. [[    / /  | | | (_) | | / /\/\ \ (_| | |  | |_ ]],
  26. [[    \/   |_|  \___/|_|_\/    \/\__,_|_|   \__|]],
  27. [[                                              ]],
  28. [[                    Powered By:]],
  29. [[         ___          _       _     _       ]],
  30. [[        / _ \____ ___| |_ ___| |__ (_)_ __  ]],
  31. [[       / /_)/ _, / __| __/ _ \ '_ \| | '_ \ ]],
  32. [[      / ___/ (_| \__ \ ||  __/ |_) | | | | |]],
  33. [[      \/    \__,_|___/\__\___|_.__/|_|_| |_|]],
  34. [[                                            ]],
  35. "",
  36. "               http://pastebin.com"}
  37. end
  38. local config = dConf -- TODO: copy table
  39. local pasteTree, pasteCats, rawSave = {}, {}, {};
  40. -- String split helper function
  41. local function strSplitFirst(sData, sSplit)
  42.     -- Only supports one character splits!
  43.     local nPos;
  44.     for i = 1, sData:len() do
  45.         local sCur = sData:sub(i, i)
  46.         if sCur == sSplit then
  47.             nPos = i
  48.             break
  49.         end
  50.     end
  51.     if nPos == nil then return sData, nil end
  52.     return string.sub(sData, 1, nPos -1), string.sub(sData, nPos +1)
  53. end
  54. -- Will get a paste, and seperate metadata etc.
  55. function plib.rawGet(sCode)
  56.     local sURL;
  57.     if sCode:sub(1, 7) == "http://" then
  58.         sURL = sCode
  59.     else
  60.         sURL = string.format(config["sBaseURL"], sCode) -- To allow support for other paste services. (as long as they have a RAW function)
  61.                                                         -- ^ Redunant if this function changes to pure http get. (url determination would occur elsewhere)
  62.     end
  63.     local sData = "" -- The code/file contents (seperated from metadata)
  64.     local meta = {} -- Some metadata is great.
  65.     local hHandle = http.get(sURL) -- TODO: Change to non-blocking
  66.     if not hHandle then
  67.         return nil, {error = true}
  68.     end
  69.     while true do
  70.         sleep(0)
  71.         local sLine = hHandle:readLine()
  72.         if sLine:sub(1, 3) == "--#" then -- Metadata!
  73.             local sFirst, sSecond = strSplitFirst(sLine:sub(4), ":")
  74.             meta[sFirst or tostring(i)] = sSecond -- Metadata only supports strings, at the moment. Metadata could be parsed as lua, but meh.
  75.         else
  76.             -- For some reason, we dont seem to need this:
  77.             sData = sLine .. "\n" -- We've hit some data, let's add it, then just dump the rest, all in one go.
  78.             break
  79.         end
  80.     end
  81.     sData = sData .. hHandle:readAll() -- Dump the rest of the data into sData.
  82.     hHandle:close()
  83.     return sData, meta
  84. end
  85.  
  86. local function stringIter(sData, sBreak) -- string iterator help function  
  87.     return function()
  88.         if not sData then return nil end
  89.         local ret
  90.         ret, sData = strSplitFirst(sData, sBreak)
  91.         if not ret and sData then
  92.             ret = ""
  93.         end
  94.         --print(ret, "..", sData)
  95.         return ret
  96.     end
  97. end -- Wow, that was simple!
  98.  
  99. local function strSplitSupreme(sData, sSplit) -- All hail.
  100.     if sData == nil then return end
  101.     local a, b = strSplitFirst(sData, sSplit)
  102.     return a, strSplitSupreme(b, sSplit)
  103. end
  104. function plib.getNode(sCode, targetTable, bTrusted)
  105.     -- if bTrusted is true, load other nodes listed inside, otherwise, no.
  106.     if rawSave[sCode] then return {"Recursive table"} end -- todo: add appropriate table here.
  107.     local sData, meta = plib.rawGet(sCode)
  108.     rawSave[sCode] = {sData = sData, meta = meta} -- prevent recursion
  109.     targetTable.nodes = targetTable.nodes or {}
  110.    
  111.     for sDataF in stringIter(sData, "\n") do
  112.         sleep(0)
  113.         --print("DataF: ", sDataF)
  114.         if sDataF:sub(1, 1) ~= "-" and sDataF:len() > 0 then -- Check for comments
  115.             --print("Is not a comment.")
  116.             --TODO: better helper function for this.
  117.             local sType, sLocation, sName, sCategory, sAuthor = strSplitSupreme(sDataF, ",")
  118.             --print(string.format("sType: %s; sLocation: %s; sName: %s; sCategory: %s; sAuthor: %s.", sType, sLocation, sName, sCategory, sAuthor))
  119.             local infoT = {sLocation = sLocation, sName = sName, sCategory = sCategory, sAuthor = sAuthor}
  120.             if sType == "program" then
  121.                 table.insert(targetTable, infoT)
  122.                 if not pasteCats[sCategory] then
  123.                     pasteCats[sCategory] = {}
  124.                 end
  125.                 table.insert(pasteCats[sCategory], infoT)
  126.             elseif sType == "node-trusted" then
  127.                 local node = infoT
  128.                 if bTrusted then
  129.                     plib.getNode(sLocation, node, true)
  130.                 end
  131.                 table.insert(targetTable.nodes, node)
  132.             elseif sType == "node" then
  133.                 local node = {}
  134.                 if bTrusted then
  135.                     plib.getNode(sLocation, node, false)
  136.                 end
  137.                 table.insert(targetTable.nodes, node)
  138.             end
  139.         end
  140.     end
  141. end
  142.  
  143. function plib.downloadAndSave(sCode, sFile)
  144.     --[[term.clear()
  145.     term.setCursorPos(1, 1)
  146.     if not sFile then
  147.         print("Enter desired filename: ")
  148.         sFile = read()
  149.     end
  150.     while fs.exists(sFile) do
  151.         print("File already exists, overwrite? Y/newname")
  152.         local inp = read()
  153.         if inp == "y" or inp == "Y" then
  154.             break
  155.         end
  156.         sFile = inp
  157.     end
  158.     --]]
  159.    
  160.     showSplash("Downloading!")
  161.     local sData, meta = plib.rawGet(sCode)
  162.     local hHandle = io.open(sFile, "w")
  163.     if not hHandle then
  164.         error("Unable to open file")
  165.     end
  166.     hHandle:write(sData)
  167.     hHandle:close()
  168. end
  169.  
  170. -- Graphical functions
  171.  
  172. -- I felt obligated to make this function, to support pastebin.
  173. function showSplash(sBottomNotice)
  174.     if config["sPoweredBySplash"] then
  175.         term.clear()
  176.         term.setCursorPos(1, 1)
  177.         for i = 1, #config["sPoweredBySplash"] do
  178.             term.setCursorPos(1, i)
  179.             term.write(config["sPoweredBySplash"][i])
  180.         end
  181.         term.setCursorPos(1, 18)
  182.         local sSpacer = ""
  183.         if sBottomNotice:len() < 32 then
  184.             sSpacer = (" "):rep(32 - sBottomNotice:len())
  185.         end
  186.         term.write(sSpacer .. sBottomNotice)
  187.         term.setCursorPos(1, 1)
  188.  
  189.         sleep(1)
  190.     else
  191.     end
  192. end
  193. -- I REALLY need to clean up varaibles. TODO TODO TODO TODO
  194. -- TODO.
  195. local orderedCats = {}; -- Who ordered the cats? No, seirously, who ordered....
  196. local nCurCat, nCurItem = 1, 1
  197. local sState, sOldState = "help", "main"
  198. local render_mart;
  199. local function w(l, str) term.setCursorPos(1, l) term.write(str) end -- sick of two long commands to write text t_t
  200. local function render()
  201.     -- I might make an API for this, since it would certainly be handy.
  202.     term.clear()
  203.     -- Core stuff:
  204.     term.setCursorPos(1,1)
  205.     w(1,"------ tmart v0.50  Powered by Pastebin.com -------")
  206.     w(18, "x:exit; h:help/creds. You are here:  " .. sState)
  207.     if sState == "main" then
  208.         render_mart() -- Render the current category, a few items, etc.
  209.     elseif sState == "help" then
  210.         w(2, "====================  credits  =====================")
  211.         w(3, " Advert: Programming")
  212.         w(4, " Espen: Feedback, Testing, ")
  213.         w(5, "        A nice http.request example")
  214.         w(6, " tomass1996: Original pastebin downloader           ")
  215.         w(7, " Everyone else that have helped, but that I can't")
  216.         w(8, " remember: You know who you are (And aren't)!")
  217.         w(9, "====================    Help    ====================")
  218.         w(10,"   m: main screen; download stuff here")
  219.         w(11,"   g: download selected item")
  220.         w(12,"   w/s: navigate categories")
  221.         w(13,"   a/d: navigate items")
  222.     end
  223.     term.setCursorPos(1,1)
  224.     return true
  225. end
  226.  
  227. local function orderCats()
  228.     --Haha, I lied. This simply dumps the table.
  229.     for k, v in pairs(pasteCats) do
  230.         table.insert(orderedCats, k)
  231.     end
  232. end
  233. local function getCatT(nID)
  234.     nID = nID or nCurCat
  235.     return pasteCats[orderedCats[nID]]
  236. end
  237. local function getPasteT(nID)
  238.     return getCatT()[nID]
  239. end
  240. local function fixedString(sStr, nSize)
  241.     sStr = tostring(sStr or "")
  242.     nSize = nSize or 12
  243.     if sStr:len() > nSize then
  244.         sStr = sStr:sub(1, nSize)
  245.     elseif sStr:len() < nSize then
  246.         sStr = sStr .. (" "):rep(nSize - sStr:len())
  247.     end
  248.     return sStr
  249. end
  250. local dataValues = {}
  251. local function getVar(sWhole, sVar)
  252.  
  253.     local sText = dataValues[sVar]
  254.  
  255.     return fixedString(sText, sWhole:len())
  256. end
  257.  
  258. local function modText(sText)
  259.     -- Our format: %name%
  260.     -- e.g %text1%
  261.     return string.gsub(sText, "(%%%s*(%w+)%s*%%)", getVar)
  262. end
  263. function render_mart()
  264.     assimilate_dataValues()
  265.     local screen = {
  266.     [[==================  Troll-Mart  ==================]],
  267.     [[   % recentlydownloaded                     %     ]],
  268.     [[   Select an item, using wasd, refridgerator.     ]],
  269.     [[--------------------------------------------------]],
  270.     [[  Category  |    File    |        Details         ]],
  271.     [[------------+------------+------------------------]],
  272.     [[ % cat1   % | % item1  % |       -  Name  -       ]],
  273.     [[ % cat2   % | % item2  % | % detail1            % ]],
  274.     [[ % cat3   % | % item3  % |       -Category-       ]],
  275.     [[ % cat4   % | % item4  % | % detail2            % ]],
  276.     [[>% cat5   %<|>% item5  %<|       - Author -       ]],
  277.     [[ % cat6   % | % item6  % | % detail3            % ]],
  278.     [[ % cat7   % | % item7  % |       -  Code  -       ]],
  279.     [[ % cat8   % | % item8  % | % detail4            % ]],
  280.     [[ % cat9   % | % item9  % |                        ]],
  281.     [[==================================================]]}
  282.     for i, v in ipairs(screen) do
  283.         w(i + 1, modText(v))
  284.     end
  285. end
  286.  
  287. local function m_clamp(n, n2, n3)
  288.     if n < n2 then
  289.         n = n2
  290.     end
  291.     if n > n3 then
  292.         n = n3
  293.     end
  294.     return n
  295. end
  296.  
  297. function assimilate_dataValues()
  298.     local numCats = #orderedCats
  299.     local numItems = #getCatT()
  300.     dataValues["nc"] = numCats
  301.     dataValues["ni"] = numItems
  302.     term.setCursorPos(1,1)
  303.     local startCat, startItem = nCurCat - 5, nCurItem - 5
  304.     for i = 1, 9 do --TODO: move depending on selection
  305.         dataValues["cat" .. tostring(i)] = orderedCats[i + startCat]
  306.     end
  307.     for i = 1, 9 do --TODO: move depending on selection
  308.         local pt = getPasteT(i + startItem)
  309.         dataValues["item" .. tostring(i)]= pt and pt.sName
  310.     end
  311.    
  312.     local ct = getPasteT(nCurItem)
  313.     dataValues["detail1"] = ct.sName
  314.     dataValues["detail2"] = ct.sCategory
  315.     dataValues["detail3"] = ct.sAuthor
  316.     dataValues["detail4"] = ct.sLocation
  317. end
  318.  
  319. -- Main function*
  320. local bExit = false; -- TODO: move this up
  321. local events = {}
  322. local timerEvents = {}
  323. local activeTimers = {}
  324. local function registerTimer(fFunct, nDelay)
  325.     local timerT = os.startTimer(nDelay)
  326.     timerEvents[fFunct] = nDelay
  327.     activeTimers[timerT] = fFunct
  328.     return timerT
  329. end
  330. local function killTimer(fFunct)
  331.     timerEvents[fFunct] = nil
  332. end
  333. function events.timer(timerT)
  334.     if activeTimers[timerT] then
  335.         --print("We has!")
  336.         if timerEvents[activeTimers[timerT]] and activeTimers[timerT]() then
  337.             --print("It wants MOAR!")
  338.             activeTimers[os.startTimer(timerEvents[activeTimers[timerT]])] = activeTimers[timerT] -- Problem?
  339.             activeTimers[timerT] = nil
  340.         else
  341.             activeTimers[timerT] = nil
  342.             --print("STOP! HAMM0R TIEM!")
  343.         end
  344.     end
  345. end
  346. local sOldState
  347. function events.char(sChar)
  348.     if sChar == "x" then
  349.         bExit = true
  350.         term.clear()
  351.         term.setCursorPos(1, 1)
  352.         print("Goodbye, and thank you for choosing Troll-Mart!")
  353.     end
  354.     local sCState = sState
  355.     if sChar == "h" then
  356.         sState = sState == "help" and sOldState or "help"
  357.     elseif sChar == "m" then
  358.         sState = "main"
  359.     end
  360.     if sState == "main" then
  361.         if sChar == "g" then
  362.             if not fs.exists("trollmart/") then
  363.                 fs.makeDir("trollmart")
  364.             end
  365.             local ct = getPasteT(nCurItem)
  366.             if ct and ct.sName and ct.sLocation then
  367.                 local sFile, sCode = ct.sName, ct.sLocation  -- Can tweak this later, and promt for filename/save dir.
  368.                 killTimer(render)
  369.                 plib.downloadAndSave(sCode, "trollmart/" .. sFile)
  370.                 dataValues["recentlydownloaded"] = "File saved as: " .. "trollmart/" .. sFile
  371.                 registerTimer(render, 0.1)
  372.             end
  373.         elseif sChar == "a" then -- Prev Category TODO: fix this bug
  374.             -- nCurCat: Current category
  375.             nCurCat = nCurCat - 1
  376.             nCurItem = 1 -- Reset this. <-- bug
  377.         elseif sChar == "d" then -- Next Category
  378.             nCurCat = nCurCat + 1
  379.             nCurItem = 1 -- Reset this (if we changed category <-- bug
  380.         elseif sChar == "w" then -- Prev Item
  381.             nCurItem = nCurItem - 1
  382.         elseif sChar == "s" then -- Next Item "down is +"
  383.             nCurItem = nCurItem + 1
  384.         end
  385.         nCurCat = m_clamp(nCurCat, 1,  #orderedCats)
  386.         nCurItem = m_clamp(nCurItem, 1, #getCatT())
  387.     end
  388.     if sCState ~= sState then
  389.         sOldState = sCState
  390.     end
  391. end
  392.  
  393. --setmetatable(events, {__index = function(_, k) return function(...) print("Event: " .. k .. "; Args: ", unpack(arg)) end end})
  394. local function main(cmdArg)
  395.     --local opt = unnamed_function(cmdArg) -- TODO: find function name for this.
  396.     showSplash("Retrieving Nodes...")
  397.     --loadConfig() --TODO: Impliment this
  398.    
  399.     -- Start render timer -- NEED TO DO BELOW getNode; until getNode uses not http.get
  400.     -- Get pluginz.
  401.     plib.getNode(config["sMasterLink"], pasteTree, true)
  402.     orderCats()
  403.     registerTimer(render, 0.1)
  404.     -- Could cache this, too.
  405.     term.setCursorPos(1,1)
  406.     while not bExit do
  407.         local sEvent, param1, param2 = os.pullEvent()
  408.         local eRes = events[sEvent] and events[sEvent](param1, param2)
  409.     end
  410. end
  411.  
  412.  
  413.  
  414. -- Commandline helpers
  415. local function displayCmdArgs()
  416.     print([[
  417.     "tmart [--gui]" -> GUI
  418.      GUI saves into 'trollmart/file'
  419.     "tmart --help" -> This message
  420.     "tmart --get [code] [--saveas 'file']" -> Gets [code]. Will prompt for savename if no metadata specifying filename or no --saveas.
  421.     Will save into current directory.
  422.     ]])
  423. end
  424.  
  425. -- REAL main function*
  426. local function parse_args(...)
  427.     --TODO: do this.
  428. end
  429.  
  430. --
  431. -- commandline stuff. TODO: use parse_args() or something.
  432. local arg = {...}
  433. local cArg = {}
  434. for i = 1, #arg do
  435.     cArg[i] = string.lower(arg[i])
  436. end
  437.  
  438. if #arg == 0 or cArg[1] == "--gui" then
  439.     main(arg)
  440. elseif cArg[1] == "--get" then
  441.     local sFile = ""
  442.     if not arg[2] then
  443.         displayCmdArgs()
  444.         error("Invalid paramters.")
  445.     end
  446.     if cArg[3] == "--saveas" and not arg[4] then
  447.         displayCmdArgs()
  448.         error("Invalid parameters.")
  449.     end
  450.     if cArg[3] == "--saveas" and arg[4] then
  451.         sFile = arg[4]
  452.     end
  453.     showSplash("Downloading...")
  454.     term.clear()
  455.     local sData, meta = plib.rawGet(arg[2])
  456.     if meta["error"] then
  457.         print("An error occured; your file probably does not exist.")
  458.         error("tmart: unable to find file.", 2)
  459.     end
  460.     if sFile == "" then
  461.         if meta["filename"] then
  462.             sFile = meta["filename"]
  463.         else
  464.             print("Input filename: ")
  465.             sFile = read()
  466.         end
  467.     end
  468.     while fs.exists(sFile) do
  469.         print("File '" .. sFile .. "' already exists. Overwrite? (y/newfilename)")
  470.         local inp = read()
  471.         if inp ~= "y" then
  472.             sFile = inp
  473.         else
  474.             break
  475.         end
  476.     end
  477.     local hHandle = io.open(sFile, "w")
  478.     if not hHandle then
  479.         error("Unable to open file")
  480.     end
  481.  
  482.     hHandle:write(sData)
  483.     hHandle:close()
  484.     print("Done.")
  485.     local sInfo = ""
  486.     if meta["version"] and meta["author"] and meta["filename"] then
  487.         sInfo = " (" .. meta["filename"] .. " version " .. meta["version"] .. ", by " .. meta["author"] .. ")"
  488.     end
  489.     print("Your file is: " .. sFile .. sInfo)
  490. elseif arg[1] == "--help" then
  491.     displayCmdArgs()
  492. elseif arg[1] == "--test" then
  493.     print("tmart: --test No longer supported.")
  494. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement