Context.address is now deprecated in favor of the new Context.node getter; emulating peripheral file system mounting; catching any errors in connect and disconnect callbacks

This commit is contained in:
Florian Nücke 2014-02-08 14:52:34 +01:00
parent 110d15ff50
commit 597770dd1b
11 changed files with 77 additions and 27 deletions

View File

@ -7,9 +7,17 @@ package li.cil.oc.api.network;
public interface Context { public interface Context {
/** /**
* The network address of the computer. * The network address of the computer.
*
* @deprecated Use <tt>node().address()</tt> instead.
*/ */
@Deprecated
String address(); String address();
/**
* The node through which the computer is attached to the component network.
*/
Node node();
/** /**
* Tests whether a player is allowed to use the computer. * Tests whether a player is allowed to use the computer.
* <p/> * <p/>

View File

@ -2,9 +2,12 @@ package li.cil.oc.api.prefab;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import dan200.computer.api.*; import dan200.computer.api.*;
import li.cil.oc.api.FileSystem;
import li.cil.oc.api.Network;
import li.cil.oc.api.network.Arguments; import li.cil.oc.api.network.Arguments;
import li.cil.oc.api.network.Context; import li.cil.oc.api.network.Context;
import li.cil.oc.api.network.Node; import li.cil.oc.api.network.Node;
import li.cil.oc.api.network.Visibility;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -25,6 +28,7 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
public ManagedPeripheral(final IPeripheral peripheral) { public ManagedPeripheral(final IPeripheral peripheral) {
this.peripheral = peripheral; this.peripheral = peripheral;
_methods = Arrays.asList(peripheral.getMethodNames()); _methods = Arrays.asList(peripheral.getMethodNames());
node = Network.newNode(this, Visibility.Network).create();
} }
@Override @Override
@ -45,8 +49,8 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
} }
} }
final FakeComputerAccess access; final FakeComputerAccess access;
if (accesses.containsKey(context.address())) { if (accesses.containsKey(context.node().address())) {
access = accesses.get(context.address()); access = accesses.get(context.node().address());
} else { } else {
// The calling contexts is not visible to us, meaning we never got // The calling contexts is not visible to us, meaning we never got
// an onConnect for it. Create a temporary access. // an onConnect for it. Create a temporary access.
@ -76,6 +80,7 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
} else if (node == this.node) { } else if (node == this.node) {
for (FakeComputerAccess access : accesses.values()) { for (FakeComputerAccess access : accesses.values()) {
peripheral.detach(access); peripheral.detach(access);
access.close();
} }
accesses.clear(); accesses.clear();
} }
@ -87,30 +92,53 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
private static class FakeComputerAccess implements IComputerAccess { private static class FakeComputerAccess implements IComputerAccess {
protected final ManagedPeripheral owner; protected final ManagedPeripheral owner;
protected final Context context; protected final Context context;
protected final Map<String, li.cil.oc.api.network.ManagedEnvironment> fileSystems = new HashMap<String, li.cil.oc.api.network.ManagedEnvironment>();
public FakeComputerAccess(final ManagedPeripheral owner, final Context context) { public FakeComputerAccess(final ManagedPeripheral owner, final Context context) {
this.owner = owner; this.owner = owner;
this.context = context; this.context = context;
} }
public void close() {
for (li.cil.oc.api.network.ManagedEnvironment fileSystem : fileSystems.values()) {
fileSystem.node().remove();
}
fileSystems.clear();
}
@Override @Override
public String mount(final String desiredLocation, final IMount mount) { public String mount(final String desiredLocation, final IMount mount) {
throw new UnsupportedOperationException(); if (fileSystems.containsKey(desiredLocation)) {
return null;
}
return mount(desiredLocation, FileSystem.asManagedEnvironment(FileSystem.fromComputerCraft(mount)));
} }
@Override @Override
public String mountWritable(final String desiredLocation, final IWritableMount mount) { public String mountWritable(final String desiredLocation, final IWritableMount mount) {
throw new UnsupportedOperationException(); if (fileSystems.containsKey(desiredLocation)) {
return null;
}
return mount(desiredLocation, FileSystem.asManagedEnvironment(FileSystem.fromComputerCraft(mount)));
}
private String mount(final String path, final li.cil.oc.api.network.ManagedEnvironment fileSystem) {
fileSystems.put(path, fileSystem);
context.node().connect(fileSystem.node());
return path;
} }
@Override @Override
public void unmount(final String location) { public void unmount(final String location) {
throw new UnsupportedOperationException(); final li.cil.oc.api.network.ManagedEnvironment fileSystem = fileSystems.remove(location);
if (fileSystem != null) {
fileSystem.node().remove();
}
} }
@Override @Override
public int getID() { public int getID() {
return context.address().hashCode(); return context.node().address().hashCode();
} }
@Override @Override

View File

@ -65,7 +65,7 @@ class Terminal(val parent: Delegator) extends Delegate {
rack.terminals(slot).key = Some(key) rack.terminals(slot).key = Some(key)
ServerPacketSender.sendServerState(rack, slot) ServerPacketSender.sendServerState(rack, slot)
stack.getTagCompound.setString(Settings.namespace + "key", key) stack.getTagCompound.setString(Settings.namespace + "key", key)
stack.getTagCompound.setString(Settings.namespace + "server", server.machine.address) stack.getTagCompound.setString(Settings.namespace + "server", server.machine.node.address)
player.inventory.onInventoryChanged() player.inventory.onInventoryChanged()
case _ => // Huh? case _ => // Huh?
} }

View File

@ -169,7 +169,7 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
override protected def onRedstoneInputChanged(side: ForgeDirection) { override protected def onRedstoneInputChanged(side: ForgeDirection) {
super.onRedstoneInputChanged(side) super.onRedstoneInputChanged(side)
computer.signal("redstone_changed", computer.address, Int.box(toLocal(side).ordinal())) computer.signal("redstone_changed", computer.node.address, Int.box(toLocal(side).ordinal()))
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -248,7 +248,7 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun
override def writeToNBTForClient(nbt: NBTTagCompound) { override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt) super.writeToNBTForClient(nbt)
nbt.setByteArray("isServerRunning", _isRunning.map(value => (if (value) 1 else 0).toByte)) nbt.setByteArray("isServerRunning", _isRunning.map(value => (if (value) 1 else 0).toByte))
nbt.setNewTagList("isPresent", servers.map(value => new NBTTagString(null, value.fold("")(_.machine.address)))) nbt.setNewTagList("isPresent", servers.map(value => new NBTTagString(null, value.fold("")(_.machine.node.address))))
nbt.setByteArray("sides", sides.map(_.ordinal.toByte)) nbt.setByteArray("sides", sides.map(_.ordinal.toByte))
nbt.setNewTagList("terminals", terminals.map(t => { nbt.setNewTagList("terminals", terminals.map(t => {
val terminalNbt = new NBTTagCompound() val terminalNbt = new NBTTagCompound()
@ -324,7 +324,7 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun
override protected def onRedstoneInputChanged(side: ForgeDirection) { override protected def onRedstoneInputChanged(side: ForgeDirection) {
super.onRedstoneInputChanged(side) super.onRedstoneInputChanged(side)
servers collect { servers collect {
case Some(server) => server.machine.signal("redstone_changed", server.machine.address, Int.box(toLocal(side).ordinal())) case Some(server) => server.machine.signal("redstone_changed", server.machine.node.address, Int.box(toLocal(side).ordinal()))
} }
} }

View File

@ -2,7 +2,7 @@ package li.cil.oc.common.tileentity
import cpw.mods.fml.common.Optional import cpw.mods.fml.common.Optional
import cpw.mods.fml.relauncher.{Side, SideOnly} import cpw.mods.fml.relauncher.{Side, SideOnly}
import li.cil.oc.{Settings, api} import li.cil.oc.api
import li.cil.oc.api.Network import li.cil.oc.api.Network
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.client.gui import li.cil.oc.client.gui
@ -67,7 +67,7 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI
// Use the same address we use internally on the outside. // Use the same address we use internally on the outside.
if (isServer) { if (isServer) {
val nbt = new NBTTagCompound() val nbt = new NBTTagCompound()
nbt.setString("address", robot.address) nbt.setString("address", robot.node.address)
node.load(nbt) node.load(nbt)
} }
Network.joinOrCreateNetwork(this) Network.joinOrCreateNetwork(this)

View File

@ -292,7 +292,7 @@ object PacketSender {
t.servers.foreach { t.servers.foreach {
case Some(server) => case Some(server) =>
pb.writeBoolean(true) pb.writeBoolean(true)
pb.writeUTF(server.machine.address) pb.writeUTF(server.machine.node.address)
case _ => case _ =>
pb.writeBoolean(false) pb.writeBoolean(false)
} }

View File

@ -20,7 +20,10 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@Callback(direct = true) @Callback(direct = true)
def getLabel(context: Context, args: Arguments): Array[AnyRef] = result(label.getLabel) def getLabel(context: Context, args: Arguments): Array[AnyRef] = label match {
case value: Label => result(label.getLabel)
case _ => null
}
@Callback @Callback
def setLabel(context: Context, args: Arguments): Array[AnyRef] = { def setLabel(context: Context, args: Arguments): Array[AnyRef] = {
@ -101,7 +104,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
Option(fileSystem.getHandle(handle)) match { Option(fileSystem.getHandle(handle)) match {
case Some(file) => case Some(file) =>
owners.get(context.address) match { owners.get(context.node.address) match {
case Some(set) if set.remove(handle) => file.close() case Some(set) if set.remove(handle) => file.close()
case _ => throw new IOException("bad file descriptor") case _ => throw new IOException("bad file descriptor")
} }
@ -112,14 +115,14 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
@Callback @Callback
def open(context: Context, args: Arguments): Array[AnyRef] = { def open(context: Context, args: Arguments): Array[AnyRef] = {
if (owners.get(context.address).fold(false)(_.size >= Settings.get.maxHandles)) { if (owners.get(context.node.address).fold(false)(_.size >= Settings.get.maxHandles)) {
throw new IOException("too many open handles") throw new IOException("too many open handles")
} }
val path = args.checkString(0) val path = args.checkString(0)
val mode = if (args.count > 1) args.checkString(1) else "r" val mode = if (args.count > 1) args.checkString(1) else "r"
val handle = fileSystem.open(clean(path), parseMode(mode)) val handle = fileSystem.open(clean(path), parseMode(mode))
if (handle > 0) { if (handle > 0) {
owners.getOrElseUpdate(context.address, mutable.Set.empty[Int]) += handle owners.getOrElseUpdate(context.node.address, mutable.Set.empty[Int]) += handle
} }
result(handle) result(handle)
} }
@ -128,7 +131,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
def read(context: Context, args: Arguments): Array[AnyRef] = { def read(context: Context, args: Arguments): Array[AnyRef] = {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1))) val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1)))
checkOwner(context.address, handle) checkOwner(context.node.address, handle)
Option(fileSystem.getHandle(handle)) match { Option(fileSystem.getHandle(handle)) match {
case Some(file) => case Some(file) =>
// Limit size of read buffer to avoid crazy allocations. // Limit size of read buffer to avoid crazy allocations.
@ -160,7 +163,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val whence = args.checkString(1) val whence = args.checkString(1)
val offset = args.checkInteger(2) val offset = args.checkInteger(2)
checkOwner(context.address, handle) checkOwner(context.node.address, handle)
Option(fileSystem.getHandle(handle)) match { Option(fileSystem.getHandle(handle)) match {
case Some(file) => case Some(file) =>
whence match { whence match {
@ -181,7 +184,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
if (!node.tryChangeBuffer(-Settings.get.hddWriteCost * value.length)) { if (!node.tryChangeBuffer(-Settings.get.hddWriteCost * value.length)) {
throw new IOException("not enough energy") throw new IOException("not enough energy")
} }
checkOwner(context.address, handle) checkOwner(context.node.address, handle)
Option(fileSystem.getHandle(handle)) match { Option(fileSystem.getHandle(handle)) match {
case Some(file) => file.write(value); result(true) case Some(file) => file.write(value); result(true)
case _ => throw new IOException("bad file descriptor") case _ => throw new IOException("bad file descriptor")

View File

@ -49,7 +49,7 @@ class InternetCard(val owner: Context) extends ManagedComponent {
@Callback @Callback
def request(context: Context, args: Arguments): Array[AnyRef] = { def request(context: Context, args: Arguments): Array[AnyRef] = {
if (context.address != owner.address) { if (context.node.address != owner.node.address) {
throw new IllegalArgumentException("can only be used by the owning computer") throw new IllegalArgumentException("can only be used by the owning computer")
} }
val address = args.checkString(0) val address = args.checkString(0)
@ -235,7 +235,7 @@ class InternetCard(val owner: Context) extends ManagedComponent {
override def onMessage(message: Message) { override def onMessage(message: Message) {
super.onMessage(message) super.onMessage(message)
message.data match { message.data match {
case Array() if (message.name == "computer.stopped" || message.name == "computer.started") && message.source.address == owner.address => case Array() if (message.name == "computer.stopped" || message.name == "computer.started") && message.source.address == owner.node.address =>
connections.values.foreach(_.close()) connections.values.foreach(_.close())
connections.clear() connections.clear()
InternetCard.this.synchronized { InternetCard.this.synchronized {

View File

@ -483,8 +483,10 @@ class Machine(val owner: Machine.Owner) extends ManagedComponent with Context wi
val invalid = mutable.Set.empty[String] val invalid = mutable.Set.empty[String]
for ((address, name) <- components) { for ((address, name) <- components) {
if (node.network.node(address) == null) { if (node.network.node(address) == null) {
OpenComputers.log.warning("A component of type '" + name + OpenComputers.log.fine("A component of type '%s' disappeared! This usually means that it didn't save its node.".format(name))
"' disappeared! This usually means that it didn't save its node.") if (name == "filesystem") {
OpenComputers.log.fine("If this was a file system provided by a ComputerCraft peripheral, this is normal.");
}
signal("component_removed", address, name) signal("component_removed", address, name)
invalid += address invalid += address
} }

View File

@ -1,7 +1,8 @@
package li.cil.oc.server.network package li.cil.oc.server.network
import li.cil.oc.api import java.util.logging.Level
import li.cil.oc.api.network.{Environment, Visibility, Node => ImmutableNode} import li.cil.oc.api.network.{Environment, Visibility, Node => ImmutableNode}
import li.cil.oc.{OpenComputers, api}
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._ import scala.collection.convert.WrapAsScala._
@ -43,11 +44,19 @@ trait Node extends ImmutableNode {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def onConnect(node: ImmutableNode) { def onConnect(node: ImmutableNode) {
host.onConnect(node) try {
host.onConnect(node)
} catch {
case e: Throwable => OpenComputers.log.log(Level.WARNING, "A component of type '%s' threw an error while being connected to the component network.".format(host.getClass.getName), e)
}
} }
def onDisconnect(node: ImmutableNode) { def onDisconnect(node: ImmutableNode) {
host.onDisconnect(node) try {
host.onDisconnect(node)
} catch {
case e: Throwable => OpenComputers.log.log(Level.WARNING, "A component of type '%s' threw an error while being disconnected from the component network.".format(host.getClass.getName), e)
}
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //