using System; using System.Threading; using EmbedIO.WebSockets; using System.Threading.Tasks; using KevDrawServer.Drawer; using EmbedIO.Sessions; using System.Collections.Generic; using GeoSigma.SigmaDrawerUtil; using System.IO; using GeoSigmaDrawLib; using System.Drawing; using System.Drawing.Imaging; using System.Net.WebSockets; using System.Diagnostics; namespace KevDrawServer { class EventSocketModule : WebSocketModule { public string MapFile { get; set; } = string.Empty; private static readonly Object locker = new Object(); private WebDrawer drawer = null; //IWebSocketContext socketContex; public EventSocketModule() : base("/event", true) { AddProtocol("json"); } /// protected override async Task OnClientConnectedAsync(IWebSocketContext context) { Logger.Info("client connected"); await SendTargetedEvent(context, new JsEvent("connected")).ConfigureAwait(false); } //CancellationTokenSource _cts; //private char[] message; /// /// Sends the targeted event. /// /// The context. /// The js event. /// A Task. private Task SendTargetedEvent(IWebSocketContext context, JsEvent jsEvent) { if (context.WebSocket.State != WebSocketState.Open) { return Task.CompletedTask; } // 取消之前的发送任务 //_cts.Cancel(); //_cts = new CancellationTokenSource(); return SendAsync(context, JsonUtils.SerializeToJson(jsEvent)); } /// protected override Task OnClientDisconnectedAsync(IWebSocketContext context) { Logger.Info("client disconnected"); return Task.CompletedTask; } public async Task BroadcastEvent(JsEvent jsEvent) { var json = JsonUtils.SerializeToJson(jsEvent); await BroadcastAsync(json).ConfigureAwait(false); } /// protected override async Task OnMessageReceivedAsync(IWebSocketContext context, byte[] rxBuffer, IWebSocketReceiveResult rxResult) { // 回应客户端 //socketContex = context; string text = Encoding.GetString(rxBuffer); //Trace.WriteLine($"Message {text}"); JsEvent evt = new JsEvent("Nothing"); Dictionary dictionary = new Dictionary(); try { evt = JsonUtils.DeserializeFromJson(text); try { dictionary = JsonUtils.DeserializeFromJson>($"{evt.Data}"); } catch { Logger.Info("Got message is block:{0}", text); } } catch (Exception ex) { Logger.Info("Got message error:{0}\r\n{1}", text, ex.Message); return; } string strEventType = evt.Type; Logger.Info("Got message of type {0}", strEventType); if (strEventType.Equals("Ping", StringComparison.CurrentCultureIgnoreCase)) { await SendTargetedEvent(context, new JsEvent("Pong")).ConfigureAwait(false); return; } string strToken = evt.Token; if (strEventType == "OpenFile") { if (!dictionary.ContainsKey("token")) { return; } strToken = $"{dictionary["token"]}"; this.clearError(context, strToken); string strFile = $"{dictionary["file"]}"; double dWidth = Convert.ToDouble(dictionary["width"]); double dHeight = Convert.ToDouble(dictionary["height"]); string strResult = await EventResponse.CreateDrawerAsync(strFile, (int)dWidth, (int)dHeight, context, strToken).ConfigureAwait(true); if (!string.IsNullOrEmpty(strResult)) { if (this.findError(context, strToken) != null) { return; } // 发送Token var jsEvent = new JsEvent("NewToken"); jsEvent.Token = strToken; jsEvent.UserID = strFile; await SendTargetedEvent(context, jsEvent).ConfigureAwait(false); } else { // 发送打开错误信息 var jsEvent = new JsEvent("OpenError"); jsEvent.Token = strToken; jsEvent.UserID = strFile; // 记录错误 GlobalSession.StoreData($"Error_{strToken}", strToken); await SendTargetedEvent(context, jsEvent).ConfigureAwait(false); return; } } else if (strEventType == "CloseDrawer") { await EventResponse.CloseDrawerAsync(strToken, context); return; } //Logger.Info("OnMessageReceivedAsync:" + strToken); SemaphoreSlim drawerLock = GetCurrentLocker(strToken, context); if (drawerLock != null) { await drawerLock.WaitAsync(); // 异步获取锁 try { WebDrawer drawerCur = GetCurrentDrawer(strToken, context); EventResponse response = new EventResponse(drawerCur, context); // FIXME: 下面的获取有利区需要知道原始文件名,所以需要知道 token,在这里扩充了一下 dictionary["token"] = strToken; JsEvent responseEvent = await Task.Run(() => response.ExcuteOperator(evt.Type, dictionary)); if (responseEvent != null) { responseEvent.Token = strToken; responseEvent.CmdID = evt.CmdID; await SendTargetedEvent(context, responseEvent).ConfigureAwait(false); // 执行后续事件 if(evt.Type== "SelectMouseUp") { string strEventAfterType = "GetElementProperty"; await ExcuteAfter(strEventAfterType, context, strToken, evt.CmdID, response); } } } finally { drawerLock.Release(); } } } /// /// 后续事件. /// /// The event name. /// The context. /// The str token. /// The cmd i d. /// The response. /// A Task. private async Task ExcuteAfter(string eventName, IWebSocketContext context, string strToken, string cmdID, EventResponse response) { JsEvent responseAfter = await Task.Run(() => response.ExcuteOperator(eventName, null)); if (responseAfter != null) { responseAfter.Token = strToken; responseAfter.CmdID = cmdID; await SendTargetedEvent(context, responseAfter).ConfigureAwait(false); } } /// /// 查找错误信息. /// /// The context. /// /// An object. private object findError(IWebSocketContext context, string token) { string strError = $"Error_{token}"; foreach (KeyValuePair kv in context.Session.TakeSnapshot()) { if(kv.Key.StartsWith(strError)) { return kv.Value; } } return null; } /// /// 清除错误信息. /// /// The context. /// private void clearError(IWebSocketContext context,string token) { string strError = $"Error_{token}"; IReadOnlyList> kvs = context.Session.TakeSnapshot(); for (int i=kvs.Count-1;i>=0;i--) { KeyValuePair kv = kvs[i]; if (kv.Key.StartsWith(strError)) { object objFind = null; GlobalSession.TryRemove(kv.Key, out objFind); } } } /// /// Gets the current locker. /// /// The token. /// The context. /// An object. private SemaphoreSlim GetCurrentLocker(string token, IWebSocketContext context) { object obj = GlobalSession.GetData($"Lock_{token}"); return (SemaphoreSlim)obj; } /// /// 获得当前Session中的Drawer. /// /// A WebDrawer. private WebDrawer GetCurrentDrawer(string token, IWebSocketContext context) { drawer = (WebDrawer)GlobalSession.GetData(token); return drawer; } ///// ///// Creates the drawer. ///// ///// The file. ///// The w. ///// The h. //public async Task CreateDrawerAsync(string file, int w, int h) //{ // DrawerConfig.StartupPath = WebConfig.StartupPath; // string strServerPath = WebConfig.MapDirectory; // drawer = new WebDrawer(w, h); // MapFile = Path.Combine(strServerPath, file); // //ImageFile = Path.Combine(strServerPath, "K1.png"); // GeoSigmaXY geo = drawer.OpenFile(MapFile); // string strToken = geo.GetDrawerXy().ToInt64().ToString(); // GlobalSession.StoreData(strToken, drawer); // GlobalSession.StoreData("DrawerFile", file); // GlobalSession.StoreData($"Lock_{strToken}", new SemaphoreSlim(1, 1)); // // 发送Token // var responseEvent = new JsEvent("NewToken"); // responseEvent.Data = strToken; // await SendTargetedEvent(context, responseEvent).ConfigureAwait(false); // return strToken; //} ////// GET: Drawer //////public ActionResult Index() //////{ ////// ViewBag.Title = "Kep图形平台"; ////// return View(); //////} //////public FileResult Image() //////{ ////// ImageFile = Server.MapPath("..") + "\\Maps\\K1.png"; ////// byte[] image = GetBytesFromImage(ImageFile); ////// return new FileContentResult(image, "image/jpeg"); //////} //public async System.Threading.Tasks.Task OpenAsync(string file, int w = 0, int h = 0) //{ // object oDrawer = null; // //drawer = (WebDrawer)context.Session["KevDrawer"]; // if (GlobalSession.ContainsKey("KevDrawer")) // { // if (GlobalSession.TryGetValue("KevDrawer", out oDrawer)) // { // GlobalSession.TryRemove("KevDrawer", out oDrawer); // this.drawer = oDrawer as WebDrawer; // if (drawer != null) // { // drawer.Dispose(); // drawer = null; // } // } // } // await this.ShowImgAsync(file, w, h); //} ////[Route(HttpVerbs.Get, "/Redraw")] //public async Task Redraw(int w = 0, int h = 0) //{ // //this.drawer = GetCurrentDrawer(); // if (drawer == null) // { // return; // } // await this.ShowImgAsync("", w, h); //} //private string imageFile = "temp/K1.png"; //private async Task ShowImgAsync(string file = "", int w = 0, int h = 0, bool sendContent = false) //{ // Bitmap bmp = null; // await Task.Run(() => // { // lock (locker) // { // if (drawer == null) // { // DrawerConfig.StartupPath = WebConfig.StartupPath; // string strServerPath = WebConfig.MapDirectory; // drawer = new WebDrawer(w, h); // MapFile = Path.Combine(strServerPath, file); // //ImageFile = Path.Combine(strServerPath, "K1.png"); // GeoSigmaXY geo = drawer.OpenFile(MapFile); // string strToken = geo.GetDrawerXy().ToInt64().ToString(); // GlobalSession.StoreData(strToken,drawer); // GlobalSession.StoreData("DrawerFile", file); // // 发送Token // var responseEvent = new JsEvent("NewToken"); // responseEvent.Data = strToken; // SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(false); // } // if (w != 0 && h != 0) // { // drawer.DrawerSize = new Size(w, h); // } // bmp = new Bitmap(drawer.DrawerSize.Width, drawer.DrawerSize.Height); // // bmp.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution); // using (Graphics g = Graphics.FromImage(bmp)) // { // drawer.OnPaint(g); // } // } // }); // await SendImg(bmp, "", sendContent); //} ///// ///// 发送图片. ///// ///// The bmp. ///// 事件名称 ///// If true, send content. ///// A Task. //private async Task SendImg(Bitmap bmp, string eventName = "", bool sendContent = false) //{ // byte[] image = null; // string strFile = string.Empty; // try // { // if (sendContent == false) // { // strFile = Path.Combine(WebConfig.HtmlRoot, imageFile); // bmp.Save(strFile); // } // else // { // image = ConvertBitmapToByteArray(bmp); // } // } // catch(Exception ex) // { // //Console.WriteLine($"SendImg: {ex.Message}"); // return; // } // string strEventName = eventName; // if (string.IsNullOrEmpty(eventName)) // { // strEventName = "Redraw"; // } // var responseEvent = new JsEvent(strEventName); // if (sendContent) // { // string base64Header = $"data:image/png;base64,"; // responseEvent.Data = (base64Header + Convert.ToBase64String(image)); // } // else // { // responseEvent.Data = imageFile; // } // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(false); //} //public async Task SaveFileAsync() //{ // if (drawer == null) // { // return; // } // bool bSuccess = drawer.SaveFile(); // var responseEvent = new JsEvent("Save"); // responseEvent.Data = bSuccess; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(false); //} //[Route(HttpVerbs.Get, "/ZoomIn")] //public async Task ZoomIn(Dictionary keyValues) //{ // //this.drawer = GetCurrentDrawer(); // if (drawer == null) // { // return; // } // double dWidth = Convert.ToDouble(keyValues["width"]); // double dHeight = Convert.ToDouble(keyValues["height"]); // drawer.DrawerSize = new Size((int)dWidth, (int)dHeight); // drawer.ZoomIn(); // await ShowImgAsync(); //} //[Route(HttpVerbs.Get, "/ZoomOut")] //public async Task ZoomOut(Dictionary keyValues) //{ // //this.drawer = GetCurrentDrawer(); // if (drawer == null) // { // return; // } // double dWidth = Convert.ToDouble(keyValues["width"]); // double dHeight = Convert.ToDouble(keyValues["height"]); // drawer.DrawerSize = new Size((int)dWidth, (int)dHeight); // drawer.ZoomOut(); // await this.ShowImgAsync(); //} //public async Task ViewAll(Dictionary keyValues) //{ // if (drawer == null) // { // return; // } // double dWidth = Convert.ToDouble(keyValues["width"]); // double dHeight = Convert.ToDouble(keyValues["height"]); // drawer.DrawerSize = new Size((int)dWidth, (int)dHeight); // drawer.ViewAll(); // await this.ShowImgAsync(); //} //[Route(HttpVerbs.Get, "/SelectAll")] //public async System.Threading.Tasks.Task SelectAll([QueryField]int arg) //{ // this.drawer = GetCurrentDrawer(); // if (drawer == null) // { // return; // } // WebDrawToolSelect drawToolSelect = new WebDrawToolSelect(drawer.Geo); // drawToolSelect.Start(); // drawToolSelect.SelectAll(); // await this.ShowImgAsync(); //} public static byte[] ConvertBitmapToByteArray(Bitmap bitmap) { if(bitmap == null) { return null; } using (MemoryStream memoryStream = new MemoryStream()) { // 选择图像格式,可以是Png、Jpeg等 bitmap.Save(memoryStream, ImageFormat.Png); return memoryStream.ToArray(); } } //public async Task SelectLButtonDown(double x, double y) //{ // if (drawer == null) // { // return; // } // Bitmap bmp = null; // await Task.Run(() => // { // lock (locker) // { // bmp = drawer.OnLButtonDown(x, y); // } // }); // if (bmp != null) // { // bmp.MakeTransparent(Color.White); // Point pt = drawer.CacheImgLocation; // string strFile = string.Empty; // try // { // strFile = Path.Combine(WebConfig.HtmlRoot, imageFile); // bmp.Save(strFile); // } // catch (Exception ex) // { // //Console.WriteLine($"SendImg: {ex.Message}"); // return; // } // string strEventName = "DragElement"; // var responseEvent = new JsEvent(strEventName); // Dictionary keyValues = new Dictionary(); // keyValues.Add("Data", imageFile); // keyValues.Add("ImgLeft", pt.X); // keyValues.Add("ImgTop", pt.Y); // responseEvent.Data = keyValues; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(false); // } //} /// /// 选中对象 /// /// //[Route(HttpVerbs.Get, "/ClickImage")] //public async Task SelectMouseUp(double endX, double endY) //{ // if (drawer == null) // { // return; // } // Bitmap bmp = null; // await Task.Run(() => // { // lock (locker) // { // bmp = drawer.LButtonUp(endX, endY); // } // }); // if (bmp != null) // { // // bmp.MakeTransparent(Color.White); // await SendImg(bmp, string.Empty, false); // } //} ////[Route(HttpVerbs.Get, "/LButtonUp")] //public async Task LButtonUp( double x, double y) //{ // if (drawer == null) // { // return; // } // Bitmap bmp = null; // await Task.Run(() => // { // lock (locker) // { // bmp = drawer.LButtonUp(x, y); // } // }); // if (bmp != null) // { // await SendImg(bmp,string.Empty, false); // } //} //public async Task MouseMove(double x, double y) //{ // if (drawer == null) // { // return ; // } // int result = 0; // //await Task.Run(() => // //{ // // lock (locker) // // { // result = this.drawer.MouseMove(x, y); // // } // //}); // //Console.WriteLine($"MouseMove hanle:{result}"); // var responseEvent = new JsEvent("SelectHandle") // { // Data = result, // }; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(true); // //return result; //} /// /// 移动浏览 /// /// 起始坐标X /// 起始坐标Y /// 终止坐标X /// 终止坐标Y /// //public async Task ViewPan(Dictionary keyValues) //{ // if (this.drawer == null) // { // return; // } // double dStartX = Convert.ToDouble(keyValues["startX"]); // double dStartY = Convert.ToDouble(keyValues["startY"]); // double dEndX = Convert.ToDouble(keyValues["endX"]); // double dEndY = Convert.ToDouble(keyValues["endY"]); // double dWidth = Convert.ToDouble(keyValues["width"]); // double dHeight = Convert.ToDouble(keyValues["height"]); // drawer.DrawerSize = new Size((int)dWidth, (int)dHeight); // Bitmap bmp = null; // await Task.Run(() => // { // lock (locker) // { // bmp = drawer.ViewOperatorPan(dStartX, dStartY, dEndX, dEndY); // } // }); // if (bmp != null) // { // await SendImg(bmp); // } //} /// /// 移动浏览 /// /// 起始坐标X /// 起始坐标Y /// 终止坐标X /// 终止坐标Y /// //public async Task ViewWindow(Dictionary keyValues) //{ // if (this.drawer == null) // { // return; // } // double dStartX = Convert.ToDouble(keyValues["startX"]); // double dStartY = Convert.ToDouble(keyValues["startY"]); // double dEndX = Convert.ToDouble(keyValues["endX"]); // double dEndY = Convert.ToDouble(keyValues["endY"]); // double dWidth = Convert.ToDouble(keyValues["width"]); // double dHeight = Convert.ToDouble(keyValues["height"]); // drawer.DrawerSize = new Size((int)dWidth, (int)dHeight); // Bitmap bmp = drawer.ViewOperatorWindow(dStartX, dStartY, dEndX, dEndY); // if (bmp != null) // { // await SendImg(bmp); // } //} //public async Task TranslateElements( double x, double y) //{ // if (drawer == null) // { // return; // } // try // { // if (socketContex.WebSocket.State == WebSocketState.Open) // { // Bitmap bmp = drawer.TranslateElements(x, y); // if (bmp != null) // { // await SendImg(bmp); // } // } // else // { // //Console.WriteLine("WebSocket connection is not open."); // } // } // catch (EmbedIO.WebSockets.WebSocketException ex) // { // //Console.WriteLine($"WebSocketException: {ex.Message}"); // } // catch (Exception ex) // { // //Console.WriteLine($"Exception: {ex.Message}"); // } //} //[Route(HttpVerbs.Get, "/MouseMove")] //public async Task MouseMove([QueryField] double x, [QueryField] double y) //{ // this.drawer = GetCurrentDrawer(); // if (drawer == null) // { // return -2; // } // return this.drawer.MouseMove(x, y); //} //public byte[] GetBytesFromImage(string filename) //{ // try // { // FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); // int length = (int)fs.Length; // byte[] image = new byte[length]; // fs.Read(image, 0, length); // fs.Close(); // return image; // } // catch (Exception ex) // { // return null; // } //} #region 图层管理 /// /// 获得图层数据. /// /// A Task. //public async Task GetLayers() //{ // if (this.drawer == null) // { // return; // } // var responseEvent = new JsEvent("ReloadLayer"); // responseEvent.Data = drawer.LayerTree.Layers; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(false); //} /// /// Sets the layers status. /// /// The layers status. /// VIEW_EDIT = 10, /// VIEW_NOT_EDIT = 11, /// NOT_VIEW_NOT_EDIT = 12 /// A Task. //public async Task SetLayersStatus(string layersStatus) //{ // if (this.drawer == null) // { // return; // } // GeoLayerTree layerTree = drawer?.LayerTree; // if (layerTree.SetLayersStatus(layersStatus)) // { // await this.ShowImgAsync(); // } //} /// /// 删除图层 /// /// /// /// //public async Task DeleteLayers(string layers, bool withSubLayer) //{ // if (drawer == null) // { // return; // } // var layerArray = layers.Split(new string[] { Environment.NewLine, ","}, StringSplitOptions.RemoveEmptyEntries); // int nCount = layerArray.Length; // if(nCount == 0) // { // return; // } // for(int i=0;i< nCount; i++) // { // int nIndexFind = layerArray[i].IndexOf("Layer:\\", 0, StringComparison.CurrentCultureIgnoreCase); // if (nIndexFind >= 0) // { // layerArray[i] = layerArray[i].Remove(0, 7); // } // } // await Task.Run(() => // { // lock (locker) // { // drawer.DeleteLayers(layerArray, withSubLayer); // } // }); // var responseEvent = new JsEvent("DeleteLayers") // { // Data = string.Empty, // }; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(true); // await this.ShowImgAsync(); //} #endregion #region 数据操作 /// /// 添加数据. /// /// The data. /// A Task. //public async Task AddBufferData(string data) //{ // if (drawer == null) // { // return; // } // int nResult = -1; // await Task.Run(() => // { // lock (locker) // { // nResult = drawer.AddBufferData(data); // } // }); // var responseEvent = new JsEvent("AddBufferData") // { // Data = nResult, // }; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(true); //} #endregion #region 坐标工具 /// /// Queries the range screen2 real x. /// /// The start x. /// /// The start y. /// /// A Task. //public async Task QueryRangeScreen2RealX(double startX,double endX, double startY, double endY) //{ // if (drawer == null) // { // return; // } // double dRectLeft = 0, dRectRight = 0, dRectTop = 0, dRectBottom = 0; // await Task.Run(() => // { // lock (locker) // { // drawer.Geo.GetScreenReal((int)startX, (int)startY, (int)endX, (int)endY // , ref dRectLeft, ref dRectTop, ref dRectRight, ref dRectBottom); // } // }); // Dictionary keyValues = new Dictionary(); // keyValues.Add("left", dRectLeft); // keyValues.Add("bottom", dRectBottom); // keyValues.Add("right", dRectRight); // keyValues.Add("top", dRectTop); // var responseEvent = new JsEvent("MapRangeReal") // { // Data = keyValues, // }; // await SendTargetedEvent(socketContex, responseEvent).ConfigureAwait(true); //} #endregion } public class ActionResult { public ActionResult(int resultType, string data, int imgLeft, int imgTop, int imgWidth, int imgHeight) { ResultType = resultType; Data = data; ImgLeft = imgLeft; ImgTop = imgTop; ImgWidth = imgWidth; ImgHeight = imgHeight; } public int ResultType { get; set; } = 0; public string Data { get; set; } = string.Empty; public int ImgLeft { get; set; } public int ImgTop { get; set; } public int ImgWidth { get; set; } public int ImgHeight { get; set; } } }