public void receiveUpdate(DatagramIn dg, IDistributedObject distObj, UInt16 field_id) { Debug.Log("Receive update for class " + distObj.getClass() + " field ID" + field_id); // first get the array of fields we'll need to unpack string[] t_fields = DCFile.fieldLookup[field_id]; // next, define an empty array of params the size of the number of fields object[] t_params = new object[t_fields.Length]; // unpack the parameters for (int i = 0; i < t_fields.Length; ++i) { t_params[i] = unserializeType(dg, t_fields[i]); } // finally, use reflection to call the function Type t_type = distObj.GetType(); MethodInfo t_method = t_type.GetMethod(DCFile.fieldNameLookup[field_id]); t_method.Invoke(distObj, t_params); }
// Add this DistributedObject to the repository. public void AddObject(IDistributedObject obj) { DistributedObjectId doId = obj.DistributedObjectId; // Store in the dictionary of objects mObjectIds[doId] = obj; }
/// <summary> /// Returns the object referenced by the doId or null if not found on this state server. /// </summary> /// <param name="doId"></param> /// <returns></returns> public IDistributedObject GetObject(DistributedObjectId doId) { IDistributedObject obj = null; mObjectIds.TryGetValue(doId, out obj); return(obj); }
/// <summary> /// Gets a disposable object that will destroy and dispose a distributed /// object when disposed. /// </summary> /// <param name="o">The object.</param> /// <returns>A disposable object.</returns> protected IAsyncDisposable DestroyAndDispose(IDistributedObject o) { return(new AsyncDisposable(async() => { await Client.DestroyAsync(o); await o.DisposeAsync(); })); }
/*******************************/ // IMessageRouter Functions /*******************************/ public void ReceiveMessage(Message message) { switch (message.MessageType) { case MessageType.Create: IClientDistributedObject distributedObject = mDistributedObjectFactory.CreateDistributedObject(message.DistributedObjectId, message.Data); if (distributedObject != null) { this.AddObject(distributedObject); List <System.Action <IClientDistributedObject> > requestedObjectCallbacks = null; if (mAnticipatedDistributedObjectIdsToCallbacks.TryGetValue(distributedObject.DistributedObjectId, out requestedObjectCallbacks)) { foreach (System.Action <IClientDistributedObject> requestedObjectCallback in requestedObjectCallbacks) { requestedObjectCallback(distributedObject); } mAnticipatedDistributedObjectIdsToCallbacks.Remove(distributedObject.DistributedObjectId); } } break; case MessageType.Update: DistributedObjectId doId = message.DistributedObjectId; IDistributedObject updateObject = null; if (mObjectIds.TryGetValue(doId, out updateObject)) { updateObject.ProcessMessage(message); } else { Console.LogError("Message update but objectId " + doId + " not found in repository"); } break; case MessageType.Delete: DistributedObjectId deletedoId = message.DistributedObjectId; IDistributedObject deleteObject; if (mObjectIds.TryGetValue(deletedoId, out deleteObject)) { if (deleteObject is ClientDistributedObject) { ClientDistributedObject deleteClientObject = deleteObject as ClientDistributedObject; if (deleteClientObject != null) { deleteClientObject.Dispose(); } } this.RemoveObject(deleteObject); } else { Console.LogError("Message delete but objectId " + deletedoId.ToString() + " not found in repository"); } break; } }
internal DistributedObjectEvent(DistributedEventType eventType, string serviceName, string objectName, IDistributedObject distributedObject, Guid source, ProxyManager proxyManager) { EventType = eventType; ServiceName = serviceName; ObjectName = objectName; _distributedObject = distributedObject; Source = source; _proxyManager = proxyManager; }
/// <summary> /// This is a new owner DistributedObject entering the system on this peer. /// </summary> internal void AddOwner(IDistributedObject distributedObject) { owners.Add(distributedObject.Id, distributedObject); // and tell all the peers // TODO: invert this so we create the message, write it to NetDataWriter, and then just blast it to all peers foreach (NetPeer netPeer in netManager.ConnectedPeerList) { distributedObject.DistributedType.SendCreateMessageInternal(netPeer); } }
// Remove this DistributedObject from the repository. public virtual void RemoveObject(IDistributedObject obj) { // Remove from object id dict DistributedObjectId doId = obj.DistributedObjectId; if (!mObjectIds.Remove(doId)) { Console.WriteLine("Warning!!! We don't have this object!"); return; } }
// Remove this DistributedObject from the repository. public override void RemoveObject(IDistributedObject obj) { if (obj.GetType().IsAssignableFrom(typeof(IServerDistributedObject))) { // Upcast to server version so we get the extra cleanup this.RemoveObject((IServerDistributedObject)obj); } else { // Just call the base class version base.RemoveObject(obj); } }
public T GetDistributedObject <T>() where T : IDistributedObject { if (DistributedEventType.DESTROYED == EventType) { throw new DistributedObjectDestroyedException(); } if (!(_distributedObject is T)) { _distributedObject = _proxyManager.GetOrCreateProxy <T>(ServiceName, ObjectName); } return((T)_distributedObject); }
/// <summary> /// Destroys a distributed object. /// </summary> /// <param name="o">The distributed object.</param> /// <param name="cancellationToken">A cancellation token.</param> public async ValueTask DestroyAsync(IDistributedObject o, CancellationToken cancellationToken = default) { // try to get the object - and then, dispose it var info = new DistributedObjectInfo(o.ServiceName, o.Name); var attempt = await _objects.TryGetAndRemoveAsync(info).CfAwait(); if (attempt) { await TryDispose(attempt.Value).CfAwait(); } var ob = (DistributedObjectBase)o; // we *know* all our objects inherit from the base object await ob.DestroyingAsync().CfAwait(); await DestroyAsync(o.ServiceName, o.Name, cancellationToken).CfAwait(); }
/// <summary> /// Delete this owner object from this Peer's tables. /// </summary> internal void Delete(IDistributedObject distributedObject, Action <NetPeer, bool> sendDeleteMessage) { Contract.Requires(distributedObject != null); Contract.Requires(sendDeleteMessage != null); Contract.Requires(distributedObject.Host == this); if (distributedObject.IsOwner) { owners.Remove(distributedObject.Id); // TODO: invert this so we create the message once and blast it to all peers foreach (NetPeer netPeer in NetPeers) { sendDeleteMessage(netPeer, false); } } else { sendDeleteMessage(distributedObject.OwningPeer, true); } }
public void HostCreateThenDisconnect() { var testWorkQueue = new WorkQueue(); // the first host under test using DistributedHost host = CreateHost(testWorkQueue, true); // create object var distributedThing = new DistributedThing(host, new LocalThing()); // construct second host using (DistributedHost host2 = CreateHost(testWorkQueue, false)) { // consume one owner ID so second object has ID 2 instead of (matching first object) ID 1 host2.NextOwnerId(); // now create an owner object on the other host var distributedThing2 = new DistributedThing(host2, new LocalThing()); // host could start announcing also, but host2 isn't listening so it wouldn't be detectable host2.Announce(); // wait until the proxy for the new object makes it to the other host WaitUtils.WaitUntil(new[] { host, host2 }, () => host2.NetPeers.Count() == 1 && ProxiesForFirstPeer(host2).Count == 1 && host.NetPeers.Count() == 1 && ProxiesForFirstPeer(host).Count == 1); IDistributedObject host2Proxy = ProxiesForFirstPeer(host2).Values.First(); Assert.AreEqual(new DistributedId(1), host2Proxy.Id); Assert.False(host2Proxy.IsOwner); IDistributedObject hostProxy = ProxiesForFirstPeer(host).Values.First(); Assert.AreEqual(new DistributedId(2), hostProxy.Id); Assert.False(hostProxy.IsOwner); } // now after things settle down there should be no proxy WaitUtils.WaitUntil(new[] { host }, () => host.PeerCount == 0 && host.ProxyPeerCount == 0); }
/// <summary> /// Destroys a distributed object. /// </summary> /// <param name="o">The distributed object.</param> /// <param name="cancellationToken">A cancellation token.</param> public async ValueTask DestroyAsync(IDistributedObject o, CancellationToken cancellationToken = default) { // try to get the object - and then, dispose it var info = new DistributedObjectInfo(o.ServiceName, o.Name); var attempt = await _objects.TryGetAndRemoveAsync(info).CfAwait(); if (attempt) { await TryDispose(attempt.Value).CfAwait(); } var ob = (DistributedObjectBase)o; // we *know* all our objects inherit from the base object await ob.DestroyingAsync().CfAwait(); // regardless of whether the object was known locally, destroy on server var clientMessage = ClientDestroyProxyCodec.EncodeRequest(o.Name, o.ServiceName); var responseMessage = await _cluster.Messaging.SendAsync(clientMessage, cancellationToken).CfAwait(); _ = ClientDestroyProxyCodec.DecodeResponse(responseMessage); }
private void OnDelete(NetPeer netPeer, DistributedId id, bool isRequest) { SerializedSocketAddress peerAddress = new SerializedSocketAddress(netPeer); if (isRequest) { // owner id may or may not still exist; it's OK if it doesn't. if (!owners.ContainsKey(id)) { // do nothing; ignore the delete request altogether } else { // we will accept this request... for testing purposes. // TBD if this is the right thing in general! IDistributedObject distributedObject = owners[id]; // and tell all proxies foreach (NetPeer proxyPeer in NetPeers) { distributedObject.DistributedType.SendDeleteMessageInternal(proxyPeer, false); } owners.Remove(id); distributedObject.OnDelete(); } } else { // this is an authoritative delete message from the owner. // we expect strong consistency here so the id should still exist. Contract.Requires(proxies[peerAddress].ContainsKey(id)); IDistributedObject proxy = proxies[peerAddress][id]; proxies[peerAddress].Remove(id); proxy.Delete(); } }
public void HostCreateAfterConnection() { var testWorkQueue = new WorkQueue(); // the first host under test using DistributedHost host = CreateHost(testWorkQueue, true); // construct second host using DistributedHost host2 = CreateHost(testWorkQueue, false); // host could start announcing also, but host2 isn't listening so it wouldn't be detectable host2.Announce(); // should generate announce response and then connection WaitUtils.WaitUntil(new[] { host, host2 }, () => host.PeerCount == 1 && host2.PeerCount == 1); // create object var distributedThing = new DistributedThing(host, new LocalThing()); // wait until the proxy for the new object makes it to the other host WaitUtils.WaitUntil(new[] { host, host2 }, () => ProxiesForFirstPeer(host2).Count == 1); IDistributedObject host2Proxy = ProxiesForFirstPeer(host2).Values.First(); Assert.AreEqual(new DistributedId(1), host2Proxy.Id); Assert.False(host2Proxy.IsOwner); // now create an owner object on the other host var distributedThing2 = new DistributedThing(host2, new LocalThing()); // wait until the proxy for the new object makes it to the first host WaitUtils.WaitUntil(new[] { host, host2 }, () => ProxiesForFirstPeer(host).Count == 1); IDistributedObject hostProxy = ProxiesForFirstPeer(host).Values.First(); Assert.AreEqual(new DistributedId(1), hostProxy.Id); Assert.False(hostProxy.IsOwner); }
public void HostCreateWithState() { var testWorkQueue = new WorkQueue(); // the first host under test using DistributedHost host = CreateHost(testWorkQueue, true); // construct second host using DistributedHost host2 = CreateHost(testWorkQueue, false); // host could start announcing also, but host2 isn't listening so it wouldn't be detectable host2.Announce(); // should generate announce response and then connection WaitUtils.WaitUntil(new[] { host, host2 }, () => host.PeerCount == 1 && host2.PeerCount == 1); // create object var distributedThing = new DistributedThing(host, new LocalThing(new[] { 1, 2 })); // wait until the proxy for the new object makes it to the other host WaitUtils.WaitUntil(new[] { host, host2 }, () => ProxiesForFirstPeer(host2).Count == 1); LocalThing host2LocalThing = FirstProxyLocalThing(host2); Assert.IsTrue(Enumerable.SequenceEqual(new[] { 1, 2 }, host2LocalThing.LocalValues.ToList())); // now create an owner object on the other host var distributedThing2 = new DistributedThing(host2, new LocalThing(new[] { 3, 4 })); // wait until the proxy for the new object makes it to the first host WaitUtils.WaitUntil(new[] { host, host2 }, () => ProxiesForFirstPeer(host).Count == 1); IDistributedObject hostProxy = ProxiesForFirstPeer(host).Values.First(); LocalThing hostLocalThing = (LocalThing)hostProxy.LocalObject; Assert.IsTrue(Enumerable.SequenceEqual(new[] { 3, 4 }, hostLocalThing.LocalValues.ToList())); }
private void onData(MemoryStream data) { DatagramIn reader = new DatagramIn(data); UInt16 type = reader.ReadUInt16(); switch ((MessageTypes)type) { case MessageTypes.CLIENT_HELLO_RESP: { Debug.Log("Response to client_hello"); if (onHello != null) { onHello(); } break; } case MessageTypes.CLIENT_EJECT: { UInt16 error_code = reader.ReadUInt16(); string reason = reader.ReadString(); Debug.Log("Ejected Code " + error_code + ": " + reason); if (onEject != null) { onEject(error_code, reason); } break; } case MessageTypes.CLIENT_ADD_INTEREST: { UInt32 context = reader.ReadUInt32(); UInt16 interest_id = reader.ReadUInt16(); UInt32 parent_id = reader.ReadUInt32(); UInt32 zone_id = reader.ReadUInt32(); Interest newInterest = new Interest(context, interest_id, zone_id, parent_id); context2interest.Add(context, newInterest); if (onAddInterest != null) { onAddInterest(newInterest); } break; } case MessageTypes.CLIENT_DONE_INTEREST_RESP: { UInt32 context = reader.ReadUInt32(); UInt16 interest_id = reader.ReadUInt16(); if (onDoneInterest != null) { onDoneInterest(context2interest[context]); } break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST, false, false); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OTHER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST, false, true); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OWNER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST_OR_OWNRECV, true, false); break; } case MessageTypes.CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER: { unserializeClass(reader, SerializationLevel.REQUIRED_BCAST_OR_OWNRECV, true, true); break; } case MessageTypes.CLIENT_OBJECT_LOCATION: { UInt32 do_id = reader.ReadUInt32(); UInt32 parent_id = reader.ReadUInt32(); UInt32 zone_id = reader.ReadUInt32(); doId2do[do_id].getLocation().changeLocation(zone_id, parent_id); doId2do[do_id].locationChanged(); break; } case MessageTypes.CLIENT_OBJECT_LEAVING: { UInt32 doId = reader.ReadUInt32(); doId2do[doId].leaving(); // freeing the DO from the doId2do map is done by the leaving method // via the removeDOfromMap function // if the leaving method is overriden, // removeDOfromMap should still be called to prevent memory leaks break; } case MessageTypes.CLIENT_OBJECT_SET_FIELD: { UInt32 doId = reader.ReadUInt32(); UInt16 field_id = reader.ReadUInt16(); receiveUpdate(reader, doId2do[doId], field_id); break; } case MessageTypes.CLIENT_OBJECT_SET_FIELDS: { UInt32 doId = reader.ReadUInt32(); IDistributedObject distObj = doId2do[doId]; UInt16 num_fields = reader.ReadUInt16(); for (int i = 0; i < num_fields; ++i) { UInt16 field_id = reader.ReadUInt16(); receiveUpdate(reader, distObj, field_id); } break; } default: { Debug.Log("Unknown message type: " + type); break; } } }
public void AddProxy(NetPeer netPeer, IDistributedObject newProxy) { Host.AddProxy(new SerializedSocketAddress(netPeer), newProxy); }
/// <inheritdoc /> public async ValueTask DestroyAsync(IDistributedObject o) { await _distributedOjects.DestroyAsync(o).CfAwait(); }
/// <summary> /// This is a new proxy being created on this peer, owned by netPeer. /// </summary> private void AddProxy(SerializedSocketAddress peerAddress, IDistributedObject proxy) { Contract.Requires(!proxy.IsOwner); proxies[peerAddress].Add(proxy.Id, proxy); }
public DistributedObjectEvent(string eventType, string serviceName, IDistributedObject distributedObject) { _eventType = eventType; _serviceName = serviceName; _distributedObject = distributedObject; }
/// <inheritdoc /> public async ValueTask DestroyAsync(IDistributedObject o) { await _distributedObjectFactory.DestroyAsync(o.ServiceName, o.Name).CAF(); }
public DistributedObjectEvent(String eventType, string serviceName, IDistributedObject distributedObject) { this.eventType = eventType; this.serviceName = serviceName; this.distributedObject = distributedObject; }