You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
745 lines
22 KiB
745 lines
22 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
|
||
|
|
namespace TouchSocket.Rpc.TouchRpc
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 通道
|
||
|
|
/// </summary>
|
||
|
|
[DebuggerDisplay("ID={ID},Status={Status}")]
|
||
|
|
public abstract class Channel : DisposableObject
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 是否具有数据可读
|
||
|
|
/// </summary>
|
||
|
|
public abstract int Available { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 缓存容量
|
||
|
|
/// </summary>
|
||
|
|
public abstract int CacheCapacity { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 判断当前通道能否调用<see cref="MoveNext()"/>
|
||
|
|
/// </summary>
|
||
|
|
public abstract bool CanMoveNext { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 能否写入
|
||
|
|
/// </summary>
|
||
|
|
public abstract bool CanWrite { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 通道ID
|
||
|
|
/// </summary>
|
||
|
|
public abstract int ID { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 最后一次操作时显示消息
|
||
|
|
/// </summary>
|
||
|
|
public abstract string LastOperationMes { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 状态
|
||
|
|
/// </summary>
|
||
|
|
public abstract ChannelStatus Status { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 目的ID地址。仅当该通道由两个客户端打通时有效。
|
||
|
|
/// </summary>
|
||
|
|
public abstract string TargetId { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 超时时间,默认1000*10ms。
|
||
|
|
/// </summary>
|
||
|
|
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否被使用
|
||
|
|
/// </summary>
|
||
|
|
public abstract bool Using { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 取消
|
||
|
|
/// </summary>
|
||
|
|
public abstract void Cancel(string operationMes = null);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步取消
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task CancelAsync(string operationMes = null)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
this.Cancel(operationMes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 完成操作
|
||
|
|
/// </summary>
|
||
|
|
public abstract void Complete(string operationMes = null);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步完成操作
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task CompleteAsync(string operationMes = null)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
this.Complete(operationMes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取当前的数据
|
||
|
|
/// </summary>
|
||
|
|
public abstract byte[] GetCurrent();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 继续。
|
||
|
|
/// <para>调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用<see cref="MoveNext()"/></para>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="operationMes"></param>
|
||
|
|
public abstract void HoldOn(string operationMes = null);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步调用继续
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="operationMes"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task HoldOnAsync(string operationMes = null)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
this.HoldOn(operationMes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转向下个元素
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public abstract bool MoveNext();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转向下个元素
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> MoveNextAsync()
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return this.MoveNext();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 阻塞读取数据,直到有数据,或者超时。
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<byte[]> ReadAsync()
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
if (this.MoveNext())
|
||
|
|
{
|
||
|
|
return this.GetCurrent();
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 尝试写入。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryWrite(byte[] data, int offset, int length)
|
||
|
|
{
|
||
|
|
if (this.CanWrite)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
this.Write(data, offset, length);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 尝试写入
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryWrite(byte[] data)
|
||
|
|
{
|
||
|
|
return this.TryWrite(data, 0, data.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步尝试写入
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public async Task<bool> TryWriteAsync(byte[] data, int offset, int length)
|
||
|
|
{
|
||
|
|
if (this.CanWrite)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
await this.WriteAsync(data, offset, length);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步尝试写入
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> TryWriteAsync(byte[] data)
|
||
|
|
{
|
||
|
|
return this.TryWriteAsync(data, 0, data.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入通道
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public abstract void Write(byte[] data, int offset, int length);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入通道
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
public void Write(byte[] data)
|
||
|
|
{
|
||
|
|
this.Write(data, 0, data.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入通道
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public Task WriteAsync(byte[] data, int offset, int length)
|
||
|
|
{
|
||
|
|
return Task.Run(() =>
|
||
|
|
{
|
||
|
|
this.Write(data, offset, length);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入通道
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
public void WriteAsync(byte[] data)
|
||
|
|
{
|
||
|
|
this.WriteAsync(data, 0, data.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal class InternalChannel : Channel
|
||
|
|
{
|
||
|
|
private readonly RpcActor m_actor;
|
||
|
|
private readonly IntelligentDataQueue<ChannelPackage> m_dataQueue;
|
||
|
|
private readonly AutoResetEvent m_moveWaitHandle;
|
||
|
|
private readonly string m_targetId;
|
||
|
|
private readonly Timer m_timer;
|
||
|
|
private int m_cacheCapacity;
|
||
|
|
private volatile bool m_canFree;
|
||
|
|
private byte[] m_currentData;
|
||
|
|
private int m_id;
|
||
|
|
private string m_lastOperationMes;
|
||
|
|
private DateTime m_lastOperationTime;
|
||
|
|
private ChannelStatus m_status;
|
||
|
|
private bool m_using;
|
||
|
|
|
||
|
|
public InternalChannel(RpcActor client, string targetId)
|
||
|
|
{
|
||
|
|
this.m_actor = client;
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
this.m_targetId = targetId;
|
||
|
|
this.m_status = ChannelStatus.Default;
|
||
|
|
this.m_cacheCapacity = 1024 * 1024 * 5;
|
||
|
|
this.m_dataQueue = new IntelligentDataQueue<ChannelPackage>(this.m_cacheCapacity)
|
||
|
|
{
|
||
|
|
OverflowWait = false,
|
||
|
|
OnQueueChanged = OnQueueChanged
|
||
|
|
};
|
||
|
|
this.m_moveWaitHandle = new AutoResetEvent(false);
|
||
|
|
this.m_canFree = true;
|
||
|
|
this.m_timer = new Timer((o) =>
|
||
|
|
{
|
||
|
|
if (DateTime.Now - this.m_lastOperationTime > TimeSpan.FromTicks(this.Timeout.Ticks * 3))
|
||
|
|
{
|
||
|
|
this.SafeDispose();
|
||
|
|
}
|
||
|
|
}, null, 1000, 1000);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 析构函数
|
||
|
|
/// </summary>
|
||
|
|
~InternalChannel()
|
||
|
|
{
|
||
|
|
this.Dispose(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否具有数据可读
|
||
|
|
/// </summary>
|
||
|
|
public override int Available => this.m_dataQueue.Count;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 缓存容量
|
||
|
|
/// </summary>
|
||
|
|
public override int CacheCapacity
|
||
|
|
{
|
||
|
|
get => this.m_cacheCapacity;
|
||
|
|
set
|
||
|
|
{
|
||
|
|
if (value < 0)
|
||
|
|
{
|
||
|
|
value = 1024;
|
||
|
|
}
|
||
|
|
this.m_cacheCapacity = value;
|
||
|
|
this.m_dataQueue.MaxSize = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 判断当前通道能否调用<see cref="MoveNext()"/>
|
||
|
|
/// </summary>
|
||
|
|
public override bool CanMoveNext
|
||
|
|
{
|
||
|
|
get
|
||
|
|
{
|
||
|
|
if (this.Available > 0)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if ((byte)this.m_status >= 4)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 能否写入
|
||
|
|
/// </summary>
|
||
|
|
public override bool CanWrite => (byte)this.m_status <= 3;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// ID
|
||
|
|
/// </summary>
|
||
|
|
public override int ID => this.m_id;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 最后一次操作时显示消息
|
||
|
|
/// </summary>
|
||
|
|
public override string LastOperationMes
|
||
|
|
{
|
||
|
|
get => this.m_lastOperationMes;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 状态
|
||
|
|
/// </summary>
|
||
|
|
public override ChannelStatus Status => this.m_status;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 目的ID地址。
|
||
|
|
/// </summary>
|
||
|
|
public override string TargetId => this.m_targetId;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否被使用
|
||
|
|
/// </summary>
|
||
|
|
public override bool Using => this.m_using;
|
||
|
|
|
||
|
|
#region 操作
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 取消
|
||
|
|
/// </summary>
|
||
|
|
public override void Cancel(string operationMes = null)
|
||
|
|
{
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
this.RequestCancel(true);
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
RunNow = true,
|
||
|
|
DataType = ChannelDataType.CancelOrder,
|
||
|
|
Message = operationMes,
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 完成操作
|
||
|
|
/// </summary>
|
||
|
|
public override void Complete(string operationMes = null)
|
||
|
|
{
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.RequestComplete(true);
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
RunNow = true,
|
||
|
|
DataType = ChannelDataType.CompleteOrder,
|
||
|
|
Message = operationMes,
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 继续。
|
||
|
|
/// <para>调用该指令时,接收方会跳出接收,但是通道依然可用,所以接收方需要重新调用<see cref="MoveNext()"/></para>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="operationMes"></param>
|
||
|
|
public override void HoldOn(string operationMes = null)
|
||
|
|
{
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
RunNow = true,
|
||
|
|
DataType = ChannelDataType.HoldOnOrder,
|
||
|
|
Message = operationMes,
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="disposing"></param>
|
||
|
|
protected override void Dispose(bool disposing)
|
||
|
|
{
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
this.m_timer.SafeDispose();
|
||
|
|
this.RequestDispose(true);
|
||
|
|
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
RunNow = true,
|
||
|
|
DataType = ChannelDataType.HoldOnOrder,
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
base.Dispose(disposing);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 操作
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取当前的数据
|
||
|
|
/// </summary>
|
||
|
|
public override byte[] GetCurrent()
|
||
|
|
{
|
||
|
|
return this.m_currentData;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转向下个元素
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public override bool MoveNext()
|
||
|
|
{
|
||
|
|
if (!this.CanMoveNext)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (this.m_dataQueue.TryDequeue(out ChannelPackage channelPackage))
|
||
|
|
{
|
||
|
|
switch (channelPackage.DataType)
|
||
|
|
{
|
||
|
|
case ChannelDataType.DataOrder:
|
||
|
|
{
|
||
|
|
this.m_currentData = channelPackage.Data.Array;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
case ChannelDataType.CompleteOrder:
|
||
|
|
this.RequestComplete(true);
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case ChannelDataType.CancelOrder:
|
||
|
|
this.RequestCancel(true);
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case ChannelDataType.DisposeOrder:
|
||
|
|
this.RequestDispose(true);
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case ChannelDataType.HoldOnOrder:
|
||
|
|
this.m_status = ChannelStatus.HoldOn;
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case ChannelDataType.QueueRun:
|
||
|
|
this.m_canFree = true;
|
||
|
|
return false;
|
||
|
|
|
||
|
|
case ChannelDataType.QueuePause:
|
||
|
|
this.m_canFree = false;
|
||
|
|
return false;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
this.m_moveWaitHandle.Reset();
|
||
|
|
if (this.m_moveWaitHandle.WaitOne(this.Timeout))
|
||
|
|
{
|
||
|
|
return this.MoveNext();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
this.m_status = ChannelStatus.Overtime;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入通道
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="data"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public override void Write(byte[] data, int offset, int length)
|
||
|
|
{
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
throw new Exception($"通道已{this.m_status}");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!SpinWait.SpinUntil(() => { return this.m_canFree; }, this.Timeout))
|
||
|
|
{
|
||
|
|
throw new TimeoutException();
|
||
|
|
}
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
DataType = ChannelDataType.DataOrder,
|
||
|
|
Data = new ArraySegment<byte>(data, offset, length),
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void ReceivedData(ChannelPackage channelPackage)
|
||
|
|
{
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
if (channelPackage.RunNow)
|
||
|
|
{
|
||
|
|
switch (channelPackage.DataType)
|
||
|
|
{
|
||
|
|
case ChannelDataType.CompleteOrder:
|
||
|
|
this.m_lastOperationMes = channelPackage.Message;
|
||
|
|
this.RequestComplete(false);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ChannelDataType.CancelOrder:
|
||
|
|
this.m_lastOperationMes = channelPackage.Message;
|
||
|
|
this.RequestCancel(false);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ChannelDataType.DisposeOrder:
|
||
|
|
this.RequestDispose(false);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ChannelDataType.HoldOnOrder:
|
||
|
|
this.m_lastOperationMes = channelPackage.Message;
|
||
|
|
this.m_status = ChannelStatus.HoldOn;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case ChannelDataType.QueueRun:
|
||
|
|
this.m_canFree = true;
|
||
|
|
return;
|
||
|
|
|
||
|
|
case ChannelDataType.QueuePause:
|
||
|
|
this.m_canFree = false;
|
||
|
|
return;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
this.m_dataQueue.Enqueue(channelPackage);
|
||
|
|
this.m_moveWaitHandle.Set();
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void SetID(int id)
|
||
|
|
{
|
||
|
|
this.m_id = id;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void SetUsing()
|
||
|
|
{
|
||
|
|
this.m_using = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Clear()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
lock (this)
|
||
|
|
{
|
||
|
|
this.m_dataQueue.Clear();
|
||
|
|
if (this.m_actor.RemoveChannel(this.m_id))
|
||
|
|
{
|
||
|
|
this.m_moveWaitHandle.Set();
|
||
|
|
this.m_moveWaitHandle.SafeDispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnQueueChanged(bool free)
|
||
|
|
{
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var channelPackage = new ChannelPackage()
|
||
|
|
{
|
||
|
|
ChannelId = this.m_id,
|
||
|
|
RunNow = true,
|
||
|
|
DataType = free ? ChannelDataType.QueueRun : ChannelDataType.QueuePause,
|
||
|
|
SourceId = this.m_actor.ID,
|
||
|
|
TargetId = this.m_targetId,
|
||
|
|
Route = this.m_targetId.HasValue()
|
||
|
|
};
|
||
|
|
this.m_actor.SendChannelPackage(channelPackage);
|
||
|
|
this.m_lastOperationTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestCancel(bool clear)
|
||
|
|
{
|
||
|
|
this.m_status = ChannelStatus.Cancel;
|
||
|
|
if (clear)
|
||
|
|
{
|
||
|
|
this.Clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestComplete(bool clear)
|
||
|
|
{
|
||
|
|
this.m_status = ChannelStatus.Completed;
|
||
|
|
if (clear)
|
||
|
|
{
|
||
|
|
this.Clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
internal void RequestDispose(bool clear)
|
||
|
|
{
|
||
|
|
if (clear)
|
||
|
|
{
|
||
|
|
this.Clear();
|
||
|
|
}
|
||
|
|
if ((byte)this.m_status > 3)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
this.m_status = ChannelStatus.Disposed;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|