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 {
/**
* The network address of the computer.
*
* @deprecated Use <tt>node().address()</tt> instead.
*/
@Deprecated
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.
* <p/>

View File

@ -2,9 +2,12 @@ package li.cil.oc.api.prefab;
import com.google.common.collect.Iterables;
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.Context;
import li.cil.oc.api.network.Node;
import li.cil.oc.api.network.Visibility;
import java.util.Arrays;
import java.util.HashMap;
@ -25,6 +28,7 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
public ManagedPeripheral(final IPeripheral peripheral) {
this.peripheral = peripheral;
_methods = Arrays.asList(peripheral.getMethodNames());
node = Network.newNode(this, Visibility.Network).create();
}
@Override
@ -45,8 +49,8 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
}
}
final FakeComputerAccess access;
if (accesses.containsKey(context.address())) {
access = accesses.get(context.address());
if (accesses.containsKey(context.node().address())) {
access = accesses.get(context.node().address());
} else {
// The calling contexts is not visible to us, meaning we never got
// 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) {
for (FakeComputerAccess access : accesses.values()) {
peripheral.detach(access);
access.close();
}
accesses.clear();
}
@ -87,30 +92,53 @@ public class ManagedPeripheral extends ManagedEnvironment implements li.cil.oc.a
private static class FakeComputerAccess implements IComputerAccess {
protected final ManagedPeripheral owner;
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) {
this.owner = owner;
this.context = context;
}
public void close() {
for (li.cil.oc.api.network.ManagedEnvironment fileSystem : fileSystems.values()) {
fileSystem.node().remove();
}
fileSystems.clear();
}
@Override
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
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
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
public int getID() {
return context.address().hashCode();
return context.node().address().hashCode();
}
@Override

View File

@ -65,7 +65,7 @@ class Terminal(val parent: Delegator) extends Delegate {
rack.terminals(slot).key = Some(key)
ServerPacketSender.sendServerState(rack, slot)
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()
case _ => // Huh?
}

View File

@ -169,7 +169,7 @@ abstract class Computer(isRemote: Boolean) extends Environment with ComponentInv
override protected def onRedstoneInputChanged(side: ForgeDirection) {
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) {
super.writeToNBTForClient(nbt)
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.setNewTagList("terminals", terminals.map(t => {
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) {
super.onRedstoneInputChanged(side)
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.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.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.
if (isServer) {
val nbt = new NBTTagCompound()
nbt.setString("address", robot.address)
nbt.setString("address", robot.node.address)
node.load(nbt)
}
Network.joinOrCreateNetwork(this)

View File

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

View File

@ -20,7 +20,10 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
// ----------------------------------------------------------------------- //
@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
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)
Option(fileSystem.getHandle(handle)) match {
case Some(file) =>
owners.get(context.address) match {
owners.get(context.node.address) match {
case Some(set) if set.remove(handle) => file.close()
case _ => throw new IOException("bad file descriptor")
}
@ -112,14 +115,14 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
@Callback
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")
}
val path = args.checkString(0)
val mode = if (args.count > 1) args.checkString(1) else "r"
val handle = fileSystem.open(clean(path), parseMode(mode))
if (handle > 0) {
owners.getOrElseUpdate(context.address, mutable.Set.empty[Int]) += handle
owners.getOrElseUpdate(context.node.address, mutable.Set.empty[Int]) += 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] = {
val handle = args.checkInteger(0)
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 {
case Some(file) =>
// 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 whence = args.checkString(1)
val offset = args.checkInteger(2)
checkOwner(context.address, handle)
checkOwner(context.node.address, handle)
Option(fileSystem.getHandle(handle)) match {
case Some(file) =>
whence match {
@ -181,7 +184,7 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label) extends ManagedC
if (!node.tryChangeBuffer(-Settings.get.hddWriteCost * value.length)) {
throw new IOException("not enough energy")
}
checkOwner(context.address, handle)
checkOwner(context.node.address, handle)
Option(fileSystem.getHandle(handle)) match {
case Some(file) => file.write(value); result(true)
case _ => throw new IOException("bad file descriptor")

View File

@ -49,7 +49,7 @@ class InternetCard(val owner: Context) extends ManagedComponent {
@Callback
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")
}
val address = args.checkString(0)
@ -235,7 +235,7 @@ class InternetCard(val owner: Context) extends ManagedComponent {
override def onMessage(message: Message) {
super.onMessage(message)
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.clear()
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]
for ((address, name) <- components) {
if (node.network.node(address) == null) {
OpenComputers.log.warning("A component of type '" + name +
"' disappeared! This usually means that it didn't save its node.")
OpenComputers.log.fine("A component of type '%s' disappeared! This usually means that it didn't save its node.".format(name))
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)
invalid += address
}

View File

@ -1,7 +1,8 @@
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.{OpenComputers, api}
import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
@ -43,11 +44,19 @@ trait Node extends ImmutableNode {
// ----------------------------------------------------------------------- //
def onConnect(node: ImmutableNode) {
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) {
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)
}
}
// ----------------------------------------------------------------------- //