/// <summary> /// 以送信息给所有客户端 /// </summary> /// <param name="msg"></param> public void SendMsgToAllClient(string msg) { lockSlim.EnterReadLock(); try { foreach (var item in dictsocket) { if (SocketTools.IsSocketConnected(item.Value.socket)) { item.Value.socket.Send(SocketTools.GetBytes(msg, IsOpenDesEnc)); } else { item.Value.socket.Close(); OnDebug?.Invoke($"The client with ip {item.Key} has logged out and can't send a message."); } } } catch (Exception ex) { OnError?.Invoke($"Error when sending to all clients:{ex.ToString()}"); } finally { lockSlim.ExitReadLock(); } }
/// <summary> /// Debugs the specified message. /// </summary> /// <param name="message">The message.</param> public void Debug(string message) { if (LogLevel <= LogLevel.Debug) { OnDebug?.Invoke(this, new LokiDebugEventArgs(message)); } }
private async Task RunRefreshLoopAsync() { OnDebug?.Invoke("Archive database refresh loop started."); while (true) { if (m_NextTryTime < DateTime.Now) { m_NextTryTime = DateTime.MinValue; try { await RefreshAsync(); } catch (Exception ex) { OnError?.Invoke(ex, "Error uploading to archive database."); } } if (m_IsRunning) { await Task.Delay((int)RefreshInterval).ConfigureAwait(false); } if (!m_IsRunning && m_DataUploadQueue.Count <= 0) { break; } } OnDebug?.Invoke("Archive database refresh loop ended."); }
/// <summary> /// 心跳协议 /// </summary> private void HearBeat() { long timeNow = SocketTools.GetTimeStamp(); lockSlim.EnterWriteLock(); try { foreach (var item in dictsocket) { long now = timeNow - item.Value.lastTickTime; OnDebug?.Invoke($"nottimeStamp: {timeNow} lastTickTime: {item.Value.lastTickTime} Time difference {now}"); if (now > HearTime) { item.Value.socket.Close(); OnDebug?.Invoke($"User No.{item.Value.id} with ip {item.Value.ip} is No heartbeat,so get out"); } } } catch (Exception ex) { OnError?.Invoke($"Error in the heartbeat:{ex.ToString()}"); } finally { lockSlim.ExitWriteLock(); } }
public void Debug(string tag, string msg) { if (!ConfigMgr.GetConfig().Debug) { return; } OnDebug?.Invoke(tag, msg); Console.WriteLine($"[DEBUG]{msg}"); }
public void Close() { OnDebug?.Invoke("Azure Table Store terminating..."); m_IsRunning = false; m_RefreshLoop?.Wait((int)RefreshInterval); OnLog?.Invoke("Azure Table Store terminated."); }
private async Task WriteAudioIn(byte[] buffer) { OnDebug?.Invoke("Write Audio " + buffer.Length, true); var request = new ConverseRequest() { AudioIn = ByteString.CopyFrom(buffer) }; await _requestStream.WriteAsync(request); }
public void Close() { OnDebug?.Invoke("Archive database terminating..."); m_IsRunning = false; m_RefreshLoop.Wait(15000); OnLog?.Invoke("Archive database terminated."); }
//这里的方法都是线程安全的 /// <summary> /// 添加一个新的客户端 /// </summary> /// <param name="ip"></param> /// <param name="socket"></param> /// <param name="thread"></param> private void AddSocketClient(string ip, System.Net.Sockets.Socket socket, Thread thread, out string outid) { lockSlim.EnterWriteLock(); outid = "0"; try { int count = dictsocket.Count; //目前的客户端数量 string id = "0"; if (count >= 1) { for (int i = 0; i < count + 1; i++) { //判断是否有当前id var key = dictsocket.Where(q => (q.Value.id.Equals(i.ToString()))).Select(q => q.Key); // Console.WriteLine("------"+key.Count()+" "); if (key.Count() == 1) { continue; } else { //是否有当前id号 id = i.ToString(); outid = id; ClientMode socketClient = new ClientMode(ip, thread, socket, id); dictsocket.Add(ip, socketClient); OnDebug?.Invoke($"Added {id.ToString()} number"); break; } } } else { outid = id; ClientMode socketClient = new ClientMode(ip, thread, socket, id); dictsocket.Add(ip, socketClient); OnDebug?.Invoke($"Added id {id.ToString()} for the first time"); } } catch (Exception ex) { OnError?.Invoke($"Error when adding a client:{ex.ToString()}"); } finally { lockSlim.ExitWriteLock(); } }
private void StopRecording() { if (_waveIn != null) { OnDebug?.Invoke("Stop Recording"); _waveIn.StopRecording(); _waveIn.Dispose(); _waveIn = null; OnAssistantStateChanged?.Invoke(AssistantState.Processing); OnDebug?.Invoke("Send Request Complete"); _requestStreamAvailable = false; _requestStream.CompleteAsync(); } }
private void ProcessInAudio(object sender, WaveInEventArgs e) { OnDebug?.Invoke($"Process Audio {e.Buffer.Length} SendSpeech={_sendSpeech} Writing={_writing}", true); if (_sendSpeech) { // cannot do more than one write at a time so if its writing already add the new data to the queue if (_writing) { _writeBuffer.Add(e.Buffer); } else { WriteAudioData(e.Buffer); } } }
public async void NewConversation() { try { OnAssistantStateChanged?.Invoke(AssistantState.Listening); _followOn = false; _assistantResponseReceived = false; AsyncDuplexStreamingCall <AssistRequest, AssistResponse> assist = _assistant.Assist(); _requestStream = assist.RequestStream; _responseStream = assist.ResponseStream; logger.Debug("New Conversation - New Config Request"); OnDebug?.Invoke("New Conversation - New Config Request"); // Once this opening request is issued if its not followed by audio an error of 'code: 14, message: Service Unavaible.' comes back, really not helpful Google! await _requestStream.WriteAsync(CreateNewRequest()); _requestStreamAvailable = true; ResetSendingAudio(true); // note recreating the WaveIn each time otherwise the recording just stops on follow ups _waveIn = new WaveIn { WaveFormat = new WaveFormat(Const.SampleRateHz, 1) }; _waveIn.DataAvailable += ProcessInAudio; _waveIn.StartRecording(); await WaitForResponse(); } catch (Exception ex) { logger.Error(ex.Message); Console.WriteLine(ex.Message); OnDebug?.Invoke($"Error {ex.Message}"); StopRecording(); } }
/// <summary> /// 通过ip发送信息给客户端 /// </summary> /// <param name="ip"></param> /// <param name="msg"></param> public bool SendMsgToClientForIP(string ip, string msg) { lockSlim.EnterReadLock(); bool isok = true; try { if (dictsocket.ContainsKey(ip.Trim())) { ClientMode clientMode = dictsocket[ip.Trim()]; if (SocketTools.IsSocketConnected(clientMode.socket)) { clientMode.socket.Send(SocketTools.GetBytes(msg, IsOpenDesEnc)); isok = true; } else { clientMode.socket.Close(); OnDebug?.Invoke($"The client with ip {clientMode.ip} has logged out and can't send a message."); isok = false; } } } catch (Exception ex) { OnError?.Invoke($"Error when sending to the client:{ex.ToString()}"); isok = false; } finally { lockSlim.ExitReadLock(); } return(isok); }
private async Task RunRefreshLoopAsync() { OnDebug?.Invoke("Azure Table Store refresh loop started."); while (true) { if (m_Buffer.Count > 0 || OutBufferCount > 0) { try { await RefreshAsync(); } catch (Exception ex) { OnError?.Invoke(ex, "Error when uploading to Azure Table Store."); } } else if (!m_IsRunning) { break; } await Task.Delay((int)RefreshInterval).ConfigureAwait(false); } OnDebug?.Invoke("Azure Table Store refresh loop ended."); }
/// <summary> /// 从号码移除一个客户端 /// </summary> /// <param name="id"></param> /// <returns></returns> public bool ReMoveClientForId(string id) { List <string> vs = GetAllClientInfo(); lockSlim.EnterWriteLock(); bool IsRemove = false; try { for (int i = 0; i < vs.Count; i++) { string[] str = vs[i].ToString().Trim().Split('-'); if (str[0].Trim().Equals(id)) { if (dictsocket.ContainsKey(str[1].Trim())) { dictsocket[str[1].Trim()].socket.Close(); //关闭连接,就在线程报异常,到时自己清除 } OnDebug?.Invoke($"remove {str[0]} str[1]"); IsRemove = true; break; } } return(IsRemove); } catch (Exception ex) { OnError?.Invoke($"Error when removing a client from a number:{ex.ToString()}"); return(false); } finally { lockSlim.ExitWriteLock(); } }
private async Task RefreshAsync() { // Prune the queues while (OutBufferCount > m_MaxMessages) { if (m_DataUploadQueue.TryDequeue(out var _)) { continue; } } //OnDebug?.Invoke($"{m_DataUploadQueue.Count} in queue."); // Upload the data if (!m_DataUploadQueue.TryPeek(out var entry)) { return; } var table = MapTable(entry); if (table == null) { OnDebug?.Invoke($"Skipping {entry.GetType().Name} for archive database..."); // Remove the message from the queue m_DataUploadQueue.TryDequeue(out entry); return; } // The base SQL statement should be as similar as possible so that it will be cached in the database server // This is why ValuesListForInsertStatement uses parameters instead of actual values var sql = $"INSERT INTO {table} {entry.InsertStatement}"; OnSQL?.Invoke("Database SQL = " + sql); // Store to database try { using (var conn = connectionFactory()) { await conn.OpenAsync(); using (var cmd = conn.CreateCommand()) { // Use a transaction using (var transaction = conn.BeginTransaction()) { // Must assign both transaction object and connection to Command object // for a pending local transaction (as per MSDN) cmd.Connection = conn; cmd.Transaction = transaction; try { // Prepare the SQL statement cmd.CommandType = CommandType.Text; cmd.CommandText = sql; cmd.Parameters.Clear(); entry.AddSqlParameters(cmd.Parameters, createSqlParameter); await cmd.ExecuteNonQueryAsync(); // Special treatment for cycle data if (entry is CycleData cycledata) { if (cycledata.Data.Count > 0) { sql = $"SELECT MAX(ID) FROM {Storage.CycleDataTable}"; OnSQL?.Invoke(sql); cmd.CommandText = sql; var id = (int)await cmd.ExecuteScalarAsync(); OnSQL?.Invoke("New Cycle Data ID = " + id); sql = $"INSERT INTO {Storage.CycleDataValuesTable} (ID, VariableName, Value)\nVALUES"; sql += string.Join(",\n", cycledata.Data.Select(kv => $" ({id}, '{kv.Key}', {(float) kv.Value})")); OnSQL?.Invoke(sql); cmd.CommandText = sql; await cmd.ExecuteNonQueryAsync(); } } transaction.Commit(); } catch { transaction.Rollback(); throw; } } OnUploadSuccess?.Invoke(entry, $"Successfully uploaded {entry.GetType().Name} to archive database."); } } } catch (DbException ex) { // Do not remove the message from the queue OnUploadError?.Invoke(entry, ex, $"Cannot upload {entry.GetType().Name} to archive database!\n{sql}"); m_NextTryTime = DateTime.Now.AddMilliseconds(ErrorRefreshInterval); return; } catch (Exception ex) { // Do not remove the message from the queue OnError?.Invoke(ex, $"Error when uploading {entry.GetType().Name} to archive database!"); m_NextTryTime = DateTime.Now.AddMilliseconds(ErrorRefreshInterval); return; } // Remove the message from the queue m_DataUploadQueue.TryDequeue(out entry); }
public void Debug(string message) { OnDebug?.Invoke(message); }
private void Log(string text) => OnDebug?.Invoke(text);
private void SendDebugMessage(string message) { OnDebug?.Invoke(this, new OnDebugEventArgs { Message = $"{message}\n" }); }
private async Task UploadBufferAsync() { if (m_Buffer.Count > 1 && m_Buffer[0].UseBatches) { // Batch upload var table = MapTable(m_Buffer[0]); var uploads = new TableBatchOperation(); var links = new TableBatchOperation(); var id = m_Buffer[0].Controller; foreach (var data in m_Buffer) { var entity = data.ToEntity(data.ID ?? m_RowKeyBase + "-" + m_Seq++); uploads.Insert(entity); if (data.ID != null) { links.Insert(new Link(table.Name, data.ID, entity.PartitionKey, entity.RowKey)); } } OnDebug?.Invoke($"Batch uploading {uploads.Count} records to Azure table storage {table.Name} for controller [{id}]..."); try { if (links.Count > 0) { await m_LinksTable.ExecuteBatchAsync(links); } var r = await table.ExecuteBatchAsync(uploads); // Check for errors var errors = m_Buffer .Where((entry, x) => r.Count <= x || (r[x].HttpStatusCode != 201 && r[x].HttpStatusCode != 204)) .ToList(); var successes = m_Buffer .Where((entry, x) => r.Count > x && (r[x].HttpStatusCode == 201 || r[x].HttpStatusCode == 204)) .ToList(); OnUploadSuccess?.Invoke(201, successes, $"{m_Buffer.Count - errors.Count} record(s) out of {m_Buffer.Count} for controller [{id}] successfully uploaded to Azure table storage {table.Name}."); m_Buffer.Clear(); if (errors.Count > 0) { m_Buffer.AddRange(errors); OnUploadError?.Invoke(0, errors, $"{errors.Count} record(s) for controller [{id}] failed to upload to Azure table storage {table.Name}."); } } catch (StorageException ex) { var status = ex.RequestInformation.HttpStatusCode; var errmsg = ex.RequestInformation.ExtendedErrorInformation?.ErrorMessage ?? ex.RequestInformation.HttpStatusMessage ?? ex.Message; switch (status) { case 0: { OnError?.Invoke(ex, $"Azure table storage batch upload to {table.Name} for controller [{id}] failed."); break; } case 401: case 403: { OnUploadError?.Invoke(status, m_Buffer, $"Azure table storage batch upload to {table.Name} for controller [{id}] forbidden: {errmsg}"); break; } default: { OnUploadError?.Invoke(status, m_Buffer, $"Azure table storage batch upload to {table.Name} for controller [{id}] failed: {errmsg}"); break; } } } catch (Exception ex) { OnError?.Invoke(ex, $"Azure table storage batch upload to {table.Name} for controller [{id}] failed."); } } else if (m_Buffer.Count > 0) { // Single upload var data = m_Buffer[0]; var id = data.Controller; var table = MapTable(data); var entity = data.ToEntity(data.ID ?? m_RowKeyBase + "-" + m_Seq++); var insert = TableOperation.Insert(entity); var link = (data.ID != null) ? TableOperation.Insert(new Link(table.Name, data.ID, entity.PartitionKey, entity.RowKey)) : null; OnDebug?.Invoke($"Uploading record to Azure table storage {table.Name} for controller [{id}]..."); try { TableResult r; if (link != null) { r = await m_LinksTable.ExecuteAsync(link); } r = await table.ExecuteAsync(insert); OnUploadSuccess?.Invoke(r.HttpStatusCode, new[] { data }, $"Azure table storage upload to {table.Name} for controller [{id}] succeeded, result = {r.HttpStatusCode}."); if (m_Buffer.Count <= 1) { m_Buffer.Clear(); } else { m_Buffer.RemoveAt(0); } } catch (StorageException ex) { var status = ex.RequestInformation.HttpStatusCode; var errmsg = ex.RequestInformation.ExtendedErrorInformation?.ErrorMessage ?? ex.RequestInformation.HttpStatusMessage ?? ex.Message; switch (status) { case 0: { OnError?.Invoke(ex, $"Azure table storage upload to {table.Name} for controller [{id}] failed."); break; } case 401: case 403: { OnUploadError?.Invoke(status, new[] { data }, $"Azure table storage upload to {table.Name} for controller [{id}] forbidden: {errmsg}"); break; } default: { OnUploadError?.Invoke(status, new[] { data }, $"Azure table storage upload to {table.Name} for controller [{id}] failed: {errmsg}"); break; } } } catch (Exception ex) { OnError?.Invoke(ex, $"Azure table storage upload to {table.Name} for controller [{id}] failed."); } } }
public static void Debug(string input) { OnDebug?.Invoke(null, input); }
private async Task WaitForResponse() { var response = await _responseStream.MoveNext(); if (response) { // multiple response elements are received per response, each can contain one of the Result, AudioOut or EventType fields ConverseResponse currentResponse = _responseStream.Current; // Debug output the whole response, useful for.. debugging. OnDebug?.Invoke(ResponseToOutput(currentResponse)); // EndOfUtterance, Assistant has recognised something so stop sending audio if (currentResponse.EventType == ConverseResponse.Types.EventType.EndOfUtterance) { ResetSendingAudio(false); } if (currentResponse.AudioOut != null) { _audioOut.AddBytesToPlay(currentResponse.AudioOut.AudioData.ToByteArray()); } if (currentResponse.Result != null) { // if the assistant has recognised something, flag this so the failure notification isn't played if (!String.IsNullOrEmpty(currentResponse.Result.SpokenRequestText)) { _assistantResponseReceived = true; } switch (currentResponse.Result.MicrophoneMode) { // this is the end of the current conversation case ConverseResult.Types.MicrophoneMode.CloseMicrophone: StopRecording(); // play failure notification if nothing recognised. if (!_assistantResponseReceived) { _audioOut.PlayNegativeNotification(); OnAssistantStateChanged?.Invoke(AssistantState.Inactive); } break; case ConverseResult.Types.MicrophoneMode.DialogFollowOn: // stop recording as the follow on is in a whole new conversation, so may as well restart the same flow StopRecording(); _followOn = true; break; } } await WaitForResponse(); } else { OnDebug?.Invoke("Response End"); // if we've received any audio... play it. _audioOut.Play(); } }
public virtual void Debug(Selection curSelection) { OnDebug?.Invoke(curSelection); }
protected override void GatedDebug(string message) { OnDebug?.Invoke(message); OnLog?.Invoke(LogLevel.Debug, message); }
public static void Debug(string message, [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) { OnDebug?.Invoke(message, file, line); }
private async Task RefreshAsync() { // Prune the queues in order of least importance while (OutBufferCount > m_MaxMessages) { if (m_MoldDataQueue.Count > 0) { if (m_MoldDataQueue.TryDequeue(out _)) { continue; } } if (m_EventsQueue.Count > 0) { if (m_EventsQueue.TryDequeue(out _)) { continue; } } if (m_AuditTrailQueue.Count > 0) { if (m_AuditTrailQueue.TryDequeue(out _)) { continue; } } if (m_AlarmsQueue.Count > 0) { if (m_AlarmsQueue.TryDequeue(out _)) { continue; } } if (m_CycleDataQueue.Count > 0) { if (m_CycleDataQueue.TryDequeue(out _)) { continue; } } } if ((DateTime.Now - m_LastDebugMessage).TotalMilliseconds > MaxUploadInterval) { OnDebug?.Invoke($"Azure - CYCLE:{m_CycleDataQueue.Count},AUDIT:{m_AuditTrailQueue.Count},ALARM:{m_AlarmsQueue.Count},MOLD:{m_MoldDataQueue.Count},EVENT:{m_EventsQueue.Count}" + (m_Buffer.Count > 0 ? $",BUF:{m_Buffer.Count}" : null)); m_LastDebugMessage = DateTime.Now; } if (m_Buffer.Count <= 0) { // See if we have anything interesting var minitems = BatchSize; var mincycledata = CycleDataBatchSize; // Not uploaded for a while, upload data anyway if (!m_IsRunning) { minitems = mincycledata = 1; } else { if (m_LastEnqueueTime == DateTime.MinValue || (DateTime.Now - m_LastEnqueueTime).TotalMilliseconds > MaxUploadInterval) { minitems = mincycledata = 1; } } // Check cycle data first if (m_CycleDataQueue.Count() >= mincycledata) { TakeIntoBuffer(m_CycleDataQueue); } else if (m_EventsQueue.Count() >= minitems) { TakeIntoBuffer(m_EventsQueue); } else if (m_AuditTrailQueue.Count() >= minitems) { TakeIntoBuffer(m_AuditTrailQueue); } else if (m_AlarmsQueue.Count() >= minitems) { TakeIntoBuffer(m_AlarmsQueue); } else if (m_MoldDataQueue.Count() >= 1) { TakeIntoBuffer(m_MoldDataQueue, 1); } } await UploadBufferAsync(); }
public static void Debug(string category, string message) { OnDebug?.Invoke(category, message); }
public SnatcherMenu(Menu mainMenu) { var menu = new Menu("Snatcher", "snatcher"); var notificationMenu = new Menu("Notification", "snatcherNotification"); var notificationEnabled = new MenuItem("snatcherNotificationEnabled", "Enabled").SetValue(false); notificationEnabled.SetTooltip("Show notification when snatched is enabled"); notificationMenu.AddItem(notificationEnabled); notificationEnabled.ValueChanged += (sender, args) => { IsNotificationEnabled = args.GetNewValue <bool>(); OnNotificationEnabledChange?.Invoke(null, new BoolEventArgs(IsNotificationEnabled)); }; IsNotificationEnabled = notificationEnabled.IsActive(); var notificationHoldKey = new MenuItem("snatcherNotificationHoldKey", "Enabled for hold key").SetValue(false); notificationMenu.AddItem(notificationHoldKey); notificationHoldKey.ValueChanged += (sender, args) => { NotificationHold = args.GetNewValue <bool>(); }; NotificationHold = notificationHoldKey.IsActive(); var notificationToggleKey = new MenuItem("snatcherNotificationToggleKey", "Enabled for toggle key").SetValue(true); notificationMenu.AddItem(notificationToggleKey); notificationToggleKey.ValueChanged += (sender, args) => { NotificationToggle = args.GetNewValue <bool>(); }; NotificationToggle = notificationToggleKey.IsActive(); var notificationSize = new MenuItem("snatcherNotificationSize", "Size").SetValue(new Slider(22, 15, 30)); notificationMenu.AddItem(notificationSize); notificationSize.ValueChanged += (sender, args) => { NotificationSize = args.GetNewValue <Slider>().Value; }; NotificationSize = notificationSize.GetValue <Slider>().Value; var notificationX = new MenuItem("snatcherNotificationX", "Coordinates X").SetValue( new Slider(15, 0, (int)HUDInfo.ScreenSizeX())); notificationMenu.AddItem(notificationX); notificationX.ValueChanged += (sender, args) => { NotificationX = args.GetNewValue <Slider>().Value; }; NotificationX = notificationX.GetValue <Slider>().Value; var notificationY = new MenuItem("snatcherNotificationY", "Coordinates Y").SetValue( new Slider(50, 0, (int)HUDInfo.ScreenSizeY())); notificationMenu.AddItem(notificationY); notificationY.ValueChanged += (sender, args) => { NotificationY = args.GetNewValue <Slider>().Value; }; NotificationY = notificationY.GetValue <Slider>().Value; var enabled = new MenuItem("snatcherEnabled", "Enabled").SetValue(true); menu.AddItem(enabled); enabled.ValueChanged += (sender, args) => { IsEnabled = args.GetNewValue <bool>(); OnEnabledChange?.Invoke(null, new BoolEventArgs(IsEnabled)); }; IsEnabled = enabled.IsActive(); var holdKey = new MenuItem("holdSnatchKey", "Hold key").SetValue(new KeyBind('O', KeyBindType.Press)); menu.AddItem(holdKey); holdKey.ValueChanged += (sender, args) => HoldKey = args.GetNewValue <KeyBind>().Active; HoldKey = holdKey.IsActive(); var holdItems = new MenuItem("enabledStealHold", "Hold steal:").SetValue( new AbilityToggler(items.ToDictionary(x => x.Key, x => true))); menu.AddItem(holdItems); holdItems.ValueChanged += (sender, args) => { SetEnabledItems(args.GetNewValue <AbilityToggler>().Dictionary, EnabledHoldItems); }; var toggleKey = new MenuItem("pressSnatchKey", "Toggle key").SetValue(new KeyBind('P', KeyBindType.Toggle)); menu.AddItem(toggleKey); toggleKey.ValueChanged += (sender, args) => ToggleKey = args.GetNewValue <KeyBind>().Active; ToggleKey = toggleKey.IsActive(); var toggleItems = new MenuItem("enabledStealToggle", "Toggle steal:").SetValue( new AbilityToggler(items.ToDictionary(x => x.Key, x => true))); menu.AddItem(toggleItems); toggleItems.ValueChanged += (sender, args) => SetEnabledItems( args.GetNewValue <AbilityToggler>().Dictionary, EnabledToggleItems); var otherUnits = new MenuItem("snatcherOtherUnits", "Use other units").SetValue(false) .SetTooltip("Like Spirit Bear, Meepo clones"); menu.AddItem(otherUnits); otherUnits.ValueChanged += (sender, args) => { UseOtherUnits = args.GetNewValue <bool>(); OnUseOtherUnitsChange?.Invoke(null, new BoolEventArgs(UseOtherUnits)); }; UseOtherUnits = otherUnits.IsActive(); var itemMoveCostThreshold = new MenuItem("snatcherMoveItemCost", "Move item cost threshold").SetValue(new Slider(1000, 0, 5000)); itemMoveCostThreshold.SetTooltip( "It will move item from inventory (when full) to backpack which costs less gold to pick up aegis/rapier/gem (disabled: 0)"); menu.AddItem(itemMoveCostThreshold); itemMoveCostThreshold.ValueChanged += (sender, args) => ItemMoveCostThreshold = args.GetNewValue <Slider>().Value; ItemMoveCostThreshold = itemMoveCostThreshold.GetValue <Slider>().Value; var updateRate = new MenuItem("snatcherUpdateRate", "Update rate").SetValue(new Slider(1, 1, 500)); updateRate.SetTooltip("Lower value => faster reaction, but requires more resources"); menu.AddItem(updateRate); updateRate.ValueChanged += (sender, args) => { UpdateRate = args.GetNewValue <Slider>().Value; OnUpdateRateChange?.Invoke(null, new IntEventArgs(UpdateRate)); }; UpdateRate = updateRate.GetValue <Slider>().Value; var debug = new MenuItem("snatcherDebug", "Debug info").SetValue(false); menu.AddItem(debug); debug.ValueChanged += (sender, args) => OnDebug?.Invoke(null, EventArgs.Empty); SetEnabledItems(holdItems.GetValue <AbilityToggler>().Dictionary, EnabledHoldItems); SetEnabledItems(toggleItems.GetValue <AbilityToggler>().Dictionary, EnabledToggleItems); menu.AddSubMenu(notificationMenu); mainMenu.AddSubMenu(menu); }
/// <summary> /// 接收信息 /// </summary> /// <param name="socket"></param> private void RecMsg(object socket) { int headSize = 4; byte[] surplusBuffer = null; System.Net.Sockets.Socket sokClient = socket as System.Net.Sockets.Socket; string socketip = sokClient.RemoteEndPoint.ToString(); while (true) { int count = -1; try { byte[] vs = new byte[1024]; count = sokClient.Receive(vs); // 接收数据,并返回数据的长度; int bytesRead = vs.Length; if (bytesRead > 0) { if (surplusBuffer == null) { surplusBuffer = vs; } else { surplusBuffer = surplusBuffer.Concat(vs).ToArray(); } int haveRead = 0; int totalLen = surplusBuffer.Length; while (haveRead <= totalLen) { if (totalLen - haveRead < headSize) { //Console.WriteLine("不够一个包~"); byte[] byteSub = new byte[totalLen - haveRead]; Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); surplusBuffer = byteSub; totalLen = 0; break; } //如果是够一个完整包了,帽读取包头的数据 byte[] headByte = new byte[headSize]; Buffer.BlockCopy(surplusBuffer, haveRead, headByte, 0, headSize); int bodySize = BitConverter.ToInt32(headByte, 0); //得到长度 if (bodySize == 0) { surplusBuffer = null; totalLen = 0; break; } //这里的 haveRead=等于N个数据包的长度 从0开始;0,1,2,3....N //如果自定义缓冲区拆解N个包后的长度 大于 总长度,说最后一段数据不够一个完整的包了,拆出来保存 if (haveRead + headSize + bodySize > totalLen) { byte[] byteSub = new byte[totalLen - haveRead]; Buffer.BlockCopy(surplusBuffer, haveRead, byteSub, 0, totalLen - haveRead); surplusBuffer = byteSub; // Console.WriteLine("不够一个包,拆出来保存"); break; } else { string strc = Encoding.UTF8.GetString(surplusBuffer, haveRead + headSize, bodySize).StringDecrypt(IsOpenDesEnc); string[] ss = strc.Split(','); //心跳事件,更新客户端的最后登陆时间 if (ss.Count() == 2 && ss[0].ToString().Equals("hear")) { // 心跳事件 0=hert,1=ip lockSlim.EnterWriteLock(); try { ClientMode socketClient; if (dictsocket.TryGetValue(ss[1].ToString(), out socketClient)) { OnDebug?.Invoke($"Update timestamp:{SocketTools.GetTimeStamp()} - ss[1].ToString()"); socketClient.lastTickTime = SocketTools.GetTimeStamp(); } } catch (Exception ex) { OnError?.Invoke($"Heartbeat error: {ex.ToString()}"); } finally { lockSlim.ExitWriteLock(); } } else { // OnRecMessage?.Invoke(socketip, strc); OnRecMessage?.Invoke(this, new SocketMsgArgs(new ClientRecInfo() { ip = socketip, msg = strc })); } haveRead = haveRead + headSize + bodySize; if (headSize + bodySize == bytesRead) { surplusBuffer = null; totalLen = 0; } } } } } catch (Exception ex) { ReMoveSocketClient(socketip); //OnError?.Invoke($"Client thread error:{socketip} " ); break; } } }