/// <summary> /// 出价 - /// 1. 输入价格 - 移动到输入框位置,点击,清空历史数据,输入新价格 /// 2. 点击出价按钮 - 移动到按钮位置,点击 /// 3. 对验证码区域截图 且 上传 /// </summary> public void OfferPrice(int targetPrice, bool enableCancelFirst, Func <CaptchaAnswerImage, bool> callbackFunc = null) { // 0. 出价前,先尝试取消,防止上一步的可能的遮罩 if (enableCancelFirst) { // this.CancelOfferedPrice(); actionManager.ClickButtonByFenceWayRToL(actionManager.AddDelta(742, 502)); } // 1. 输入价格 且 出价 // TODO: 坐标方法 - 应该抽取出来单独管理 actionManager.InputTextAtPoint(actionManager.AddDelta(676, 417), targetPrice.ToString(), true, "第二阶段出价"); actionManager.ClickButtonAtPoint(actionManager.AddDelta(800, 415), true, "第二阶段出价"); // 2. 对验证码区域截屏且上传 // 这里尝试异步 ThreadUtils.StartNewTaskSafe(() => { // 这里等待会阻塞进程 KK.Sleep(390); CaptchaAnswerImage img = CaptureCaptchaImage(); UploadCaptchaImage(img); callbackFunc?.Invoke(img); } ); // return img; }
private void LoopAwaitAnswer(string imageUuid) { logger.InfoFormat("Phase1 - begin LoopAwaitAnswer"); while (isAwaitWork) { long ss = KK.CurrentMills(); try { var taskContext = CaptchaTaskContext.me; var answer = taskContext.GetAnswer(imageUuid); if (answer?.Length > 0) { phase1Manager.SubmitOfferedPrice(answer); break; } } catch (Exception e) { logger.Error("LoopInquiryCaptchaAnswer error:", e); } finally { KK.Sleep(100); } } logger.InfoFormat("Phase1 - end LoopAwaitAnswer"); }
/// <summary> /// 如果 isAbsolute != true, 在相对坐标(x, y)上点击一次 /// 否则 在绝对坐标(x, y)上点击一次 /// </summary> /// <param name="p12"></param> /// <param name="isAbsolute"></param> public void ClickBtnOnceAtPoint(CoordPoint p12, string memo = "", bool isAbsolute = false, int delayMills = 0, int clickCount = 1) { if (delayMills > 0) { KK.Sleep(delayMills); } long t1 = KK.CurrentMills(); CoordPoint po = p12; if (!isAbsolute) { po = Datum.AddDelta(p12.x, p12.y); } int ret = robot.MoveTo(po.x, po.y); robot.LeftClick(); if (clickCount > 1) { robot.LeftClick(); } logger.InfoFormat("点击按钮#{0} @ {1} with count#{2}, elapsed {3}.", memo, po.ToString(), clickCount, KK.CurrentMills() - t1); }
private void WatchSocketClient() { KK.Sleep(3 * 1000); while (watching) { KK.Sleep(DETECT_INTERVAL_MILLS); if (IsCurrentInDisabledTimeRange()) { continue; } try { if (notifyRestarting) { logger.InfoFormat("already tell socket client to reconnect"); continue; } bool connected = socketClient.IsConnected(); // 如果已未连接,则通知重新连接 if (!connected) { TellToReconnect("already disconnected"); continue; } RawMessage msg = MessageUtils.BuildPingMessage(ClientService.AssignedClientNo); socketClient.Send(msg); continuousDisconnectedCount = 0; counter.IncrementPing(); long pingCnt = counter.GetPingCount(); long pongCnt = counter.GetPongCount(); DateTime dt = DateTime.Now; if (dt.Minute > 57 && dt.Second % 8 == 0) { logger.InfoFormat("dice socket connected#{0}, ping#{1}, pong#{2}", connected, pingCnt, pongCnt); } // 如果ping和pong相差超过三次,则通知重新连接 long delta = pingCnt - pongCnt; if (delta > 3) { TellToReconnect("already over " + delta + " no pong response from server"); } } catch (Exception e) { logger.Error("WatchSocketClient error", e); } finally { } } }
public static void TryStopThreadByWait(Thread th, int mills1, int mills2, string memo) { if (th != null) { KK.Sleep(mills1); ThreadUtils.TryStopThread(th); KK.Sleep(mills2); logger.InfoFormat("NOW {0}#State is {1}", memo, th.ThreadState); } }
/// <summary> /// 提交已出的价格 /// </summary> public void SubmitOfferedPrice() { actionManager.ClickButtonByFenceWayLToR(actionManager.AddDelta(553, 500)); // TODO: 等待, 点击完成验证码确认按钮, 会弹出 出价有效 // TODO: 应该检测 区域 是否有 出价有效 KK.Sleep(600); actionManager.ClickButtonAtPoint(actionManager.AddDelta(661, 478), false, "第一阶段提交#确定"); // 清除以前输入的价格 actionManager.CleanTextAtPoint(actionManager.AddDelta(676, 417), 6, true, "第一阶段提交"); }
public void ClickLoginButton() { // 可能有身份证输入框 var d2 = new CoordPoint(642, 473); actionManager.ClickBtnOnceAtPoint(d2, "投标竞拍T2"); KK.Sleep(200); // 没有身份证输入框 var d1 = new CoordPoint(642, 427); actionManager.ClickBtnOnceAtPoint(d1, "投标竞拍T1"); }
// private int SubmitOfferedPrice(int fixSec, PriceStrategyOperate oper, string answer, PagePrice pp, int offeredPrice, int usedDelayMills, DateTime occurTime) private int SubmitOfferedPrice(BiddingPriceRequest req) { bool submitted = false; string memo = ""; DateTime occurTime = DateTime.Now; if (req.OperateStatus == StrategyOperateStatus.CAPTCHA_INPUTTED) { if (req.ComputedDelayMills > 0) { KK.Sleep(req.ComputedDelayMills); } phase2Manager.SubmitOfferedPrice(); submitted = true; logger.InfoFormat("strategy#{0} exec submit", req.StrategySecond); } else { string answer = CaptchaTaskContext.me.GetAnswer(req.CaptchaUuid); if (answer == null || answer.Length == 0) { submitted = false; logger.ErrorFormat("strategy#{0} can not exec submit, because has no captcha-answer#{1}", req.StrategySecond, req.CaptchaUuid); return(-1); } else { if (req.ComputedDelayMills > 0) { KK.Sleep(req.ComputedDelayMills); } phase2Manager.SubmitOfferedPrice(answer); memo = "WiAns"; logger.WarnFormat("strategy#{0} exec submit and fill captcha-answer#{1}", req.StrategySecond, answer); } } if (submitted) { req.OperateStatus = StrategyOperateStatus.PRICE_SUBMITTED; biddingPriceManager.RemoveStrategy(req.StrategySecond); AsyncReportPriceSubbmitted(req, occurTime, memo); } return(0); }
public void StartClient() { logger.InfoFormat("begin start socket-client with address#{0}:{1}", ip, port); socketStarting = true; working = true; connectStatus = ConnectStatusEnum.CONNECTING; try { IPAddress ipAddr = IPAddress.Parse(ip); IPEndPoint remoteEP = new IPEndPoint(ipAddr, port); // Create a TCP/IP socket. _client = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp); // Connect to the remote endpoint. _client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), _client); while (connectStatus == ConnectStatusEnum.CONNECTING) { KK.Sleep(100); if (connectStatus == ConnectStatusEnum.CONNECT_FAILED) { break; } } socketStarting = false; logger.InfoFormat("connectStatus is {0}", connectStatus); logger.InfoFormat("end socket-client connect with address#{0}:{1}, _client#{2}", ip, port, _client); this.InvokeAfterSuccessConnected(); } catch (Exception e) { logger.Error("StartClient error", e); } finally { socketStarting = false; } // 无论何种情况,都应开启守护 if (EnableSocketGuard) { KeepAliveManager.ME.RestartGuard(this); } }
/// <summary> /// 提交已出的价格 /// </summary> public void SubmitOfferedPrice() { // TODO: 为了尽快的点击到确定按钮,提供3种模式 if (conf.IsConfirmModeNormal()) { actionManager.ClickButtonAtPoint(actionManager.AddDelta(554, 506), false, "第二阶段提交#1"); } else if (conf.IsConfirmModeMixed()) { actionManager.ClickButtonAtPoint(actionManager.AddDelta(554, 506), false, "第二阶段提交#1"); actionManager.ClickButtonByFenceWayLToR(actionManager.AddDelta(553, 500)); } else if (conf.IsConfirmModeFence()) { actionManager.ClickButtonByFenceWayLToR(actionManager.AddDelta(553, 500)); } else { actionManager.ClickButtonByFenceWayLToR(actionManager.AddDelta(553, 500)); } // TODO: 等待, 点击完成验证码确认按钮, 会弹出 出价有效 // TODO: 应该检测 区域 是否有 出价有效 KK.Sleep(600); // 尝试得到提交的结果截图, 0.6s 1.6s 2.6s ThreadUtils.StartNewBackgroudThread(() => { for (int i = 0; i < 3; i++) { try { string imgPath = actionManager.CaptureFlashScreen(); logger.InfoFormat("result of phase2-act is {0}", imgPath); KK.Sleep((i + 1) * 1000); } catch (Exception e) { logger.Error("act2 background CaptureFlashScreen error", e); } } }); actionManager.ClickButtonAtPoint(actionManager.AddDelta(661, 478), false, "第二阶段提交#确定"); // 清除以前输入的价格 actionManager.CleanTextAtPoint(actionManager.AddDelta(676, 417), 6, true, "第二阶段提交"); }
/// <summary> /// 出价 - /// 1. 输入价格 - 移动到输入框位置,点击,清空历史数据,输入新价格 /// 2. 点击出价按钮 - 移动到按钮位置,点击 /// 3. 对验证码区域截图 且 上传 /// </summary> public CaptchaAnswerImage OfferPrice(int targetPrice, bool enableCancelFirst, bool needUploadCaptchaTask = false) { // 0. 出价前,先尝试取消,防止上一步的可能的遮罩 if (enableCancelFirst) { actionManager.ClickButtonByFenceWayRToL(actionManager.AddDelta(742, 502)); } // 1. 输入价格 且 出价 actionManager.InputTextAtPoint(actionManager.AddDelta(676, 317), targetPrice.ToString(), true, "第一阶段出价#i1"); actionManager.InputTextAtPoint(actionManager.AddDelta(676, 375), targetPrice.ToString(), true, "第一阶段出价#i2"); actionManager.ClickButtonAtPoint(actionManager.AddDelta(800, 373), true, "第一阶段出价"); // 2. 对验证码区域截屏且上传 KK.Sleep(500); CaptchaAnswerImage img = CaptureCaptchaImage(); UploadCaptchaImage(img); return(img); }
private void TellToReconnect(string reason) { continuousDisconnectedCount++; // 每3次 未连接,则多停一会 if (continuousDisconnectedCount % 3 == 0) { logger.InfoFormat("continuous disconnected count over 3 times, disconnect count is {0}", continuousDisconnectedCount); KK.Sleep(DETECT_INTERVAL_MILLS * 6); } if (notifyRestarting) { logger.InfoFormat("already tell socket client to reconnect"); } else { logger.WarnFormat("tell try to reconnect, reason is {0}", reason); ThreadUtils.StartNewBackgroudThread(() => { socketClient.RestartClient(); }); notifyRestarting = true; } }
private void ReceiveForEver() { while (working) { try { // TODO: 这里只能读取一个buffer大小, 后续优化 byte[] bytes = new byte[1024 * 4]; int bytesRec = _client.Receive(bytes); byte[] data = new byte[bytesRec]; ByteUtils.arraycopy(bytes, 0, data, 0, bytesRec); RawMessage raw = RawMessageEncoder.me.decode(data); if (raw.getMessageType() != (int)RawMessageType.PING_COMMAND) { logger.InfoFormat("receive data is {0}, {1}, {2}", raw.totalLength, raw.messageType, raw.bodyText); } MessageDispatcher.ME.Dispatch(raw); this.anotherRecvCallback?.Invoke(raw); // logger.InfoFormat("Echoed test = {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec)); } catch (Exception e) { // logger.ErrorFormat("Receive error", e.Message); logger.Error("Receive error", e); // TODO: 出现错误, 先临时处理 不再接收了 working = false; KK.Sleep(50); } } }
private void _LoginBidAccount(string bidNo, string password, string idCardNo, bool clickLoginButton) { // 登录页 var p21 = actionManager.DeltaPoint(610, 168); var p22 = actionManager.DeltaPoint(610, 218); var p23 = actionManager.DeltaPoint(610, 264); actionManager.InputTextAtPoint(p21, bidNo, true, "投标号"); KK.Sleep(KK.RandomInt(100, 500)); actionManager.InputTextAtPoint(p22, password, true, "密码"); KK.Sleep(KK.RandomInt(100, 500)); // 可能需要输入身份证 - 身份证 isIdCardShow = IsIdCardNeeded(); if (isIdCardShow) { actionManager.InputTextAtPoint(p23, idCardNo, true, "身份证"); } else { var p231 = actionManager.DeltaPoint(610, 256); actionManager.InputTextAtPoint(p231, idCardNo, true, "身份证"); } KK.Sleep(KK.RandomInt(100, 500)); //this.inputCaptchaAtLogin(p23, "301726"); //this.clickLoginAtLogin(p24); if (clickLoginButton) { ClickLoginButton(); } logger.InfoFormat("login account#{0} ", bidNo); }
/// <summary> /// 循环询问验证码图片的答案 /// </summary> private void LoopInquiryCaptchaAnswer() { while (isInquiryWork) { long ss = KK.CurrentMills(); try { var taskContext = CaptchaTaskContext.me; long s1 = KK.CurrentMills(); if (CaptchaTaskContext.me.IsAllImagesAnswered()) { KK.Sleep(30); continue; } var images = new List <CaptchaAnswerImage>(taskContext.GetImagesOfAwaitAnswer()); logger.DebugFormat("inquiry answer, image size is {0}. First Uuid is {1}", images.Count, images[0].Uuid); foreach (var img in images) { if (img == null) { continue; } if (img.Answer == null || img.Answer.Length == 0) { var req = KK.CreateImageAnswerRequest(img.Uuid); DataResult <CaptchaImageAnswerResponse> dr = HttpClients .PostAsJson <DataResult <CaptchaImageAnswerResponse> >(conf.GetCaptchaAnswerUrl, req); if (DataResults.IsOK(dr) && dr.Data?.answer?.Length > 0) { img.Answer = dr.Data.answer; taskContext.PutAnswer(img.Uuid, dr.Data.answer); taskContext.RemoveAwaitImage(img.Uuid); logger.InfoFormat("GET task#{0}'s answer is {1}", img.Uuid, dr.Data.answer); // TODO:这段应该剥离出去 // TryInputAnswerAhead(img.Uuid, dr.Data.answer); captchaInputCallbackFunc?.Invoke(img); } } else { taskContext.RemoveAwaitImage(img.Uuid); // captchaInputCallbackFunc?.Invoke(img); } } } catch (Exception e) { logger.Error("LoopInquiryCaptchaAnswer error:", e); } finally { KK.Sleep(30); } } logger.InfoFormat("END LoopInquiryCaptchaAnswer."); }
private void LoopDetectPriceAndTimeInScreen() { logger.InfoFormat("begin loopDetectPriceAndTimeInScreen"); int i = 0; PageTimePriceResult lastResultx = null; while (isCollectingWork) { long ss = KK.CurrentMills(); try { long s1 = KK.CurrentMills(); PageTimePriceResult lastResult = actionManager.DetectPriceAndTimeInScreen(lastResultx); // 重复检测 if (lastResult.status == 300) { continue; } SetShowUpText(ToShowUpText(lastResult)); // 处理异常情况 if (lastResult.status != 0) { ProcessErrorDetect(lastResult); // TODO: 这里也需要处理 可能需要的提交,因为远程会下发一个可能的当前秒数 // 目的是防止出现卡秒现象 continue; } lastResultx = lastResult; PagePrice pp = lastResult.data; logger.DebugFormat("detectPriceAndTimeInScreen elapsed {0}ms", KK.CurrentMills() - s1); if (pp != null) { if (pp.pageTime.Minute == 28) { if (IsOneRoundStarted) { ResetContext(); IsOneRoundStarted = false; } } else if (pp.pageTime.Minute == 29) { if (!IsOneRoundStarted) { IsOneRoundStarted = true; } } s1 = KK.CurrentMills(); AfterSuccessDetectInner(pp); logger.DebugFormat("afterDetect elapsed {0}ms", KK.CurrentMills() - s1); } else { // TODO: } } catch (Exception e) { logger.Error("detect price and time error", e); } finally { // TODO: 这里可能不需要每次重置dict // actionManager.ResetDictIndex(); KK.Sleep(12); } logger.DebugFormat("round {0} loopDetectPriceAndTimeInScreen elapsed {1}ms", i++, KK.CurrentMills() - ss); } logger.InfoFormat("END loopDetectPriceAndTimeInScreen "); }