From dbd2f3067f997f2ef318a97aed6cccf8f1067871 Mon Sep 17 00:00:00 2001 From: payonel Date: Sat, 4 Feb 2017 11:25:01 -0800 Subject: [PATCH 1/4] term safe slow write, fix pastebin get, low mem loadfile fix --- .../assets/opencomputers/loot/openos/bin/pastebin.lua | 2 +- .../assets/opencomputers/loot/openos/boot/00_base.lua | 3 ++- .../assets/opencomputers/loot/openos/lib/term.lua | 8 +++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/pastebin.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/pastebin.lua index 685428499..b5ff93473 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/pastebin.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/pastebin.lua @@ -21,7 +21,7 @@ local function get(pasteId, filename) end io.write("Downloading from pastebin.com... ") - local url = "http://pastebin.com/raw.php?i=" .. pasteId + local url = "http://pastebin.com/raw/" .. pasteId local result, response = pcall(internet.request, url) if result then io.write("success.\n") diff --git a/src/main/resources/assets/opencomputers/loot/openos/boot/00_base.lua b/src/main/resources/assets/opencomputers/loot/openos/boot/00_base.lua index 87311875c..581584347 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/boot/00_base.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/boot/00_base.lua @@ -15,7 +15,8 @@ function loadfile(filename, mode, env) end table.insert(buffer, data) end - buffer = table.concat(buffer):gsub("^#![^\n]+", "") -- remove shebang if any + buffer[1] = (buffer[1] or ""):gsub("^#![^\n]+", "") -- remove shebang if any + buffer = table.concat(buffer) return load(buffer, "=" .. filename, mode, env) end diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua index 297fbd890..b936ac261 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua @@ -390,7 +390,13 @@ function term.drawText(value, wrap, window) local function scroll(_sy,_y) return _sy + term.internal.scroll(window,_y-h), math.min(_y,h) end + local uptime = computer.uptime + local last_sleep = uptime() while index <= vlen do + if uptime() - last_sleep > 4 then + os.sleep(0) + last_sleep = uptime() + end local si,ei = value:find("[\t\r\n\a]", index) si = si or vlen+1 if index==si then @@ -401,7 +407,7 @@ function term.drawText(value, wrap, window) x,y=1,y+1 sy,y = scroll(sy,y) elseif delim=="\a" and not beeped then - require("computer").beep() + computer.beep() beeped = true end cr_last = delim == "\r" From e8352fb07f06f42c484f3bf2d991043b5f0f663a Mon Sep 17 00:00:00 2001 From: Vexatos Date: Sat, 4 Feb 2017 22:11:08 +0100 Subject: [PATCH 2/4] Use lower-case name for checking debug card access so that comparison with whitelist works properly. Closes #2262. --- src/main/scala/li/cil/oc/Settings.scala | 2 +- src/main/scala/li/cil/oc/common/item/DebugCard.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 09db72e59..a7a8efee4 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -660,7 +660,7 @@ object Settings { } def checkAccess(ctxOpt: Option[DebugCard.AccessContext]): Option[String] = ctxOpt match { - case Some(ctx) => values.get(ctx.player) match { + case Some(ctx) => values.get(ctx.player.toLowerCase) match { case Some(x) => if (x == ctx.nonce) None else Some("debug card is invalidated, please re-bind it to yourself") diff --git a/src/main/scala/li/cil/oc/common/item/DebugCard.scala b/src/main/scala/li/cil/oc/common/item/DebugCard.scala index 7aaf1c669..7c5a56853 100644 --- a/src/main/scala/li/cil/oc/common/item/DebugCard.scala +++ b/src/main/scala/li/cil/oc/common/item/DebugCard.scala @@ -19,7 +19,7 @@ class DebugCard(val parent: Delegator) extends traits.Delegate { } override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = { - if (player.isSneaking) { + if (!world.isRemote && player.isSneaking) { val data = new DebugCardData(stack) val name = player.getCommandSenderName From d8471278ba18f5f09e2e8c6cdf494da2b498a02b Mon Sep 17 00:00:00 2001 From: payonel Date: Sat, 4 Feb 2017 14:48:47 -0800 Subject: [PATCH 3/4] require("internet").request now returns a function object The function object can be called to read from the stream, same usage as before But the object also exposes the request handle userdata, to allow calling close for example: ``` local request = require("internet").request("http://www.google.com") print(request()) -- same as before request:close() -- clean up resources now, as opposed to waiting for gc ``` closes #2255 --- .../loot/openos/lib/internet.lua | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/internet.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/internet.lua index 0b252bb30..c924a0dab 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/internet.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/internet.lua @@ -11,10 +11,10 @@ function internet.request(url, data, headers) checkArg(2, data, "string", "table", "nil") checkArg(3, headers, "table", "nil") - local inet = component.internet - if not inet then + if not component.isAvailable("internet") then error("no primary internet card found", 2) end + local inet = component.internet local post if type(data) == "string" then @@ -31,23 +31,35 @@ function internet.request(url, data, headers) error(reason, 2) end - return function() - while true do - local data, reason = request.read() - if not data then - request.close() - if reason then - error(reason, 2) - else - return nil -- eof + return setmetatable( + { + ["()"] = "function():string -- Tries to read data from the socket stream and return the read byte array.", + close = setmetatable({}, + { + __call = request.close, + __tostring = function() return "function() -- closes the connection" end + }) + }, + { + __call = function() + while true do + local data, reason = request.read() + if not data then + request.close() + if reason then + error(reason, 2) + else + return nil -- eof + end + elseif #data > 0 then + return data end - elseif #data > 0 then - return data + -- else: no data, block + os.sleep(0) end - -- else: no data, block - os.sleep(0) - end - end + end, + __index = request, + }) end ------------------------------------------------------------------------------- From 2751cec8c1526d489976627b4ffa0d6731616ee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 5 Feb 2017 16:01:32 +0100 Subject: [PATCH 4/4] Fixed nodes able to reach an added node but not being reachable by the added node not being notified of the node being added. This fixes screens stopping to respond *in some configurations* when their chunk is loaded. Closes #2225. --- .../java/li/cil/oc/api/network/Network.java | 2 +- .../oc/server/component/GraphicsCard.scala | 36 ++++++++----------- .../li/cil/oc/server/network/Network.scala | 20 +++++++---- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/java/li/cil/oc/api/network/Network.java b/src/main/java/li/cil/oc/api/network/Network.java index 3d76f0014..e1d6fa893 100644 --- a/src/main/java/li/cil/oc/api/network/Network.java +++ b/src/main/java/li/cil/oc/api/network/Network.java @@ -103,7 +103,7 @@ public interface Network { Iterable nodes(); /** - * The list of addressed nodes in the network visible to the specified node. + * The list of addressed nodes in the network reachable by the specified node. *

* This does not include nodes with a visibility of None * or a visibility of Neighbors when there is no direct connection diff --git a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala index 0fe212ccf..90824d085 100644 --- a/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala +++ b/src/main/scala/li/cil/oc/server/component/GraphicsCard.scala @@ -3,13 +3,13 @@ package li.cil.oc.server.component import java.util import li.cil.oc.Constants -import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute -import li.cil.oc.api.driver.DeviceInfo.DeviceClass import li.cil.oc.Localization import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.Network import li.cil.oc.api.driver.DeviceInfo +import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute +import li.cil.oc.api.driver.DeviceInfo.DeviceClass import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context @@ -72,32 +72,15 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI ) def capacityInfo = (maxResolution._1 * maxResolution._2).toString + def widthInfo = Array("1", "4", "8").apply(maxDepth.ordinal()) + def clockInfo = ((2000 / setBackgroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setForegroundCosts(tier)).toInt / 100).toString + "/" + ((2000 / setPaletteColorCosts(tier)).toInt / 100).toString + "/" + ((2000 / setCosts(tier)).toInt / 100).toString + "/" + ((2000 / copyCosts(tier)).toInt / 100).toString + "/" + ((2000 / fillCosts(tier)).toInt / 100).toString override def getDeviceInfo: util.Map[String, String] = deviceInfo // ----------------------------------------------------------------------- // - override val canUpdate = true - - override def update() { - super.update() - if (node.network != null && screenInstance.isEmpty && screenAddress.isDefined) { - Option(node.network.node(screenAddress.get)) match { - case Some(node: Node) if node.host.isInstanceOf[api.internal.TextBuffer] => - screenInstance = Some(node.host.asInstanceOf[api.internal.TextBuffer]) - case _ => - // This could theoretically happen after loading an old address, but - // if the screen either disappeared between saving and now or changed - // type. The first scenario is more likely, and could happen if the - // chunk the screen is in isn't loaded when the chunk the GPU is in - // gets loaded. - screenAddress = None - } - } - } - @Callback(doc = """function(address:string[, reset:boolean=true]):boolean -- Binds the GPU to the screen with the specified address and resets screen settings if `reset` is true.""") def bind(context: Context, args: Arguments): Array[AnyRef] = { val address = args.checkString(0) @@ -395,6 +378,17 @@ class GraphicsCard(val tier: Int) extends prefab.ManagedEnvironment with DeviceI } } + override def onConnect(node: Node): Unit = { + super.onConnect(node) + if (screenInstance.isEmpty && screenAddress.fold(false)(_ == node.address)) { + node.host match { + case buffer: api.internal.TextBuffer => + screenInstance = Some(buffer) + case _ => // Not the screen node we're looking for. + } + } + } + override def onDisconnect(node: Node) { super.onDisconnect(node) if (node == this.node || screenAddress.contains(node.address)) { diff --git a/src/main/scala/li/cil/oc/server/network/Network.scala b/src/main/scala/li/cil/oc/server/network/Network.scala index ed3e1762d..95a11b980 100644 --- a/src/main/scala/li/cil/oc/server/network/Network.scala +++ b/src/main/scala/li/cil/oc/server/network/Network.scala @@ -165,12 +165,20 @@ private class Network private(private val data: mutable.Map[String, Network.Vert def nodes: Iterable[ImmutableNode] = data.values.map(_.data) - def nodes(reference: ImmutableNode): Iterable[ImmutableNode] = { + def reachableNodes(reference: ImmutableNode): Iterable[ImmutableNode] = { val referenceNeighbors = neighbors(reference).toSet nodes.filter(node => node != reference && (node.reachability == Visibility.Network || (node.reachability == Visibility.Neighbors && referenceNeighbors.contains(node)))) } + def reachingNodes(reference: ImmutableNode): Iterable[ImmutableNode] = { + if (reference.reachability == Visibility.Network) nodes.filter(node => node != reference) + else if (reference.reachability == Visibility.Neighbors) { + val referenceNeighbors = neighbors(reference).toSet + nodes.filter(node => node != reference && referenceNeighbors.contains(node)) + } else Iterable.empty + } + def neighbors(node: ImmutableNode): Iterable[ImmutableNode] = { data.get(node.address) match { case Some(n) if n.data == node => n.edges.map(_.other(n).data) @@ -199,13 +207,13 @@ private class Network private(private val data: mutable.Map[String, Network.Vert def sendToReachable(source: ImmutableNode, name: String, args: AnyRef*) = { if (source.network != wrapper) throw new IllegalArgumentException("Source node must be in this network.") - send(source, nodes(source), name, args: _*) + send(source, reachableNodes(source), name, args: _*) } def sendToVisible(source: ImmutableNode, name: String, args: AnyRef*) = { if (source.network != wrapper) throw new IllegalArgumentException("Source node must be in this network.") - send(source, nodes(source) collect { + send(source, reachableNodes(source) collect { case component: api.network.Component if component.canBeSeenFrom(source) => component }, name, args: _*) } @@ -241,11 +249,11 @@ private class Network private(private val data: mutable.Map[String, Network.Vert connects += ((addedNode, Iterable(addedNode))) case Visibility.Neighbors => connects += ((addedNode, Iterable(addedNode) ++ neighbors(addedNode))) - nodes(addedNode).foreach(node => connects += ((node, Iterable(addedNode)))) + reachingNodes(addedNode).foreach(node => connects += ((node, Iterable(addedNode)))) case Visibility.Network => // Explicitly send to the added node itself first. connects += ((addedNode, Iterable(addedNode) ++ nodes.filter(_ != addedNode))) - nodes(addedNode).foreach(node => connects += ((node, Iterable(addedNode)))) + reachingNodes(addedNode).foreach(node => connects += ((node, Iterable(addedNode)))) } } else { @@ -767,7 +775,7 @@ object Network extends api.detail.NetworkAPI { def nodes = network.nodes.asJava - def nodes(reference: ImmutableNode) = network.nodes(reference).asJava + def nodes(reference: ImmutableNode) = network.reachableNodes(reference).asJava def neighbors(node: ImmutableNode) = network.neighbors(node).asJava