public interface IListener : IDisposable
{
event EventHandler<IPeer> OnPeerConnected;
void Start();
string Address { get; }
}
public interface IPeer : IDisposable
{
bool IsConnected { get; }
string TargetAddress { get; }
string BaseAddress { get; }
void Send(CommandBase command);
CommandBase Receive();
void Connect(string connectionString);
void Close(object closingMessage = null);
}
public interface IPeerFactory : IDisposable
{
IPeer Produce();
}
为了简化场景,避免涉及更为艰深的网络通信问题,在此以模拟的形式实现网络通信。
public abstract class InMemoryPeerBase : IPeer
{
protected internal InMemoryPeerBase opposite;
protected readonly InMemoryConnectionCenter center;
protected Queue<CommandBase> receivedData = new Queue<CommandBase>();
protected InMemoryPeerBase(InMemoryConnectionCenter center)
{
this.center = center;
}
public string TargetAddress { get; protected set; }
public string BaseAddress { get; protected set; }
public bool IsConnected { get; protected set; }
public abstract void Connect(string connectionString);
public void Close(object closingMessage = null)
public void Send(CommandBase command)
public CommandBase Receive()
}
public void Send(CommandBase command)
{
this.opposite.receivedData.Enqueue(command);
}
public CommandBase Receive()
{
if (this.receivedData.TryDequeue(out var ret))
{
return ret;
}
return null;
}
public void Close(object closingMessage = null)
{
this.IsConnected = false;
this.center.RemovePeer(this);
}
public class ActiveInMemoryPeer : InMemoryPeerBase
{
public ActiveInMemoryPeer(InMemoryConnectionCenter center, string address) : base(center)
{
this.BaseAddress = address;
}
public override void Connect(string connectionString)
{
this.TargetAddress = connectionString;
if (this.center.Connect(connectionString, this))
{
this.IsConnected = true;
this.center.AddPeer(this);
}
else
{
this.IsConnected = false;
}
}
}
public class PassiveInMemoryPeer : InMemoryPeerBase
{
public PassiveInMemoryPeer(InMemoryConnectionCenter center, ActiveInMemoryPeer peer) : base(center)
{
this.opposite = peer;
this.opposite.opposite = this;
this.BaseAddress = peer.TargetAddress;
this.TargetAddress = peer.BaseAddress;
}
public override void Connect(string connectionString)
{
throw new NotSupportedException();
}
}
public class InMemoryPeerFactory : IPeerFactory
{
private readonly InMemoryConnectionCenter center;
private readonly InMemoryListener server;
public InMemoryPeerFactory(InMemoryConnectionCenter center, InMemoryListener server)
{
this.center = center;
this.server = server;
}
public IPeer Produce()
{
return new ActiveInMemoryPeer(this.center, this.server.Address);
}
}
public class InMemoryConnectionCenter
{
private int number = 0;
private readonly ConcurrentDictionary<string, InMemoryListener> dicServers = new ConcurrentDictionary<string, InMemoryListener>();
private readonly ConcurrentDictionary<string, List<InMemoryPeerBase>> dicPeers = new ConcurrentDictionary<string, List<InMemoryPeerBase>>();
public NodeOptions NodeOptions { get => new NodeOptions { WellKnownNodes = this.ProduceWellKnownNodes() }; }
public string[] ProduceWellKnownNodes() => Enumerable.Range(0, this.number).Select(_ => _.ToString()).ToArray();
public (IListener listener, IPeerFactory peerFactory) Produce()
internal void AddPeer(InMemoryPeerBase peer)
internal void RemovePeer(InMemoryPeerBase peer)
internal bool Connect(string baseAddress, ActiveInMemoryPeer peer)
}
public (IListener listener, IPeerFactory peerFactory) Produce()
{
var listener = this.ProduceListener();
var peerFactory = this.ProducePeerFactory(listener);
return (listener, peerFactory);
}
private InMemoryListener ProduceListener()
{
var address = this.number.ToString();
var server = new InMemoryListener(this, address);
this.dicServers[address] = server;
this.number++;
return server;
}
private IPeerFactory ProducePeerFactory(InMemoryListener server)
{
return new InMemoryPeerFactory(this, server);
}
internal void AddPeer(InMemoryPeerBase peer)
{
var key = peer.TargetAddress;
if (this.dicPeers.ContainsKey(key))
this.dicPeers[key].Add(peer);
else
this.dicPeers[key] = new List<InMemoryPeerBase>(new[] { peer });
}
internal void RemovePeer(InMemoryPeerBase peer)
{
var key = peer.TargetAddress;
if (this.dicPeers.ContainsKey(key))
this.dicPeers[key].Remove(peer);
}
internal bool Connect(string baseAddress, ActiveInMemoryPeer peer)
{
return this.dicServers[baseAddress].Connect(peer);
}
public class InMemoryListener : IListener
{
private readonly InMemoryConnectionCenter center;
public InMemoryListener(InMemoryConnectionCenter center, string address)
{
this.center = center;
this.Address = address;
}
public event EventHandler<IPeer> OnPeerConnected;
public string Address { get; }
public void Start() { }
internal bool Connect(ActiveInMemoryPeer peer)
{
var oppositePeer = new PassiveInMemoryPeer(this.center, peer);
this.center.AddPeer(oppositePeer);
this.OnPeerConnected?.Invoke(this, oppositePeer);
return true;
}
}
public abstract class CommandBase
{
public abstract string CommandType { get; }
public abstract void OnReceived(Node node, ConnectionNode connectionNode);
}
public static class Commands
{
public const string Version = nameof(Version);
public const string VersionAcknowledge = nameof(VersionAcknowledge);
public const string GetBlocks = nameof(GetBlocks);
public const string Inventory = nameof(Inventory);
public const string GetData = nameof(GetData);
public const string Block = nameof(Block);
public const string Transaction = nameof(Transaction);
}