Added item-reports endpoint, schematic-exporter2.lua
This commit is contained in:
parent
78a8aec3e8
commit
4762e216d9
|
@ -0,0 +1,299 @@
|
||||||
|
local g = require("simple-graphics")
|
||||||
|
local mon = peripheral.wrap("monitor_24")
|
||||||
|
local W, H = mon.getSize()
|
||||||
|
local RUNNING = true -- Flag to indicate global program state.
|
||||||
|
|
||||||
|
-- Export flags
|
||||||
|
local EXPORTING = false -- Flag to indicate if we're exporting.
|
||||||
|
local EXPORT_SKIP = false -- Flag to indicate we should skip the current item.
|
||||||
|
local EXPORT_REPORT = false -- Flag to indicate we should report the current item as invalid.
|
||||||
|
|
||||||
|
local function startsWith(str, start)
|
||||||
|
return str:sub(1, #start) == start
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getTotalItemCount(itemList)
|
||||||
|
local total = 0
|
||||||
|
for name, value in pairs(itemList) do
|
||||||
|
if not startsWith(name, "__") then
|
||||||
|
total = total + value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local count = 1
|
||||||
|
if itemList.__COUNT__ then count = itemList.__COUNT__ end
|
||||||
|
return count * total
|
||||||
|
end
|
||||||
|
|
||||||
|
local function findItem(items, name)
|
||||||
|
for _, item in pairs(items) do
|
||||||
|
if item.name == name then return item end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function attemptItemExport(name, count)
|
||||||
|
local P_NAME = "meBridge_4"
|
||||||
|
local p = peripheral.wrap(P_NAME)
|
||||||
|
if p == nil then
|
||||||
|
return nil, "Missing peripheral "..P_NAME
|
||||||
|
end
|
||||||
|
local func = function()
|
||||||
|
return p.exportItem({name=name, count=count}, "south")
|
||||||
|
end
|
||||||
|
local success, result = pcall(func)
|
||||||
|
if success then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return nil, result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function drawProgress(p)
|
||||||
|
local discreteWidth = W - 2
|
||||||
|
local filled = p * discreteWidth
|
||||||
|
g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
|
||||||
|
g.drawXLine(mon, 2, 2+filled-1, 5, colors.green)
|
||||||
|
local s = string.format("%.0f%%", p*100)
|
||||||
|
for i = 1, #s do
|
||||||
|
local x = 2+i
|
||||||
|
local c = s:sub(i,i)
|
||||||
|
local bg = colors.lightGray
|
||||||
|
if x < filled then bg = colors.green end
|
||||||
|
g.drawText(mon, x, 5, c, colors.white, bg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setProgressText(text)
|
||||||
|
g.drawXLine(mon, 2, W-1, 6, colors.gray)
|
||||||
|
if text ~= nil and #text > 0 then
|
||||||
|
g.drawText(mon, 2, 6, text, colors.white, colors.gray)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clearMainPanel()
|
||||||
|
g.fillRect(mon, 1, 7, W, H-6, colors.black)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clearExportPanel()
|
||||||
|
g.fillRect(mon, 1, 7, W, H-9, colors.black)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function promptForUrlInput()
|
||||||
|
clearMainPanel()
|
||||||
|
drawProgress(0)
|
||||||
|
setProgressText(nil)
|
||||||
|
g.drawText(mon, 1, 8, "Please enter a schematic URL that", colors.white, colors.black)
|
||||||
|
g.drawText(mon, 1, 9, "you've obtained from", colors.white, colors.black)
|
||||||
|
g.drawText(mon, 1, 10, "schematics.andrewlalis.com in the", colors.white, colors.black)
|
||||||
|
g.drawText(mon, 1, 11, "computer to your right to continue.", colors.white, colors.black)
|
||||||
|
|
||||||
|
g.clear(term, colors.black)
|
||||||
|
g.drawText(term, 1, 1, "Paste your schematic URL here (CTRL+V): ", colors.white)
|
||||||
|
g.drawText(term, 2, 2, "*Press enter without pasting to quit*", colors.gray)
|
||||||
|
term.setCursorPos(1, 3)
|
||||||
|
term.setTextColor(colors.lightGray)
|
||||||
|
local link = io.read()
|
||||||
|
if link == nil or #link == 0 then
|
||||||
|
g.drawText(term, 1, 8, "No URL entered. Quitting.", colors.white)
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
g.drawText(term, 1, 8, "URL was pasted. Please continue on the monitor.", colors.white)
|
||||||
|
return link
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fetchItemLists(url)
|
||||||
|
local response = http.get(url)
|
||||||
|
if response == nil then
|
||||||
|
return nil, "HTTP request failed."
|
||||||
|
end
|
||||||
|
if response.getResponseCode() ~= 200 then
|
||||||
|
return nil, "HTTP code " .. response.getResponseCode()
|
||||||
|
end
|
||||||
|
local rawText = response.readAll()
|
||||||
|
response.close()
|
||||||
|
local itemLists, jsonErr = textutils.unserializeJSON(rawText)
|
||||||
|
if not itemLists then
|
||||||
|
return nil, "Failed to parse JSON: "..jsonErr
|
||||||
|
end
|
||||||
|
return itemLists
|
||||||
|
end
|
||||||
|
|
||||||
|
local function exportItem(name, count)
|
||||||
|
clearExportPanel()
|
||||||
|
g.drawText(mon, 1, 7, "Exporting "..count.." of", colors.white, colors.black)
|
||||||
|
g.drawText(mon, 1, 8, name, colors.lime, colors.black)
|
||||||
|
-- Check for flags and do different stuff if so.
|
||||||
|
if EXPORT_REPORT then
|
||||||
|
-- Report the item issue to the schematic site.
|
||||||
|
g.drawText(mon, 1, 10, "Reporting item. Skipping to next one.", colors.orange, colors.black)
|
||||||
|
os.sleep(2)
|
||||||
|
return count
|
||||||
|
elseif EXPORT_SKIP then
|
||||||
|
-- Skip this item.
|
||||||
|
g.drawText(mon, 1, 10, "Skipping this item.", colors.orange, colors.black)
|
||||||
|
os.sleep(2)
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
local me = peripheral.find("meBridge")
|
||||||
|
if me == nil then
|
||||||
|
g.drawText(mon, 1, 10, "Error: No \"meBridge\" peripheral.", colors.red, colors.black)
|
||||||
|
g.drawText(mon, 1, 11, "Attach one please.", colors.red, colors.black)
|
||||||
|
os.sleep(1)
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local allItems, err = me.listItems()
|
||||||
|
if allItems == nil or #allItems < 5 then
|
||||||
|
g.drawText(mon, 1, 10, "Error: Couldn't list AE items.", colors.red, colors.black)
|
||||||
|
g.drawText(mon, 1, 11, "Msg: " .. err, colors.red, colors.black)
|
||||||
|
os.sleep(1)
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local item = findItem(allItems, name)
|
||||||
|
if item ~= nil and item.amount > 0 then
|
||||||
|
local exported, err = attemptItemExport(name, count)
|
||||||
|
if exported ~= nil then
|
||||||
|
if exported == 0 then
|
||||||
|
g.drawText(mon, 1, 10, "Exported 0 items. Make sure there is", colors.yellow, colors.black)
|
||||||
|
g.drawText(mon, 1, 11, "space in the output container.", colors.yellow, colors.black)
|
||||||
|
os.sleep(0.5)
|
||||||
|
end
|
||||||
|
return exported
|
||||||
|
end
|
||||||
|
g.drawText(mon, 1, 10, "Transfer failed: " .. err, colors.red, colors.black)
|
||||||
|
os.sleep(1)
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
g.drawText(mon, 1, 10, "Item isn't present in the AE system.", colors.yellow, colors.black)
|
||||||
|
g.drawText(mon, 1, 11, "Please add some, craft, or skip.", colors.yellow, colors.black)
|
||||||
|
os.sleep(1)
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function exportSchematics(itemLists)
|
||||||
|
-- First build a list of instances of schematics, each with a task list.
|
||||||
|
local totalItemCount = 0
|
||||||
|
local listInstances = {}
|
||||||
|
for _, list in pairs(itemLists) do
|
||||||
|
totalItemCount = totalItemCount + getTotalItemCount(list)
|
||||||
|
for i = 1, list.__COUNT__ do
|
||||||
|
local instance = {
|
||||||
|
name = list.__NAME__,
|
||||||
|
instanceNumber = i,
|
||||||
|
countOfThisType = list.__COUNT__,
|
||||||
|
tasks = {}
|
||||||
|
}
|
||||||
|
for name, amount in pairs(list) do
|
||||||
|
if not startsWith(name, "__") then
|
||||||
|
table.insert(instance.tasks, {name=name, amount=amount})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(listInstances, instance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Now execute on that task list, quitting if the EXPORTING flag goes false.
|
||||||
|
local totalItemsExported = 0
|
||||||
|
local instanceIndex = 1
|
||||||
|
while instanceIndex <= #listInstances and EXPORTING do
|
||||||
|
local listInstance = listInstances[instanceIndex]
|
||||||
|
setProgressText(listInstance.instanceNumber.."/"..listInstance.countOfThisType.." "..listInstance.name)
|
||||||
|
local taskIndex = 1
|
||||||
|
while taskIndex <= #listInstance.tasks and EXPORTING do
|
||||||
|
local task = listInstance.tasks[taskIndex]
|
||||||
|
local itemsExported = 0
|
||||||
|
-- Reset item-specific control flags.
|
||||||
|
EXPORT_REPORT = false
|
||||||
|
EXPORT_SKIP = false
|
||||||
|
while itemsExported < task.amount and EXPORTING do
|
||||||
|
local exportedCount = exportItem(task.name, task.amount - itemsExported)
|
||||||
|
itemsExported = itemsExported + exportedCount
|
||||||
|
totalItemsExported = totalItemsExported + exportedCount
|
||||||
|
drawProgress(totalItemsExported / totalItemCount)
|
||||||
|
end
|
||||||
|
taskIndex = taskIndex + 1
|
||||||
|
end
|
||||||
|
instanceIndex = instanceIndex + 1
|
||||||
|
end
|
||||||
|
-- Done! Show a small message, then set the EXPORTING flag to false.
|
||||||
|
EXPORTING = false
|
||||||
|
for i = 1, 3 do -- Queue up some no-op touch events make sure the event handler quits.
|
||||||
|
os.queueEvent("monitor_touch", "monitor_24", 1, 1)
|
||||||
|
end
|
||||||
|
g.drawText(mon, 1, H-4, "Export complete!", colors.lime, colors.black)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handleExportEvents()
|
||||||
|
while EXPORTING do
|
||||||
|
local event, monName, x, y = os.pullEvent("monitor_touch")
|
||||||
|
if monName == "monitor_24" and y >= H-2 then
|
||||||
|
if x >= 27 then
|
||||||
|
EXPORTING = false
|
||||||
|
elseif x >= 14 then
|
||||||
|
EXPORT_REPORT = true
|
||||||
|
else
|
||||||
|
EXPORT_SKIP = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handleSchematicUrl(url)
|
||||||
|
clearMainPanel()
|
||||||
|
if url == nil then
|
||||||
|
g.drawText(mon, 1, 8, "No URL was entered. Quitting.", colors.white, colors.black)
|
||||||
|
RUNNING = false
|
||||||
|
os.sleep(2)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
g.drawText(mon, 1, 8, "Fetching item lists from URL...", colors.lightGray, colors.black)
|
||||||
|
local itemLists, err = fetchItemLists(url)
|
||||||
|
if not itemLists then
|
||||||
|
g.drawText(mon, 1, 9, "Failed to fetch item lists.", colors.red, colors.black)
|
||||||
|
g.drawText(mon, 1, 10, err, colors.red, colors.black)
|
||||||
|
os.sleep(3)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
g.drawText(mon, 1, 9, "Got lists for "..(#itemLists).." schematics.", colors.white, colors.black)
|
||||||
|
local y = 10
|
||||||
|
for i, itemList in pairs(itemLists) do
|
||||||
|
local count = itemList.__COUNT__
|
||||||
|
local name = itemList.__NAME__
|
||||||
|
g.drawText(mon, 2, y, count.."x "..name, colors.white, colors.black)
|
||||||
|
y = y+1
|
||||||
|
if y == H and i < #itemLists then
|
||||||
|
local numRemaining = #itemLists - i
|
||||||
|
g.drawText(mon, 2, y, "... and "..numRemaining.." more.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
os.sleep(3)
|
||||||
|
-- Draw control buttons.
|
||||||
|
g.fillRect(mon, 1, H-2, 13, 3, colors.blue)
|
||||||
|
g.drawText(mon, 5, H-1, "Skip", colors.white)
|
||||||
|
g.fillRect(mon, 14, H-2, 13, 3, colors.yellow)
|
||||||
|
g.drawText(mon, 14, H-1, "Report Error", colors.lightBlue)
|
||||||
|
g.fillRect(mon, 27, H-2, 13, 3, colors.red)
|
||||||
|
g.drawText(mon, 31, H-1, "Quit", colors.white)
|
||||||
|
EXPORTING = true
|
||||||
|
local fExport = function() exportSchematics(itemLists) end
|
||||||
|
local fHandleEvents = function() handleExportEvents() end
|
||||||
|
parallel.waitForAll(fExport, fHandleEvents)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- MAIN SCRIPT
|
||||||
|
|
||||||
|
g.clear(mon, colors.black)
|
||||||
|
g.fillRect(mon, 1, 1, W, 3, colors.yellow)
|
||||||
|
g.drawTextCenter(mon, W/2, 2, "Schematic Exporter", colors.black)
|
||||||
|
|
||||||
|
g.fillRect(mon, 1, 4, W, 3, colors.gray)
|
||||||
|
g.drawText(mon, 2, 4, "Progress", colors.white)
|
||||||
|
g.drawXLine(mon, 2, W-1, 5, colors.lightGray)
|
||||||
|
|
||||||
|
while RUNNING do
|
||||||
|
local url = promptForUrlInput()
|
||||||
|
handleSchematicUrl(url)
|
||||||
|
end
|
|
@ -17,6 +17,7 @@ void startServer() {
|
||||||
PathDelegatingHandler handler = new PathDelegatingHandler();
|
PathDelegatingHandler handler = new PathDelegatingHandler();
|
||||||
handler.addMapping("POST", "/extracts", &handleExtract);
|
handler.addMapping("POST", "/extracts", &handleExtract);
|
||||||
handler.addMapping("GET", "/extracts/{extractId}", &getExtract);
|
handler.addMapping("GET", "/extracts/{extractId}", &getExtract);
|
||||||
|
handler.addMapping("POST", "/item-reports", &handleItemReport);
|
||||||
handler.addMapping("GET", "/status", (ref HttpRequestContext ctx) {
|
handler.addMapping("GET", "/status", (ref HttpRequestContext ctx) {
|
||||||
ctx.response.setStatus(HttpStatus.OK);
|
ctx.response.setStatus(HttpStatus.OK);
|
||||||
ctx.response.writeBodyString("online");
|
ctx.response.writeBodyString("online");
|
||||||
|
@ -42,4 +43,14 @@ private void getExtract(ref HttpRequestContext ctx) {
|
||||||
string extractId = ctx.request.getPathParamAs!string("extractId");
|
string extractId = ctx.request.getPathParamAs!string("extractId");
|
||||||
const extractFile = buildPath(EXTRACTS_DIR, extractId ~ ".json");
|
const extractFile = buildPath(EXTRACTS_DIR, extractId ~ ".json");
|
||||||
fileResponse(ctx.response, extractFile, "application/json");
|
fileResponse(ctx.response, extractFile, "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleItemReport(ref HttpRequestContext ctx) {
|
||||||
|
import std.string : strip;
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
string itemName = ctx.request.readBodyAsString().strip();
|
||||||
|
File f = File("item-reports.txt", "a");
|
||||||
|
f.writeln(itemName);
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue