From ecda7ce619e654009493e6fb6eb98425a6b00267 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Wed, 18 Dec 2019 15:24:29 +0800 Subject: [PATCH 1/5] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E8=8E=B7=E5=8F=96sessi?= =?UTF-8?q?on=E9=9B=86=E5=90=88=E6=8A=A5=E9=94=99=202.=E5=A2=9E=E5=8A=A0tc?= =?UTF-8?q?p=E6=B5=8B=E8=AF=95=E5=9B=BE=E8=A1=A8=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ReportController.cs | 63 ++++++++ .../JT808.DotNetty.CleintBenchmark.csproj | 22 ++- src/JT808.DotNetty.CleintBenchmark/Program.cs | 29 +++- .../Services/CleintBenchmarkHostedService.cs | 2 +- .../appsettings.json | 8 +- .../wwwroot/echarts.min.js | 13 ++ .../wwwroot/index.html | 153 ++++++++++++++++++ .../JT808.DotNetty.Client.csproj | 2 +- src/JT808.DotNetty.Client/JT808TcpClient.cs | 4 +- .../Session/JT808SessionManager.cs | 4 +- 10 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 src/JT808.DotNetty.CleintBenchmark/Controllers/ReportController.cs create mode 100644 src/JT808.DotNetty.CleintBenchmark/wwwroot/echarts.min.js create mode 100644 src/JT808.DotNetty.CleintBenchmark/wwwroot/index.html diff --git a/src/JT808.DotNetty.CleintBenchmark/Controllers/ReportController.cs b/src/JT808.DotNetty.CleintBenchmark/Controllers/ReportController.cs new file mode 100644 index 0000000..0474c14 --- /dev/null +++ b/src/JT808.DotNetty.CleintBenchmark/Controllers/ReportController.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JT808.DotNetty.Client; +using JT808.DotNetty.Client.Metadata; +using JT808.DotNetty.Client.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Primitives; + +namespace JT808.DotNetty.CleintBenchmark +{ + /// + /// 车辆控制器 + /// + [Route("JT808WebApi")] + [ApiController] + [EnableCors("Domain")] + public class ReportController : ControllerBase + { + private readonly IJT808TcpClientFactory clientFactory; + private readonly JT808ReceiveAtomicCounterService ReceiveAtomicCounterService; + private readonly JT808SendAtomicCounterService SendAtomicCounterService; + + /// + /// + /// + public ReportController( + IJT808TcpClientFactory factory, + JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService, + JT808SendAtomicCounterService jT808SendAtomicCounterService) + { + clientFactory = factory; + ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService; + SendAtomicCounterService = jT808SendAtomicCounterService; + } + + [HttpPost] + [HttpGet] + [Route("QueryReport")] + public ActionResult QueryReport() + { + var clients = clientFactory.GetAll(); + JT808Report report = new JT808Report() + { + SendTotalCount = SendAtomicCounterService.MsgSuccessCount, + ReceiveTotalCount = ReceiveAtomicCounterService.MsgSuccessCount, + CurrentDate = DateTime.Now, + Connections = clients.Count, + OnlineConnections = clients.Where(w => w.IsOpen).Count(), + OfflineConnections = clients.Where(w => !w.IsOpen).Count(), + }; + return report; + } + } +} \ No newline at end of file diff --git a/src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj b/src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj index cc4b46b..61abd40 100644 --- a/src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj +++ b/src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,11 @@ 7.3 + + + + + @@ -18,6 +23,21 @@ + + + Always + + + Always + + + + + + Always + + + Always diff --git a/src/JT808.DotNetty.CleintBenchmark/Program.cs b/src/JT808.DotNetty.CleintBenchmark/Program.cs index 97eb163..2c46412 100644 --- a/src/JT808.DotNetty.CleintBenchmark/Program.cs +++ b/src/JT808.DotNetty.CleintBenchmark/Program.cs @@ -7,8 +7,10 @@ using System.Threading.Tasks; using JT808.Protocol; using JT808.DotNetty.Client; using JT808.DotNetty.CleintBenchmark.Configs; -using JT808.DotNetty.CleintBenchmark.Services; using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Builder; +using JT808.DotNetty.CleintBenchmark.Services; namespace JT808.DotNetty.CleintBenchmark { @@ -22,6 +24,31 @@ namespace JT808.DotNetty.CleintBenchmark config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.Configure(app => + { + app.UseRouting(); + app.UseCors("Domain"); + app.UseStaticFiles(); + app.UseDefaultFiles("/index.html"); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + }) + .ConfigureServices((hostContext, services) => + { + services.AddControllers(); + services.AddCors(options => + options.AddPolicy("Domain", builder => + builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + .AllowAnyOrigin())); + + }); + }) .ConfigureLogging((context, logging) => { if (Environment.OSVersion.Platform == PlatformID.Unix) diff --git a/src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs b/src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs index 69bcf96..231041c 100644 --- a/src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs +++ b/src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs @@ -71,7 +71,7 @@ namespace JT808.DotNetty.CleintBenchmark.Services } catch (Exception ex) { - logger.LogError(ex, ""); + logger.LogError(ex.Message); } }); Thread.Sleep(clientBenchmarkOptions.Interval); diff --git a/src/JT808.DotNetty.CleintBenchmark/appsettings.json b/src/JT808.DotNetty.CleintBenchmark/appsettings.json index 21a624a..7611940 100644 --- a/src/JT808.DotNetty.CleintBenchmark/appsettings.json +++ b/src/JT808.DotNetty.CleintBenchmark/appsettings.json @@ -3,20 +3,22 @@ "IncludeScopes": false, "Debug": { "LogLevel": { - "Default": "Trace" + "Default": "Error" } }, "Console": { "LogLevel": { - "Default": "Trace" + "Default": "Error" } } }, + "AllowedHosts": "*", + //"urls": "http://*:15004;", "ClientBenchmarkOptions": { "IP": "127.0.0.1", "Port": 808, "DeviceCount": 100, "Interval": 1000, - "DeviceTemplate": 300000 //需要多台机器同时访问,那么可以根据这个避开重复终端号 100000-200000-300000 + "DeviceTemplate": 100000 //需要多台机器同时访问,那么可以根据这个避开重复终端号 100000-200000-300000 } } diff --git a/src/JT808.DotNetty.CleintBenchmark/wwwroot/echarts.min.js b/src/JT808.DotNetty.CleintBenchmark/wwwroot/echarts.min.js new file mode 100644 index 0000000..60cdcce --- /dev/null +++ b/src/JT808.DotNetty.CleintBenchmark/wwwroot/echarts.min.js @@ -0,0 +1,13 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.echarts={})}(this,function(t){"use strict";function e(t){var e={},i={},n=t.match(/Firefox\/([\d.]+)/),r=t.match(/MSIE\s([\d.]+)/)||t.match(/Trident\/.+?rv:(([\d.]+))/),a=t.match(/Edge\/([\d.]+)/),o=/micromessenger/i.test(t);return n&&(i.firefox=!0,i.version=n[1]),r&&(i.ie=!0,i.version=r[1]),a&&(i.edge=!0,i.version=a[1]),o&&(i.weChat=!0),{browser:i,os:e,node:!1,canvasSupported:!!document.createElement("canvas").getContext,svgSupported:"undefined"!=typeof SVGRect,touchEventsSupported:"ontouchstart"in window&&!i.ie&&!i.edge,pointerEventsSupported:"onpointerdown"in window&&(i.edge||i.ie&&i.version>=11),domSupported:"undefined"!=typeof document}}function i(t,e){"createCanvas"===t&&(Tp=null),Ip[t]=e}function n(t){if(null==t||"object"!=typeof t)return t;var e=t,i=yp.call(t);if("[object Array]"===i){if(!E(t)){e=[];for(var r=0,a=t.length;a>r;r++)e[r]=n(t[r])}}else if(mp[i]){if(!E(t)){var o=t.constructor;if(t.constructor.from)e=o.from(t);else{e=new o(t.length);for(var r=0,a=t.length;a>r;r++)e[r]=n(t[r])}}}else if(!vp[i]&&!E(t)&&!C(t)){e={};for(var s in t)t.hasOwnProperty(s)&&(e[s]=n(t[s]))}return e}function r(t,e,i){if(!S(e)||!S(t))return i?n(e):t;for(var a in e)if(e.hasOwnProperty(a)){var o=t[a],s=e[a];!S(s)||!S(o)||x(s)||x(o)||C(s)||C(o)||M(s)||M(o)||E(s)||E(o)?!i&&a in t||(t[a]=n(e[a],!0)):r(o,s,i)}return t}function a(t,e){for(var i=t[0],n=1,a=t.length;a>n;n++)i=r(i,t[n],e);return i}function o(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i]);return t}function s(t,e,i){for(var n in e)e.hasOwnProperty(n)&&(i?null!=e[n]:null==t[n])&&(t[n]=e[n]);return t}function l(){return Tp||(Tp=Cp().getContext("2d")),Tp}function u(t,e){if(t){if(t.indexOf)return t.indexOf(e);for(var i=0,n=t.length;n>i;i++)if(t[i]===e)return i}return-1}function h(t,e){function i(){}var n=t.prototype;i.prototype=e.prototype,t.prototype=new i;for(var r in n)n.hasOwnProperty(r)&&(t.prototype[r]=n[r]);t.prototype.constructor=t,t.superClass=e}function c(t,e,i){t="prototype"in t?t.prototype:t,e="prototype"in e?e.prototype:e,s(t,e,i)}function d(t){return t?"string"==typeof t?!1:"number"==typeof t.length:void 0}function f(t,e,i){if(t&&e)if(t.forEach&&t.forEach===xp)t.forEach(e,i);else if(t.length===+t.length)for(var n=0,r=t.length;r>n;n++)e.call(i,t[n],n,t);else for(var a in t)t.hasOwnProperty(a)&&e.call(i,t[a],a,t)}function p(t,e,i){if(t&&e){if(t.map&&t.map===Sp)return t.map(e,i);for(var n=[],r=0,a=t.length;a>r;r++)n.push(e.call(i,t[r],r,t));return n}}function g(t,e,i,n){if(t&&e){if(t.reduce&&t.reduce===Mp)return t.reduce(e,i,n);for(var r=0,a=t.length;a>r;r++)i=e.call(n,i,t[r],r,t);return i}}function v(t,e,i){if(t&&e){if(t.filter&&t.filter===wp)return t.filter(e,i);for(var n=[],r=0,a=t.length;a>r;r++)e.call(i,t[r],r,t)&&n.push(t[r]);return n}}function m(t,e,i){if(t&&e)for(var n=0,r=t.length;r>n;n++)if(e.call(i,t[n],n,t))return t[n]}function y(t,e){var i=bp.call(arguments,2);return function(){return t.apply(e,i.concat(bp.call(arguments)))}}function _(t){var e=bp.call(arguments,1);return function(){return t.apply(this,e.concat(bp.call(arguments)))}}function x(t){return"[object Array]"===yp.call(t)}function w(t){return"function"==typeof t}function b(t){return"[object String]"===yp.call(t)}function S(t){var e=typeof t;return"function"===e||!!t&&"object"===e}function M(t){return!!vp[yp.call(t)]}function I(t){return!!mp[yp.call(t)]}function C(t){return"object"==typeof t&&"number"==typeof t.nodeType&&"object"==typeof t.ownerDocument}function T(t){return t!==t}function D(){for(var t=0,e=arguments.length;e>t;t++)if(null!=arguments[t])return arguments[t]}function A(t,e){return null!=t?t:e}function k(t,e,i){return null!=t?t:null!=e?e:i}function P(){return Function.call.apply(bp,arguments)}function L(t){if("number"==typeof t)return[t,t,t,t];var e=t.length;return 2===e?[t[0],t[1],t[0],t[1]]:3===e?[t[0],t[1],t[2],t[1]]:t}function O(t,e){if(!t)throw new Error(e)}function z(t){return null==t?null:"function"==typeof t.trim?t.trim():t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}function B(t){t[Dp]=!0}function E(t){return t[Dp]}function R(t){function e(t,e){i?n.set(t,e):n.set(e,t)}var i=x(t);this.data={};var n=this;t instanceof R?t.each(e):t&&f(t,e)}function N(t){return new R(t)}function F(t,e){for(var i=new t.constructor(t.length+e.length),n=0;nd;d++){var p=1<o;o++)for(var s=0;8>s;s++)null==a[s]&&(a[s]=0),a[s]+=((o+s)%2?-1:1)*de(i,7,0===o?1:0,1<a;a++){var o=document.createElement("div"),s=o.style,l=a%2,u=(a>>1)%2;s.cssText=["position:absolute","visibility: hidden","padding: 0","margin: 0","border-width: 0","width:0","height:0",n[l]+":0",r[u]+":0",n[1-l]+":auto",r[1-u]+":auto",""].join("!important;"),t.appendChild(o),i.push(o)}return i}function me(t,e){for(var i=e.transformer,n=e.srcCoords,r=!0,a=[],o=[],s=0;4>s;s++){var l=t[s].getBoundingClientRect(),u=2*s,h=l.left,c=l.top;a.push(h,c),r&=n&&h===n[u]&&c===n[u+1],o.push(t[s].offsetLeft,t[s].offsetTop)}return r?i:(e.srcCoords=a,e.transformer=fe(a,o))}function ye(t,e,i){if(e=e||window.event,null!=e.zrX)return e;var n=e.type,r=n&&n.indexOf("touch")>=0;if(r){var a="touchend"!==n?e.targetTouches[0]:e.changedTouches[0];a&&pe(t,a,e,i)}else pe(t,e,e,i),e.zrDelta=e.wheelDelta?e.wheelDelta/120:-(e.detail||0)/3;var o=e.button;return null==e.which&&void 0!==o&&Gp.test(e.type)&&(e.which=1&o?1:2&o?3:4&o?2:0),e}function _e(t,e,i){Fp?t.addEventListener(e,i):t.attachEvent("on"+e,i)}function xe(t,e,i){Fp?t.removeEventListener(e,i):t.detachEvent("on"+e,i)}function we(t){var e=t[1][0]-t[0][0],i=t[1][1]-t[0][1];return Math.sqrt(e*e+i*i)}function be(t){return[(t[0][0]+t[1][0])/2,(t[0][1]+t[1][1])/2]}function Se(t,e,i){return{type:t,event:i,target:e.target,topTarget:e.topTarget,cancelBubble:!1,offsetX:i.zrX,offsetY:i.zrY,gestureEvent:i.gestureEvent,pinchX:i.pinchX,pinchY:i.pinchY,pinchScale:i.pinchScale,wheelDelta:i.zrDelta,zrByTouch:i.zrByTouch,which:i.which,stop:Me}}function Me(){Wp(this.event)}function Ie(){}function Ce(t,e,i){if(t[t.rectHover?"rectContain":"contain"](e,i)){for(var n,r=t;r;){if(r.clipPath&&!r.clipPath.contain(e,i))return!1;r.silent&&(n=!0),r=r.parent}return n?Yp:!0}return!1}function Te(){var t=new Zp(6);return De(t),t}function De(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function Ae(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function ke(t,e,i){var n=e[0]*i[0]+e[2]*i[1],r=e[1]*i[0]+e[3]*i[1],a=e[0]*i[2]+e[2]*i[3],o=e[1]*i[2]+e[3]*i[3],s=e[0]*i[4]+e[2]*i[5]+e[4],l=e[1]*i[4]+e[3]*i[5]+e[5];return t[0]=n,t[1]=r,t[2]=a,t[3]=o,t[4]=s,t[5]=l,t}function Pe(t,e,i){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4]+i[0],t[5]=e[5]+i[1],t}function Le(t,e,i){var n=e[0],r=e[2],a=e[4],o=e[1],s=e[3],l=e[5],u=Math.sin(i),h=Math.cos(i);return t[0]=n*h+o*u,t[1]=-n*u+o*h,t[2]=r*h+s*u,t[3]=-r*u+h*s,t[4]=h*a+u*l,t[5]=h*l-u*a,t}function Oe(t,e,i){var n=i[0],r=i[1];return t[0]=e[0]*n,t[1]=e[1]*r,t[2]=e[2]*n,t[3]=e[3]*r,t[4]=e[4]*n,t[5]=e[5]*r,t}function ze(t,e){var i=e[0],n=e[2],r=e[4],a=e[1],o=e[3],s=e[5],l=i*o-a*n;return l?(l=1/l,t[0]=o*l,t[1]=-a*l,t[2]=-n*l,t[3]=i*l,t[4]=(n*s-o*r)*l,t[5]=(a*r-i*s)*l,t):null}function Be(t){var e=Te();return Ae(e,t),e}function Ee(t){return t>Qp||-Qp>t}function Re(t){this._target=t.target,this._life=t.life||1e3,this._delay=t.delay||0,this._initialized=!1,this.loop=null==t.loop?!1:t.loop,this.gap=t.gap||0,this.easing=t.easing||"Linear",this.onframe=t.onframe,this.ondestroy=t.ondestroy,this.onrestart=t.onrestart,this._pausedTime=0,this._paused=!1}function Ne(t){return t=Math.round(t),0>t?0:t>255?255:t}function Fe(t){return t=Math.round(t),0>t?0:t>360?360:t}function Ge(t){return 0>t?0:t>1?1:t}function Ve(t){return Ne(t.length&&"%"===t.charAt(t.length-1)?parseFloat(t)/100*255:parseInt(t,10))}function He(t){return Ge(t.length&&"%"===t.charAt(t.length-1)?parseFloat(t)/100:parseFloat(t))}function We(t,e,i){return 0>i?i+=1:i>1&&(i-=1),1>6*i?t+(e-t)*i*6:1>2*i?e:2>3*i?t+(e-t)*(2/3-i)*6:t}function Ue(t,e,i){return t+(e-t)*i}function Xe(t,e,i,n,r){return t[0]=e,t[1]=i,t[2]=n,t[3]=r,t}function Ye(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}function je(t,e){dg&&Ye(dg,e),dg=cg.put(t,dg||e.slice())}function qe(t,e){if(t){e=e||[];var i=cg.get(t);if(i)return Ye(e,i);t+="";var n=t.replace(/ /g,"").toLowerCase();if(n in hg)return Ye(e,hg[n]),je(t,e),e;if("#"!==n.charAt(0)){var r=n.indexOf("("),a=n.indexOf(")");if(-1!==r&&a+1===n.length){var o=n.substr(0,r),s=n.substr(r+1,a-(r+1)).split(","),l=1;switch(o){case"rgba":if(4!==s.length)return void Xe(e,0,0,0,1);l=He(s.pop());case"rgb":return 3!==s.length?void Xe(e,0,0,0,1):(Xe(e,Ve(s[0]),Ve(s[1]),Ve(s[2]),l),je(t,e),e);case"hsla":return 4!==s.length?void Xe(e,0,0,0,1):(s[3]=He(s[3]),Ze(s,e),je(t,e),e);case"hsl":return 3!==s.length?void Xe(e,0,0,0,1):(Ze(s,e),je(t,e),e);default:return}}Xe(e,0,0,0,1)}else{if(4===n.length){var u=parseInt(n.substr(1),16);return u>=0&&4095>=u?(Xe(e,(3840&u)>>4|(3840&u)>>8,240&u|(240&u)>>4,15&u|(15&u)<<4,1),je(t,e),e):void Xe(e,0,0,0,1)}if(7===n.length){var u=parseInt(n.substr(1),16);return u>=0&&16777215>=u?(Xe(e,(16711680&u)>>16,(65280&u)>>8,255&u,1),je(t,e),e):void Xe(e,0,0,0,1)}}}}function Ze(t,e){var i=(parseFloat(t[0])%360+360)%360/360,n=He(t[1]),r=He(t[2]),a=.5>=r?r*(n+1):r+n-r*n,o=2*r-a;return e=e||[],Xe(e,Ne(255*We(o,a,i+1/3)),Ne(255*We(o,a,i)),Ne(255*We(o,a,i-1/3)),1),4===t.length&&(e[3]=t[3]),e}function Ke(t){if(t){var e,i,n=t[0]/255,r=t[1]/255,a=t[2]/255,o=Math.min(n,r,a),s=Math.max(n,r,a),l=s-o,u=(s+o)/2;if(0===l)e=0,i=0;else{i=.5>u?l/(s+o):l/(2-s-o);var h=((s-n)/6+l/2)/l,c=((s-r)/6+l/2)/l,d=((s-a)/6+l/2)/l;n===s?e=d-c:r===s?e=1/3+h-d:a===s&&(e=2/3+c-h),0>e&&(e+=1),e>1&&(e-=1)}var f=[360*e,i,u];return null!=t[3]&&f.push(t[3]),f}}function $e(t,e){var i=qe(t);if(i){for(var n=0;3>n;n++)i[n]=0>e?i[n]*(1-e)|0:(255-i[n])*e+i[n]|0,i[n]>255?i[n]=255:t[n]<0&&(i[n]=0);return ni(i,4===i.length?"rgba":"rgb")}}function Qe(t){var e=qe(t);return e?((1<<24)+(e[0]<<16)+(e[1]<<8)+ +e[2]).toString(16).slice(1):void 0}function Je(t,e,i){if(e&&e.length&&t>=0&&1>=t){i=i||[];var n=t*(e.length-1),r=Math.floor(n),a=Math.ceil(n),o=e[r],s=e[a],l=n-r;return i[0]=Ne(Ue(o[0],s[0],l)),i[1]=Ne(Ue(o[1],s[1],l)),i[2]=Ne(Ue(o[2],s[2],l)),i[3]=Ge(Ue(o[3],s[3],l)),i}}function ti(t,e,i){if(e&&e.length&&t>=0&&1>=t){var n=t*(e.length-1),r=Math.floor(n),a=Math.ceil(n),o=qe(e[r]),s=qe(e[a]),l=n-r,u=ni([Ne(Ue(o[0],s[0],l)),Ne(Ue(o[1],s[1],l)),Ne(Ue(o[2],s[2],l)),Ge(Ue(o[3],s[3],l))],"rgba");return i?{color:u,leftIndex:r,rightIndex:a,value:n}:u}}function ei(t,e,i,n){return t=qe(t),t?(t=Ke(t),null!=e&&(t[0]=Fe(e)),null!=i&&(t[1]=He(i)),null!=n&&(t[2]=He(n)),ni(Ze(t),"rgba")):void 0}function ii(t,e){return t=qe(t),t&&null!=e?(t[3]=Ge(e),ni(t,"rgba")):void 0}function ni(t,e){if(t&&t.length){var i=t[0]+","+t[1]+","+t[2];return("rgba"===e||"hsva"===e||"hsla"===e)&&(i+=","+t[3]),e+"("+i+")"}}function ri(t,e){return t[e]}function ai(t,e,i){t[e]=i}function oi(t,e,i){return(e-t)*i+t}function si(t,e,i){return i>.5?e:t}function li(t,e,i,n,r){var a=t.length;if(1===r)for(var o=0;a>o;o++)n[o]=oi(t[o],e[o],i);else for(var s=a&&t[0].length,o=0;a>o;o++)for(var l=0;s>l;l++)n[o][l]=oi(t[o][l],e[o][l],i)}function ui(t,e,i){var n=t.length,r=e.length;if(n!==r){var a=n>r;if(a)t.length=r;else for(var o=n;r>o;o++)t.push(1===i?e[o]:vg.call(e[o]))}for(var s=t[0]&&t[0].length,o=0;ol;l++)isNaN(t[o][l])&&(t[o][l]=e[o][l])}function hi(t,e,i){if(t===e)return!0;var n=t.length;if(n!==e.length)return!1;if(1===i){for(var r=0;n>r;r++)if(t[r]!==e[r])return!1}else for(var a=t[0].length,r=0;n>r;r++)for(var o=0;a>o;o++)if(t[r][o]!==e[r][o])return!1;return!0}function ci(t,e,i,n,r,a,o,s,l){var u=t.length;if(1===l)for(var h=0;u>h;h++)s[h]=di(t[h],e[h],i[h],n[h],r,a,o);else for(var c=t[0].length,h=0;u>h;h++)for(var d=0;c>d;d++)s[h][d]=di(t[h][d],e[h][d],i[h][d],n[h][d],r,a,o)}function di(t,e,i,n,r,a,o){var s=.5*(i-t),l=.5*(n-e);return(2*(e-i)+s+l)*o+(-3*(e-i)-2*s-l)*a+s*r+e}function fi(t){if(d(t)){var e=t.length;if(d(t[0])){for(var i=[],n=0;e>n;n++)i.push(vg.call(t[n]));return i}return vg.call(t)}return t}function pi(t){return t[0]=Math.floor(t[0]),t[1]=Math.floor(t[1]),t[2]=Math.floor(t[2]),"rgba("+t.join(",")+")"}function gi(t){var e=t[t.length-1].value;return d(e&&e[0])?2:1}function vi(t,e,i,n,r,a){var o=t._getter,s=t._setter,l="spline"===e,u=n.length;if(u){var h,c=n[0].value,f=d(c),p=!1,g=!1,v=f?gi(n):0;n.sort(function(t,e){return t.time-e.time}),h=n[u-1].time;for(var m=[],y=[],_=n[0].value,x=!0,w=0;u>w;w++){m.push(n[w].time/h);var b=n[w].value;if(f&&hi(b,_,v)||!f&&b===_||(x=!1),_=b,"string"==typeof b){var S=qe(b);S?(b=S,p=!0):g=!0}y.push(b)}if(a||!x){for(var M=y[u-1],w=0;u-1>w;w++)f?ui(y[w],M,v):!isNaN(y[w])||isNaN(M)||g||p||(y[w]=M);f&&ui(o(t._target,r),M,v);var I,C,T,D,A,k,P=0,L=0;if(p)var O=[0,0,0,0];var z=function(t,e){var i;if(0>e)i=0;else if(L>e){for(I=Math.min(P+1,u-1),i=I;i>=0&&!(m[i]<=e);i--);i=Math.min(i,u-2)}else{for(i=P;u>i&&!(m[i]>e);i++);i=Math.min(i-1,u-2)}P=i,L=e;var n=m[i+1]-m[i];if(0!==n)if(C=(e-m[i])/n,l)if(D=y[i],T=y[0===i?i:i-1],A=y[i>u-2?u-1:i+1],k=y[i>u-3?u-1:i+2],f)ci(T,D,A,k,C,C*C,C*C*C,o(t,r),v);else{var a;if(p)a=ci(T,D,A,k,C,C*C,C*C*C,O,1),a=pi(O);else{if(g)return si(D,A,C);a=di(T,D,A,k,C,C*C,C*C*C)}s(t,r,a)}else if(f)li(y[i],y[i+1],C,o(t,r),v);else{var a;if(p)li(y[i],y[i+1],C,O,1),a=pi(O);else{if(g)return si(y[i],y[i+1],C);a=oi(y[i],y[i+1],C)}s(t,r,a)}},B=new Re({target:t._target,life:h,loop:t._loop,delay:t._delay,onframe:z,ondestroy:i});return e&&"spline"!==e&&(B.easing=e),B}}}function mi(t,e,i,n,r,a,o,s){function l(){h--,h||a&&a()}b(n)?(a=r,r=n,n=0):w(r)?(a=r,r="linear",n=0):w(n)?(a=n,n=0):w(i)?(a=i,i=500):i||(i=500),t.stopAnimation(),yi(t,"",t,e,i,n,s);var u=t.animators.slice(),h=u.length;h||a&&a();for(var c=0;c0&&t.animate(e,!1).when(null==r?500:r,s).delay(a||0)}function _i(t,e,i,n){if(e){var r={};r[e]={},r[e][i]=n,t.attr(r)}else t.attr(i,n)}function xi(t,e,i,n){0>i&&(t+=i,i=-i),0>n&&(e+=n,n=-n),this.x=t,this.y=e,this.width=i,this.height=n}function wi(t){for(var e=0;t>=Ag;)e|=1&t,t>>=1;return t+e}function bi(t,e,i,n){var r=e+1;if(r===i)return 1;if(n(t[r++],t[e])<0){for(;i>r&&n(t[r],t[r-1])<0;)r++;Si(t,e,r)}else for(;i>r&&n(t[r],t[r-1])>=0;)r++;return r-e}function Si(t,e,i){for(i--;i>e;){var n=t[e];t[e++]=t[i],t[i--]=n}}function Mi(t,e,i,n,r){for(n===e&&n++;i>n;n++){for(var a,o=t[n],s=e,l=n;l>s;)a=s+l>>>1,r(o,t[a])<0?l=a:s=a+1;var u=n-s;switch(u){case 3:t[s+3]=t[s+2];case 2:t[s+2]=t[s+1];case 1:t[s+1]=t[s];break;default:for(;u>0;)t[s+u]=t[s+u-1],u--}t[s]=o}}function Ii(t,e,i,n,r,a){var o=0,s=0,l=1;if(a(t,e[i+r])>0){for(s=n-r;s>l&&a(t,e[i+r+l])>0;)o=l,l=(l<<1)+1,0>=l&&(l=s);l>s&&(l=s),o+=r,l+=r}else{for(s=r+1;s>l&&a(t,e[i+r-l])<=0;)o=l,l=(l<<1)+1,0>=l&&(l=s);l>s&&(l=s);var u=o;o=r-l,l=r-u}for(o++;l>o;){var h=o+(l-o>>>1);a(t,e[i+h])>0?o=h+1:l=h}return l}function Ci(t,e,i,n,r,a){var o=0,s=0,l=1;if(a(t,e[i+r])<0){for(s=r+1;s>l&&a(t,e[i+r-l])<0;)o=l,l=(l<<1)+1,0>=l&&(l=s);l>s&&(l=s);var u=o;o=r-l,l=r-u}else{for(s=n-r;s>l&&a(t,e[i+r+l])>=0;)o=l,l=(l<<1)+1,0>=l&&(l=s);l>s&&(l=s),o+=r,l+=r}for(o++;l>o;){var h=o+(l-o>>>1);a(t,e[i+h])<0?l=h:o=h+1}return l}function Ti(t,e){function i(t,e){l[c]=t,u[c]=e,c+=1}function n(){for(;c>1;){var t=c-2;if(t>=1&&u[t-1]<=u[t]+u[t+1]||t>=2&&u[t-2]<=u[t]+u[t-1])u[t-1]u[t+1])break;a(t)}}function r(){for(;c>1;){var t=c-2;t>0&&u[t-1]=r?o(n,r,a,h):s(n,r,a,h)))}function o(i,n,r,a){var o=0;for(o=0;n>o;o++)d[o]=t[i+o];var s=0,l=r,u=i;if(t[u++]=t[l++],0!==--a){if(1===n){for(o=0;a>o;o++)t[u+o]=t[l+o];return void(t[u+a]=d[s])}for(var c,f,p,g=h;;){c=0,f=0,p=!1;do if(e(t[l],d[s])<0){if(t[u++]=t[l++],f++,c=0,0===--a){p=!0;break}}else if(t[u++]=d[s++],c++,f=0,1===--n){p=!0;break}while(g>(c|f));if(p)break;do{if(c=Ci(t[l],d,s,n,0,e),0!==c){for(o=0;c>o;o++)t[u+o]=d[s+o];if(u+=c,s+=c,n-=c,1>=n){p=!0;break}}if(t[u++]=t[l++],0===--a){p=!0;break}if(f=Ii(d[s],t,l,a,0,e),0!==f){for(o=0;f>o;o++)t[u+o]=t[l+o];if(u+=f,l+=f,a-=f,0===a){p=!0;break}}if(t[u++]=d[s++],1===--n){p=!0;break}g--}while(c>=kg||f>=kg);if(p)break;0>g&&(g=0),g+=2}if(h=g,1>h&&(h=1),1===n){for(o=0;a>o;o++)t[u+o]=t[l+o];t[u+a]=d[s]}else{if(0===n)throw new Error;for(o=0;n>o;o++)t[u+o]=d[s+o]}}else for(o=0;n>o;o++)t[u+o]=d[s+o]}function s(i,n,r,a){var o=0;for(o=0;a>o;o++)d[o]=t[r+o];var s=i+n-1,l=a-1,u=r+a-1,c=0,f=0;if(t[u--]=t[s--],0!==--n){if(1===a){for(u-=n,s-=n,f=u+1,c=s+1,o=n-1;o>=0;o--)t[f+o]=t[c+o];return void(t[u]=d[l])}for(var p=h;;){var g=0,v=0,m=!1;do if(e(d[l],t[s])<0){if(t[u--]=t[s--],g++,v=0,0===--n){m=!0;break}}else if(t[u--]=d[l--],v++,g=0,1===--a){m=!0;break}while(p>(g|v));if(m)break;do{if(g=n-Ci(d[l],t,i,n,n-1,e),0!==g){for(u-=g,s-=g,n-=g,f=u+1,c=s+1,o=g-1;o>=0;o--)t[f+o]=t[c+o];if(0===n){m=!0;break}}if(t[u--]=d[l--],1===--a){m=!0;break}if(v=a-Ii(t[s],d,0,a,a-1,e),0!==v){for(u-=v,l-=v,a-=v,f=u+1,c=l+1,o=0;v>o;o++)t[f+o]=d[c+o];if(1>=a){m=!0;break}}if(t[u--]=t[s--],0===--n){m=!0;break}p--}while(g>=kg||v>=kg);if(m)break;0>p&&(p=0),p+=2}if(h=p,1>h&&(h=1),1===a){for(u-=n,s-=n,f=u+1,c=s+1,o=n-1;o>=0;o--)t[f+o]=t[c+o];t[u]=d[l]}else{if(0===a)throw new Error;for(c=u-(a-1),o=0;a>o;o++)t[c+o]=d[o]}}else for(c=u-(a-1),o=0;a>o;o++)t[c+o]=d[o]}var l,u,h=kg,c=0,d=[];l=[],u=[],this.mergeRuns=n,this.forceMergeRuns=r,this.pushRun=i}function Di(t,e,i,n){i||(i=0),n||(n=t.length);var r=n-i;if(!(2>r)){var a=0;if(Ag>r)return a=bi(t,i,n,e),void Mi(t,i,n,i+a,e);var o=new Ti(t,e),s=wi(r);do{if(a=bi(t,i,n,e),s>a){var l=r;l>s&&(l=s),Mi(t,i,i+l,i+a,e),a=l}o.pushRun(i,a),o.mergeRuns(),r-=a,i+=a}while(0!==r);o.forceMergeRuns()}}function Ai(t,e){return t.zlevel===e.zlevel?t.z===e.z?t.z2-e.z2:t.z-e.z:t.zlevel-e.zlevel}function ki(t,e,i){var n=null==e.x?0:e.x,r=null==e.x2?1:e.x2,a=null==e.y?0:e.y,o=null==e.y2?0:e.y2;e.global||(n=n*i.width+i.x,r=r*i.width+i.x,a=a*i.height+i.y,o=o*i.height+i.y),n=isNaN(n)?0:n,r=isNaN(r)?1:r,a=isNaN(a)?0:a,o=isNaN(o)?0:o;var s=t.createLinearGradient(n,a,r,o);return s}function Pi(t,e,i){var n=i.width,r=i.height,a=Math.min(n,r),o=null==e.x?.5:e.x,s=null==e.y?.5:e.y,l=null==e.r?.5:e.r;e.global||(o=o*n+i.x,s=s*r+i.y,l*=a);var u=t.createRadialGradient(o,s,0,o,s,l);return u}function Li(){return!1}function Oi(t,e,i){var n=Cp(),r=e.getWidth(),a=e.getHeight(),o=n.style;return o&&(o.position="absolute",o.left=0,o.top=0,o.width=r+"px",o.height=a+"px",n.setAttribute("data-zr-dom-id",t)),n.width=r*i,n.height=a*i,n}function zi(t){if("string"==typeof t){var e=Ug.get(t);return e&&e.image}return t}function Bi(t,e,i,n,r){if(t){if("string"==typeof t){if(e&&e.__zrImageSrc===t||!i)return e;var a=Ug.get(t),o={hostEl:i,cb:n,cbPayload:r};return a?(e=a.image,!Ri(e)&&a.pending.push(o)):(e=new Image,e.onload=e.onerror=Ei,Ug.put(t,e.__cachedImgObj={image:e,pending:[o]}),e.src=e.__zrImageSrc=t),e}return t}return e}function Ei(){var t=this.__cachedImgObj;this.onload=this.onerror=this.__cachedImgObj=null;for(var e=0;ea;a++)r=Math.max(Ki(n[a],e).width,r);return Yg>jg&&(Yg=0,Xg={}),Yg++,Xg[i]=r,r}function Fi(t,e,i,n,r,a,o,s){return o?Vi(t,e,i,n,r,a,o,s):Gi(t,e,i,n,r,a,s)}function Gi(t,e,i,n,r,a,o){var s=$i(t,e,r,a,o),l=Ni(t,e);r&&(l+=r[1]+r[3]);var u=s.outerHeight,h=Hi(0,l,i),c=Wi(0,u,n),d=new xi(h,c,l,u);return d.lineHeight=s.lineHeight,d}function Vi(t,e,i,n,r,a,o,s){var l=Qi(t,{rich:o,truncate:s,font:e,textAlign:i,textPadding:r,textLineHeight:a}),u=l.outerWidth,h=l.outerHeight,c=Hi(0,u,i),d=Wi(0,h,n);return new xi(c,d,u,h)}function Hi(t,e,i){return"right"===i?t-=e:"center"===i&&(t-=e/2),t}function Wi(t,e,i){return"middle"===i?t-=e/2:"bottom"===i&&(t-=e),t}function Ui(t,e,i){var n=e.textPosition,r=e.textDistance,a=i.x,o=i.y;r=r||0;var s=i.height,l=i.width,u=s/2,h="left",c="top";switch(n){case"left":a-=r,o+=u,h="right",c="middle";break;case"right":a+=r+l,o+=u,c="middle";break;case"top":a+=l/2,o-=r,h="center",c="bottom";break;case"bottom":a+=l/2,o+=s+r,h="center";break;case"inside":a+=l/2,o+=u,h="center",c="middle";break;case"insideLeft":a+=r,o+=u,c="middle";break;case"insideRight":a+=l-r,o+=u,h="right",c="middle";break;case"insideTop":a+=l/2,o+=r,h="center";break;case"insideBottom":a+=l/2,o+=s-r,h="center",c="bottom";break;case"insideTopLeft":a+=r,o+=r;break;case"insideTopRight":a+=l-r,o+=r,h="right";break;case"insideBottomLeft":a+=r,o+=s-r,c="bottom";break;case"insideBottomRight":a+=l-r,o+=s-r,h="right",c="bottom"}return t=t||{},t.x=a,t.y=o,t.textAlign=h,t.textVerticalAlign=c,t}function Xi(t,e,i,n,r){if(!e)return"";var a=(t+"").split("\n");r=Yi(e,i,n,r);for(var o=0,s=a.length;s>o;o++)a[o]=ji(a[o],r);return a.join("\n")}function Yi(t,e,i,n){n=o({},n),n.font=e;var i=A(i,"...");n.maxIterations=A(n.maxIterations,2);var r=n.minChar=A(n.minChar,0);n.cnCharWidth=Ni("国",e);var a=n.ascCharWidth=Ni("a",e);n.placeholder=A(n.placeholder,"");for(var s=t=Math.max(0,t-1),l=0;r>l&&s>=a;l++)s-=a;var u=Ni(i,e);return u>s&&(i="",u=0),s=t-u,n.ellipsis=i,n.ellipsisWidth=u,n.contentWidth=s,n.containerWidth=t,n}function ji(t,e){var i=e.containerWidth,n=e.font,r=e.contentWidth;if(!i)return"";var a=Ni(t,n);if(i>=a)return t;for(var o=0;;o++){if(r>=a||o>=e.maxIterations){t+=e.ellipsis;break}var s=0===o?qi(t,r,e.ascCharWidth,e.cnCharWidth):a>0?Math.floor(t.length*r/a):0;t=t.substr(0,s),a=Ni(t,n)}return""===t&&(t=e.placeholder),t}function qi(t,e,i,n){for(var r=0,a=0,o=t.length;o>a&&e>r;a++){var s=t.charCodeAt(a);r+=s>=0&&127>=s?i:n}return a}function Zi(t){return Ni("国",t)}function Ki(t,e){return Kg.measureText(t,e)}function $i(t,e,i,n,r){null!=t&&(t+="");var a=A(n,Zi(e)),o=t?t.split("\n"):[],s=o.length*a,l=s,u=!0;if(i&&(l+=i[0]+i[2]),t&&r){u=!1;var h=r.outerHeight,c=r.outerWidth;if(null!=h&&l>h)t="",o=[];else if(null!=c)for(var d=Yi(c-(i?i[1]+i[3]:0),e,r.ellipsis,{minChar:r.minChar,placeholder:r.placeholder}),f=0,p=o.length;p>f;f++)o[f]=ji(o[f],d)}return{lines:o,height:s,outerHeight:l,lineHeight:a,canCacheByTextString:u}}function Qi(t,e){var i={lines:[],width:0,height:0};if(null!=t&&(t+=""),!t)return i;for(var n,r=qg.lastIndex=0;null!=(n=qg.exec(t));){var a=n.index;a>r&&Ji(i,t.substring(r,a)),Ji(i,n[2],n[1]),r=qg.lastIndex}rf)return{lines:[],width:0,height:0};_.textWidth=Ni(_.text,b);var M=x.textWidth,I=null==M||"auto"===M;if("string"==typeof M&&"%"===M.charAt(M.length-1))_.percentWidth=M,u.push(_),M=0;else{if(I){M=_.textWidth;var C=x.textBackgroundColor,T=C&&C.image;T&&(T=zi(T),Ri(T)&&(M=Math.max(M,T.width*S/T.height)))}var D=w?w[1]+w[3]:0;M+=D;var P=null!=d?d-m:null;null!=P&&M>P&&(!I||D>P?(_.text="",_.textWidth=M=0):(_.text=Xi(_.text,P-D,b,c.ellipsis,{minChar:c.minChar}),_.textWidth=Ni(_.text,b),M=_.textWidth+D))}m+=_.width=M,x&&(v=Math.max(v,_.lineHeight))}g.width=m,g.lineHeight=v,s+=v,l=Math.max(l,m)}i.outerWidth=i.width=A(e.textWidth,l),i.outerHeight=i.height=A(e.textHeight,s),h&&(i.outerWidth+=h[1]+h[3],i.outerHeight+=h[0]+h[2]);for(var p=0;pl&&(o+=l,l=-l),0>u&&(s+=u,u=-u),"number"==typeof h?i=n=r=a=h:h instanceof Array?1===h.length?i=n=r=a=h[0]:2===h.length?(i=r=h[0],n=a=h[1]):3===h.length?(i=h[0],n=a=h[1],r=h[2]):(i=h[0],n=h[1],r=h[2],a=h[3]):i=n=r=a=0;var c;i+n>l&&(c=i+n,i*=l/c,n*=l/c),r+a>l&&(c=r+a,r*=l/c,a*=l/c),n+r>u&&(c=n+r,n*=u/c,r*=u/c),i+a>u&&(c=i+a,i*=u/c,a*=u/c),t.moveTo(o+i,s),t.lineTo(o+l-n,s),0!==n&&t.arc(o+l-n,s+n,n,-Math.PI/2,0),t.lineTo(o+l,s+u-r),0!==r&&t.arc(o+l-r,s+u-r,r,0,Math.PI/2),t.lineTo(o+a,s+u),0!==a&&t.arc(o+a,s+u-a,a,Math.PI/2,Math.PI),t.lineTo(o,s+i),0!==i&&t.arc(o+i,s+i,i,Math.PI,1.5*Math.PI)}function nn(t){return rn(t),f(t.rich,rn),t}function rn(t){if(t){t.font=tn(t);var e=t.textAlign;"middle"===e&&(e="center"),t.textAlign=null==e||Qg[e]?e:"left";var i=t.textVerticalAlign||t.textBaseline;"center"===i&&(i="middle"),t.textVerticalAlign=null==i||Jg[i]?i:"top";var n=t.textPadding;n&&(t.textPadding=L(t.textPadding))}}function an(t,e,i,n,r,a){n.rich?sn(t,e,i,n,r,a):on(t,e,i,n,r,a)}function on(t,e,i,n,r,a){var o,s=cn(n),l=!1,u=e.__attrCachedBy===zg.PLAIN_TEXT;a!==Bg?(a&&(o=a.style,l=!s&&u&&o),e.__attrCachedBy=s?zg.NONE:zg.PLAIN_TEXT):u&&(e.__attrCachedBy=zg.NONE);var h=n.font||$g;l&&h===(o.font||$g)||(e.font=h);var c=t.__computedFont;t.__styleFont!==h&&(t.__styleFont=h,c=t.__computedFont=e.font);var d=n.textPadding,f=n.textLineHeight,p=t.__textCotentBlock;(!p||t.__dirtyText)&&(p=t.__textCotentBlock=$i(i,c,d,f,n.truncate));var g=p.outerHeight,v=p.lines,m=p.lineHeight,y=pn(iv,t,n,r),_=y.baseX,x=y.baseY,w=y.textAlign||"left",b=y.textVerticalAlign;un(e,n,r,_,x);var S=Wi(x,g,b),M=_,I=S;if(s||d){var C=Ni(i,c),T=C;d&&(T+=d[1]+d[3]);var D=Hi(_,T,w);s&&dn(t,e,n,D,S,T,g),d&&(M=_n(_,w,d),I+=d[0])}e.textAlign=w,e.textBaseline="middle",e.globalAlpha=n.opacity||1;for(var A=0;AC&&(x=b[C],!x.textAlign||"left"===x.textAlign);)hn(t,e,x,n,M,m,T,"left"),I-=x.width,T+=x.width,C++;for(;A>=0&&(x=b[A],"right"===x.textAlign);)hn(t,e,x,n,M,m,D,"right"),I-=x.width,D-=x.width,A--;for(T+=(a-(T-v)-(y-D)-I)/2;A>=C;)x=b[C],hn(t,e,x,n,M,m,T+x.width/2,"center"),T+=x.width,C++;m+=M}}function un(t,e,i,n,r){if(i&&e.textRotation){var a=e.textOrigin;"center"===a?(n=i.width/2+i.x,r=i.height/2+i.y):a&&(n=a[0]+i.x,r=a[1]+i.y),t.translate(n,r),t.rotate(-e.textRotation),t.translate(-n,-r)}}function hn(t,e,i,n,r,a,o,s){var l=n.rich[i.styleName]||{};l.text=i.text;var u=i.textVerticalAlign,h=a+r/2;"top"===u?h=a+i.height/2:"bottom"===u&&(h=a+r-i.height/2),!i.isLineHolder&&cn(l)&&dn(t,e,l,"right"===s?o-i.width:"center"===s?o-i.width/2:o,h-i.height/2,i.width,i.height);var c=i.textPadding;c&&(o=_n(o,s,c),h-=i.height/2-c[2]-i.textHeight/2),gn(e,"shadowBlur",k(l.textShadowBlur,n.textShadowBlur,0)),gn(e,"shadowColor",l.textShadowColor||n.textShadowColor||"transparent"),gn(e,"shadowOffsetX",k(l.textShadowOffsetX,n.textShadowOffsetX,0)),gn(e,"shadowOffsetY",k(l.textShadowOffsetY,n.textShadowOffsetY,0)),gn(e,"textAlign",s),gn(e,"textBaseline","middle"),gn(e,"font",i.font||$g); +var d=vn(l.textStroke||n.textStroke,p),f=mn(l.textFill||n.textFill),p=A(l.textStrokeWidth,n.textStrokeWidth);d&&(gn(e,"lineWidth",p),gn(e,"strokeStyle",d),e.strokeText(i.text,o,h)),f&&(gn(e,"fillStyle",f),e.fillText(i.text,o,h))}function cn(t){return!!(t.textBackgroundColor||t.textBorderWidth&&t.textBorderColor)}function dn(t,e,i,n,r,a,o){var s=i.textBackgroundColor,l=i.textBorderWidth,u=i.textBorderColor,h=b(s);if(gn(e,"shadowBlur",i.textBoxShadowBlur||0),gn(e,"shadowColor",i.textBoxShadowColor||"transparent"),gn(e,"shadowOffsetX",i.textBoxShadowOffsetX||0),gn(e,"shadowOffsetY",i.textBoxShadowOffsetY||0),h||l&&u){e.beginPath();var c=i.textBorderRadius;c?en(e,{x:n,y:r,width:a,height:o,r:c}):e.rect(n,r,a,o),e.closePath()}if(h)if(gn(e,"fillStyle",s),null!=i.fillOpacity){var d=e.globalAlpha;e.globalAlpha=i.fillOpacity*i.opacity,e.fill(),e.globalAlpha=d}else e.fill();else if(S(s)){var f=s.image;f=Bi(f,null,t,fn,s),f&&Ri(f)&&e.drawImage(f,n,r,a,o)}if(l&&u)if(gn(e,"lineWidth",l),gn(e,"strokeStyle",u),null!=i.strokeOpacity){var d=e.globalAlpha;e.globalAlpha=i.strokeOpacity*i.opacity,e.stroke(),e.globalAlpha=d}else e.stroke()}function fn(t,e){e.image=t}function pn(t,e,i,n){var r=i.x||0,a=i.y||0,o=i.textAlign,s=i.textVerticalAlign;if(n){var l=i.textPosition;if(l instanceof Array)r=n.x+yn(l[0],n.width),a=n.y+yn(l[1],n.height);else{var u=e&&e.calculateTextPosition?e.calculateTextPosition(ev,i,n):Ui(ev,i,n);r=u.x,a=u.y,o=o||u.textAlign,s=s||u.textVerticalAlign}var h=i.textOffset;h&&(r+=h[0],a+=h[1])}return t=t||{},t.baseX=r,t.baseY=a,t.textAlign=o,t.textVerticalAlign=s,t}function gn(t,e,i){return t[e]=Og(t,e,i),t[e]}function vn(t,e){return null==t||0>=e||"transparent"===t||"none"===t?null:t.image||t.colorStops?"#000":t}function mn(t){return null==t||"none"===t?null:t.image||t.colorStops?"#000":t}function yn(t,e){return"string"==typeof t?t.lastIndexOf("%")>=0?parseFloat(t)/100*e:parseFloat(t):t}function _n(t,e,i){return"right"===e?t-i[1]:"center"===e?t+i[3]/2-i[1]/2:t+i[3]}function xn(t,e){return null!=t&&(t||e.textBackgroundColor||e.textBorderWidth&&e.textBorderColor||e.textPadding)}function wn(t){t=t||{},Mg.call(this,t);for(var e in t)t.hasOwnProperty(e)&&"style"!==e&&(this[e]=t[e]);this.style=new Rg(t.style,this),this._rect=null,this.__clipPaths=null}function bn(t){wn.call(this,t)}function Sn(t){return parseInt(t,10)}function Mn(t){return t?t.__builtin__?!0:"function"!=typeof t.resize||"function"!=typeof t.refresh?!1:!0:!1}function In(t,e,i){return uv.copy(t.getBoundingRect()),t.transform&&uv.applyTransform(t.transform),hv.width=e,hv.height=i,!uv.intersect(hv)}function Cn(t,e){if(t===e)return!1;if(!t||!e||t.length!==e.length)return!0;for(var i=0;in;n++){var a=i[n];!t.emphasis[e].hasOwnProperty(a)&&t[e].hasOwnProperty(a)&&(t.emphasis[e][a]=t[e][a])}}}function Vn(t){return!Tv(t)||Dv(t)||t instanceof Date?t:t.value}function Hn(t){return Tv(t)&&!(t instanceof Array)}function Wn(t,e){e=(e||[]).slice();var i=p(t||[],function(t){return{exist:t}});return Cv(e,function(t,n){if(Tv(t)){for(var r=0;r=i.length&&i.push({option:t})}}),i}function Un(t){var e=N();Cv(t,function(t){var i=t.exist;i&&e.set(i.id,t)}),Cv(t,function(t){var i=t.option;O(!i||null==i.id||!e.get(i.id)||e.get(i.id)===t,"id duplicates: "+(i&&i.id)),i&&null!=i.id&&e.set(i.id,t),!t.keyInfo&&(t.keyInfo={})}),Cv(t,function(t,i){var n=t.exist,r=t.option,a=t.keyInfo;if(Tv(r)){if(a.name=null!=r.name?r.name+"":n?n.name:Av+i,n)a.id=n.id;else if(null!=r.id)a.id=r.id+"";else{var o=0;do a.id="\x00"+a.name+"\x00"+o++;while(e.get(a.id))}e.set(a.id,t)}})}function Xn(t){var e=t.name;return!(!e||!e.indexOf(Av))}function Yn(t){return Tv(t)&&t.id&&0===(t.id+"").indexOf("\x00_ec_\x00")}function jn(t,e){return null!=e.dataIndexInside?e.dataIndexInside:null!=e.dataIndex?x(e.dataIndex)?p(e.dataIndex,function(e){return t.indexOfRawIndex(e)}):t.indexOfRawIndex(e.dataIndex):null!=e.name?x(e.name)?p(e.name,function(e){return t.indexOfName(e)}):t.indexOfName(e.name):void 0}function qn(){var t="__\x00ec_inner_"+Pv++ +"_"+Math.random().toFixed(5);return function(e){return e[t]||(e[t]={})}}function Zn(t,e,i){if(b(e)){var n={};n[e+"Index"]=0,e=n}var r=i&&i.defaultMainType;!r||Kn(e,r+"Index")||Kn(e,r+"Id")||Kn(e,r+"Name")||(e[r+"Index"]=0);var a={};return Cv(e,function(n,r){var n=e[r];if("dataIndex"===r||"dataIndexInside"===r)return void(a[r]=n);var o=r.match(/^(\w+)(Index|Id|Name)$/)||[],s=o[1],l=(o[2]||"").toLowerCase();if(!(!s||!l||null==n||"index"===l&&"none"===n||i&&i.includeMainTypes&&u(i.includeMainTypes,s)<0)){var h={mainType:s};("index"!==l||"all"!==n)&&(h[l]=n);var c=t.queryComponents(h);a[s+"Models"]=c,a[s+"Model"]=c[0]}}),a}function Kn(t,e){return t&&t.hasOwnProperty(e)}function $n(t,e,i){t.setAttribute?t.setAttribute(e,i):t[e]=i}function Qn(t,e){return t.getAttribute?t.getAttribute(e):t[e]}function Jn(t){return"auto"===t?gp.domSupported?"html":"richText":t||"html"}function tr(t){var e={main:"",sub:""};return t&&(t=t.split(Lv),e.main=t[0]||"",e.sub=t[1]||""),e}function er(t){O(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(t),'componentType "'+t+'" illegal')}function ir(t){t.$constructor=t,t.extend=function(t){var e=this,i=function(){t.$constructor?t.$constructor.apply(this,arguments):e.apply(this,arguments)};return o(i.prototype,t),i.extend=this.extend,i.superCall=rr,i.superApply=ar,h(i,this),i.superClass=e,i}}function nr(t){var e=["__\x00is_clz",zv++,Math.random().toFixed(3)].join("_");t.prototype[e]=!0,t.isInstance=function(t){return!(!t||!t[e])}}function rr(t,e){var i=P(arguments,2);return this.superClass.prototype[e].apply(t,i)}function ar(t,e,i){return this.superClass.prototype[e].apply(t,i)}function or(t,e){function i(t){var e=n[t.main];return e&&e[Ov]||(e=n[t.main]={},e[Ov]=!0),e}e=e||{};var n={};if(t.registerClass=function(t,e){if(e)if(er(e),e=tr(e),e.sub){if(e.sub!==Ov){var r=i(e);r[e.sub]=t}}else n[e.main]=t;return t},t.getClass=function(t,e,i){var r=n[t];if(r&&r[Ov]&&(r=e?r[e]:null),i&&!r)throw new Error(e?"Component "+t+"."+(e||"")+" not exists. Load it first.":t+".type should be specified.");return r},t.getClassesByMainType=function(t){t=tr(t);var e=[],i=n[t.main];return i&&i[Ov]?f(i,function(t,i){i!==Ov&&e.push(t)}):e.push(i),e},t.hasClass=function(t){return t=tr(t),!!n[t.main]},t.getAllClassMainTypes=function(){var t=[];return f(n,function(e,i){t.push(i)}),t},t.hasSubTypes=function(t){t=tr(t);var e=n[t.main];return e&&e[Ov]},t.parseClassType=tr,e.registerWhenExtend){var r=t.extend;r&&(t.extend=function(e){var i=r.call(this,e);return t.registerClass(i,e.type)})}return t}function sr(t){return t>-Hv&&Hv>t}function lr(t){return t>Hv||-Hv>t}function ur(t,e,i,n,r){var a=1-r;return a*a*(a*t+3*r*e)+r*r*(r*n+3*a*i)}function hr(t,e,i,n,r){var a=1-r;return 3*(((e-t)*a+2*(i-e)*r)*a+(n-i)*r*r)}function cr(t,e,i,n,r,a){var o=n+3*(e-i)-t,s=3*(i-2*e+t),l=3*(e-t),u=t-r,h=s*s-3*o*l,c=s*l-9*o*u,d=l*l-3*s*u,f=0;if(sr(h)&&sr(c))if(sr(s))a[0]=0;else{var p=-l/s;p>=0&&1>=p&&(a[f++]=p)}else{var g=c*c-4*h*d;if(sr(g)){var v=c/h,p=-s/o+v,m=-v/2;p>=0&&1>=p&&(a[f++]=p),m>=0&&1>=m&&(a[f++]=m)}else if(g>0){var y=Vv(g),_=h*s+1.5*o*(-c+y),x=h*s+1.5*o*(-c-y);_=0>_?-Gv(-_,Xv):Gv(_,Xv),x=0>x?-Gv(-x,Xv):Gv(x,Xv);var p=(-s-(_+x))/(3*o);p>=0&&1>=p&&(a[f++]=p)}else{var w=(2*h*s-3*o*c)/(2*Vv(h*h*h)),b=Math.acos(w)/3,S=Vv(h),M=Math.cos(b),p=(-s-2*S*M)/(3*o),m=(-s+S*(M+Uv*Math.sin(b)))/(3*o),I=(-s+S*(M-Uv*Math.sin(b)))/(3*o);p>=0&&1>=p&&(a[f++]=p),m>=0&&1>=m&&(a[f++]=m),I>=0&&1>=I&&(a[f++]=I)}}return f}function dr(t,e,i,n,r){var a=6*i-12*e+6*t,o=9*e+3*n-3*t-9*i,s=3*e-3*t,l=0;if(sr(o)){if(lr(a)){var u=-s/a;u>=0&&1>=u&&(r[l++]=u)}}else{var h=a*a-4*o*s;if(sr(h))r[0]=-a/(2*o);else if(h>0){var c=Vv(h),u=(-a+c)/(2*o),d=(-a-c)/(2*o);u>=0&&1>=u&&(r[l++]=u),d>=0&&1>=d&&(r[l++]=d)}}return l}function fr(t,e,i,n,r,a){var o=(e-t)*r+t,s=(i-e)*r+e,l=(n-i)*r+i,u=(s-o)*r+o,h=(l-s)*r+s,c=(h-u)*r+u;a[0]=t,a[1]=o,a[2]=u,a[3]=c,a[4]=c,a[5]=h,a[6]=l,a[7]=n}function pr(t,e,i,n,r,a,o,s,l,u,h){var c,d,f,p,g,v=.005,m=1/0;Yv[0]=l,Yv[1]=u;for(var y=0;1>y;y+=.05)jv[0]=ur(t,i,r,o,y),jv[1]=ur(e,n,a,s,y),p=zp(Yv,jv),m>p&&(c=y,m=p);m=1/0;for(var _=0;32>_&&!(Wv>v);_++)d=c-v,f=c+v,jv[0]=ur(t,i,r,o,d),jv[1]=ur(e,n,a,s,d),p=zp(jv,Yv),d>=0&&m>p?(c=d,m=p):(qv[0]=ur(t,i,r,o,f),qv[1]=ur(e,n,a,s,f),g=zp(qv,Yv),1>=f&&m>g?(c=f,m=g):v*=.5);return h&&(h[0]=ur(t,i,r,o,c),h[1]=ur(e,n,a,s,c)),Vv(m)}function gr(t,e,i,n){var r=1-n;return r*(r*t+2*n*e)+n*n*i}function vr(t,e,i,n){return 2*((1-n)*(e-t)+n*(i-e))}function mr(t,e,i,n,r){var a=t-2*e+i,o=2*(e-t),s=t-n,l=0;if(sr(a)){if(lr(o)){var u=-s/o;u>=0&&1>=u&&(r[l++]=u)}}else{var h=o*o-4*a*s;if(sr(h)){var u=-o/(2*a);u>=0&&1>=u&&(r[l++]=u)}else if(h>0){var c=Vv(h),u=(-o+c)/(2*a),d=(-o-c)/(2*a);u>=0&&1>=u&&(r[l++]=u),d>=0&&1>=d&&(r[l++]=d)}}return l}function yr(t,e,i){var n=t+i-2*e;return 0===n?.5:(t-e)/n}function _r(t,e,i,n,r){var a=(e-t)*n+t,o=(i-e)*n+e,s=(o-a)*n+a;r[0]=t,r[1]=a,r[2]=s,r[3]=s,r[4]=o,r[5]=i}function xr(t,e,i,n,r,a,o,s,l){var u,h=.005,c=1/0;Yv[0]=o,Yv[1]=s;for(var d=0;1>d;d+=.05){jv[0]=gr(t,i,r,d),jv[1]=gr(e,n,a,d);var f=zp(Yv,jv);c>f&&(u=d,c=f)}c=1/0;for(var p=0;32>p&&!(Wv>h);p++){var g=u-h,v=u+h;jv[0]=gr(t,i,r,g),jv[1]=gr(e,n,a,g);var f=zp(jv,Yv);if(g>=0&&c>f)u=g,c=f;else{qv[0]=gr(t,i,r,v),qv[1]=gr(e,n,a,v);var m=zp(qv,Yv);1>=v&&c>m?(u=v,c=m):h*=.5}}return l&&(l[0]=gr(t,i,r,u),l[1]=gr(e,n,a,u)),Vv(c)}function wr(t,e,i){if(0!==t.length){var n,r=t[0],a=r[0],o=r[0],s=r[1],l=r[1];for(n=1;nh;h++){var p=d(t,i,r,o,nm[h]);l[0]=Zv(p,l[0]),u[0]=Kv(p,u[0])}for(f=c(e,n,a,s,rm),h=0;f>h;h++){var g=d(e,n,a,s,rm[h]);l[1]=Zv(g,l[1]),u[1]=Kv(g,u[1])}l[0]=Zv(t,l[0]),u[0]=Kv(t,u[0]),l[0]=Zv(o,l[0]),u[0]=Kv(o,u[0]),l[1]=Zv(e,l[1]),u[1]=Kv(e,u[1]),l[1]=Zv(s,l[1]),u[1]=Kv(s,u[1])}function Mr(t,e,i,n,r,a,o,s){var l=yr,u=gr,h=Kv(Zv(l(t,i,r),1),0),c=Kv(Zv(l(e,n,a),1),0),d=u(t,i,r,h),f=u(e,n,a,c);o[0]=Zv(t,r,d),o[1]=Zv(e,a,f),s[0]=Kv(t,r,d),s[1]=Kv(e,a,f)}function Ir(t,e,i,n,r,a,o,s,l){var u=oe,h=se,c=Math.abs(r-a);if(1e-4>c%Jv&&c>1e-4)return s[0]=t-i,s[1]=e-n,l[0]=t+i,void(l[1]=e+n);if(tm[0]=Qv(r)*i+t,tm[1]=$v(r)*n+e,em[0]=Qv(a)*i+t,em[1]=$v(a)*n+e,u(s,tm,em),h(l,tm,em),r%=Jv,0>r&&(r+=Jv),a%=Jv,0>a&&(a+=Jv),r>a&&!o?a+=Jv:a>r&&o&&(r+=Jv),o){var d=a;a=r,r=d}for(var f=0;a>f;f+=Math.PI/2)f>r&&(im[0]=Qv(f)*i+t,im[1]=$v(f)*n+e,u(s,im,s),h(l,im,l))}function Cr(t,e,i,n,r,a,o){if(0===r)return!1;var s=r,l=0,u=t;if(o>e+s&&o>n+s||e-s>o&&n-s>o||a>t+s&&a>i+s||t-s>a&&i-s>a)return!1;if(t===i)return Math.abs(a-t)<=s/2;l=(e-n)/(t-i),u=(t*n-i*e)/(t-i);var h=l*a-o+u,c=h*h/(l*l+1);return s/2*s/2>=c}function Tr(t,e,i,n,r,a,o,s,l,u,h){if(0===l)return!1;var c=l;if(h>e+c&&h>n+c&&h>a+c&&h>s+c||e-c>h&&n-c>h&&a-c>h&&s-c>h||u>t+c&&u>i+c&&u>r+c&&u>o+c||t-c>u&&i-c>u&&r-c>u&&o-c>u)return!1;var d=pr(t,e,i,n,r,a,o,s,u,h,null);return c/2>=d}function Dr(t,e,i,n,r,a,o,s,l){if(0===o)return!1;var u=o;if(l>e+u&&l>n+u&&l>a+u||e-u>l&&n-u>l&&a-u>l||s>t+u&&s>i+u&&s>r+u||t-u>s&&i-u>s&&r-u>s)return!1;var h=xr(t,e,i,n,r,a,s,l,null);return u/2>=h}function Ar(t){return t%=ym,0>t&&(t+=ym),t}function kr(t,e,i,n,r,a,o,s,l){if(0===o)return!1;var u=o;s-=t,l-=e;var h=Math.sqrt(s*s+l*l);if(h-u>i||i>h+u)return!1;if(Math.abs(n-r)%_m<1e-4)return!0;if(a){var c=n;n=Ar(r),r=Ar(c)}else n=Ar(n),r=Ar(r);n>r&&(r+=_m);var d=Math.atan2(l,s);return 0>d&&(d+=_m),d>=n&&r>=d||d+_m>=n&&r>=d+_m}function Pr(t,e,i,n,r,a){if(a>e&&a>n||e>a&&n>a)return 0;if(n===e)return 0;var o=e>n?1:-1,s=(a-e)/(n-e);(1===s||0===s)&&(o=e>n?.5:-.5);var l=s*(i-t)+t;return l===r?1/0:l>r?o:0}function Lr(t,e){return Math.abs(t-e)e&&u>n&&u>a&&u>s||e>u&&n>u&&a>u&&s>u)return 0;var h=cr(e,n,a,s,u,Sm);if(0===h)return 0;for(var c,d,f=0,p=-1,g=0;h>g;g++){var v=Sm[g],m=0===v||1===v?.5:1,y=ur(t,i,r,o,v);l>y||(0>p&&(p=dr(e,n,a,s,Mm),Mm[1]1&&Or(),c=ur(e,n,a,s,Mm[0]),p>1&&(d=ur(e,n,a,s,Mm[1]))),f+=2===p?vc?m:-m:vd?m:-m:d>s?m:-m:vc?m:-m:c>s?m:-m)}return f}function Br(t,e,i,n,r,a,o,s){if(s>e&&s>n&&s>a||e>s&&n>s&&a>s)return 0;var l=mr(e,n,a,s,Sm);if(0===l)return 0;var u=yr(e,n,a);if(u>=0&&1>=u){for(var h=0,c=gr(e,n,a,u),d=0;l>d;d++){var f=0===Sm[d]||1===Sm[d]?.5:1,p=gr(t,i,r,Sm[d]);o>p||(h+=Sm[d]c?f:-f:c>a?f:-f)}return h}var f=0===Sm[0]||1===Sm[0]?.5:1,p=gr(t,i,r,Sm[0]);return o>p?0:e>a?f:-f}function Er(t,e,i,n,r,a,o,s){if(s-=e,s>i||-i>s)return 0;var l=Math.sqrt(i*i-s*s);Sm[0]=-l,Sm[1]=l;var u=Math.abs(n-r);if(1e-4>u)return 0;if(1e-4>u%wm){n=0,r=wm;var h=a?1:-1;return o>=Sm[0]+t&&o<=Sm[1]+t?h:0}if(a){var l=n;n=Ar(r),r=Ar(l)}else n=Ar(n),r=Ar(r);n>r&&(r+=wm);for(var c=0,d=0;2>d;d++){var f=Sm[d];if(f+t>o){var p=Math.atan2(s,f),h=a?1:-1;0>p&&(p=wm+p),(p>=n&&r>=p||p+wm>=n&&r>=p+wm)&&(p>Math.PI/2&&p<1.5*Math.PI&&(h=-h),c+=h)}}return c}function Rr(t,e,i,n,r){for(var a=0,o=0,s=0,l=0,u=0,h=0;h1&&(i||(a+=Pr(o,s,l,u,n,r))),1===h&&(o=t[h],s=t[h+1],l=o,u=s),c){case xm.M:l=t[h++],u=t[h++],o=l,s=u;break;case xm.L:if(i){if(Cr(o,s,t[h],t[h+1],e,n,r))return!0}else a+=Pr(o,s,t[h],t[h+1],n,r)||0;o=t[h++],s=t[h++];break;case xm.C:if(i){if(Tr(o,s,t[h++],t[h++],t[h++],t[h++],t[h],t[h+1],e,n,r))return!0}else a+=zr(o,s,t[h++],t[h++],t[h++],t[h++],t[h],t[h+1],n,r)||0;o=t[h++],s=t[h++];break;case xm.Q:if(i){if(Dr(o,s,t[h++],t[h++],t[h],t[h+1],e,n,r))return!0}else a+=Br(o,s,t[h++],t[h++],t[h],t[h+1],n,r)||0;o=t[h++],s=t[h++];break;case xm.A:var d=t[h++],f=t[h++],p=t[h++],g=t[h++],v=t[h++],m=t[h++];h+=1;var y=1-t[h++],_=Math.cos(v)*p+d,x=Math.sin(v)*g+f;h>1?a+=Pr(o,s,_,x,n,r):(l=_,u=x);var w=(n-d)*g/p+d;if(i){if(kr(d,f,g,v,v+m,y,e,w,r))return!0}else a+=Er(d,f,g,v,v+m,y,w,r);o=Math.cos(v+m)*p+d,s=Math.sin(v+m)*g+f;break;case xm.R:l=o=t[h++],u=s=t[h++];var b=t[h++],S=t[h++],_=l+b,x=u+S;if(i){if(Cr(l,u,_,u,e,n,r)||Cr(_,u,_,x,e,n,r)||Cr(_,x,l,x,e,n,r)||Cr(l,x,l,u,e,n,r))return!0}else a+=Pr(_,u,_,x,n,r),a+=Pr(l,x,l,u,n,r);break;case xm.Z:if(i){if(Cr(o,s,l,u,e,n,r))return!0}else a+=Pr(o,s,l,u,n,r);o=l,s=u}}return i||Lr(s,u)||(a+=Pr(o,s,l,u,n,r)||0),0!==a}function Nr(t,e,i){return Rr(t,0,!1,e,i)}function Fr(t,e,i,n){return Rr(t,e,!0,i,n)}function Gr(t){wn.call(this,t),this.path=null}function Vr(t,e,i,n,r,a,o,s,l,u,h){var c=l*(Em/180),d=Bm(c)*(t-i)/2+zm(c)*(e-n)/2,f=-1*zm(c)*(t-i)/2+Bm(c)*(e-n)/2,p=d*d/(o*o)+f*f/(s*s);p>1&&(o*=Om(p),s*=Om(p));var g=(r===a?-1:1)*Om((o*o*s*s-o*o*f*f-s*s*d*d)/(o*o*f*f+s*s*d*d))||0,v=g*o*f/s,m=g*-s*d/o,y=(t+i)/2+Bm(c)*v-zm(c)*m,_=(e+n)/2+zm(c)*v+Bm(c)*m,x=Fm([1,0],[(d-v)/o,(f-m)/s]),w=[(d-v)/o,(f-m)/s],b=[(-1*d-v)/o,(-1*f-m)/s],S=Fm(w,b);Nm(w,b)<=-1&&(S=Em),Nm(w,b)>=1&&(S=0),0===a&&S>0&&(S-=2*Em),1===a&&0>S&&(S+=2*Em),h.addData(u,y,_,o,s,x,S,c,a)}function Hr(t){if(!t)return new mm;for(var e,i=0,n=0,r=i,a=n,o=new mm,s=mm.CMD,l=t.match(Gm),u=0;ug;g++)f[g]=parseFloat(f[g]);for(var v=0;p>v;){var m,y,_,x,w,b,S,M=i,I=n;switch(d){case"l":i+=f[v++],n+=f[v++],h=s.L,o.addData(h,i,n);break;case"L":i=f[v++],n=f[v++],h=s.L,o.addData(h,i,n);break;case"m":i+=f[v++],n+=f[v++],h=s.M,o.addData(h,i,n),r=i,a=n,d="l";break;case"M":i=f[v++],n=f[v++],h=s.M,o.addData(h,i,n),r=i,a=n,d="L";break;case"h":i+=f[v++],h=s.L,o.addData(h,i,n);break;case"H":i=f[v++],h=s.L,o.addData(h,i,n);break;case"v":n+=f[v++],h=s.L,o.addData(h,i,n);break;case"V":n=f[v++],h=s.L,o.addData(h,i,n);break;case"C":h=s.C,o.addData(h,f[v++],f[v++],f[v++],f[v++],f[v++],f[v++]),i=f[v-2],n=f[v-1];break;case"c":h=s.C,o.addData(h,f[v++]+i,f[v++]+n,f[v++]+i,f[v++]+n,f[v++]+i,f[v++]+n),i+=f[v-2],n+=f[v-1];break;case"S":m=i,y=n;var C=o.len(),T=o.data;e===s.C&&(m+=i-T[C-4],y+=n-T[C-3]),h=s.C,M=f[v++],I=f[v++],i=f[v++],n=f[v++],o.addData(h,m,y,M,I,i,n);break;case"s":m=i,y=n;var C=o.len(),T=o.data;e===s.C&&(m+=i-T[C-4],y+=n-T[C-3]),h=s.C,M=i+f[v++],I=n+f[v++],i+=f[v++],n+=f[v++],o.addData(h,m,y,M,I,i,n);break;case"Q":M=f[v++],I=f[v++],i=f[v++],n=f[v++],h=s.Q,o.addData(h,M,I,i,n);break;case"q":M=f[v++]+i,I=f[v++]+n,i+=f[v++],n+=f[v++],h=s.Q,o.addData(h,M,I,i,n);break;case"T":m=i,y=n;var C=o.len(),T=o.data;e===s.Q&&(m+=i-T[C-4],y+=n-T[C-3]),i=f[v++],n=f[v++],h=s.Q,o.addData(h,m,y,i,n);break;case"t":m=i,y=n;var C=o.len(),T=o.data;e===s.Q&&(m+=i-T[C-4],y+=n-T[C-3]),i+=f[v++],n+=f[v++],h=s.Q,o.addData(h,m,y,i,n);break;case"A":_=f[v++],x=f[v++],w=f[v++],b=f[v++],S=f[v++],M=i,I=n,i=f[v++],n=f[v++],h=s.A,Vr(M,I,i,n,b,S,_,x,w,h,o);break;case"a":_=f[v++],x=f[v++],w=f[v++],b=f[v++],S=f[v++],M=i,I=n,i+=f[v++],n+=f[v++],h=s.A,Vr(M,I,i,n,b,S,_,x,w,h,o)}}("z"===d||"Z"===d)&&(h=s.Z,o.addData(h),i=r,n=a),e=h}return o.toStatic(),o}function Wr(t,e){var i=Hr(t);return e=e||{},e.buildPath=function(t){if(t.setData){t.setData(i.data);var e=t.getContext();e&&t.rebuildPath(e)}else{var e=t;i.rebuildPath(e)}},e.applyTransform=function(t){Lm(i,t),this.dirty(!0)},e}function Ur(t,e){return new Gr(Wr(t,e))}function Xr(t,e){return Gr.extend(Wr(t,e))}function Yr(t,e){for(var i=[],n=t.length,r=0;n>r;r++){var a=t[r];a.path||a.createPathProxy(),a.__dirtyPath&&a.buildPath(a.path,a.shape,!0),i.push(a.path)}var o=new Gr(e);return o.createPathProxy(),o.buildPath=function(t){t.appendPath(i);var e=t.getContext();e&&t.rebuildPath(e)},o}function jr(t,e,i,n,r,a,o){var s=.5*(i-t),l=.5*(n-e);return(2*(e-i)+s+l)*o+(-3*(e-i)-2*s-l)*a+s*r+e}function qr(t,e,i){var n=e.points,r=e.smooth;if(n&&n.length>=2){if(r&&"spline"!==r){var a=Zm(n,r,i,e.smoothConstraint);t.moveTo(n[0][0],n[0][1]);for(var o=n.length,s=0;(i?o:o-1)>s;s++){var l=a[2*s],u=a[2*s+1],h=n[(s+1)%o];t.bezierCurveTo(l[0],l[1],u[0],u[1],h[0],h[1])}}else{"spline"===r&&(n=qm(n,i)),t.moveTo(n[0][0],n[0][1]);for(var s=1,c=n.length;c>s;s++)t.lineTo(n[s][0],n[s][1])}i&&t.closePath()}}function Zr(t,e,i){var n=i&&i.lineWidth;if(e&&n){var r=e.x1,a=e.x2,o=e.y1,s=e.y2;Qm(2*r)===Qm(2*a)?t.x1=t.x2=$r(r,n,!0):(t.x1=r,t.x2=a),Qm(2*o)===Qm(2*s)?t.y1=t.y2=$r(o,n,!0):(t.y1=o,t.y2=s)}}function Kr(t,e,i){var n=i&&i.lineWidth;if(e&&n){var r=e.x,a=e.y,o=e.width,s=e.height;t.x=$r(r,n,!0),t.y=$r(a,n,!0),t.width=Math.max($r(r+o,n,!1)-t.x,0===o?0:1),t.height=Math.max($r(a+s,n,!1)-t.y,0===s?0:1)}}function $r(t,e,i){var n=Qm(2*t);return(n+Qm(e))%2===0?n/2:(n+(i?1:-1))/2}function Qr(t,e,i){var n=t.cpx2,r=t.cpy2;return null===n||null===r?[(i?hr:ur)(t.x1,t.cpx1,t.cpx2,t.x2,e),(i?hr:ur)(t.y1,t.cpy1,t.cpy2,t.y2,e)]:[(i?vr:gr)(t.x1,t.cpx1,t.x2,e),(i?vr:gr)(t.y1,t.cpy1,t.y2,e)]}function Jr(t){wn.call(this,t),this._displayables=[],this._temporaryDisplayables=[],this._cursor=0,this.notClear=!0}function ta(t){return Gr.extend(t)}function ea(t,e){return Xr(t,e)}function ia(t,e){xy[t]=e}function na(t){return xy.hasOwnProperty(t)?xy[t]:void 0}function ra(t,e,i,n){var r=Ur(t,e);return i&&("center"===n&&(i=oa(i,r.getBoundingRect())),sa(r,i)),r}function aa(t,e,i){var n=new bn({style:{image:t,x:e.x,y:e.y,width:e.width,height:e.height},onload:function(t){if("center"===i){var r={width:t.width,height:t.height};n.setStyle(oa(e,r))}}});return n}function oa(t,e){var i,n=e.width/e.height,r=t.height*n;r<=t.width?i=t.height:(r=t.width,i=r/n);var a=t.x+t.width/2,o=t.y+t.height/2;return{x:a-r/2,y:o-i/2,width:r,height:i}}function sa(t,e){if(t.applyTransform){var i=t.getBoundingRect(),n=i.calculateTransform(e);t.applyTransform(n)}}function la(t){return Zr(t.shape,t.shape,t.style),t}function ua(t){return Kr(t.shape,t.shape,t.style),t}function ha(t){return null!=t&&"none"!==t}function ca(t){if("string"!=typeof t)return t;var e=Sy.get(t);return e||(e=$e(t,-.1),1e4>My&&(Sy.set(t,e),My++)),e}function da(t){if(t.__hoverStlDirty){t.__hoverStlDirty=!1;var e=t.__hoverStl;if(!e)return void(t.__cachedNormalStl=t.__cachedNormalZ2=null);var i=t.__cachedNormalStl={};t.__cachedNormalZ2=t.z2;var n=t.style;for(var r in e)null!=e[r]&&(i[r]=n[r]);i.fill=n.fill,i.stroke=n.stroke}}function fa(t){var e=t.__hoverStl;if(e&&!t.__highlighted){var i=t.__zr,n=t.useHoverLayer&&i&&"canvas"===i.painter.type;if(t.__highlighted=n?"layer":"plain",!(t.isGroup||!i&&t.useHoverLayer)){var r=t,a=t.style;n&&(r=i.addHover(t),a=r.style),Ea(a),n||da(r),a.extendFrom(e),pa(a,e,"fill"),pa(a,e,"stroke"),Ba(a),n||(t.dirty(!1),t.z2+=py)}}}function pa(t,e,i){!ha(e[i])&&ha(t[i])&&(t[i]=ca(t[i]))}function ga(t){var e=t.__highlighted;if(e&&(t.__highlighted=!1,!t.isGroup))if("layer"===e)t.__zr&&t.__zr.removeHover(t);else{var i=t.style,n=t.__cachedNormalStl;n&&(Ea(i),t.setStyle(n),Ba(i));var r=t.__cachedNormalZ2;null!=r&&t.z2-r===py&&(t.z2=r)}}function va(t,e,i){var n,r=my,a=my;t.__highlighted&&(r=vy,n=!0),e(t,i),t.__highlighted&&(a=vy,n=!0),t.isGroup&&t.traverse(function(t){!t.isGroup&&e(t,i)}),n&&t.__highDownOnUpdate&&t.__highDownOnUpdate(r,a)}function ma(t,e){e=t.__hoverStl=e!==!1&&(t.hoverStyle||e||{}),t.__hoverStlDirty=!0,t.__highlighted&&(t.__cachedNormalStl=null,ga(t),fa(t))}function ya(t){!ba(this,t)&&!this.__highByOuter&&va(this,fa)}function _a(t){!ba(this,t)&&!this.__highByOuter&&va(this,ga)}function xa(t){this.__highByOuter|=1<<(t||0),va(this,fa)}function wa(t){!(this.__highByOuter&=~(1<<(t||0)))&&va(this,ga)}function ba(t,e){return t.__highDownSilentOnTouch&&e.zrByTouch}function Sa(t,e){Ma(t,!0),va(t,ma,e)}function Ma(t,e){var i=e===!1;if(t.__highDownSilentOnTouch=t.highDownSilentOnTouch,t.__highDownOnUpdate=t.highDownOnUpdate,!i||t.__highDownDispatcher){var n=i?"off":"on";t[n]("mouseover",ya)[n]("mouseout",_a),t[n]("emphasis",xa)[n]("normal",wa),t.__highByOuter=t.__highByOuter||0,t.__highDownDispatcher=!i}}function Ia(t){return!(!t||!t.__highDownDispatcher)}function Ca(t){var e=_y[t];return null==e&&32>=yy&&(e=_y[t]=yy++),e}function Ta(t,e,i,n,r,a,o){r=r||fy;var s,l=r.labelFetcher,u=r.labelDataIndex,h=r.labelDimIndex,c=i.getShallow("show"),d=n.getShallow("show");(c||d)&&(l&&(s=l.getFormattedLabel(u,"normal",null,h)),null==s&&(s=w(r.defaultText)?r.defaultText(u,r):r.defaultText));var f=c?s:null,p=d?A(l?l.getFormattedLabel(u,"emphasis",null,h):null,s):null;(null!=f||null!=p)&&(Aa(t,i,a,r),Aa(e,n,o,r,!0)),t.text=f,e.text=p}function Da(t,e,i){var n=t.style;e&&(Ea(n),t.setStyle(e),Ba(n)),n=t.__hoverStl,i&&n&&(Ea(n),o(n,i),Ba(n))}function Aa(t,e,i,n,r){return Pa(t,e,n,r),i&&o(t,i),t}function ka(t,e,i){var n,r={isRectText:!0};i===!1?n=!0:r.autoColor=i,Pa(t,e,r,n)}function Pa(t,e,i,n){if(i=i||fy,i.isRectText){var r;i.getTextPosition?r=i.getTextPosition(e,n):(r=e.getShallow("position")||(n?null:"inside"),"outside"===r&&(r="top")),t.textPosition=r,t.textOffset=e.getShallow("offset");var a=e.getShallow("rotate");null!=a&&(a*=Math.PI/180),t.textRotation=a,t.textDistance=A(e.getShallow("distance"),n?null:5)}var o,s=e.ecModel,l=s&&s.option.textStyle,u=La(e);if(u){o={};for(var h in u)if(u.hasOwnProperty(h)){var c=e.getModel(["rich",h]);Oa(o[h]={},c,l,i,n)}}return t.rich=o,Oa(t,e,l,i,n,!0),i.forceRich&&!i.textStyle&&(i.textStyle={}),t}function La(t){for(var e;t&&t!==t.ecModel;){var i=(t.option||fy).rich;if(i){e=e||{};for(var n in i)i.hasOwnProperty(n)&&(e[n]=1)}t=t.parentModel}return e}function Oa(t,e,i,n,r,a){i=!r&&i||fy,t.textFill=za(e.getShallow("color"),n)||i.color,t.textStroke=za(e.getShallow("textBorderColor"),n)||i.textBorderColor,t.textStrokeWidth=A(e.getShallow("textBorderWidth"),i.textBorderWidth),r||(a&&(t.insideRollbackOpt=n,Ba(t)),null==t.textFill&&(t.textFill=n.autoColor)),t.fontStyle=e.getShallow("fontStyle")||i.fontStyle,t.fontWeight=e.getShallow("fontWeight")||i.fontWeight,t.fontSize=e.getShallow("fontSize")||i.fontSize,t.fontFamily=e.getShallow("fontFamily")||i.fontFamily,t.textAlign=e.getShallow("align"),t.textVerticalAlign=e.getShallow("verticalAlign")||e.getShallow("baseline"),t.textLineHeight=e.getShallow("lineHeight"),t.textWidth=e.getShallow("width"),t.textHeight=e.getShallow("height"),t.textTag=e.getShallow("tag"),a&&n.disableBox||(t.textBackgroundColor=za(e.getShallow("backgroundColor"),n),t.textPadding=e.getShallow("padding"),t.textBorderColor=za(e.getShallow("borderColor"),n),t.textBorderWidth=e.getShallow("borderWidth"),t.textBorderRadius=e.getShallow("borderRadius"),t.textBoxShadowColor=e.getShallow("shadowColor"),t.textBoxShadowBlur=e.getShallow("shadowBlur"),t.textBoxShadowOffsetX=e.getShallow("shadowOffsetX"),t.textBoxShadowOffsetY=e.getShallow("shadowOffsetY")),t.textShadowColor=e.getShallow("textShadowColor")||i.textShadowColor,t.textShadowBlur=e.getShallow("textShadowBlur")||i.textShadowBlur,t.textShadowOffsetX=e.getShallow("textShadowOffsetX")||i.textShadowOffsetX,t.textShadowOffsetY=e.getShallow("textShadowOffsetY")||i.textShadowOffsetY}function za(t,e){return"auto"!==t?t:e&&e.autoColor?e.autoColor:null}function Ba(t){var e,i=t.textPosition,n=t.insideRollbackOpt;if(n&&null==t.textFill){var r=n.autoColor,a=n.isRectText,o=n.useInsideStyle,s=o!==!1&&(o===!0||a&&i&&"string"==typeof i&&i.indexOf("inside")>=0),l=!s&&null!=r;(s||l)&&(e={textFill:t.textFill,textStroke:t.textStroke,textStrokeWidth:t.textStrokeWidth}),s&&(t.textFill="#fff",null==t.textStroke&&(t.textStroke=r,null==t.textStrokeWidth&&(t.textStrokeWidth=2))),l&&(t.textFill=r)}t.insideRollback=e}function Ea(t){var e=t.insideRollback;e&&(t.textFill=e.textFill,t.textStroke=e.textStroke,t.textStrokeWidth=e.textStrokeWidth,t.insideRollback=null)}function Ra(t,e){var i=e||e.getModel("textStyle");return z([t.fontStyle||i&&i.getShallow("fontStyle")||"",t.fontWeight||i&&i.getShallow("fontWeight")||"",(t.fontSize||i&&i.getShallow("fontSize")||12)+"px",t.fontFamily||i&&i.getShallow("fontFamily")||"sans-serif"].join(" "))}function Na(t,e,i,n,r,a){"function"==typeof r&&(a=r,r=null);var o=n&&n.isAnimationEnabled();if(o){var s=t?"Update":"",l=n.getShallow("animationDuration"+s),u=n.getShallow("animationEasing"+s),h=n.getShallow("animationDelay"+s);"function"==typeof h&&(h=h(r,n.getAnimationDelayParams?n.getAnimationDelayParams(e,r):null)),"function"==typeof l&&(l=l(r)),l>0?e.animateTo(i,l,h||0,u,a,!!a):(e.stopAnimation(),e.attr(i),a&&a())}else e.stopAnimation(),e.attr(i),a&&a()}function Fa(t,e,i,n,r){Na(!0,t,e,i,n,r)}function Ga(t,e,i,n,r){Na(!1,t,e,i,n,r)}function Va(t,e){for(var i=De([]);t&&t!==e;)ke(i,t.getLocalTransform(),i),t=t.parent;return i}function Ha(t,e,i){return e&&!d(e)&&(e=Jp.getLocalTransform(e)),i&&(e=ze([],e)),ae([],t,e)}function Wa(t,e,i){var n=0===e[4]||0===e[5]||0===e[0]?1:Math.abs(2*e[4]/e[0]),r=0===e[4]||0===e[5]||0===e[2]?1:Math.abs(2*e[4]/e[2]),a=["left"===t?-n:"right"===t?n:0,"top"===t?-r:"bottom"===t?r:0];return a=Ha(a,e,i),Math.abs(a[0])>Math.abs(a[1])?a[0]>0?"right":"left":a[1]>0?"bottom":"top"}function Ua(t,e,i){function n(t){var e={};return t.traverse(function(t){!t.isGroup&&t.anid&&(e[t.anid]=t)}),e}function r(t){var e={position:W(t.position),rotation:t.rotation};return t.shape&&(e.shape=o({},t.shape)),e}if(t&&e){var a=n(t);e.traverse(function(t){if(!t.isGroup&&t.anid){var e=a[t.anid];if(e){var n=r(t);t.attr(r(e)),Fa(t,n,i,t.dataIndex)}}})}}function Xa(t,e){return p(t,function(t){var i=t[0];i=cy(i,e.x),i=dy(i,e.x+e.width);var n=t[1];return n=cy(n,e.y),n=dy(n,e.y+e.height),[i,n]})}function Ya(t,e){var i=cy(t.x,e.x),n=dy(t.x+t.width,e.x+e.width),r=cy(t.y,e.y),a=dy(t.y+t.height,e.y+e.height);return n>=i&&a>=r?{x:i,y:r,width:n-i,height:a-r}:void 0}function ja(t,e,i){e=o({rectHover:!0},e);var n=e.style={strokeNoScale:!0};return i=i||{x:-1,y:-1,width:2,height:2},t?0===t.indexOf("image://")?(n.image=t.slice(8),s(n,i),new bn(e)):ra(t.replace("path://",""),e,i,"center"):void 0}function qa(t,e,i,n,r){for(var a=0,o=r[r.length-1];ag||g>1)return!1;var v=Ka(f,p,h,c)/d;return 0>v||v>1?!1:!0}function Ka(t,e,i,n){return t*n-i*e}function $a(t){return 1e-6>=t&&t>=-1e-6}function Qa(t,e,i){this.parentModel=e,this.ecModel=i,this.option=t}function Ja(t,e,i){for(var n=0;n=0&&i.push(t)}),i}t.topologicalTravel=function(t,e,n,r){function a(t){l[t].entryCount--,0===l[t].entryCount&&u.push(t)}function o(t){h[t]=!0,a(t)}if(t.length){var s=i(e),l=s.graph,u=s.noEntryList,h={};for(f(t,function(t){h[t]=!0});u.length;){var c=u.pop(),d=l[c],p=!!h[c];p&&(n.call(r,c,d.originalDeps.slice()),delete h[c]),f(d.successor,p?o:a)}f(h,function(){throw new Error("Circle dependency may exists")})}}}function ro(t){return t.replace(/^\s+|\s+$/g,"")}function ao(t,e,i,n){var r=e[1]-e[0],a=i[1]-i[0];if(0===r)return 0===a?i[0]:(i[0]+i[1])/2;if(n)if(r>0){if(t<=e[0])return i[0];if(t>=e[1])return i[1]}else{if(t>=e[0])return i[0];if(t<=e[1])return i[1]}else{if(t===e[0])return i[0];if(t===e[1])return i[1]}return(t-e[0])/r*a+i[0]}function oo(t,e){switch(t){case"center":case"middle":t="50%";break;case"left":case"top":t="0%";break;case"right":case"bottom":t="100%"}return"string"==typeof t?ro(t).match(/%$/)?parseFloat(t)/100*e:parseFloat(t):null==t?0/0:+t}function so(t,e,i){return null==e&&(e=10),e=Math.min(Math.max(0,e),20),t=(+t).toFixed(e),i?t:+t}function lo(t){return t.sort(function(t,e){return t-e}),t}function uo(t){if(t=+t,isNaN(t))return 0;for(var e=1,i=0;Math.round(t*e)/e!==t;)e*=10,i++;return i}function ho(t){var e=t.toString(),i=e.indexOf("e"); +if(i>0){var n=+e.slice(i+1);return 0>n?-n:0}var r=e.indexOf(".");return 0>r?0:e.length-1-r}function co(t,e){var i=Math.log,n=Math.LN10,r=Math.floor(i(t[1]-t[0])/n),a=Math.round(i(Math.abs(e[1]-e[0]))/n),o=Math.min(Math.max(-r+a,0),20);return isFinite(o)?o:20}function fo(t,e,i){if(!t[e])return 0;var n=g(t,function(t,e){return t+(isNaN(e)?0:e)},0);if(0===n)return 0;for(var r=Math.pow(10,i),a=p(t,function(t){return(isNaN(t)?0:t)/n*r*100}),o=100*r,s=p(a,function(t){return Math.floor(t)}),l=g(s,function(t,e){return t+e},0),u=p(a,function(t,e){return t-s[e]});o>l;){for(var h=Number.NEGATIVE_INFINITY,c=null,d=0,f=u.length;f>d;++d)u[d]>h&&(h=u[d],c=d);++s[c],u[c]=0,++l}return s[e]/r}function po(t){var e=2*Math.PI;return(t%e+e)%e}function go(t){return t>-Oy&&Oy>t}function vo(t){if(t instanceof Date)return t;if("string"==typeof t){var e=By.exec(t);if(!e)return new Date(0/0);if(e[8]){var i=+e[4]||0;return"Z"!==e[8].toUpperCase()&&(i-=e[8].slice(0,3)),new Date(Date.UTC(+e[1],+(e[2]||1)-1,+e[3]||1,i,+(e[5]||0),+e[6]||0,+e[7]||0))}return new Date(+e[1],+(e[2]||1)-1,+e[3]||1,+e[4]||0,+(e[5]||0),+e[6]||0,+e[7]||0)}return new Date(null==t?0/0:Math.round(t))}function mo(t){return Math.pow(10,yo(t))}function yo(t){if(0===t)return 0;var e=Math.floor(Math.log(t)/Math.LN10);return t/Math.pow(10,e)>=10&&e++,e}function _o(t,e){var i,n=yo(t),r=Math.pow(10,n),a=t/r;return i=e?1.5>a?1:2.5>a?2:4>a?3:7>a?5:10:1>a?1:2>a?2:3>a?3:5>a?5:10,t=i*r,n>=-20?+t.toFixed(0>n?-n:0):t}function xo(t,e){var i=(t.length-1)*e+1,n=Math.floor(i),r=+t[n-1],a=i-n;return a?r+a*(t[n]-r):r}function wo(t){function e(t,i,n){return t.interval[n]s;s++)a[s]<=i&&(a[s]=i,o[s]=s?1:1-n),i=a[s],n=o[s];a[0]===a[1]&&o[0]*o[1]!==1?t.splice(r,1):r++}return t}function bo(t){return t-parseFloat(t)>=0}function So(t){return isNaN(t)?"-":(t=(t+"").split("."),t[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(t.length>1?"."+t[1]:""))}function Mo(t,e){return t=(t||"").toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()}),e&&t&&(t=t.charAt(0).toUpperCase()+t.slice(1)),t}function Io(t){return null==t?"":(t+"").replace(Ny,function(t,e){return Fy[e]})}function Co(t,e,i){x(e)||(e=[e]);var n=e.length;if(!n)return"";for(var r=e[0].$vars||[],a=0;as;s++)for(var l=0;l':'':{renderMode:r,content:"{marker"+a+"|} ",style:{color:i}}:""}function Ao(t,e){return t+="","0000".substr(0,e-t.length)+t}function ko(t,e,i){("week"===t||"month"===t||"quarter"===t||"half-year"===t||"year"===t)&&(t="MM-dd\nyyyy");var n=vo(e),r=i?"UTC":"",a=n["get"+r+"FullYear"](),o=n["get"+r+"Month"]()+1,s=n["get"+r+"Date"](),l=n["get"+r+"Hours"](),u=n["get"+r+"Minutes"](),h=n["get"+r+"Seconds"](),c=n["get"+r+"Milliseconds"]();return t=t.replace("MM",Ao(o,2)).replace("M",o).replace("yyyy",a).replace("yy",a%100).replace("dd",Ao(s,2)).replace("d",s).replace("hh",Ao(l,2)).replace("h",l).replace("mm",Ao(u,2)).replace("m",u).replace("ss",Ao(h,2)).replace("s",h).replace("SSS",Ao(c,3))}function Po(t){return t?t.charAt(0).toUpperCase()+t.substr(1):t}function Lo(t){return Fi(t.text,t.font,t.textAlign,t.textVerticalAlign,t.textPadding,t.textLineHeight,t.rich,t.truncate)}function Oo(t,e,i,n,r,a,o,s){return Fi(t,e,i,n,r,s,a,o)}function zo(t,e,i,n,r){var a=0,o=0;null==n&&(n=1/0),null==r&&(r=1/0);var s=0;e.eachChild(function(l,u){var h,c,d=l.position,f=l.getBoundingRect(),p=e.childAt(u+1),g=p&&p.getBoundingRect();if("horizontal"===t){var v=f.width+(g?-g.x+f.x:0);h=a+v,h>n||l.newline?(a=0,h=v,o+=s+i,s=f.height):s=Math.max(s,f.height)}else{var m=f.height+(g?-g.y+f.y:0);c=o+m,c>r||l.newline?(a+=s+i,o=0,c=m,s=f.width):s=Math.max(s,f.width)}l.newline||(d[0]=a,d[1]=o,"horizontal"===t?a=h+i:o=c+i)})}function Bo(t,e,i){i=Ry(i||0);var n=e.width,r=e.height,a=oo(t.left,n),o=oo(t.top,r),s=oo(t.right,n),l=oo(t.bottom,r),u=oo(t.width,n),h=oo(t.height,r),c=i[2]+i[0],d=i[1]+i[3],f=t.aspect;switch(isNaN(u)&&(u=n-s-d-a),isNaN(h)&&(h=r-l-c-o),null!=f&&(isNaN(u)&&isNaN(h)&&(f>n/r?u=.8*n:h=.8*r),isNaN(u)&&(u=f*h),isNaN(h)&&(h=u/f)),isNaN(a)&&(a=n-s-u-d),isNaN(o)&&(o=r-l-h-c),t.left||t.right){case"center":a=n/2-u/2-i[3];break;case"right":a=n-u-d}switch(t.top||t.bottom){case"middle":case"center":o=r/2-h/2-i[0];break;case"bottom":o=r-h-c}a=a||0,o=o||0,isNaN(u)&&(u=n-d-a-(s||0)),isNaN(h)&&(h=r-c-o-(l||0));var p=new xi(a+i[3],o+i[0],u,h);return p.margin=i,p}function Eo(t,e,i){function n(i,n){var o={},l=0,u={},h=0,c=2;if(Uy(i,function(e){u[e]=t[e]}),Uy(i,function(t){r(e,t)&&(o[t]=u[t]=e[t]),a(o,t)&&l++,a(u,t)&&h++}),s[n])return a(e,i[1])?u[i[2]]=null:a(e,i[2])&&(u[i[1]]=null),u;if(h!==c&&l){if(l>=c)return o;for(var d=0;dn;n++)if(t[n].length>e)return t[n];return t[i-1]}function Vo(t){var e=t.get("coordinateSystem"),i={coordSysName:e,coordSysDims:[],axisMap:N(),categoryAxisMap:N()},n=e_[e];return n?(n(t,i,i.axisMap,i.categoryAxisMap),i):void 0}function Ho(t){return"category"===t.get("type")}function Wo(t){this.fromDataset=t.fromDataset,this.data=t.data||(t.sourceFormat===a_?{}:[]),this.sourceFormat=t.sourceFormat||o_,this.seriesLayoutBy=t.seriesLayoutBy||l_,this.dimensionsDefine=t.dimensionsDefine,this.encodeDefine=t.encodeDefine&&N(t.encodeDefine),this.startIndex=t.startIndex||0,this.dimensionsDetectCount=t.dimensionsDetectCount}function Uo(t){var e=t.option.source,i=o_;if(I(e))i=s_;else if(x(e)){0===e.length&&(i=n_);for(var n=0,r=e.length;r>n;n++){var a=e[n];if(null!=a){if(x(a)){i=n_;break}if(S(a)){i=r_;break}}}}else if(S(e)){for(var o in e)if(e.hasOwnProperty(o)&&d(e[o])){i=a_;break}}else if(null!=e)throw new Error("Invalid data");h_(t).sourceFormat=i}function Xo(t){return h_(t).source}function Yo(t){h_(t).datasetMap=N()}function jo(t){var e=t.option,i=e.data,n=I(i)?s_:i_,r=!1,a=e.seriesLayoutBy,o=e.sourceHeader,s=e.dimensions,l=Jo(t);if(l){var u=l.option;i=u.source,n=h_(l).sourceFormat,r=!0,a=a||u.seriesLayoutBy,null==o&&(o=u.sourceHeader),s=s||u.dimensions}var h=qo(i,n,a,o,s),c=e.encode;!c&&l&&(c=Qo(t,l,i,n,a,h)),h_(t).source=new Wo({data:i,fromDataset:r,seriesLayoutBy:a,sourceFormat:n,dimensionsDefine:h.dimensionsDefine,startIndex:h.startIndex,dimensionsDetectCount:h.dimensionsDetectCount,encodeDefine:c})}function qo(t,e,i,n,r){if(!t)return{dimensionsDefine:Zo(r)};var a,o,s;if(e===n_)"auto"===n||null==n?Ko(function(t){null!=t&&"-"!==t&&(b(t)?null==o&&(o=1):o=0)},i,t,10):o=n?1:0,r||1!==o||(r=[],Ko(function(t,e){r[e]=null!=t?t:""},i,t)),a=r?r.length:i===u_?t.length:t[0]?t[0].length:null;else if(e===r_)r||(r=$o(t),s=!0);else if(e===a_)r||(r=[],s=!0,f(t,function(t,e){r.push(e)}));else if(e===i_){var l=Vn(t[0]);a=x(l)&&l.length||1}var u;return s&&f(r,function(t,e){"name"===(S(t)?t.name:t)&&(u=e)}),{startIndex:o,dimensionsDefine:Zo(r),dimensionsDetectCount:a,potentialNameDimIndex:u}}function Zo(t){if(t){var e=N();return p(t,function(t){if(t=o({},S(t)?t:{name:t}),null==t.name)return t;t.name+="",null==t.displayName&&(t.displayName=t.name);var i=e.get(t.name);return i?t.name+="-"+i.count++:e.set(t.name,{count:1}),t})}}function Ko(t,e,i,n){if(null==n&&(n=1/0),e===u_)for(var r=0;rr;r++)t(i[r]?i[r][0]:null,r);else for(var a=i[0]||[],r=0;rr;r++)t(a[r],r)}function $o(t){for(var e,i=0;i_&&null==y;_++)es(i,n,r,a.dimensionsDefine,a.startIndex,_)||(y=_);if(null!=y){s.value=y;var x=a.potentialNameDimIndex||Math.max(y-1,0);u.push(x),l.push(x)}}return l.length&&(s.itemName=l),u.length&&(s.seriesName=u),s}function Jo(t){var e=t.option,i=e.data;return i?void 0:t.ecModel.getComponent("dataset",e.datasetIndex||0)}function ts(t,e){return es(t.data,t.sourceFormat,t.seriesLayoutBy,t.dimensionsDefine,t.startIndex,e)}function es(t,e,i,n,r,a){function o(t){return null!=t&&isFinite(t)&&""!==t?!1:b(t)&&"-"!==t?!0:void 0}var s,l=5;if(I(t))return!1;var u;if(n&&(u=n[a],u=S(u)?u.name:u),e===n_)if(i===u_){for(var h=t[a],c=0;c<(h||[]).length&&l>c;c++)if(null!=(s=o(h[r+c])))return s}else for(var c=0;cc;c++){var d=t[r+c];if(d&&null!=(s=o(d[a])))return s}else if(e===r_){if(!u)return;for(var c=0;cc;c++){var f=t[c];if(f&&null!=(s=o(f[u])))return s}}else if(e===a_){if(!u)return;var h=t[u];if(!h||I(h))return!1;for(var c=0;cc;c++)if(null!=(s=o(h[c])))return s}else if(e===i_)for(var c=0;cc;c++){var f=t[c],p=Vn(f);if(!x(p))return!1;if(null!=(s=o(p[a])))return s}return!1}function is(t,e){if(e){var i=e.seiresIndex,n=e.seriesId,r=e.seriesName;return null!=i&&t.componentIndex!==i||null!=n&&t.id!==n||null!=r&&t.name!==r}}function ns(t,e){var i=t.color&&!t.colorLayer;f(e,function(e,a){"colorLayer"===a&&i||Ky.hasClass(a)||("object"==typeof e?t[a]=t[a]?r(t[a],e,!1):n(e):null==t[a]&&(t[a]=e))})}function rs(t){t=t,this.option={},this.option[c_]=1,this._componentsMap=N({series:[]}),this._seriesIndices,this._seriesIndicesMap,ns(t,this._theme.option),r(t,Qy,!1),this.mergeOption(t)}function as(t,e){x(e)||(e=e?[e]:[]);var i={};return f(e,function(e){i[e]=(t.get(e)||[]).slice()}),i}function os(t,e,i){var n=e.type?e.type:i?i.subType:Ky.determineSubType(t,e);return n}function ss(t,e){t._seriesIndicesMap=N(t._seriesIndices=p(e,function(t){return t.componentIndex})||[])}function ls(t,e){return e.hasOwnProperty("subType")?v(t,function(t){return t.subType===e.subType}):t}function us(t){f(f_,function(e){this[e]=y(t[e],t)},this)}function hs(){this._coordinateSystems=[]}function cs(t){this._api=t,this._timelineOptions=[],this._mediaList=[],this._mediaDefault,this._currentMediaIndices=[],this._optionBackup,this._newBaseOption}function ds(t,e,i){var n,r,a=[],o=[],s=t.timeline;if(t.baseOption&&(r=t.baseOption),(s||t.options)&&(r=r||{},a=(t.options||[]).slice()),t.media){r=r||{};var l=t.media;g_(l,function(t){t&&t.option&&(t.query?o.push(t):n||(n=t))})}return r||(r=t),r.timeline||(r.timeline=s),g_([r].concat(a).concat(p(o,function(t){return t.option})),function(t){g_(e,function(e){e(t,i)})}),{baseOption:r,timelineOptions:a,mediaDefault:n,mediaList:o}}function fs(t,e,i){var n={width:e,height:i,aspectratio:e/i},r=!0;return f(t,function(t,e){var i=e.match(__);if(i&&i[1]&&i[2]){var a=i[1],o=i[2].toLowerCase();ps(n[o],t,a)||(r=!1)}}),r}function ps(t,e,i){return"min"===i?t>=e:"max"===i?e>=t:t===e}function gs(t,e){return t.join(",")===e.join(",")}function vs(t,e){e=e||{},g_(e,function(e,i){if(null!=e){var n=t[i];if(Ky.hasClass(i)){e=Fn(e),n=Fn(n);var r=Wn(n,e);t[i]=m_(r,function(t){return t.option&&t.exist?y_(t.exist,t.option,!0):t.exist||t.option})}else t[i]=y_(n,e,!0)}})}function ms(t){var e=t&&t.itemStyle;if(e)for(var i=0,n=b_.length;n>i;i++){var a=b_[i],o=e.normal,s=e.emphasis;o&&o[a]&&(t[a]=t[a]||{},t[a].normal?r(t[a].normal,o[a]):t[a].normal=o[a],o[a]=null),s&&s[a]&&(t[a]=t[a]||{},t[a].emphasis?r(t[a].emphasis,s[a]):t[a].emphasis=s[a],s[a]=null)}}function ys(t,e,i){if(t&&t[e]&&(t[e].normal||t[e].emphasis)){var n=t[e].normal,r=t[e].emphasis;n&&(i?(t[e].normal=t[e].emphasis=null,s(t[e],n)):t[e]=n),r&&(t.emphasis=t.emphasis||{},t.emphasis[e]=r)}}function _s(t){ys(t,"itemStyle"),ys(t,"lineStyle"),ys(t,"areaStyle"),ys(t,"label"),ys(t,"labelLine"),ys(t,"upperLabel"),ys(t,"edgeLabel")}function xs(t,e){var i=w_(t)&&t[e],n=w_(i)&&i.textStyle;if(n)for(var r=0,a=kv.length;a>r;r++){var e=kv[r];n.hasOwnProperty(e)&&(i[e]=n[e])}}function ws(t){t&&(_s(t),xs(t,"label"),t.emphasis&&xs(t.emphasis,"label"))}function bs(t){if(w_(t)){ms(t),_s(t),xs(t,"label"),xs(t,"upperLabel"),xs(t,"edgeLabel"),t.emphasis&&(xs(t.emphasis,"label"),xs(t.emphasis,"upperLabel"),xs(t.emphasis,"edgeLabel"));var e=t.markPoint;e&&(ms(e),ws(e));var i=t.markLine;i&&(ms(i),ws(i));var n=t.markArea;n&&ws(n);var r=t.data;if("graph"===t.type){r=r||t.nodes;var a=t.links||t.edges;if(a&&!I(a))for(var o=0;o=0;p--){var g=t[p];if(s||(d=g.data.rawIndexOf(g.stackedByDimension,c)),d>=0){var v=g.data.getByRawIndex(g.stackResultDimension,d);if(h>=0&&v>0||0>=h&&0>v){h+=v,f=v;break}}}return n[0]=h,n[1]=f,n});o.hostModel.setData(l),e.data=l})}function As(t,e){Wo.isInstance(t)||(t=Wo.seriesDataToSource(t)),this._source=t;var i=this._data=t.data,n=t.sourceFormat;n===s_&&(this._offset=0,this._dimSize=e,this._data=i);var r=A_[n===n_?n+"_"+t.seriesLayoutBy:n];o(this,r)}function ks(){return this._data.length}function Ps(t){return this._data[t]}function Ls(t){for(var e=0;ee.outputData.count()&&e.model.getRawData().cloneShallow(e.outputData)}function Ys(t,e){f(t.CHANGABLE_METHODS,function(i){t.wrapMethod(i,_(js,e))})}function js(t){var e=qs(t);e&&e.setOutputEnd(this.count())}function qs(t){var e=(t.ecModel||{}).scheduler,i=e&&e.getPipeline(t.uid);if(i){var n=i.currentTask;if(n){var r=n.agentStubMap;r&&(n=r.get(t.uid))}return n}}function Zs(){this.group=new Dg,this.uid=eo("viewChart"),this.renderTask=Rs({plan:Qs,reset:Js}),this.renderTask.context={view:this}}function Ks(t,e,i){if(t&&(t.trigger(e,i),t.isGroup&&!Ia(t)))for(var n=0,r=t.childCount();r>n;n++)Ks(t.childAt(n),e,i)}function $s(t,e,i){var n=jn(t,e),r=e&&null!=e.highlightKey?Ca(e.highlightKey):null;null!=n?f(Fn(n),function(e){Ks(t.getItemGraphicEl(e),i,r)}):t.eachItemGraphicEl(function(t){Ks(t,i,r)})}function Qs(t){return H_(t.model)}function Js(t){var e=t.model,i=t.ecModel,n=t.api,r=t.payload,a=e.pipelineContext.progressiveRender,o=t.view,s=r&&V_(r).updateMethod,l=a?"incrementalPrepareRender":s&&o[s]?s:"render";return"render"!==l&&o[l](e,i,n,r),U_[l]}function tl(t,e,i){function n(){h=(new Date).getTime(),c=null,t.apply(o,s||[])}var r,a,o,s,l,u=0,h=0,c=null;e=e||0;var d=function(){r=(new Date).getTime(),o=this,s=arguments;var t=l||e,d=l||i;l=null,a=r-(d?u:h)-t,clearTimeout(c),d?c=setTimeout(n,t):a>=0?n():c=setTimeout(n,-a),u=r};return d.clear=function(){c&&(clearTimeout(c),c=null)},d.debounceNextCall=function(t){l=t},d}function el(t,e,i,n){var r=t[e];if(r){var a=r[X_]||r,o=r[j_],s=r[Y_];if(s!==i||o!==n){if(null==i||!n)return t[e]=a;r=t[e]=tl(a,i,"debounce"===n),r[X_]=a,r[j_]=n,r[Y_]=i}return r}}function il(t,e,i,n){this.ecInstance=t,this.api=e,this.unfinished;var i=this._dataProcessorHandlers=i.slice(),n=this._visualHandlers=n.slice();this._allHandlers=i.concat(n),this._stageTaskMap=N()}function nl(t,e,i,n,r){function a(t,e){return t.setDirty&&(!t.dirtyMap||t.dirtyMap.get(e.__pipeline.id))}r=r||{};var o;f(e,function(e){if(!r.visualType||r.visualType===e.visualType){var s=t._stageTaskMap.get(e.uid),l=s.seriesTaskMap,u=s.overallTask;if(u){var h,c=u.agentStubMap;c.each(function(t){a(r,t)&&(t.dirty(),h=!0)}),h&&u.dirty(),tx(u,n);var d=t.getPerformArgs(u,r.block);c.each(function(t){t.perform(d)}),o|=u.perform(d)}else l&&l.each(function(s){a(r,s)&&s.dirty();var l=t.getPerformArgs(s,r.block);l.skip=!e.performRawSeries&&i.isSeriesFiltered(s.context.model),tx(s,n),o|=s.perform(l)})}}),t.unfinished|=o}function rl(t,e,i,n,r){function a(i){var a=i.uid,s=o.get(a)||o.set(a,Rs({plan:hl,reset:cl,count:fl}));s.context={model:i,ecModel:n,api:r,useClearVisual:e.isVisual&&!e.isLayout,plan:e.plan,reset:e.reset,scheduler:t},pl(t,i,s)}var o=i.seriesTaskMap||(i.seriesTaskMap=N()),s=e.seriesType,l=e.getTargetSeries;e.createOnAllSeries?n.eachRawSeries(a):s?n.eachRawSeriesByType(s,a):l&&l(n,r).each(a);var u=t._pipelineMap;o.each(function(t,e){u.get(e)||(t.dispose(),o.removeKey(e))})}function al(t,e,i,n,r){function a(e){var i=e.uid,n=s.get(i);n||(n=s.set(i,Rs({reset:sl,onDirty:ul})),o.dirty()),n.context={model:e,overallProgress:h,modifyOutputEnd:c},n.agent=o,n.__block=h,pl(t,e,n)}var o=i.overallTask=i.overallTask||Rs({reset:ol});o.context={ecModel:n,api:r,overallReset:e.overallReset,scheduler:t};var s=o.agentStubMap=o.agentStubMap||N(),l=e.seriesType,u=e.getTargetSeries,h=!0,c=e.modifyOutputEnd;l?n.eachRawSeriesByType(l,a):u?u(n,r).each(a):(h=!1,f(n.getSeries(),a));var d=t._pipelineMap;s.each(function(t,e){d.get(e)||(t.dispose(),o.dirty(),s.removeKey(e))})}function ol(t){t.overallReset(t.ecModel,t.api,t.payload)}function sl(t){return t.overallProgress&&ll}function ll(){this.agent.dirty(),this.getDownstream().dirty()}function ul(){this.agent&&this.agent.dirty()}function hl(t){return t.plan&&t.plan(t.model,t.ecModel,t.api,t.payload)}function cl(t){t.useClearVisual&&t.data.clearAllVisual();var e=t.resetDefines=Fn(t.reset(t.model,t.ecModel,t.api,t.payload));return e.length>1?p(e,function(t,e){return dl(e)}):ex}function dl(t){return function(e,i){var n=i.data,r=i.resetDefines[t];if(r&&r.dataEach)for(var a=e.start;a0?parseInt(n,10)/100:n?parseFloat(n):0;var r=i.getAttribute("stop-color")||"#000000";e.addColorStop(n,r)}i=i.nextSibling}}function xl(t,e){t&&t.__inheritedStyle&&(e.__inheritedStyle||(e.__inheritedStyle={}),s(e.__inheritedStyle,t.__inheritedStyle))}function wl(t){for(var e=z(t).split(dx),i=[],n=0;n0;a-=2){var o=r[a],s=r[a-1];switch(n=n||Te(),s){case"translate":o=z(o).split(dx),Pe(n,n,[parseFloat(o[0]),parseFloat(o[1]||0)]);break;case"scale":o=z(o).split(dx),Oe(n,n,[parseFloat(o[0]),parseFloat(o[1]||o[0])]);break;case"rotate":o=z(o).split(dx),Le(n,n,parseFloat(o[0]));break;case"skew":o=z(o).split(dx),console.warn("Skew transform is not supported yet");break;case"matrix":var o=z(o).split(dx);n[0]=parseFloat(o[0]),n[1]=parseFloat(o[1]),n[2]=parseFloat(o[2]),n[3]=parseFloat(o[3]),n[4]=parseFloat(o[4]),n[5]=parseFloat(o[5])}}e.setLocalTransform(n)}}function Il(t){var e=t.getAttribute("style"),i={};if(!e)return i;var n={};yx.lastIndex=0;for(var r;null!=(r=yx.exec(e));)n[r[1]]=r[2];for(var a in gx)gx.hasOwnProperty(a)&&null!=n[a]&&(i[gx[a]]=n[a]);return i}function Cl(t,e,i){var n=e/t.width,r=i/t.height,a=Math.min(n,r),o=[a,a],s=[-(t.x+t.width/2)*a+e/2,-(t.y+t.height/2)*a+i/2];return{scale:o,position:s}}function Tl(t,e){return function(i,n,r){(e||!this._disposed)&&(i=i&&i.toLowerCase(),Rp.prototype[t].call(this,i,n,r))}}function Dl(){Rp.call(this)}function Al(t,e,i){function r(t,e){return t.__prio-e.__prio}i=i||{},"string"==typeof e&&(e=ew[e]),this.id,this.group,this._dom=t;var a="canvas",o=this._zr=zn(t,{renderer:i.renderer||a,devicePixelRatio:i.devicePixelRatio,width:i.width,height:i.height});this._throttledZrFlush=tl(y(o.flush,o),17);var e=n(e);e&&C_(e,!0),this._theme=e,this._chartsViews=[],this._chartsMap={},this._componentsViews=[],this._componentsMap={},this._coordSysMgr=new hs;var s=this._api=jl(this);Di(tw,r),Di($x,r),this._scheduler=new il(this,s,$x,tw),Rp.call(this,this._ecEventProcessor=new ql),this._messageCenter=new Dl,this._initEvents(),this.resize=y(this.resize,this),this._pendingActions=[],o.animation.on("frame",this._onframe,this),Rl(o,this),B(this)}function kl(t,e,i){if(!this._disposed){var n,r=this._model,a=this._coordSysMgr.getCoordinateSystems();e=Zn(r,e);for(var o=0;oe.get("hoverLayerThreshold")&&!gp.node&&e.eachSeries(function(e){if(!e.preventUsingHoverLayer){var i=t._chartsMap[e.__viewId];i.__alive&&i.group.traverse(function(t){t.useHoverLayer=!0})}})}function Xl(t,e){var i=t.get("blendMode")||null;e.group.traverse(function(t){t.isGroup||t.style.blend!==i&&t.setStyle("blend",i),t.eachPendingDisplayable&&t.eachPendingDisplayable(function(t){t.setStyle("blend",i)})})}function Yl(t,e){var i=t.get("z"),n=t.get("zlevel");e.group.traverse(function(t){"group"!==t.type&&(null!=i&&(t.z=i),null!=n&&(t.zlevel=n))})}function jl(t){var e=t._coordSysMgr;return o(new us(t),{getCoordinateSystems:y(e.getCoordinateSystems,e),getComponentByElement:function(e){for(;e;){var i=e.__ecComponentInfo;if(null!=i)return t._model.getComponent(i.mainType,i.index);e=e.parent}}})}function ql(){this.eventInfo}function Zl(t){function e(t,e){for(var i=0;i65535?vw:yw}function Du(t){var e=t.constructor;return e===Array?t.slice():new e(t)}function Au(t,e){f(_w.concat(e.__wrappedMethods||[]),function(i){e.hasOwnProperty(i)&&(t[i]=e[i])}),t.__wrappedMethods=e.__wrappedMethods,f(xw,function(i){t[i]=n(e[i])}),t._calculationInfo=o(e._calculationInfo)}function ku(t,e,i,n,r){var a=gw[e.type],o=n-1,s=e.name,l=t[s][o];if(l&&l.lengthc;c+=i)t[s].push(new a(Math.min(r-c,i)))}function Pu(t){var e=t._invertedIndicesMap;f(e,function(i,n){var r=t._dimensionInfos[n],a=r.ordinalMeta;if(a){i=e[n]=new mw(a.categories.length);for(var o=0;o=0?this._indices[t]:-1}function Bu(t,e){var i=t._idList[e];return null==i&&(i=Lu(t,t._idDimIdx,e)),null==i&&(i=pw+e),i}function Eu(t){return x(t)||(t=[t]),t}function Ru(t,e){var i=t.dimensions,n=new ww(p(i,t.getDimensionInfo,t),t.hostModel);Au(n,t);for(var r=n._storage={},a=t._storage,o=0;o=0?(r[s]=Nu(a[s]),n._rawExtent[s]=Fu(),n._extent[s]=null):r[s]=a[s])}return n}function Nu(t){for(var e=new Array(t.length),i=0;ip;p++){var g=a[p]=o({},S(a[p])?a[p]:{name:a[p]}),v=g.name,m=c[p]={otherDims:{}};null!=v&&null==u.get(v)&&(m.name=m.displayName=v,u.set(v,p)),null!=g.type&&(m.type=g.type),null!=g.displayName&&(m.displayName=g.displayName)}l.each(function(t,e){if(t=Fn(t).slice(),1===t.length&&!b(t[0])&&t[0]<0)return void l.set(e,!1);var i=l.set(e,[]);f(t,function(t,n){b(t)&&(t=u.get(t)),null!=t&&d>t&&(i[n]=t,r(c[t],e,n))})});var y=0;f(t,function(t){var e,t,i,a;if(b(t))e=t,t={};else{e=t.name;var o=t.ordinalMeta;t.ordinalMeta=null,t=n(t),t.ordinalMeta=o,i=t.dimsDef,a=t.otherDims,t.name=t.coordDim=t.coordDimIndex=t.dimsDef=t.otherDims=null}var u=l.get(e);if(u!==!1){var u=Fn(u);if(!u.length)for(var h=0;h<(i&&i.length||1);h++){for(;yI;I++){var m=c[I]=c[I]||{},C=m.coordDim;null==C&&(m.coordDim=Hu(M,h,w),m.coordDimIndex=0,(!_||0>=x)&&(m.isExtraCoord=!0),x--),null==m.name&&(m.name=Hu(m.coordDim,u)),null==m.type&&ts(e,I,m.name)&&(m.type="ordinal")}return c}function Vu(t,e,i,n){var r=Math.max(t.dimensionsDetectCount||1,e.length,i.length,n||0);return f(e,function(t){var e=t.dimsDef;e&&(r=Math.max(r,e.length))}),r}function Hu(t,e,i){if(i||null!=e.get(t)){for(var n=0;null!=e.get(t+n);)n++;t+=n}return e.set(t,!0),t}function Wu(t,e,i){i=i||{};var n,r,a,o,s=i.byIndex,l=i.stackedCoordDimension,u=!(!t||!t.get("stack"));if(f(e,function(t,i){b(t)&&(e[i]=t={name:t}),u&&!t.isExtraCoord&&(s||n||!t.ordinalMeta||(n=t),r||"ordinal"===t.type||"time"===t.type||l&&l!==t.coordDim||(r=t))}),!r||s||n||(s=!0),r){a="__\x00ecstackresult",o="__\x00ecstackedover",n&&(n.createInvertedIndices=!0);var h=r.coordDim,c=r.type,d=0;f(e,function(t){t.coordDim===h&&d++}),e.push({name:a,coordDim:h,coordDimIndex:d,type:c,isExtraCoord:!0,isCalculationCoord:!0}),d++,e.push({name:o,coordDim:o,coordDimIndex:d,type:c,isExtraCoord:!0,isCalculationCoord:!0})}return{stackedDimension:r&&r.name,stackedByDimension:n&&n.name,isStackedByIndex:s,stackedOverDimension:o,stackResultDimension:a}}function Uu(t,e){return!!e&&e===t.getCalculationInfo("stackedDimension")}function Xu(t,e){return Uu(t,e)?t.getCalculationInfo("stackResultDimension"):e}function Yu(t,e,i){i=i||{},Wo.isInstance(t)||(t=Wo.seriesDataToSource(t));var n,r=e.get("coordinateSystem"),a=hs.get(r),o=Vo(e);o&&(n=p(o.coordSysDims,function(t){var e={name:t},i=o.axisMap.get(t);if(i){var n=i.get("type");e.type=Iu(n)}return e})),n||(n=a&&(a.getDimensionsInfo?a.getDimensionsInfo():a.dimensions.slice())||["x","y"]);var s,l,u=Mw(t,{coordDimensions:n,generateCoord:i.generateCoord});o&&f(u,function(t,e){var i=t.coordDim,n=o.categoryAxisMap.get(i);n&&(null==s&&(s=e),t.ordinalMeta=n.getOrdinalMeta()),null!=t.otherDims.itemName&&(l=!0)}),l||null==s||(u[s].otherDims.itemName=0);var h=Wu(e,u),c=new ww(u,e);c.setCalculationInfo(h);var d=null!=s&&ju(t)?function(t,e,i,n){return n===s?i:this.defaultDimValueGetter(t,e,i,n)}:null;return c.hasItemOption=!1,c.initData(t,null,d),c}function ju(t){if(t.sourceFormat===i_){var e=qu(t.data||[]);return null!=e&&!x(Vn(e))}}function qu(t){for(var e=0;eo&&(o=r.interval=i),null!=n&&o>n&&(o=r.interval=n);var s=r.intervalPrecision=th(o),l=r.niceTickExtent=[Dw(Math.ceil(t[0]/o)*o,s),Dw(Math.floor(t[1]/o)*o,s)];return ih(l,t),r}function th(t){return ho(t)+2}function eh(t,e,i){t[e]=Math.max(Math.min(t[e],i[1]),i[0])}function ih(t,e){!isFinite(t[0])&&(t[0]=e[0]),!isFinite(t[1])&&(t[1]=e[1]),eh(t,0,e),eh(t,1,e),t[0]>t[1]&&(t[0]=t[1])}function nh(t,e,i,n){var r=[];if(!t)return r;var a=1e4;e[0]a)return[];return e[1]>(r.length?r[r.length-1]:i[1])&&r.push(e[1]),r}function rh(t){return t.get("stack")||Pw+t.seriesIndex}function ah(t){return t.dim+t.index}function oh(t,e){var i=[];return e.eachSeriesByType(t,function(t){ch(t)&&!dh(t)&&i.push(t)}),i}function sh(t){var e={};f(t,function(t){var i=t.coordinateSystem,n=i.getBaseAxis();if("time"===n.type||"value"===n.type)for(var r=t.getData(),a=n.dim+"_"+n.index,o=r.mapDimension(n.dim),s=0,l=r.count();l>s;++s){var u=r.get(o,s);e[a]?e[a].push(u):e[a]=[u]}});var i=[];for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];if(r){r.sort(function(t,e){return t-e});for(var a=null,o=1;o0&&(a=null===a?s:Math.min(a,s))}i[n]=a}}return i}function lh(t){var e=sh(t),i=[];return f(t,function(t){var n,r=t.coordinateSystem,a=r.getBaseAxis(),o=a.getExtent();if("category"===a.type)n=a.getBandWidth();else if("value"===a.type||"time"===a.type){var s=a.dim+"_"+a.index,l=e[s],u=Math.abs(o[1]-o[0]),h=a.scale.getExtent(),c=Math.abs(h[1]-h[0]);n=l?u/c*l:u}else{var d=t.getData();n=Math.abs(o[1]-o[0])/d.count()}var f=oo(t.get("barWidth"),n),p=oo(t.get("barMaxWidth"),n),g=oo(t.get("barMinWidth")||1,n),v=t.get("barGap"),m=t.get("barCategoryGap");i.push({bandWidth:n,barWidth:f,barMaxWidth:p,barMinWidth:g,barGap:v,barCategoryGap:m,axisKey:ah(a),stackId:rh(t)})}),uh(i)}function uh(t){var e={};f(t,function(t){var i=t.axisKey,n=t.bandWidth,r=e[i]||{bandWidth:n,remainedWidth:n,autoWidthCount:0,categoryGap:"20%",gap:"30%",stacks:{}},a=r.stacks;e[i]=r;var o=t.stackId;a[o]||r.autoWidthCount++,a[o]=a[o]||{width:0,maxWidth:0};var s=t.barWidth;s&&!a[o].width&&(a[o].width=s,s=Math.min(r.remainedWidth,s),r.remainedWidth-=s);var l=t.barMaxWidth;l&&(a[o].maxWidth=l);var u=t.barMinWidth;u&&(a[o].minWidth=u);var h=t.barGap;null!=h&&(r.gap=h);var c=t.barCategoryGap;null!=c&&(r.categoryGap=c)});var i={};return f(e,function(t,e){i[e]={};var n=t.stacks,r=t.bandWidth,a=oo(t.categoryGap,r),o=oo(t.gap,1),s=t.remainedWidth,l=t.autoWidthCount,u=(s-a)/(l+(l-1)*o);u=Math.max(u,0),f(n,function(t){var e=t.maxWidth,i=t.minWidth;if(t.width){var n=t.width;e&&(n=Math.min(n,e)),i&&(n=Math.max(n,i)),t.width=n,s-=n,l--}else{var n=u;e&&n>e&&(n=Math.min(e,s)),i&&i>n&&(n=i),n!==u&&(t.width=n,s-=n,l--)}}),u=(s-a)/(l+(l-1)*o),u=Math.max(u,0);var h,c=0;f(n,function(t){t.width||(t.width=u),h=t,c+=t.width*(1+o)}),h&&(c-=h.width*o);var d=-c/2;f(n,function(t,n){i[e][n]=i[e][n]||{bandWidth:r,offset:d,width:t.width},d+=t.width*(1+o)})}),i}function hh(t,e,i){if(t&&e){var n=t[ah(e)];return null!=n&&null!=i&&(n=n[rh(i)]),n}}function ch(t){return t.coordinateSystem&&"cartesian2d"===t.coordinateSystem.type}function dh(t){return t.pipelineContext&&t.pipelineContext.large}function fh(t,e){return e.toGlobalCoord(e.dataToCoord("log"===e.type?1:0))}function ph(t,e){return jw(t,Yw(e))}function gh(t,e){var i,n,r,a=t.type,o=e.getMin(),s=e.getMax(),l=null!=o,u=null!=s,h=t.getExtent();"ordinal"===a?i=e.getCategories().length:(n=e.get("boundaryGap"),x(n)||(n=[n||0,n||0]),"boolean"==typeof n[0]&&(n=[0,0]),n[0]=oo(n[0],1),n[1]=oo(n[1],1),r=h[1]-h[0]||Math.abs(h[0])),null==o&&(o="ordinal"===a?i?0:0/0:h[0]-n[0]*r),null==s&&(s="ordinal"===a?i?i-1:0/0:h[1]+n[1]*r),"dataMin"===o?o=h[0]:"function"==typeof o&&(o=o({min:h[0],max:h[1]})),"dataMax"===s?s=h[1]:"function"==typeof s&&(s=s({min:h[0],max:h[1]})),(null==o||!isFinite(o))&&(o=0/0),(null==s||!isFinite(s))&&(s=0/0),t.setBlank(T(o)||T(s)||"ordinal"===a&&!t.getOrdinalMeta().categories.length),e.getNeedCrossZero()&&(o>0&&s>0&&!l&&(o=0),0>o&&0>s&&!u&&(s=0));var c=e.ecModel;if(c&&"time"===a){var d,p=oh("bar",c);if(f(p,function(t){d|=t.getBaseAxis()===e.axis}),d){var g=lh(p),v=vh(o,s,e,g);o=v.min,s=v.max}}return[o,s]}function vh(t,e,i,n){var r=i.axis.getExtent(),a=r[1]-r[0],o=hh(n,i.axis);if(void 0===o)return{min:t,max:e};var s=1/0;f(o,function(t){s=Math.min(t.offset,s)});var l=-1/0;f(o,function(t){l=Math.max(t.offset+t.width,l)}),s=Math.abs(s),l=Math.abs(l);var u=s+l,h=e-t,c=1-(s+l)/a,d=h/c-h;return e+=d*(l/u),t-=d*(s/u),{min:t,max:e}}function mh(t,e){var i=gh(t,e),n=null!=e.getMin(),r=null!=e.getMax(),a=e.get("splitNumber");"log"===t.type&&(t.base=e.get("logBase"));var o=t.type;t.setExtent(i[0],i[1]),t.niceExtent({splitNumber:a,fixMin:n,fixMax:r,minInterval:"interval"===o||"time"===o?e.get("minInterval"):null,maxInterval:"interval"===o||"time"===o?e.get("maxInterval"):null});var s=e.get("interval");null!=s&&t.setInterval&&t.setInterval(s)}function yh(t,e){if(e=e||t.get("type"))switch(e){case"category":return new Tw(t.getOrdinalMeta?t.getOrdinalMeta():t.getCategories(),[1/0,-1/0]);case"value":return new kw;default:return(Zu.getClass(e)||kw).create(t)}}function _h(t){var e=t.scale.getExtent(),i=e[0],n=e[1];return!(i>0&&n>0||0>i&&0>n)}function xh(t){var e=t.getLabelModel().get("formatter"),i="category"===t.type?t.scale.getExtent()[0]:null;return"string"==typeof e?e=function(e){return function(i){return i=t.scale.getLabel(i),e.replace("{value}",null!=i?i:"")}}(e):"function"==typeof e?function(n,r){return null!=i&&(r=n-i),e(wh(t,n),r)}:function(e){return t.scale.getLabel(e)}}function wh(t,e){return"category"===t.type?t.scale.getLabel(e):e}function bh(t){var e=t.model,i=t.scale;if(e.get("axisLabel.show")&&!i.isBlank()){var n,r,a="category"===t.type,o=i.getExtent();a?r=i.count():(n=i.getTicks(),r=n.length);var s,l=t.getLabelModel(),u=xh(t),h=1;r>40&&(h=Math.ceil(r/40));for(var c=0;r>c;c+=h){var d=n?n[c]:o[0]+c,f=u(d),p=l.getTextRect(f),g=Sh(p,l.get("rotate")||0);s?s.union(g):s=g}return s}}function Sh(t,e){var i=e*Math.PI/180,n=t.plain(),r=n.width,a=n.height,o=r*Math.cos(i)+a*Math.sin(i),s=r*Math.sin(i)+a*Math.cos(i),l=new xi(n.x,n.y,o,s);return l}function Mh(t){var e=t.get("interval");return null==e?"auto":e}function Ih(t){return"category"===t.type&&0===Mh(t.getLabelModel())}function Ch(t,e){if("image"!==this.type){var i=this.style,n=this.shape;n&&"line"===n.symbolType?i.stroke=t:this.__isEmptyBrush?(i.stroke=t,i.fill=e||"#fff"):(i.fill&&(i.fill=t),i.stroke&&(i.stroke=t)),this.dirty(!1)}}function Th(t,e,i,n,r,a,o){var s=0===t.indexOf("empty");s&&(t=t.substr(5,1).toLowerCase()+t.substr(6));var l;return l=0===t.indexOf("image://")?aa(t.slice(8),new xi(e,i,n,r),o?"center":"cover"):0===t.indexOf("path://")?ra(t.slice(7),{},new xi(e,i,n,r),o?"center":"cover"):new sb({shape:{symbolType:t,x:e,y:i,width:n,height:r}}),l.__isEmptyBrush=s,l.setColor=Ch,l.setColor(a),l}function Dh(t){return Yu(t.getSource(),t)}function Ah(t,e){var i=e;Qa.isInstance(e)||(i=new Qa(e),c(i,Jw));var n=yh(i);return n.setExtent(t[0],t[1]),mh(n,i),n}function kh(t){c(t,Jw)}function Ph(t,e){return Math.abs(t-e)>1^-(1&s),l=l>>1^-(1&l),s+=r,l+=a,r=s,a=l,n.push([s/i,l/i])}return n}function Eh(t){return"category"===t.type?Nh(t):Vh(t)}function Rh(t,e){return"category"===t.type?Gh(t,e):{ticks:t.scale.getTicks()}}function Nh(t){var e=t.getLabelModel(),i=Fh(t,e);return!e.get("show")||t.scale.isBlank()?{labels:[],labelCategoryInterval:i.labelCategoryInterval}:i}function Fh(t,e){var i=Hh(t,"labels"),n=Mh(e),r=Wh(i,n);if(r)return r;var a,o;return w(n)?a=Zh(t,n):(o="auto"===n?Xh(t):n,a=qh(t,o)),Uh(i,n,{labels:a,labelCategoryInterval:o})}function Gh(t,e){var i=Hh(t,"ticks"),n=Mh(e),r=Wh(i,n);if(r)return r;var a,o;if((!e.get("show")||t.scale.isBlank())&&(a=[]),w(n))a=Zh(t,n,!0);else if("auto"===n){var s=Fh(t,t.getLabelModel());o=s.labelCategoryInterval,a=p(s.labels,function(t){return t.tickValue})}else o=n,a=qh(t,o,!0);return Uh(i,n,{ticks:a,tickCategoryInterval:o})}function Vh(t){var e=t.scale.getTicks(),i=xh(t);return{labels:p(e,function(e,n){return{formattedLabel:i(e,n),rawLabel:t.scale.getLabel(e),tickValue:e}})}}function Hh(t,e){return db(t)[e]||(db(t)[e]=[])}function Wh(t,e){for(var i=0;i40&&(s=Math.max(1,Math.floor(o/40)));for(var l=a[0],u=t.dataToCoord(l+1)-t.dataToCoord(l),h=Math.abs(u*Math.cos(n)),c=Math.abs(u*Math.sin(n)),d=0,f=0;l<=a[1];l+=s){var p=0,g=0,v=Fi(i(l),e.font,"center","top");p=1.3*v.width,g=1.3*v.height,d=Math.max(d,p,7),f=Math.max(f,g,7)}var m=d/h,y=f/c;isNaN(m)&&(m=1/0),isNaN(y)&&(y=1/0);var _=Math.max(0,Math.floor(Math.min(m,y))),x=db(t.model),w=t.getExtent(),b=x.lastAutoInterval,S=x.lastTickCount;return null!=b&&null!=S&&Math.abs(b-_)<=1&&Math.abs(S-o)<=1&&b>_&&x.axisExtend0===w[0]&&x.axisExtend1===w[1]?_=b:(x.lastTickCount=o,x.lastAutoInterval=_,x.axisExtend0=w[0],x.axisExtend1=w[1]),_}function jh(t){var e=t.getLabelModel();return{axisRotate:t.getRotate?t.getRotate():t.isHorizontal&&!t.isHorizontal()?90:0,labelRotate:e.get("rotate")||0,font:e.getFont()}}function qh(t,e,i){function n(t){l.push(i?t:{formattedLabel:r(t),rawLabel:a.getLabel(t),tickValue:t})}var r=xh(t),a=t.scale,o=a.getExtent(),s=t.getLabelModel(),l=[],u=Math.max((e||0)+1,1),h=o[0],c=a.count();0!==h&&u>1&&c/u>2&&(h=Math.round(Math.ceil(h/u)*u));var d=Ih(t),f=s.get("showMinLabel")||d,p=s.get("showMaxLabel")||d;f&&h!==o[0]&&n(o[0]);for(var g=h;g<=o[1];g+=u)n(g);return p&&g-u!==o[1]&&n(o[1]),l}function Zh(t,e,i){var n=t.scale,r=xh(t),a=[];return f(n.getTicks(),function(t){var o=n.getLabel(t);e(t,o)&&a.push(i?t:{formattedLabel:r(t),rawLabel:o,tickValue:t})}),a}function Kh(t,e){var i=t[1]-t[0],n=e,r=i/n/2;t[0]+=r,t[1]-=r}function $h(t,e,i,n){function r(t,e){return t=so(t),e=so(e),d?t>e:e>t}var a=e.length;if(t.onBand&&!i&&a){var o,s,l=t.getExtent();if(1===a)e[0].coord=l[0],o=e[1]={coord:l[0]};else{var u=e[a-1].tickValue-e[0].tickValue,h=(e[a-1].coord-e[0].coord)/u;f(e,function(t){t.coord-=h/2});var c=t.scale.getExtent();s=1+c[1]-e[a-1].tickValue,o={coord:e[a-1].coord+h*s},e.push(o)}var d=l[0]>l[1];r(e[0].coord,l[0])&&(n?e[0].coord=l[0]:e.shift()),n&&r(l[0],e[0].coord)&&e.unshift({coord:l[0]}),r(l[1],o.coord)&&(n?o.coord=l[1]:e.pop()),n&&r(o.coord,l[1])&&e.push({coord:l[1]})}}function Qh(t,e){var i=t.mapDimension("defaultedLabel",!0),n=i.length;if(1===n)return Es(t,e,i[0]);if(n){for(var r=[],a=0;a0?i=n[0]:n[1]<0&&(i=n[1]),i}function uc(t,e,i,n){var r=0/0;t.stacked&&(r=i.get(i.getCalculationInfo("stackedOverDimension"),n)),isNaN(r)&&(r=t.valueStart);var a=t.baseDataOffset,o=[];return o[a]=i.get(t.baseDim,n),o[1-a]=r,e.dataToPoint(o)}function hc(t,e){var i=[];return e.diff(t).add(function(t){i.push({cmd:"+",idx:t})}).update(function(t,e){i.push({cmd:"=",idx:e,idx1:t})}).remove(function(t){i.push({cmd:"-",idx:t})}).execute(),i}function cc(t){return isNaN(t[0])||isNaN(t[1])}function dc(t,e,i,n,r,a,o,s,l,u){return"none"!==u&&u?fc.apply(this,arguments):pc.apply(this,arguments)}function fc(t,e,i,n,r,a,o,s,l,u,h){for(var c=0,d=i,f=0;n>f;f++){var p=e[d];if(d>=r||0>d)break;if(cc(p)){if(h){d+=a;continue}break}if(d===i)t[a>0?"moveTo":"lineTo"](p[0],p[1]);else if(l>0){var g=e[c],v="y"===u?1:0,m=(p[v]-g[v])*l;Ab(Pb,g),Pb[v]=g[v]+m,Ab(Lb,p),Lb[v]=p[v]-m,t.bezierCurveTo(Pb[0],Pb[1],Lb[0],Lb[1],p[0],p[1])}else t.lineTo(p[0],p[1]);c=d,d+=a}return f}function pc(t,e,i,n,r,a,o,s,l,u,h){for(var c=0,d=i,f=0;n>f;f++){var p=e[d];if(d>=r||0>d)break;if(cc(p)){if(h){d+=a;continue}break}if(d===i)t[a>0?"moveTo":"lineTo"](p[0],p[1]),Ab(Pb,p);else if(l>0){var g=d+a,v=e[g];if(h)for(;v&&cc(e[g]);)g+=a,v=e[g];var m=.5,y=e[c],v=e[g];if(!v||cc(v))Ab(Lb,p);else{cc(v)&&!h&&(v=p),j(kb,v,y);var _,x;if("x"===u||"y"===u){var w="x"===u?0:1;_=Math.abs(p[w]-y[w]),x=Math.abs(p[w]-v[w])}else _=Op(p,y),x=Op(p,v);m=x/(x+_),Db(Lb,p,kb,-l*(1-m))}Cb(Pb,Pb,s),Tb(Pb,Pb,o),Cb(Lb,Lb,s),Tb(Lb,Lb,o),t.bezierCurveTo(Pb[0],Pb[1],Lb[0],Lb[1],p[0],p[1]),Db(Pb,p,kb,l*m)}else t.lineTo(p[0],p[1]);c=d,d+=a}return f}function gc(t,e){var i=[1/0,1/0],n=[-1/0,-1/0];if(e)for(var r=0;rn[0]&&(n[0]=a[0]),a[1]>n[1]&&(n[1]=a[1])}return{min:e?i:n,max:e?n:i}}function vc(t,e,i){var n=t.getArea(),r=t.getBaseAxis().isHorizontal(),a=n.x,o=n.y,s=n.width,l=n.height,u=i.get("lineStyle.width")||2;a-=u/2,o-=u/2,s+=u,l+=u;var h=new ty({shape:{x:a,y:o,width:s,height:l}});return e&&(h.shape[r?"width":"height"]=0,Ga(h,{shape:{width:s,height:l}},i)),h}function mc(t,e,i){var n=t.getArea(),r=new Ym({shape:{cx:so(t.cx,1),cy:so(t.cy,1),r0:so(n.r0,1),r:so(n.r,1),startAngle:n.startAngle,endAngle:n.endAngle,clockwise:n.clockwise}});return e&&(r.shape.endAngle=n.startAngle,Ga(r,{shape:{endAngle:n.endAngle}},i)),r}function yc(t,e){if(t.length===e.length){for(var i=0;ir;r++)n.push(uc(i,t,e,r));return n}function wc(t,e,i){for(var n=e.getBaseAxis(),r="x"===n.dim||"radius"===n.dim?0:1,a=[],o=0;o=0;a--){var o=i[a].dimension,s=t.dimensions[o],l=t.getDimensionInfo(s);if(n=l&&l.coordDim,"x"===n||"y"===n){r=i[a];break}}if(r){var u=e.getAxis(n),h=p(r.stops,function(t){return{coord:u.toGlobalCoord(u.dataToCoord(t.value)),color:t.color}}),c=h.length,d=r.outerColors.slice();c&&h[0].coord>h[c-1].coord&&(h.reverse(),d.reverse());var g=10,v=h[0].coord-g,m=h[c-1].coord+g,y=m-v;if(.001>y)return"transparent";f(h,function(t){t.offset=(t.coord-v)/y}),h.push({offset:c?h[c-1].offset:.5,color:d[1]||"transparent"}),h.unshift({offset:c?h[0].offset:.5,color:d[0]||"transparent"});var _=new ly(0,0,0,0,h,!0);return _[n]=v,_[n+"2"]=m,_}}}function Sc(t,e,i){var n=t.get("showAllSymbol"),r="auto"===n;if(!n||r){var a=i.getAxesByScale("ordinal")[0];if(a&&(!r||!Mc(a,e))){var o=e.mapDimension(a.dim),s={};return f(a.getViewLabels(),function(t){s[t.tickValue]=1}),function(t){return!s.hasOwnProperty(e.get(o,t))}}}}function Mc(t,e){var i=t.getExtent(),n=Math.abs(i[1]-i[0])/t.scale.count();isNaN(n)&&(n=0);for(var r=e.count(),a=Math.max(1,Math.round(r/5)),o=0;r>o;o+=a)if(1.5*Jh.getSymbolSize(e,o)[t.isHorizontal()?1:0]>n)return!1;return!0}function Ic(t,e,i){if("cartesian2d"===t.type){var n=t.getBaseAxis().isHorizontal(),r=vc(t,e,i);if(!i.get("clip",!0)){var a=r.shape,o=Math.max(a.width,a.height);n?(a.y-=o,a.height+=2*o):(a.x-=o,a.width+=2*o)}return r}return mc(t,e,i)}function Cc(t){return this._axes[t]}function Tc(t){Gb.call(this,t)}function Dc(t,e){return e.type||(e.data?"category":"value")}function Ac(t,e){return t.getCoordSysModel()===e}function kc(t,e,i){this._coordsMap={},this._coordsList=[],this._axesMap={},this._axesList=[],this._initCartesian(t,e,i),this.model=t}function Pc(t,e,i,n){function r(t){return t.dim+"_"+t.index}i.getAxesOnZeroOf=function(){return a?[a]:[]};var a,o=t[e],s=i.model,l=s.get("axisLine.onZero"),u=s.get("axisLine.onZeroAxisIndex");if(l){if(null!=u)Lc(o[u])&&(a=o[u]);else for(var h in o)if(o.hasOwnProperty(h)&&Lc(o[h])&&!n[r(o[h])]){a=o[h];break}a&&(n[r(a)]=!0)}}function Lc(t){return t&&"category"!==t.type&&"time"!==t.type&&_h(t)}function Oc(t,e){var i=t.getExtent(),n=i[0]+i[1];t.toGlobalCoord="x"===t.dim?function(t){return t+e}:function(t){return n-t+e},t.toLocalCoord="x"===t.dim?function(t){return t-e}:function(t){return n-t+e}}function zc(t){return p(Zb,function(e){var i=t.getReferringComponents(e)[0];return i})}function Bc(t){return"cartesian2d"===t.get("coordinateSystem")}function Ec(t,e,i,n){var r,a,o=po(i-t.rotation),s=n[0]>n[1],l="start"===e&&!s||"start"!==e&&s;return go(o-Kb/2)?(a=l?"bottom":"top",r="center"):go(o-1.5*Kb)?(a=l?"top":"bottom",r="center"):(a="middle",r=1.5*Kb>o&&o>Kb/2?l?"left":"right":l?"right":"left"),{rotation:o,textAlign:r,textVerticalAlign:a}}function Rc(t,e,i){if(!Ih(t.axis)){var n=t.get("axisLabel.showMinLabel"),r=t.get("axisLabel.showMaxLabel");e=e||[],i=i||[];var a=e[0],o=e[1],s=e[e.length-1],l=e[e.length-2],u=i[0],h=i[1],c=i[i.length-1],d=i[i.length-2];n===!1?(Nc(a),Nc(u)):Fc(a,o)&&(n?(Nc(o),Nc(h)):(Nc(a),Nc(u))),r===!1?(Nc(s),Nc(c)):Fc(l,s)&&(r?(Nc(l),Nc(d)):(Nc(s),Nc(c)))}}function Nc(t){t&&(t.ignore=!0)}function Fc(t,e){var i=t&&t.getBoundingRect().clone(),n=e&&e.getBoundingRect().clone();if(i&&n){var r=De([]);return Le(r,r,-t.rotation),i.applyTransform(ke([],r,t.getLocalTransform())),n.applyTransform(ke([],r,e.getLocalTransform())),i.intersect(n)}}function Gc(t){return"middle"===t||"center"===t}function Vc(t,e,i){var n=e.axis;if(e.get("axisTick.show")&&!n.scale.isBlank()){for(var r=e.getModel("axisTick"),a=r.getModel("lineStyle"),o=r.get("length"),l=n.getTicksCoords(),u=[],h=[],c=t._transform,d=[],f=0;f=0||t===e}function Zc(t){var e=Kc(t);if(e){var i=e.axisPointerModel,n=e.axis.scale,r=i.option,a=i.get("status"),o=i.get("value");null!=o&&(o=n.parse(o));var s=Qc(i);null==a&&(r.status=s?"show":"hide");var l=n.getExtent().slice();l[0]>l[1]&&l.reverse(),(null==o||o>l[1])&&(o=l[1]),o=f&&((o>f||d>=0&&0>s)&&(o=f,s=d,r=l,a.length=0),SS(u,function(t){a.push({seriesIndex:e.seriesIndex,dataIndexInside:t,dataIndex:e.getData().getRawIndex(t)})}))}}),{payloadBatch:a,snapToValue:r}}function dd(t,e,i,n){t[e.key]={value:i,payloadBatch:n}}function fd(t,e,i,n){var r=i.payloadBatch,a=e.axis,o=a.model,s=e.axisPointerModel;if(e.triggerTooltip&&r.length){var l=e.coordSys.model,u=Jc(l),h=t.map[u];h||(h=t.map[u]={coordSysId:l.id,coordSysIndex:l.componentIndex,coordSysType:l.type,coordSysMainType:l.mainType,dataByAxis:[]},t.list.push(h)),h.dataByAxis.push({axisDim:a.dim,axisIndex:o.componentIndex,axisType:o.type,axisId:o.id,value:n,valueLabelOpt:{precision:s.get("label.precision"),formatter:s.get("label.formatter")},seriesDataIndices:r.slice()})}}function pd(t,e,i){var n=i.axesInfo=[];SS(e,function(e,i){var r=e.axisPointerModel.option,a=t[i];a?(!e.useHandle&&(r.status="show"),r.value=a.value,r.seriesDataIndices=(a.payloadBatch||[]).slice()):!e.useHandle&&(r.status="hide"),"show"===r.status&&n.push({axisDim:e.axis.dim,axisIndex:e.axis.model.componentIndex,value:r.value})})}function gd(t,e,i,n){if(_d(e)||!t.list.length)return void n({type:"hideTip"});var r=((t.list[0].dataByAxis[0]||{}).seriesDataIndices||[])[0]||{};n({type:"showTip",escapeConnect:!0,x:e[0],y:e[1],tooltipOption:i.tooltipOption,position:i.position,dataIndexInside:r.dataIndexInside,dataIndex:r.dataIndex,seriesIndex:r.seriesIndex,dataByCoordSys:t.list})}function vd(t,e,i){var n=i.getZr(),r="axisPointerLastHighlights",a=IS(n)[r]||{},o=IS(n)[r]={};SS(t,function(t){var e=t.axisPointerModel.option;"show"===e.status&&SS(e.seriesDataIndices,function(t){var e=t.seriesIndex+" | "+t.dataIndex;o[e]=t})});var s=[],l=[];f(a,function(t,e){!o[e]&&l.push(t)}),f(o,function(t,e){!a[e]&&s.push(t)}),l.length&&i.dispatchAction({type:"downplay",escapeConnect:!0,batch:l}),s.length&&i.dispatchAction({type:"highlight",escapeConnect:!0,batch:s})}function md(t,e){for(var i=0;i<(t||[]).length;i++){var n=t[i];if(e.axis.dim===n.axisDim&&e.axis.model.componentIndex===n.axisIndex)return n}}function yd(t){var e=t.axis.model,i={},n=i.axisDim=t.axis.dim;return i.axisIndex=i[n+"AxisIndex"]=e.componentIndex,i.axisName=i[n+"AxisName"]=e.name,i.axisId=i[n+"AxisId"]=e.id,i}function _d(t){return!t||null==t[0]||isNaN(t[0])||null==t[1]||isNaN(t[1])}function xd(t,e,i){if(!gp.node){var n=e.getZr();TS(n).records||(TS(n).records={}),wd(n,e);var r=TS(n).records[t]||(TS(n).records[t]={});r.handler=i}}function wd(t,e){function i(i,n){t.on(i,function(i){var r=Id(e);DS(TS(t).records,function(t){t&&n(t,i,r.dispatchAction)}),bd(r.pendings,e)})}TS(t).initialized||(TS(t).initialized=!0,i("click",_(Md,"click")),i("mousemove",_(Md,"mousemove")),i("globalout",Sd))}function bd(t,e){var i,n=t.showTip.length,r=t.hideTip.length;n?i=t.showTip[n-1]:r&&(i=t.hideTip[r-1]),i&&(i.dispatchAction=null,e.dispatchAction(i))}function Sd(t,e,i){t.handler("leave",null,i)}function Md(t,e,i,n){e.handler(t,i,n)}function Id(t){var e={showTip:[],hideTip:[]},i=function(n){var r=e[n.type];r?r.push(n):(n.dispatchAction=i,t.dispatchAction(n))};return{dispatchAction:i,pendings:e}}function Cd(t,e){if(!gp.node){var i=e.getZr(),n=(TS(i).records||{})[t];n&&(TS(i).records[t]=null)}}function Td(){}function Dd(t,e,i,n){Ad(kS(i).lastProp,n)||(kS(i).lastProp=n,e?Fa(i,n,t):(i.stopAnimation(),i.attr(n)))}function Ad(t,e){if(S(t)&&S(e)){var i=!0;return f(e,function(e,n){i=i&&Ad(t[n],e)}),!!i}return t===e}function kd(t,e){t[e.get("label.show")?"show":"hide"]()}function Pd(t){return{position:t.position.slice(),rotation:t.rotation||0}}function Ld(t,e,i){var n=e.get("z"),r=e.get("zlevel");t&&t.traverse(function(t){"group"!==t.type&&(null!=n&&(t.z=n),null!=r&&(t.zlevel=r),t.silent=i)})}function Od(t){var e,i=t.get("type"),n=t.getModel(i+"Style");return"line"===i?(e=n.getLineStyle(),e.fill=null):"shadow"===i&&(e=n.getAreaStyle(),e.stroke=null),e}function zd(t,e,i,n,r){var a=i.get("value"),o=Ed(a,e.axis,e.ecModel,i.get("seriesDataIndices"),{precision:i.get("label.precision"),formatter:i.get("label.formatter")}),s=i.getModel("label"),l=Ry(s.get("padding")||0),u=s.getFont(),h=Fi(o,u),c=r.position,d=h.width+l[1]+l[3],f=h.height+l[0]+l[2],p=r.align;"right"===p&&(c[0]-=d),"center"===p&&(c[0]-=d/2);var g=r.verticalAlign;"bottom"===g&&(c[1]-=f),"middle"===g&&(c[1]-=f/2),Bd(c,d,f,n);var v=s.get("backgroundColor");v&&"auto"!==v||(v=e.get("axisLine.lineStyle.color")),t.label={shape:{x:0,y:0,width:d,height:f,r:s.get("borderRadius")},position:c.slice(),style:{text:o,textFont:u,textFill:s.getTextColor(),textPosition:"inside",textPadding:l,fill:v,stroke:s.get("borderColor")||"transparent",lineWidth:s.get("borderWidth")||0,shadowBlur:s.get("shadowBlur"),shadowColor:s.get("shadowColor"),shadowOffsetX:s.get("shadowOffsetX"),shadowOffsetY:s.get("shadowOffsetY")},z2:10}}function Bd(t,e,i,n){var r=n.getWidth(),a=n.getHeight();t[0]=Math.min(t[0]+e,r)-e,t[1]=Math.min(t[1]+i,a)-i,t[0]=Math.max(t[0],0),t[1]=Math.max(t[1],0)}function Ed(t,e,i,n,r){t=e.scale.parse(t);var a=e.scale.getLabel(t,{precision:r.precision}),o=r.formatter;if(o){var s={value:wh(e,t),axisDimension:e.dim,axisIndex:e.index,seriesData:[]};f(n,function(t){var e=i.getSeriesByIndex(t.seriesIndex),n=t.dataIndexInside,r=e&&e.getDataParams(n);r&&s.seriesData.push(r)}),b(o)?a=o.replace("{value}",a):w(o)&&(a=o(s))}return a}function Rd(t,e,i){var n=Te();return Le(n,n,i.rotation),Pe(n,n,i.position),Ha([t.dataToCoord(e),(i.labelOffset||0)+(i.labelDirection||1)*(i.labelMargin||0)],n)}function Nd(t,e,i,n,r,a){var o=$b.innerTextLayout(i.rotation,0,i.labelDirection);i.labelMargin=r.get("label.margin"),zd(e,n,r,a,{position:Rd(n.axis,t,i),align:o.textAlign,verticalAlign:o.textVerticalAlign})}function Fd(t,e,i){return i=i||0,{x1:t[i],y1:t[1-i],x2:e[i],y2:e[1-i]}}function Gd(t,e,i){return i=i||0,{x:t[i],y:t[1-i],width:e[i],height:e[1-i]}}function Vd(t,e){var i={};return i[e.dim+"AxisIndex"]=e.index,t.getCartesian(i)}function Hd(t){return"x"===t.dim?0:1}function Wd(t){var e="cubic-bezier(0.23, 1, 0.32, 1)",i="left "+t+"s "+e+",top "+t+"s "+e;return p(RS,function(t){return t+"transition:"+i}).join(";")}function Ud(t){var e=[],i=t.get("fontSize"),n=t.getTextColor();return n&&e.push("color:"+n),e.push("font:"+t.getFont()),i&&e.push("line-height:"+Math.round(3*i/2)+"px"),BS(["decoration","align"],function(i){var n=t.get(i);n&&e.push("text-"+i+":"+n)}),e.join(";")}function Xd(t){var e=[],i=t.get("transitionDuration"),n=t.get("backgroundColor"),r=t.getModel("textStyle"),a=t.get("padding");return i&&e.push(Wd(i)),n&&(gp.canvasSupported?e.push("background-Color:"+n):(e.push("background-Color:#"+Qe(n)),e.push("filter:alpha(opacity=70)"))),BS(["width","color","radius"],function(i){var n="border-"+i,r=ES(n),a=t.get(r);null!=a&&e.push(n+":"+a+("color"===i?"":"px"))}),e.push(Ud(r)),null!=a&&e.push("padding:"+Ry(a).join("px ")+"px"),e.join(";")+";"}function Yd(t,e){if(gp.wxa)return null;var i=document.createElement("div"),n=this._zr=e.getZr();this.el=i,this._x=e.getWidth()/2,this._y=e.getHeight()/2,t.appendChild(i),this._container=t,this._show=!1,this._hideTimeout;var r=this;i.onmouseenter=function(){r._enterable&&(clearTimeout(r._hideTimeout),r._show=!0),r._inContent=!0},i.onmousemove=function(e){if(e=e||window.event,!r._enterable){var i=n.handler;ye(t,e,!0),i.dispatch("mousemove",e)}},i.onmouseleave=function(){r._enterable&&r._show&&r.hideLater(r._hideDelay),r._inContent=!1}}function jd(t){this._zr=t.getZr(),this._show=!1,this._hideTimeout}function qd(t){for(var e=t.pop();t.length;){var i=t.pop();i&&(Qa.isInstance(i)&&(i=i.get("tooltip",!0)),"string"==typeof i&&(i={formatter:i}),e=new Qa(i,e,e.ecModel))}return e}function Zd(t,e){return t.dispatchAction||y(e.dispatchAction,e)}function Kd(t,e,i,n,r,a,o){var s=i.getOuterSize(),l=s.width,u=s.height;return null!=a&&(t+l+a>n?t-=l+a:t+=a),null!=o&&(e+u+o>r?e-=u+o:e+=o),[t,e]}function $d(t,e,i,n,r){var a=i.getOuterSize(),o=a.width,s=a.height;return t=Math.min(t+o,n)-o,e=Math.min(e+s,r)-s,t=Math.max(t,0),e=Math.max(e,0),[t,e]}function Qd(t,e,i){var n=i[0],r=i[1],a=5,o=0,s=0,l=e.width,u=e.height;switch(t){case"inside":o=e.x+l/2-n/2,s=e.y+u/2-r/2;break;case"top":o=e.x+l/2-n/2,s=e.y-r-a;break;case"bottom":o=e.x+l/2-n/2,s=e.y+u+a;break;case"left":o=e.x-n-a,s=e.y+u/2-r/2;break;case"right":o=e.x+l+a,s=e.y+u/2-r/2}return[o,s]}function Jd(t){return"center"===t||"middle"===t}function tf(t){Gn(t,"label",["show"])}function ef(t){return!(isNaN(parseFloat(t.x))&&isNaN(parseFloat(t.y)))}function nf(t){return!isNaN(parseFloat(t.x))&&!isNaN(parseFloat(t.y))}function rf(t,e,i,n,r,a){var o=[],s=Uu(e,n),l=s?e.getCalculationInfo("stackResultDimension"):n,u=hf(e,l,t),h=e.indicesOfNearest(l,u)[0];o[r]=e.get(i,h),o[a]=e.get(n,h);var c=uo(e.get(n,h));return c=Math.min(c,20),c>=0&&(o[a]=+o[a].toFixed(c)),o}function af(t,e){var i=t.getData(),r=t.coordinateSystem;if(e&&!nf(e)&&!x(e.coord)&&r){var a=r.dimensions,o=of(e,i,r,t);if(e=n(e),e.type&&qS[e.type]&&o.baseAxis&&o.valueAxis){var s=YS(a,o.baseAxis.dim),l=YS(a,o.valueAxis.dim);e.coord=qS[e.type](i,o.baseDataDim,o.valueDataDim,s,l),e.value=e.coord[l]}else{for(var u=[null!=e.xAxis?e.xAxis:e.radiusAxis,null!=e.yAxis?e.yAxis:e.angleAxis],h=0;2>h;h++)qS[u[h]]&&(u[h]=hf(i,i.mapDimension(a[h]),u[h]));e.coord=u}}return e}function of(t,e,i,n){var r={};return null!=t.valueIndex||null!=t.valueDim?(r.valueDataDim=null!=t.valueIndex?e.getDimension(t.valueIndex):t.valueDim,r.valueAxis=i.getAxis(sf(n,r.valueDataDim)),r.baseAxis=i.getOtherAxis(r.valueAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim)):(r.baseAxis=n.getBaseAxis(),r.valueAxis=i.getOtherAxis(r.baseAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim),r.valueDataDim=e.mapDimension(r.valueAxis.dim)),r}function sf(t,e){var i=t.getData(),n=i.dimensions;e=i.getDimension(e);for(var r=0;rn?t.coord&&t.coord[n]:t.value}function hf(t,e,i){if("average"===i){var n=0,r=0;return t.each(e,function(t){isNaN(t)||(n+=t,r++)}),n/r}return"median"===i?t.getMedian(e):t.getDataExtent(e,!0)["max"===i?1:0]}function cf(t){return isNaN(+t.cpx1)||isNaN(+t.cpy1)}function df(t){return"_"+t+"Type"}function ff(t,e,i){var n=e.getItemVisual(i,"color"),r=e.getItemVisual(i,t),a=e.getItemVisual(i,t+"Size");if(r&&"none"!==r){x(a)||(a=[a,a]);var o=Th(r,-a[0]/2,-a[1]/2,a[0],a[1],n);return o.name=t,o}}function pf(t){var e=new $S({name:"line",subPixelOptimize:!0});return gf(e.shape,t),e}function gf(t,e){t.x1=e[0][0],t.y1=e[0][1],t.x2=e[1][0],t.y2=e[1][1],t.percent=1;var i=e[2];i?(t.cpx1=i[0],t.cpy1=i[1]):(t.cpx1=0/0,t.cpy1=0/0)}function vf(){var t=this,e=t.childOfName("fromSymbol"),i=t.childOfName("toSymbol"),n=t.childOfName("label");if(e||i||!n.ignore){for(var r=1,a=this.parent;a;)a.scale&&(r/=a.scale[0]),a=a.parent;var o=t.childOfName("line");if(this.__dirty||o.__dirty){var s=o.shape.percent,l=o.pointAt(0),u=o.pointAt(s),h=j([],u,l);if(te(h,h),e){e.attr("position",l);var c=o.tangentAt(0);e.attr("rotation",Math.PI/2-Math.atan2(c[1],c[0])),e.attr("scale",[r*s,r*s])}if(i){i.attr("position",u);var c=o.tangentAt(1);i.attr("rotation",-Math.PI/2-Math.atan2(c[1],c[0])),i.attr("scale",[r*s,r*s])}if(!n.ignore){n.attr("position",u);var d,f,p,g=5*r;if("end"===n.__position)d=[h[0]*g+u[0],h[1]*g+u[1]],f=h[0]>.8?"left":h[0]<-.8?"right":"center",p=h[1]>.8?"top":h[1]<-.8?"bottom":"middle";else if("middle"===n.__position){var v=s/2,c=o.tangentAt(v),m=[c[1],-c[0]],y=o.pointAt(v);m[1]>0&&(m[0]=-m[0],m[1]=-m[1]),d=[y[0]+m[0]*g,y[1]+m[1]*g],f="center",p="bottom";var _=-Math.atan2(c[1],c[0]);u[0].8?"right":h[0]<-.8?"left":"center",p=h[1]>.8?"bottom":h[1]<-.8?"top":"middle";n.attr({style:{textVerticalAlign:n.__verticalAlign||p,textAlign:n.__textAlign||f},position:d,scale:[r,r]})}}}}function mf(t,e,i){Dg.call(this),this._createLine(t,e,i)}function yf(t){this._ctor=t||mf,this.group=new Dg}function _f(t,e,i,n){var r=e.getItemLayout(i);if(Sf(r)){var a=new t._ctor(e,i,n);e.setItemGraphicEl(i,a),t.group.add(a)}}function xf(t,e,i,n,r,a){var o=e.getItemGraphicEl(n);return Sf(i.getItemLayout(r))?(o?o.updateData(i,r,a):o=new t._ctor(i,r,a),i.setItemGraphicEl(r,o),void t.group.add(o)):void t.group.remove(o)}function wf(t){var e=t.hostModel;return{lineStyle:e.getModel("lineStyle").getLineStyle(),hoverLineStyle:e.getModel("emphasis.lineStyle").getLineStyle(),labelModel:e.getModel("label"),hoverLabelModel:e.getModel("emphasis.label")}}function bf(t){return isNaN(t[0])||isNaN(t[1])}function Sf(t){return!bf(t[0])&&!bf(t[1])}function Mf(t){return!isNaN(t)&&!isFinite(t)}function If(t,e,i,n){var r=1-t,a=n.dimensions[t];return Mf(e[r])&&Mf(i[r])&&e[t]===i[t]&&n.getAxis(a).containData(e[t])}function Cf(t,e){if("cartesian2d"===t.type){var i=e[0].coord,n=e[1].coord;if(i&&n&&(If(1,i,n,t)||If(0,i,n,t)))return!0}return lf(t,e[0])&&lf(t,e[1])}function Tf(t,e,i,n,r){var a,o=n.coordinateSystem,s=t.getItemModel(e),l=oo(s.get("x"),r.getWidth()),u=oo(s.get("y"),r.getHeight());if(isNaN(l)||isNaN(u)){if(n.getMarkerPosition)a=n.getMarkerPosition(t.getValues(t.dimensions,e));else{var h=o.dimensions,c=t.get(h[0],e),d=t.get(h[1],e);a=o.dataToPoint([c,d])}if("cartesian2d"===o.type){var f=o.getAxis("x"),p=o.getAxis("y"),h=o.dimensions;Mf(t.get(h[0],e))?a[0]=f.toGlobalCoord(f.getExtent()[i?0:1]):Mf(t.get(h[1],e))&&(a[1]=p.toGlobalCoord(p.getExtent()[i?0:1]))}isNaN(l)||(a[0]=l),isNaN(u)||(a[1]=u)}else a=[l,u];t.setItemLayout(e,a)}function Df(t,e,i){var n;n=t?p(t&&t.dimensions,function(t){var i=e.getData().getDimensionInfo(e.getData().mapDimension(t))||{};return s({name:t},i)}):[{name:"value",type:"float"}];var r=new ww(n,i),a=new ww(n,i),o=new ww([],i),l=p(i.get("data"),_(iM,e,t,i));t&&(l=v(l,_(Cf,t)));var u=t?uf:function(t){return t.value};return r.initData(p(l,function(t){return t[0]}),null,u),a.initData(p(l,function(t){return t[1]}),null,u),o.initData(p(l,function(t){return t[2]})),o.hasItemOption=!0,{from:r,to:a,line:o}}function Af(t){var e=t.type,i={number:"value",time:"time"};if(i[e]&&(t.axisType=i[e],delete t.type),kf(t),Pf(t,"controlPosition")){var n=t.controlStyle||(t.controlStyle={});Pf(n,"position")||(n.position=t.controlPosition),"none"!==n.position||Pf(n,"show")||(n.show=!1,delete n.position),delete t.controlPosition}f(t.data||[],function(t){S(t)&&!x(t)&&(!Pf(t,"value")&&Pf(t,"name")&&(t.value=t.name),kf(t))})}function kf(t){var e=t.itemStyle||(t.itemStyle={}),i=e.emphasis||(e.emphasis={}),n=t.label||t.label||{},r=n.normal||(n.normal={}),a={normal:1,emphasis:1};f(n,function(t,e){a[e]||Pf(r,e)||(r[e]=t)}),i.label&&!Pf(n,"emphasis")&&(n.emphasis=i.label,delete i.label)}function Pf(t,e){return t.hasOwnProperty(e)}function Lf(t,e){return Bo(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()},t.get("padding"))}function Of(t,e,i,r){var a=ra(t.get(e).replace(/^path:\/\//,""),n(r||{}),new xi(i[0],i[1],i[2],i[3]),"center");return a}function zf(t,e,i,n,a,o){var s=e.get("color");if(a)a.setColor(s),i.add(a),o&&o.onUpdate(a);else{var l=t.get("symbol");a=Th(l,-1,-1,2,2,s),a.setStyle("strokeNoScale",!0),i.add(a),o&&o.onCreate(a)}var u=e.getItemStyle(["color","symbol","symbolSize"]);a.setStyle(u),n=r({rectHover:!0,z2:100},n,!0);var h=t.get("symbolSize");h=h instanceof Array?h.slice():[+h,+h],h[0]/=2,h[1]/=2,n.scale=h;var c=t.get("symbolOffset");if(c){var d=n.position=n.position||[0,0];d[0]+=oo(c[0],h[0]),d[1]+=oo(c[1],h[1])}var f=t.get("symbolRotate");return n.rotation=(f||0)*Math.PI/180||0,a.attr(n),a.updateTransform(),a}function Bf(t,e,i,n,r){if(!t.dragging){var a=n.getModel("checkpointStyle"),o=i.dataToCoord(n.getData().get(["value"],e));r||!a.get("animation",!0)?t.attr({position:[o,0]}):(t.stopAnimation(!0),t.animateTo({position:[o,0]},a.get("animationDuration",!0),a.get("animationEasing",!0)))}}function Ef(t){return document.createElementNS(cM,t)}function Rf(t){return gM(1e4*t)/1e4}function Nf(t){return wM>t&&t>-wM}function Ff(t,e){var i=e?t.textFill:t.fill;return null!=i&&i!==pM}function Gf(t,e){var i=e?t.textStroke:t.stroke;return null!=i&&i!==pM}function Vf(t,e){e&&Hf(t,"transform","matrix("+fM.call(e,",")+")")}function Hf(t,e,i){(!i||"linear"!==i.type&&"radial"!==i.type)&&t.setAttribute(e,i)}function Wf(t,e,i){t.setAttributeNS("http://www.w3.org/1999/xlink",e,i)}function Uf(t,e,i,n){if(Ff(e,i)){var r=i?e.textFill:e.fill;r="transparent"===r?pM:r,Hf(t,"fill",r),Hf(t,"fill-opacity",null!=e.fillOpacity?e.fillOpacity*e.opacity:e.opacity)}else Hf(t,"fill",pM);if(Gf(e,i)){var a=i?e.textStroke:e.stroke;a="transparent"===a?pM:a,Hf(t,"stroke",a);var o=i?e.textStrokeWidth:e.lineWidth,s=!i&&e.strokeNoScale?n.getLineScale():1;Hf(t,"stroke-width",o/s),Hf(t,"paint-order",i?"stroke":"fill"),Hf(t,"stroke-opacity",null!=e.strokeOpacity?e.strokeOpacity:e.opacity);var l=e.lineDash;l?(Hf(t,"stroke-dasharray",e.lineDash.join(",")),Hf(t,"stroke-dashoffset",gM(e.lineDashOffset||0))):Hf(t,"stroke-dasharray",""),e.lineCap&&Hf(t,"stroke-linecap",e.lineCap),e.lineJoin&&Hf(t,"stroke-linejoin",e.lineJoin),e.miterLimit&&Hf(t,"stroke-miterlimit",e.miterLimit)}else Hf(t,"stroke",pM)}function Xf(t){for(var e=[],i=t.data,n=t.len(),r=0;n>r;){var a=i[r++],o="",s=0;switch(a){case dM.M:o="M",s=2;break;case dM.L:o="L",s=2;break;case dM.Q:o="Q",s=4;break;case dM.C:o="C",s=6;break;case dM.A:var l=i[r++],u=i[r++],h=i[r++],c=i[r++],d=i[r++],f=i[r++],p=i[r++],g=i[r++],v=Math.abs(f),m=Nf(v-_M)||(g?f>=_M:-f>=_M),y=f>0?f%_M:f%_M+_M,_=!1;_=m?!0:Nf(v)?!1:y>=yM==!!g;var x=Rf(l+h*mM(d)),w=Rf(u+c*vM(d));m&&(f=g?_M-1e-4:-_M+1e-4,_=!0,9===r&&e.push("M",x,w));var b=Rf(l+h*mM(d+f)),S=Rf(u+c*vM(d+f));e.push("A",Rf(h),Rf(c),gM(p*xM),+_,+g,b,S);break;case dM.Z:o="Z";break;case dM.R:var b=Rf(i[r++]),S=Rf(i[r++]),M=Rf(i[r++]),I=Rf(i[r++]);e.push("M",b,S,"L",b+M,S,"L",b+M,S+I,"L",b,S+I,"L",b,S)}o&&e.push(o);for(var C=0;s>C;C++)e.push(Rf(i[r++]))}return e.join(" ")}function Yf(t,e,i,n,r,a,o){De(TM),e&&i&&Ae(TM,i);var s=n.textRotation;if(r&&s){var l=n.textOrigin;"center"===l?(a=r.width/2+r.x,o=r.height/2+r.y):l&&(a=l[0]+r.x,o=l[1]+r.y),TM[4]-=a,TM[5]-=o,Le(TM,TM,s),TM[4]+=a,TM[5]+=o}Vf(t,TM)}function jf(t,e,i){return"right"===e?t-i[1]:"center"===e?t+i[3]/2-i[1]/2:t+i[3]}function qf(t,e,i,n){Hf(t,"dominant-baseline","middle"),Hf(t,"text-anchor",DM[e]),Hf(t,"x",i),Hf(t,"y",n)}function Zf(){}function Kf(t,e){for(var i=0,n=e.length,r=0,a=0;n>i;i++){var o=e[i];if(o.removed){for(var s=[],l=a;lr;r++)i[t][r].h!==e&&n.push(i[t][r]);i[t]=n}i[t]&&0===i[t].length&&delete i[t]}else delete i[t];return this},trigger:function(t){var e=this._$handlers[t],i=this._$eventProcessor;if(e){var n=arguments,r=n.length;r>3&&(n=Ep.call(n,1));for(var a=e.length,o=0;a>o;){var s=e[o];if(i&&i.filter&&null!=s.query&&!i.filter(t,s.query))o++;else{switch(r){case 1:s.h.call(s.ctx);break;case 2:s.h.call(s.ctx,n[1]);break;case 3:s.h.call(s.ctx,n[1],n[2]);break;default:s.h.apply(s.ctx,n)}s.one?(e.splice(o,1),a--):o++}}}return i&&i.afterTrigger&&i.afterTrigger(t),this},triggerWithContext:function(t){var e=this._$handlers[t],i=this._$eventProcessor;if(e){var n=arguments,r=n.length;r>4&&(n=Ep.call(n,1,n.length-1));for(var a=n[n.length-1],o=e.length,s=0;o>s;){var l=e[s];if(i&&i.filter&&null!=l.query&&!i.filter(t,l.query))s++;else{switch(r){case 1:l.h.call(a);break;case 2:l.h.call(a,n[1]);break;case 3:l.h.call(a,n[1],n[2]);break;default:l.h.apply(a,n)}l.one?(e.splice(s,1),o--):s++}}}return i&&i.afterTrigger&&i.afterTrigger(t),this}};var Np=Math.log(2),Fp="undefined"!=typeof window&&!!window.addEventListener,Gp=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Vp="___zrEVENTSAVED",Hp=[],Wp=Fp?function(t){t.preventDefault(),t.stopPropagation(),t.cancelBubble=!0}:function(t){t.returnValue=!1,t.cancelBubble=!0},Up=function(){this._track=[]};Up.prototype={constructor:Up,recognize:function(t,e,i){return this._doTrack(t,e,i),this._recognize(t)},clear:function(){return this._track.length=0,this},_doTrack:function(t,e,i){var n=t.touches;if(n){for(var r={points:[],touches:[],target:e,event:t},a=0,o=n.length;o>a;a++){var s=n[a],l=pe(i,s,{});r.points.push([l.zrX,l.zrY]),r.touches.push(s)}this._track.push(r)}},_recognize:function(t){for(var e in Xp)if(Xp.hasOwnProperty(e)){var i=Xp[e](this._track,t);if(i)return i}}};var Xp={pinch:function(t,e){var i=t.length;if(i){var n=(t[i-1]||{}).points,r=(t[i-2]||{}).points||n;if(r&&r.length>1&&n&&n.length>1){var a=we(n)/we(r);!isFinite(a)&&(a=1),e.pinchScale=a;var o=be(n);return e.pinchX=o[0],e.pinchY=o[1],{type:"pinch",target:t[0].target,event:e}}}}},Yp="silent";Ie.prototype.dispose=function(){};var jp=["click","dblclick","mousewheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],qp=function(t,e,i,n){Rp.call(this),this.storage=t,this.painter=e,this.painterRoot=n,i=i||new Ie,this.proxy=null,this._hovered={},this._lastTouchMoment,this._lastX,this._lastY,this._gestureMgr,le.call(this),this.setHandlerProxy(i)};qp.prototype={constructor:qp,setHandlerProxy:function(t){this.proxy&&this.proxy.dispose(),t&&(f(jp,function(e){t.on&&t.on(e,this[e],this)},this),t.handler=this),this.proxy=t},mousemove:function(t){var e=t.zrX,i=t.zrY,n=this._hovered,r=n.target;r&&!r.__zr&&(n=this.findHover(n.x,n.y),r=n.target);var a=this._hovered=this.findHover(e,i),o=a.target,s=this.proxy;s.setCursor&&s.setCursor(o?o.cursor:"default"),r&&o!==r&&this.dispatchToElement(n,"mouseout",t),this.dispatchToElement(a,"mousemove",t),o&&o!==r&&this.dispatchToElement(a,"mouseover",t)},mouseout:function(t){this.dispatchToElement(this._hovered,"mouseout",t);var e,i=t.toElement||t.relatedTarget;do i=i&&i.parentNode;while(i&&9!==i.nodeType&&!(e=i===this.painterRoot));!e&&this.trigger("globalout",{event:t})},resize:function(){this._hovered={}},dispatch:function(t,e){var i=this[t];i&&i.call(this,e)},dispose:function(){this.proxy.dispose(),this.storage=this.proxy=this.painter=null},setCursorStyle:function(t){var e=this.proxy;e.setCursor&&e.setCursor(t)},dispatchToElement:function(t,e,i){t=t||{};var n=t.target;if(!n||!n.silent){for(var r="on"+e,a=Se(e,t,i);n&&(n[r]&&(a.cancelBubble=n[r].call(n,a)),n.trigger(e,a),n=n.parent,!a.cancelBubble););a.cancelBubble||(this.trigger(e,a),this.painter&&this.painter.eachOtherLayer(function(t){"function"==typeof t[r]&&t[r].call(t,a),t.trigger&&t.trigger(e,a)}))}},findHover:function(t,e,i){for(var n=this.storage.getDisplayList(),r={x:t,y:e},a=n.length-1;a>=0;a--){var o;if(n[a]!==i&&!n[a].ignore&&(o=Ce(n[a],t,e))&&(!r.topTarget&&(r.topTarget=n[a]),o!==Yp)){r.target=n[a];break}}return r},processGesture:function(t,e){this._gestureMgr||(this._gestureMgr=new Up);var i=this._gestureMgr;"start"===e&&i.clear();var n=i.recognize(t,this.findHover(t.zrX,t.zrY,null).target,this.proxy.dom);if("end"===e&&i.clear(),n){var r=n.type;t.gestureEvent=r,this.dispatchToElement({target:n.target},r,n.event)}}},f(["click","mousedown","mouseup","mousewheel","dblclick","contextmenu"],function(t){qp.prototype[t]=function(e){var i=this.findHover(e.zrX,e.zrY),n=i.target;if("mousedown"===t)this._downEl=n,this._downPoint=[e.zrX,e.zrY],this._upEl=n;else if("mouseup"===t)this._upEl=n;else if("click"===t){if(this._downEl!==this._upEl||!this._downPoint||Op(this._downPoint,[e.zrX,e.zrY])>4)return;this._downPoint=null}this.dispatchToElement(i,t,e)}}),c(qp,Rp),c(qp,le);var Zp="undefined"==typeof Float32Array?Array:Float32Array,Kp=(Object.freeze||Object)({create:Te,identity:De,copy:Ae,mul:ke,translate:Pe,rotate:Le,scale:Oe,invert:ze,clone:Be}),$p=De,Qp=5e-5,Jp=function(t){t=t||{},t.position||(this.position=[0,0]),null==t.rotation&&(this.rotation=0),t.scale||(this.scale=[1,1]),this.origin=this.origin||null},tg=Jp.prototype;tg.transform=null,tg.needLocalTransform=function(){return Ee(this.rotation)||Ee(this.position[0])||Ee(this.position[1])||Ee(this.scale[0]-1)||Ee(this.scale[1]-1)};var eg=[];tg.updateTransform=function(){var t=this.parent,e=t&&t.transform,i=this.needLocalTransform(),n=this.transform;if(!i&&!e)return void(n&&$p(n));n=n||Te(),i?this.getLocalTransform(n):$p(n),e&&(i?ke(n,t.transform,n):Ae(n,t.transform)),this.transform=n;var r=this.globalScaleRatio;if(null!=r&&1!==r){this.getGlobalScale(eg);var a=eg[0]<0?-1:1,o=eg[1]<0?-1:1,s=((eg[0]-a)*r+a)/eg[0]||0,l=((eg[1]-o)*r+o)/eg[1]||0;n[0]*=s,n[1]*=s,n[2]*=l,n[3]*=l}this.invTransform=this.invTransform||Te(),ze(this.invTransform,n)},tg.getLocalTransform=function(t){return Jp.getLocalTransform(this,t)},tg.setTransform=function(t){var e=this.transform,i=t.dpr||1;e?t.setTransform(i*e[0],i*e[1],i*e[2],i*e[3],i*e[4],i*e[5]):t.setTransform(i,0,0,i,0,0)},tg.restoreTransform=function(t){var e=t.dpr||1;t.setTransform(e,0,0,e,0,0)};var ig=[],ng=Te();tg.setLocalTransform=function(t){if(t){var e=t[0]*t[0]+t[1]*t[1],i=t[2]*t[2]+t[3]*t[3],n=this.position,r=this.scale;Ee(e-1)&&(e=Math.sqrt(e)),Ee(i-1)&&(i=Math.sqrt(i)),t[0]<0&&(e=-e),t[3]<0&&(i=-i),n[0]=t[4],n[1]=t[5],r[0]=e,r[1]=i,this.rotation=Math.atan2(-t[1]/i,t[0]/e)}},tg.decomposeTransform=function(){if(this.transform){var t=this.parent,e=this.transform;t&&t.transform&&(ke(ig,t.invTransform,e),e=ig);var i=this.origin;i&&(i[0]||i[1])&&(ng[4]=i[0],ng[5]=i[1],ke(ig,e,ng),ig[4]-=i[0],ig[5]-=i[1],e=ig),this.setLocalTransform(e)}},tg.getGlobalScale=function(t){var e=this.transform;return t=t||[],e?(t[0]=Math.sqrt(e[0]*e[0]+e[1]*e[1]),t[1]=Math.sqrt(e[2]*e[2]+e[3]*e[3]),e[0]<0&&(t[0]=-t[0]),e[3]<0&&(t[1]=-t[1]),t):(t[0]=1,t[1]=1,t)},tg.transformCoordToLocal=function(t,e){var i=[t,e],n=this.invTransform;return n&&ae(i,i,n),i},tg.transformCoordToGlobal=function(t,e){var i=[t,e],n=this.transform; +return n&&ae(i,i,n),i},Jp.getLocalTransform=function(t,e){e=e||[],$p(e);var i=t.origin,n=t.scale||[1,1],r=t.rotation||0,a=t.position||[0,0];return i&&(e[4]-=i[0],e[5]-=i[1]),Oe(e,e,n),r&&Le(e,e,r),i&&(e[4]+=i[0],e[5]+=i[1]),e[4]+=a[0],e[5]+=a[1],e};var rg={linear:function(t){return t},quadraticIn:function(t){return t*t},quadraticOut:function(t){return t*(2-t)},quadraticInOut:function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)},cubicIn:function(t){return t*t*t},cubicOut:function(t){return--t*t*t+1},cubicInOut:function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},quarticIn:function(t){return t*t*t*t},quarticOut:function(t){return 1- --t*t*t*t},quarticInOut:function(t){return(t*=2)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},quinticIn:function(t){return t*t*t*t*t},quinticOut:function(t){return--t*t*t*t*t+1},quinticInOut:function(t){return(t*=2)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},sinusoidalIn:function(t){return 1-Math.cos(t*Math.PI/2)},sinusoidalOut:function(t){return Math.sin(t*Math.PI/2)},sinusoidalInOut:function(t){return.5*(1-Math.cos(Math.PI*t))},exponentialIn:function(t){return 0===t?0:Math.pow(1024,t-1)},exponentialOut:function(t){return 1===t?1:1-Math.pow(2,-10*t)},exponentialInOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?.5*Math.pow(1024,t-1):.5*(-Math.pow(2,-10*(t-1))+2)},circularIn:function(t){return 1-Math.sqrt(1-t*t)},circularOut:function(t){return Math.sqrt(1- --t*t)},circularInOut:function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},elasticIn:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),-(i*Math.pow(2,10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n)))},elasticOut:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),i*Math.pow(2,-10*t)*Math.sin(2*(t-e)*Math.PI/n)+1)},elasticInOut:function(t){var e,i=.1,n=.4;return 0===t?0:1===t?1:(!i||1>i?(i=1,e=n/4):e=n*Math.asin(1/i)/(2*Math.PI),(t*=2)<1?-.5*i*Math.pow(2,10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n):i*Math.pow(2,-10*(t-=1))*Math.sin(2*(t-e)*Math.PI/n)*.5+1)},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return--t*t*((e+1)*t+e)+1},backInOut:function(t){var e=2.5949095;return(t*=2)<1?.5*t*t*((e+1)*t-e):.5*((t-=2)*t*((e+1)*t+e)+2)},bounceIn:function(t){return 1-rg.bounceOut(1-t)},bounceOut:function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bounceInOut:function(t){return.5>t?.5*rg.bounceIn(2*t):.5*rg.bounceOut(2*t-1)+.5}};Re.prototype={constructor:Re,step:function(t,e){if(this._initialized||(this._startTime=t+this._delay,this._initialized=!0),this._paused)return void(this._pausedTime+=e);var i=(t-this._startTime-this._pausedTime)/this._life;if(!(0>i)){i=Math.min(i,1);var n=this.easing,r="string"==typeof n?rg[n]:n,a="function"==typeof r?r(i):i;return this.fire("frame",a),1===i?this.loop?(this.restart(t),"restart"):(this._needsRemove=!0,"destroy"):null}},restart:function(t){var e=(t-this._startTime-this._pausedTime)%this._life;this._startTime=t-e+this.gap,this._pausedTime=0,this._needsRemove=!1},fire:function(t,e){t="on"+t,this[t]&&this[t](this._target,e)},pause:function(){this._paused=!0},resume:function(){this._paused=!1}};var ag=function(){this.head=null,this.tail=null,this._len=0},og=ag.prototype;og.insert=function(t){var e=new sg(t);return this.insertEntry(e),e},og.insertEntry=function(t){this.head?(this.tail.next=t,t.prev=this.tail,t.next=null,this.tail=t):this.head=this.tail=t,this._len++},og.remove=function(t){var e=t.prev,i=t.next;e?e.next=i:this.head=i,i?i.prev=e:this.tail=e,t.next=t.prev=null,this._len--},og.len=function(){return this._len},og.clear=function(){this.head=this.tail=null,this._len=0};var sg=function(t){this.value=t,this.next,this.prev},lg=function(t){this._list=new ag,this._map={},this._maxSize=t||10,this._lastRemovedEntry=null},ug=lg.prototype;ug.put=function(t,e){var i=this._list,n=this._map,r=null;if(null==n[t]){var a=i.len(),o=this._lastRemovedEntry;if(a>=this._maxSize&&a>0){var s=i.head;i.remove(s),delete n[s.key],r=s.value,this._lastRemovedEntry=s}o?o.value=e:o=new sg(e),o.key=t,i.insertEntry(o),n[t]=o}return r},ug.get=function(t){var e=this._map[t],i=this._list;return null!=e?(e!==i.tail&&(i.remove(e),i.insertEntry(e)),e.value):void 0},ug.clear=function(){this._list.clear(),this._map={}};var hg={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]},cg=new lg(20),dg=null,fg=Je,pg=ti,gg=(Object.freeze||Object)({parse:qe,lift:$e,toHex:Qe,fastLerp:Je,fastMapToColor:fg,lerp:ti,mapToColor:pg,modifyHSL:ei,modifyAlpha:ii,stringify:ni}),vg=Array.prototype.slice,mg=function(t,e,i,n){this._tracks={},this._target=t,this._loop=e||!1,this._getter=i||ri,this._setter=n||ai,this._clipCount=0,this._delay=0,this._doneList=[],this._onframeList=[],this._clipList=[]};mg.prototype={when:function(t,e){var i=this._tracks;for(var n in e)if(e.hasOwnProperty(n)){if(!i[n]){i[n]=[];var r=this._getter(this._target,n);if(null==r)continue;0!==t&&i[n].push({time:0,value:fi(r)})}i[n].push({time:t,value:e[n]})}return this},during:function(t){return this._onframeList.push(t),this},pause:function(){for(var t=0;ti;i++)t[i].call(this)},start:function(t,e){var i,n=this,r=0,a=function(){r--,r||n._doneCallback()};for(var o in this._tracks)if(this._tracks.hasOwnProperty(o)){var s=vi(this,t,a,this._tracks[o],o,e);s&&(this._clipList.push(s),r++,this.animation&&this.animation.addClip(s),i=s)}if(i){var l=i.onframe;i.onframe=function(t,e){l(t,e);for(var i=0;il;l++)s&&(s=s[o[l]]);s&&(i=s)}else i=r;if(!i)return void bg('Property "'+t+'" is not existed in element '+r.id);var c=r.animators,d=new mg(i,e);return d.during(function(){r.dirty(n)}).done(function(){c.splice(u(c,d),1)}),c.push(d),a&&a.animation.addAnimator(d),d},stopAnimation:function(t){for(var e=this.animators,i=e.length,n=0;i>n;n++)e[n].stop(t);return e.length=0,this},animateTo:function(t,e,i,n,r,a){mi(this,t,e,i,n,r,a)},animateFrom:function(t,e,i,n,r,a){mi(this,t,e,i,n,r,a,!0)}};var Mg=function(t){Jp.call(this,t),Rp.call(this,t),Sg.call(this,t),this.id=t.id||fp()};Mg.prototype={type:"element",name:"",__zr:null,ignore:!1,clipPath:null,isGroup:!1,drift:function(t,e){switch(this.draggable){case"horizontal":e=0;break;case"vertical":t=0}var i=this.transform;i||(i=this.transform=[1,0,0,1,0,0]),i[4]+=t,i[5]+=e,this.decomposeTransform(),this.dirty(!1)},beforeUpdate:function(){},afterUpdate:function(){},update:function(){this.updateTransform()},traverse:function(){},attrKV:function(t,e){if("position"===t||"scale"===t||"origin"===t){if(e){var i=this[t];i||(i=this[t]=[]),i[0]=e[0],i[1]=e[1]}}else this[t]=e},hide:function(){this.ignore=!0,this.__zr&&this.__zr.refresh()},show:function(){this.ignore=!1,this.__zr&&this.__zr.refresh()},attr:function(t,e){if("string"==typeof t)this.attrKV(t,e);else if(S(t))for(var i in t)t.hasOwnProperty(i)&&this.attrKV(i,t[i]);return this.dirty(!1),this},setClipPath:function(t){var e=this.__zr;e&&t.addSelfToZr(e),this.clipPath&&this.clipPath!==t&&this.removeClipPath(),this.clipPath=t,t.__zr=e,t.__clipTarget=this,this.dirty(!1)},removeClipPath:function(){var t=this.clipPath;t&&(t.__zr&&t.removeSelfFromZr(t.__zr),t.__zr=null,t.__clipTarget=null,this.clipPath=null,this.dirty(!1))},addSelfToZr:function(t){this.__zr=t;var e=this.animators;if(e)for(var i=0;in||i>s||l>a||r>u)},contain:function(t,e){var i=this;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height},clone:function(){return new xi(this.x,this.y,this.width,this.height)},copy:function(t){this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height},plain:function(){return{x:this.x,y:this.y,width:this.width,height:this.height}}},xi.create=function(t){return new xi(t.x,t.y,t.width,t.height)};var Dg=function(t){t=t||{},Mg.call(this,t);for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);this._children=[],this.__storage=null,this.__dirty=!0};Dg.prototype={constructor:Dg,isGroup:!0,type:"group",silent:!1,children:function(){return this._children.slice()},childAt:function(t){return this._children[t]},childOfName:function(t){for(var e=this._children,i=0;i=0&&(i.splice(n,0,t),this._doAdd(t))}return this},_doAdd:function(t){t.parent&&t.parent.remove(t),t.parent=this;var e=this.__storage,i=this.__zr;e&&e!==t.__storage&&(e.addToStorage(t),t instanceof Dg&&t.addChildrenToStorage(e)),i&&i.refresh()},remove:function(t){var e=this.__zr,i=this.__storage,n=this._children,r=u(n,t);return 0>r?this:(n.splice(r,1),t.parent=null,i&&(i.delFromStorage(t),t instanceof Dg&&t.delChildrenFromStorage(i)),e&&e.refresh(),this)},removeAll:function(){var t,e,i=this._children,n=this.__storage;for(e=0;en;n++)this._updateAndAddDisplayable(e[n],null,t);i.length=this._displayListLen,gp.canvasSupported&&Di(i,Ai)},_updateAndAddDisplayable:function(t,e,i){if(!t.ignore||i){t.beforeUpdate(),t.__dirty&&t.update(),t.afterUpdate();var n=t.clipPath;if(n){e=e?e.slice():[];for(var r=n,a=t;r;)r.parent=a,r.updateTransform(),e.push(r),a=r,r=r.clipPath}if(t.isGroup){for(var o=t._children,s=0;se;e++)this.delRoot(t[e]);else{var r=u(this._roots,t);r>=0&&(this.delFromStorage(t),this._roots.splice(r,1),t instanceof Dg&&t.delChildrenFromStorage(this))}},addToStorage:function(t){return t&&(t.__storage=this,t.dirty(!1)),this},delFromStorage:function(t){return t&&(t.__storage=null),this},dispose:function(){this._renderList=this._roots=null},displayableSortFunc:Ai};var Lg={shadowBlur:1,shadowOffsetX:1,shadowOffsetY:1,textShadowBlur:1,textShadowOffsetX:1,textShadowOffsetY:1,textBoxShadowBlur:1,textBoxShadowOffsetX:1,textBoxShadowOffsetY:1},Og=function(t,e,i){return Lg.hasOwnProperty(e)?i*=t.dpr:i},zg={NONE:0,STYLE_BIND:1,PLAIN_TEXT:2},Bg=9,Eg=[["shadowBlur",0],["shadowOffsetX",0],["shadowOffsetY",0],["shadowColor","#000"],["lineCap","butt"],["lineJoin","miter"],["miterLimit",10]],Rg=function(t){this.extendFrom(t,!1)};Rg.prototype={constructor:Rg,fill:"#000",stroke:null,opacity:1,fillOpacity:null,strokeOpacity:null,lineDash:null,lineDashOffset:0,shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,lineWidth:1,strokeNoScale:!1,text:null,font:null,textFont:null,fontStyle:null,fontWeight:null,fontSize:null,fontFamily:null,textTag:null,textFill:"#000",textStroke:null,textWidth:null,textHeight:null,textStrokeWidth:0,textLineHeight:null,textPosition:"inside",textRect:null,textOffset:null,textAlign:null,textVerticalAlign:null,textDistance:5,textShadowColor:"transparent",textShadowBlur:0,textShadowOffsetX:0,textShadowOffsetY:0,textBoxShadowColor:"transparent",textBoxShadowBlur:0,textBoxShadowOffsetX:0,textBoxShadowOffsetY:0,transformText:!1,textRotation:0,textOrigin:null,textBackgroundColor:null,textBorderColor:null,textBorderWidth:0,textBorderRadius:0,textPadding:null,rich:null,truncate:null,blend:null,bind:function(t,e,i){var n=this,r=i&&i.style,a=!r||t.__attrCachedBy!==zg.STYLE_BIND;t.__attrCachedBy=zg.STYLE_BIND;for(var o=0;o0},extendFrom:function(t,e){if(t)for(var i in t)!t.hasOwnProperty(i)||e!==!0&&(e===!1?this.hasOwnProperty(i):null==t[i])||(this[i]=t[i])},set:function(t,e){"string"==typeof t?this[t]=e:this.extendFrom(t,!0)},clone:function(){var t=new this.constructor;return t.extendFrom(this,!0),t},getGradient:function(t,e,i){for(var n="radial"===e.type?Pi:ki,r=n(t,e,i),a=e.colorStops,o=0;o=0&&i.splice(n,1),t.__hoverMir=null},clearHover:function(){for(var t=this._hoverElements,e=0;er;){var a=t[r],o=a.__from;o&&o.__zr?(r++,o.invisible||(a.transform=o.transform,a.invTransform=o.invTransform,a.__clipPaths=o.__clipPaths,this._doPaintEl(a,i,!0,n))):(t.splice(r,1),o.__hoverMir=null,e--)}i.ctx.restore()}},getHoverLayer:function(){return this.getLayer(av)},_paintList:function(t,e,i){if(this._redrawId===i){e=e||!1,this._updateLayerStatus(t);var n=this._doPaintList(t,e);if(this._needsManuallyCompositing&&this._compositeManually(),!n){var r=this;Wg(function(){r._paintList(t,e,i)})}}},_compositeManually:function(){var t=this.getLayer(ov).ctx,e=this._domRoot.width,i=this._domRoot.height;t.clearRect(0,0,e,i),this.eachBuiltinLayer(function(n){n.virtual&&t.drawImage(n.dom,0,0,e,i)})},_doPaintList:function(t,e){for(var i=[],n=0;n15)break}}a.__drawIndex=v,a.__drawIndex0&&t>n[0]){for(o=0;r-1>o&&!(n[o]t);o++);a=i[n[o]]}if(n.splice(o+1,0,t),i[t]=e,!e.virtual)if(a){var l=a.dom;l.nextSibling?s.insertBefore(e.dom,l.nextSibling):s.appendChild(e.dom)}else s.firstChild?s.insertBefore(e.dom,s.firstChild):s.appendChild(e.dom)},eachLayer:function(t,e){var i,n,r=this._zlevelList;for(n=0;n0?sv:0),this._needsManuallyCompositing),o.__builtin__||bg("ZLevel "+s+" has been used by unkown layer "+o.id),o!==r&&(o.__used=!0,o.__startIndex!==i&&(o.__dirty=!0),o.__startIndex=i,o.__drawIndex=o.incremental?-1:i,e(i),r=o),n.__dirty&&(o.__dirty=!0,o.incremental&&o.__drawIndex<0&&(o.__drawIndex=i))}e(i),this.eachBuiltinLayer(function(t){!t.__used&&t.getElementCount()>0&&(t.__dirty=!0,t.__startIndex=t.__endIndex=t.__drawIndex=0),t.__dirty&&t.__drawIndex<0&&(t.__drawIndex=t.__startIndex)})},clear:function(){return this.eachBuiltinLayer(this._clearLayer),this},_clearLayer:function(t){t.clear()},setBackgroundColor:function(t){this._backgroundColor=t},configLayer:function(t,e){if(e){var i=this._layerConfig;i[t]?r(i[t],e,!0):i[t]=e;for(var n=0;n=0&&this._clips.splice(e,1)},removeAnimator:function(t){for(var e=t.getClips(),i=0;io;o++){var s=i[o],l=s.step(t,e);l&&(r.push(l),a.push(s))}for(var o=0;n>o;)i[o]._needsRemove?(i[o]=i[n-1],i.pop(),n--):o++;n=r.length;for(var o=0;n>o;o++)a[o].fire(r[o]);this._time=t,this.onframe(e),this.trigger("frame",e),this.stage.update&&this.stage.update()},_startLoop:function(){function t(){e._running&&(Wg(t),!e._paused&&e._update())}var e=this;this._running=!0,Wg(t)},start:function(){this._time=(new Date).getTime(),this._pausedTime=0,this._startLoop()},stop:function(){this._running=!1},pause:function(){this._paused||(this._pauseStart=(new Date).getTime(),this._paused=!0)},resume:function(){this._paused&&(this._pausedTime+=(new Date).getTime()-this._pauseStart,this._paused=!1)},clear:function(){this._clips=[]},isFinished:function(){return!this._clips.length},animate:function(t,e){e=e||{};var i=new mg(t,e.loop,e.getter,e.setter);return this.addAnimator(i),i}},c(dv,Rp);var fv=300,pv=["click","dblclick","mousewheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],gv=["touchstart","touchend","touchmove"],vv={pointerdown:1,pointerup:1,pointermove:1,pointerout:1},mv=p(pv,function(t){var e=t.replace("mouse","pointer");return vv[e]?e:t}),yv={mousemove:function(t){t=ye(this.dom,t),this.trigger("mousemove",t)},mouseout:function(t){t=ye(this.dom,t);var e=t.toElement||t.relatedTarget;if(e!==this.dom)for(;e&&9!==e.nodeType;){if(e===this.dom)return;e=e.parentNode}this.trigger("mouseout",t)},touchstart:function(t){t=ye(this.dom,t),t.zrByTouch=!0,this._lastTouchMoment=new Date,this.handler.processGesture(t,"start"),yv.mousemove.call(this,t),yv.mousedown.call(this,t),kn(this)},touchmove:function(t){t=ye(this.dom,t),t.zrByTouch=!0,this.handler.processGesture(t,"change"),yv.mousemove.call(this,t),kn(this)},touchend:function(t){t=ye(this.dom,t),t.zrByTouch=!0,this.handler.processGesture(t,"end"),yv.mouseup.call(this,t),+new Date-this._lastTouchMoment=0||n&&u(n,o)<0)){var s=e.getShallow(o);null!=s&&(r[t[a][0]]=s)}}return r}},Ev=Bv([["lineWidth","width"],["stroke","color"],["opacity"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["shadowColor"]]),Rv={getLineStyle:function(t){var e=Ev(this,t);return e.lineDash=this.getLineDash(e.lineWidth),e},getLineDash:function(t){null==t&&(t=1);var e=this.get("type"),i=Math.max(t,2),n=4*t;return"solid"===e||null==e?!1:"dashed"===e?[n,n]:[i,i]}},Nv=Bv([["fill","color"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["opacity"],["shadowColor"]]),Fv={getAreaStyle:function(t,e){return Nv(this,t,e)}},Gv=Math.pow,Vv=Math.sqrt,Hv=1e-8,Wv=1e-4,Uv=Vv(3),Xv=1/3,Yv=V(),jv=V(),qv=V(),Zv=Math.min,Kv=Math.max,$v=Math.sin,Qv=Math.cos,Jv=2*Math.PI,tm=V(),em=V(),im=V(),nm=[],rm=[],am={M:1,L:2,C:3,Q:4,A:5,Z:6,R:7},om=[],sm=[],lm=[],um=[],hm=Math.min,cm=Math.max,dm=Math.cos,fm=Math.sin,pm=Math.sqrt,gm=Math.abs,vm="undefined"!=typeof Float32Array,mm=function(t){this._saveData=!t,this._saveData&&(this.data=[]),this._ctx=null};mm.prototype={constructor:mm,_xi:0,_yi:0,_x0:0,_y0:0,_ux:0,_uy:0,_len:0,_lineDash:null,_dashOffset:0,_dashIdx:0,_dashSum:0,setScale:function(t,e,i){i=i||0,this._ux=gm(i/xg/t)||0,this._uy=gm(i/xg/e)||0},getContext:function(){return this._ctx},beginPath:function(t){return this._ctx=t,t&&t.beginPath(),t&&(this.dpr=t.dpr),this._saveData&&(this._len=0),this._lineDash&&(this._lineDash=null,this._dashOffset=0),this},moveTo:function(t,e){return this.addData(am.M,t,e),this._ctx&&this._ctx.moveTo(t,e),this._x0=t,this._y0=e,this._xi=t,this._yi=e,this},lineTo:function(t,e){var i=gm(t-this._xi)>this._ux||gm(e-this._yi)>this._uy||this._len<5;return this.addData(am.L,t,e),this._ctx&&i&&(this._needsDash()?this._dashedLineTo(t,e):this._ctx.lineTo(t,e)),i&&(this._xi=t,this._yi=e),this},bezierCurveTo:function(t,e,i,n,r,a){return this.addData(am.C,t,e,i,n,r,a),this._ctx&&(this._needsDash()?this._dashedBezierTo(t,e,i,n,r,a):this._ctx.bezierCurveTo(t,e,i,n,r,a)),this._xi=r,this._yi=a,this},quadraticCurveTo:function(t,e,i,n){return this.addData(am.Q,t,e,i,n),this._ctx&&(this._needsDash()?this._dashedQuadraticTo(t,e,i,n):this._ctx.quadraticCurveTo(t,e,i,n)),this._xi=i,this._yi=n,this},arc:function(t,e,i,n,r,a){return this.addData(am.A,t,e,i,i,n,r-n,0,a?0:1),this._ctx&&this._ctx.arc(t,e,i,n,r,a),this._xi=dm(r)*i+t,this._yi=fm(r)*i+e,this},arcTo:function(t,e,i,n,r){return this._ctx&&this._ctx.arcTo(t,e,i,n,r),this},rect:function(t,e,i,n){return this._ctx&&this._ctx.rect(t,e,i,n),this.addData(am.R,t,e,i,n),this},closePath:function(){this.addData(am.Z);var t=this._ctx,e=this._x0,i=this._y0;return t&&(this._needsDash()&&this._dashedLineTo(e,i),t.closePath()),this._xi=e,this._yi=i,this},fill:function(t){t&&t.fill(),this.toStatic()},stroke:function(t){t&&t.stroke(),this.toStatic()},setLineDash:function(t){if(t instanceof Array){this._lineDash=t,this._dashIdx=0;for(var e=0,i=0;ii;i++)this.data[i]=t[i];this._len=e},appendPath:function(t){t instanceof Array||(t=[t]);for(var e=t.length,i=0,n=this._len,r=0;e>r;r++)i+=t[r].len();vm&&this.data instanceof Float32Array&&(this.data=new Float32Array(n+i));for(var r=0;e>r;r++)for(var a=t[r].data,o=0;oe.length&&(this._expandData(),e=this.data);for(var i=0;ia&&(a=r+a),a%=r,f-=a*h,p-=a*c;h>0&&t>=f||0>h&&f>=t||0===h&&(c>0&&e>=p||0>c&&p>=e);)n=this._dashIdx,i=o[n],f+=h*i,p+=c*i,this._dashIdx=(n+1)%g,h>0&&l>f||0>h&&f>l||c>0&&u>p||0>c&&p>u||s[n%2?"moveTo":"lineTo"](h>=0?hm(f,t):cm(f,t),c>=0?hm(p,e):cm(p,e));h=f-t,c=p-e,this._dashOffset=-pm(h*h+c*c)},_dashedBezierTo:function(t,e,i,n,r,a){var o,s,l,u,h,c=this._dashSum,d=this._dashOffset,f=this._lineDash,p=this._ctx,g=this._xi,v=this._yi,m=ur,y=0,_=this._dashIdx,x=f.length,w=0;for(0>d&&(d=c+d),d%=c,o=0;1>o;o+=.1)s=m(g,t,i,r,o+.1)-m(g,t,i,r,o),l=m(v,e,n,a,o+.1)-m(v,e,n,a,o),y+=pm(s*s+l*l);for(;x>_&&(w+=f[_],!(w>d));_++);for(o=(w-d)/y;1>=o;)u=m(g,t,i,r,o),h=m(v,e,n,a,o),_%2?p.moveTo(u,h):p.lineTo(u,h),o+=f[_]/y,_=(_+1)%x;_%2!==0&&p.lineTo(r,a),s=r-u,l=a-h,this._dashOffset=-pm(s*s+l*l)},_dashedQuadraticTo:function(t,e,i,n){var r=i,a=n;i=(i+2*t)/3,n=(n+2*e)/3,t=(this._xi+2*t)/3,e=(this._yi+2*e)/3,this._dashedBezierTo(t,e,i,n,r,a)},toStatic:function(){var t=this.data;t instanceof Array&&(t.length=this._len,vm&&(this.data=new Float32Array(t)))},getBoundingRect:function(){om[0]=om[1]=lm[0]=lm[1]=Number.MAX_VALUE,sm[0]=sm[1]=um[0]=um[1]=-Number.MAX_VALUE;for(var t=this.data,e=0,i=0,n=0,r=0,a=0;ac;){var d=s[c++];switch(1===c&&(n=s[c],r=s[c+1],e=n,i=r),d){case am.M:e=n=s[c++],i=r=s[c++],t.moveTo(n,r);break;case am.L:a=s[c++],o=s[c++],(gm(a-n)>l||gm(o-r)>u||c===h-1)&&(t.lineTo(a,o),n=a,r=o);break;case am.C:t.bezierCurveTo(s[c++],s[c++],s[c++],s[c++],s[c++],s[c++]),n=s[c-2],r=s[c-1];break;case am.Q:t.quadraticCurveTo(s[c++],s[c++],s[c++],s[c++]),n=s[c-2],r=s[c-1];break;case am.A:var f=s[c++],p=s[c++],g=s[c++],v=s[c++],m=s[c++],y=s[c++],_=s[c++],x=s[c++],w=g>v?g:v,b=g>v?1:g/v,S=g>v?v/g:1,M=Math.abs(g-v)>.001,I=m+y;M?(t.translate(f,p),t.rotate(_),t.scale(b,S),t.arc(0,0,w,m,I,1-x),t.scale(1/b,1/S),t.rotate(-_),t.translate(-f,-p)):t.arc(f,p,w,m,I,1-x),1===c&&(e=dm(m)*g+f,i=fm(m)*v+p),n=dm(I)*g+f,r=fm(I)*v+p;break;case am.R:e=n=s[c],i=r=s[c+1],t.rect(s[c++],s[c++],s[c++],s[c++]);break;case am.Z:t.closePath(),n=e,r=i}}}},mm.CMD=am;var ym=2*Math.PI,_m=2*Math.PI,xm=mm.CMD,wm=2*Math.PI,bm=1e-4,Sm=[-1,-1,-1],Mm=[-1,-1],Im=Vg.prototype.getCanvasPattern,Cm=Math.abs,Tm=new mm(!0);Gr.prototype={constructor:Gr,type:"path",__dirtyPath:!0,strokeContainThreshold:5,segmentIgnoreThreshold:0,subPixelOptimize:!1,brush:function(t,e){var i=this.style,n=this.path||Tm,r=i.hasStroke(),a=i.hasFill(),o=i.fill,s=i.stroke,l=a&&!!o.colorStops,u=r&&!!s.colorStops,h=a&&!!o.image,c=r&&!!s.image;if(i.bind(t,this,e),this.setTransform(t),this.__dirty){var d;l&&(d=d||this.getBoundingRect(),this._fillGradient=i.getGradient(t,o,d)),u&&(d=d||this.getBoundingRect(),this._strokeGradient=i.getGradient(t,s,d))}l?t.fillStyle=this._fillGradient:h&&(t.fillStyle=Im.call(o,t)),u?t.strokeStyle=this._strokeGradient:c&&(t.strokeStyle=Im.call(s,t));var f=i.lineDash,p=i.lineDashOffset,g=!!t.setLineDash,v=this.getGlobalScale();if(n.setScale(v[0],v[1],this.segmentIgnoreThreshold),this.__dirtyPath||f&&!g&&r?(n.beginPath(t),f&&!g&&(n.setLineDash(f),n.setLineDashOffset(p)),this.buildPath(n,this.shape,!1),this.path&&(this.__dirtyPath=!1)):(t.beginPath(),this.path.rebuildPath(t)),a)if(null!=i.fillOpacity){var m=t.globalAlpha;t.globalAlpha=i.fillOpacity*i.opacity,n.fill(t),t.globalAlpha=m}else n.fill(t);if(f&&g&&(t.setLineDash(f),t.lineDashOffset=p),r)if(null!=i.strokeOpacity){var m=t.globalAlpha;t.globalAlpha=i.strokeOpacity*i.opacity,n.stroke(t),t.globalAlpha=m}else n.stroke(t);f&&g&&t.setLineDash([]),null!=i.text&&(this.restoreTransform(t),this.drawRectText(t,this.getBoundingRect()))},buildPath:function(){},createPathProxy:function(){this.path=new mm},getBoundingRect:function(){var t=this._rect,e=this.style,i=!t;if(i){var n=this.path;n||(n=this.path=new mm),this.__dirtyPath&&(n.beginPath(),this.buildPath(n,this.shape,!1)),t=n.getBoundingRect()}if(this._rect=t,e.hasStroke()){var r=this._rectWithStroke||(this._rectWithStroke=t.clone());if(this.__dirty||i){r.copy(t);var a=e.lineWidth,o=e.strokeNoScale?this.getLineScale():1;e.hasFill()||(a=Math.max(a,this.strokeContainThreshold||4)),o>1e-10&&(r.width+=a/o,r.height+=a/o,r.x-=a/o/2,r.y-=a/o/2)}return r}return t},contain:function(t,e){var i=this.transformCoordToLocal(t,e),n=this.getBoundingRect(),r=this.style;if(t=i[0],e=i[1],n.contain(t,e)){var a=this.path.data;if(r.hasStroke()){var o=r.lineWidth,s=r.strokeNoScale?this.getLineScale():1;if(s>1e-10&&(r.hasFill()||(o=Math.max(o,this.strokeContainThreshold)),Fr(a,o/s,t,e)))return!0}if(r.hasFill())return Nr(a,t,e)}return!1},dirty:function(t){null==t&&(t=!0),t&&(this.__dirtyPath=t,this._rect=null),this.__dirty=this.__dirtyText=!0,this.__zr&&this.__zr.refresh(),this.__clipTarget&&this.__clipTarget.dirty()},animateShape:function(t){return this.animate("shape",t)},attrKV:function(t,e){"shape"===t?(this.setShape(e),this.__dirtyPath=!0,this._rect=null):wn.prototype.attrKV.call(this,t,e)},setShape:function(t,e){var i=this.shape;if(i){if(S(t))for(var n in t)t.hasOwnProperty(n)&&(i[n]=t[n]);else i[t]=e;this.dirty(!0)}return this},getLineScale:function(){var t=this.transform;return t&&Cm(t[0]-1)>1e-10&&Cm(t[3]-1)>1e-10?Math.sqrt(Cm(t[0]*t[3]-t[2]*t[1])):1}},Gr.extend=function(t){var e=function(e){Gr.call(this,e),t.style&&this.style.extendFrom(t.style,!1);var i=t.shape;if(i){this.shape=this.shape||{};var n=this.shape;for(var r in i)!n.hasOwnProperty(r)&&i.hasOwnProperty(r)&&(n[r]=i[r])}t.init&&t.init.call(this,e)};h(e,Gr);for(var i in t)"style"!==i&&"shape"!==i&&(e.prototype[i]=t[i]);return e},h(Gr,wn);var Dm=mm.CMD,Am=[[],[],[]],km=Math.sqrt,Pm=Math.atan2,Lm=function(t,e){var i,n,r,a,o,s,l=t.data,u=Dm.M,h=Dm.C,c=Dm.L,d=Dm.R,f=Dm.A,p=Dm.Q;for(r=0,a=0;ro;o++){var s=Am[o];s[0]=l[r++],s[1]=l[r++],ae(s,s,e),l[a++]=s[0],l[a++]=s[1]}}},Om=Math.sqrt,zm=Math.sin,Bm=Math.cos,Em=Math.PI,Rm=function(t){return Math.sqrt(t[0]*t[0]+t[1]*t[1])},Nm=function(t,e){return(t[0]*e[0]+t[1]*e[1])/(Rm(t)*Rm(e))},Fm=function(t,e){return(t[0]*e[1]=11?function(){var e,i=this.__clipPaths,n=this.style;if(i)for(var r=0;ra;a++)r+=ee(t[a-1],t[a]);var o=r/2;o=i>o?i:o;for(var a=0;o>a;a++){var s,l,u,h=a/(o-1)*(e?i:i-1),c=Math.floor(h),d=h-c,f=t[c%i];e?(s=t[(c-1+i)%i],l=t[(c+1)%i],u=t[(c+2)%i]):(s=t[0===c?c:c-1],l=t[c>i-2?i-1:c+1],u=t[c>i-3?i-1:c+2]);var p=d*d,g=d*p;n.push([jr(s[0],f[0],l[0],u[0],d,p,g),jr(s[1],f[1],l[1],u[1],d,p,g)])}return n},Zm=function(t,e,i,n){var r,a,o,s,l=[],u=[],h=[],c=[];if(n){o=[1/0,1/0],s=[-1/0,-1/0];for(var d=0,f=t.length;f>d;d++)oe(o,o,t[d]),se(s,s,t[d]);oe(o,o,n[0]),se(s,s,n[1])}for(var d=0,f=t.length;f>d;d++){var p=t[d];if(i)r=t[d?d-1:f-1],a=t[(d+1)%f];else{if(0===d||d===f-1){l.push(W(t[d]));continue}r=t[d-1],a=t[d+1]}j(u,a,r),J(u,u,e);var g=ee(p,r),v=ee(p,a),m=g+v;0!==m&&(g/=m,v/=m),J(h,u,-g),J(c,u,v);var y=X([],p,h),_=X([],p,c);n&&(se(y,y,o),oe(y,y,s),se(_,_,o),oe(_,_,s)),l.push(y),l.push(_)}return i&&l.push(l.shift()),l},Km=Gr.extend({type:"polygon",shape:{points:null,smooth:!1,smoothConstraint:null},buildPath:function(t,e){qr(t,e,!0)}}),$m=Gr.extend({type:"polyline",shape:{points:null,smooth:!1,smoothConstraint:null},style:{stroke:"#000",fill:null},buildPath:function(t,e){qr(t,e,!1)}}),Qm=Math.round,Jm={},ty=Gr.extend({type:"rect",shape:{r:0,x:0,y:0,width:0,height:0},buildPath:function(t,e){var i,n,r,a;this.subPixelOptimize?(Kr(Jm,e,this.style),i=Jm.x,n=Jm.y,r=Jm.width,a=Jm.height,Jm.r=e.r,e=Jm):(i=e.x,n=e.y,r=e.width,a=e.height),e.r?en(t,e):t.rect(i,n,r,a),t.closePath()}}),ey={},iy=Gr.extend({type:"line",shape:{x1:0,y1:0,x2:0,y2:0,percent:1},style:{stroke:"#000",fill:null},buildPath:function(t,e){var i,n,r,a;this.subPixelOptimize?(Zr(ey,e,this.style),i=ey.x1,n=ey.y1,r=ey.x2,a=ey.y2):(i=e.x1,n=e.y1,r=e.x2,a=e.y2);var o=e.percent;0!==o&&(t.moveTo(i,n),1>o&&(r=i*(1-o)+r*o,a=n*(1-o)+a*o),t.lineTo(r,a))},pointAt:function(t){var e=this.shape;return[e.x1*(1-t)+e.x2*t,e.y1*(1-t)+e.y2*t]}}),ny=[],ry=Gr.extend({type:"bezier-curve",shape:{x1:0,y1:0,x2:0,y2:0,cpx1:0,cpy1:0,percent:1},style:{stroke:"#000",fill:null},buildPath:function(t,e){var i=e.x1,n=e.y1,r=e.x2,a=e.y2,o=e.cpx1,s=e.cpy1,l=e.cpx2,u=e.cpy2,h=e.percent;0!==h&&(t.moveTo(i,n),null==l||null==u?(1>h&&(_r(i,o,r,h,ny),o=ny[1],r=ny[2],_r(n,s,a,h,ny),s=ny[1],a=ny[2]),t.quadraticCurveTo(o,s,r,a)):(1>h&&(fr(i,o,l,r,h,ny),o=ny[1],l=ny[2],r=ny[3],fr(n,s,u,a,h,ny),s=ny[1],u=ny[2],a=ny[3]),t.bezierCurveTo(o,s,l,u,r,a)))},pointAt:function(t){return Qr(this.shape,t,!1)},tangentAt:function(t){var e=Qr(this.shape,t,!0);return te(e,e)}}),ay=Gr.extend({type:"arc",shape:{cx:0,cy:0,r:0,startAngle:0,endAngle:2*Math.PI,clockwise:!0},style:{stroke:"#000",fill:null},buildPath:function(t,e){var i=e.cx,n=e.cy,r=Math.max(e.r,0),a=e.startAngle,o=e.endAngle,s=e.clockwise,l=Math.cos(a),u=Math.sin(a);t.moveTo(l*r+i,u*r+n),t.arc(i,n,r,a,o,!s)}}),oy=Gr.extend({type:"compound",shape:{paths:null},_updatePathDirty:function(){for(var t=this.__dirtyPath,e=this.shape.paths,i=0;i"'])/g,Fy={"&":"&","<":"<",">":">",'"':""","'":"'"},Gy=["a","b","c","d","e","f","g"],Vy=function(t,e){return"{"+t+(null==e?"":e)+"}" +},Hy=Xi,Wy=(Object.freeze||Object)({addCommas:So,toCamelCase:Mo,normalizeCssArray:Ry,encodeHTML:Io,formatTpl:Co,formatTplSimple:To,getTooltipMarker:Do,formatTime:ko,capitalFirst:Po,truncateText:Hy,getTextBoundingRect:Lo,getTextRect:Oo}),Uy=f,Xy=["left","right","top","bottom","width","height"],Yy=[["width","left","right"],["height","top","bottom"]],jy=zo,qy=(_(zo,"vertical"),_(zo,"horizontal"),{getBoxLayoutParams:function(){return{left:this.get("left"),top:this.get("top"),right:this.get("right"),bottom:this.get("bottom"),width:this.get("width"),height:this.get("height")}}}),Zy=qn(),Ky=Qa.extend({type:"component",id:"",name:"",mainType:"",subType:"",componentIndex:0,defaultOption:null,ecModel:null,dependentModels:[],uid:null,layoutMode:null,$constructor:function(t,e,i,n){Qa.call(this,t,e,i,n),this.uid=eo("ec_cpt_model")},init:function(t,e,i){this.mergeDefaultAndTheme(t,i)},mergeDefaultAndTheme:function(t,e){var i=this.layoutMode,n=i?Ro(t):{},a=e.getTheme();r(t,a.get(this.mainType)),r(t,this.getDefaultOption()),i&&Eo(t,n,i)},mergeOption:function(t){r(this.option,t,!0);var e=this.layoutMode;e&&Eo(this.option,t,e)},optionUpdated:function(){},getDefaultOption:function(){var t=Zy(this);if(!t.defaultOption){for(var e=[],i=this.constructor;i;){var n=i.prototype.defaultOption;n&&e.push(n),i=i.superClass}for(var a={},o=e.length-1;o>=0;o--)a=r(a,e[o],!0);t.defaultOption=a}return t.defaultOption},getReferringComponents:function(t){return this.ecModel.queryComponents({mainType:t,index:this.get(t+"Index",!0),id:this.get(t+"Id",!0)})}});or(Ky,{registerWhenExtend:!0}),io(Ky),no(Ky,Fo),c(Ky,qy);var $y="";"undefined"!=typeof navigator&&($y=navigator.platform||"");var Qy={color:["#c23531","#2f4554","#61a0a8","#d48265","#91c7ae","#749f83","#ca8622","#bda29a","#6e7074","#546570","#c4ccd3"],gradientColor:["#f6efa6","#d88273","#bf444c"],textStyle:{fontFamily:$y.match(/^Win/)?"Microsoft YaHei":"sans-serif",fontSize:12,fontStyle:"normal",fontWeight:"normal"},blendMode:null,animation:"auto",animationDuration:1e3,animationDurationUpdate:300,animationEasing:"exponentialOut",animationEasingUpdate:"cubicOut",animationThreshold:2e3,progressiveThreshold:3e3,progressive:400,hoverLayerThreshold:3e3,useUTC:!1},Jy=qn(),t_={clearColorPalette:function(){Jy(this).colorIdx=0,Jy(this).colorNameMap={}},getColorFromPalette:function(t,e,i){e=e||this;var n=Jy(e),r=n.colorIdx||0,a=n.colorNameMap=n.colorNameMap||{};if(a.hasOwnProperty(t))return a[t];var o=Fn(this.get("color",!0)),s=this.get("colorLayer",!0),l=null!=i&&s?Go(s,i):o;if(l=l||o,l&&l.length){var u=l[r];return t&&(a[t]=u),n.colorIdx=(r+1)%l.length,u}}},e_={cartesian2d:function(t,e,i,n){var r=t.getReferringComponents("xAxis")[0],a=t.getReferringComponents("yAxis")[0];e.coordSysDims=["x","y"],i.set("x",r),i.set("y",a),Ho(r)&&(n.set("x",r),e.firstCategoryDimIndex=0),Ho(a)&&(n.set("y",a),e.firstCategoryDimIndex=1)},singleAxis:function(t,e,i,n){var r=t.getReferringComponents("singleAxis")[0];e.coordSysDims=["single"],i.set("single",r),Ho(r)&&(n.set("single",r),e.firstCategoryDimIndex=0)},polar:function(t,e,i,n){var r=t.getReferringComponents("polar")[0],a=r.findAxisModel("radiusAxis"),o=r.findAxisModel("angleAxis");e.coordSysDims=["radius","angle"],i.set("radius",a),i.set("angle",o),Ho(a)&&(n.set("radius",a),e.firstCategoryDimIndex=0),Ho(o)&&(n.set("angle",o),e.firstCategoryDimIndex=1)},geo:function(t,e){e.coordSysDims=["lng","lat"]},parallel:function(t,e,i,n){var r=t.ecModel,a=r.getComponent("parallel",t.get("parallelIndex")),o=e.coordSysDims=a.dimensions.slice();f(a.parallelAxisIndex,function(t,a){var s=r.getComponent("parallelAxis",t),l=o[a];i.set(l,s),Ho(s)&&null==e.firstCategoryDimIndex&&(n.set(l,s),e.firstCategoryDimIndex=a)})}},i_="original",n_="arrayRows",r_="objectRows",a_="keyedColumns",o_="unknown",s_="typedArray",l_="column",u_="row";Wo.seriesDataToSource=function(t){return new Wo({data:t,sourceFormat:I(t)?s_:i_,fromDataset:!1})},nr(Wo);var h_=qn(),c_="\x00_ec_inner",d_=Qa.extend({init:function(t,e,i,n){i=i||{},this.option=null,this._theme=new Qa(i),this._optionManager=n},setOption:function(t,e){O(!(c_ in t),"please use chart.getOption()"),this._optionManager.setOption(t,e),this.resetOption(null)},resetOption:function(t){var e=!1,i=this._optionManager;if(!t||"recreate"===t){var n=i.mountOption("recreate"===t);this.option&&"recreate"!==t?(this.restoreData(),this.mergeOption(n)):rs.call(this,n),e=!0}if(("timeline"===t||"media"===t)&&this.restoreData(),!t||"recreate"===t||"timeline"===t){var r=i.getTimelineOption(this);r&&(this.mergeOption(r),e=!0)}if(!t||"recreate"===t||"media"===t){var a=i.getMediaOption(this,this._api);a.length&&f(a,function(t){this.mergeOption(t,e=!0)},this)}return e},mergeOption:function(t){function e(e,n){var r=Fn(t[e]),s=Wn(a.get(e),r);Un(s),f(s,function(t){var i=t.option;S(i)&&(t.keyInfo.mainType=e,t.keyInfo.subType=os(e,i,t.exist))});var l=as(a,n);i[e]=[],a.set(e,[]),f(s,function(t,n){var r=t.exist,s=t.option;if(O(S(s)||r,"Empty component definition"),s){var u=Ky.getClass(e,t.keyInfo.subType,!0);if(r&&r.constructor===u)r.name=t.keyInfo.name,r.mergeOption(s,this),r.optionUpdated(s,!1);else{var h=o({dependentModels:l,componentIndex:n},t.keyInfo);r=new u(s,this,this,h),o(r,h),r.init(s,this,this,h),r.optionUpdated(null,!0)}}else r.mergeOption({},this),r.optionUpdated({},!1);a.get(e)[n]=r,i[e][n]=r.option},this),"series"===e&&ss(this,a.get("series"))}var i=this.option,a=this._componentsMap,s=[];Yo(this),f(t,function(t,e){null!=t&&(Ky.hasClass(e)?e&&s.push(e):i[e]=null==i[e]?n(t):r(i[e],t,!0))}),Ky.topologicalTravel(s,Ky.getAllClassMainTypes(),e,this),this._seriesIndicesMap=N(this._seriesIndices=this._seriesIndices||[])},getOption:function(){var t=n(this.option);return f(t,function(e,i){if(Ky.hasClass(i)){for(var e=Fn(e),n=e.length-1;n>=0;n--)Yn(e[n])&&e.splice(n,1);t[i]=e}}),delete t[c_],t},getTheme:function(){return this._theme},getComponent:function(t,e){var i=this._componentsMap.get(t);return i?i[e||0]:void 0},queryComponents:function(t){var e=t.mainType;if(!e)return[];var i=t.index,n=t.id,r=t.name,a=this._componentsMap.get(e);if(!a||!a.length)return[];var o;if(null!=i)x(i)||(i=[i]),o=v(p(i,function(t){return a[t]}),function(t){return!!t});else if(null!=n){var s=x(n);o=v(a,function(t){return s&&u(n,t.id)>=0||!s&&t.id===n})}else if(null!=r){var l=x(r);o=v(a,function(t){return l&&u(r,t.name)>=0||!l&&t.name===r})}else o=a.slice();return ls(o,t)},findComponents:function(t){function e(t){var e=r+"Index",i=r+"Id",n=r+"Name";return!t||null==t[e]&&null==t[i]&&null==t[n]?null:{mainType:r,index:t[e],id:t[i],name:t[n]}}function i(e){return t.filter?v(e,t.filter):e}var n=t.query,r=t.mainType,a=e(n),o=a?this.queryComponents(a):this._componentsMap.get(r);return i(ls(o,t))},eachComponent:function(t,e,i){var n=this._componentsMap;if("function"==typeof t)i=e,e=t,n.each(function(t,n){f(t,function(t,r){e.call(i,n,t,r)})});else if(b(t))f(n.get(t),e,i);else if(S(t)){var r=this.findComponents(t);f(r,e,i)}},getSeriesByName:function(t){var e=this._componentsMap.get("series");return v(e,function(e){return e.name===t})},getSeriesByIndex:function(t){return this._componentsMap.get("series")[t]},getSeriesByType:function(t){var e=this._componentsMap.get("series");return v(e,function(e){return e.subType===t})},getSeries:function(){return this._componentsMap.get("series").slice()},getSeriesCount:function(){return this._componentsMap.get("series").length},eachSeries:function(t,e){f(this._seriesIndices,function(i){var n=this._componentsMap.get("series")[i];t.call(e,n,i)},this)},eachRawSeries:function(t,e){f(this._componentsMap.get("series"),t,e)},eachSeriesByType:function(t,e,i){f(this._seriesIndices,function(n){var r=this._componentsMap.get("series")[n];r.subType===t&&e.call(i,r,n)},this)},eachRawSeriesByType:function(t,e,i){return f(this.getSeriesByType(t),e,i)},isSeriesFiltered:function(t){return null==this._seriesIndicesMap.get(t.componentIndex)},getCurrentSeriesIndices:function(){return(this._seriesIndices||[]).slice()},filterSeries:function(t,e){var i=v(this._componentsMap.get("series"),t,e);ss(this,i)},restoreData:function(t){var e=this._componentsMap;ss(this,e.get("series"));var i=[];e.each(function(t,e){i.push(e)}),Ky.topologicalTravel(i,Ky.getAllClassMainTypes(),function(i){f(e.get(i),function(e){("series"!==i||!is(e,t))&&e.restoreData()})})}});c(d_,t_);var f_=["getDom","getZr","getWidth","getHeight","getDevicePixelRatio","dispatchAction","isDisposed","on","off","getDataURL","getConnectedDataURL","getModel","getOption","getViewOfComponentModel","getViewOfSeriesModel"],p_={};hs.prototype={constructor:hs,create:function(t,e){var i=[];f(p_,function(n){var r=n.create(t,e);i=i.concat(r||[])}),this._coordinateSystems=i},update:function(t,e){f(this._coordinateSystems,function(i){i.update&&i.update(t,e)})},getCoordinateSystems:function(){return this._coordinateSystems.slice()}},hs.register=function(t,e){p_[t]=e},hs.get=function(t){return p_[t]};var g_=f,v_=n,m_=p,y_=r,__=/^(min|max)?(.+)$/;cs.prototype={constructor:cs,setOption:function(t,e){t&&f(Fn(t.series),function(t){t&&t.data&&I(t.data)&&B(t.data)}),t=v_(t);var i=this._optionBackup,n=ds.call(this,t,e,!i);this._newBaseOption=n.baseOption,i?(vs(i.baseOption,n.baseOption),n.timelineOptions.length&&(i.timelineOptions=n.timelineOptions),n.mediaList.length&&(i.mediaList=n.mediaList),n.mediaDefault&&(i.mediaDefault=n.mediaDefault)):this._optionBackup=n},mountOption:function(t){var e=this._optionBackup;return this._timelineOptions=m_(e.timelineOptions,v_),this._mediaList=m_(e.mediaList,v_),this._mediaDefault=v_(e.mediaDefault),this._currentMediaIndices=[],v_(t?e.baseOption:this._newBaseOption)},getTimelineOption:function(t){var e,i=this._timelineOptions;if(i.length){var n=t.getComponent("timeline");n&&(e=v_(i[n.getCurrentIndex()],!0))}return e},getMediaOption:function(){var t=this._api.getWidth(),e=this._api.getHeight(),i=this._mediaList,n=this._mediaDefault,r=[],a=[];if(!i.length&&!n)return a;for(var o=0,s=i.length;s>o;o++)fs(i[o].query,t,e)&&r.push(o);return!r.length&&n&&(r=[-1]),r.length&&!gs(r,this._currentMediaIndices)&&(a=m_(r,function(t){return v_(-1===t?n.option:i[t].option)})),this._currentMediaIndices=r,a}};var x_=f,w_=S,b_=["areaStyle","lineStyle","nodeStyle","linkStyle","chordStyle","label","labelLine"],S_=function(t,e){x_(Ss(t.series),function(t){w_(t)&&bs(t)});var i=["xAxis","yAxis","radiusAxis","angleAxis","singleAxis","parallelAxis","radar"];e&&i.push("valueAxis","categoryAxis","logAxis","timeAxis"),x_(i,function(e){x_(Ss(t[e]),function(t){t&&(xs(t,"axisLabel"),xs(t.axisPointer,"label"))})}),x_(Ss(t.parallel),function(t){var e=t&&t.parallelAxisDefault;xs(e,"axisLabel"),xs(e&&e.axisPointer,"label")}),x_(Ss(t.calendar),function(t){ys(t,"itemStyle"),xs(t,"dayLabel"),xs(t,"monthLabel"),xs(t,"yearLabel")}),x_(Ss(t.radar),function(t){xs(t,"name")}),x_(Ss(t.geo),function(t){w_(t)&&(ws(t),x_(Ss(t.regions),function(t){ws(t)}))}),x_(Ss(t.timeline),function(t){ws(t),ys(t,"label"),ys(t,"itemStyle"),ys(t,"controlStyle",!0);var e=t.data;x(e)&&f(e,function(t){S(t)&&(ys(t,"label"),ys(t,"itemStyle"))})}),x_(Ss(t.toolbox),function(t){ys(t,"iconStyle"),x_(t.feature,function(t){ys(t,"iconStyle")})}),xs(Ms(t.axisPointer),"label"),xs(Ms(t.tooltip).axisPointer,"label")},M_=[["x","left"],["y","top"],["x2","right"],["y2","bottom"]],I_=["grid","geo","parallel","legend","toolbox","title","visualMap","dataZoom","timeline"],C_=function(t,e){S_(t,e),t.series=Fn(t.series),f(t.series,function(t){if(S(t)){var e=t.type;if("line"===e)null!=t.clipOverflow&&(t.clip=t.clipOverflow);else if("pie"===e||"gauge"===e)null!=t.clockWise&&(t.clockwise=t.clockWise);else if("gauge"===e){var i=Is(t,"pointer.color");null!=i&&Cs(t,"itemStyle.color",i)}Ts(t)}}),t.dataRange&&(t.visualMap=t.dataRange),f(I_,function(e){var i=t[e];i&&(x(i)||(i=[i]),f(i,function(t){Ts(t)}))})},T_=function(t){var e=N();t.eachSeries(function(t){var i=t.get("stack");if(i){var n=e.get(i)||e.set(i,[]),r=t.getData(),a={stackResultDimension:r.getCalculationInfo("stackResultDimension"),stackedOverDimension:r.getCalculationInfo("stackedOverDimension"),stackedDimension:r.getCalculationInfo("stackedDimension"),stackedByDimension:r.getCalculationInfo("stackedByDimension"),isStackedByIndex:r.getCalculationInfo("isStackedByIndex"),data:r,seriesModel:t};if(!a.stackedDimension||!a.isStackedByIndex&&!a.stackedByDimension)return;n.length&&r.setCalculationInfo("stackedOnSeries",n[n.length-1].seriesModel),n.push(a)}}),e.each(Ds)},D_=As.prototype;D_.pure=!1,D_.persistent=!0,D_.getSource=function(){return this._source};var A_={arrayRows_column:{pure:!0,count:function(){return Math.max(0,this._data.length-this._source.startIndex)},getItem:function(t){return this._data[t+this._source.startIndex]},appendData:Ls},arrayRows_row:{pure:!0,count:function(){var t=this._data[0];return t?Math.max(0,t.length-this._source.startIndex):0},getItem:function(t){t+=this._source.startIndex;for(var e=[],i=this._data,n=0;n=1)&&(t=1),t}var i=this._upstream,n=t&&t.skip;if(this._dirty&&i){var r=this.context;r.data=r.outputData=i.context.outputData}this.__pipeline&&(this.__pipeline.currentTask=this);var a;this._plan&&!n&&(a=this._plan(this.context));var o=e(this._modBy),s=this._modDataCount||0,l=e(t&&t.modBy),u=t&&t.modDataCount||0;(o!==l||s!==u)&&(a="reset");var h;(this._dirty||"reset"===a)&&(this._dirty=!1,h=Gs(this,n)),this._modBy=l,this._modDataCount=u;var c=t&&t.step;if(this._dueEnd=i?i._outputDueEnd:this._count?this._count(this.context):1/0,this._progress){var d=this._dueIndex,f=Math.min(null!=c?this._dueIndex+c:1/0,this._dueEnd);if(!n&&(h||f>d)){var p=this._progress;if(x(p))for(var g=0;gn?n++:null}function e(){var t=n%o*r+Math.ceil(n/o),e=n>=i?null:a>t?t:n;return n++,e}var i,n,r,a,o,s={reset:function(l,u,h,c){n=l,i=u,r=h,a=c,o=Math.ceil(a/r),s.next=r>1&&a>0?e:t}};return s}();z_.dirty=function(){this._dirty=!0,this._onDirty&&this._onDirty(this.context)},z_.unfinished=function(){return this._progress&&this._dueIndex":"",v=p+s.join(p||", ");return{renderMode:n,content:v,style:u}}function a(t){return{renderMode:n,content:Io(So(t)),style:u}}var o=this;n=n||"html";var s="html"===n?"
":"\n",l="richText"===n,u={},h=0,c=this.getData(),d=c.mapDimension("defaultedTooltip",!0),p=d.length,v=this.getRawValue(t),m=x(v),y=c.getItemVisual(t,"color");S(y)&&y.colorStops&&(y=(y.colorStops[0]||{}).color),y=y||"transparent";var _=p>1||m&&!p?r(v):a(p?Es(c,t,d[0]):m?v[0]:v),w=_.content,b=o.seriesIndex+"at"+h,M=Do({color:y,type:"item",renderMode:n,markerId:b});u[b]=y,++h;var I=c.getName(t),C=this.name;Xn(this)||(C=""),C=C?Io(C)+(e?": ":s):"";var T="string"==typeof M?M:M.content,D=e?T+C+w:C+T+(I?Io(I)+": "+w:w);return{html:D,markers:u}},isAnimationEnabled:function(){if(gp.node)return!1;var t=this.getShallow("animation");return t&&this.getData().count()>this.getShallow("animationThreshold")&&(t=!1),t},restoreData:function(){this.dataTask.dirty()},getColorFromPalette:function(t,e,i){var n=this.ecModel,r=t_.getColorFromPalette.call(this,t,e,i);return r||(r=n.getColorFromPalette(t,e,i)),r},coordDimToDataDim:function(t){return this.getRawData().mapDimension(t,!0)},getProgressive:function(){return this.get("progressive")},getProgressiveThreshold:function(){return this.get("progressiveThreshold")},getAxisTooltipData:null,getTooltipPosition:null,pipeTask:null,preventIncremental:null,pipelineContext:null});c(R_,O_),c(R_,t_);var N_=function(){this.group=new Dg,this.uid=eo("viewComponent")};N_.prototype={constructor:N_,init:function(){},render:function(){},dispose:function(){},filterForExposedEvent:null};var F_=N_.prototype;F_.updateView=F_.updateLayout=F_.updateVisual=function(){},ir(N_),or(N_,{registerWhenExtend:!0});var G_=function(){var t=qn();return function(e){var i=t(e),n=e.pipelineContext,r=i.large,a=i.progressiveRender,o=i.large=n.large,s=i.progressiveRender=n.progressiveRender;return!!(r^o||a^s)&&"reset"}},V_=qn(),H_=G_();Zs.prototype={type:"chart",init:function(){},render:function(){},highlight:function(t,e,i,n){$s(t.getData(),n,"emphasis")},downplay:function(t,e,i,n){$s(t.getData(),n,"normal")},remove:function(){this.group.removeAll()},dispose:function(){},incrementalPrepareRender:null,incrementalRender:null,updateTransform:null,filterForExposedEvent:null};var W_=Zs.prototype;W_.updateView=W_.updateLayout=W_.updateVisual=function(t,e,i,n){this.render(t,e,i,n)},ir(Zs,["dispose"]),or(Zs,{registerWhenExtend:!0}),Zs.markUpdateMethod=function(t,e){V_(t).updateMethod=e};var U_={incrementalPrepareRender:{progress:function(t,e){e.view.incrementalRender(t,e.model,e.ecModel,e.api,e.payload)}},render:{forceFirstProgress:!0,progress:function(t,e){e.view.render(e.model,e.ecModel,e.api,e.payload)}}},X_="\x00__throttleOriginMethod",Y_="\x00__throttleRate",j_="\x00__throttleType",q_={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){var i=t.getData(),n=(t.visualColorAccessPath||"itemStyle.color").split("."),r=t.get(n)||t.getColorFromPalette(t.name,null,e.getSeriesCount());i.setVisual("color",r);var a=(t.visualBorderColorAccessPath||"itemStyle.borderColor").split("."),o=t.get(a);if(i.setVisual("borderColor",o),!e.isSeriesFiltered(t)){"function"!=typeof r||r instanceof sy||i.each(function(e){i.setItemVisual(e,"color",r(t.getDataParams(e)))});var s=function(t,e){var i=t.getItemModel(e),r=i.get(n,!0),o=i.get(a,!0);null!=r&&t.setItemVisual(e,"color",r),null!=o&&t.setItemVisual(e,"borderColor",o)};return{dataEach:i.hasItemOption?s:null}}}},Z_={legend:{selector:{all:"全选",inverse:"反选"}},toolbox:{brush:{title:{rect:"矩形选择",polygon:"圈选",lineX:"横向选择",lineY:"纵向选择",keep:"保持选择",clear:"清除选择"}},dataView:{title:"数据视图",lang:["数据视图","关闭","刷新"]},dataZoom:{title:{zoom:"区域缩放",back:"区域缩放还原"}},magicType:{title:{line:"切换为折线图",bar:"切换为柱状图",stack:"切换为堆叠",tiled:"切换为平铺"}},restore:{title:"还原"},saveAsImage:{title:"保存为图片",lang:["右键另存为图片"]}},series:{typeNames:{pie:"饼图",bar:"柱状图",line:"折线图",scatter:"散点图",effectScatter:"涟漪散点图",radar:"雷达图",tree:"树图",treemap:"矩形树图",boxplot:"箱型图",candlestick:"K线图",k:"K线图",heatmap:"热力图",map:"地图",parallel:"平行坐标图",lines:"线图",graph:"关系图",sankey:"桑基图",funnel:"漏斗图",gauge:"仪表盘图",pictorialBar:"象形柱图",themeRiver:"主题河流图",sunburst:"旭日图"}},aria:{general:{withTitle:"这是一个关于“{title}”的图表。",withoutTitle:"这是一个图表,"},series:{single:{prefix:"",withName:"图表类型是{seriesType},表示{seriesName}。",withoutName:"图表类型是{seriesType}。"},multiple:{prefix:"它由{seriesCount}个图表系列组成。",withName:"第{seriesId}个系列是一个表示{seriesName}的{seriesType},",withoutName:"第{seriesId}个系列是一个{seriesType},",separator:{middle:";",end:"。"}}},data:{allData:"其数据是——",partialData:"其中,前{displayCnt}项是——",withName:"{name}的数据是{value}",withoutName:"{value}",separator:{middle:",",end:""}}}},K_=function(t,e){function i(t,e){if("string"!=typeof t)return t;var i=t;return f(e,function(t,e){i=i.replace(new RegExp("\\{\\s*"+e+"\\s*\\}","g"),t)}),i}function n(t){var e=o.get(t);if(null==e){for(var i=t.split("."),n=Z_.aria,r=0;rs)){var d=r();l=d?i(n("general.withTitle"),{title:d}):n("general.withoutTitle");var p=[],g=s>1?"series.multiple.prefix":"series.single.prefix";l+=i(n(g),{seriesCount:s}),e.eachSeries(function(t,e){if(c>e){var r,o=t.get("name"),l="series."+(s>1?"multiple":"single")+".";r=n(o?l+"withName":l+"withoutName"),r=i(r,{seriesId:t.seriesIndex,seriesName:t.get("name"),seriesType:a(t.subType)});var h=t.getData();window.data=h,r+=h.count()>u?i(n("data.partialData"),{displayCnt:u}):n("data.allData");for(var d=[],f=0;ff){var g=h.getName(f),v=Es(h,f);d.push(i(n(g?"data.withName":"data.withoutName"),{name:g,value:v}))}r+=d.join(n("data.separator.middle"))+n("data.separator.end"),p.push(r)}}),l+=p.join(n("series.multiple.separator.middle"))+n("series.multiple.separator.end"),t.setAttribute("aria-label",l)}}},$_=Math.PI,Q_=function(t,e){e=e||{},s(e,{text:"loading",color:"#c23531",textColor:"#000",maskColor:"rgba(255, 255, 255, 0.8)",zlevel:0});var i=new ty({style:{fill:e.maskColor},zlevel:e.zlevel,z:1e4}),n=new ay({shape:{startAngle:-$_/2,endAngle:-$_/2+.1,r:10},style:{stroke:e.color,lineCap:"round",lineWidth:5},zlevel:e.zlevel,z:10001}),r=new ty({style:{fill:"none",text:e.text,textPosition:"right",textDistance:10,textFill:e.textColor},zlevel:e.zlevel,z:10001});n.animateShape(!0).when(1e3,{endAngle:3*$_/2}).start("circularInOut"),n.animateShape(!0).when(1e3,{startAngle:3*$_/2}).delay(300).start("circularInOut");var a=new Dg;return a.add(n),a.add(r),a.add(i),a.resize=function(){var e=t.getWidth()/2,a=t.getHeight()/2;n.setShape({cx:e,cy:a});var o=n.shape.r;r.setShape({x:e-o,y:a-o,width:2*o,height:2*o}),i.setShape({x:0,y:0,width:t.getWidth(),height:t.getHeight()})},a.resize(),a},J_=il.prototype;J_.restoreData=function(t,e){t.restoreData(e),this._stageTaskMap.each(function(t){var e=t.overallTask;e&&e.dirty()})},J_.getPerformArgs=function(t,e){if(t.__pipeline){var i=this._pipelineMap.get(t.__pipeline.id),n=i.context,r=!e&&i.progressiveEnabled&&(!n||n.progressiveRender)&&t.__idxInPipeline>i.blockIndex,a=r?i.step:null,o=n&&n.modDataCount,s=null!=o?Math.ceil(o/a):null;return{step:a,modBy:s,modDataCount:o}}},J_.getPipeline=function(t){return this._pipelineMap.get(t)},J_.updateStreamModes=function(t,e){var i=this._pipelineMap.get(t.uid),n=t.getData(),r=n.count(),a=i.progressiveEnabled&&e.incrementalPrepareRender&&r>=i.threshold,o=t.get("large")&&r>=t.get("largeThreshold"),s="mod"===t.get("progressiveChunkMode")?r:null;t.pipelineContext=i.context={progressiveRender:a,modDataCount:s,large:o}},J_.restorePipelines=function(t){var e=this,i=e._pipelineMap=N();t.eachSeries(function(t){var n=t.getProgressive(),r=t.uid;i.set(r,{id:r,head:null,tail:null,threshold:t.getProgressiveThreshold(),progressiveEnabled:n&&!(t.preventIncremental&&t.preventIncremental()),blockIndex:-1,step:Math.round(n||700),count:0}),pl(e,t,t.dataTask)})},J_.prepareStageTasks=function(){var t=this._stageTaskMap,e=this.ecInstance.getModel(),i=this.api;f(this._allHandlers,function(n){var r=t.get(n.uid)||t.set(n.uid,[]);n.reset&&rl(this,n,r,e,i),n.overallReset&&al(this,n,r,e,i)},this)},J_.prepareView=function(t,e,i,n){var r=t.renderTask,a=r.context;a.model=e,a.ecModel=i,a.api=n,r.__block=!t.incrementalPrepareRender,pl(this,e,r)},J_.performDataProcessorTasks=function(t,e){nl(this,this._dataProcessorHandlers,t,e,{block:!0})},J_.performVisualTasks=function(t,e,i){nl(this,this._visualHandlers,t,e,i)},J_.performSeriesTasks=function(t){var e;t.eachSeries(function(t){e|=t.dataTask.perform()}),this.unfinished|=e},J_.plan=function(){this._pipelineMap.each(function(t){var e=t.tail;do{if(e.__block){t.blockIndex=e.__idxInPipeline;break}e=e.getUpstream()}while(e)})};var tx=J_.updatePayload=function(t,e){"remain"!==e&&(t.context.payload=e)},ex=dl(0);il.wrapStageHandler=function(t,e){return w(t)&&(t={overallReset:t,seriesType:gl(t)}),t.uid=eo("stageHandler"),e&&(t.visualType=e),t};var ix,nx={},rx={};vl(nx,d_),vl(rx,us),nx.eachSeriesByType=nx.eachRawSeriesByType=function(t){ix=t},nx.eachComponent=function(t){"series"===t.mainType&&t.subType&&(ix=t.subType)};var ax=["#37A2DA","#32C5E9","#67E0E3","#9FE6B8","#FFDB5C","#ff9f7f","#fb7293","#E062AE","#E690D1","#e7bcf3","#9d96f5","#8378EA","#96BFFF"],ox={color:ax,colorLayer:[["#37A2DA","#ffd85c","#fd7b5f"],["#37A2DA","#67E0E3","#FFDB5C","#ff9f7f","#E062AE","#9d96f5"],["#37A2DA","#32C5E9","#9FE6B8","#FFDB5C","#ff9f7f","#fb7293","#e7bcf3","#8378EA","#96BFFF"],ax]},sx="#eee",lx=function(){return{axisLine:{lineStyle:{color:sx}},axisTick:{lineStyle:{color:sx}},axisLabel:{textStyle:{color:sx}},splitLine:{lineStyle:{type:"dashed",color:"#aaa"}},splitArea:{areaStyle:{color:sx}}}},ux=["#dd6b66","#759aa0","#e69d87","#8dc1a9","#ea7e53","#eedd78","#73a373","#73b9bc","#7289ab","#91ca8c","#f49f42"],hx={color:ux,backgroundColor:"#333",tooltip:{axisPointer:{lineStyle:{color:sx},crossStyle:{color:sx}}},legend:{textStyle:{color:sx}},textStyle:{color:sx},title:{textStyle:{color:sx}},toolbox:{iconStyle:{normal:{borderColor:sx}}},dataZoom:{textStyle:{color:sx}},visualMap:{textStyle:{color:sx}},timeline:{lineStyle:{color:sx},itemStyle:{normal:{color:ux[1]}},label:{normal:{textStyle:{color:sx}}},controlStyle:{normal:{color:sx,borderColor:sx}}},timeAxis:lx(),logAxis:lx(),valueAxis:lx(),categoryAxis:lx(),line:{symbol:"circle"},graph:{color:ux},gauge:{title:{textStyle:{color:sx}}},candlestick:{itemStyle:{normal:{color:"#FD1050",color0:"#0CF49B",borderColor:"#FD1050",borderColor0:"#0CF49B"}}}};hx.categoryAxis.splitLine.show=!1,Ky.extend({type:"dataset",defaultOption:{seriesLayoutBy:l_,sourceHeader:null,dimensions:null,source:null},optionUpdated:function(){Uo(this)}}),N_.extend({type:"dataset"});var cx=Gr.extend({type:"ellipse",shape:{cx:0,cy:0,rx:0,ry:0},buildPath:function(t,e){var i=.5522848,n=e.cx,r=e.cy,a=e.rx,o=e.ry,s=a*i,l=o*i;t.moveTo(n-a,r),t.bezierCurveTo(n-a,r-l,n-s,r-o,n,r-o),t.bezierCurveTo(n+s,r-o,n+a,r-l,n+a,r),t.bezierCurveTo(n+a,r+l,n+s,r+o,n,r+o),t.bezierCurveTo(n-s,r+o,n-a,r+l,n-a,r),t.closePath()}}),dx=/[\s,]+/;yl.prototype.parse=function(t,e){e=e||{};var i=ml(t);if(!i)throw new Error("Illegal svg");var n=new Dg;this._root=n;var r=i.getAttribute("viewBox")||"",a=parseFloat(i.getAttribute("width")||e.width),o=parseFloat(i.getAttribute("height")||e.height);isNaN(a)&&(a=null),isNaN(o)&&(o=null),bl(i,n,null,!0);for(var s=i.firstChild;s;)this._parseNode(s,n),s=s.nextSibling;var l,u;if(r){var h=z(r).split(dx);h.length>=4&&(l={x:parseFloat(h[0]||0),y:parseFloat(h[1]||0),width:parseFloat(h[2]),height:parseFloat(h[3])})}if(l&&null!=a&&null!=o&&(u=Cl(l,a,o),!e.ignoreViewBox)){var c=n;n=new Dg,n.add(c),c.scale=u.scale.slice(),c.position=u.position.slice()}return e.ignoreRootClip||null==a||null==o||n.setClipPath(new ty({shape:{x:0,y:0,width:a,height:o}})),{root:n,width:a,height:o,viewBoxRect:l,viewBoxTransform:u} +},yl.prototype._parseNode=function(t,e){var i=t.nodeName.toLowerCase();"defs"===i?this._isDefine=!0:"text"===i&&(this._isText=!0);var n;if(this._isDefine){var r=px[i];if(r){var a=r.call(this,t),o=t.getAttribute("id");o&&(this._defs[o]=a)}}else{var r=fx[i];r&&(n=r.call(this,t,e),e.add(n))}for(var s=t.firstChild;s;)1===s.nodeType&&this._parseNode(s,n),3===s.nodeType&&this._isText&&this._parseText(s,n),s=s.nextSibling;"defs"===i?this._isDefine=!1:"text"===i&&(this._isText=!1)},yl.prototype._parseText=function(t,e){if(1===t.nodeType){var i=t.getAttribute("dx")||0,n=t.getAttribute("dy")||0;this._textX+=parseFloat(i),this._textY+=parseFloat(n)}var r=new Hm({style:{text:t.textContent,transformText:!0},position:[this._textX||0,this._textY||0]});xl(e,r),bl(t,r,this._defs);var a=r.style.fontSize;a&&9>a&&(r.style.fontSize=9,r.scale=r.scale||[1,1],r.scale[0]*=a/9,r.scale[1]*=a/9);var o=r.getBoundingRect();return this._textX+=o.width,e.add(r),r};var fx={g:function(t,e){var i=new Dg;return xl(e,i),bl(t,i,this._defs),i},rect:function(t,e){var i=new ty;return xl(e,i),bl(t,i,this._defs),i.setShape({x:parseFloat(t.getAttribute("x")||0),y:parseFloat(t.getAttribute("y")||0),width:parseFloat(t.getAttribute("width")||0),height:parseFloat(t.getAttribute("height")||0)}),i},circle:function(t,e){var i=new Wm;return xl(e,i),bl(t,i,this._defs),i.setShape({cx:parseFloat(t.getAttribute("cx")||0),cy:parseFloat(t.getAttribute("cy")||0),r:parseFloat(t.getAttribute("r")||0)}),i},line:function(t,e){var i=new iy;return xl(e,i),bl(t,i,this._defs),i.setShape({x1:parseFloat(t.getAttribute("x1")||0),y1:parseFloat(t.getAttribute("y1")||0),x2:parseFloat(t.getAttribute("x2")||0),y2:parseFloat(t.getAttribute("y2")||0)}),i},ellipse:function(t,e){var i=new cx;return xl(e,i),bl(t,i,this._defs),i.setShape({cx:parseFloat(t.getAttribute("cx")||0),cy:parseFloat(t.getAttribute("cy")||0),rx:parseFloat(t.getAttribute("rx")||0),ry:parseFloat(t.getAttribute("ry")||0)}),i},polygon:function(t,e){var i=t.getAttribute("points");i&&(i=wl(i));var n=new Km({shape:{points:i||[]}});return xl(e,n),bl(t,n,this._defs),n},polyline:function(t,e){var i=new Gr;xl(e,i),bl(t,i,this._defs);var n=t.getAttribute("points");n&&(n=wl(n));var r=new $m({shape:{points:n||[]}});return r},image:function(t,e){var i=new bn;return xl(e,i),bl(t,i,this._defs),i.setStyle({image:t.getAttribute("xlink:href"),x:t.getAttribute("x"),y:t.getAttribute("y"),width:t.getAttribute("width"),height:t.getAttribute("height")}),i},text:function(t,e){var i=t.getAttribute("x")||0,n=t.getAttribute("y")||0,r=t.getAttribute("dx")||0,a=t.getAttribute("dy")||0;this._textX=parseFloat(i)+parseFloat(r),this._textY=parseFloat(n)+parseFloat(a);var o=new Dg;return xl(e,o),bl(t,o,this._defs),o},tspan:function(t,e){var i=t.getAttribute("x"),n=t.getAttribute("y");null!=i&&(this._textX=parseFloat(i)),null!=n&&(this._textY=parseFloat(n));var r=t.getAttribute("dx")||0,a=t.getAttribute("dy")||0,o=new Dg;return xl(e,o),bl(t,o,this._defs),this._textX+=r,this._textY+=a,o},path:function(t,e){var i=t.getAttribute("d")||"",n=Ur(i);return xl(e,n),bl(t,n,this._defs),n}},px={lineargradient:function(t){var e=parseInt(t.getAttribute("x1")||0,10),i=parseInt(t.getAttribute("y1")||0,10),n=parseInt(t.getAttribute("x2")||10,10),r=parseInt(t.getAttribute("y2")||0,10),a=new ly(e,i,n,r);return _l(t,a),a},radialgradient:function(){}},gx={fill:"fill",stroke:"stroke","stroke-width":"lineWidth",opacity:"opacity","fill-opacity":"fillOpacity","stroke-opacity":"strokeOpacity","stroke-dasharray":"lineDash","stroke-dashoffset":"lineDashOffset","stroke-linecap":"lineCap","stroke-linejoin":"lineJoin","stroke-miterlimit":"miterLimit","font-family":"fontFamily","font-size":"fontSize","font-style":"fontStyle","font-weight":"fontWeight","text-align":"textAlign","alignment-baseline":"textBaseline"},vx=/url\(\s*#(.*?)\)/,mx=/(translate|scale|rotate|skewX|skewY|matrix)\(([\-\s0-9\.e,]*)\)/g,yx=/([^\s:;]+)\s*:\s*([^:;]+)/g,_x=N(),xx={registerMap:function(t,e,i){var n;return x(e)?n=e:e.svg?n=[{type:"svg",source:e.svg,specialAreas:e.specialAreas}]:(e.geoJson&&!e.features&&(i=e.specialAreas,e=e.geoJson),n=[{type:"geoJSON",source:e,specialAreas:i}]),f(n,function(t){var e=t.type;"geoJson"===e&&(e=t.type="geoJSON");var i=bx[e];i(t)}),_x.set(t,n)},retrieveMap:function(t){return _x.get(t)}},bx={geoJSON:function(t){var e=t.source;t.geoJSON=b(e)?"undefined"!=typeof JSON&&JSON.parse?JSON.parse(e):new Function("return ("+e+");")():e},svg:function(t){t.svgXML=ml(t.source)}},Sx=O,Mx=f,Ix=w,Cx=S,Tx=Ky.parseClassType,Dx="4.5.0",Ax={zrender:"4.1.2"},kx=1,Px=1e3,Lx=800,Ox=900,zx=5e3,Bx=1e3,Ex=1100,Rx=2e3,Nx=3e3,Fx=3500,Gx=4e3,Vx=5e3,Hx={PROCESSOR:{FILTER:Px,SERIES_FILTER:Lx,STATISTIC:zx},VISUAL:{LAYOUT:Bx,PROGRESSIVE_LAYOUT:Ex,GLOBAL:Rx,CHART:Nx,POST_CHART_LAYOUT:Fx,COMPONENT:Gx,BRUSH:Vx}},Wx="__flagInMainProcess",Ux="__optionUpdated",Xx=/^[a-zA-Z0-9_]+$/;Dl.prototype.on=Tl("on",!0),Dl.prototype.off=Tl("off",!0),Dl.prototype.one=Tl("one",!0),c(Dl,Rp);var Yx=Al.prototype;Yx._onframe=function(){if(!this._disposed){var t=this._scheduler;if(this[Ux]){var e=this[Ux].silent;this[Wx]=!0,Pl(this),jx.update.call(this),this[Wx]=!1,this[Ux]=!1,Bl.call(this,e),El.call(this,e)}else if(t.unfinished){var i=kx,n=this._model,r=this._api;t.unfinished=!1;do{var a=+new Date;t.performSeriesTasks(n),t.performDataProcessorTasks(n),Ol(this,n),t.performVisualTasks(n),Hl(this,this._model,r,"remain"),i-=+new Date-a}while(i>0&&t.unfinished);t.unfinished||this._zr.flush()}}},Yx.getDom=function(){return this._dom},Yx.getZr=function(){return this._zr},Yx.setOption=function(t,e,i){if(!this._disposed){var n;if(Cx(e)&&(i=e.lazyUpdate,n=e.silent,e=e.notMerge),this[Wx]=!0,!this._model||e){var r=new cs(this._api),a=this._theme,o=this._model=new d_;o.scheduler=this._scheduler,o.init(null,null,a,r)}this._model.setOption(t,Qx),i?(this[Ux]={silent:n},this[Wx]=!1):(Pl(this),jx.update.call(this),this._zr.flush(),this[Ux]=!1,this[Wx]=!1,Bl.call(this,n),El.call(this,n))}},Yx.setTheme=function(){console.error("ECharts#setTheme() is DEPRECATED in ECharts 3.0")},Yx.getModel=function(){return this._model},Yx.getOption=function(){return this._model&&this._model.getOption()},Yx.getWidth=function(){return this._zr.getWidth()},Yx.getHeight=function(){return this._zr.getHeight()},Yx.getDevicePixelRatio=function(){return this._zr.painter.dpr||window.devicePixelRatio||1},Yx.getRenderedCanvas=function(t){if(gp.canvasSupported){t=t||{},t.pixelRatio=t.pixelRatio||1,t.backgroundColor=t.backgroundColor||this._model.get("backgroundColor");var e=this._zr;return e.painter.getRenderedCanvas(t)}},Yx.getSvgDataUrl=function(){if(gp.svgSupported){var t=this._zr,e=t.storage.getDisplayList();return f(e,function(t){t.stopAnimation(!0)}),t.painter.pathToDataUrl()}},Yx.getDataURL=function(t){if(!this._disposed){t=t||{};var e=t.excludeComponents,i=this._model,n=[],r=this;Mx(e,function(t){i.eachComponent({mainType:t},function(t){var e=r._componentsMap[t.__viewId];e.group.ignore||(n.push(e),e.group.ignore=!0)})});var a="svg"===this._zr.painter.getType()?this.getSvgDataUrl():this.getRenderedCanvas(t).toDataURL("image/"+(t&&t.type||"png"));return Mx(n,function(t){t.group.ignore=!1}),a}},Yx.getConnectedDataURL=function(t){if(!this._disposed&&gp.canvasSupported){var e=this.group,i=Math.min,r=Math.max,a=1/0;if(rw[e]){var o=a,s=a,l=-a,u=-a,h=[],c=t&&t.pixelRatio||1;f(nw,function(a){if(a.group===e){var c=a.getRenderedCanvas(n(t)),d=a.getDom().getBoundingClientRect();o=i(d.left,o),s=i(d.top,s),l=r(d.right,l),u=r(d.bottom,u),h.push({dom:c,left:d.left,top:d.top})}}),o*=c,s*=c,l*=c,u*=c;var d=l-o,p=u-s,g=Cp();g.width=d,g.height=p;var v=zn(g);return t.connectedBackgroundColor&&v.add(new ty({shape:{x:0,y:0,width:d,height:p},style:{fill:t.connectedBackgroundColor}})),Mx(h,function(t){var e=new bn({style:{x:t.left*c-o,y:t.top*c-s,image:t.dom}});v.add(e)}),v.refreshImmediately(),g.toDataURL("image/"+(t&&t.type||"png"))}return this.getDataURL(t)}},Yx.convertToPixel=_(kl,"convertToPixel"),Yx.convertFromPixel=_(kl,"convertFromPixel"),Yx.containPixel=function(t,e){if(!this._disposed){var i,n=this._model;return t=Zn(n,t),f(t,function(t,n){n.indexOf("Models")>=0&&f(t,function(t){var r=t.coordinateSystem;if(r&&r.containPoint)i|=!!r.containPoint(e);else if("seriesModels"===n){var a=this._chartsMap[t.__viewId];a&&a.containPoint&&(i|=a.containPoint(e,t))}},this)},this),!!i}},Yx.getVisual=function(t,e){var i=this._model;t=Zn(i,t,{defaultMainType:"series"});var n=t.seriesModel,r=n.getData(),a=t.hasOwnProperty("dataIndexInside")?t.dataIndexInside:t.hasOwnProperty("dataIndex")?r.indexOfRawIndex(t.dataIndex):null;return null!=a?r.getItemVisual(a,e):r.getVisual(e)},Yx.getViewOfComponentModel=function(t){return this._componentsMap[t.__viewId]},Yx.getViewOfSeriesModel=function(t){return this._chartsMap[t.__viewId]};var jx={prepareAndUpdate:function(t){Pl(this),jx.update.call(this,t)},update:function(t){var e=this._model,i=this._api,n=this._zr,r=this._coordSysMgr,a=this._scheduler;if(e){a.restoreData(e,t),a.performSeriesTasks(e),r.create(e,i),a.performDataProcessorTasks(e,t),Ol(this,e),r.update(e,i),Fl(e),a.performVisualTasks(e,t),Gl(this,e,i,t);var o=e.get("backgroundColor")||"transparent";if(gp.canvasSupported)n.setBackgroundColor(o);else{var s=qe(o);o=ni(s,"rgb"),0===s[3]&&(o="transparent")}Wl(e,i)}},updateTransform:function(t){var e=this._model,i=this,n=this._api;if(e){var r=[];e.eachComponent(function(a,o){var s=i.getViewOfComponentModel(o);if(s&&s.__alive)if(s.updateTransform){var l=s.updateTransform(o,e,n,t);l&&l.update&&r.push(s)}else r.push(s)});var a=N();e.eachSeries(function(r){var o=i._chartsMap[r.__viewId];if(o.updateTransform){var s=o.updateTransform(r,e,n,t);s&&s.update&&a.set(r.uid,1)}else a.set(r.uid,1)}),Fl(e),this._scheduler.performVisualTasks(e,t,{setDirty:!0,dirtyMap:a}),Hl(i,e,n,t,a),Wl(e,this._api)}},updateView:function(t){var e=this._model;e&&(Zs.markUpdateMethod(t,"updateView"),Fl(e),this._scheduler.performVisualTasks(e,t,{setDirty:!0}),Gl(this,this._model,this._api,t),Wl(e,this._api))},updateVisual:function(t){jx.update.call(this,t)},updateLayout:function(t){jx.update.call(this,t)}};Yx.resize=function(t){if(!this._disposed){this._zr.resize(t);var e=this._model;if(this._loadingFX&&this._loadingFX.resize(),e){var i=e.resetOption("media"),n=t&&t.silent;this[Wx]=!0,i&&Pl(this),jx.update.call(this),this[Wx]=!1,Bl.call(this,n),El.call(this,n)}}},Yx.showLoading=function(t,e){if(!this._disposed&&(Cx(t)&&(e=t,t=""),t=t||"default",this.hideLoading(),iw[t])){var i=iw[t](this._api,e),n=this._zr;this._loadingFX=i,n.add(i)}},Yx.hideLoading=function(){this._disposed||(this._loadingFX&&this._zr.remove(this._loadingFX),this._loadingFX=null)},Yx.makeActionFromEvent=function(t){var e=o({},t);return e.type=Kx[t.type],e},Yx.dispatchAction=function(t,e){if(!this._disposed&&(Cx(e)||(e={silent:!!e}),Zx[t.type]&&this._model)){if(this[Wx])return void this._pendingActions.push(t);zl.call(this,t,e.silent),e.flush?this._zr.flush(!0):e.flush!==!1&&gp.browser.weChat&&this._throttledZrFlush(),Bl.call(this,e.silent),El.call(this,e.silent)}},Yx.appendData=function(t){if(!this._disposed){var e=t.seriesIndex,i=this.getModel(),n=i.getSeriesByIndex(e);n.appendData(t),this._scheduler.unfinished=!0}},Yx.on=Tl("on",!1),Yx.off=Tl("off",!1),Yx.one=Tl("one",!1);var qx=["click","dblclick","mouseover","mouseout","mousemove","mousedown","mouseup","globalout","contextmenu"];Yx._initEvents=function(){Mx(qx,function(t){var e=function(e){var i,n=this.getModel(),r=e.target,a="globalout"===t;if(a)i={};else if(r&&null!=r.dataIndex){var s=r.dataModel||n.getSeriesByIndex(r.seriesIndex);i=s&&s.getDataParams(r.dataIndex,r.dataType,r)||{}}else r&&r.eventData&&(i=o({},r.eventData));if(i){var l=i.componentType,u=i.componentIndex;("markLine"===l||"markPoint"===l||"markArea"===l)&&(l="series",u=i.seriesIndex);var h=l&&null!=u&&n.getComponent(l,u),c=h&&this["series"===h.mainType?"_chartsMap":"_componentsMap"][h.__viewId];i.event=e,i.type=t,this._ecEventProcessor.eventInfo={targetEl:r,packedEvent:i,model:h,view:c},this.trigger(t,i)}};e.zrEventfulCallAtLast=!0,this._zr.on(t,e,this)},this),Mx(Kx,function(t,e){this._messageCenter.on(e,function(t){this.trigger(e,t)},this)},this)},Yx.isDisposed=function(){return this._disposed},Yx.clear=function(){this._disposed||this.setOption({series:[]},!0)},Yx.dispose=function(){if(!this._disposed){this._disposed=!0,$n(this.getDom(),sw,"");var t=this._api,e=this._model;Mx(this._componentsViews,function(i){i.dispose(e,t)}),Mx(this._chartsViews,function(i){i.dispose(e,t)}),this._zr.dispose(),delete nw[this.id]}},c(Al,Rp),ql.prototype={constructor:ql,normalizeQuery:function(t){var e={},i={},n={};if(b(t)){var r=Tx(t);e.mainType=r.main||null,e.subType=r.sub||null}else{var a=["Index","Name","Id"],o={name:1,dataIndex:1,dataType:1};f(t,function(t,r){for(var s=!1,l=0;l0&&h===r.length-u.length){var c=r.slice(0,h);"data"!==c&&(e.mainType=c,e[u.toLowerCase()]=t,s=!0)}}o.hasOwnProperty(r)&&(i[r]=t,s=!0),s||(n[r]=t)})}return{cptQuery:e,dataQuery:i,otherQuery:n}},filter:function(t,e){function i(t,e,i,n){return null==t[i]||e[n||i]===t[i]}var n=this.eventInfo;if(!n)return!0;var r=n.targetEl,a=n.packedEvent,o=n.model,s=n.view;if(!o||!s)return!0;var l=e.cptQuery,u=e.dataQuery;return i(l,o,"mainType")&&i(l,o,"subType")&&i(l,o,"index","componentIndex")&&i(l,o,"name")&&i(l,o,"id")&&i(u,a,"name")&&i(u,a,"dataIndex")&&i(u,a,"dataType")&&(!s.filterForExposedEvent||s.filterForExposedEvent(t,e.otherQuery,r,a))},afterTrigger:function(){this.eventInfo=null}};var Zx={},Kx={},$x=[],Qx=[],Jx=[],tw=[],ew={},iw={},nw={},rw={},aw=new Date-0,ow=new Date-0,sw="_echarts_instance_",lw=Ql;hu(Rx,q_),nu(C_),ru(Ox,T_),du("default",Q_),ou({type:"highlight",event:"highlight",update:"highlight"},G),ou({type:"downplay",event:"downplay",update:"downplay"},G),iu("light",ox),iu("dark",hx);var uw={};wu.prototype={constructor:wu,add:function(t){return this._add=t,this},update:function(t){return this._update=t,this},remove:function(t){return this._remove=t,this},execute:function(){var t,e=this._old,i=this._new,n={},r={},a=[],o=[];for(bu(e,n,a,"_oldKeyGetter",this),bu(i,r,o,"_newKeyGetter",this),t=0;th;h++)this._add&&this._add(l[h]);else this._add&&this._add(l)}}}};var hw=N(["tooltip","label","itemName","itemId","seriesName"]),cw=S,dw="undefined",fw=-1,pw="e\x00\x00",gw={"float":typeof Float64Array===dw?Array:Float64Array,"int":typeof Int32Array===dw?Array:Int32Array,ordinal:Array,number:Array,time:Array},vw=typeof Uint32Array===dw?Array:Uint32Array,mw=typeof Int32Array===dw?Array:Int32Array,yw=typeof Uint16Array===dw?Array:Uint16Array,_w=["hasItemOption","_nameList","_idList","_invertedIndicesMap","_rawData","_chunkSize","_chunkCount","_dimValueGetter","_count","_rawCount","_nameDimIdx","_idDimIdx"],xw=["_extent","_approximateExtent","_rawExtent"],ww=function(t,e){t=t||["x","y"];for(var i={},n=[],r={},a=0;ah;h++){var c=r[h];o[c]||(o[c]=Fu()),n[c]||(n[c]=[]),ku(n,this._dimensionInfos[c],i,u,l),this._chunkCount=n[c].length}for(var d=new Array(a),f=s;l>f;f++){for(var p=f-s,g=Math.floor(f/i),v=f%i,m=0;a>m;m++){var c=r[m],y=this._dimValueGetterArrayRows(t[p]||d,c,p,m);n[c][g][v]=y;var _=o[c];y<_[0]&&(_[0]=y),y>_[1]&&(_[1]=y)}e&&(this._nameList[f]=e[p])}this._rawCount=this._count=l,this._extent={},Pu(this)},bw._initDataFromProvider=function(t,e){if(!(t>=e)){for(var i,n=this._chunkSize,r=this._rawData,a=this._storage,o=this.dimensions,s=o.length,l=this._dimensionInfos,u=this._nameList,h=this._idList,c=this._rawExtent,d=this._nameRepeatCount={},f=this._chunkCount,p=0;s>p;p++){var g=o[p];c[g]||(c[g]=Fu());var v=l[g];0===v.otherDims.itemName&&(i=this._nameDimIdx=p),0===v.otherDims.itemId&&(this._idDimIdx=p),a[g]||(a[g]=[]),ku(a,v,n,f,e),this._chunkCount=a[g].length}for(var m=new Array(s),y=t;e>y;y++){m=r.getItem(y,m);for(var _=Math.floor(y/n),x=y%n,w=0;s>w;w++){var g=o[w],b=a[g][_],S=this._dimValueGetter(m,g,y,w);b[x]=S;var M=c[g];SM[1]&&(M[1]=S)}if(!r.pure){var I=u[y];if(m&&null==I)if(null!=m.name)u[y]=I=m.name;else if(null!=i){var C=o[i],T=a[C][_];if(T){I=T[x];var D=l[C].ordinalMeta;D&&D.categories.length&&(I=D.categories[I])}}var A=null==m?null:m.id;null==A&&null!=I&&(d[I]=d[I]||0,A=I,d[I]>0&&(A+="__ec__"+d[I]),d[I]++),null!=A&&(h[y]=A)}}!r.persistent&&r.clean&&r.clean(),this._rawCount=this._count=e,this._extent={},Pu(this)}},bw.count=function(){return this._count},bw.getIndices=function(){var t,e=this._indices;if(e){var i=e.constructor,n=this._count;if(i===Array){t=new i(n);for(var r=0;n>r;r++)t[r]=e[r]}else t=new i(e.buffer,0,n)}else for(var i=Tu(this),t=new i(this.count()),r=0;r=0&&e=0&&en;n++)i.push(this.get(t[n],e));return i},bw.hasValue=function(t){for(var e=this._dimensionsSummary.dataDimsOnCoord,i=0,n=e.length;n>i;i++)if(isNaN(this.get(e[i],t)))return!1;return!0},bw.getDataExtent=function(t){t=this.getDimension(t);var e=this._storage[t],i=Fu();if(!e)return i;var n,r=this.count(),a=!this._indices;if(a)return this._rawExtent[t].slice();if(n=this._extent[t])return n.slice();n=i;for(var o=n[0],s=n[1],l=0;r>l;l++){var u=this._getFast(t,this.getRawIndex(l));o>u&&(o=u),u>s&&(s=u)}return n=[o,s],this._extent[t]=n,n},bw.getApproximateExtent=function(t){return t=this.getDimension(t),this._approximateExtent[t]||this.getDataExtent(t)},bw.setApproximateExtent=function(t,e){e=this.getDimension(e),this._approximateExtent[e]=t.slice()},bw.getCalculationInfo=function(t){return this._calculationInfo[t]},bw.setCalculationInfo=function(t,e){cw(t)?o(this._calculationInfo,t):this._calculationInfo[t]=e},bw.getSum=function(t){var e=this._storage[t],i=0;if(e)for(var n=0,r=this.count();r>n;n++){var a=this.get(t,n);isNaN(a)||(i+=a)}return i},bw.getMedian=function(t){var e=[];this.each(t,function(t){isNaN(t)||e.push(t)});var i=[].concat(e).sort(function(t,e){return t-e}),n=this.count();return 0===n?0:n%2===1?i[(n-1)/2]:(i[n/2]+i[n/2-1])/2},bw.rawIndexOf=function(t,e){var i=t&&this._invertedIndicesMap[t],n=i[e];return null==n||isNaN(n)?fw:n},bw.indexOfName=function(t){for(var e=0,i=this.count();i>e;e++)if(this.getName(e)===t)return e;return-1},bw.indexOfRawIndex=function(t){if(t>=this._rawCount||0>t)return-1;if(!this._indices)return t;var e=this._indices,i=e[t];if(null!=i&&i=n;){var a=(n+r)/2|0;if(e[a]t))return a;r=a-1}}return-1},bw.indicesOfNearest=function(t,e,i){var n=this._storage,r=n[t],a=[];if(!r)return a;null==i&&(i=1/0);for(var o=Number.MAX_VALUE,s=-1,l=0,u=this.count();u>l;l++){var h=e-this.get(t,l),c=Math.abs(h);i>=h&&o>=c&&((o>c||h>=0&&0>s)&&(o=c,s=h,a.length=0),a.push(l))}return a},bw.getRawIndex=Ou,bw.getRawDataItem=function(t){if(this._rawData.persistent)return this._rawData.getItem(this.getRawIndex(t));for(var e=[],i=0;io;o++)s[o]=this.get(t[o],a);s[o]=a,e.apply(i,s)}}},bw.filterSelf=function(t,e,i,n){if(this._count){"function"==typeof t&&(n=i,i=e,e=t,t=[]),i=i||n||this,t=p(Eu(t),this.getDimension,this);for(var r=this.count(),a=Tu(this),o=new a(r),s=[],l=t.length,u=0,h=t[0],c=0;r>c;c++){var d,f=this.getRawIndex(c);if(0===l)d=e.call(i,c);else if(1===l){var g=this._getFast(h,f);d=e.call(i,g,c)}else{for(var v=0;l>v;v++)s[v]=this._getFast(h,f);s[v]=c,d=e.apply(i,s)}d&&(o[u++]=f)}return r>u&&(this._indices=o),this._count=u,this._extent={},this.getRawIndex=this._indices?zu:Ou,this}},bw.selectRange=function(t){if(this._count){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(i);var n=e.length;if(n){var r=this.count(),a=Tu(this),o=new a(r),s=0,l=e[0],u=t[l][0],h=t[l][1],c=!1;if(!this._indices){var d=0;if(1===n){for(var f=this._storage[e[0]],p=0;pm;m++){var y=g[m];(y>=u&&h>=y||isNaN(y))&&(o[s++]=d),d++}c=!0}else if(2===n){for(var f=this._storage[l],_=this._storage[e[1]],x=t[e[1]][0],w=t[e[1]][1],p=0;pm;m++){var y=g[m],S=b[m];(y>=u&&h>=y||isNaN(y))&&(S>=x&&w>=S||isNaN(S))&&(o[s++]=d),d++}c=!0}}if(!c)if(1===n)for(var m=0;r>m;m++){var M=this.getRawIndex(m),y=this._getFast(l,M);(y>=u&&h>=y||isNaN(y))&&(o[s++]=M)}else for(var m=0;r>m;m++){for(var I=!0,M=this.getRawIndex(m),p=0;n>p;p++){var C=e[p],y=this._getFast(i,M);(yt[C][1])&&(I=!1)}I&&(o[s++]=this.getRawIndex(m))}return r>s&&(this._indices=o),this._count=s,this._extent={},this.getRawIndex=this._indices?zu:Ou,this}}},bw.mapArray=function(t,e,i,n){"function"==typeof t&&(n=i,i=e,e=t,t=[]),i=i||n||this;var r=[];return this.each(t,function(){r.push(e&&e.apply(this,arguments))},i),r},bw.map=function(t,e,i,n){i=i||n||this,t=p(Eu(t),this.getDimension,this);var r=Ru(this,t);r._indices=this._indices,r.getRawIndex=r._indices?zu:Ou;for(var a=r._storage,o=[],s=this._chunkSize,l=t.length,u=this.count(),h=[],c=r._rawExtent,d=0;u>d;d++){for(var f=0;l>f;f++)h[f]=this.get(t[f],d);h[l]=d;var g=e&&e.apply(i,h);if(null!=g){"object"!=typeof g&&(o[0]=g,g=o);for(var v=this.getRawIndex(d),m=Math.floor(v/s),y=v%s,_=0;_b[1]&&(b[1]=w)}}}return r},bw.downSample=function(t,e,i,n){for(var r=Ru(this,[t]),a=r._storage,o=[],s=Math.floor(1/e),l=a[t],u=this.count(),h=this._chunkSize,c=r._rawExtent[t],d=new(Tu(this))(u),f=0,p=0;u>p;p+=s){s>u-p&&(s=u-p,o.length=s);for(var g=0;s>g;g++){var v=this.getRawIndex(p+g),m=Math.floor(v/h),y=v%h;o[g]=l[m][y]}var _=i(o),x=this.getRawIndex(Math.min(p+n(o,_)||0,u-1)),w=Math.floor(x/h),b=x%h;l[w][b]=_,_c[1]&&(c[1]=_),d[f++]=x}return r._count=f,r._indices=d,r.getRawIndex=zu,r},bw.getItemModel=function(t){var e=this.hostModel;return new Qa(this.getRawDataItem(t),e,e&&e.ecModel)},bw.diff=function(t){var e=this;return new wu(t?t.getIndices():[],this.getIndices(),function(e){return Bu(t,e)},function(t){return Bu(e,t)})},bw.getVisual=function(t){var e=this._visual;return e&&e[t]},bw.setVisual=function(t,e){if(cw(t))for(var i in t)t.hasOwnProperty(i)&&this.setVisual(i,t[i]);else this._visual=this._visual||{},this._visual[t]=e},bw.setLayout=function(t,e){if(cw(t))for(var i in t)t.hasOwnProperty(i)&&this.setLayout(i,t[i]);else this._layout[t]=e},bw.getLayout=function(t){return this._layout[t]},bw.getItemLayout=function(t){return this._itemLayouts[t]},bw.setItemLayout=function(t,e,i){this._itemLayouts[t]=i?o(this._itemLayouts[t]||{},e):e},bw.clearItemLayouts=function(){this._itemLayouts.length=0},bw.getItemVisual=function(t,e,i){var n=this._itemVisuals[t],r=n&&n[e];return null!=r||i?r:this.getVisual(e)},bw.setItemVisual=function(t,e,i){var n=this._itemVisuals[t]||{},r=this.hasItemVisual;if(this._itemVisuals[t]=n,cw(e))for(var a in e)e.hasOwnProperty(a)&&(n[a]=e[a],r[a]=!0);else n[e]=i,r[e]=!0},bw.clearAllVisual=function(){this._visual={},this._itemVisuals=[],this.hasItemVisual={}};var Sw=function(t){t.seriesIndex=this.seriesIndex,t.dataIndex=this.dataIndex,t.dataType=this.dataType};bw.setItemGraphicEl=function(t,e){var i=this.hostModel;e&&(e.dataIndex=t,e.dataType=this.dataType,e.seriesIndex=i&&i.seriesIndex,"group"===e.type&&e.traverse(Sw,e)),this._graphicEls[t]=e},bw.getItemGraphicEl=function(t){return this._graphicEls[t]},bw.eachItemGraphicEl=function(t,e){f(this._graphicEls,function(i,n){i&&t&&t.call(e,i,n)})},bw.cloneShallow=function(t){if(!t){var e=p(this.dimensions,this.getDimensionInfo,this);t=new ww(e,this.hostModel)}if(t._storage=this._storage,Au(t,this),this._indices){var i=this._indices.constructor;t._indices=new i(this._indices)}else t._indices=null;return t.getRawIndex=t._indices?zu:Ou,t},bw.wrapMethod=function(t,e){var i=this[t];"function"==typeof i&&(this.__wrappedMethods=this.__wrappedMethods||[],this.__wrappedMethods.push(t),this[t]=function(){var t=i.apply(this,arguments);return e.apply(this,[t].concat(P(arguments)))})},bw.TRANSFERABLE_METHODS=["cloneShallow","downSample","map"],bw.CHANGABLE_METHODS=["filterSelf","selectRange"];var Mw=function(t,e){return e=e||{},Gu(e.coordDimensions||[],t,{dimsDef:e.dimensionsDefine||t.dimensionsDefine,encodeDef:e.encodeDefine||t.encodeDefine,dimCount:e.dimensionsCount,generateCoord:e.generateCoord,generateCoordCount:e.generateCoordCount})};Zu.prototype.parse=function(t){return t},Zu.prototype.getSetting=function(t){return this._setting[t]},Zu.prototype.contain=function(t){var e=this._extent;return t>=e[0]&&t<=e[1]},Zu.prototype.normalize=function(t){var e=this._extent;return e[1]===e[0]?.5:(t-e[0])/(e[1]-e[0])},Zu.prototype.scale=function(t){var e=this._extent;return t*(e[1]-e[0])+e[0]},Zu.prototype.unionExtent=function(t){var e=this._extent;t[0]e[1]&&(e[1]=t[1])},Zu.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},Zu.prototype.getExtent=function(){return this._extent.slice()},Zu.prototype.setExtent=function(t,e){var i=this._extent;isNaN(t)||(i[0]=t),isNaN(e)||(i[1]=e)},Zu.prototype.isBlank=function(){return this._isBlank},Zu.prototype.setBlank=function(t){this._isBlank=t},Zu.prototype.getLabel=null,ir(Zu),or(Zu,{registerWhenExtend:!0}),Ku.createByAxisModel=function(t){var e=t.option,i=e.data,n=i&&p(i,Qu);return new Ku({categories:n,needCollect:!n,deduplication:e.dedplication!==!1})};var Iw=Ku.prototype;Iw.getOrdinal=function(t){return $u(this).get(t)},Iw.parseAndCollect=function(t){var e,i=this._needCollect;if("string"!=typeof t&&!i)return t;if(i&&!this._deduplication)return e=this.categories.length,this.categories[e]=t,e;var n=$u(this);return e=n.get(t),null==e&&(i?(e=this.categories.length,this.categories[e]=t,n.set(t,e)):e=0/0),e};var Cw=Zu.prototype,Tw=Zu.extend({type:"ordinal",init:function(t,e){(!t||x(t))&&(t=new Ku({categories:t})),this._ordinalMeta=t,this._extent=e||[0,t.categories.length-1]},parse:function(t){return"string"==typeof t?this._ordinalMeta.getOrdinal(t):Math.round(t)},contain:function(t){return t=this.parse(t),Cw.contain.call(this,t)&&null!=this._ordinalMeta.categories[t]},normalize:function(t){return Cw.normalize.call(this,this.parse(t))},scale:function(t){return Math.round(Cw.scale.call(this,t))},getTicks:function(){for(var t=[],e=this._extent,i=e[0];i<=e[1];)t.push(i),i++;return t},getLabel:function(t){return this.isBlank()?void 0:this._ordinalMeta.categories[t]},count:function(){return this._extent[1]-this._extent[0]+1},unionExtentFromData:function(t,e){this.unionExtent(t.getApproximateExtent(e))},getOrdinalMeta:function(){return this._ordinalMeta},niceTicks:G,niceExtent:G});Tw.create=function(){return new Tw};var Dw=so,Aw=so,kw=Zu.extend({type:"interval",_interval:0,_intervalPrecision:2,setExtent:function(t,e){var i=this._extent;isNaN(t)||(i[0]=parseFloat(t)),isNaN(e)||(i[1]=parseFloat(e))},unionExtent:function(t){var e=this._extent;t[0]e[1]&&(e[1]=t[1]),kw.prototype.setExtent.call(this,e[0],e[1])},getInterval:function(){return this._interval},setInterval:function(t){this._interval=t,this._niceExtent=this._extent.slice(),this._intervalPrecision=th(t)},getTicks:function(){return nh(this._interval,this._extent,this._niceExtent,this._intervalPrecision)},getLabel:function(t,e){if(null==t)return"";var i=e&&e.precision;return null==i?i=ho(t)||0:"auto"===i&&(i=this._intervalPrecision),t=Aw(t,i,!0),So(t)},niceTicks:function(t,e,i){t=t||5;var n=this._extent,r=n[1]-n[0];if(isFinite(r)){0>r&&(r=-r,n.reverse());var a=Ju(n,t,e,i);this._intervalPrecision=a.intervalPrecision,this._interval=a.interval,this._niceExtent=a.niceTickExtent}},niceExtent:function(t){var e=this._extent;if(e[0]===e[1])if(0!==e[0]){var i=e[0];t.fixMax?e[0]-=i/2:(e[1]+=i/2,e[0]-=i/2)}else e[1]=1;var n=e[1]-e[0];isFinite(n)||(e[0]=0,e[1]=1),this.niceTicks(t.splitNumber,t.minInterval,t.maxInterval);var r=this._interval;t.fixMin||(e[0]=Aw(Math.floor(e[0]/r)*r)),t.fixMax||(e[1]=Aw(Math.ceil(e[1]/r)*r))}});kw.create=function(){return new kw};var Pw="__ec_stack_",Lw=.5,Ow="undefined"!=typeof Float32Array?Float32Array:Array,zw=({seriesType:"bar",plan:G_(),reset:function(t){function e(t,e){for(var i,c=t.count,d=new Ow(2*c),f=new Ow(c),p=[],g=[],v=0,m=0;null!=(i=t.next());)g[u]=e.get(o,i),g[1-u]=e.get(s,i),p=n.dataToPoint(g,null,p),d[v++]=p[0],d[v++]=p[1],f[m++]=i;e.setLayout({largePoints:d,largeDataIndices:f,barWidth:h,valueAxisStart:fh(r,a,!1),valueAxisHorizontal:l})}if(ch(t)&&dh(t)){var i=t.getData(),n=t.coordinateSystem,r=n.getBaseAxis(),a=n.getOtherAxis(r),o=i.mapDimension(a.dim),s=i.mapDimension(r.dim),l=a.isHorizontal(),u=l?0:1,h=hh(lh([t]),r,t).width; +return h>Lw||(h=Lw),{progress:e}}}},kw.prototype),Bw=Math.ceil,Ew=Math.floor,Rw=1e3,Nw=60*Rw,Fw=60*Nw,Gw=24*Fw,Vw=function(t,e,i,n){for(;n>i;){var r=i+n>>>1;t[r][1]a&&(a=e),null!=i&&a>i&&(a=i);var o=Ww.length,s=Vw(Ww,a,0,o),l=Ww[Math.min(s,o-1)],u=l[1];if("year"===l[0]){var h=r/u,c=_o(h/t,!0);u*=c}var d=this.getSetting("useUTC")?0:60*new Date(+n[0]||+n[1]).getTimezoneOffset()*1e3,f=[Math.round(Bw((n[0]-d)/u)*u+d),Math.round(Ew((n[1]-d)/u)*u+d)];ih(f,n),this._stepLvl=l,this._interval=u,this._niceExtent=f},parse:function(t){return+vo(t)}});f(["contain","normalize"],function(t){Hw.prototype[t]=function(e){return zw[t].call(this,this.parse(e))}});var Ww=[["hh:mm:ss",Rw],["hh:mm:ss",5*Rw],["hh:mm:ss",10*Rw],["hh:mm:ss",15*Rw],["hh:mm:ss",30*Rw],["hh:mm\nMM-dd",Nw],["hh:mm\nMM-dd",5*Nw],["hh:mm\nMM-dd",10*Nw],["hh:mm\nMM-dd",15*Nw],["hh:mm\nMM-dd",30*Nw],["hh:mm\nMM-dd",Fw],["hh:mm\nMM-dd",2*Fw],["hh:mm\nMM-dd",6*Fw],["hh:mm\nMM-dd",12*Fw],["MM-dd\nyyyy",Gw],["MM-dd\nyyyy",2*Gw],["MM-dd\nyyyy",3*Gw],["MM-dd\nyyyy",4*Gw],["MM-dd\nyyyy",5*Gw],["MM-dd\nyyyy",6*Gw],["week",7*Gw],["MM-dd\nyyyy",10*Gw],["week",14*Gw],["week",21*Gw],["month",31*Gw],["week",42*Gw],["month",62*Gw],["week",70*Gw],["quarter",95*Gw],["month",31*Gw*4],["month",31*Gw*5],["half-year",380*Gw/2],["month",31*Gw*8],["month",31*Gw*10],["year",380*Gw]];Hw.create=function(t){return new Hw({useUTC:t.ecModel.get("useUTC")})};var Uw=Zu.prototype,Xw=kw.prototype,Yw=ho,jw=so,qw=Math.floor,Zw=Math.ceil,Kw=Math.pow,$w=Math.log,Qw=Zu.extend({type:"log",base:10,$constructor:function(){Zu.apply(this,arguments),this._originalScale=new kw},getTicks:function(){var t=this._originalScale,e=this._extent,i=t.getExtent();return p(Xw.getTicks.call(this),function(n){var r=so(Kw(this.base,n));return r=n===e[0]&&t.__fixMin?ph(r,i[0]):r,r=n===e[1]&&t.__fixMax?ph(r,i[1]):r},this)},getLabel:Xw.getLabel,scale:function(t){return t=Uw.scale.call(this,t),Kw(this.base,t)},setExtent:function(t,e){var i=this.base;t=$w(t)/$w(i),e=$w(e)/$w(i),Xw.setExtent.call(this,t,e)},getExtent:function(){var t=this.base,e=Uw.getExtent.call(this);e[0]=Kw(t,e[0]),e[1]=Kw(t,e[1]);var i=this._originalScale,n=i.getExtent();return i.__fixMin&&(e[0]=ph(e[0],n[0])),i.__fixMax&&(e[1]=ph(e[1],n[1])),e},unionExtent:function(t){this._originalScale.unionExtent(t);var e=this.base;t[0]=$w(t[0])/$w(e),t[1]=$w(t[1])/$w(e),Uw.unionExtent.call(this,t)},unionExtentFromData:function(t,e){this.unionExtent(t.getApproximateExtent(e))},niceTicks:function(t){t=t||10;var e=this._extent,i=e[1]-e[0];if(!(1/0===i||0>=i)){var n=mo(i),r=t/i*n;for(.5>=r&&(n*=10);!isNaN(n)&&Math.abs(n)<1&&Math.abs(n)>0;)n*=10;var a=[so(Zw(e[0]/n)*n),so(qw(e[1]/n)*n)];this._interval=n,this._niceExtent=a}},niceExtent:function(t){Xw.niceExtent.call(this,t);var e=this._originalScale;e.__fixMin=t.fixMin,e.__fixMax=t.fixMax}});f(["contain","normalize"],function(t){Qw.prototype[t]=function(e){return e=$w(e)/$w(this.base),Uw[t].call(this,e)}}),Qw.create=function(){return new Qw};var Jw={getMin:function(t){var e=this.option,i=t||null==e.rangeStart?e.min:e.rangeStart;return this.axis&&null!=i&&"dataMin"!==i&&"function"!=typeof i&&!T(i)&&(i=this.axis.scale.parse(i)),i},getMax:function(t){var e=this.option,i=t||null==e.rangeEnd?e.max:e.rangeEnd;return this.axis&&null!=i&&"dataMax"!==i&&"function"!=typeof i&&!T(i)&&(i=this.axis.scale.parse(i)),i},getNeedCrossZero:function(){var t=this.option;return null!=t.rangeStart||null!=t.rangeEnd?!1:!t.scale},getCoordSysModel:G,setRange:function(t,e){this.option.rangeStart=t,this.option.rangeEnd=e},resetRange:function(){this.option.rangeStart=this.option.rangeEnd=null}},tb=ta({type:"triangle",shape:{cx:0,cy:0,width:0,height:0},buildPath:function(t,e){var i=e.cx,n=e.cy,r=e.width/2,a=e.height/2;t.moveTo(i,n-a),t.lineTo(i+r,n+a),t.lineTo(i-r,n+a),t.closePath()}}),eb=ta({type:"diamond",shape:{cx:0,cy:0,width:0,height:0},buildPath:function(t,e){var i=e.cx,n=e.cy,r=e.width/2,a=e.height/2;t.moveTo(i,n-a),t.lineTo(i+r,n),t.lineTo(i,n+a),t.lineTo(i-r,n),t.closePath()}}),ib=ta({type:"pin",shape:{x:0,y:0,width:0,height:0},buildPath:function(t,e){var i=e.x,n=e.y,r=e.width/5*3,a=Math.max(r,e.height),o=r/2,s=o*o/(a-o),l=n-a+o+s,u=Math.asin(s/o),h=Math.cos(u)*o,c=Math.sin(u),d=Math.cos(u),f=.6*o,p=.7*o;t.moveTo(i-h,l+s),t.arc(i,l,o,Math.PI-u,2*Math.PI+u),t.bezierCurveTo(i+h-c*f,l+s+d*f,i,n-p,i,n),t.bezierCurveTo(i,n-p,i-h+c*f,l+s+d*f,i-h,l+s),t.closePath()}}),nb=ta({type:"arrow",shape:{x:0,y:0,width:0,height:0},buildPath:function(t,e){var i=e.height,n=e.width,r=e.x,a=e.y,o=n/3*2;t.moveTo(r,a),t.lineTo(r+o,a+i),t.lineTo(r,a+i/4*3),t.lineTo(r-o,a+i),t.lineTo(r,a),t.closePath()}}),rb={line:iy,rect:ty,roundRect:ty,square:ty,circle:Wm,diamond:eb,pin:ib,arrow:nb,triangle:tb},ab={line:function(t,e,i,n,r){r.x1=t,r.y1=e+n/2,r.x2=t+i,r.y2=e+n/2},rect:function(t,e,i,n,r){r.x=t,r.y=e,r.width=i,r.height=n},roundRect:function(t,e,i,n,r){r.x=t,r.y=e,r.width=i,r.height=n,r.r=Math.min(i,n)/4},square:function(t,e,i,n,r){var a=Math.min(i,n);r.x=t,r.y=e,r.width=a,r.height=a},circle:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.r=Math.min(i,n)/2},diamond:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.width=i,r.height=n},pin:function(t,e,i,n,r){r.x=t+i/2,r.y=e+n/2,r.width=i,r.height=n},arrow:function(t,e,i,n,r){r.x=t+i/2,r.y=e+n/2,r.width=i,r.height=n},triangle:function(t,e,i,n,r){r.cx=t+i/2,r.cy=e+n/2,r.width=i,r.height=n}},ob={};f(rb,function(t,e){ob[e]=new t});var sb=ta({type:"symbol",shape:{symbolType:"",x:0,y:0,width:0,height:0},calculateTextPosition:function(t,e,i){var n=Ui(t,e,i),r=this.shape;return r&&"pin"===r.symbolType&&"inside"===e.textPosition&&(n.y=i.y+.4*i.height),n},buildPath:function(t,e,i){var n=e.symbolType;if("none"!==n){var r=ob[n];r||(n="rect",r=ob[n]),ab[n](e.x,e.y,e.width,e.height,r.shape),r.buildPath(t,r.shape,i)}}}),lb={isDimensionStacked:Uu,enableDataStack:Wu,getStackedDimension:Xu},ub=(Object.freeze||Object)({createList:Dh,getLayoutRect:Bo,dataStack:lb,createScale:Ah,mixinAxisModelCommonMethods:kh,completeDimensions:Gu,createDimensions:Mw,createSymbol:Th}),hb=1e-8;Oh.prototype={constructor:Oh,properties:null,getBoundingRect:function(){var t=this._rect;if(t)return t;for(var e=Number.MAX_VALUE,i=[e,e],n=[-e,-e],r=[],a=[],o=this.geometries,s=0;sn;n++)if("polygon"===i[n].type){var a=i[n].exterior,o=i[n].interiors;if(Lh(a,t[0],t[1])){for(var s=0;s<(o?o.length:0);s++)if(Lh(o[s]))continue t;return!0}}return!1},transformTo:function(t,e,i,n){var r=this.getBoundingRect(),a=r.width/r.height;i?n||(n=i/a):i=a*n;for(var o=new xi(t,e,i,n),s=r.calculateTransform(o),l=this.geometries,u=0;u0}),function(t){var e=t.properties,i=t.geometry,n=i.coordinates,r=[];"Polygon"===i.type&&r.push({type:"polygon",exterior:n[0],interiors:n.slice(1)}),"MultiPolygon"===i.type&&f(n,function(t){t[0]&&r.push({type:"polygon",exterior:t[0],interiors:t.slice(1)})});var a=new Oh(e.name,r,e.cp);return a.properties=e,a})},db=qn(),fb=[0,1],pb=function(t,e,i){this.dim=t,this.scale=e,this._extent=i||[0,0],this.inverse=!1,this.onBand=!1};pb.prototype={constructor:pb,contain:function(t){var e=this._extent,i=Math.min(e[0],e[1]),n=Math.max(e[0],e[1]);return t>=i&&n>=t},containData:function(t){return this.contain(this.dataToCoord(t))},getExtent:function(){return this._extent.slice()},getPixelPrecision:function(t){return co(t||this.scale.getExtent(),this._extent)},setExtent:function(t,e){var i=this._extent;i[0]=t,i[1]=e},dataToCoord:function(t,e){var i=this._extent,n=this.scale;return t=n.normalize(t),this.onBand&&"ordinal"===n.type&&(i=i.slice(),Kh(i,n.count())),ao(t,fb,i,e)},coordToData:function(t,e){var i=this._extent,n=this.scale;this.onBand&&"ordinal"===n.type&&(i=i.slice(),Kh(i,n.count()));var r=ao(t,i,fb,e);return this.scale.scale(r)},pointToData:function(){},getTicksCoords:function(t){t=t||{};var e=t.tickModel||this.getTickModel(),i=Rh(this,e),n=i.ticks,r=p(n,function(t){return{coord:this.dataToCoord(t),tickValue:t}},this),a=e.get("alignWithLabel");return $h(this,r,a,t.clamp),r},getViewLabels:function(){return Eh(this).labels},getLabelModel:function(){return this.model.getModel("axisLabel")},getTickModel:function(){return this.model.getModel("axisTick")},getBandWidth:function(){var t=this._extent,e=this.scale.getExtent(),i=e[1]-e[0]+(this.onBand?1:0);0===i&&(i=1);var n=Math.abs(t[1]-t[0]);return Math.abs(n)/i},isHorizontal:null,getRotate:null,calculateCategoryInterval:function(){return Yh(this)}};var gb=cb,vb={};f(["map","each","filter","indexOf","inherits","reduce","filter","bind","curry","isArray","isString","isObject","isFunction","extend","defaults","clone","merge"],function(t){vb[t]=Ap[t]});var mb={};f(["extendShape","extendPath","makePath","makeImage","mergePath","resizePath","createIcon","setHoverStyle","setLabelStyle","setTextStyle","setText","getFont","updateProps","initProps","getTransform","clipPointsByRect","clipRectByRect","registerShape","getShapeClass","Group","Image","Text","Circle","Sector","Ring","Polygon","Polyline","Rect","Line","BezierCurve","Arc","IncrementalDisplayable","CompoundPath","LinearGradient","RadialGradient","BoundingRect"],function(t){mb[t]=Iy[t]}),R_.extend({type:"series.line",dependencies:["grid","polar"],getInitialData:function(){return Yu(this.getSource(),this)},defaultOption:{zlevel:0,z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,hoverAnimation:!0,clip:!0,label:{position:"top"},lineStyle:{width:2,type:"solid"},step:!1,smooth:!1,smoothMonotone:null,symbol:"emptyCircle",symbolSize:4,symbolRotate:null,showSymbol:!0,showAllSymbol:"auto",connectNulls:!1,sampling:"none",animationEasing:"linear",progressive:0,hoverLayerThreshold:1/0}});var yb=Jh.prototype,_b=Jh.getSymbolSize=function(t,e){var i=t.getItemVisual(e,"symbolSize");return i instanceof Array?i.slice():[+i,+i]};yb._createSymbol=function(t,e,i,n,r){this.removeAll();var a=e.getItemVisual(i,"color"),o=Th(t,-1,-1,2,2,a,r);o.attr({z2:100,culling:!0,scale:tc(n)}),o.drift=ec,this._symbolType=t,this.add(o)},yb.stopSymbolAnimation=function(t){this.childAt(0).stopAnimation(t)},yb.getSymbolPath=function(){return this.childAt(0)},yb.getScale=function(){return this.childAt(0).scale},yb.highlight=function(){this.childAt(0).trigger("emphasis")},yb.downplay=function(){this.childAt(0).trigger("normal")},yb.setZ=function(t,e){var i=this.childAt(0);i.zlevel=t,i.z=e},yb.setDraggable=function(t){var e=this.childAt(0);e.draggable=t,e.cursor=t?"move":e.cursor},yb.updateData=function(t,e,i){this.silent=!1;var n=t.getItemVisual(e,"symbol")||"circle",r=t.hostModel,a=_b(t,e),o=n!==this._symbolType;if(o){var s=t.getItemVisual(e,"symbolKeepAspect");this._createSymbol(n,t,e,a,s)}else{var l=this.childAt(0);l.silent=!1,Fa(l,{scale:tc(a)},r,e)}if(this._updateCommon(t,e,a,i),o){var l=this.childAt(0),u=i&&i.fadeIn,h={scale:l.scale.slice()};u&&(h.style={opacity:l.style.opacity}),l.scale=[0,0],u&&(l.style.opacity=0),Ga(l,h,r,e)}this._seriesModel=r};var xb=["itemStyle"],wb=["emphasis","itemStyle"],bb=["label"],Sb=["emphasis","label"];yb._updateCommon=function(t,e,i,n){function r(e){return b?t.getName(e):Qh(t,e)}var a=this.childAt(0),s=t.hostModel,l=t.getItemVisual(e,"color");"image"!==a.type?a.useStyle({strokeNoScale:!0}):a.setStyle({opacity:null,shadowBlur:null,shadowOffsetX:null,shadowOffsetY:null,shadowColor:null});var u=n&&n.itemStyle,h=n&&n.hoverItemStyle,c=n&&n.symbolRotate,d=n&&n.symbolOffset,f=n&&n.labelModel,p=n&&n.hoverLabelModel,g=n&&n.hoverAnimation,v=n&&n.cursorStyle;if(!n||t.hasItemOption){var m=n&&n.itemModel?n.itemModel:t.getItemModel(e);u=m.getModel(xb).getItemStyle(["color"]),h=m.getModel(wb).getItemStyle(),c=m.getShallow("symbolRotate"),d=m.getShallow("symbolOffset"),f=m.getModel(bb),p=m.getModel(Sb),g=m.getShallow("hoverAnimation"),v=m.getShallow("cursor")}else h=o({},h);var y=a.style;a.attr("rotation",(c||0)*Math.PI/180||0),d&&a.attr("position",[oo(d[0],i[0]),oo(d[1],i[1])]),v&&a.attr("cursor",v),a.setColor(l,n&&n.symbolInnerColor),a.setStyle(u);var _=t.getItemVisual(e,"opacity");null!=_&&(y.opacity=_);var x=t.getItemVisual(e,"liftZ"),w=a.__z2Origin;null!=x?null==w&&(a.__z2Origin=a.z2,a.z2+=x):null!=w&&(a.z2=w,a.__z2Origin=null);var b=n&&n.useNameLabel;Ta(y,h,f,p,{labelFetcher:s,labelDataIndex:e,defaultText:r,isRectText:!0,autoColor:l}),a.__symbolOriginalScale=tc(i),a.hoverStyle=h,a.highDownOnUpdate=g&&s.isAnimationEnabled()?ic:null,Sa(a)},yb.fadeOut=function(t,e){var i=this.childAt(0);this.silent=i.silent=!0,!(e&&e.keepLabel)&&(i.style.text=null),Fa(i,{style:{opacity:0},scale:[0,0]},this._seriesModel,this.dataIndex,t)},h(Jh,Dg);var Mb=nc.prototype;Mb.updateData=function(t,e){e=ac(e);var i=this.group,n=t.hostModel,r=this._data,a=this._symbolCtor,o=oc(t);r||i.removeAll(),t.diff(r).add(function(n){var r=t.getItemLayout(n);if(rc(t,r,n,e)){var s=new a(t,n,o);s.attr("position",r),t.setItemGraphicEl(n,s),i.add(s)}}).update(function(s,l){var u=r.getItemGraphicEl(l),h=t.getItemLayout(s);return rc(t,h,s,e)?(u?(u.updateData(t,s,o),Fa(u,{position:h},n)):(u=new a(t,s),u.attr("position",h)),i.add(u),void t.setItemGraphicEl(s,u)):void i.remove(u)}).remove(function(t){var e=r.getItemGraphicEl(t);e&&e.fadeOut(function(){i.remove(e)})}).execute(),this._data=t},Mb.isPersistent=function(){return!0},Mb.updateLayout=function(){var t=this._data;t&&t.eachItemGraphicEl(function(e,i){var n=t.getItemLayout(i);e.attr("position",n)})},Mb.incrementalPrepareUpdate=function(t){this._seriesScope=oc(t),this._data=null,this.group.removeAll()},Mb.incrementalUpdate=function(t,e,i){function n(t){t.isGroup||(t.incremental=t.useHoverLayer=!0)}i=ac(i);for(var r=t.start;r0&&cc(i[r-1]);r--);for(;r>n&&cc(i[n]);n++);}for(;r>n;)n+=dc(t,i,n,r,r,1,a.min,a.max,e.smooth,e.smoothMonotone,e.connectNulls)+1}}),zb=Gr.extend({type:"ec-polygon",shape:{points:[],stackedOnPoints:[],smooth:0,stackedOnSmooth:0,smoothConstraint:!0,smoothMonotone:null,connectNulls:!1},brush:Xm(Gr.prototype.brush),buildPath:function(t,e){var i=e.points,n=e.stackedOnPoints,r=0,a=i.length,o=e.smoothMonotone,s=gc(i,e.smoothConstraint),l=gc(n,e.smoothConstraint);if(e.connectNulls){for(;a>0&&cc(i[a-1]);a--);for(;a>r&&cc(i[r]);r++);}for(;a>r;){var u=dc(t,i,r,a,a,1,s.min,s.max,e.smooth,o,e.connectNulls);dc(t,n,r+u-1,u,a,-1,l.min,l.max,e.stackedOnSmooth,o,e.connectNulls),r+=u+1,t.closePath()}}});Zs.extend({type:"line",init:function(){var t=new Dg,e=new nc;this.group.add(e.group),this._symbolDraw=e,this._lineGroup=t},render:function(t,e,i){var n=t.coordinateSystem,r=this.group,a=t.getData(),o=t.getModel("lineStyle"),l=t.getModel("areaStyle"),u=a.mapArray(a.getItemLayout),h="polar"===n.type,c=this._coordSys,d=this._symbolDraw,f=this._polyline,p=this._polygon,g=this._lineGroup,v=t.get("animation"),m=!l.isEmpty(),y=l.get("origin"),_=sc(n,a,y),x=xc(n,a,_),w=t.get("showSymbol"),b=w&&!h&&Sc(t,a,n),S=this._data;S&&S.eachItemGraphicEl(function(t,e){t.__temp&&(r.remove(t),S.setItemGraphicEl(e,null))}),w||d.remove(),r.add(g);var M,I=!h&&t.get("step");n&&n.getArea&&(M=n.getArea(),null!=M.width?(M.x-=.1,M.y-=.1,M.width+=.2,M.height+=.2):M.r0&&(M.r0-=.5,M.r1+=.5)),f&&c.type===n.type&&I===this._step?(m&&!p?p=this._newPolygon(u,x,n,v):p&&!m&&(g.remove(p),p=this._polygon=null),g.setClipPath(Ic(n,!1,t)),w&&d.updateData(a,{isIgnore:b,clipShape:M}),a.eachItemGraphicEl(function(t){t.stopAnimation(!0)}),yc(this._stackedOnPoints,x)&&yc(this._points,u)||(v?this._updateAnimation(a,x,n,i,I,y):(I&&(u=wc(u,n,I),x=wc(x,n,I)),f.setShape({points:u}),p&&p.setShape({points:u,stackedOnPoints:x})))):(w&&d.updateData(a,{isIgnore:b,clipShape:M}),I&&(u=wc(u,n,I),x=wc(x,n,I)),f=this._newPolyline(u,n,v),m&&(p=this._newPolygon(u,x,n,v)),g.setClipPath(Ic(n,!0,t)));var C=bc(a,n)||a.getVisual("color");f.useStyle(s(o.getLineStyle(),{fill:"none",stroke:C,lineJoin:"bevel"}));var T=t.get("smooth");if(T=_c(t.get("smooth")),f.setShape({smooth:T,smoothMonotone:t.get("smoothMonotone"),connectNulls:t.get("connectNulls")}),p){var D=a.getCalculationInfo("stackedOnSeries"),A=0;p.useStyle(s(l.getAreaStyle(),{fill:C,opacity:.7,lineJoin:"bevel"})),D&&(A=_c(D.get("smooth"))),p.setShape({smooth:T,stackedOnSmooth:A,smoothMonotone:t.get("smoothMonotone"),connectNulls:t.get("connectNulls")})}this._data=a,this._coordSys=n,this._stackedOnPoints=x,this._points=u,this._step=I,this._valueOrigin=y},dispose:function(){},highlight:function(t,e,i,n){var r=t.getData(),a=jn(r,n);if(!(a instanceof Array)&&null!=a&&a>=0){var o=r.getItemGraphicEl(a);if(!o){var s=r.getItemLayout(a);if(!s)return;o=new Jh(r,a),o.position=s,o.setZ(t.get("zlevel"),t.get("z")),o.ignore=isNaN(s[0])||isNaN(s[1]),o.__temp=!0,r.setItemGraphicEl(a,o),o.stopSymbolAnimation(!0),this.group.add(o)}o.highlight()}else Zs.prototype.highlight.call(this,t,e,i,n)},downplay:function(t,e,i,n){var r=t.getData(),a=jn(r,n);if(null!=a&&a>=0){var o=r.getItemGraphicEl(a);o&&(o.__temp?(r.setItemGraphicEl(a,null),this.group.remove(o)):o.downplay())}else Zs.prototype.downplay.call(this,t,e,i,n)},_newPolyline:function(t){var e=this._polyline;return e&&this._lineGroup.remove(e),e=new Ob({shape:{points:t},silent:!0,z2:10}),this._lineGroup.add(e),this._polyline=e,e},_newPolygon:function(t,e){var i=this._polygon;return i&&this._lineGroup.remove(i),i=new zb({shape:{points:t,stackedOnPoints:e},silent:!0}),this._lineGroup.add(i),this._polygon=i,i},_updateAnimation:function(t,e,i,n,r,a){var o=this._polyline,s=this._polygon,l=t.hostModel,u=Ib(this._data,t,this._stackedOnPoints,e,this._coordSys,i,this._valueOrigin,a),h=u.current,c=u.stackedOnCurrent,d=u.next,f=u.stackedOnNext;r&&(h=wc(u.current,i,r),c=wc(u.stackedOnCurrent,i,r),d=wc(u.next,i,r),f=wc(u.stackedOnNext,i,r)),o.shape.__points=u.current,o.shape.points=h,Fa(o,{shape:{points:d}},l),s&&(s.setShape({points:h,stackedOnPoints:c}),Fa(s,{shape:{points:d,stackedOnPoints:f}},l));for(var p=[],g=u.status,v=0;ve&&(e=t[i]);return isFinite(e)?e:0/0},min:function(t){for(var e=1/0,i=0;i1){var u;"string"==typeof i?u=Rb[i]:"function"==typeof i&&(u=i),u&&t.setData(e.downSample(e.mapDimension(a.dim),1/l,u,Nb))}}}}},Gb=function(t){this._axes={},this._dimList=[],this.name=t||""};Gb.prototype={constructor:Gb,type:"cartesian",getAxis:function(t){return this._axes[t]},getAxes:function(){return p(this._dimList,Cc,this)},getAxesByScale:function(t){return t=t.toLowerCase(),v(this.getAxes(),function(e){return e.scale.type===t})},addAxis:function(t){var e=t.dim;this._axes[e]=t,this._dimList.push(e)},dataToCoord:function(t){return this._dataCoordConvert(t,"dataToCoord")},coordToData:function(t){return this._dataCoordConvert(t,"coordToData")},_dataCoordConvert:function(t,e){for(var i=this._dimList,n=t instanceof Array?[]:{},r=0;re[1]&&e.reverse(),e},getOtherAxis:function(){this.grid.getOtherAxis()},pointToData:function(t,e){return this.coordToData(this.toLocalCoord(t["x"===this.dim?0:1]),e)},toLocalCoord:null,toGlobalCoord:null},h(Vb,pb);var Hb={show:!0,zlevel:0,z:0,inverse:!1,name:"",nameLocation:"end",nameRotate:null,nameTruncate:{maxWidth:null,ellipsis:"...",placeholder:"."},nameTextStyle:{},nameGap:15,silent:!1,triggerEvent:!1,tooltip:{show:!1},axisPointer:{},axisLine:{show:!0,onZero:!0,onZeroAxisIndex:null,lineStyle:{color:"#333",width:1,type:"solid"},symbol:["none","none"],symbolSize:[10,15]},axisTick:{show:!0,inside:!1,length:5,lineStyle:{width:1}},axisLabel:{show:!0,inside:!1,rotate:0,showMinLabel:null,showMaxLabel:null,margin:8,fontSize:12},splitLine:{show:!0,lineStyle:{color:["#ccc"],width:1,type:"solid"}},splitArea:{show:!1,areaStyle:{color:["rgba(250,250,250,0.3)","rgba(200,200,200,0.3)"]}}},Wb={};Wb.categoryAxis=r({boundaryGap:!0,deduplication:null,splitLine:{show:!1},axisTick:{alignWithLabel:!1,interval:"auto"},axisLabel:{interval:"auto"}},Hb),Wb.valueAxis=r({boundaryGap:[0,0],splitNumber:5},Hb),Wb.timeAxis=s({scale:!0,min:"dataMin",max:"dataMax"},Wb.valueAxis),Wb.logAxis=s({scale:!0,logBase:10},Wb.valueAxis);var Ub=["value","category","time","log"],Xb=function(t,e,i,n){f(Ub,function(o){e.extend({type:t+"Axis."+o,mergeDefaultAndTheme:function(e,n){var a=this.layoutMode,s=a?Ro(e):{},l=n.getTheme();r(e,l.get(o+"Axis")),r(e,this.getDefaultOption()),e.type=i(t,e),a&&Eo(e,s,a)},optionUpdated:function(){var t=this.option;"category"===t.type&&(this.__ordinalMeta=Ku.createByAxisModel(this))},getCategories:function(t){var e=this.option;return"category"===e.type?t?e.data:this.__ordinalMeta.categories:void 0},getOrdinalMeta:function(){return this.__ordinalMeta},defaultOption:a([{},Wb[o+"Axis"],n],!0)})}),Ky.registerSubTypeDefaulter(t+"Axis",_(i,t))},Yb=Ky.extend({type:"cartesian2dAxis",axis:null,init:function(){Yb.superApply(this,"init",arguments),this.resetRange()},mergeOption:function(){Yb.superApply(this,"mergeOption",arguments),this.resetRange()},restoreData:function(){Yb.superApply(this,"restoreData",arguments),this.resetRange()},getCoordSysModel:function(){return this.ecModel.queryComponents({mainType:"grid",index:this.option.gridIndex,id:this.option.gridId})[0]}});r(Yb.prototype,Jw);var jb={offset:0};Xb("x",Yb,Dc,jb),Xb("y",Yb,Dc,jb),Ky.extend({type:"grid",dependencies:["xAxis","yAxis"],layoutMode:"box",coordinateSystem:null,defaultOption:{show:!1,zlevel:0,z:0,left:"10%",top:60,right:"10%",bottom:60,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"}});var qb=kc.prototype;qb.type="grid",qb.axisPointerEnabled=!0,qb.getRect=function(){return this._rect},qb.update=function(t,e){var i=this._axesMap;this._updateScale(t,this.model),f(i.x,function(t){mh(t.scale,t.model)}),f(i.y,function(t){mh(t.scale,t.model)});var n={};f(i.x,function(t){Pc(i,"y",t,n)}),f(i.y,function(t){Pc(i,"x",t,n)}),this.resize(this.model,e)},qb.resize=function(t,e,i){function n(){f(a,function(t){var e=t.isHorizontal(),i=e?[0,r.width]:[0,r.height],n=t.inverse?1:0;t.setExtent(i[n],i[1-n]),Oc(t,e?r.x:r.y)})}var r=Bo(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()});this._rect=r;var a=this._axesList;n(),!i&&t.get("containLabel")&&(f(a,function(t){if(!t.model.get("axisLabel.inside")){var e=bh(t);if(e){var i=t.isHorizontal()?"height":"width",n=t.model.get("axisLabel.margin");r[i]-=e[i]+n,"top"===t.position?r.y+=e.height+n:"left"===t.position&&(r.x+=e.width+n)}}}),n())},qb.getAxis=function(t,e){var i=this._axesMap[t];if(null!=i){if(null==e)for(var n in i)if(i.hasOwnProperty(n))return i[n];return i[e]}},qb.getAxes=function(){return this._axesList.slice()},qb.getCartesian=function(t,e){if(null!=t&&null!=e){var i="x"+t+"y"+e;return this._coordsMap[i]}S(t)&&(e=t.yAxisIndex,t=t.xAxisIndex);for(var n=0,r=this._coordsList;nu[1]?-1:1,c=["start"===r?u[0]-h*l:"end"===r?u[1]+h*l:(u[0]+u[1])/2,Gc(r)?t.labelOffset+a*l:0],d=e.get("nameRotate");null!=d&&(d=d*Kb/180);var f;Gc(r)?n=tS(t.rotation,null!=d?d:t.rotation,a):(n=Ec(t,r,d||0,u),f=t.axisNameAvailableWidth,null!=f&&(f=Math.abs(f/Math.sin(n.rotation)),!isFinite(f)&&(f=null)));var p=s.getFont(),g=e.get("nameTruncate",!0)||{},v=g.ellipsis,m=D(t.nameTruncateMaxWidth,g.maxWidth,f),y=null!=v&&null!=m?Hy(i,m,p,v,{minChar:2,placeholder:g.placeholder}):i,_=e.get("tooltip",!0),x=e.mainType,w={componentType:x,name:i,$vars:["name"]};w[x+"Index"]=e.componentIndex;var b=new Hm({anid:"name",__fullText:i,__truncatedText:y,position:c,rotation:n.rotation,silent:eS(e),z2:1,tooltip:_&&_.show?o({content:i,formatter:function(){return i},formatterParams:w},_):null});Aa(b.style,s,{text:y,textFont:p,textFill:s.getTextColor()||e.get("axisLine.lineStyle.color"),textAlign:s.get("align")||n.textAlign,textVerticalAlign:s.get("verticalAlign")||n.textVerticalAlign}),e.get("triggerEvent")&&(b.eventData=Jb(e),b.eventData.targetType="axisName",b.eventData.name=i),this._dumbGroup.add(b),b.updateTransform(),this.group.add(b),b.decomposeTransform()}}},Jb=$b.makeAxisEventDataBase=function(t){var e={componentType:t.mainType,componentIndex:t.componentIndex};return e[t.mainType+"Index"]=t.componentIndex,e},tS=$b.innerTextLayout=function(t,e,i){var n,r,a=po(e-t);return go(a)?(r=i>0?"top":"bottom",n="center"):go(a-Kb)?(r=i>0?"bottom":"top",n="center"):(r="middle",n=a>0&&Kb>a?i>0?"right":"left":i>0?"left":"right"),{rotation:a,textAlign:n,textVerticalAlign:r}},eS=$b.isLabelSilent=function(t){var e=t.get("tooltip");return t.get("silent")||!(t.get("triggerEvent")||e&&e.show)},iS=f,nS=_,rS=pu({type:"axis",_axisPointer:null,axisPointerClass:null,render:function(t,e,i,n){this.axisPointerClass&&Zc(t),rS.superApply(this,"render",arguments),td(this,t,e,i,n,!0)},updateAxisPointer:function(t,e,i,n){td(this,t,e,i,n,!1)},remove:function(t,e){var i=this._axisPointer;i&&i.remove(e),rS.superApply(this,"remove",arguments)},dispose:function(t,e){ed(this,e),rS.superApply(this,"dispose",arguments)}}),aS=[];rS.registerAxisPointerClass=function(t,e){aS[t]=e},rS.getAxisPointerClass=function(t){return t&&aS[t]};var oS=["axisLine","axisTickLabel","axisName"],sS=["splitArea","splitLine"],lS=rS.extend({type:"cartesianAxis",axisPointerClass:"CartesianAxisPointer",render:function(t,e,i,n){this.group.removeAll();var r=this._axisGroup;if(this._axisGroup=new Dg,this.group.add(this._axisGroup),t.get("show")){var a=t.getCoordSysModel(),o=id(a,t),s=new $b(t,o);f(oS,s.add,s),this._axisGroup.add(s.getGroup()),f(sS,function(e){t.get(e+".show")&&this["_"+e](t,a)},this),Ua(r,this._axisGroup,t),lS.superCall(this,"render",t,e,i,n)}},remove:function(){this._splitAreaColors=null},_splitLine:function(t,e){var i=t.axis;if(!i.scale.isBlank()){var n=t.getModel("splitLine"),r=n.getModel("lineStyle"),a=r.get("color");a=x(a)?a:[a];for(var o=e.coordinateSystem.getRect(),l=i.isHorizontal(),u=0,h=i.getTicksCoords({tickModel:n}),c=[],d=[],f=r.getLineStyle(),p=0;p=0},getOrient:function(){return"vertical"===this.get("orient")?{index:1,name:"vertical"}:{index:0,name:"horizontal"}},defaultOption:{zlevel:0,z:4,show:!0,orient:"horizontal",left:"center",top:0,align:"auto",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderRadius:0,borderWidth:0,padding:5,itemGap:10,itemWidth:25,itemHeight:14,inactiveColor:"#ccc",inactiveBorderColor:"#ccc",itemStyle:{borderWidth:0},textStyle:{color:"#333"},selectedMode:!0,selector:!1,selectorLabel:{show:!0,borderRadius:10,padding:[3,5,3,5],fontSize:12,fontFamily:" sans-serif",color:"#666",borderWidth:1,borderColor:"#666"},emphasis:{selectorLabel:{show:!0,color:"#eee",backgroundColor:"#666"}},selectorPosition:"auto",selectorItemGap:7,selectorButtonGap:10,tooltip:{show:!1}}});ou("legendToggleSelect","legendselectchanged",_(nd,"toggleSelected")),ou("legendAllSelect","legendselectall",_(nd,"allSelect")),ou("legendInverseSelect","legendinverseselect",_(nd,"inverseSelect")),ou("legendSelect","legendselected",_(nd,"select")),ou("legendUnSelect","legendunselected",_(nd,"unSelect"));var dS=_,fS=f,pS=Dg,gS=pu({type:"legend.plain",newlineDisabled:!1,init:function(){this.group.add(this._contentGroup=new pS),this._backgroundEl,this.group.add(this._selectorGroup=new pS),this._isFirstRender=!0},getContentGroup:function(){return this._contentGroup},getSelectorGroup:function(){return this._selectorGroup},render:function(t,e,i){var n=this._isFirstRender;if(this._isFirstRender=!1,this.resetInner(),t.get("show",!0)){var r=t.get("align"),a=t.get("orient");r&&"auto"!==r||(r="right"===t.get("left")&&"vertical"===a?"right":"left");var o=t.get("selector",!0),l=t.get("selectorPosition",!0);!o||l&&"auto"!==l||(l="horizontal"===a?"end":"start"),this.renderInner(r,t,e,i,o,a,l);var u=t.getBoxLayoutParams(),h={width:i.getWidth(),height:i.getHeight()},c=t.get("padding"),d=Bo(u,h,c),f=this.layoutInner(t,r,d,n,o,l),p=Bo(s({width:f.width,height:f.height},u),h,c);this.group.attr("position",[p.x-f.x,p.y-f.y]),this.group.add(this._backgroundEl=rd(f,t))}},resetInner:function(){this.getContentGroup().removeAll(),this._backgroundEl&&this.group.remove(this._backgroundEl),this.getSelectorGroup().removeAll()},renderInner:function(t,e,i,n,r,a,o){var s=this.getContentGroup(),l=N(),u=e.get("selectedMode"),h=[];i.eachRawSeries(function(t){!t.get("legendHoverLink")&&h.push(t.id)}),fS(e.getData(),function(r,a){var o=r.get("name");if(!this.newlineDisabled&&(""===o||"\n"===o))return void s.add(new pS({newline:!0}));var c=i.getSeriesByName(o)[0];if(!l.get(o))if(c){var d=c.getData(),f=d.getVisual("color"),p=d.getVisual("borderColor");"function"==typeof f&&(f=f(c.getDataParams(0))),"function"==typeof p&&(p=p(c.getDataParams(0)));var g=d.getVisual("legendSymbol")||"roundRect",v=d.getVisual("symbol"),m=this._createItem(o,a,r,e,g,v,t,f,p,u);m.on("click",dS(od,o,n)).on("mouseover",dS(sd,c.name,null,n,h)).on("mouseout",dS(ld,c.name,null,n,h)),l.set(o,!0)}else i.eachRawSeries(function(i){if(!l.get(o)&&i.legendDataProvider){var s=i.legendDataProvider(),c=s.indexOfName(o);if(0>c)return;var d=s.getItemVisual(c,"color"),f=s.getItemVisual(c,"borderColor"),p="roundRect",g=this._createItem(o,a,r,e,p,null,t,d,f,u);g.on("click",dS(od,o,n)).on("mouseover",dS(sd,null,o,n,h)).on("mouseout",dS(ld,null,o,n,h)),l.set(o,!0)}},this)},this),r&&this._createSelector(r,e,n,a,o)},_createSelector:function(t,e,i){function n(t){var n=t.type,a=new Hm({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){i.dispatchAction({type:"all"===n?"legendAllSelect":"legendInverseSelect"})}});r.add(a);var o=e.getModel("selectorLabel"),s=e.getModel("emphasis.selectorLabel");Ta(a.style,a.hoverStyle={},o,s,{defaultText:t.title,isRectText:!1}),Sa(a)}var r=this.getSelectorGroup();fS(t,function(t){n(t)})},_createItem:function(t,e,i,n,r,a,s,l,u,h){var c=n.get("itemWidth"),d=n.get("itemHeight"),f=n.get("inactiveColor"),p=n.get("inactiveBorderColor"),g=n.get("symbolKeepAspect"),v=n.getModel("itemStyle"),m=n.isSelected(t),y=new pS,_=i.getModel("textStyle"),x=i.get("icon"),w=i.getModel("tooltip"),b=w.parentModel;r=x||r;var S=Th(r,0,0,c,d,m?l:f,null==g?!0:g);if(y.add(ad(S,r,v,u,p,m)),!x&&a&&(a!==r||"none"===a)){var M=.8*d;"none"===a&&(a="circle");var I=Th(a,(c-M)/2,(d-M)/2,M,M,m?l:f,null==g?!0:g);y.add(ad(I,a,v,u,p,m))}var C="left"===s?c+5:-5,T=s,D=n.get("formatter"),A=t;"string"==typeof D&&D?A=D.replace("{name}",null!=t?t:""):"function"==typeof D&&(A=D(t)),y.add(new Hm({style:Aa({},_,{text:A,x:C,y:d/2,textFill:m?_.getTextColor():f,textAlign:T,textVerticalAlign:"middle"})}));var k=new ty({shape:y.getBoundingRect(),invisible:!0,tooltip:w.get("show")?o({content:t,formatter:b.get("formatter",!0)||function(){return t},formatterParams:{componentType:"legend",legendIndex:n.componentIndex,name:t,$vars:["name"]}},w.option):null});return y.add(k),y.eachChild(function(t){t.silent=!0}),k.silent=!h,this.getContentGroup().add(y),Sa(y),y.__legendDataIndex=e,y},layoutInner:function(t,e,i,n,r,a){var o=this.getContentGroup(),s=this.getSelectorGroup();jy(t.get("orient"),o,t.get("itemGap"),i.width,i.height);var l=o.getBoundingRect(),u=[-l.x,-l.y];if(r){jy("horizontal",s,t.get("selectorItemGap",!0));var h=s.getBoundingRect(),c=[-h.x,-h.y],d=t.get("selectorButtonGap",!0),f=t.getOrient().index,p=0===f?"width":"height",g=0===f?"height":"width",v=0===f?"y":"x";"end"===a?c[f]+=l[p]+d:u[f]+=h[p]+d,c[1-f]+=l[g]/2-h[g]/2,s.attr("position",c),o.attr("position",u);var m={x:0,y:0};return m[p]=l[p]+d+h[p],m[g]=Math.max(l[g],h[g]),m[v]=Math.min(0,h[v]+c[1-f]),m}return o.attr("position",u),this.group.getBoundingRect()},remove:function(){this.getContentGroup().removeAll(),this._isFirstRender=!0}}),vS=function(t){var e=t.findComponents({mainType:"legend"});e&&e.length&&t.filterSeries(function(t){for(var i=0;ii[r],f=[-h.x,-h.y];e||(f[n]=s.position[n]);var p=[0,0],g=[-c.x,-c.y],v=A(t.get("pageButtonGap",!0),t.get("itemGap",!0));if(d){var m=t.get("pageButtonPosition",!0);"end"===m?g[n]+=i[r]-c[r]:p[n]+=c[r]+v}g[1-n]+=h[a]/2-c[a]/2,s.attr("position",f),l.attr("position",p),u.attr("position",g);var y={x:0,y:0};if(y[r]=d?i[r]:h[r],y[a]=Math.max(h[a],c[a]),y[o]=Math.min(0,c[o]+g[1-n]),l.__rectSize=i[r],d){var _={x:0,y:0};_[r]=Math.max(i[r]-c[r]-v,0),_[a]=y[a],l.setClipPath(new ty({shape:_})),l.__rectSize=_[r]}else u.eachChild(function(t){t.attr({invisible:!0,silent:!0})});var x=this._getPageInfo(t);return null!=x.pageIndex&&Fa(s,{position:x.contentPosition},d?t:!1),this._updatePageInfoView(t,x),y},_pageGo:function(t,e,i){var n=this._getPageInfo(e)[t];null!=n&&i.dispatchAction({type:"legendScroll",scrollDataIndex:n,legendId:e.id})},_updatePageInfoView:function(t,e){var i=this._controllerGroup;f(["pagePrev","pageNext"],function(n){var r=null!=e[n+"DataIndex"],a=i.childOfName(n);a&&(a.setStyle("fill",r?t.get("pageIconColor",!0):t.get("pageIconInactiveColor",!0)),a.cursor=r?"pointer":"default")});var n=i.childOfName("pageText"),r=t.get("pageFormatter"),a=e.pageIndex,o=null!=a?a+1:0,s=e.pageCount;n&&r&&n.setStyle("text",b(r)?r.replace("{current}",o).replace("{total}",s):r({current:o,total:s}))},_getPageInfo:function(t){function e(t){if(t){var e=t.getBoundingRect(),i=e[l]+t.position[o];return{s:i,e:i+e[s],i:t.__legendDataIndex}}}function i(t,e){return t.e>=e&&t.s<=e+a}var n=t.get("scrollDataIndex",!0),r=this.getContentGroup(),a=this._containerGroup.__rectSize,o=t.getOrient().index,s=_S[o],l=xS[o],u=this._findTargetItemIndex(n),h=r.children(),c=h[u],d=h.length,f=d?1:0,p={contentPosition:r.position.slice(),pageCount:f,pageIndex:f-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(!c)return p;var g=e(c);p.contentPosition[o]=-g.s;for(var v=u+1,m=g,y=g,_=null;d>=v;++v)_=e(h[v]),(!_&&y.e>m.s+a||_&&!i(_,m.s))&&(m=y.i>m.i?y:_,m&&(null==p.pageNextDataIndex&&(p.pageNextDataIndex=m.i),++p.pageCount)),y=_;for(var v=u-1,m=g,y=g,_=null;v>=-1;--v)_=e(h[v]),_&&i(y,_.s)||!(m.io||x(o))return{point:[]};var s=a.getItemGraphicEl(o),l=i.coordinateSystem;if(i.getTooltipPosition)n=i.getTooltipPosition(o)||[];else if(l&&l.dataToPoint)n=l.dataToPoint(a.getValues(p(l.dimensions,function(t){return a.mapDimension(t)}),o,!0))||[];else if(s){var u=s.getBoundingRect().clone();u.applyTransform(s.transform),n=[u.x+u.width/2,u.y+u.height/2]}return{point:n,el:s}},SS=f,MS=_,IS=qn(),CS=function(t,e,i){var n=t.currTrigger,r=[t.x,t.y],a=t,o=t.dispatchAction||y(i.dispatchAction,i),s=e.getComponent("axisPointer").coordSysAxesInfo;if(s){_d(r)&&(r=bS({seriesIndex:a.seriesIndex,dataIndex:a.dataIndex},e).point);var l=_d(r),u=a.axesInfo,h=s.axesInfo,c="leave"===n||_d(r),d={},f={},p={list:[],map:{}},g={showPointer:MS(dd,f),showTooltip:MS(fd,p)};SS(s.coordSysMap,function(t,e){var i=l||t.containPoint(r);SS(s.coordSysAxesInfo[e],function(t){var e=t.axis,n=md(u,t);if(!c&&i&&(!u||n)){var a=n&&n.value;null!=a||l||(a=e.pointToData(r)),null!=a&&hd(t,a,g,!1,d)}})});var v={};return SS(h,function(t,e){var i=t.linkGroup;i&&!f[e]&&SS(i.axesInfo,function(e,n){var r=f[n];if(e!==t&&r){var a=r.value;i.mapper&&(a=t.axis.scale.parse(i.mapper(a,yd(e),yd(t)))),v[t.key]=a}})}),SS(v,function(t,e){hd(h[e],t,g,!0,d)}),pd(f,h,d),gd(p,r,t,o),vd(h,o,i),d}},TS=(fu({type:"axisPointer",coordSysAxesInfo:null,defaultOption:{show:"auto",triggerOn:null,zlevel:0,z:50,type:"line",snap:!1,triggerTooltip:!0,value:null,status:null,link:[],animation:null,animationDurationUpdate:200,lineStyle:{color:"#aaa",width:1,type:"solid"},shadowStyle:{color:"rgba(150,150,150,0.3)"},label:{show:!0,formatter:null,precision:"auto",margin:3,color:"#fff",padding:[5,7,5,7],backgroundColor:"auto",borderColor:null,borderWidth:0,shadowBlur:3,shadowColor:"#aaa"},handle:{show:!1,icon:"M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z",size:45,margin:50,color:"#333",shadowBlur:3,shadowColor:"#aaa",shadowOffsetX:0,shadowOffsetY:2,throttle:40}}}),qn()),DS=f,AS=pu({type:"axisPointer",render:function(t,e,i){var n=e.getComponent("tooltip"),r=t.get("triggerOn")||n&&n.get("triggerOn")||"mousemove|click";xd("axisPointer",i,function(t,e,i){"none"!==r&&("leave"===t||r.indexOf(t)>=0)&&i({type:"updateAxisPointer",currTrigger:t,x:e&&e.offsetX,y:e&&e.offsetY})})},remove:function(t,e){Cd(e.getZr(),"axisPointer"),AS.superApply(this._model,"remove",arguments)},dispose:function(t,e){Cd("axisPointer",e),AS.superApply(this._model,"dispose",arguments)}}),kS=qn(),PS=n,LS=y;Td.prototype={_group:null,_lastGraphicKey:null,_handle:null,_dragging:!1,_lastValue:null,_lastStatus:null,_payloadInfo:null,animationThreshold:15,render:function(t,e,i,n){var r=e.get("value"),a=e.get("status");if(this._axisModel=t,this._axisPointerModel=e,this._api=i,n||this._lastValue!==r||this._lastStatus!==a){this._lastValue=r,this._lastStatus=a;var o=this._group,s=this._handle;if(!a||"hide"===a)return o&&o.hide(),void(s&&s.hide());o&&o.show(),s&&s.show();var l={};this.makeElOption(l,r,t,e,i);var u=l.graphicKey;u!==this._lastGraphicKey&&this.clear(i),this._lastGraphicKey=u;var h=this._moveAnimation=this.determineAnimation(t,e);if(o){var c=_(Dd,e,h);this.updatePointerEl(o,l,c,e),this.updateLabelEl(o,l,c,e)}else o=this._group=new Dg,this.createPointerEl(o,l,t,e),this.createLabelEl(o,l,t,e),i.getZr().add(o);Ld(o,e,!0),this._renderHandle(r)}},remove:function(t){this.clear(t)},dispose:function(t){this.clear(t)},determineAnimation:function(t,e){var i=e.get("animation"),n=t.axis,r="category"===n.type,a=e.get("snap");if(!a&&!r)return!1;if("auto"===i||null==i){var o=this.animationThreshold;if(r&&n.getBandWidth()>o)return!0;if(a){var s=Kc(t).seriesDataCount,l=n.getExtent();return Math.abs(l[0]-l[1])/s>o}return!1}return i===!0},makeElOption:function(){},createPointerEl:function(t,e){var i=e.pointer;if(i){var n=kS(t).pointerEl=new Iy[i.type](PS(e.pointer));t.add(n)}},createLabelEl:function(t,e,i,n){if(e.label){var r=kS(t).labelEl=new ty(PS(e.label));t.add(r),kd(r,n)}},updatePointerEl:function(t,e,i){var n=kS(t).pointerEl;n&&e.pointer&&(n.setStyle(e.pointer.style),i(n,{shape:e.pointer.shape}))},updateLabelEl:function(t,e,i,n){var r=kS(t).labelEl;r&&(r.setStyle(e.label.style),i(r,{shape:e.label.shape,position:e.label.position}),kd(r,n))},_renderHandle:function(t){if(!this._dragging&&this.updateHandleTransform){var e=this._axisPointerModel,i=this._api.getZr(),n=this._handle,r=e.getModel("handle"),a=e.get("status");if(!r.get("show")||!a||"hide"===a)return n&&i.remove(n),void(this._handle=null);var o;this._handle||(o=!0,n=this._handle=ja(r.get("icon"),{cursor:"move",draggable:!0,onmousemove:function(t){Wp(t.event)},onmousedown:LS(this._onHandleDragMove,this,0,0),drift:LS(this._onHandleDragMove,this),ondragend:LS(this._onHandleDragEnd,this)}),i.add(n)),Ld(n,e,!1);var s=["color","borderColor","borderWidth","opacity","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY"];n.setStyle(r.getItemStyle(null,s));var l=r.get("size");x(l)||(l=[l,l]),n.attr("scale",[l[0]/2,l[1]/2]),el(this,"_doDispatchAxisPointer",r.get("throttle")||0,"fixRate"),this._moveHandleToValue(t,o)}},_moveHandleToValue:function(t,e){Dd(this._axisPointerModel,!e&&this._moveAnimation,this._handle,Pd(this.getHandleTransform(t,this._axisModel,this._axisPointerModel)))},_onHandleDragMove:function(t,e){var i=this._handle;if(i){this._dragging=!0;var n=this.updateHandleTransform(Pd(i),[t,e],this._axisModel,this._axisPointerModel);this._payloadInfo=n,i.stopAnimation(),i.attr(Pd(n)),kS(i).lastProp=null,this._doDispatchAxisPointer()}},_doDispatchAxisPointer:function(){var t=this._handle;if(t){var e=this._payloadInfo,i=this._axisModel;this._api.dispatchAction({type:"updateAxisPointer",x:e.cursorPoint[0],y:e.cursorPoint[1],tooltipOption:e.tooltipOption,axesInfo:[{axisDim:i.axis.dim,axisIndex:i.componentIndex}]})}},_onHandleDragEnd:function(){this._dragging=!1;var t=this._handle;if(t){var e=this._axisPointerModel.get("value");this._moveHandleToValue(e),this._api.dispatchAction({type:"hideTip"})}},getHandleTransform:null,updateHandleTransform:null,clear:function(t){this._lastValue=null,this._lastStatus=null;var e=t.getZr(),i=this._group,n=this._handle;e&&i&&(this._lastGraphicKey=null,i&&e.remove(i),n&&e.remove(n),this._group=null,this._handle=null,this._payloadInfo=null)},doClear:function(){},buildLabel:function(t,e,i){return i=i||0,{x:t[i],y:t[1-i],width:e[i],height:e[1-i]}}},Td.prototype.constructor=Td,ir(Td);var OS=Td.extend({makeElOption:function(t,e,i,n,r){var a=i.axis,o=a.grid,s=n.get("type"),l=Vd(o,a).getOtherAxis(a).getGlobalExtent(),u=a.toGlobalCoord(a.dataToCoord(e,!0));if(s&&"none"!==s){var h=Od(n),c=zS[s](a,u,l);c.style=h,t.graphicKey=c.type,t.pointer=c}var d=id(o.model,i);Nd(e,t,d,i,n,r)},getHandleTransform:function(t,e,i){var n=id(e.axis.grid.model,e,{labelInside:!1});return n.labelMargin=i.get("handle.margin"),{position:Rd(e.axis,t,n),rotation:n.rotation+(n.labelDirection<0?Math.PI:0)}},updateHandleTransform:function(t,e,i){var n=i.axis,r=n.grid,a=n.getGlobalExtent(!0),o=Vd(r,n).getOtherAxis(n).getGlobalExtent(),s="x"===n.dim?0:1,l=t.position;l[s]+=e[s],l[s]=Math.min(a[1],l[s]),l[s]=Math.max(a[0],l[s]);var u=(o[1]+o[0])/2,h=[u,u];h[s]=l[s];var c=[{verticalAlign:"middle"},{align:"center"}];return{position:l,rotation:t.rotation,cursorPoint:h,tooltipOption:c[s]}}}),zS={line:function(t,e,i){var n=Fd([e,i[0]],[e,i[1]],Hd(t));return{type:"Line",subPixelOptimize:!0,shape:n}},shadow:function(t,e,i){var n=Math.max(1,t.getBandWidth()),r=i[1]-i[0];return{type:"Rect",shape:Gd([e-n/2,i[0]],[n,r],Hd(t))}}};rS.registerAxisPointerClass("CartesianAxisPointer",OS),nu(function(t){if(t){(!t.axisPointer||0===t.axisPointer.length)&&(t.axisPointer={});var e=t.axisPointer.link;e&&!x(e)&&(t.axisPointer.link=[e])}}),ru(Hx.PROCESSOR.STATISTIC,function(t,e){t.getComponent("axisPointer").coordSysAxesInfo=Wc(t,e)}),ou({type:"updateAxisPointer",event:"updateAxisPointer",update:":updateAxisPointer"},CS),fu({type:"tooltip",dependencies:["axisPointer"],defaultOption:{zlevel:0,z:60,show:!0,showContent:!0,trigger:"item",triggerOn:"mousemove|click",alwaysShowContent:!1,displayMode:"single",renderMode:"auto",confine:!1,showDelay:0,hideDelay:100,transitionDuration:.4,enterable:!1,backgroundColor:"rgba(50,50,50,0.7)",borderColor:"#333",borderRadius:4,borderWidth:0,padding:5,extraCssText:"",axisPointer:{type:"line",axis:"auto",animation:"auto",animationDurationUpdate:200,animationEasingUpdate:"exponentialOut",crossStyle:{color:"#999",width:1,type:"dashed",textStyle:{}}},textStyle:{color:"#fff",fontSize:14}}});var BS=f,ES=Mo,RS=["","-webkit-","-moz-","-o-"],NS="position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;";Yd.prototype={constructor:Yd,_enterable:!0,update:function(){var t=this._container,e=t.currentStyle||document.defaultView.getComputedStyle(t),i=t.style;"absolute"!==i.position&&"absolute"!==e.position&&(i.position="relative")},show:function(t){clearTimeout(this._hideTimeout);var e=this.el;e.style.cssText=NS+Xd(t)+";left:"+this._x+"px;top:"+this._y+"px;"+(t.get("extraCssText")||""),e.style.display=e.innerHTML?"block":"none",e.style.pointerEvents=this._enterable?"auto":"none",this._show=!0},setContent:function(t){this.el.innerHTML=null==t?"":t},setEnterable:function(t){this._enterable=t},getSize:function(){var t=this.el;return[t.clientWidth,t.clientHeight]},moveTo:function(t,e){var i,n=this._zr; +n&&n.painter&&(i=n.painter.getViewportRootOffset())&&(t+=i.offsetLeft,e+=i.offsetTop);var r=this.el.style;r.left=t+"px",r.top=e+"px",this._x=t,this._y=e},hide:function(){this.el.style.display="none",this._show=!1},hideLater:function(t){!this._show||this._inContent&&this._enterable||(t?(this._hideDelay=t,this._show=!1,this._hideTimeout=setTimeout(y(this.hide,this),t)):this.hide())},isShow:function(){return this._show},getOuterSize:function(){var t=this.el.clientWidth,e=this.el.clientHeight;if(document.defaultView&&document.defaultView.getComputedStyle){var i=document.defaultView.getComputedStyle(this.el);i&&(t+=parseInt(i.borderLeftWidth,10)+parseInt(i.borderRightWidth,10),e+=parseInt(i.borderTopWidth,10)+parseInt(i.borderBottomWidth,10))}return{width:t,height:e}}},jd.prototype={constructor:jd,_enterable:!0,update:function(){},show:function(){this._hideTimeout&&clearTimeout(this._hideTimeout),this.el.attr("show",!0),this._show=!0},setContent:function(t,e,i){this.el&&this._zr.remove(this.el);for(var n={},r=t,a="{marker",o="|}",s=r.indexOf(a);s>=0;){var l=r.indexOf(o),u=r.substr(s+a.length,l-s-a.length);n["marker"+u]=u.indexOf("sub")>-1?{textWidth:4,textHeight:4,textBorderRadius:2,textBackgroundColor:e[u],textOffset:[3,0]}:{textWidth:10,textHeight:10,textBorderRadius:5,textBackgroundColor:e[u]},r=r.substr(l+1),s=r.indexOf("{marker")}this.el=new Hm({style:{rich:n,text:t,textLineHeight:20,textBackgroundColor:i.get("backgroundColor"),textBorderRadius:i.get("borderRadius"),textFill:i.get("textStyle.color"),textPadding:i.get("padding")},z:i.get("z")}),this._zr.add(this.el);var h=this;this.el.on("mouseover",function(){h._enterable&&(clearTimeout(h._hideTimeout),h._show=!0),h._inContent=!0}),this.el.on("mouseout",function(){h._enterable&&h._show&&h.hideLater(h._hideDelay),h._inContent=!1})},setEnterable:function(t){this._enterable=t},getSize:function(){var t=this.el.getBoundingRect();return[t.width,t.height]},moveTo:function(t,e){this.el&&this.el.attr("position",[t,e])},hide:function(){this.el&&this.el.hide(),this._show=!1},hideLater:function(t){!this._show||this._inContent&&this._enterable||(t?(this._hideDelay=t,this._show=!1,this._hideTimeout=setTimeout(y(this.hide,this),t)):this.hide())},isShow:function(){return this._show},getOuterSize:function(){var t=this.getSize();return{width:t[0],height:t[1]}}};var FS=y,GS=f,VS=oo,HS=new ty({shape:{x:-1,y:-1,width:2,height:2}});pu({type:"tooltip",init:function(t,e){if(!gp.node){var i=t.getComponent("tooltip"),n=i.get("renderMode");this._renderMode=Jn(n);var r;"html"===this._renderMode?(r=new Yd(e.getDom(),e),this._newLine="
"):(r=new jd(e),this._newLine="\n"),this._tooltipContent=r}},render:function(t,e,i){if(!gp.node){this.group.removeAll(),this._tooltipModel=t,this._ecModel=e,this._api=i,this._lastDataByCoordSys=null,this._alwaysShowContent=t.get("alwaysShowContent");var n=this._tooltipContent;n.update(),n.setEnterable(t.get("enterable")),this._initGlobalListener(),this._keepShow()}},_initGlobalListener:function(){var t=this._tooltipModel,e=t.get("triggerOn");xd("itemTooltip",this._api,FS(function(t,i,n){"none"!==e&&(e.indexOf(t)>=0?this._tryShow(i,n):"leave"===t&&this._hide(n))},this))},_keepShow:function(){var t=this._tooltipModel,e=this._ecModel,i=this._api;if(null!=this._lastX&&null!=this._lastY&&"none"!==t.get("triggerOn")){var n=this;clearTimeout(this._refreshUpdateTimeout),this._refreshUpdateTimeout=setTimeout(function(){!i.isDisposed()&&n.manuallyShowTip(t,e,i,{x:n._lastX,y:n._lastY})})}},manuallyShowTip:function(t,e,i,n){if(n.from!==this.uid&&!gp.node){var r=Zd(n,i);this._ticket="";var a=n.dataByCoordSys;if(n.tooltip&&null!=n.x&&null!=n.y){var o=HS;o.position=[n.x,n.y],o.update(),o.tooltip=n.tooltip,this._tryShow({offsetX:n.x,offsetY:n.y,target:o},r)}else if(a)this._tryShow({offsetX:n.x,offsetY:n.y,position:n.position,event:{},dataByCoordSys:n.dataByCoordSys,tooltipOption:n.tooltipOption},r);else if(null!=n.seriesIndex){if(this._manuallyAxisShowTip(t,e,i,n))return;var s=bS(n,e),l=s.point[0],u=s.point[1];null!=l&&null!=u&&this._tryShow({offsetX:l,offsetY:u,position:n.position,target:s.el,event:{}},r)}else null!=n.x&&null!=n.y&&(i.dispatchAction({type:"updateAxisPointer",x:n.x,y:n.y}),this._tryShow({offsetX:n.x,offsetY:n.y,position:n.position,target:i.getZr().findHover(n.x,n.y).target,event:{}},r))}},manuallyHideTip:function(t,e,i,n){var r=this._tooltipContent;!this._alwaysShowContent&&this._tooltipModel&&r.hideLater(this._tooltipModel.get("hideDelay")),this._lastX=this._lastY=null,n.from!==this.uid&&this._hide(Zd(n,i))},_manuallyAxisShowTip:function(t,e,i,n){var r=n.seriesIndex,a=n.dataIndex,o=e.getComponent("axisPointer").coordSysAxesInfo;if(null!=r&&null!=a&&null!=o){var s=e.getSeriesByIndex(r);if(s){var l=s.getData(),t=qd([l.getItemModel(a),s,(s.coordinateSystem||{}).model,t]);if("axis"===t.get("trigger"))return i.dispatchAction({type:"updateAxisPointer",seriesIndex:r,dataIndex:a,position:n.position}),!0}}},_tryShow:function(t,e){var i=t.target,n=this._tooltipModel;if(n){this._lastX=t.offsetX,this._lastY=t.offsetY;var r=t.dataByCoordSys;r&&r.length?this._showAxisTooltip(r,t):i&&null!=i.dataIndex?(this._lastDataByCoordSys=null,this._showSeriesItemTooltip(t,i,e)):i&&i.tooltip?(this._lastDataByCoordSys=null,this._showComponentItemTooltip(t,i,e)):(this._lastDataByCoordSys=null,this._hide(e))}},_showOrMove:function(t,e){var i=t.get("showDelay");e=y(e,this),clearTimeout(this._showTimout),i>0?this._showTimout=setTimeout(e,i):e()},_showAxisTooltip:function(t,e){var i=this._ecModel,n=this._tooltipModel,a=[e.offsetX,e.offsetY],o=[],s=[],l=qd([e.tooltipOption,n]),u=this._renderMode,h=this._newLine,c={};GS(t,function(t){GS(t.dataByAxis,function(t){var e=i.getComponent(t.axisDim+"Axis",t.axisIndex),n=t.value,a=[];if(e&&null!=n){var l=Ed(n,e.axis,i,t.seriesDataIndices,t.valueLabelOpt);f(t.seriesDataIndices,function(o){var h=i.getSeriesByIndex(o.seriesIndex),d=o.dataIndexInside,f=h&&h.getDataParams(d);if(f.axisDim=t.axisDim,f.axisIndex=t.axisIndex,f.axisType=t.axisType,f.axisId=t.axisId,f.axisValue=wh(e.axis,n),f.axisValueLabel=l,f){s.push(f);var p,g=h.formatTooltip(d,!0,null,u);if(S(g)){p=g.html;var v=g.markers;r(c,v)}else p=g;a.push(p)}});var d=l;o.push("html"!==u?a.join(h):(d?Io(d)+h:"")+a.join(h))}})},this),o.reverse(),o=o.join(this._newLine+this._newLine);var d=e.position;this._showOrMove(l,function(){this._updateContentNotChangedOnAxis(t)?this._updatePosition(l,d,a[0],a[1],this._tooltipContent,s):this._showTooltipContent(l,o,s,Math.random(),a[0],a[1],d,void 0,c)})},_showSeriesItemTooltip:function(t,e,i){var n=this._ecModel,r=e.seriesIndex,a=n.getSeriesByIndex(r),o=e.dataModel||a,s=e.dataIndex,l=e.dataType,u=o.getData(),h=qd([u.getItemModel(s),o,a&&(a.coordinateSystem||{}).model,this._tooltipModel]),c=h.get("trigger");if(null==c||"item"===c){var d,f,p=o.getDataParams(s,l),g=o.formatTooltip(s,!1,l,this._renderMode);S(g)?(d=g.html,f=g.markers):(d=g,f=null);var v="item_"+o.name+"_"+s;this._showOrMove(h,function(){this._showTooltipContent(h,d,p,v,t.offsetX,t.offsetY,t.position,t.target,f)}),i({type:"showTip",dataIndexInside:s,dataIndex:u.getRawIndex(s),seriesIndex:r,from:this.uid})}},_showComponentItemTooltip:function(t,e,i){var n=e.tooltip;if("string"==typeof n){var r=n;n={content:r,formatter:r}}var a=new Qa(n,this._tooltipModel,this._ecModel),o=a.get("content"),s=Math.random();this._showOrMove(a,function(){this._showTooltipContent(a,o,a.get("formatterParams")||{},s,t.offsetX,t.offsetY,t.position,e)}),i({type:"showTip",from:this.uid})},_showTooltipContent:function(t,e,i,n,r,a,o,s,l){if(this._ticket="",t.get("showContent")&&t.get("show")){var u=this._tooltipContent,h=t.get("formatter");o=o||t.get("position");var c=e;if(h&&"string"==typeof h)c=Co(h,i,!0);else if("function"==typeof h){var d=FS(function(e,n){e===this._ticket&&(u.setContent(n,l,t),this._updatePosition(t,o,r,a,u,i,s))},this);this._ticket=n,c=h(i,n,d)}u.setContent(c,l,t),u.show(t),this._updatePosition(t,o,r,a,u,i,s)}},_updatePosition:function(t,e,i,n,r,a,o){var s=this._api.getWidth(),l=this._api.getHeight();e=e||t.get("position");var u=r.getSize(),h=t.get("align"),c=t.get("verticalAlign"),d=o&&o.getBoundingRect().clone();if(o&&d.applyTransform(o.transform),"function"==typeof e&&(e=e([i,n],a,r.el,d,{viewSize:[s,l],contentSize:u.slice()})),x(e))i=VS(e[0],s),n=VS(e[1],l);else if(S(e)){e.width=u[0],e.height=u[1];var f=Bo(e,{width:s,height:l});i=f.x,n=f.y,h=null,c=null}else if("string"==typeof e&&o){var p=Qd(e,d,u);i=p[0],n=p[1]}else{var p=Kd(i,n,r,s,l,h?null:20,c?null:20);i=p[0],n=p[1]}if(h&&(i-=Jd(h)?u[0]/2:"right"===h?u[0]:0),c&&(n-=Jd(c)?u[1]/2:"bottom"===c?u[1]:0),t.get("confine")){var p=$d(i,n,r,s,l);i=p[0],n=p[1]}r.moveTo(i,n)},_updateContentNotChangedOnAxis:function(t){var e=this._lastDataByCoordSys,i=!!e&&e.length===t.length;return i&&GS(e,function(e,n){var r=e.dataByAxis||{},a=t[n]||{},o=a.dataByAxis||[];i&=r.length===o.length,i&&GS(r,function(t,e){var n=o[e]||{},r=t.seriesDataIndices||[],a=n.seriesDataIndices||[];i&=t.value===n.value&&t.axisType===n.axisType&&t.axisId===n.axisId&&r.length===a.length,i&&GS(r,function(t,e){var n=a[e];i&=t.seriesIndex===n.seriesIndex&&t.dataIndex===n.dataIndex})})}),this._lastDataByCoordSys=t,!!i},_hide:function(t){this._lastDataByCoordSys=null,t({type:"hideTip",from:this.uid})},dispose:function(t,e){gp.node||(this._tooltipContent.hide(),Cd("itemTooltip",e))}}),ou({type:"showTip",event:"showTip",update:"tooltip:manuallyShowTip"},function(){}),ou({type:"hideTip",event:"hideTip",update:"tooltip:manuallyHideTip"},function(){});var WS=So,US=Io,XS=fu({type:"marker",dependencies:["series","grid","polar","geo"],init:function(t,e,i){this.mergeDefaultAndTheme(t,i),this._mergeOption(t,i,!1,!0)},isAnimationEnabled:function(){if(gp.node)return!1;var t=this.__hostSeries;return this.getShallow("animation")&&t&&t.isAnimationEnabled()},mergeOption:function(t,e){this._mergeOption(t,e,!1,!1)},_mergeOption:function(t,e,i,n){var r=this.constructor,a=this.mainType+"Model";i||e.eachSeries(function(t){var i=t.get(this.mainType,!0),s=t[a];return i&&i.data?(s?s._mergeOption(i,e,!0):(n&&tf(i),f(i.data,function(t){t instanceof Array?(tf(t[0]),tf(t[1])):tf(t)}),s=new r(i,this,e),o(s,{mainType:this.mainType,seriesIndex:t.seriesIndex,name:t.name,createdBySelf:!0}),s.__hostSeries=t),void(t[a]=s)):void(t[a]=null)},this)},formatTooltip:function(t){var e=this.getData(),i=this.getRawValue(t),n=x(i)?p(i,WS).join(", "):WS(i),r=e.getName(t),a=US(this.name);return(null!=i||r)&&(a+="
"),r&&(a+=US(r),null!=i&&(a+=" : ")),null!=i&&(a+=US(n)),a},getData:function(){return this._data},setData:function(t){this._data=t}});c(XS,O_),XS.extend({type:"markLine",defaultOption:{zlevel:0,z:5,symbol:["circle","arrow"],symbolSize:[8,16],precision:2,tooltip:{trigger:"item"},label:{show:!0,position:"end"},lineStyle:{type:"dashed"},emphasis:{label:{show:!0},lineStyle:{width:3}},animationEasing:"linear"}});var YS=u,jS=_,qS={min:jS(rf,"min"),max:jS(rf,"max"),average:jS(rf,"average")},ZS=iy.prototype,KS=ry.prototype,$S=ta({type:"ec-line",style:{stroke:"#000",fill:null},shape:{x1:0,y1:0,x2:0,y2:0,percent:1,cpx1:null,cpy1:null},buildPath:function(t,e){this[cf(e)?"_buildPathLine":"_buildPathCurve"](t,e)},_buildPathLine:ZS.buildPath,_buildPathCurve:KS.buildPath,pointAt:function(t){return this[cf(this.shape)?"_pointAtLine":"_pointAtCurve"](t)},_pointAtLine:ZS.pointAt,_pointAtCurve:KS.pointAt,tangentAt:function(t){var e=this.shape,i=cf(e)?[e.x2-e.x1,e.y2-e.y1]:this._tangentAtCurve(t);return te(i,i)},_tangentAtCurve:KS.tangentAt}),QS=["fromSymbol","toSymbol"],JS=mf.prototype;JS.beforeUpdate=vf,JS._createLine=function(t,e,i){var n=t.hostModel,r=t.getItemLayout(e),a=pf(r);a.shape.percent=0,Ga(a,{shape:{percent:1}},n,e),this.add(a);var o=new Hm({name:"label",lineLabelOriginalOpacity:1});this.add(o),f(QS,function(i){var n=ff(i,t,e);this.add(n),this[df(i)]=t.getItemVisual(e,i)},this),this._updateCommonStl(t,e,i)},JS.updateData=function(t,e,i){var n=t.hostModel,r=this.childOfName("line"),a=t.getItemLayout(e),o={shape:{}};gf(o.shape,a),Fa(r,o,n,e),f(QS,function(i){var n=t.getItemVisual(e,i),r=df(i);if(this[r]!==n){this.remove(this.childOfName(i));var a=ff(i,t,e);this.add(a)}this[r]=n},this),this._updateCommonStl(t,e,i)},JS._updateCommonStl=function(t,e,i){var n=t.hostModel,r=this.childOfName("line"),a=i&&i.lineStyle,o=i&&i.hoverLineStyle,l=i&&i.labelModel,u=i&&i.hoverLabelModel;if(!i||t.hasItemOption){var h=t.getItemModel(e);a=h.getModel("lineStyle").getLineStyle(),o=h.getModel("emphasis.lineStyle").getLineStyle(),l=h.getModel("label"),u=h.getModel("emphasis.label")}var c=t.getItemVisual(e,"color"),d=k(t.getItemVisual(e,"opacity"),a.opacity,1);r.useStyle(s({strokeNoScale:!0,fill:"none",stroke:c,opacity:d},a)),r.hoverStyle=o,f(QS,function(t){var e=this.childOfName(t);e&&(e.setColor(c),e.setStyle({opacity:d}))},this);var p,g,v=l.getShallow("show"),m=u.getShallow("show"),y=this.childOfName("label");if((v||m)&&(p=c||"#000",g=n.getFormattedLabel(e,"normal",t.dataType),null==g)){var _=n.getRawValue(e);g=null==_?t.getName(e):isFinite(_)?so(_):_}var x=v?g:null,w=m?A(n.getFormattedLabel(e,"emphasis",t.dataType),g):null,b=y.style;(null!=x||null!=w)&&(Aa(y.style,l,{text:x},{autoColor:p}),y.__textAlign=b.textAlign,y.__verticalAlign=b.textVerticalAlign,y.__position=l.get("position")||"middle"),y.hoverStyle=null!=w?{text:w,textFill:u.getTextColor(!0),fontStyle:u.getShallow("fontStyle"),fontWeight:u.getShallow("fontWeight"),fontSize:u.getShallow("fontSize"),fontFamily:u.getShallow("fontFamily")}:{text:null},y.ignore=!v&&!m,Sa(this)},JS.highlight=function(){this.trigger("emphasis")},JS.downplay=function(){this.trigger("normal")},JS.updateLayout=function(t,e){this.setLinePoints(t.getItemLayout(e))},JS.setLinePoints=function(t){var e=this.childOfName("line");gf(e.shape,t),e.dirty()},h(mf,Dg);var tM=yf.prototype;tM.isPersistent=function(){return!0},tM.updateData=function(t){var e=this,i=e.group,n=e._lineData;e._lineData=t,n||i.removeAll();var r=wf(t);t.diff(n).add(function(i){_f(e,t,i,r)}).update(function(i,a){xf(e,n,t,a,i,r)}).remove(function(t){i.remove(n.getItemGraphicEl(t))}).execute()},tM.updateLayout=function(){var t=this._lineData;t&&t.eachItemGraphicEl(function(e,i){e.updateLayout(t,i)},this)},tM.incrementalPrepareUpdate=function(t){this._seriesScope=wf(t),this._lineData=null,this.group.removeAll()},tM.incrementalUpdate=function(t,e){function i(t){t.isGroup||(t.incremental=t.useHoverLayer=!0)}for(var n=t.start;n=0&&"number"==typeof h&&(h=+h.toFixed(Math.min(m,20))),g.coord[f]=v.coord[f]=h,a=[g,v,{type:l,valueIndex:a.valueIndex,value:h}]}return a=[af(t,a[0]),af(t,a[1]),o({},a[2])],a[2].type=a[2].type||"",r(a[2],a[0]),r(a[2],a[1]),a};eM.extend({type:"markLine",updateTransform:function(t,e,i){e.eachSeries(function(t){var e=t.markLineModel;if(e){var n=e.getData(),r=e.__from,a=e.__to;r.each(function(e){Tf(r,e,!0,t,i),Tf(a,e,!1,t,i)}),n.each(function(t){n.setItemLayout(t,[r.getItemLayout(t),a.getItemLayout(t)])}),this.markerGroupMap.get(t.id).updateLayout()}},this)},renderSeries:function(t,e,i,n){function r(e,i,r){var a=e.getItemModel(i);Tf(e,i,r,t,n),e.setItemVisual(i,{symbolSize:a.get("symbolSize")||g[r?0:1],symbol:a.get("symbol",!0)||p[r?0:1],color:a.get("itemStyle.color")||s.getVisual("color")})}var a=t.coordinateSystem,o=t.id,s=t.getData(),l=this.markerGroupMap,u=l.get(o)||l.set(o,new yf);this.group.add(u.group);var h=Df(a,t,e),c=h.from,d=h.to,f=h.line;e.__from=c,e.__to=d,e.setData(f);var p=e.get("symbol"),g=e.get("symbolSize");x(p)||(p=[p,p]),"number"==typeof g&&(g=[g,g]),h.from.each(function(t){r(c,t,!0),r(d,t,!1)}),f.each(function(t){var e=f.getItemModel(t).get("lineStyle.color");f.setItemVisual(t,{color:e||c.getItemVisual(t,"color")}),f.setItemLayout(t,[c.getItemLayout(t),d.getItemLayout(t)]),f.setItemVisual(t,{fromSymbolSize:c.getItemVisual(t,"symbolSize"),fromSymbol:c.getItemVisual(t,"symbol"),toSymbolSize:d.getItemVisual(t,"symbolSize"),toSymbol:d.getItemVisual(t,"symbol")})}),u.updateData(f),h.line.eachItemGraphicEl(function(t){t.traverse(function(t){t.dataModel=e})}),u.__keep=!0,u.group.silent=e.get("silent")||t.get("silent")}}),nu(function(t){t.markLine=t.markLine||{}});var nM=function(t){var e=t&&t.timeline;x(e)||(e=e?[e]:[]),f(e,function(t){t&&Af(t)})};Ky.registerSubTypeDefaulter("timeline",function(){return"slider"}),ou({type:"timelineChange",event:"timelineChanged",update:"prepareAndUpdate"},function(t,e){var i=e.getComponent("timeline");return i&&null!=t.currentIndex&&(i.setCurrentIndex(t.currentIndex),!i.get("loop",!0)&&i.isIndexMax()&&i.setPlayState(!1)),e.resetOption("timeline"),s({currentIndex:i.option.currentIndex},t)}),ou({type:"timelinePlayChange",event:"timelinePlayChanged",update:"update"},function(t,e){var i=e.getComponent("timeline");i&&null!=t.playState&&i.setPlayState(t.playState)});var rM=Ky.extend({type:"timeline",layoutMode:"box",defaultOption:{zlevel:0,z:4,show:!0,axisType:"time",realtime:!0,left:"20%",top:null,right:"20%",bottom:0,width:null,height:40,padding:5,controlPosition:"left",autoPlay:!1,rewind:!1,loop:!0,playInterval:2e3,currentIndex:0,itemStyle:{},label:{color:"#000"},data:[]},init:function(t,e,i){this._data,this._names,this.mergeDefaultAndTheme(t,i),this._initData()},mergeOption:function(){rM.superApply(this,"mergeOption",arguments),this._initData()},setCurrentIndex:function(t){null==t&&(t=this.option.currentIndex);var e=this._data.count();this.option.loop?t=(t%e+e)%e:(t>=e&&(t=e-1),0>t&&(t=0)),this.option.currentIndex=t},getCurrentIndex:function(){return this.option.currentIndex},isIndexMax:function(){return this.getCurrentIndex()>=this._data.count()-1},setPlayState:function(t){this.option.autoPlay=!!t},getPlayState:function(){return!!this.option.autoPlay},_initData:function(){var t=this.option,e=t.data||[],i=t.axisType,r=this._names=[];if("category"===i){var a=[];f(e,function(t,e){var i,o=Vn(t);S(t)?(i=n(t),i.value=e):i=e,a.push(i),b(o)||null!=o&&!isNaN(o)||(o=""),r.push(o+"")}),e=a}var o={category:"ordinal",time:"time"}[i]||"number",s=this._data=new ww([{name:"value",type:o}],this);s.initData(e,r)},getData:function(){return this._data},getCategories:function(){return"category"===this.get("axisType")?this._names.slice():void 0}}),aM=rM.extend({type:"timeline.slider",defaultOption:{backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,orient:"horizontal",inverse:!1,tooltip:{trigger:"item"},symbol:"emptyCircle",symbolSize:10,lineStyle:{show:!0,width:2,color:"#304654"},label:{position:"auto",show:!0,interval:"auto",rotate:0,color:"#304654"},itemStyle:{color:"#304654",borderWidth:1},checkpointStyle:{symbol:"circle",symbolSize:13,color:"#c23531",borderWidth:5,borderColor:"rgba(194,53,49, 0.5)",animation:!0,animationDuration:300,animationEasing:"quinticInOut"},controlStyle:{show:!0,showPlayBtn:!0,showPrevBtn:!0,showNextBtn:!0,itemSize:22,itemGap:12,position:"left",playIcon:"path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z",stopIcon:"path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z",nextIcon:"path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z",prevIcon:"path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z",color:"#304654",borderColor:"#304654",borderWidth:1},emphasis:{label:{show:!0,color:"#c23531"},itemStyle:{color:"#c23531"},controlStyle:{color:"#c23531",borderColor:"#c23531",borderWidth:2}},data:[]}});c(aM,O_);var oM=N_.extend({type:"timeline"}),sM=function(t,e,i,n){pb.call(this,t,e,i),this.type=n||"value",this.model=null};sM.prototype={constructor:sM,getLabelModel:function(){return this.model.getModel("label")},isHorizontal:function(){return"horizontal"===this.model.get("orient")}},h(sM,pb);var lM=y,uM=f,hM=Math.PI;oM.extend({type:"timeline.slider",init:function(t,e){this.api=e,this._axis,this._viewRect,this._timer,this._currentPointer,this._mainGroup,this._labelGroup},render:function(t,e,i){if(this.model=t,this.api=i,this.ecModel=e,this.group.removeAll(),t.get("show",!0)){var n=this._layout(t,i),r=this._createGroup("mainGroup"),a=this._createGroup("labelGroup"),o=this._axis=this._createAxis(n,t);t.formatTooltip=function(t){return Io(o.scale.getLabel(t))},uM(["AxisLine","AxisTick","Control","CurrentPointer"],function(e){this["_render"+e](n,r,o,t)},this),this._renderAxisLabel(n,a,o,t),this._position(n,t)}this._doPlayStop()},remove:function(){this._clearTimer(),this.group.removeAll()},dispose:function(){this._clearTimer()},_layout:function(t,e){var i=t.get("label.position"),n=t.get("orient"),r=Lf(t,e);null==i||"auto"===i?i="horizontal"===n?r.y+r.height/2=0||"+"===i?"left":"right"},o={horizontal:i>=0||"+"===i?"top":"bottom",vertical:"middle"},s={horizontal:0,vertical:hM/2},l="vertical"===n?r.height:r.width,u=t.getModel("controlStyle"),h=u.get("show",!0),c=h?u.get("itemSize"):0,d=h?u.get("itemGap"):0,f=c+d,p=t.get("label.rotate")||0;p=p*hM/180;var g,v,m,y,_=u.get("position",!0),x=h&&u.get("showPlayBtn",!0),w=h&&u.get("showPrevBtn",!0),b=h&&u.get("showNextBtn",!0),S=0,M=l;return"left"===_||"bottom"===_?(x&&(g=[0,0],S+=f),w&&(v=[S,0],S+=f),b&&(m=[M-c,0],M-=f)):(x&&(g=[M-c,0],M-=f),w&&(v=[0,0],S+=f),b&&(m=[M-c,0],M-=f)),y=[S,M],t.get("inverse")&&y.reverse(),{viewRect:r,mainLength:l,orient:n,rotation:s[n],labelRotation:p,labelPosOpt:i,labelAlign:t.get("label.align")||a[n],labelBaseline:t.get("label.verticalAlign")||t.get("label.baseline")||o[n],playPosition:g,prevBtnPosition:v,nextBtnPosition:m,axisExtent:y,controlSize:c,controlGap:d}},_position:function(t){function e(t){var e=t.position;t.origin=[h[0][0]-e[0],h[1][0]-e[1]]}function i(t){return[[t.x,t.x+t.width],[t.y,t.y+t.height]]}function n(t,e,i,n,r){t[n]+=i[n][r]-e[n][r]}var r=this._mainGroup,a=this._labelGroup,o=t.viewRect;if("vertical"===t.orient){var s=Te(),l=o.x,u=o.y+o.height;Pe(s,s,[-l,-u]),Le(s,s,-hM/2),Pe(s,s,[l,u]),o=o.clone(),o.applyTransform(s)}var h=i(o),c=i(r.getBoundingRect()),d=i(a.getBoundingRect()),f=r.position,p=a.position;p[0]=f[0]=h[0][0];var g=t.labelPosOpt;if(isNaN(g)){var v="+"===g?0:1;n(f,c,h,1,v),n(p,d,h,1,1-v)}else{var v=g>=0?0:1;n(f,c,h,1,v),p[1]=f[1]+g}r.attr("position",f),a.attr("position",p),r.rotation=a.rotation=t.rotation,e(r),e(a)},_createAxis:function(t,e){var i=e.getData(),n=e.get("axisType"),r=yh(e,n);r.getTicks=function(){return i.mapArray(["value"],function(t){return t})};var a=i.getDataExtent("value");r.setExtent(a[0],a[1]),r.niceTicks();var o=new sM("value",r,t.axisExtent,n);return o.model=e,o},_createGroup:function(t){var e=this["_"+t]=new Dg;return this.group.add(e),e},_renderAxisLine:function(t,e,i,n){var r=i.getExtent();n.get("lineStyle.show")&&e.add(new iy({shape:{x1:r[0],y1:0,x2:r[1],y2:0},style:o({lineCap:"round"},n.getModel("lineStyle").getLineStyle()),silent:!0,z2:1}))},_renderAxisTick:function(t,e,i,n){var r=n.getData(),a=i.scale.getTicks();uM(a,function(t){var a=i.dataToCoord(t),o=r.getItemModel(t),s=o.getModel("itemStyle"),l=o.getModel("emphasis.itemStyle"),u={position:[a,0],onclick:lM(this._changeTimeline,this,t)},h=zf(o,s,e,u);Sa(h,l.getItemStyle()),o.get("tooltip")?(h.dataIndex=t,h.dataModel=n):h.dataIndex=h.dataModel=null},this)},_renderAxisLabel:function(t,e,i,n){var r=i.getLabelModel();if(r.get("show")){var a=n.getData(),o=i.getViewLabels();uM(o,function(n){var r=n.tickValue,o=a.getItemModel(r),s=o.getModel("label"),l=o.getModel("emphasis.label"),u=i.dataToCoord(n.tickValue),h=new Hm({position:[u,0],rotation:t.labelRotation-t.rotation,onclick:lM(this._changeTimeline,this,r),silent:!1});Aa(h.style,s,{text:n.formattedLabel,textAlign:t.labelAlign,textVerticalAlign:t.labelBaseline}),e.add(h),Sa(h,Aa({},l))},this)}},_renderControl:function(t,e,i,n){function r(t,i,r,h){if(t){var c={position:t,origin:[a/2,0],rotation:h?-o:0,rectHover:!0,style:s,onclick:r},d=Of(n,i,u,c);e.add(d),Sa(d,l)}}var a=t.controlSize,o=t.rotation,s=n.getModel("controlStyle").getItemStyle(),l=n.getModel("emphasis.controlStyle").getItemStyle(),u=[0,-a/2,a,a],h=n.getPlayState(),c=n.get("inverse",!0);r(t.nextBtnPosition,"controlStyle.nextIcon",lM(this._changeTimeline,this,c?"-":"+")),r(t.prevBtnPosition,"controlStyle.prevIcon",lM(this._changeTimeline,this,c?"+":"-")),r(t.playPosition,"controlStyle."+(h?"stopIcon":"playIcon"),lM(this._handlePlayClick,this,!h),!0)},_renderCurrentPointer:function(t,e,i,n){var r=n.getData(),a=n.getCurrentIndex(),o=r.getItemModel(a).getModel("checkpointStyle"),s=this,l={onCreate:function(t){t.draggable=!0,t.drift=lM(s._handlePointerDrag,s),t.ondragend=lM(s._handlePointerDragend,s),Bf(t,a,i,n,!0)},onUpdate:function(t){Bf(t,a,i,n)}};this._currentPointer=zf(o,o,this._mainGroup,{},this._currentPointer,l)},_handlePlayClick:function(t){this._clearTimer(),this.api.dispatchAction({type:"timelinePlayChange",playState:t,from:this.uid})},_handlePointerDrag:function(t,e,i){this._clearTimer(),this._pointerChangeTimeline([i.offsetX,i.offsetY])},_handlePointerDragend:function(t){this._pointerChangeTimeline([t.offsetX,t.offsetY],!0)},_pointerChangeTimeline:function(t,e){var i=this._toAxisCoord(t)[0],n=this._axis,r=lo(n.getExtent().slice());i>r[1]&&(i=r[1]),is&&(n=s,e=a)}),e},_clearTimer:function(){this._timer&&(clearTimeout(this._timer),this._timer=null)},_changeTimeline:function(t){var e=this.model.getCurrentIndex();"+"===t?t=e+1:"-"===t&&(t=e-1),this.api.dispatchAction({type:"timelineChange",currentIndex:t,from:this.uid})}}),nu(nM);var cM="http://www.w3.org/2000/svg",dM=mm.CMD,fM=Array.prototype.join,pM="none",gM=Math.round,vM=Math.sin,mM=Math.cos,yM=Math.PI,_M=2*Math.PI,xM=180/yM,wM=1e-4,bM={};bM.brush=function(t){var e=t.style,i=t.__svgEl;i||(i=Ef("path"),t.__svgEl=i),t.path||t.createPathProxy();var n=t.path;if(t.__dirtyPath){n.beginPath(),n.subPixelOptimize=!1,t.buildPath(n,t.shape),t.__dirtyPath=!1;var r=Xf(n);r.indexOf("NaN")<0&&Hf(i,"d",r)}Uf(i,e,!1,t),Vf(i,t.transform),null!=e.text&&AM(t,t.getBoundingRect())};var SM={};SM.brush=function(t){var e=t.style,i=e.image;if(i instanceof HTMLImageElement){var n=i.src;i=n}if(i){var r=e.x||0,a=e.y||0,o=e.width,s=e.height,l=t.__svgEl;l||(l=Ef("image"),t.__svgEl=l),i!==t.__imageSrc&&(Wf(l,"href",i),t.__imageSrc=i),Hf(l,"width",o),Hf(l,"height",s),Hf(l,"x",r),Hf(l,"y",a),Vf(l,t.transform),null!=e.text&&AM(t,t.getBoundingRect())}};var MM={},IM=new xi,CM={},TM=[],DM={left:"start",right:"end",center:"middle",middle:"middle"},AM=function(t,e){var i=t.style,n=t.transform,r=t instanceof Hm||i.transformText;t.__dirty&&nn(i,!0);var a=i.text;if(null!=a&&(a+=""),xn(a,i)){null==a&&(a=""),!r&&n&&(IM.copy(e),IM.applyTransform(n),e=IM);var o=t.__textSvgEl;o||(o=Ef("text"),t.__textSvgEl=o);var s=o.style,l=i.font||Zg,u=o.__computedFont;l!==o.__styleFont&&(s.font=o.__styleFont=l,u=o.__computedFont=s.font);var h=i.textPadding,c=i.textLineHeight,d=t.__textCotentBlock;(!d||t.__dirtyText)&&(d=t.__textCotentBlock=$i(a,u,h,c,i.truncate));var f=d.outerHeight,p=d.lineHeight;pn(CM,t,i,e);var g=CM.baseX,v=CM.baseY,m=CM.textAlign||"left",y=CM.textVerticalAlign;Yf(o,r,n,i,e,g,v);var _=Wi(v,f,y),x=g,w=_;h&&(x=jf(g,m,h),w+=h[0]),w+=p/2,Uf(o,i,!0,t);var b=d.canCacheByTextString,S=t.__tspanList||(t.__tspanList=[]),M=S.length;if(b&&t.__canCacheByTextString&&t.__text===a){if(t.__dirtyText&&M)for(var I=0;M>I;++I)qf(S[I],m,x,w+I*p)}else{t.__text=a,t.__canCacheByTextString=b;for(var C=d.lines,T=C.length,I=0;T>I;I++){var D=S[I],A=C[I];D?D.__zrText!==A&&(D.innerHTML="",D.appendChild(document.createTextNode(A))):(D=S[I]=Ef("tspan"),o.appendChild(D),D.appendChild(document.createTextNode(A))),qf(D,m,x,w+I*p)}if(M>T){for(;M>I;I++)o.removeChild(S[I]);S.length=T}}}};MM.drawRectText=AM,MM.brush=function(t){var e=t.style;null!=e.text&&AM(t,!1)},Zf.prototype={diff:function(t,e,i){function n(){for(var i=-1*s;s>=i;i+=2){var n,l=u[i-1],h=u[i+1],c=(h?h.newPos:0)-i;l&&(u[i-1]=void 0);var d=l&&l.newPos+1=0&&o>c;if(d||f){if(!d||f&&l.newPos=a&&c+1>=o)return Kf(r,n.components,e,t);u[i]=n}else u[i]=void 0}s++}i||(i=function(t,e){return t===e}),this.equals=i;var r=this;t=t.slice(),e=e.slice();var a=e.length,o=t.length,s=1,l=a+o,u=[{newPos:-1,components:[]}],h=this.extractCommon(u[0],e,t,0);if(u[0].newPos+1>=a&&h+1>=o){for(var c=[],d=0;d=s;){var f=n();if(f)return f}},pushComponent:function(t,e,i){var n=t[t.length-1];n&&n.added===e&&n.removed===i?t[t.length-1]={count:n.count+1,added:e,removed:i}:t.push({count:1,added:e,removed:i})},extractCommon:function(t,e,i,n){for(var r=e.length,a=i.length,o=t.newPos,s=o-n,l=0;r>o+1&&a>s+1&&this.equals(e[o+1],i[s+1]);)o++,s++,l++;return l&&t.components.push({count:l}),t.newPos=o,s},tokenize:function(t){return t.slice()},join:function(t){return t.slice()}};var kM=new Zf,PM=function(t,e,i){return kM.diff(t,e,i)},LM="0",OM="1";Qf.prototype.createElement=Ef,Qf.prototype.getDefs=function(t){var e=this._svgRoot,i=this._svgRoot.getElementsByTagName("defs"); +return 0===i.length?t?(i=e.insertBefore(this.createElement("defs"),e.firstChild),i.contains||(i.contains=function(t){var e=i.children;if(!e)return!1;for(var n=e.length-1;n>=0;--n)if(e[n]===t)return!0;return!1}),i):null:i[0]},Qf.prototype.update=function(t,e){if(t){var i=this.getDefs(!1);if(t[this._domName]&&i.contains(t[this._domName]))"function"==typeof e&&e(t);else{var n=this.add(t);n&&(t[this._domName]=n)}}},Qf.prototype.addDom=function(t){var e=this.getDefs(!0);e.appendChild(t)},Qf.prototype.removeDom=function(t){var e=this.getDefs(!1);e&&t[this._domName]&&(e.removeChild(t[this._domName]),t[this._domName]=null)},Qf.prototype.getDoms=function(){var t=this.getDefs(!1);if(!t)return[];var e=[];return f(this._tagNames,function(i){var n=t.getElementsByTagName(i);e=e.concat([].slice.call(n))}),e},Qf.prototype.markAllUnused=function(){var t=this.getDoms(),e=this;f(t,function(t){t[e._markLabel]=LM})},Qf.prototype.markUsed=function(t){t&&(t[this._markLabel]=OM)},Qf.prototype.removeUnused=function(){var t=this.getDefs(!1);if(t){var e=this.getDoms(),i=this;f(e,function(e){e[i._markLabel]!==OM&&t.removeChild(e)})}},Qf.prototype.getSvgProxy=function(t){return t instanceof Gr?bM:t instanceof bn?SM:t instanceof Hm?MM:bM},Qf.prototype.getTextSvgElement=function(t){return t.__textSvgEl},Qf.prototype.getSvgElement=function(t){return t.__svgEl},h(Jf,Qf),Jf.prototype.addWithoutUpdate=function(t,e){if(e&&e.style){var i=this;f(["fill","stroke"],function(n){if(e.style[n]&&("linear"===e.style[n].type||"radial"===e.style[n].type)){var r,a=e.style[n],o=i.getDefs(!0);a._dom?(r=a._dom,o.contains(a._dom)||i.addDom(r)):r=i.add(a),i.markUsed(e);var s=r.getAttribute("id");t.setAttribute(n,"url(#"+s+")")}})}},Jf.prototype.add=function(t){var e;if("linear"===t.type)e=this.createElement("linearGradient");else{if("radial"!==t.type)return bg("Illegal gradient type."),null;e=this.createElement("radialGradient")}return t.id=t.id||this.nextId++,e.setAttribute("id","zr"+this._zrId+"-gradient-"+t.id),this.updateDom(t,e),this.addDom(e),e},Jf.prototype.update=function(t){var e=this;Qf.prototype.update.call(this,t,function(){var i=t.type,n=t._dom.tagName;"linear"===i&&"linearGradient"===n||"radial"===i&&"radialGradient"===n?e.updateDom(t,t._dom):(e.removeDom(t),e.add(t))})},Jf.prototype.updateDom=function(t,e){if("linear"===t.type)e.setAttribute("x1",t.x),e.setAttribute("y1",t.y),e.setAttribute("x2",t.x2),e.setAttribute("y2",t.y2);else{if("radial"!==t.type)return void bg("Illegal gradient type.");e.setAttribute("cx",t.x),e.setAttribute("cy",t.y),e.setAttribute("r",t.r)}t.global?e.setAttribute("gradientUnits","userSpaceOnUse"):e.setAttribute("gradientUnits","objectBoundingBox"),e.innerHTML="";for(var i=t.colorStops,n=0,r=i.length;r>n;++n){var a=this.createElement("stop");a.setAttribute("offset",100*i[n].offset+"%");var o=i[n].color;if(o.indexOf(!1)){var s=qe(o)[3],l=Qe(o);a.setAttribute("stop-color","#"+l),a.setAttribute("stop-opacity",s)}else a.setAttribute("stop-color",i[n].color);e.appendChild(a)}t._dom=e},Jf.prototype.markUsed=function(t){if(t.style){var e=t.style.fill;e&&e._dom&&Qf.prototype.markUsed.call(this,e._dom),e=t.style.stroke,e&&e._dom&&Qf.prototype.markUsed.call(this,e._dom)}},h(tp,Qf),tp.prototype.update=function(t){var e=this.getSvgElement(t);e&&this.updateDom(e,t.__clipPaths,!1);var i=this.getTextSvgElement(t);i&&this.updateDom(i,t.__clipPaths,!0),this.markUsed(t)},tp.prototype.updateDom=function(t,e,i){if(e&&e.length>0){var n,r,a=this.getDefs(!0),o=e[0],s=i?"_textDom":"_dom";o[s]?(r=o[s].getAttribute("id"),n=o[s],a.contains(n)||a.appendChild(n)):(r="zr"+this._zrId+"-clip-"+this.nextId,++this.nextId,n=this.createElement("clipPath"),n.setAttribute("id",r),a.appendChild(n),o[s]=n);var l=this.getSvgProxy(o);if(o.transform&&o.parent.invTransform&&!i){var u=Array.prototype.slice.call(o.transform);ke(o.transform,o.parent.invTransform,o.transform),l.brush(o),o.transform=u}else l.brush(o);var h=this.getSvgElement(o);n.innerHTML="",n.appendChild(h.cloneNode()),t.setAttribute("clip-path","url(#"+r+")"),e.length>1&&this.updateDom(n,e.slice(1),i)}else t&&t.setAttribute("clip-path","none")},tp.prototype.markUsed=function(t){var e=this;t.__clipPaths&&f(t.__clipPaths,function(t){t._dom&&Qf.prototype.markUsed.call(e,t._dom),t._textDom&&Qf.prototype.markUsed.call(e,t._textDom)})},h(ep,Qf),ep.prototype.addWithoutUpdate=function(t,e){if(e&&ip(e.style)){var i;if(e._shadowDom){i=e._shadowDom;var n=this.getDefs(!0);n.contains(e._shadowDom)||this.addDom(i)}else i=this.add(e);this.markUsed(e);var r=i.getAttribute("id");t.style.filter="url(#"+r+")"}},ep.prototype.add=function(t){var e=this.createElement("filter");return t._shadowDomId=t._shadowDomId||this.nextId++,e.setAttribute("id","zr"+this._zrId+"-shadow-"+t._shadowDomId),this.updateDom(t,e),this.addDom(e),e},ep.prototype.update=function(t,e){var i=e.style;if(ip(i)){var n=this;Qf.prototype.update.call(this,e,function(){n.updateDom(e,e._shadowDom)})}else this.remove(t,e)},ep.prototype.remove=function(t,e){null!=e._shadowDomId&&(this.removeDom(t),t.style.filter="")},ep.prototype.updateDom=function(t,e){var i=e.getElementsByTagName("feDropShadow");i=0===i.length?this.createElement("feDropShadow"):i[0];var n,r,a,o,s=t.style,l=t.scale?t.scale[0]||1:1,u=t.scale?t.scale[1]||1:1;if(s.shadowBlur||s.shadowOffsetX||s.shadowOffsetY)n=s.shadowOffsetX||0,r=s.shadowOffsetY||0,a=s.shadowBlur,o=s.shadowColor;else{if(!s.textShadowBlur)return void this.removeDom(e,s);n=s.textShadowOffsetX||0,r=s.textShadowOffsetY||0,a=s.textShadowBlur,o=s.textShadowColor}i.setAttribute("dx",n/l),i.setAttribute("dy",r/u),i.setAttribute("flood-color",o);var h=a/2/l,c=a/2/u,d=h+" "+c;i.setAttribute("stdDeviation",d),e.setAttribute("x","-100%"),e.setAttribute("y","-100%"),e.setAttribute("width",Math.ceil(a/2*200)+"%"),e.setAttribute("height",Math.ceil(a/2*200)+"%"),e.appendChild(i),t._shadowDom=e},ep.prototype.markUsed=function(t){t._shadowDom&&Qf.prototype.markUsed.call(this,t._shadowDom)};var zM=function(t,e,i,n){this.root=t,this.storage=e,this._opts=i=o({},i||{});var r=Ef("svg");r.setAttribute("xmlns","http://www.w3.org/2000/svg"),r.setAttribute("version","1.1"),r.setAttribute("baseProfile","full"),r.style.cssText="user-select:none;position:absolute;left:0;top:0;",this.gradientManager=new Jf(n,r),this.clipPathManager=new tp(n,r),this.shadowManager=new ep(n,r);var a=document.createElement("div");a.style.cssText="overflow:hidden;position:relative",this._svgRoot=r,this._viewport=a,t.appendChild(a),a.appendChild(r),this.resize(i.width,i.height),this._visibleList=[]};zM.prototype={constructor:zM,getType:function(){return"svg"},getViewportRoot:function(){return this._viewport},getViewportRootOffset:function(){var t=this.getViewportRoot();return t?{offsetLeft:t.offsetLeft||0,offsetTop:t.offsetTop||0}:void 0},refresh:function(){var t=this.storage.getDisplayList(!0);this._paintList(t)},setBackgroundColor:function(t){this._viewport.style.background=t},_paintList:function(t){this.gradientManager.markAllUnused(),this.clipPathManager.markAllUnused(),this.shadowManager.markAllUnused();var e,i=this._svgRoot,n=this._visibleList,r=t.length,a=[];for(e=0;r>e;e++){var o=t[e],s=rp(o),l=hp(o)||up(o);o.invisible||(o.__dirty&&(s&&s.brush(o),this.clipPathManager.update(o),o.style&&(this.gradientManager.update(o.style.fill),this.gradientManager.update(o.style.stroke),this.shadowManager.update(l,o)),o.__dirty=!1),a.push(o))}var u,h=PM(n,a);for(e=0;e=0;--n)if(e[n]===t)return!0;return!1}),i}return null}return i[0]},resize:function(t,e){var i=this._viewport;i.style.display="none";var n=this._opts;if(null!=t&&(n.width=t),null!=e&&(n.height=e),t=this._getSize(0),e=this._getSize(1),i.style.display="",this._width!==t||this._height!==e){this._width=t,this._height=e;var r=i.style;r.width=t+"px",r.height=e+"px";var a=this._svgRoot;a.setAttribute("width",t),a.setAttribute("height",e)}},getWidth:function(){return this._width},getHeight:function(){return this._height},_getSize:function(t){var e=this._opts,i=["width","height"][t],n=["clientWidth","clientHeight"][t],r=["paddingLeft","paddingTop"][t],a=["paddingRight","paddingBottom"][t];if(null!=e[i]&&"auto"!==e[i])return parseFloat(e[i]);var o=this.root,s=document.defaultView.getComputedStyle(o);return(o[n]||np(s[i])||np(o.style[i]))-(np(s[r])||0)-(np(s[a])||0)|0},dispose:function(){this.root.innerHTML="",this._svgRoot=this._viewport=this.storage=null},clear:function(){this._viewport&&this.root.removeChild(this._viewport)},pathToDataUrl:function(){this.refresh();var t=this._svgRoot.outerHTML;return"data:image/svg+xml;charset=UTF-8,"+t}},f(["getLayer","insertLayer","eachLayer","eachBuiltinLayer","eachOtherLayer","getLayers","modLayer","delLayer","clearLayer","toDataURL","pathToImage"],function(t){zM.prototype[t]=cp(t)}),Rn("svg",zM),t.version=Dx,t.dependencies=Ax,t.PRIORITY=Hx,t.init=Kl,t.connect=$l,t.disConnect=Ql,t.disconnect=lw,t.dispose=Jl,t.getInstanceByDom=tu,t.getInstanceById=eu,t.registerTheme=iu,t.registerPreprocessor=nu,t.registerProcessor=ru,t.registerPostUpdate=au,t.registerAction=ou,t.registerCoordinateSystem=su,t.getCoordinateSystemDimensions=lu,t.registerLayout=uu,t.registerVisual=hu,t.registerLoading=du,t.extendComponentModel=fu,t.extendComponentView=pu,t.extendSeriesModel=gu,t.extendChartView=vu,t.setCanvasCreator=mu,t.registerMap=yu,t.getMap=_u,t.dataTool=uw,t.zrender=Iv,t.number=Ey,t.format=Wy,t.throttle=tl,t.helper=ub,t.matrix=Kp,t.vector=Bp,t.color=gg,t.parseGeoJSON=cb,t.parseGeoJson=gb,t.util=vb,t.graphic=mb,t.List=ww,t.Model=Qa,t.Axis=pb,t.env=gp}); \ No newline at end of file diff --git a/src/JT808.DotNetty.CleintBenchmark/wwwroot/index.html b/src/JT808.DotNetty.CleintBenchmark/wwwroot/index.html new file mode 100644 index 0000000..8c6a6e5 --- /dev/null +++ b/src/JT808.DotNetty.CleintBenchmark/wwwroot/index.html @@ -0,0 +1,153 @@ + + + + + + 收发查看 + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj b/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj index 9f870a8..40d4089 100644 --- a/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj +++ b/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/JT808.DotNetty.Client/JT808TcpClient.cs b/src/JT808.DotNetty.Client/JT808TcpClient.cs index dc67dad..b2cb1bc 100644 --- a/src/JT808.DotNetty.Client/JT808TcpClient.cs +++ b/src/JT808.DotNetty.Client/JT808TcpClient.cs @@ -64,14 +64,14 @@ namespace JT808.DotNetty.Client }); } - public async void Send(JT808ClientRequest request) + public void Send(JT808ClientRequest request) { if (disposed) return; if (clientChannel == null) throw new NullReferenceException("Channel is empty."); if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty."); if (clientChannel.Active && clientChannel.Open) { - await clientChannel.WriteAndFlushAsync(request); + clientChannel.WriteAndFlushAsync(request); } } diff --git a/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs b/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs index 601958b..8127dd1 100644 --- a/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs +++ b/src/JT808.DotNetty.Core/Session/JT808SessionManager.cs @@ -294,11 +294,11 @@ namespace JT808.DotNetty.Core.Session } public IEnumerable GetTcpAll() { - return Sessions.Select(s => (JT808TcpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.tcp).ToList(); + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Select(s => (JT808TcpSession)s.Value).ToList(); } public IEnumerable GetUdpAll() { - return Sessions.Select(s => (JT808UdpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.udp).ToList(); + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Select(s => (JT808UdpSession)s.Value).ToList(); } } } From 1a7c6c879426e9bfad21104ae61b780dcd310e90 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Wed, 18 Dec 2019 17:28:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?1.=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=8F=8A=E5=8D=8F=E8=AE=AE=202.=E5=A2=9E=E5=8A=A0pipeline?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=203.=E7=A7=BB=E9=99=A4gateway=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- README.md | 17 +- README_V1.0.0.md | 120 - doc/README.md | 27 +- doc/{img => dotnetty}/demo1.png | Bin doc/{img => dotnetty}/demo2.png | Bin doc/{img => dotnetty}/design_model.png | Bin doc/{img => dotnetty}/performance_1000.png | Bin doc/{img => dotnetty}/performance_10000.png | Bin doc/{img => dotnetty}/performance_2000.png | Bin doc/{img => dotnetty}/performance_5000.png | Bin doc/pipeline/client_10k.png | Bin 0 -> 22003 bytes doc/pipeline/server_network_10k.png | Bin 0 -> 63584 bytes doc/pipeline/server_proccess_10k.png | Bin 0 -> 60562 bytes .../Configs/ClientBenchmarkOptions.cs | 19 - .../Configs/NLog.xsd | 3106 ----------------- .../Configs/nlog.unix.config | 36 - .../Configs/nlog.win.config | 35 - .../JT808.Gateway.CleintBenchmark.csproj | 33 - src/JT808.Gateway.CleintBenchmark/Program.cs | 51 - .../Services/CleintBenchmarkHostedService.cs | 82 - .../CleintBenchmarkReportHostedService.cs | 53 - .../Configs/JT808ConsumerConfig.cs | 15 - .../Configs/JT808MsgConsumerConfig.cs | 13 - .../Configs/JT808MsgProducerConfig.cs | 13 - .../Configs/JT808MsgReplyConsumerConfig.cs | 13 - .../Configs/JT808MsgReplyProducerConfig.cs | 13 - .../Configs/JT808ProducerConfig.cs | 15 - .../Configs/JT808SessionConsumerConfig.cs | 13 - .../Configs/JT808SessionProducerConfig.cs | 13 - .../JT808.Gateway.Kafka.csproj | 39 - .../JT808ClientBuilderDefault.cs | 24 - .../JT808ClientKafkaExtensions.cs | 66 - src/JT808.Gateway.Kafka/JT808MsgConsumer.cs | 82 - src/JT808.Gateway.Kafka/JT808MsgProducer.cs | 38 - .../JT808MsgReplyConsumer.cs | 82 - .../JT808MsgReplyProducer.cs | 38 - .../JT808ServerKafkaExtensions.cs | 48 - .../JT808SessionConsumer.cs | 82 - .../JT808SessionProducer.cs | 38 - .../JT808.Gateway.SimpleClient.csproj | 18 - src/JT808.Gateway.SimpleClient/Program.cs | 52 - .../Services/GrpcClientService.cs | 68 - .../Services/UpService.cs | 68 - .../Configs/NLog.xsd | 3106 ----------------- .../Configs/nlog.Unix.config | 36 - .../Configs/nlog.Win32NT.config | 36 - .../Configs/test.cer | Bin 784 -> 0 bytes .../JT808.Gateway.SimpleServer.csproj | 39 - src/JT808.Gateway.SimpleServer/Program.cs | 71 - src/JT808.Gateway.sln | 102 - .../MsgIdHandler/IJT808MsgIdHandler.cs | 14 - .../JT808MsgIdHandlerExtensions.cs | 18 - .../JT808MsgIdHandlerHostedService.cs | 34 - .../MsgLogging/IJT808MsgLogging.cs | 15 - .../JT808MsgDownLoggingHostedService.cs | 36 - .../MsgLogging/JT808MsgLoggingExtensions.cs | 19 - .../MsgLogging/JT808MsgLoggingType.cs | 18 - .../JT808MsgUpLoggingHostedService.cs | 36 - .../JT808ReplyMessageExtensions.cs | 57 - .../JT808ReplyMessageHostedService.cs | 34 - .../ReplyMessage/JT808ReplyMessageService.cs | 165 - .../JT808SessionNoticeExtensions.cs | 60 - .../JT808SessionNoticeHostedService.cs | 35 - .../JT808SessionNoticeService.cs | 24 - .../Traffic/JT808TrafficService.cs | 32 - .../Traffic/JT808TrafficServiceExtensions.cs | 33 - .../JT808TrafficServiceHostedService.cs | 38 - .../Traffic/TrafficRedisClient.cs | 9 - .../Transmit/Configs/DataTransferOptions.cs | 13 - .../Transmit/Configs/RemoteServerOptions.cs | 11 - .../Handlers/ClientConnectionHandler.cs | 76 - .../JT808DotNettyTransmitExtensions.cs | 39 - .../JT808DotNettyTransmitHostedService.cs | 33 - .../Transmit/JT808DotNettyTransmitService.cs | 236 -- src/JT808.Gateway/Client/DeviceConfig.cs | 28 - .../Client/JT808ClientDotnettyExtensions.cs | 23 - .../Client/JT808ClientMsgSNDistributedImpl.cs | 16 - src/JT808.Gateway/Client/JT808TcpClient.cs | 112 - .../Client/JT808TcpClientExtensions.cs | 103 - .../Client/JT808TcpClientFactory.cs | 62 - .../Codecs/JT808ClientTcpDecoder.cs | 20 - .../Codecs/JT808ClientTcpEncoder.cs | 52 - src/JT808.Gateway/Codecs/JT808TcpDecoder.cs | 32 - src/JT808.Gateway/Codecs/JT808TcpEncoder.cs | 52 - src/JT808.Gateway/Codecs/JT808UdpDecoder.cs | 33 - .../Configurations/JT808Configuration.cs | 41 - src/JT808.Gateway/Dtos/JT808ResultDto.cs | 29 - .../Dtos/JT808TcpSessionInfoDto.cs | 24 - .../Dtos/JT808UdpSessionInfoDto.cs | 24 - .../Enums/JT808TransportProtocolType.cs | 15 - .../JT808TcpClientConnectionHandler.cs | 96 - .../Handlers/JT808TcpClientHandler.cs | 31 - .../Handlers/JT808TcpConnectionHandler.cs | 104 - .../Handlers/JT808TcpServerHandler.cs | 77 - .../Handlers/JT808UdpServerHandler.cs | 79 - src/JT808.Gateway/IJT808ClientBuilder.cs | 14 - src/JT808.Gateway/IJT808GatewayBuilder.cs | 14 - .../Impls/JT808DatagramPacketImpl.cs | 18 - .../Impls/JT808GatewayBuilderDefault.cs | 25 - .../Impls/JT808MsgProducerDefaultImpl.cs | 30 - .../Impls/JT808MsgReplyConsumerDefaultImpl.cs | 193 - .../Impls/JT808SessionProducerDefaultImpl.cs | 32 - .../Interfaces/IJT808DatagramPacket.cs | 13 - src/JT808.Gateway/Interfaces/IJT808Reply.cs | 17 - src/JT808.Gateway/Interfaces/IJT808Session.cs | 20 - .../Interfaces/IJT808SessionService.cs | 30 - .../IJT808UnificationSendService.cs | 12 - src/JT808.Gateway/JT808.Gateway.csproj | 45 - src/JT808.Gateway/JT808GatewayConstants.cs | 48 - src/JT808.Gateway/JT808GatewayExtensions.cs | 54 - .../Metadata/JT808AtomicCounter.cs | 49 - .../Metadata/JT808ClientReport.cs | 16 - .../Metadata/JT808ClientRequest.cs | 30 - .../Metadata/JT808HttpRequest.cs | 22 - .../Metadata/JT808HttpResponse.cs | 22 - src/JT808.Gateway/Metadata/JT808Request.cs | 23 - src/JT808.Gateway/Metadata/JT808Response.cs | 31 - src/JT808.Gateway/Metadata/JT808TcpSession.cs | 32 - src/JT808.Gateway/Metadata/JT808UdpPackage.cs | 20 - src/JT808.Gateway/Metadata/JT808UdpSession.cs | 38 - src/JT808.Gateway/Protos/JT808Gateway.proto | 63 - src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs | 15 - src/JT808.Gateway/PubSub/IJT808MsgProducer.cs | 17 - .../PubSub/IJT808MsgReplyConsumer.cs | 15 - .../PubSub/IJT808MsgReplyProducer.cs | 17 - src/JT808.Gateway/PubSub/IJT808PubSub.cs | 11 - .../PubSub/IJT808SessionConsumer.cs | 18 - .../PubSub/IJT808SessionProducer.cs | 13 - .../Services/JT808AtomicCounterService.cs | 52 - .../JT808AtomicCounterServiceFactory.cs | 30 - .../JT808ClientReceiveAtomicCounterService.cs | 35 - .../JT808ClientReportHostedService.cs | 37 - .../Services/JT808ClientReportService.cs | 43 - .../JT808ClientSendAtomicCounterService.cs | 35 - .../Services/JT808GatewayService.cs | 102 - .../Services/JT808MsgReplyHostedService.cs | 42 - src/JT808.Gateway/Services/JT808MsgService.cs | 11 - .../Services/JT808SessionService.cs | 98 - .../Services/JT808UnificationSendService.cs | 45 - .../Session/JT808SessionManager.cs | 304 -- .../Simples/JT808SimpleTcpClient.cs | 50 - .../Simples/JT808SimpleUdpClient.cs | 48 - .../Tcp/JT808TcpDotnettyExtensions.cs | 21 - src/JT808.Gateway/Tcp/JT808TcpServerHost.cs | 95 - .../Udp/JT808UdpDotnettyExtensions.cs | 22 - src/JT808.Gateway/Udp/JT808UdpServerHost.cs | 76 - 147 files changed, 36 insertions(+), 12087 deletions(-) delete mode 100644 README_V1.0.0.md rename doc/{img => dotnetty}/demo1.png (100%) rename doc/{img => dotnetty}/demo2.png (100%) rename doc/{img => dotnetty}/design_model.png (100%) rename doc/{img => dotnetty}/performance_1000.png (100%) rename doc/{img => dotnetty}/performance_10000.png (100%) rename doc/{img => dotnetty}/performance_2000.png (100%) rename doc/{img => dotnetty}/performance_5000.png (100%) create mode 100644 doc/pipeline/client_10k.png create mode 100644 doc/pipeline/server_network_10k.png create mode 100644 doc/pipeline/server_proccess_10k.png delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config delete mode 100644 src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config delete mode 100644 src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj delete mode 100644 src/JT808.Gateway.CleintBenchmark/Program.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs delete mode 100644 src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj delete mode 100644 src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgProducer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808SessionConsumer.cs delete mode 100644 src/JT808.Gateway.Kafka/JT808SessionProducer.cs delete mode 100644 src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj delete mode 100644 src/JT808.Gateway.SimpleClient/Program.cs delete mode 100644 src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs delete mode 100644 src/JT808.Gateway.SimpleClient/Services/UpService.cs delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/NLog.xsd delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config delete mode 100644 src/JT808.Gateway.SimpleServer/Configs/test.cer delete mode 100644 src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj delete mode 100644 src/JT808.Gateway.SimpleServer/Program.cs delete mode 100644 src/JT808.Gateway.sln delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs delete mode 100644 src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs delete mode 100644 src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs delete mode 100644 src/JT808.Gateway/Client/DeviceConfig.cs delete mode 100644 src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClient.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClientExtensions.cs delete mode 100644 src/JT808.Gateway/Client/JT808TcpClientFactory.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808TcpDecoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808TcpEncoder.cs delete mode 100644 src/JT808.Gateway/Codecs/JT808UdpDecoder.cs delete mode 100644 src/JT808.Gateway/Configurations/JT808Configuration.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808ResultDto.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs delete mode 100644 src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs delete mode 100644 src/JT808.Gateway/Enums/JT808TransportProtocolType.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs delete mode 100644 src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs delete mode 100644 src/JT808.Gateway/IJT808ClientBuilder.cs delete mode 100644 src/JT808.Gateway/IJT808GatewayBuilder.cs delete mode 100644 src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs delete mode 100644 src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808Reply.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808Session.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808SessionService.cs delete mode 100644 src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs delete mode 100644 src/JT808.Gateway/JT808.Gateway.csproj delete mode 100644 src/JT808.Gateway/JT808GatewayConstants.cs delete mode 100644 src/JT808.Gateway/JT808GatewayExtensions.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808AtomicCounter.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808ClientReport.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808ClientRequest.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808HttpRequest.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808HttpResponse.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808Request.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808Response.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808TcpSession.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808UdpPackage.cs delete mode 100644 src/JT808.Gateway/Metadata/JT808UdpSession.cs delete mode 100644 src/JT808.Gateway/Protos/JT808Gateway.proto delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgProducer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808PubSub.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs delete mode 100644 src/JT808.Gateway/PubSub/IJT808SessionProducer.cs delete mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReportHostedService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientReportService.cs delete mode 100644 src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs delete mode 100644 src/JT808.Gateway/Services/JT808GatewayService.cs delete mode 100644 src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs delete mode 100644 src/JT808.Gateway/Services/JT808MsgService.cs delete mode 100644 src/JT808.Gateway/Services/JT808SessionService.cs delete mode 100644 src/JT808.Gateway/Services/JT808UnificationSendService.cs delete mode 100644 src/JT808.Gateway/Session/JT808SessionManager.cs delete mode 100644 src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs delete mode 100644 src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs delete mode 100644 src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Tcp/JT808TcpServerHost.cs delete mode 100644 src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs delete mode 100644 src/JT808.Gateway/Udp/JT808UdpServerHost.cs diff --git a/LICENSE b/LICENSE index 67b52f7..79a535b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 SmallChi(Koike) +Copyright (c) 2019 SmallChi(Koike) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e7bcda4..62abed7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# JT808DotNetty +# JT808Gateway -基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 +基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 + +基于Pipeline封装的JT808DotNetty支持TCP/UDP通用消息业务处理 [了解JT808协议进这边](https://github.com/SmallChi/JT808) @@ -14,7 +16,7 @@ [![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE)[![Build Status](https://travis-ci.org/SmallChi/JT808DotNetty.svg?branch=master)](https://travis-ci.org/SmallChi/JT808DotNetty) -## 新网关的优势: +## 新网关的优势 1. 跨平台 2. 借助 .NET Core模块化的思想 @@ -55,7 +57,7 @@ |Traffic|流量统计服务 |由于运营商sim卡查询流量滞后,通过流量统计服务可以实时准确的统计设备流量,可以最优配置设备的流量大小,以节省成本 |Transmit| 原包转发服务|该服务可以将设备上报原始数据转发到第三方,支持全部转发,指定终端号转发| -## NuGet安装 +## 基于DotNetty的NuGet安装 | Package Name | Version | Downloads | | --------------------- | -------------------------------------------------- | --------------------------------------------------- | @@ -75,6 +77,13 @@ | Install-Package JT808.DotNetty.Kafka | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Kafka.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Kafka.svg) | | Install-Package JT808.DotNetty.RabbitMQ | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.RabbitMQ.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.RabbitMQ.svg) | +## 基于Pipeline的NuGet安装 + +| Package Name | Version | Downloads | +| --------------------- | -------------------------------------------------- | --------------------------------------------------- | +| Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) | +| Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) | + ## 举个栗子1 ``` demo1 diff --git a/README_V1.0.0.md b/README_V1.0.0.md deleted file mode 100644 index 1277e7e..0000000 --- a/README_V1.0.0.md +++ /dev/null @@ -1,120 +0,0 @@ -# JT808DotNetty - -基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 - -[了解JT808协议进这边](https://github.com/SmallChi/JT808) - -[了解JT809协议进这边](https://github.com/SmallChi/JT809) - -[了解JT1078协议进这边](https://github.com/SmallChi/JT1078) - -[了解JTNE协议进这边](https://github.com/SmallChi/JTNewEnergy) - -[玩一玩压力测试](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README.md) - -[V2.2.1老版本](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README_V2.2.1.md) - -[![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE) - -## 新网关的优势 - -1. 跨平台 -2. 借助 .NET Core模块化的思想 -3. 单机同时一万辆车在线不是梦(真有一万辆车那都很吃香了<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> ) -4. 简单易上手 - -## 设计模型 - -![design_model](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/design_model.png) - -## 基于Grpc的消息业务处理程序(JT808.Gateway.GrpcService) - -``` 1 -services.AddGrpcClient(o => -{ - o.Address = new Uri("https://localhost:5001"); -}); -``` - -## 集成接口功能(JT808.Gateway.PubSub) - -|接口名称|接口说明|使用场景| -|:------:|:------|:------| -| IJT808SessionProducer| 会话通知(在线/离线)数据生产接口| 有些超长待机的设备,不会实时保持连接,那么通过平台下发的命令是无法到达的,这时候就需要设备一上线,就即时通知服务去处理,然后在即时的下发消息到设备。| -| IJT808SessionConsumer| 会话通知(在线/离线)数据消费接口| -| -| IJT808MsgProducer| 数据生产接口| 网关将接收到的数据发送到队列| -| IJT808MsgConsumer| 数据消费接口| 将数据进行对应的消息业务处理(例:设备流量统计、第三方平台数据转发、消息日志等) | -| IJT808MsgReplyProducer| 应答数据生产接口|将生产的数据解析为对应的消息Id应答发送到队列 | -| IJT808MsgReplyConsumer| 应答数据消费接口| 将接收到的应答数据下发给设备| - -> 使用物联网卡通过udp下发指令时,存储的那个socket地址端口,有效期非常短,不速度快点下发,那个socket地址端口就可能映射到别的对应卡去了,所以此处采用跟随设备消息下发指令。 - -## 基于网关的相关服务(JT808.Gateway.BusinessServices) - -|服务名称|服务说明|使用场景| -|:------:|:------|:------| -|MsgIdHandler| 消息处理服务|从队列中消费设备上报数据,再结合自身的业务场景,将数据进行处理并入库 | -|MsgLogging | 消息日志服务|从队列中消费设备上报和平台应答数据,再将数据存入influxdb等数据库中,便于技术和技术支持排查设备与平台交互的原始数据| -|ReplyMessage| 消息响应服务| 用于响应设备上报消息,以及下发指令信息到设备| -|SessionNotice| 会话管理服务| 通知设备上线下线,对于udp设备来说,可以在设备上线时,将指令跟随消息下发到设备| -|Traffic|流量统计服务 |由于运营商sim卡查询流量滞后,通过流量统计服务可以实时准确的统计设备流量,可以最优配置设备的流量大小,以节省成本 -|Transmit| 原包转发服务|该服务可以将设备上报原始数据转发到第三方,支持全部转发,指定终端号转发| - -## NuGet安装 - -| Package Name | Version | Downloads | -| --------------------- | -------------------------------------------------- | --------------------------------------------------- | -| Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) | -| Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) | - -## 举个栗子1 - -1.进入JT808.Gateway.SimpleServer项目下的Debug目录运行服务端 - -2.进入JT808.Gateway.SimpleClient项目下的Debug目录运行客户端 - -``` 1 -static void Main(string[] args) -{ - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - //配置Grpc服务端 - webBuilder - .ConfigureKestrel(options => - { - options.Listen(IPAddress.Any, 5001, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http2; - listenOptions.UseHttps($"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs", "test.cer")}", ""); - }); - }) - .Configure(app => - { - app.UseRouting(); - app.UseEndpoints(endpoints => - { - //配置Grpc服务节点 - endpoints.MapGrpcService(); - }); - }); - }) - .ConfigureServices((hostContext,services) => - { - //services.Configure(hostContext.Configuration.GetSection("Kestrel")); - //添加Grpc服务 - services.AddGrpc(); - //添加JT808协议 - services.AddJT808Configure() - //添加JT808网关配置 - .AddJT808Gateway(hostContext.Configuration) - //添加基于Tcp的808网关 - .AddJT808GatewayTcpHost() - //添加基于Udp的808网关 - .AddJT808GatewayUdpHost() - .Builder(); - }) - .Build() - .Run(); -} -``` diff --git a/doc/README.md b/doc/README.md index ae791e0..9aaebe3 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,6 @@ -## 压力测试 +# 压力测试 + +## 基于DotNetty [感谢泥水佬提供的压力测试工具](https://www.cnblogs.com/smark/p/4496660.html?utm_source=tuicool) @@ -7,10 +9,25 @@ | win server 2016 | 4c8g | 压力测试客户端 | | centos7 | 4c8g | JT808服务端 | -![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_1000.png) +![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_1000.png) + +![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_2000.png) + +![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_5000.png) + +![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/performance_10000.png) + +## 基于pipeline + +| 操作系统 | 配置 | 使用 | +|:-------:|:-------:|:-------:| +| centos7 | 4c8g | JT808服务端 | +| centos7 | 4c8g | JT808客户端 | + +> 计算网络增强型 sn1ne ecs.sn1ne.xlarge 4 vCPU 8 GiB Intel Xeon E5-2682v4 / Intel Xeon(Skylake) Platinum 8163 2.5 GHz 1.5 Gbps 50 万 PPS -![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_2000.png) +![server_proccess_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/server_proccess_10k.png) -![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_5000.png) +![server_network_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/server_network_10k.png) -![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_10000.png) +![client_10k](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/pipeline/client_10k.png) diff --git a/doc/img/demo1.png b/doc/dotnetty/demo1.png similarity index 100% rename from doc/img/demo1.png rename to doc/dotnetty/demo1.png diff --git a/doc/img/demo2.png b/doc/dotnetty/demo2.png similarity index 100% rename from doc/img/demo2.png rename to doc/dotnetty/demo2.png diff --git a/doc/img/design_model.png b/doc/dotnetty/design_model.png similarity index 100% rename from doc/img/design_model.png rename to doc/dotnetty/design_model.png diff --git a/doc/img/performance_1000.png b/doc/dotnetty/performance_1000.png similarity index 100% rename from doc/img/performance_1000.png rename to doc/dotnetty/performance_1000.png diff --git a/doc/img/performance_10000.png b/doc/dotnetty/performance_10000.png similarity index 100% rename from doc/img/performance_10000.png rename to doc/dotnetty/performance_10000.png diff --git a/doc/img/performance_2000.png b/doc/dotnetty/performance_2000.png similarity index 100% rename from doc/img/performance_2000.png rename to doc/dotnetty/performance_2000.png diff --git a/doc/img/performance_5000.png b/doc/dotnetty/performance_5000.png similarity index 100% rename from doc/img/performance_5000.png rename to doc/dotnetty/performance_5000.png diff --git a/doc/pipeline/client_10k.png b/doc/pipeline/client_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..85875d6c56f46263760cf301c65382a2bf586820 GIT binary patch literal 22003 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%0DS+N!*{!T$0&1T#y!Q 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 literal 0 HcmV?d00001 diff --git a/doc/pipeline/server_network_10k.png b/doc/pipeline/server_network_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..4a469900ebfbf316cbaae7a2a8e4b41247e5ceee GIT binary patch literal 63584 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

L#8nWwuko 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≫⃒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 literal 0 HcmV?d00001 diff --git a/doc/pipeline/server_proccess_10k.png b/doc/pipeline/server_proccess_10k.png new file mode 100644 index 0000000000000000000000000000000000000000..c41d69d679d03c616f80ee0c1911a6139e7f2ec2 GIT binary patch literal 60562 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 literal 0 HcmV?d00001 diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs b/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs deleted file mode 100644 index f8dd628..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.CleintBenchmark.Configs -{ - public class ClientBenchmarkOptions : IOptions - { - public string IP { get; set; } - public int Port { get; set; } - public int DeviceCount { get; set; } = 10; - ///

- /// 5000ms毫秒 - /// - public int Interval { get; set; } = 5000; - public ClientBenchmarkOptions Value =>this; - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd b/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd deleted file mode 100644 index 2f57d09..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd +++ /dev/null @@ -1,3106 +0,0 @@ - - - - - - - - - - - - - - - Watch config file for changes and reload automatically. - - - - - Print internal NLog messages to the console. Default value is: false - - - - - Print internal NLog messages to the console error output. Default value is: false - - - - - Write internal NLog messages to the specified file. - - - - - Log level threshold for internal log messages. Default value is: Info. - - - - - Global log level threshold for application log messages. Messages below this level won't be logged.. - - - - - Throw an exception when there is an internal error. Default value is: false. - - - - - Throw an exception when there is a configuration error. If not set, determined by throwExceptions. - - - - - Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. - - - - - Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. - - - - - Write timestamps for internal NLog messages. Default value is: true. - - - - - Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. - - - - - Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. - - - - - - - - - - - - - - Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). - - - - - - - - - - - - - - - - - Prefix for targets/layout renderers/filters/conditions loaded from this assembly. - - - - - Load NLog extensions from the specified file (*.dll) - - - - - Load NLog extensions from the specified assembly. Assembly name should be fully qualified. - - - - - - - - - - Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name* - - - - - Comma separated list of levels that this rule matches. - - - - - Minimum level that this rule matches. - - - - - Maximum level that this rule matches. - - - - - Level that this rule matches. - - - - - Comma separated list of target names. - - - - - Ignore further rules if this one matches. - - - - - Enable or disable logging rule. Disabled rules are ignored. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. - - - - - Ignore any errors in the include file. - - - - - - - Variable name. - - - - - Variable value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events that should be processed in a batch by the lazy writer thread. - - - - - Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch - - - - - Action to be taken when the lazy writer thread request queue count exceeds the set limit. - - - - - Limit on the number of requests in the lazy writer thread request queue. - - - - - Time in milliseconds to sleep between batches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Delay the flush until the LogEvent has been confirmed as written - - - - - Condition expression. Log events who meet this condition will cause a flush on the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events to be buffered. - - - - - Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. - - - - - Indicates whether to use sliding timeout. - - - - - Action to take if the buffer overflows. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Viewer parameter name. - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to use default row highlighting rules. - - - - - Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Condition that must be met in order to set the specified foreground and background color. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - Indicates whether to ignore case when comparing texts. - - - - - Regular expression to be matched. You must specify either text or regex. - - - - - Text to be matched. You must specify either text or regex. - - - - - Indicates whether to match whole words only. - - - - - Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send the log messages to the standard error instead of the standard output. - - - - - Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. - - - - - Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. - - - - - Name of the database provider. - - - - - Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. - - - - - Indicates whether to keep the database connection open between the log events. - - - - - Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. - - - - - Name of the connection string (as specified in <connectionStrings> configuration section. - - - - - Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. - - - - - Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. - - - - - Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Text of the SQL command to be run on each log level. - - - - - Type of the SQL command to be run on each log level. - - - - - - - - - - - - - - - - - - - - - - - Type of the command. - - - - - Connection string to run the command against. If not provided, connection string from the target is used. - - - - - Indicates whether to ignore failures. - - - - - Command text. - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Database parameter name. - - - - - Database parameter precision. - - - - - Database parameter scale. - - - - - Database parameter size. - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Layout that renders event Category. - - - - - Layout that renders event ID. - - - - - Name of the Event Log to write to. This can be System, Application or any user-defined name. - - - - - Name of the machine on which Event Log service is running. - - - - - Value to be used as the event Source. - - - - - Action to take if the message is larger than the option. - - - - - Optional entrytype. When not set, or when not convertable to then determined by - - - - - Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API - - - - - Message length limit to write to the Event Log. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether to return to the first target after any successful write. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - File encoding. - - - - - Line ending mode. - - - - - Way file archives are numbered. - - - - - Name of the file to be used for an archive. - - - - - Indicates whether to automatically archive log files every time the specified time passes. - - - - - Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: - - - - - Indicates whether to compress archive files into the zip archive format. - - - - - Maximum number of archive files that should be kept. - - - - - Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. - - - - - Is the an absolute or relative path? - - - - - Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. - - - - - Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write - - - - - Is the an absolute or relative path? - - - - - Value indicationg whether file creation calls should be synchronized by a system global mutex. - - - - - Maximum number of log filenames that should be stored as existing. - - - - - Indicates whether the footer should be written only when the file is archived. - - - - - Name of the file to write to. - - - - - Value specifying the date format to use when archiving files. - - - - - Indicates whether to archive old log file on startup. - - - - - Indicates whether to create directories if they do not exist. - - - - - File attributes (Windows only). - - - - - Indicates whether to delete old log file on startup. - - - - - Indicates whether to replace file contents on each write instead of appending log message at the end. - - - - - Indicates whether to enable log file(s) to be deleted. - - - - - Number of times the write is appended on the file before NLog discards the log message. - - - - - Indicates whether concurrent writes to the log file by multiple processes on the same host. - - - - - Indicates whether to keep log file open instead of opening and closing it on each logging event. - - - - - Indicates whether concurrent writes to the log file by multiple processes on different network hosts. - - - - - Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). - - - - - Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Log file buffer size in bytes. - - - - - Indicates whether to automatically flush the file buffers after each log message. - - - - - Delay in milliseconds to wait before attempting to write to the file again. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Condition expression. Log events who meet this condition will be forwarded to the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Windows domain name to change context to. - - - - - Required impersonation level. - - - - - Type of the logon provider. - - - - - Logon Type. - - - - - User account password. - - - - - Indicates whether to revert to the credentials of the process instead of impersonating another user. - - - - - Username to change context to. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Interval in which messages will be written up to the number of messages. - - - - - Maximum allowed number of messages written per . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Endpoint address. - - - - - Name of the endpoint configuration in WCF configuration file. - - - - - Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) - - - - - Client ID. - - - - - Indicates whether to include per-event properties in the payload sent to the server. - - - - - Indicates whether to use binary message encoding. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Layout that should be use to calculate the value for the parameter. - - - - - Name of the parameter. - - - - - Type of the parameter. - - - - - Type of the parameter. Obsolete alias for - - - - - Parameter can combine multiple LogEvents into a single parameter value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send message as HTML instead of plain text. - - - - - Encoding to be used for sending e-mail. - - - - - Indicates whether to add new lines between log entries. - - - - - CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Mail message body (repeated for each log message send in one mail). - - - - - Mail subject. - - - - - Sender's email address (e.g. joe@domain.com). - - - - - Indicates the SMTP client timeout. - - - - - Priority used for sending mails. - - - - - Indicates whether NewLine characters in the body should be replaced with tags. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - SMTP Server to be used for sending. - - - - - SMTP Authentication mode. - - - - - Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. - - - - - Port number that SMTP Server is listening on. - - - - - Indicates whether the default Settings from System.Net.MailSettings should be used. - - - - - Folder where applications save mail messages to be processed by the local SMTP server. - - - - - Specifies how outgoing email messages will be handled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Class name. - - - - - Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Encoding to be used. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Network address. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Indicates whether to keep connection open whenever possible. - - - - - Maximum current connections. 0 = no maximum. - - - - - Maximum queue size. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Indicates whether to perform layout calculation. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether performance counter should be automatically created. - - - - - Name of the performance counter category. - - - - - Counter help text. - - - - - Name of the performance counter. - - - - - Performance counter type. - - - - - The value by which to increment the counter. - - - - - Performance counter instance name. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Default filter to be applied when no specific rule matches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - Condition to be tested. - - - - - Resulting filter to be applied when the condition matches. - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of times to repeat each log message. - - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of retries that should be attempted on the wrapped target in case of a failure. - - - - - Time to wait between retries in milliseconds. - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Always use independent of - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Encoding. - - - - - Value whether escaping be done according to the old NLog style (Very non-standard) - - - - - Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) - - - - - Web service method name. Only used with Soap. - - - - - Web service namespace. Only used with Soap. - - - - - Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) - - - - - Protocol to be used when calling web service. - - - - - Web service URL. - - - - - Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). - - - - - (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). - - - - - Column delimiter. - - - - - Quote Character. - - - - - Quoting mode. - - - - - Indicates whether CVS should include header. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout of the column. - - - - - Name of the column. - - - - - - - - - - - - - - - - - - List of property names to exclude when is true - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Option to render the empty object value {} - - - - - Option to suppress the extra spaces in the output json - - - - - - - - - - - - - - - Determines wether or not this attribute will be Json encoded. - - - - - Indicates whether to escape non-ascii characters - - - - - Layout that will be rendered as the attribute's value. - - - - - Name of the attribute. - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - - - - - - - - - - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include contents of the stack. - - - - - - - - - - - - - - Layout text. - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Condition expression. - - - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Layout to be used to filter log messages. - - - - - Default number of unique filter values to expect, will automatically increase if needed - - - - - Append FilterCount to the when an event is no longer filtered - - - - - Insert FilterCount value into when an event is no longer filtered - - - - - Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. - - - - - Max number of unique filter values to expect simultaneously - - - - - Max length of filter values, will truncate if above limit - - - - - Default buffer size for the internal buffers - - - - - Reuse internal buffers, and doesn't have to constantly allocate new buffers - - - - - How long before a filter expires, and logging is accepted again - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config b/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config deleted file mode 100644 index 2c8b777..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config b/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config deleted file mode 100644 index 14d4a10..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj b/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj deleted file mode 100644 index ad20926..0000000 --- a/src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - - diff --git a/src/JT808.Gateway.CleintBenchmark/Program.cs b/src/JT808.Gateway.CleintBenchmark/Program.cs deleted file mode 100644 index 88451ca..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Program.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; -using System; -using System.Threading.Tasks; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using JT808.Gateway.CleintBenchmark.Configs; -using JT808.Gateway.Client; -using JT808.Gateway.CleintBenchmark.Services; - -namespace JT808.Gateway.CleintBenchmark -{ - class Program - { - static async Task Main(string[] args) - { - var serverHostBuilder = new HostBuilder() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureLogging((context, logging) => - { - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - NLog.LogManager.LoadConfiguration("Configs/nlog.unix.config"); - } - else - { - NLog.LogManager.LoadConfiguration("Configs/nlog.win.config"); - } - logging.AddNLog(); - logging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => - { - services.Configure(hostContext.Configuration.GetSection("ClientBenchmarkOptions")); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Client(); - services.AddHostedService(); - services.AddHostedService(); - }); - await serverHostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs b/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs deleted file mode 100644 index 8cfa879..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs +++ /dev/null @@ -1,82 +0,0 @@ -using JT808.Gateway.CleintBenchmark.Configs; -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - - -namespace JT808.Gateway.CleintBenchmark.Services -{ - public class CleintBenchmarkHostedService : IHostedService - { - private readonly ClientBenchmarkOptions clientBenchmarkOptions; - - private readonly ILogger logger; - - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - private CancellationTokenSource cts=new CancellationTokenSource(); - - private TaskFactory taskFactory; - - public CleintBenchmarkHostedService( - ILoggerFactory loggerFactory, - IJT808TcpClientFactory jT808TcpClientFactory, - IOptions clientBenchmarkOptionsAccessor) - { - this.jT808TcpClientFactory = jT808TcpClientFactory; - clientBenchmarkOptions = clientBenchmarkOptionsAccessor.Value; - logger = loggerFactory.CreateLogger("CleintBenchmarkHostedService"); - taskFactory = new TaskFactory(); - } - public Task StartAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StartAsync..."); - ThreadPool.GetMinThreads(out var minWorkerThreads, out var minCompletionPortThreads); - ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads); - logger.LogInformation($"GetMinThreads:{minWorkerThreads}-{minCompletionPortThreads}"); - logger.LogInformation($"GetMaxThreads:{maxWorkerThreads}-{maxCompletionPortThreads}"); - //ThreadPool.SetMaxThreads(20, 20); - //ThreadPool.GetMaxThreads(out var setMaxWorkerThreads, out var setMaxCompletionPortThreads); - //logger.LogInformation($"SetMaxThreads:{setMaxWorkerThreads}-{setMaxCompletionPortThreads}"); - for (int i=0;i< clientBenchmarkOptions.DeviceCount; i++) - { - taskFactory.StartNew((item) => - { - var client = jT808TcpClientFactory.Create(new DeviceConfig(((int)item).ToString(), clientBenchmarkOptions.IP, clientBenchmarkOptions.Port)); - int lat = new Random(1000).Next(100000, 180000); - int Lng = new Random(1000).Next(100000, 180000); - while (!cts.IsCancellationRequested) - { - client.Send(new JT808_0x0200() - { - Lat = lat, - Lng = Lng, - GPSTime = DateTime.Now, - Speed = 50, - Direction = 30, - AlarmFlag = 5, - Altitude = 50, - StatusFlag = 10 - }); - Thread.Sleep(clientBenchmarkOptions.Interval); - } - }, i,cts.Token); - } - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - cts.Cancel(); - logger.LogInformation("StopAsync..."); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs b/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs deleted file mode 100644 index 768f475..0000000 --- a/src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using JT808.Gateway.Services; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - - -namespace JT808.Gateway.CleintBenchmark.Services -{ - public class CleintBenchmarkReportHostedService : IHostedService - { - private readonly JT808ClientReportService jT808ReportService; - - private CancellationTokenSource cts=new CancellationTokenSource(); - - private readonly ILogger logger; - public CleintBenchmarkReportHostedService( - ILoggerFactory loggerFactory, - JT808ClientReportService jT808ReportService) - { - this.jT808ReportService = jT808ReportService; - logger = loggerFactory.CreateLogger("CleintBenchmarkReportHostedService"); - } - public Task StartAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StartAsync..."); - Task.Run(() => { - while (!cts.IsCancellationRequested) - { - logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports.LastOrDefault())); - Thread.Sleep(3000); - } - }, cts.Token); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - logger.LogInformation("StopAsync..."); - cts.Cancel(); - logger.LogInformation("正在生成报表..."); - logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports,Formatting.Indented)); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs deleted file mode 100644 index 9d2aa55..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808ConsumerConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808ConsumerConfig: ConsumerConfig, IOptions - { - public string TopicName { get; set; } - - public JT808ConsumerConfig Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs deleted file mode 100644 index 53746e2..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808MsgConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs deleted file mode 100644 index d55b2ce..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgProducerConfig : JT808ProducerConfig, IOptions - { - JT808MsgProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs deleted file mode 100644 index 79f4c3c..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgReplyConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808MsgReplyConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs deleted file mode 100644 index 9b62e6e..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808MsgReplyProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808MsgReplyProducerConfig : JT808ProducerConfig, IOptions - { - JT808MsgReplyProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs deleted file mode 100644 index fca47cd..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808ProducerConfig.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808ProducerConfig : ProducerConfig,IOptions - { - public string TopicName { get; set; } - - public JT808ProducerConfig Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs deleted file mode 100644 index 6b57a0a..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808SessionConsumerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808SessionConsumerConfig : JT808ConsumerConfig, IOptions - { - JT808SessionConsumerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs b/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs deleted file mode 100644 index bba6871..0000000 --- a/src/JT808.Gateway.Kafka/Configs/JT808SessionProducerConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Confluent.Kafka; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configs.Kafka -{ - public class JT808SessionProducerConfig : JT808ProducerConfig, IOptions - { - JT808SessionProducerConfig IOptions.Value => this; - } -} diff --git a/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj b/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj deleted file mode 100644 index f68e24b..0000000 --- a/src/JT808.Gateway.Kafka/JT808.Gateway.Kafka.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - netstandard2.0 - 8.0 - Copyright 2018. - SmallChi(Koike) - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - false - 1.0.0-preview1 - false - LICENSE - true - JT808.Gateway.Kafka - JT808.Gateway.Kafka - 基于Kafka的JT808消息发布与订阅 - 基于Kafka的JT808消息发布与订阅 - - - - - - - - - - - - - - - - - - - diff --git a/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs b/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs deleted file mode 100644 index 3279c64..0000000 --- a/src/JT808.Gateway.Kafka/JT808ClientBuilderDefault.cs +++ /dev/null @@ -1,24 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Kafka -{ - internal class JT808ClientBuilderDefault : IJT808ClientBuilder - { - public IJT808Builder JT808Builder { get; } - - public JT808ClientBuilderDefault(IJT808Builder builder) - { - JT808Builder = builder; - } - - public IJT808Builder Builder() - { - return JT808Builder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs b/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs deleted file mode 100644 index b334097..0000000 --- a/src/JT808.Gateway.Kafka/JT808ClientKafkaExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -using JJT808.Gateway.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace JT808.Gateway.Kafka -{ - public static class JT808ClientKafkaExtensions - { - public static IJT808ClientBuilder AddJT808ClientKafka(this IJT808Builder builder) - { - return new JT808ClientBuilderDefault(builder); - } - /// - /// - /// - /// - /// GetSection("JT808MsgConsumerConfig") - /// - public static IJT808ClientBuilder AddMsgConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyProducerConfig") - /// - public static IJT808ClientBuilder AddMsgReplyProducer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyProducerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyConsumerConfig") - /// - public static IJT808ClientBuilder AddMsgReplyConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgReplyConsumer), typeof(JT808MsgReplyConsumer), ServiceLifetime.Singleton)); - return jT808ClientBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808SessionConsumerConfig") - /// - public static IJT808ClientBuilder AddSessionConsumer(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808SessionConsumerConfig")); - jT808ClientBuilder.JT808Builder.Services.TryAddSingleton(); - return jT808ClientBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs b/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs deleted file mode 100644 index 56818f2..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgConsumer : IJT808MsgConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808MsgConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808MsgConsumer"); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgProducer.cs b/src/JT808.Gateway.Kafka/JT808MsgProducer.cs deleted file mode 100644 index 67d6d1b..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgProducer : IJT808MsgProducer - { - public string TopicName { get; } - - private readonly IProducer producer; - public JT808MsgProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string terminalNo, byte[] data) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = terminalNo, - Value = data - }); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs b/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs deleted file mode 100644 index 004a391..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgReplyConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808MsgReplyConsumer : IJT808MsgReplyConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808MsgReplyConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808MsgReplyConsumer"); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs b/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs deleted file mode 100644 index f29e9be..0000000 --- a/src/JT808.Gateway.Kafka/JT808MsgReplyProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JJT808.Gateway.Kafka -{ - public class JT808MsgReplyProducer : IJT808MsgReplyProducer - { - public string TopicName { get;} - - private IProducer producer; - public JT808MsgReplyProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string terminalNo, byte[] data) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = terminalNo, - Value = data - }); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs b/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs deleted file mode 100644 index e8e1dc1..0000000 --- a/src/JT808.Gateway.Kafka/JT808ServerKafkaExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace JT808.Gateway.Kafka -{ - public static class JT808ServerKafkaExtensions - { - /// - /// - /// - /// - /// GetSection("JT808MsgProducerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaMsgProducer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgProducerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgProducer), typeof(JT808MsgProducer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808MsgReplyConsumerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaMsgReplyConsumer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808MsgReplyConsumerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808MsgReplyConsumer), typeof(JT808MsgReplyConsumer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - /// - /// - /// - /// - /// GetSection("JT808SessionProducerConfig") - /// - public static IJT808GatewayBuilder AddJT808ServerKafkaSessionProducer(this IJT808GatewayBuilder jT808GatewayBuilder, IConfiguration configuration) - { - jT808GatewayBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808SessionProducerConfig")); - jT808GatewayBuilder.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808SessionProducer), typeof(JT808SessionProducer), ServiceLifetime.Singleton)); - return jT808GatewayBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs b/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs deleted file mode 100644 index 9ccf830..0000000 --- a/src/JT808.Gateway.Kafka/JT808SessionConsumer.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808SessionConsumer : IJT808SessionConsumer - { - public CancellationTokenSource Cts => new CancellationTokenSource(); - - private readonly IConsumer consumer; - - private readonly ILogger logger; - - public string TopicName { get; } - - public JT808SessionConsumer( - IOptions consumerConfigAccessor, - ILoggerFactory loggerFactory) - { - consumer = new ConsumerBuilder(consumerConfigAccessor.Value).Build(); - TopicName = consumerConfigAccessor.Value.TopicName; - logger = loggerFactory.CreateLogger("JT808SessionConsumer"); - } - - public void OnMessage(Action<(string Notice, string TerminalNo)> callback) - { - Task.Run(() => - { - while (!Cts.IsCancellationRequested) - { - try - { - //如果不指定分区,根据kafka的机制会从多个分区中拉取数据 - //如果指定分区,根据kafka的机制会从相应的分区中拉取数据 - var data = consumer.Consume(Cts.Token); - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"Topic: {data.Topic} Key: {data.Key} Partition: {data.Partition} Offset: {data.Offset} TopicPartitionOffset:{data.TopicPartitionOffset}"); - } - callback((data.Key, data.Value)); - } - catch (ConsumeException ex) - { - logger.LogError(ex, TopicName); - } - catch (OperationCanceledException ex) - { - logger.LogError(ex, TopicName); - } - catch (Exception ex) - { - logger.LogError(ex, TopicName); - } - } - }, Cts.Token); - } - - public void Subscribe() - { - consumer.Subscribe(TopicName); - } - - public void Unsubscribe() - { - consumer.Unsubscribe(); - } - - public void Dispose() - { - consumer.Close(); - consumer.Dispose(); - } - } -} diff --git a/src/JT808.Gateway.Kafka/JT808SessionProducer.cs b/src/JT808.Gateway.Kafka/JT808SessionProducer.cs deleted file mode 100644 index 3b6494f..0000000 --- a/src/JT808.Gateway.Kafka/JT808SessionProducer.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Confluent.Kafka; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Kafka -{ - public class JT808SessionProducer : IJT808SessionProducer - { - public string TopicName { get; } - - private readonly IProducer producer; - public JT808SessionProducer( - IOptions producerConfigAccessor) - { - producer = new ProducerBuilder(producerConfigAccessor.Value).Build(); - TopicName = producerConfigAccessor.Value.TopicName; - } - - public void Dispose() - { - producer.Dispose(); - } - - public async Task ProduceAsync(string notice,string terminalNo) - { - await producer.ProduceAsync(TopicName, new Message - { - Key = notice, - Value = terminalNo - }); - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj b/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj deleted file mode 100644 index 597fe2f..0000000 --- a/src/JT808.Gateway.SimpleClient/JT808.Gateway.SimpleClient.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - diff --git a/src/JT808.Gateway.SimpleClient/Program.cs b/src/JT808.Gateway.SimpleClient/Program.cs deleted file mode 100644 index e58a3d5..0000000 --- a/src/JT808.Gateway.SimpleClient/Program.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Gateway.SimpleClient.Services; -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; -using Grpc.Net.Client; -using JT808.Gateway.GrpcService; -using System.Net; - -namespace JT808.Gateway.SimpleClient -{ - class Program - { - static async Task Main(string[] args) - { - //ref https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0#call-insecure-grpc-services-with-net-core-client - //ref https://docs.microsoft.com/zh-cn/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0 - - //先执行 dotnet dev-certs https --trust 命令生成开发证书 - //使用 certmgr.msc 导出证书在服务端配置对应证书文件 - //Uri "https://localhost:5001" - - var serverHostBuilder = new HostBuilder() - .ConfigureLogging((context, logging) => - { - logging.AddConsole(); - logging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => - { - services.AddGrpcClient(o => - { - o.Address = new Uri("https://localhost:5001"); - }); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddLogging(options => { - options.AddConsole(); - options.SetMinimumLevel(LogLevel.Trace); - }); - services.AddJT808Configure() - .AddJT808Client(); - services.AddHostedService(); - //services.AddHostedService(); - }); - await serverHostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs b/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs deleted file mode 100644 index e21a3dc..0000000 --- a/src/JT808.Gateway.SimpleClient/Services/GrpcClientService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using JT808.Gateway.GrpcService; -using static JT808.Gateway.GrpcService.JT808Gateway; -using Google.Protobuf; -using System.Text.Json; -using JT808.Protocol.Extensions; - -namespace JT808.Gateway.SimpleClient.Services -{ - public class GrpcClientService : IHostedService - { - private readonly ILogger logger; - private readonly JT808GatewayClient client; - - public GrpcClientService( - ILoggerFactory loggerFactory, - JT808GatewayClient jT808GatewayClient) - { - this.client = jT808GatewayClient; - logger = loggerFactory.CreateLogger("GrpcClientService"); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - Task.Run(() => { - //while (!cancellationToken.IsCancellationRequested) - //{ - Thread.Sleep(1000 * 10); - var result1 = client.GetTcpAtomicCounter(new Empty()); - var result2 = client.GetUdpAtomicCounter(new Empty()); - var result3 = client.GetTcpSessionAll(new Empty()); - var result4 = client.GetUdpSessionAll(new Empty()); - var result5 = client.UnificationSend(new UnificationSendRequest() - { - TerminalPhoneNo= "12345678910", - Data= ByteString.CopyFrom("7E 02 00 00 26 12 34 56 78 90 12 00 7D 02 00 00 00 01 00 00 00 02 00 BA 7F 0E 07 E4 F1 1C 00 28 00 3C 00 00 18 10 15 10 10 10 01 04 00 00 00 64 02 02 00 7D 01 13 7E".ToHexBytes()) - }); - var result6 = client.RemoveSessionByTerminalPhoneNo(new SessionRemoveRequest() - { - TerminalPhoneNo= "12345678910" - }); - - logger.LogDebug(JsonSerializer.Serialize(result1)); - logger.LogDebug(JsonSerializer.Serialize(result2)); - logger.LogDebug(JsonSerializer.Serialize(result3)); - logger.LogDebug(JsonSerializer.Serialize(result4)); - logger.LogDebug(JsonSerializer.Serialize(result5)); - logger.LogDebug(JsonSerializer.Serialize(result6)); - //} - }, cancellationToken); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.SimpleClient/Services/UpService.cs b/src/JT808.Gateway.SimpleClient/Services/UpService.cs deleted file mode 100644 index a9a9d83..0000000 --- a/src/JT808.Gateway.SimpleClient/Services/UpService.cs +++ /dev/null @@ -1,68 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.SimpleClient.Services -{ - public class UpService : IHostedService - { - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - public UpService(IJT808TcpClientFactory jT808TcpClientFactory) - { - this.jT808TcpClientFactory = jT808TcpClientFactory; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - JT808TcpClient client1 = jT808TcpClientFactory.Create(new DeviceConfig("12345678910", "127.0.0.1", 808)); - //1.终端注册 - client1.Send(new JT808_0x0100() - { - PlateNo = "粤A12345", - PlateColor = 2, - AreaID = 0, - CityOrCountyId = 0, - MakerId = "Koike001", - TerminalId = "Koike001", - TerminalModel = "Koike001" - }); - //2.终端鉴权 - client1.Send(new JT808_0x0102() - { - Code = "1234" - }); - Task.Run(() => { - while (true) - { - var i = 0; - //3.每5000秒发一次 - client1.Send(new JT808_0x0200() - { - Lat = 110000 + i, - Lng = 100000 + i, - GPSTime = DateTime.Now, - Speed = 50, - Direction = 30, - AlarmFlag = 5, - Altitude = 50, - StatusFlag = 10 - }); - i++; - Thread.Sleep(5000); - } - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd b/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd deleted file mode 100644 index 2f57d09..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/NLog.xsd +++ /dev/null @@ -1,3106 +0,0 @@ - - - - - - - - - - - - - - - Watch config file for changes and reload automatically. - - - - - Print internal NLog messages to the console. Default value is: false - - - - - Print internal NLog messages to the console error output. Default value is: false - - - - - Write internal NLog messages to the specified file. - - - - - Log level threshold for internal log messages. Default value is: Info. - - - - - Global log level threshold for application log messages. Messages below this level won't be logged.. - - - - - Throw an exception when there is an internal error. Default value is: false. - - - - - Throw an exception when there is a configuration error. If not set, determined by throwExceptions. - - - - - Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. - - - - - Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. - - - - - Write timestamps for internal NLog messages. Default value is: true. - - - - - Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. - - - - - Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. - - - - - - - - - - - - - - Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). - - - - - - - - - - - - - - - - - Prefix for targets/layout renderers/filters/conditions loaded from this assembly. - - - - - Load NLog extensions from the specified file (*.dll) - - - - - Load NLog extensions from the specified assembly. Assembly name should be fully qualified. - - - - - - - - - - Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name* - - - - - Comma separated list of levels that this rule matches. - - - - - Minimum level that this rule matches. - - - - - Maximum level that this rule matches. - - - - - Level that this rule matches. - - - - - Comma separated list of target names. - - - - - Ignore further rules if this one matches. - - - - - Enable or disable logging rule. Disabled rules are ignored. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. - - - - - Ignore any errors in the include file. - - - - - - - Variable name. - - - - - Variable value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events that should be processed in a batch by the lazy writer thread. - - - - - Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch - - - - - Action to be taken when the lazy writer thread request queue count exceeds the set limit. - - - - - Limit on the number of requests in the lazy writer thread request queue. - - - - - Time in milliseconds to sleep between batches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Delay the flush until the LogEvent has been confirmed as written - - - - - Condition expression. Log events who meet this condition will cause a flush on the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Number of log events to be buffered. - - - - - Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. - - - - - Indicates whether to use sliding timeout. - - - - - Action to take if the buffer overflows. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Viewer parameter name. - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to use default row highlighting rules. - - - - - Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Condition that must be met in order to set the specified foreground and background color. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - Indicates whether to ignore case when comparing texts. - - - - - Regular expression to be matched. You must specify either text or regex. - - - - - Text to be matched. You must specify either text or regex. - - - - - Indicates whether to match whole words only. - - - - - Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. - - - - - Background color. - - - - - Foreground color. - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send the log messages to the standard error instead of the standard output. - - - - - Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) - - - - - The encoding for writing messages to the . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. - - - - - Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. - - - - - Name of the database provider. - - - - - Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. - - - - - Indicates whether to keep the database connection open between the log events. - - - - - Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. - - - - - Name of the connection string (as specified in <connectionStrings> configuration section. - - - - - Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. - - - - - Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. - - - - - Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Text of the SQL command to be run on each log level. - - - - - Type of the SQL command to be run on each log level. - - - - - - - - - - - - - - - - - - - - - - - Type of the command. - - - - - Connection string to run the command against. If not provided, connection string from the target is used. - - - - - Indicates whether to ignore failures. - - - - - Command text. - - - - - - - - - - - - - - Layout that should be use to calcuate the value for the parameter. - - - - - Database parameter name. - - - - - Database parameter precision. - - - - - Database parameter scale. - - - - - Database parameter size. - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Layout that renders event Category. - - - - - Layout that renders event ID. - - - - - Name of the Event Log to write to. This can be System, Application or any user-defined name. - - - - - Name of the machine on which Event Log service is running. - - - - - Value to be used as the event Source. - - - - - Action to take if the message is larger than the option. - - - - - Optional entrytype. When not set, or when not convertable to then determined by - - - - - Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API - - - - - Message length limit to write to the Event Log. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether to return to the first target after any successful write. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - File encoding. - - - - - Line ending mode. - - - - - Way file archives are numbered. - - - - - Name of the file to be used for an archive. - - - - - Indicates whether to automatically archive log files every time the specified time passes. - - - - - Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: - - - - - Indicates whether to compress archive files into the zip archive format. - - - - - Maximum number of archive files that should be kept. - - - - - Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. - - - - - Is the an absolute or relative path? - - - - - Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. - - - - - Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write - - - - - Is the an absolute or relative path? - - - - - Value indicationg whether file creation calls should be synchronized by a system global mutex. - - - - - Maximum number of log filenames that should be stored as existing. - - - - - Indicates whether the footer should be written only when the file is archived. - - - - - Name of the file to write to. - - - - - Value specifying the date format to use when archiving files. - - - - - Indicates whether to archive old log file on startup. - - - - - Indicates whether to create directories if they do not exist. - - - - - File attributes (Windows only). - - - - - Indicates whether to delete old log file on startup. - - - - - Indicates whether to replace file contents on each write instead of appending log message at the end. - - - - - Indicates whether to enable log file(s) to be deleted. - - - - - Number of times the write is appended on the file before NLog discards the log message. - - - - - Indicates whether concurrent writes to the log file by multiple processes on the same host. - - - - - Indicates whether to keep log file open instead of opening and closing it on each logging event. - - - - - Indicates whether concurrent writes to the log file by multiple processes on different network hosts. - - - - - Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). - - - - - Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Log file buffer size in bytes. - - - - - Indicates whether to automatically flush the file buffers after each log message. - - - - - Delay in milliseconds to wait before attempting to write to the file again. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Condition expression. Log events who meet this condition will be forwarded to the wrapped target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Windows domain name to change context to. - - - - - Required impersonation level. - - - - - Type of the logon provider. - - - - - Logon Type. - - - - - User account password. - - - - - Indicates whether to revert to the credentials of the process instead of impersonating another user. - - - - - Username to change context to. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Interval in which messages will be written up to the number of messages. - - - - - Maximum allowed number of messages written per . - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Endpoint address. - - - - - Name of the endpoint configuration in WCF configuration file. - - - - - Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) - - - - - Client ID. - - - - - Indicates whether to include per-event properties in the payload sent to the server. - - - - - Indicates whether to use binary message encoding. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Layout that should be use to calculate the value for the parameter. - - - - - Name of the parameter. - - - - - Type of the parameter. - - - - - Type of the parameter. Obsolete alias for - - - - - Parameter can combine multiple LogEvents into a single parameter value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Text to be rendered. - - - - - Header. - - - - - Footer. - - - - - Indicates whether to send message as HTML instead of plain text. - - - - - Encoding to be used for sending e-mail. - - - - - Indicates whether to add new lines between log entries. - - - - - CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). - - - - - Mail message body (repeated for each log message send in one mail). - - - - - Mail subject. - - - - - Sender's email address (e.g. joe@domain.com). - - - - - Indicates the SMTP client timeout. - - - - - Priority used for sending mails. - - - - - Indicates whether NewLine characters in the body should be replaced with tags. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - SMTP Server to be used for sending. - - - - - SMTP Authentication mode. - - - - - Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). - - - - - Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. - - - - - Port number that SMTP Server is listening on. - - - - - Indicates whether the default Settings from System.Net.MailSettings should be used. - - - - - Folder where applications save mail messages to be processed by the local SMTP server. - - - - - Specifies how outgoing email messages will be handled. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Class name. - - - - - Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Encoding to be used. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Network address. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Indicates whether to keep connection open whenever possible. - - - - - Maximum current connections. 0 = no maximum. - - - - - Maximum queue size. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Encoding to be used. - - - - - Instance of that is used to format log messages. - - - - - End of line value if a newline is appended at the end of log message . - - - - - Maximum message size in bytes. - - - - - Indicates whether to append newline at the end of log message. - - - - - Action that should be taken if the will be more connections than . - - - - - Action that should be taken if the message is larger than maxMessageSize. - - - - - Maximum current connections. 0 = no maximum. - - - - - Indicates whether to keep connection open whenever possible. - - - - - Size of the connection cache (number of connections which are kept alive). - - - - - Network address. - - - - - Maximum queue size. - - - - - NDC item separator. - - - - - Indicates whether to include source info (file name and line number) in the information sent over the network. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include stack contents. - - - - - Indicates whether to include dictionary contents. - - - - - Indicates whether to include call site (class and method name) in the information sent over the network. - - - - - Option to include all properties from the log events - - - - - AppInfo field. By default it's the friendly name of the current AppDomain. - - - - - Indicates whether to include NLog-specific extensions to log4j schema. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Indicates whether to perform layout calculation. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Indicates whether performance counter should be automatically created. - - - - - Name of the performance counter category. - - - - - Counter help text. - - - - - Name of the performance counter. - - - - - Performance counter type. - - - - - The value by which to increment the counter. - - - - - Performance counter instance name. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Default filter to be applied when no specific rule matches. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - Condition to be tested. - - - - - Resulting filter to be applied when the condition matches. - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of times to repeat each log message. - - - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Number of retries that should be attempted on the wrapped target in case of a failure. - - - - - Time to wait between retries in milliseconds. - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - Name of the target. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - Name of the target. - - - - - Layout used to format log messages. - - - - - Always use independent of - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - - - - - - - - - - - - - - - - - - - - - - - - Name of the target. - - - - - Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. - - - - - Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit - - - - - Encoding. - - - - - Value whether escaping be done according to the old NLog style (Very non-standard) - - - - - Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) - - - - - Web service method name. Only used with Soap. - - - - - Web service namespace. Only used with Soap. - - - - - Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) - - - - - Protocol to be used when calling web service. - - - - - Web service URL. - - - - - Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). - - - - - (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). - - - - - Column delimiter. - - - - - Quote Character. - - - - - Quoting mode. - - - - - Indicates whether CVS should include header. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Layout of the column. - - - - - Name of the column. - - - - - - - - - - - - - - - - - - List of property names to exclude when is true - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Option to render the empty object value {} - - - - - Option to suppress the extra spaces in the output json - - - - - - - - - - - - - - - Determines wether or not this attribute will be Json encoded. - - - - - Indicates whether to escape non-ascii characters - - - - - Layout that will be rendered as the attribute's value. - - - - - Name of the attribute. - - - - - - - - - - - - - - Footer layout. - - - - - Header layout. - - - - - Body layout (can be repeated multiple times). - - - - - - - - - - - - - - - - - - Option to include all properties from the log events - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the dictionary. - - - - - Indicates whether to include contents of the stack. - - - - - Indicates whether to include contents of the stack. - - - - - - - - - - - - - - Layout text. - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Condition expression. - - - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - Substring to be matched. - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - String to compare the layout to. - - - - - Indicates whether to ignore case when comparing strings. - - - - - Layout to be used to filter log messages. - - - - - - - - - - - - - - - - - - - - - - - - Action to be taken when filter matches. - - - - - Layout to be used to filter log messages. - - - - - Default number of unique filter values to expect, will automatically increase if needed - - - - - Append FilterCount to the when an event is no longer filtered - - - - - Insert FilterCount value into when an event is no longer filtered - - - - - Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. - - - - - Max number of unique filter values to expect simultaneously - - - - - Max length of filter values, will truncate if above limit - - - - - Default buffer size for the internal buffers - - - - - Reuse internal buffers, and doesn't have to constantly allocate new buffers - - - - - How long before a filter expires, and logging is accepted again - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config b/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config deleted file mode 100644 index ee227dd..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/nlog.Unix.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config b/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config deleted file mode 100644 index ec26e74..0000000 --- a/src/JT808.Gateway.SimpleServer/Configs/nlog.Win32NT.config +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/JT808.Gateway.SimpleServer/Configs/test.cer b/src/JT808.Gateway.SimpleServer/Configs/test.cer deleted file mode 100644 index 04963c13899644cbd857fd8651659b7a0fd1f9a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 784 zcmXqLV&*YuV*IjznTe5!iNoVPn`ZU4>~jXZY@Awc9&O)w85y}*84N@Wg$xAPm_u2Z zg*kKblM{0?@{3ChSmwcO}=MdiWuH}`HTB!%+kt^H6~2I9z8ixx_9B( zEuE70Z(8irT=Vx)^Yn?Yd>@yl%+hd?6_@#VeMgVM3PzKeomE-=1rwPVv}<%_{$F;A z-^sFmGh3X;BX!oUoF>QrpSc%Ks=Tk3E3*A;z34XWJ+-Z})AgFH&narMHG~_b&)nL- zoNcd|?97Y?;vjKBkT|aacN0={@w0IO6|pcjnTId}DMsX207fz} z78n_n17#0vZ+%)(^X~Qw;~s+B$3M zEaj~d(=2}|8k`c5DY$-sTevB9ipuE)KaO6tOJx07F}aAzVLL-bG~eo|rw(BbJQ7 diff --git a/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj b/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj deleted file mode 100644 index d8666d6..0000000 --- a/src/JT808.Gateway.SimpleServer/JT808.Gateway.SimpleServer.csproj +++ /dev/null @@ -1,39 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - - - diff --git a/src/JT808.Gateway.SimpleServer/Program.cs b/src/JT808.Gateway.SimpleServer/Program.cs deleted file mode 100644 index 2590e7f..0000000 --- a/src/JT808.Gateway.SimpleServer/Program.cs +++ /dev/null @@ -1,71 +0,0 @@ -using JT808.Gateway.Services; -using JT808.Gateway.Tcp; -using JT808.Gateway.Udp; -using JT808.Protocol; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; -using System; -using System.IO; -using System.Net; - -namespace JT808.Gateway.SimpleServer -{ - class Program - { - static void Main(string[] args) - { - Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - Console.WriteLine($"Environment.OSVersion.Platform:{Environment.OSVersion.Platform.ToString()}"); - NLog.LogManager.LoadConfiguration($"Configs/nlog.{Environment.OSVersion.Platform.ToString()}.config"); - configLogging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true }); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder - .ConfigureKestrel(options => - { - options.Listen(IPAddress.Any, 5001, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http2; - listenOptions.UseHttps($"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs", "test.cer")}", ""); - }); - }) - .Configure(app => - { - app.UseRouting(); - app.UseEndpoints(endpoints => - { - endpoints.MapGrpcService(); - }); - }); - }) - .ConfigureServices((hostContext,services) => - { - //services.Configure(hostContext.Configuration.GetSection("Kestrel")); - services.AddGrpc(); - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Gateway(hostContext.Configuration) - .AddJT808GatewayTcpHost() - .AddJT808GatewayUdpHost() - .Builder(); - }) - .Build() - .Run(); - } - } -} diff --git a/src/JT808.Gateway.sln b/src/JT808.Gateway.sln deleted file mode 100644 index b6b12d5..0000000 --- a/src/JT808.Gateway.sln +++ /dev/null @@ -1,102 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29411.108 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway", "JT808.Gateway\JT808.Gateway.csproj", "{A42A396F-D32B-4AC2-B554-735AA7E2DBA8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.SimpleServer", "JT808.Gateway.SimpleServer\JT808.Gateway.SimpleServer.csproj", "{F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.SimpleClient", "JT808.Gateway.SimpleClient\JT808.Gateway.SimpleClient.csproj", "{886D4937-7265-40DC-87CC-85CE35553214}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.Kafka", "JT808.Gateway.Kafka\JT808.Gateway.Kafka.csproj", "{790E132C-7D92-4A6A-8CF0-2C181331FB31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.CleintBenchmark", "JT808.Gateway.CleintBenchmark\JT808.Gateway.CleintBenchmark.csproj", "{1A925C08-2590-4E55-84F2-96F01306D34D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{DC0E0AC1-C4BD-4291-AD16-744080411C3D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Traffic.Test", "JT808.Gateway.Tests\JT808.Gateway.Traffic.Test\JT808.Gateway.Traffic.Test.csproj", "{D4DF5285-612A-417D-BDE4-690BDF0C07C6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Transmit.Test", "JT808.Gateway.Tests\JT808.Gateway.Transmit.Test\JT808.Gateway.Transmit.Test.csproj", "{5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.SessionNotice.Test", "JT808.Gateway.Tests\JT808.Gateway.SessionNotice.Test\JT808.Gateway.SessionNotice.Test.csproj", "{562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.ReplyMessage.Test", "JT808.Gateway.Tests\JT808.Gateway.ReplyMessage.Test\JT808.Gateway.ReplyMessage.Test.csproj", "{CDE064DE-0E8E-4165-8F6A-6C03A8783506}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.MsgLogging.Test", "JT808.Gateway.Tests\JT808.Gateway.MsgLogging.Test\JT808.Gateway.MsgLogging.Test.csproj", "{8BD638B1-1F16-4BA8-8506-1B83DA4A884E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.MsgIdHandler.Test", "JT808.Gateway.Tests\JT808.Gateway.MsgIdHandler.Test\JT808.Gateway.MsgIdHandler.Test.csproj", "{CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.Gateway.Test", "JT808.Gateway.Tests\JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{F1031636-69CF-4C44-AF0B-F8BE8DE03864}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A42A396F-D32B-4AC2-B554-735AA7E2DBA8}.Release|Any CPU.Build.0 = Release|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F9ABFDDB-84A2-44C8-A162-A1FE4EA4D332}.Release|Any CPU.Build.0 = Release|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Debug|Any CPU.Build.0 = Debug|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Release|Any CPU.ActiveCfg = Release|Any CPU - {886D4937-7265-40DC-87CC-85CE35553214}.Release|Any CPU.Build.0 = Release|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {790E132C-7D92-4A6A-8CF0-2C181331FB31}.Release|Any CPU.Build.0 = Release|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A925C08-2590-4E55-84F2-96F01306D34D}.Release|Any CPU.Build.0 = Release|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D4DF5285-612A-417D-BDE4-690BDF0C07C6}.Release|Any CPU.Build.0 = Release|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB}.Release|Any CPU.Build.0 = Release|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE}.Release|Any CPU.Build.0 = Release|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDE064DE-0E8E-4165-8F6A-6C03A8783506}.Release|Any CPU.Build.0 = Release|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E}.Release|Any CPU.Build.0 = Release|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E}.Release|Any CPU.Build.0 = Release|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1031636-69CF-4C44-AF0B-F8BE8DE03864}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {D4DF5285-612A-417D-BDE4-690BDF0C07C6} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {5E2C290C-637B-4F8B-AE03-1A4B669F7FFB} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {562B16BD-1D4C-40FD-86CF-7845DBC9C1EE} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {CDE064DE-0E8E-4165-8F6A-6C03A8783506} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {8BD638B1-1F16-4BA8-8506-1B83DA4A884E} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {CC2ABC8E-CC78-4B68-8670-90C2BCAB434E} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - {F1031636-69CF-4C44-AF0B-F8BE8DE03864} = {DC0E0AC1-C4BD-4291-AD16-744080411C3D} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {F5671BD2-B44A-4A7C-80EA-E060A512992D} - EndGlobalSection -EndGlobal diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs deleted file mode 100644 index 59bf986..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/IJT808MsgIdHandler.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - /// - /// JT808消息Id处理程序 - /// - public interface IJT808MsgIdHandler - { - void Processor((string TerminalNo, byte[] Data) parameter); - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs deleted file mode 100644 index 433e065..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - public static class JT808MsgIdHandlerExtensions - { - public static IJT808ClientBuilder AddJT808MsgIdHandler(this IJT808ClientBuilder jT808ClientBuilder) - where TJT808MsgIdHandler: IJT808MsgIdHandler - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(typeof(IJT808MsgIdHandler),typeof(TJT808MsgIdHandler)); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs deleted file mode 100644 index d85eb04..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgIdHandler/JT808MsgIdHandlerHostedService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgIdHandler -{ - public class JT808MsgIdHandlerHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - - private readonly IJT808MsgIdHandler jT808MsgIdHandler; - public JT808MsgIdHandlerHostedService( - IJT808MsgIdHandler jT808DotNettyMsgIdHandler, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgIdHandler = jT808DotNettyMsgIdHandler; - this.jT808MsgConsumer = jT808MsgConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808MsgIdHandler.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs deleted file mode 100644 index b3daf96..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/IJT808MsgLogging.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - /// - /// 808数据上下行日志接口 - /// - public interface IJT808MsgLogging - { - void Processor((string TerminalNo, byte[] Data) parameter, JT808MsgLoggingType jT808MsgLoggingType); - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs deleted file mode 100644 index 7c52f15..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgDownLoggingHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public class JT808MsgDownLoggingHostedService : IHostedService - { - private readonly IJT808MsgReplyConsumer jT808MsgReplyConsumer; - private readonly IJT808MsgLogging jT808MsgLogging; - public JT808MsgDownLoggingHostedService( - IJT808MsgLogging jT808MsgLogging, - IJT808MsgReplyConsumer jT808MsgReplyConsumer) - { - this.jT808MsgReplyConsumer = jT808MsgReplyConsumer; - this.jT808MsgLogging = jT808MsgLogging; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgReplyConsumer.Subscribe(); - jT808MsgReplyConsumer.OnMessage(item=> - { - jT808MsgLogging.Processor(item, JT808MsgLoggingType.down); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgReplyConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs deleted file mode 100644 index 00f16ac..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public static class JT808MsgLoggingExtensions - { - public static IJT808ClientBuilder AddJT808MsgLogging(this IJT808ClientBuilder jT808ClientBuilder) - where TJT808MsgLogging: IJT808MsgLogging - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(typeof(IJT808MsgLogging),typeof(TJT808MsgLogging)); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs deleted file mode 100644 index 1c83329..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgLoggingType.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public enum JT808MsgLoggingType - { - /// - /// 数据上行 - /// - up, - /// - /// 数据下行 - /// - down - } -} diff --git a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs b/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs deleted file mode 100644 index be257b7..0000000 --- a/src/JT808.Gateway/BusinessServices/MsgLogging/JT808MsgUpLoggingHostedService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.MsgLogging -{ - public class JT808MsgUpLoggingHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly IJT808MsgLogging jT808MsgLogging; - public JT808MsgUpLoggingHostedService( - IJT808MsgLogging jT808MsgLogging, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808MsgLogging = jT808MsgLogging; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(item=> - { - jT808MsgLogging.Processor(item, JT808MsgLoggingType.up); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs deleted file mode 100644 index 049f824..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public static class JT808ReplyMessageExtensions - { - /// - /// 独享消息应答服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 独享消息应答服务(不同的消费者实例) - /// - /// 自定义消息回复服务 - /// - /// - public static IJT808ClientBuilder AddInprocJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - where TReplyMessageService : JT808ReplyMessageService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享消息应答服务(消费者单实例) - /// - /// 自定义消息回复服务 - /// - /// - public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - where TReplyMessageService : JT808ReplyMessageService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - /// - /// 共享消息应答服务(消费者单实例) - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808ReplyMessage(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs deleted file mode 100644 index 1bd7e74..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageHostedService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public class JT808ReplyMessageHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly JT808ReplyMessageService jT808DotNettyReplyMessageService; - - public JT808ReplyMessageHostedService( - JT808ReplyMessageService jT808DotNettyReplyMessageService, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808DotNettyReplyMessageService = jT808DotNettyReplyMessageService; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808DotNettyReplyMessageService.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs b/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs deleted file mode 100644 index 3fc64f6..0000000 --- a/src/JT808.Gateway/BusinessServices/ReplyMessage/JT808ReplyMessageService.cs +++ /dev/null @@ -1,165 +0,0 @@ -using JT808.Gateway.PubSub; -using JT808.Protocol; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.ReplyMessage -{ - public class JT808ReplyMessageService - { - protected Dictionary> HandlerDict { get; } - - protected JT808Serializer JT808Serializer { get; } - protected IJT808MsgReplyProducer JT808MsgReplyProducer { get; } - public JT808ReplyMessageService( - IJT808Config jT808Config, - IJT808MsgReplyProducer jT808MsgReplyProducer) - { - this.JT808Serializer = jT808Config.GetSerializer(); - this.JT808MsgReplyProducer = jT808MsgReplyProducer; - HandlerDict = new Dictionary> { - {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001}, - {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102}, - {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002}, - {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003}, - {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100}, - {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 }, - {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 }, - {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 } - }; - } - - public virtual void Processor((string TerminalNo, byte[] Data) parameter) - { - try - { - var request = JT808Serializer.HeaderDeserialize(parameter.Data); - if (HandlerDict.TryGetValue(request.Header.MsgId, out var func)) - { - var buffer = func(request); - if (buffer != null) - { - JT808MsgReplyProducer.ProduceAsync(parameter.TerminalNo, buffer); - } - } - } - catch - { - } - } - - /// - /// 终端通用应答 - /// 平台无需回复 - /// 实现自己的业务 - /// - /// - /// - public virtual byte[] Msg0x0001(JT808HeaderPackage request) - { - return null; - } - /// - /// 终端心跳 - /// - /// - /// - public virtual byte[] Msg0x0002(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注销 - /// - /// - /// - public virtual byte[] Msg0x0003(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注册 - /// - /// - /// - public virtual byte[] Msg0x0100(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100() - { - Code = "J" + request.Header.TerminalPhoneNo, - JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端鉴权 - /// - /// - /// - public virtual byte[] Msg0x0102(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 位置信息汇报 - /// - /// - /// - public virtual byte[] Msg0x0200(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 定位数据批量上传 - /// - /// - /// - public virtual byte[] Msg0x0704(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 数据上行透传 - /// - /// - /// - public virtual byte[] Msg0x0900(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs deleted file mode 100644 index c2c3b9b..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public static class JT808SessionNoticeExtensions - { - /// - /// 独享消息会话通知服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - - /// - /// 独享消息会话通知服务(不同的消费者实例) - /// - /// 自定义会话通知服务 - /// - /// - public static IJT808ClientBuilder AddInprocJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - where TSessionNoticeService : JT808SessionNoticeService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - - /// - /// 共享消息会话通知服务(消费者单实例) - /// - /// 自定义会话通知服务 - /// - /// - public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - where TSessionNoticeService : JT808SessionNoticeService - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - - /// - /// 共享消息会话通知服务(消费者单实例) - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808SessionNotice(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs deleted file mode 100644 index 44c04ae..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeHostedService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Threading.Tasks; -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public class JT808SessionNoticeHostedService : IHostedService - { - private readonly JT808SessionNoticeService jT808DotNettySessionNoticeService; - private readonly IJT808SessionConsumer jT808SessionConsumer; - public JT808SessionNoticeHostedService( - IJT808SessionConsumer jT808SessionConsumer, - JT808SessionNoticeService jT808DotNettySessionNoticeService) - { - this.jT808DotNettySessionNoticeService = jT808DotNettySessionNoticeService; - this.jT808SessionConsumer = jT808SessionConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808SessionConsumer.Subscribe(); - jT808SessionConsumer.OnMessage(jT808DotNettySessionNoticeService.Processor); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808SessionConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs b/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs deleted file mode 100644 index ccf4ace..0000000 --- a/src/JT808.Gateway/BusinessServices/SessionNotice/JT808SessionNoticeService.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.SessionNotice -{ - public class JT808SessionNoticeService - { - protected ILogger logger { get; } - public JT808SessionNoticeService(ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger("JT808DotNettySessionNoticeService"); - } - public virtual void Processor((string Notice, string TerminalNo) parameter) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"{parameter.Notice}-{parameter.TerminalNo}"); - } - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs deleted file mode 100644 index f028a5d..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public class JT808TrafficService:IDisposable - { - private readonly CSRedis.CSRedisClient redisClien; - public JT808TrafficService(IConfiguration configuration) - { - redisClien = new CSRedis.CSRedisClient(configuration.GetConnectionString("TrafficRedisHost")); - TrafficRedisClient.Initialization(redisClien); - } - - public void Dispose() - { - redisClien.Dispose(); - } - - /// - /// 按设备每天统计sim卡流量 - /// - /// - /// - public void Processor(string terminalNo,int len) - { - TrafficRedisClient.HIncrBy(terminalNo, DateTime.Now.ToString("yyyyMMdd"), len); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs deleted file mode 100644 index 4a83b0d..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public static class JT808TrafficServiceExtensions - { - /// - /// 独享消息流量统计服务(不同的消费者实例) - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808Traffic(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享消息流量统计服务(消费者单实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808Traffic(this IJT808ClientBuilder jT808ClientBuilder) - { - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs b/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs deleted file mode 100644 index 84c4299..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/JT808TrafficServiceHostedService.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Protocol.Extensions; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - public class JT808TrafficServiceHostedService : IHostedService - { - private readonly IJT808MsgConsumer jT808MsgConsumer; - private readonly JT808TrafficService jT808DotNettyTrafficService; - - public JT808TrafficServiceHostedService( - JT808TrafficService jT808DotNettyTrafficService, - IJT808MsgConsumer jT808MsgConsumer) - { - this.jT808MsgConsumer = jT808MsgConsumer; - this.jT808DotNettyTrafficService = jT808DotNettyTrafficService; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage((item)=> { - string str = item.Data.ToHexString(); - jT808DotNettyTrafficService.Processor(item.TerminalNo, item.Data.Length); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs b/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs deleted file mode 100644 index eb04aa0..0000000 --- a/src/JT808.Gateway/BusinessServices/Traffic/TrafficRedisClient.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Traffic -{ - class TrafficRedisClient: RedisHelper - { } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs b/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs deleted file mode 100644 index 5a50189..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Configs/DataTransferOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Transmit.Configs -{ - public class DataTransferOptions - { - public string Host { get; set; } - - public List TerminalNos { get; set; } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs b/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs deleted file mode 100644 index b9872cb..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Configs/RemoteServerOptions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.BusinessServices.Transmit.Configs -{ - public class RemoteServerOptions - { - public List DataTransfer { get; set; } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs b/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs deleted file mode 100644 index 397b063..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/Handlers/ClientConnectionHandler.cs +++ /dev/null @@ -1,76 +0,0 @@ -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using Polly; -using System; -using System.Linq; -using System.Collections.Generic; -using System.Net; -using System.Text; -using Microsoft.Extensions.Logging; - -namespace JT808.Gateway.BusinessServices.Transmit.Handlers -{ - public class ClientConnectionHandler : ChannelHandlerAdapter - { - private readonly Bootstrap bootstrap; - public Dictionary channeldic; - private readonly ILogger logger; - public ClientConnectionHandler(Bootstrap bootstrap, - Dictionary channeldic, - ILoggerFactory loggerFactory) - { - this.bootstrap = bootstrap; - this.channeldic = channeldic; - logger = loggerFactory.CreateLogger(); - } - public override void ChannelInactive(IChannelHandlerContext context) - { - Policy.HandleResult(context.Channel.Open) - .WaitAndRetryForeverAsync(retryAttempt => - { - return retryAttempt > 20 ? TimeSpan.FromSeconds(Math.Pow(2, 50)) : TimeSpan.FromSeconds(Math.Pow(2, retryAttempt));//超过重试20次,之后重试都是接近12个小时重试一次 - }, - (exception, timespan, ctx) => - { - logger.LogError($"服务端断开{context.Channel.RemoteAddress},重试结果{exception.Result},重试次数{timespan},下次重试间隔(s){ctx.TotalSeconds}"); - }) - .ExecuteAsync(async () => - { - try - { - var oldChannel = channeldic.FirstOrDefault(m => m.Value == context.Channel); - if (default(KeyValuePair).Equals(oldChannel)) - { - if(logger.IsEnabled( LogLevel.Debug)) - logger.LogDebug($"服务器已经删除了{oldChannel.Key}远程服务器配置"); - return true; - } - var channel = await bootstrap.ConnectAsync(context.Channel.RemoteAddress); - channeldic.Remove(oldChannel.Key); - channeldic.Add(oldChannel.Key, channel); - return channel.Open; - } - catch (Exception ex) - { - logger.LogError($"服务端断开后{context.Channel.RemoteAddress},重连异常:{ex}"); - return false; - } - }); - } - - public override void ChannelRead(IChannelHandlerContext context, object message) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogError($"服务端返回消息{message}"); - } - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - logger.LogError($"服务端Exception: {exception}"); - context.CloseAsync(); - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs deleted file mode 100644 index 969b2fd..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using JT808.Gateway.BusinessServices.Transmit.Configs; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public static class JT808DotNettyTransmitExtensions - { - /// - /// 独享转发服务(不同的消费者实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddInprocJT808Transmit(this IJT808ClientBuilder jT808ClientBuilder,IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("RemoteServerOptions")); - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - jT808ClientBuilder.JT808Builder.Services.AddHostedService(); - return jT808ClientBuilder; - } - /// - /// 共享转发服务(消费者单实例) - /// - /// - /// - /// - public static IJT808ClientBuilder AddShareJT808Transmit(this IJT808ClientBuilder jT808ClientBuilder, IConfiguration configuration) - { - jT808ClientBuilder.JT808Builder.Services.Configure(configuration.GetSection("RemoteServerOptions")); - jT808ClientBuilder.JT808Builder.Services.AddSingleton(); - return jT808ClientBuilder; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs deleted file mode 100644 index 51504b5..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitHostedService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using System.Threading; -using JT808.Gateway.PubSub; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public class JT808DotNettyTransmitHostedService:IHostedService - { - private readonly JT808DotNettyTransmitService jT808DotNettyTransmitService; - private readonly IJT808MsgConsumer jT808MsgConsumer; - public JT808DotNettyTransmitHostedService( - IJT808MsgConsumer jT808MsgConsumer, - JT808DotNettyTransmitService jT808DotNettyTransmitService) - { - this.jT808DotNettyTransmitService = jT808DotNettyTransmitService; - this.jT808MsgConsumer = jT808MsgConsumer; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Subscribe(); - jT808MsgConsumer.OnMessage(jT808DotNettyTransmitService.Send); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - jT808MsgConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs b/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs deleted file mode 100644 index 1c2d8c3..0000000 --- a/src/JT808.Gateway/BusinessServices/Transmit/JT808DotNettyTransmitService.cs +++ /dev/null @@ -1,236 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System.Linq; -using JT808.Gateway.BusinessServices.Transmit.Configs; -using JT808.Gateway.BusinessServices.Transmit.Handlers; - -namespace JT808.Gateway.BusinessServices.Transmit -{ - public class JT808DotNettyTransmitService - { - private readonly ILogger logger; - private readonly ILoggerFactory loggerFactory; - private IOptionsMonitor optionsMonitor; - public Dictionary channeldic = new Dictionary(); - public JT808DotNettyTransmitService(ILoggerFactory loggerFactory, - IOptionsMonitor optionsMonitor) - { - this.loggerFactory = loggerFactory; - logger = loggerFactory.CreateLogger("JT808DotNettyTransmitService"); - this.optionsMonitor = optionsMonitor; - InitialDispatcherClient(); - } - public void Send((string TerminalNo, byte[] Data) parameter) - { - if (optionsMonitor.CurrentValue.DataTransfer != null) - { - foreach (var item in optionsMonitor.CurrentValue.DataTransfer) - { - if (channeldic.TryGetValue($"all_{item.Host}", out var allClientChannel)) - { - try - { - if (allClientChannel.Open) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"转发所有数据到该网关{item.Host}"); - } - allClientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); - } - else - { - logger.LogError($"{item.Host}链接已关闭"); - } - } - catch (Exception ex) - { - logger.LogError($"{item.Host}发送数据出现异常:{ex}"); - } - } - else - { - if (item.TerminalNos.Contains(parameter.TerminalNo) && channeldic.TryGetValue($"{parameter.TerminalNo}_{item.Host}", out var clientChannel)) - { - try - { - if (clientChannel.Open) - { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - logger.LogDebug($"转发{parameter.TerminalNo}到该网关{item.Host}"); - clientChannel.WriteAndFlushAsync(Unpooled.WrappedBuffer(parameter.Data)); - } - else - { - logger.LogError($"{item.Host},{parameter.TerminalNo}链接已关闭"); - } - } - catch (Exception ex) - { - logger.LogError($"{item.Host},{parameter.TerminalNo}发送数据出现异常:{ex}"); - } - } - } - } - } - } - - public void InitialDispatcherClient() - { - Task.Run(async () => - { - var group = new MultithreadEventLoopGroup(); - var bootstrap = new Bootstrap(); - bootstrap.Group(group) - .Channel() - .Option(ChannelOption.TcpNodelay, true) - .Handler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - pipeline.AddLast(new ClientConnectionHandler(bootstrap, channeldic, loggerFactory)); - })); - optionsMonitor.OnChange(options => - { - List lastRemoteServers = new List(); - if (options.DataTransfer != null) - { - if (options.DataTransfer.Any()) - { - foreach (var item in options.DataTransfer) - { - if (item.TerminalNos != null) - { - if (item.TerminalNos.Any()) - { - foreach (var terminal in item.TerminalNos) - { - lastRemoteServers.Add($"{terminal}_{item.Host}"); - } - } - else - { - lastRemoteServers.Add($"all_{item.Host}"); - } - } - else - { - lastRemoteServers.Add($"all_{item.Host}"); - } - } - } - } - DelRemoteServsers(lastRemoteServers); - AddRemoteServsers(bootstrap, lastRemoteServers); - }); - await InitRemoteServsers(bootstrap); - }); - } - /// - /// 初始化远程服务器 - /// - /// - /// - /// - private async Task InitRemoteServsers(Bootstrap bootstrap) - { - List remoteServers = new List(); - if (optionsMonitor.CurrentValue.DataTransfer != null) - { - if (optionsMonitor.CurrentValue.DataTransfer.Any()) - { - foreach (var item in optionsMonitor.CurrentValue.DataTransfer) - { - if (item.TerminalNos != null) - { - if (item.TerminalNos.Any()) - { - foreach (var terminal in item.TerminalNos) - { - remoteServers.Add($"{terminal}_{item.Host}"); - } - } - else - { - remoteServers.Add($"all_{item.Host}"); - } - } - else - { - remoteServers.Add($"all_{item.Host}"); - } - } - } - } - foreach (var item in remoteServers) - { - try - { - string ip_port = item.Split('_')[1]; - IChannel clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip_port.Split(':')[0]), int.Parse(ip_port.Split(':')[1]))); - channeldic.Add(item, clientChannel); - if (clientChannel.Open) - { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - logger.LogDebug($"该终端{item.Replace("_", "已连接上该服务器")}"); - } - } - } - catch (Exception ex) - { - logger.LogError($"初始化配置链接远程服务端{item},链接异常:{ex}"); - } - } - await Task.CompletedTask; - } - /// - /// 动态删除远程服务器 - /// - /// - private void DelRemoteServsers(List lastRemoteServers) - { - var delChannels = channeldic.Keys.Except(lastRemoteServers).ToList(); - foreach (var item in delChannels) - { - channeldic[item].CloseAsync(); - channeldic.Remove(item); - } - } - /// - /// 动态添加远程服务器 - /// - /// - /// - private void AddRemoteServsers(Bootstrap bootstrap, List lastRemoteServers) - { - var addChannels = lastRemoteServers.Except(channeldic.Keys).ToList(); - foreach (var item in addChannels) - { - try - { - var ip_port = item.Split('_')[1]; - IChannel clientChannel = bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip_port.Split(':')[0]), int.Parse(ip_port.Split(':')[1]))).Result; - channeldic.Add(item, clientChannel); - if (clientChannel.Open) { - if (logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - logger.LogDebug($"该终端{item.Replace("_", "已连接上该服务器")}"); - } - } - } - catch (Exception ex) - { - logger.LogError($"变更配置后链接远程服务端{item},重连异常:{ex}"); - } - } - } - } -} diff --git a/src/JT808.Gateway/Client/DeviceConfig.cs b/src/JT808.Gateway/Client/DeviceConfig.cs deleted file mode 100644 index 53518ef..0000000 --- a/src/JT808.Gateway/Client/DeviceConfig.cs +++ /dev/null @@ -1,28 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Client -{ - public class DeviceConfig - { - public DeviceConfig(string terminalPhoneNo, string tcpHost,int tcpPort) - { - TerminalPhoneNo = terminalPhoneNo; - TcpHost = tcpHost; - TcpPort = tcpPort; - MsgSNDistributed = new JT808ClientMsgSNDistributedImpl(); - } - public string TerminalPhoneNo { get; private set; } - public string TcpHost { get; private set; } - public int TcpPort { get; private set; } - /// - /// 心跳时间(秒) - /// - public int Heartbeat { get; set; } = 30; - - public IJT808MsgSNDistributed MsgSNDistributed { get; } - } -} diff --git a/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs b/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs deleted file mode 100644 index 05d998f..0000000 --- a/src/JT808.Gateway/Client/JT808ClientDotnettyExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ - -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol; -using JT808.Gateway.Services; - -namespace JT808.Gateway.Client -{ - public static class JT808ClientDotnettyExtensions - { - public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder) - { - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddSingleton(); - jT808Builder.Services.AddHostedService(); - return jT808Builder; - } - } -} diff --git a/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs b/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs deleted file mode 100644 index a7c11b6..0000000 --- a/src/JT808.Gateway/Client/JT808ClientMsgSNDistributedImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using System.Threading; - -namespace JT808.Gateway.Client -{ - internal class JT808ClientMsgSNDistributedImpl : IJT808MsgSNDistributed - { - int _counter = 0; - - public ushort Increment() - { - return (ushort)Interlocked.Increment(ref _counter); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClient.cs b/src/JT808.Gateway/Client/JT808TcpClient.cs deleted file mode 100644 index 9b6b93c..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClient.cs +++ /dev/null @@ -1,112 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using Microsoft.Extensions.Logging; -using System; -using System.Runtime.InteropServices; -using Microsoft.Extensions.DependencyInjection; -using System.Net; -using JT808.Protocol; -using JT808.Gateway.Services; -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Client -{ - public sealed class JT808TcpClient : IDisposable - { - private MultithreadEventLoopGroup group; - - private IChannel clientChannel; - - private bool disposed = false; - - public DeviceConfig DeviceConfig { get; private set; } - - public ILoggerFactory LoggerFactory { get; private set; } - - public JT808TcpClient(DeviceConfig deviceConfig, IServiceProvider serviceProvider) - { - DeviceConfig = deviceConfig; - LoggerFactory = serviceProvider.GetRequiredService(); - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService = serviceProvider.GetRequiredService(); - JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService = serviceProvider.GetRequiredService(); - IJT808Config jT808Config = serviceProvider.GetRequiredService(); - group = new MultithreadEventLoopGroup(1); - Bootstrap bootstrap = new Bootstrap(); - bootstrap.Group(group); - bootstrap.Channel(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - bootstrap.Option(ChannelOption.SoReuseport, true); - } - bootstrap - .Option(ChannelOption.SoBacklog, 8192) - .Handler(new ActionChannelInitializer(channel => - { - channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); - channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600)); - channel.Pipeline.AddLast("jt808TcpDecode", new JT808ClientTcpDecoder()); - channel.Pipeline.AddLast("jt808TcpEncode", new JT808ClientTcpEncoder(jT808Config,jT808SendAtomicCounterService, LoggerFactory)); - channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this)); - channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(jT808ReceiveAtomicCounterService,this)); - })); - clientChannel = bootstrap.ConnectAsync(IPAddress.Parse(DeviceConfig.TcpHost), DeviceConfig.TcpPort).Result; - } - - public async void Send(JT808ClientRequest request) - { - if (disposed) return; - if (clientChannel == null) throw new NullReferenceException("Channel is empty."); - if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty."); - if (clientChannel.Active && clientChannel.Open) - { - await clientChannel.WriteAndFlushAsync(request); - } - } - - public bool IsOpen - { - get - { - if (clientChannel == null) return false; - return clientChannel.Active && clientChannel.Open; - } - } - - private void Dispose(bool disposing) - { - if (disposed) - { - return; - } - if (disposing) - { - // 清理托管资源 - group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); - } - disposed = true; - } - - ~JT808TcpClient() - { - //必须为false - //这表明,隐式清理时,只要处理非托管资源就可以了。 - Dispose(false); - } - - public void Dispose() - { - //必须为true - Dispose(true); - //通知垃圾回收机制不再调用终结器(析构器) - GC.SuppressFinalize(this); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs b/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs deleted file mode 100644 index 919405e..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClientExtensions.cs +++ /dev/null @@ -1,103 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Client -{ - public static class JT808TcpClientExtensions - { - public static void Send(this JT808TcpClient client, JT808Header header, JT808Bodies bodies, int minBufferSize = 1024) - { - JT808Package package = new JT808Package(); - package.Header = header; - package.Bodies = bodies; - package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo; - package.Header.MsgNum = client.DeviceConfig.MsgSNDistributed.Increment(); - JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize); - client.Send(request); - } - - /// - /// 终端通用应答 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0001 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端通用应答.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端心跳 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0002 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端心跳.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端注销 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0003 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端注销.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端鉴权 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0102 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 终端注册 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0100 bodies, int minBufferSize = 100) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.终端注册.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - - /// - /// 位置信息汇报 - /// - /// - /// - /// - public static void Send(this JT808TcpClient client, JT808_0x0200 bodies, int minBufferSize = 200) - { - JT808Header header = new JT808Header(); - header.MsgId = JT808MsgId.位置信息汇报.ToUInt16Value(); - client.Send(header, bodies, minBufferSize); - } - } -} diff --git a/src/JT808.Gateway/Client/JT808TcpClientFactory.cs b/src/JT808.Gateway/Client/JT808TcpClientFactory.cs deleted file mode 100644 index 1e78b8a..0000000 --- a/src/JT808.Gateway/Client/JT808TcpClientFactory.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.Client -{ - public interface IJT808TcpClientFactory : IDisposable - { - JT808TcpClient Create(DeviceConfig deviceConfig); - - List GetAll(); - } - - public class JT808TcpClientFactory: IJT808TcpClientFactory - { - private readonly ConcurrentDictionary dict; - - private readonly IServiceProvider serviceProvider; - - public JT808TcpClientFactory(IServiceProvider serviceProvider) - { - dict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - this.serviceProvider = serviceProvider; - } - - public JT808TcpClient Create(DeviceConfig deviceConfig) - { - if(dict.TryGetValue(deviceConfig.TerminalPhoneNo,out var client)) - { - return client; - } - else - { - JT808TcpClient jT808TcpClient = new JT808TcpClient(deviceConfig, serviceProvider); - dict.TryAdd(deviceConfig.TerminalPhoneNo, jT808TcpClient); - return jT808TcpClient; - } - } - - public void Dispose() - { - foreach(var client in dict) - { - try - { - client.Value.Dispose(); - } - catch - { - } - } - } - - public List GetAll() - { - return dict.Values.ToList(); - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs b/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs deleted file mode 100644 index c3aa8f1..0000000 --- a/src/JT808.Gateway/Codecs/JT808ClientTcpDecoder.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using System.Collections.Generic; -using JT808.Protocol; -using DotNetty.Transport.Channels; - -namespace JT808.Gateway.Codecs -{ - public class JT808ClientTcpDecoder : ByteToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List output) - { - byte[] buffer = new byte[input.Capacity + 2]; - input.ReadBytes(buffer, 1, input.Capacity); - buffer[0] = JT808Package.BeginFlag; - buffer[input.Capacity + 1] = JT808Package.EndFlag; - output.Add(buffer); - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs b/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs deleted file mode 100644 index eddc19c..0000000 --- a/src/JT808.Gateway/Codecs/JT808ClientTcpEncoder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using JT808.Protocol; -using DotNetty.Transport.Channels; -using Microsoft.Extensions.Logging; -using JT808.Gateway.Metadata; -using JT808.Gateway.Services; - -namespace JT808.Gateway.Codecs -{ - public class JT808ClientTcpEncoder : MessageToByteEncoder - { - private readonly ILogger logger; - private readonly JT808ClientSendAtomicCounterService jT808SendAtomicCounterService; - private readonly JT808Serializer JT808Serializer; - - public JT808ClientTcpEncoder( - IJT808Config jT808Config, - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService,ILoggerFactory loggerFactory) - { - logger=loggerFactory.CreateLogger(); - this.jT808SendAtomicCounterService = jT808SendAtomicCounterService; - JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void Encode(IChannelHandlerContext context, JT808ClientRequest message, IByteBuffer output) - { - if (message.Package != null) - { - try - { - var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); - output.WriteBytes(sendData); - jT808SendAtomicCounterService.MsgSuccessIncrement(); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - catch (System.Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - } - else if (message.HexData != null) - { - output.WriteBytes(message.HexData); - jT808SendAtomicCounterService.MsgSuccessIncrement(); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs b/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs deleted file mode 100644 index 10e3ff1..0000000 --- a/src/JT808.Gateway/Codecs/JT808TcpDecoder.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using System.Collections.Generic; -using JT808.Protocol; -using DotNetty.Transport.Channels; - -namespace JT808.Gateway.Codecs -{ - public class JT808TcpDecoder : ByteToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List output) - { - //过滤掉不是808标准包 - //不包括头尾标识 - //(消息 ID )2+(消息体属性)2+(终端手机号)6+(消息流水号)2+(检验码 )1 - if (input.Capacity < 12) - { - byte[] buffer = new byte[input.Capacity]; - input.ReadBytes(buffer, 0, input.Capacity); - return; - } - else - { - byte[] buffer = new byte[input.Capacity + 2]; - input.ReadBytes(buffer, 1, input.Capacity); - buffer[0] = JT808Package.BeginFlag; - buffer[input.Capacity + 1] = JT808Package.EndFlag; - output.Add(buffer); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs b/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs deleted file mode 100644 index ca92147..0000000 --- a/src/JT808.Gateway/Codecs/JT808TcpEncoder.cs +++ /dev/null @@ -1,52 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using JT808.Protocol; -using DotNetty.Transport.Channels; -using Microsoft.Extensions.Logging; -using JT808.Protocol.Interfaces; -using JT808.Gateway.Interfaces; - -namespace JT808.Gateway.Codecs -{ - /// - /// tcp统一下发出口 - /// - public class JT808TcpEncoder : MessageToByteEncoder - { - private readonly ILogger logger; - - private readonly JT808Serializer JT808Serializer; - - public JT808TcpEncoder( - IJT808Config jT808Config, - ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger(); - this.JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void Encode(IChannelHandlerContext context, IJT808Reply message, IByteBuffer output) - { - if (message.Package != null) - { - try - { - var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); - output.WriteBytes(Unpooled.WrappedBuffer(sendData)); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - catch (System.Exception ex) - { - logger.LogError(ex, context.Channel.Id.AsShortText()); - } - } - else if (message.HexData != null) - { - output.WriteBytes(Unpooled.WrappedBuffer(message.HexData)); - } - } - } -} diff --git a/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs b/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs deleted file mode 100644 index d3018f8..0000000 --- a/src/JT808.Gateway/Codecs/JT808UdpDecoder.cs +++ /dev/null @@ -1,33 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Transport.Channels; -using System.Collections.Generic; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Codecs -{ - public class JT808UdpDecoder : MessageToMessageDecoder - { - protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List output) - { - if (!message.Content.IsReadable()) return; - IByteBuffer byteBuffer = message.Content; - //过滤掉非808标准包 - //不包括头尾标识 - //(消息 ID )2+(消息体属性)2+(终端手机号)6+(消息流水号)2+(检验码 )1 - if (byteBuffer.ReadableBytes < 12) - { - byte[] buffer = new byte[byteBuffer.ReadableBytes]; - byteBuffer.ReadBytes(buffer, 0, byteBuffer.ReadableBytes); - return; - } - else - { - byte[] buffer = new byte[byteBuffer.ReadableBytes]; - byteBuffer.ReadBytes(buffer); - output.Add(new JT808UdpPackage(buffer, message.Sender)); - } - } - } -} diff --git a/src/JT808.Gateway/Configurations/JT808Configuration.cs b/src/JT808.Gateway/Configurations/JT808Configuration.cs deleted file mode 100644 index c39ab4e..0000000 --- a/src/JT808.Gateway/Configurations/JT808Configuration.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Configurations -{ - public class JT808Configuration - { - public int TcpPort { get; set; } = 808; - - public int UdpPort { get; set; } = 808; - - public int QuietPeriodSeconds { get; set; } = 1; - - public TimeSpan QuietPeriodTimeSpan => TimeSpan.FromSeconds(QuietPeriodSeconds); - - public int ShutdownTimeoutSeconds { get; set; } = 3; - - public TimeSpan ShutdownTimeoutTimeSpan => TimeSpan.FromSeconds(ShutdownTimeoutSeconds); - - public int SoBacklog { get; set; } = 8192; - - public int EventLoopCount { get; set; } = Environment.ProcessorCount; - - public int ReaderIdleTimeSeconds { get; set; } = 3600; - - public int WriterIdleTimeSeconds { get; set; } = 3600; - - public int AllIdleTimeSeconds { get; set; } = 3600; - - /// - /// 转发远程地址 (可选项)知道转发的地址有利于提升性能 - /// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: - // 1.消息的序列化 - // 2.消息的下发 - // 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle - // 就跟神兽貔貅一样。。。 - /// - public List ForwardingRemoteIPAddress { get; set; } - } -} diff --git a/src/JT808.Gateway/Dtos/JT808ResultDto.cs b/src/JT808.Gateway/Dtos/JT808ResultDto.cs deleted file mode 100644 index 0b72015..0000000 --- a/src/JT808.Gateway/Dtos/JT808ResultDto.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Dtos -{ - public class JT808ResultDto - { - public JT808ResultDto() - { - Code = JT808ResultCode.Ok; - } - - public string Message { get; set; } - - public int Code { get; set; } - - public T Data { get; set; } - } - - public class JT808ResultCode - { - public const int Ok = 200; - public const int Empty = 201; - public const int NotFound = 404; - public const int Fail = 400; - public const int Error = 500; - } -} diff --git a/src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs b/src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs deleted file mode 100644 index 423381e..0000000 --- a/src/JT808.Gateway/Dtos/JT808TcpSessionInfoDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace JT808.Gateway.Dtos -{ - public class JT808TcpSessionInfoDto - { - /// - /// 最后上线时间 - /// - public DateTime LastActiveTime { get; set; } - /// - /// 上线时间 - /// - public DateTime StartTime { get; set; } - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - /// - /// 远程ip地址 - /// - public string RemoteAddressIP { get; set; } - } -} diff --git a/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs b/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs deleted file mode 100644 index 9ba9c16..0000000 --- a/src/JT808.Gateway/Dtos/JT808UdpSessionInfoDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace JT808.Gateway.Dtos -{ - public class JT808UdpSessionInfoDto - { - /// - /// 最后上线时间 - /// - public DateTime LastActiveTime { get; set; } - /// - /// 上线时间 - /// - public DateTime StartTime { get; set; } - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - /// - /// 远程ip地址 - /// - public string RemoteAddressIP { get; set; } - } -} diff --git a/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs b/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs deleted file mode 100644 index ce9bb9f..0000000 --- a/src/JT808.Gateway/Enums/JT808TransportProtocolType.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Enums -{ - /// - /// 传输协议类型 - /// - public enum JT808TransportProtocolType - { - tcp=1, - udp = 2 - } -} diff --git a/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs deleted file mode 100644 index 26ea698..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpClientConnectionHandler.cs +++ /dev/null @@ -1,96 +0,0 @@ -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Channels; -using JT808.Gateway.Client; -using JT808.Protocol.MessageBody; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808客户端连接通道处理程序 - /// - public class JT808TcpClientConnectionHandler : ChannelHandlerAdapter - { - private readonly ILogger logger; - private readonly JT808TcpClient jT808TcpClient; - - public JT808TcpClientConnectionHandler( - JT808TcpClient jT808TcpClient) - { - logger = jT808TcpClient.LoggerFactory.CreateLogger(); - this.jT808TcpClient = jT808TcpClient; - } - - /// - /// 通道激活 - /// - /// - public override void ChannelActive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } Successful client connection to server."); - base.ChannelActive(context); - } - - /// - /// 设备主动断开 - /// - /// - public override void ChannelInactive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($">>>{ channelId } The client disconnects from the server."); - - base.ChannelInactive(context); - } - - /// - /// 服务器主动断开 - /// - /// - /// - public override Task CloseAsync(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); - - return base.CloseAsync(context); - } - - public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); - - /// - /// 超时策略 - /// - /// - /// - public override void UserEventTriggered(IChannelHandlerContext context, object evt) - { - IdleStateEvent idleStateEvent = evt as IdleStateEvent; - if (idleStateEvent != null) - { - if(idleStateEvent.State== IdleState.WriterIdle) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); - jT808TcpClient.Send(new JT808_0x0002()); - } - } - base.UserEventTriggered(context, evt); - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogError(exception,$"{channelId} {exception.Message}" ); - - context.CloseAsync(); - } - } -} - diff --git a/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs deleted file mode 100644 index f619a2b..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpClientHandler.cs +++ /dev/null @@ -1,31 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using System; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using JT808.Gateway.Services; -using JT808.Gateway.Client; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808客户端处理程序 - /// - internal class JT808TcpClientHandler : SimpleChannelInboundHandler - { - private readonly ILogger logger; - private readonly JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService; - public JT808TcpClientHandler(JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService,JT808TcpClient jT808TcpClient) - { - logger = jT808TcpClient.LoggerFactory.CreateLogger(); - this.jT808ReceiveAtomicCounterService= jT808ReceiveAtomicCounterService; - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) - { - if(logger.IsEnabled(LogLevel.Trace)) - logger.LogTrace("accept msg<<<" + ByteBufferUtil.HexDump(msg)); - jT808ReceiveAtomicCounterService.MsgSuccessIncrement(); - } - } -} diff --git a/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs deleted file mode 100644 index 36f7008..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpConnectionHandler.cs +++ /dev/null @@ -1,104 +0,0 @@ -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Channels; -using JT808.Gateway.Session; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808服务通道处理程序 - /// - internal class JT808TcpConnectionHandler : ChannelHandlerAdapter - { - private readonly ILogger logger; - - private readonly JT808SessionManager jT808SessionManager; - - public JT808TcpConnectionHandler( - JT808SessionManager jT808SessionManager, - ILoggerFactory loggerFactory) - { - this.jT808SessionManager = jT808SessionManager; - logger = loggerFactory.CreateLogger(); - } - - /// - /// 通道激活 - /// - /// - public override void ChannelActive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } Successful client connection to server."); - base.ChannelActive(context); - } - - /// - /// 设备主动断开 - /// - /// - public override void ChannelInactive(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($">>>{ channelId } The client disconnects from the server."); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - base.ChannelInactive(context); - } - - /// - /// 服务器主动断开 - /// - /// - /// - public override Task CloseAsync(IChannelHandlerContext context) - { - string channelId = context.Channel.Id.AsShortText(); - if (logger.IsEnabled(LogLevel.Debug)) - logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - return base.CloseAsync(context); - } - - public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); - - /// - /// 超时策略 - /// - /// - /// - public override void UserEventTriggered(IChannelHandlerContext context, object evt) - { - IdleStateEvent idleStateEvent = evt as IdleStateEvent; - if (idleStateEvent != null) - { - if(idleStateEvent.State== IdleState.ReaderIdle) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); - // 由于808是设备发心跳,如果很久没有上报数据,那么就由服务器主动关闭连接。 - jT808SessionManager.RemoveSessionByChannel(context.Channel); - context.CloseAsync(); - } - // 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: - // 1.消息的序列化 - // 2.消息的下发 - // 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle - // 就跟神兽貔貅一样。。。 - } - base.UserEventTriggered(context, evt); - } - - public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) - { - string channelId = context.Channel.Id.AsShortText(); - logger.LogError(exception,$"{channelId} {exception.Message}" ); - jT808SessionManager.RemoveSessionByChannel(context.Channel); - context.CloseAsync(); - } - } -} - diff --git a/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs b/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs deleted file mode 100644 index 35dda80..0000000 --- a/src/JT808.Gateway/Handlers/JT808TcpServerHandler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Protocol; -using System; -using Microsoft.Extensions.Logging; -using JT808.Protocol.Exceptions; -using JT808.Gateway.Session; -using JT808.Gateway.Services; -using JT808.Gateway.PubSub; -using JT808.Gateway.Enums; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808服务端处理程序 - /// - internal class JT808TcpServerHandler : SimpleChannelInboundHandler - { - private readonly JT808SessionManager jT808SessionManager; - - private readonly JT808AtomicCounterService jT808AtomicCounterService; - - private readonly ILogger logger; - - private readonly JT808Serializer JT808Serializer; - - private readonly IJT808MsgProducer JT808MsgProducer; - - public JT808TcpServerHandler( - IJT808MsgProducer jT808MsgProducer, - IJT808Config jT808Config, - ILoggerFactory loggerFactory, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - this.JT808MsgProducer = jT808MsgProducer; - this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - this.JT808Serializer = jT808Config.GetSerializer(); - logger = loggerFactory.CreateLogger(); - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) - { - try - { - //解析到头部,然后根据具体的消息Id通过队列去进行消费 - //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, - //解析具体的消息体,具体调用JT808Serializer.Deserialize - JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg); - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgSuccessCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - jT808AtomicCounterService.MsgSuccessIncrement(); - jT808SessionManager.TryAdd(jT808HeaderPackage.Header.TerminalPhoneNo,ctx.Channel); - JT808MsgProducer.ProduceAsync(jT808HeaderPackage.Header.TerminalPhoneNo, msg); - } - catch (JT808Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex,$"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - } - catch (Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); - } - } - } - } -} diff --git a/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs b/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs deleted file mode 100644 index 3ae3972..0000000 --- a/src/JT808.Gateway/Handlers/JT808UdpServerHandler.cs +++ /dev/null @@ -1,79 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Protocol; -using System; -using Microsoft.Extensions.Logging; -using JT808.Gateway.Services; -using JT808.Gateway.Session; -using JT808.Gateway.PubSub; -using JT808.Gateway.Metadata; -using JT808.Gateway.Enums; - -namespace JT808.Gateway.Handlers -{ - /// - /// JT808 Udp服务端处理程序 - /// - internal class JT808UdpServerHandler : SimpleChannelInboundHandler - { - private readonly JT808AtomicCounterService jT808AtomicCounterService; - - private readonly ILogger logger; - - private readonly JT808SessionManager jT808UdpSessionManager; - - private readonly JT808Serializer JT808Serializer; - - private readonly IJT808MsgProducer JT808MsgProducer; - - public JT808UdpServerHandler( - IJT808MsgProducer jT808MsgProducer, - IJT808Config jT808Config, - ILoggerFactory loggerFactory, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - JT808SessionManager jT808UdpSessionManager) - { - this.JT808MsgProducer = jT808MsgProducer; - this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - this.jT808UdpSessionManager = jT808UdpSessionManager; - logger = loggerFactory.CreateLogger(); - JT808Serializer = jT808Config.GetSerializer(); - } - - protected override void ChannelRead0(IChannelHandlerContext ctx, JT808UdpPackage msg) - { - try - { - //解析到头部,然后根据具体的消息Id通过队列去进行消费 - //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, - //解析具体的消息体,具体调用JT808Serializer.Deserialize - JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg.Buffer); - if (logger.IsEnabled(LogLevel.Trace)) - { - logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - jT808AtomicCounterService.MsgSuccessIncrement(); - jT808UdpSessionManager.TryAdd(ctx.Channel, msg.Sender, jT808HeaderPackage.Header.TerminalPhoneNo); - JT808MsgProducer.ProduceAsync(jT808HeaderPackage.Header.TerminalPhoneNo, msg.Buffer); - } - catch (JT808.Protocol.Exceptions.JT808Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - } - catch (Exception ex) - { - jT808AtomicCounterService.MsgFailIncrement(); - if (logger.IsEnabled(LogLevel.Error)) - { - logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); - } - } - } - - public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush(); - } -} diff --git a/src/JT808.Gateway/IJT808ClientBuilder.cs b/src/JT808.Gateway/IJT808ClientBuilder.cs deleted file mode 100644 index e8681b9..0000000 --- a/src/JT808.Gateway/IJT808ClientBuilder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway -{ - public interface IJT808ClientBuilder - { - IJT808Builder JT808Builder { get; } - IJT808Builder Builder(); - } -} diff --git a/src/JT808.Gateway/IJT808GatewayBuilder.cs b/src/JT808.Gateway/IJT808GatewayBuilder.cs deleted file mode 100644 index 6160c23..0000000 --- a/src/JT808.Gateway/IJT808GatewayBuilder.cs +++ /dev/null @@ -1,14 +0,0 @@ -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway -{ - public interface IJT808GatewayBuilder - { - IJT808Builder JT808Builder { get; } - IJT808Builder Builder(); - } -} diff --git a/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs b/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs deleted file mode 100644 index 12bf62b..0000000 --- a/src/JT808.Gateway/Impls/JT808DatagramPacketImpl.cs +++ /dev/null @@ -1,18 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Interfaces; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Impls -{ - class JT808DatagramPacketImpl : IJT808DatagramPacket - { - public DatagramPacket Create(byte[] message, EndPoint recipient) - { - return new DatagramPacket(Unpooled.WrappedBuffer(message), recipient); - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs b/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs deleted file mode 100644 index d5e79b5..0000000 --- a/src/JT808.Gateway/Impls/JT808GatewayBuilderDefault.cs +++ /dev/null @@ -1,25 +0,0 @@ -using JT808.Gateway; -using JT808.Protocol; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Impls -{ - internal class JT808GatewayBuilderDefault : IJT808GatewayBuilder - { - public IJT808Builder JT808Builder { get; } - - public JT808GatewayBuilderDefault(IJT808Builder builder) - { - JT808Builder = builder; - } - - public IJT808Builder Builder() - { - return JT808Builder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs deleted file mode 100644 index 6c68938..0000000 --- a/src/JT808.Gateway/Impls/JT808MsgProducerDefaultImpl.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808MsgProducerDefaultImpl : IJT808MsgProducer - { - private readonly JT808MsgService JT808MsgService; - public string TopicName => JT808GatewayConstants.MsgTopic; - public JT808MsgProducerDefaultImpl(JT808MsgService jT808MsgService) - { - JT808MsgService = jT808MsgService; - } - public void Dispose() - { - - } - - public Task ProduceAsync(string terminalNo, byte[] data) - { - JT808MsgService.MsgQueue.Add((terminalNo, data)); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs deleted file mode 100644 index ed86362..0000000 --- a/src/JT808.Gateway/Impls/JT808MsgReplyConsumerDefaultImpl.cs +++ /dev/null @@ -1,193 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using JT808.Protocol; -using JT808.Protocol.Enums; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808MsgReplyConsumerDefaultImpl : IJT808MsgReplyConsumer - { - private readonly JT808MsgService JT808MsgService; - private readonly JT808Serializer JT808Serializer; - private Dictionary> HandlerDict; - public JT808MsgReplyConsumerDefaultImpl( - IJT808Config jT808Config, - JT808MsgService jT808MsgService) - { - JT808MsgService = jT808MsgService; - this.JT808Serializer = jT808Config.GetSerializer(); - HandlerDict = new Dictionary> { - {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001}, - {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102}, - {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002}, - {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003}, - {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100}, - {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 }, - {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 }, - {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 } - }; - } - public CancellationTokenSource Cts =>new CancellationTokenSource(); - - public string TopicName => JT808GatewayConstants.MsgReplyTopic; - - public void Dispose() - { - Cts.Dispose(); - } - - public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) - { - Task.Run(() => - { - foreach(var item in JT808MsgService.MsgQueue.GetConsumingEnumerable()) - { - try - { - var package = JT808Serializer.HeaderDeserialize(item.Data); - if (HandlerDict.TryGetValue(package.Header.MsgId, out var func)) - { - var buffer = func(package); - if (buffer != null) - { - callback((item.TerminalNo, buffer)); - } - } - } - catch (Exception ex) - { - - } - } - }, Cts.Token); - } - - public void Subscribe() - { - - } - - public void Unsubscribe() - { - Cts.Cancel(); - } - - /// - /// 终端通用应答 - /// 平台无需回复 - /// 实现自己的业务 - /// - /// - /// - public byte[] Msg0x0001(JT808HeaderPackage request) - { - return null; - } - /// - /// 终端心跳 - /// - /// - /// - public byte[] Msg0x0002(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注销 - /// - /// - /// - public byte[] Msg0x0003(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端注册 - /// - /// - /// - public byte[] Msg0x0100(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100() - { - Code = "J" + request.Header.TerminalPhoneNo, - JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 终端鉴权 - /// - /// - /// - public byte[] Msg0x0102(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 位置信息汇报 - /// - /// - /// - public byte[] Msg0x0200(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 定位数据批量上传 - /// - /// - /// - public byte[] Msg0x0704(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - /// - /// 数据上行透传 - /// - /// - /// - public byte[] Msg0x0900(JT808HeaderPackage request) - { - return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() - { - MsgId = request.Header.MsgId, - JT808PlatformResult = JT808PlatformResult.成功, - MsgNum = request.Header.MsgNum - })); - } - } -} diff --git a/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs b/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs deleted file mode 100644 index 4651d85..0000000 --- a/src/JT808.Gateway/Impls/JT808SessionProducerDefaultImpl.cs +++ /dev/null @@ -1,32 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using System.Threading.Tasks; - -namespace JT808.Gateway.Impls -{ - internal class JT808SessionProducerDefaultImpl : IJT808SessionProducer - { - private readonly ILogger logger; - public JT808SessionProducerDefaultImpl(ILoggerFactory loggerFactory) - { - logger = loggerFactory.CreateLogger(); - } - - public string TopicName => JT808GatewayConstants.SessionTopic; - - public void Dispose() - { - - } - - public Task ProduceAsync(string terminalNo, string notice) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug($"{terminalNo}-{notice}"); - } - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs b/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs deleted file mode 100644 index dcfd9d0..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808DatagramPacket.cs +++ /dev/null @@ -1,13 +0,0 @@ -using DotNetty.Transport.Channels.Sockets; -using System.Net; - -namespace JT808.Gateway.Interfaces -{ - /// - /// 基于udp的创建发送包 - /// - public interface IJT808DatagramPacket - { - DatagramPacket Create(byte[] message, EndPoint recipient); - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808Reply.cs b/src/JT808.Gateway/Interfaces/IJT808Reply.cs deleted file mode 100644 index d515cd7..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808Reply.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - public interface IJT808Reply - { - JT808Package Package { get; set; } - byte[] HexData { get; set; } - /// - /// 根据实际情况适当调整包的大小 - /// - int MinBufferSize { get; set; } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808Session.cs b/src/JT808.Gateway/Interfaces/IJT808Session.cs deleted file mode 100644 index 80cae87..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808Session.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - public interface IJT808Session - { - /// - /// 终端手机号 - /// - string TerminalPhoneNo { get; set; } - IChannel Channel { get; set; } - DateTime LastActiveTime { get; set; } - DateTime StartTime { get; set; } - JT808TransportProtocolType TransportProtocolType { get; set; } - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808SessionService.cs b/src/JT808.Gateway/Interfaces/IJT808SessionService.cs deleted file mode 100644 index c8e58e5..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808SessionService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway.Dtos; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Interfaces -{ - /// - /// JT808会话服务 - /// - public interface IJT808SessionService - { - /// - /// 获取udp会话集合 - /// - /// - JT808ResultDto> GetUdpAll(); - /// - /// 获取tcp会话集合 - /// - /// - JT808ResultDto> GetTcpAll(); - /// - /// 通过设备终端号移除对应会话 - /// - /// - /// - JT808ResultDto RemoveByTerminalPhoneNo(string terminalPhoneNo); - } -} diff --git a/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs b/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs deleted file mode 100644 index 227e225..0000000 --- a/src/JT808.Gateway/Interfaces/IJT808UnificationSendService.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JT808.Gateway.Dtos; - -namespace JT808.Gateway.Interfaces -{ - /// - /// JT808统一下发命令服务 - /// - public interface IJT808UnificationSendService - { - JT808ResultDto Send(string terminalPhoneNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/JT808.Gateway.csproj b/src/JT808.Gateway/JT808.Gateway.csproj deleted file mode 100644 index ff7b4aa..0000000 --- a/src/JT808.Gateway/JT808.Gateway.csproj +++ /dev/null @@ -1,45 +0,0 @@ - - - - netstandard2.0 - 8.0 - Copyright 2018. - SmallChi(Koike) - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE - false - 1.0.0-preview1 - false - LICENSE - true - JT808.Gateway - JT808.Gateway - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - diff --git a/src/JT808.Gateway/JT808GatewayConstants.cs b/src/JT808.Gateway/JT808GatewayConstants.cs deleted file mode 100644 index b09709a..0000000 --- a/src/JT808.Gateway/JT808GatewayConstants.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace JT808.Gateway -{ - public static class JT808GatewayConstants - { - public const string SessionOnline= "JT808SessionOnline"; - - public const string SessionOffline = "JT808SessionOffline"; - public const string SessionTopic = "jt808session"; - public const string MsgTopic = "jt808msgdefault"; - public const string MsgReplyTopic = "jt808msgreplydefault"; - - public static class JT808WebApiRouteTable - { - public const string RouteTablePrefix = "/jt808api"; - - public const string SessionPrefix = "Session"; - - public const string TcpPrefix = "Tcp"; - - public const string UdpPrefix = "Udp"; - - /// - /// 基于Tcp的包计数器 - /// - public static string GetTcpAtomicCounter = $"{RouteTablePrefix}/{TcpPrefix}/GetAtomicCounter"; - /// - /// 基于Tcp的会话服务集合 - /// - public static string SessionTcpGetAll = $"{RouteTablePrefix}/{TcpPrefix}/{SessionPrefix}/GetAll"; - /// - /// 会话服务-通过设备终端号移除对应会话 - /// - public static string SessionRemoveByTerminalPhoneNo = $"{RouteTablePrefix}/{SessionPrefix}/RemoveByTerminalPhoneNo"; - /// - /// 统一下发信息 - /// - public static string UnificationSend = $"{RouteTablePrefix}/UnificationSend"; - /// - /// 获取Udp包计数器 - /// - public static string GetUdpAtomicCounter = $"{RouteTablePrefix}/{UdpPrefix}/GetAtomicCounter"; - /// - /// 基于Udp的会话服务集合 - /// - public static string SessionUdpGetAll = $"{RouteTablePrefix}/{UdpPrefix}/{SessionPrefix}/GetAll"; - } - } -} diff --git a/src/JT808.Gateway/JT808GatewayExtensions.cs b/src/JT808.Gateway/JT808GatewayExtensions.cs deleted file mode 100644 index 17ed1b0..0000000 --- a/src/JT808.Gateway/JT808GatewayExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using JT808.Gateway; -using JT808.Gateway.Configurations; -using JT808.Gateway.Impls; -using JT808.Gateway.Interfaces; -using JT808.Gateway.PubSub; -using JT808.Gateway.Services; -using JT808.Gateway.Session; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Options; -using System; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("JT808.Gateway.Test")] - -namespace JT808.Gateway -{ - public static class JT808GatewayExtensions - { - public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, IConfiguration configuration) - { - IJT808GatewayBuilder nettyBuilder = new JT808GatewayBuilderDefault(jt808Builder); - nettyBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808Configuration")); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.AddHostedService(); - return nettyBuilder; - } - - public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, Action jt808Options) - { - IJT808GatewayBuilder nettyBuilder = new JT808GatewayBuilderDefault(jt808Builder); - nettyBuilder.JT808Builder.Services.Configure(jt808Options); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.AddHostedService(); - return nettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs deleted file mode 100644 index 6362905..0000000 --- a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.Metadata -{ - /// - /// - /// - /// - internal class JT808AtomicCounter - { - long counter = 0; - - public JT808AtomicCounter(long initialCount = 0) - { - this.counter = initialCount; - } - - public void Reset() - { - Interlocked.Exchange(ref counter, 0); - } - - public long Increment() - { - return Interlocked.Increment(ref counter); - } - - public long Add(long len) - { - return Interlocked.Add(ref counter,len); - } - - public long Decrement() - { - return Interlocked.Decrement(ref counter); - } - - public long Count - { - get - { - return Interlocked.Read(ref counter); - } - } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808ClientReport.cs b/src/JT808.Gateway/Metadata/JT808ClientReport.cs deleted file mode 100644 index 6896252..0000000 --- a/src/JT808.Gateway/Metadata/JT808ClientReport.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Metadata -{ - public class JT808ClientReport - { - public long SendTotalCount { get; set; } - public long ReceiveTotalCount { get; set; } - public DateTime CurrentDate { get; set; } - public int Connections { get; set; } - public int OnlineConnections { get; set; } - public int OfflineConnections { get; set; } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808ClientRequest.cs b/src/JT808.Gateway/Metadata/JT808ClientRequest.cs deleted file mode 100644 index 9122dcd..0000000 --- a/src/JT808.Gateway/Metadata/JT808ClientRequest.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808ClientRequest - { - public JT808Package Package { get; } - - public byte[] HexData { get; } - - /// - /// 根据实际情况适当调整包的大小 - /// - public int MinBufferSize { get;} - - public JT808ClientRequest(JT808Package package,int minBufferSize=1024) - { - Package = package; - MinBufferSize = minBufferSize; - } - - public JT808ClientRequest(byte[] hexData) - { - HexData = hexData; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808HttpRequest.cs b/src/JT808.Gateway/Metadata/JT808HttpRequest.cs deleted file mode 100644 index 8c21e94..0000000 --- a/src/JT808.Gateway/Metadata/JT808HttpRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808HttpRequest - { - public string Json { get; set; } - - public JT808HttpRequest() - { - - } - - public JT808HttpRequest(string json) - { - Json = json; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808HttpResponse.cs b/src/JT808.Gateway/Metadata/JT808HttpResponse.cs deleted file mode 100644 index f018dcb..0000000 --- a/src/JT808.Gateway/Metadata/JT808HttpResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808HttpResponse - { - public byte[] Data { get; set; } - - public JT808HttpResponse() - { - - } - - public JT808HttpResponse(byte[] data) - { - this.Data = data; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808Request.cs b/src/JT808.Gateway/Metadata/JT808Request.cs deleted file mode 100644 index 5817ed8..0000000 --- a/src/JT808.Gateway/Metadata/JT808Request.cs +++ /dev/null @@ -1,23 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808Request - { - public JT808HeaderPackage Package { get; } - - /// - /// 用于消息发送 - /// - public byte[] OriginalPackage { get;} - - public JT808Request(JT808HeaderPackage package, byte[] originalPackage) - { - Package = package; - OriginalPackage = originalPackage; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808Response.cs b/src/JT808.Gateway/Metadata/JT808Response.cs deleted file mode 100644 index 5425f73..0000000 --- a/src/JT808.Gateway/Metadata/JT808Response.cs +++ /dev/null @@ -1,31 +0,0 @@ -using JT808.Gateway.Interfaces; -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace JT808.Gateway.Metadata -{ - public class JT808Response: IJT808Reply - { - public JT808Package Package { get; set; } - public byte[] HexData { get; set; } - public int MinBufferSize { get; set; } - - public JT808Response() - { - - } - - public JT808Response(JT808Package package, int minBufferSize = 1024) - { - Package = package; - MinBufferSize = minBufferSize; - } - - public JT808Response(byte[] hexData) - { - HexData = hexData; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Metadata/JT808TcpSession.cs b/src/JT808.Gateway/Metadata/JT808TcpSession.cs deleted file mode 100644 index dff9d78..0000000 --- a/src/JT808.Gateway/Metadata/JT808TcpSession.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using System; - -namespace JT808.Gateway.Metadata -{ - public class JT808TcpSession: IJT808Session - { - public JT808TcpSession(IChannel channel, string terminalPhoneNo) - { - Channel = channel; - TerminalPhoneNo = terminalPhoneNo; - StartTime = DateTime.Now; - LastActiveTime = DateTime.Now; - } - - public JT808TcpSession() { } - - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - - public IChannel Channel { get; set; } - - public DateTime LastActiveTime { get; set; } - - public DateTime StartTime { get; set; } - public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.tcp; - } -} diff --git a/src/JT808.Gateway/Metadata/JT808UdpPackage.cs b/src/JT808.Gateway/Metadata/JT808UdpPackage.cs deleted file mode 100644 index 3f7c4c1..0000000 --- a/src/JT808.Gateway/Metadata/JT808UdpPackage.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Metadata -{ - public class JT808UdpPackage - { - public JT808UdpPackage(byte[] buffer, EndPoint sender) - { - Buffer = buffer; - Sender = sender; - } - - public byte[] Buffer { get; } - - public EndPoint Sender { get; } - } -} diff --git a/src/JT808.Gateway/Metadata/JT808UdpSession.cs b/src/JT808.Gateway/Metadata/JT808UdpSession.cs deleted file mode 100644 index b0c60c5..0000000 --- a/src/JT808.Gateway/Metadata/JT808UdpSession.cs +++ /dev/null @@ -1,38 +0,0 @@ -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using System; -using System.Net; - -namespace JT808.Gateway.Metadata -{ - public class JT808UdpSession: IJT808Session - { - public JT808UdpSession(IChannel channel, - EndPoint sender, - string terminalPhoneNo) - { - Channel = channel; - TerminalPhoneNo = terminalPhoneNo; - StartTime = DateTime.Now; - LastActiveTime = DateTime.Now; - Sender = sender; - } - - public EndPoint Sender { get; set; } - - public JT808UdpSession() { } - - /// - /// 终端手机号 - /// - public string TerminalPhoneNo { get; set; } - - public IChannel Channel { get; set; } - - public DateTime LastActiveTime { get; set; } - - public DateTime StartTime { get; set; } - public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.udp; - } -} diff --git a/src/JT808.Gateway/Protos/JT808Gateway.proto b/src/JT808.Gateway/Protos/JT808Gateway.proto deleted file mode 100644 index 042fc89..0000000 --- a/src/JT808.Gateway/Protos/JT808Gateway.proto +++ /dev/null @@ -1,63 +0,0 @@ -syntax = "proto3"; - -option csharp_namespace = "JT808.Gateway.GrpcService"; - -package JT808GatewayGrpc; - -service JT808Gateway{ - // 会话服务-获取会话服务集合 - rpc GetTcpSessionAll(Empty) returns (TcpSessionInfoReply); - // 会话服务-通过设备终端号移除对应会话 - rpc RemoveSessionByTerminalPhoneNo(SessionRemoveRequest) returns (SessionRemoveReply); - // 统一下发信息 - rpc UnificationSend(UnificationSendRequest) returns (UnificationSendReply); - // 获取Tcp包计数器 - rpc GetTcpAtomicCounter(Empty) returns (TcpAtomicCounterReply); - // 会话服务-获取会话服务集合 - rpc GetUdpSessionAll(Empty) returns (UdpSessionInfoReply); - // 获取Udp包计数器 - rpc GetUdpAtomicCounter(Empty) returns (UdpAtomicCounterReply); -} - -message Empty{} - -message TcpSessionInfoReply{ - repeated SessionInfo TcpSessions=1; -} -message UdpSessionInfoReply{ - repeated SessionInfo UdpSessions=1; -} - -message SessionInfo{ - string StartTime=1; - string LastActiveTime=2; - string TerminalPhoneNo=3; - string RemoteAddressIP=4; -} - -message SessionRemoveRequest{ - string TerminalPhoneNo=1; -} - -message SessionRemoveReply{ - bool Success = 1; -} - -message UnificationSendRequest{ - string TerminalPhoneNo=1; - bytes Data=2; -} - -message UnificationSendReply{ - bool Success = 1; -} - -message TcpAtomicCounterReply{ - int64 MsgSuccessCount=1; - int64 MsgFailCount=2; -} - -message UdpAtomicCounterReply{ - int64 MsgSuccessCount=1; - int64 MsgFailCount=2; -} \ No newline at end of file diff --git a/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs b/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs deleted file mode 100644 index d247c8a..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgConsumer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs b/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs deleted file mode 100644 index 33cb252..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgProducer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgProducer : IJT808PubSub, IDisposable - { - /// - /// - /// - /// 设备终端号 - /// 808 hex data - Task ProduceAsync(string terminalNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs b/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs deleted file mode 100644 index 3bbe675..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgReplyConsumer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgReplyConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs b/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs deleted file mode 100644 index 99b7ae3..0000000 --- a/src/JT808.Gateway/PubSub/IJT808MsgReplyProducer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808MsgReplyProducer : IJT808PubSub, IDisposable - { - /// - /// - /// - /// 设备终端号 - /// 808 hex data - Task ProduceAsync(string terminalNo, byte[] data); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808PubSub.cs b/src/JT808.Gateway/PubSub/IJT808PubSub.cs deleted file mode 100644 index 983c205..0000000 --- a/src/JT808.Gateway/PubSub/IJT808PubSub.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.PubSub -{ - public interface IJT808PubSub - { - string TopicName { get; } - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs b/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs deleted file mode 100644 index eb3a03e..0000000 --- a/src/JT808.Gateway/PubSub/IJT808SessionConsumer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace JT808.Gateway.PubSub -{ - /// - /// 会话通知(在线/离线) - /// - public interface IJT808SessionConsumer : IJT808PubSub, IDisposable - { - void OnMessage(Action<(string Notice, string TerminalNo)> callback); - CancellationTokenSource Cts { get; } - void Subscribe(); - void Unsubscribe(); - } -} diff --git a/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs b/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs deleted file mode 100644 index 572cd75..0000000 --- a/src/JT808.Gateway/PubSub/IJT808SessionProducer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.PubSub -{ - /// - /// 会话通知(在线/离线) - /// - public interface IJT808SessionProducer : IJT808PubSub, IDisposable - { - Task ProduceAsync(string notice,string terminalNo); - } -} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs deleted file mode 100644 index cddd31f..0000000 --- a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 计数包服务 - /// - public class JT808AtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - private readonly JT808AtomicCounter MsgFailCounter; - - public JT808AtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - MsgFailCounter = new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - MsgFailCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - - public long MsgFailIncrement() - { - return MsgFailCounter.Increment(); - } - - public long MsgFailCount - { - get - { - return MsgFailCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs deleted file mode 100644 index 087ddcc..0000000 --- a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.Gateway.Enums; -using System; -using System.Collections.Concurrent; - -namespace JT808.Gateway.Services -{ - public class JT808AtomicCounterServiceFactory - { - private readonly ConcurrentDictionary cache; - - public JT808AtomicCounterServiceFactory() - { - cache = new ConcurrentDictionary(); - } - - public JT808AtomicCounterService Create(JT808TransportProtocolType type) - { - if(cache.TryGetValue(type,out var service)) - { - return service; - } - else - { - var serviceNew = new JT808AtomicCounterService(); - cache.TryAdd(type, serviceNew); - return serviceNew; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs b/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs deleted file mode 100644 index 1239084..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReceiveAtomicCounterService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 接收计数包服务 - /// - public class JT808ClientReceiveAtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - public JT808ClientReceiveAtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs b/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs deleted file mode 100644 index be63e82..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReportHostedService.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - public class JT808ClientReportHostedService : IHostedService - { - private readonly JT808ClientReportService jT808ReportService; - private CancellationTokenSource cts = new CancellationTokenSource(); - public JT808ClientReportHostedService(JT808ClientReportService jT808ReportService) - { - this.jT808ReportService = jT808ReportService; - } - public Task StartAsync(CancellationToken cancellationToken) - { - Task.Run(() => - { - while (!cts.IsCancellationRequested) - { - jT808ReportService.Create(); - Thread.Sleep(1000); - //Task.Delay(TimeSpan.FromSeconds(1), cts.Token); - } - }, cts.Token); - return Task.CompletedTask; - } - public Task StopAsync(CancellationToken cancellationToken) - { - cts.Cancel(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientReportService.cs b/src/JT808.Gateway/Services/JT808ClientReportService.cs deleted file mode 100644 index da27f8a..0000000 --- a/src/JT808.Gateway/Services/JT808ClientReportService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JT808.Gateway.Client; -using JT808.Gateway.Metadata; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace JT808.Gateway.Services -{ - public class JT808ClientReportService - { - private readonly JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService; - private readonly JT808ClientSendAtomicCounterService jT808SendAtomicCounterService; - private readonly IJT808TcpClientFactory jT808TcpClientFactory; - - public List JT808Reports { get; private set; } - - public JT808ClientReportService( - JT808ClientReceiveAtomicCounterService jT808ReceiveAtomicCounterService, - JT808ClientSendAtomicCounterService jT808SendAtomicCounterService, - IJT808TcpClientFactory jT808TcpClientFactory) - { - this.jT808ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService; - this.jT808SendAtomicCounterService = jT808SendAtomicCounterService; - this.jT808TcpClientFactory = jT808TcpClientFactory; - JT808Reports = new List(); - } - - public void Create() - { - var clients = jT808TcpClientFactory.GetAll(); - JT808Reports.Add(new JT808ClientReport() - { - SendTotalCount= jT808SendAtomicCounterService.MsgSuccessCount, - ReceiveTotalCount= jT808ReceiveAtomicCounterService.MsgSuccessCount, - CurrentDate=DateTime.Now, - Connections= clients.Count, - OnlineConnections= clients.Where(w => w.IsOpen).Count(), - OfflineConnections= clients.Where(w => !w.IsOpen).Count(), - }); - } - } -} diff --git a/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs b/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs deleted file mode 100644 index 62b12c4..0000000 --- a/src/JT808.Gateway/Services/JT808ClientSendAtomicCounterService.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JT808.Gateway.Metadata; - -namespace JT808.Gateway.Services -{ - /// - /// 发送计数包服务 - /// - public class JT808ClientSendAtomicCounterService - { - private readonly JT808AtomicCounter MsgSuccessCounter; - - public JT808ClientSendAtomicCounterService() - { - MsgSuccessCounter=new JT808AtomicCounter(); - } - - public void Reset() - { - MsgSuccessCounter.Reset(); - } - - public long MsgSuccessIncrement() - { - return MsgSuccessCounter.Increment(); - } - - public long MsgSuccessCount - { - get - { - return MsgSuccessCounter.Count; - } - } - } -} diff --git a/src/JT808.Gateway/Services/JT808GatewayService.cs b/src/JT808.Gateway/Services/JT808GatewayService.cs deleted file mode 100644 index 9a97d18..0000000 --- a/src/JT808.Gateway/Services/JT808GatewayService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using JT808.Gateway.Interfaces; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Gateway.Enums; -using JT808.Gateway.GrpcService; -using Grpc.Core; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - public class JT808GatewayService: JT808Gateway.JT808GatewayBase - { - private readonly JT808AtomicCounterService jT808TcpAtomicCounterService; - - private readonly JT808AtomicCounterService jT808UdpAtomicCounterService; - - private readonly IJT808SessionService jT808SessionService; - - private readonly IJT808UnificationSendService jT808UnificationSendService; - - public JT808GatewayService( - IJT808UnificationSendService jT808UnificationSendService, - IJT808SessionService jT808SessionService, - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory - ) - { - this.jT808UnificationSendService = jT808UnificationSendService; - this.jT808SessionService = jT808SessionService; - this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - } - - public override Task GetTcpSessionAll(Empty request, ServerCallContext context) - { - var result = jT808SessionService.GetTcpAll(); - TcpSessionInfoReply reply = new TcpSessionInfoReply(); - if (result.Data != null) - { - foreach (var item in result.Data) - { - reply.TcpSessions.Add(new SessionInfo - { - LastActiveTime = item.LastActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), - StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), - RemoteAddressIP = item.RemoteAddressIP, - TerminalPhoneNo = item.TerminalPhoneNo - }); - } - } - return Task.FromResult(reply); - } - - public override Task RemoveSessionByTerminalPhoneNo(SessionRemoveRequest request, ServerCallContext context) - { - var result = jT808SessionService.RemoveByTerminalPhoneNo(request.TerminalPhoneNo); - return Task.FromResult(new SessionRemoveReply { Success = result.Data }); - } - - public override Task GetUdpSessionAll(Empty request, ServerCallContext context) - { - var result = jT808SessionService.GetUdpAll(); - UdpSessionInfoReply reply = new UdpSessionInfoReply(); - if (result.Data != null) - { - foreach (var item in result.Data) - { - reply.UdpSessions.Add(new SessionInfo - { - LastActiveTime = item.LastActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), - StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), - RemoteAddressIP = item.RemoteAddressIP, - TerminalPhoneNo = item.TerminalPhoneNo - }); - } - } - return Task.FromResult(reply); - } - - public override Task UnificationSend(UnificationSendRequest request, ServerCallContext context) - { - var result = jT808UnificationSendService.Send(request.TerminalPhoneNo, request.Data.ToByteArray()); - return Task.FromResult(new UnificationSendReply { Success = result.Data }); - } - - public override Task GetTcpAtomicCounter(Empty request, ServerCallContext context) - { - TcpAtomicCounterReply reply = new TcpAtomicCounterReply(); - reply.MsgFailCount=jT808TcpAtomicCounterService.MsgFailCount; - reply.MsgSuccessCount=jT808TcpAtomicCounterService.MsgSuccessCount; - return Task.FromResult(reply); - } - - public override Task GetUdpAtomicCounter(Empty request, ServerCallContext context) - { - UdpAtomicCounterReply reply = new UdpAtomicCounterReply(); - reply.MsgFailCount = jT808UdpAtomicCounterService.MsgFailCount; - reply.MsgSuccessCount = jT808UdpAtomicCounterService.MsgSuccessCount; - return Task.FromResult(reply); - } - } -} diff --git a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs deleted file mode 100644 index ccb3030..0000000 --- a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using JT808.Gateway.PubSub; -using JT808.Gateway.Session; -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Services -{ - internal class JT808MsgReplyHostedService : IHostedService - { - private readonly JT808SessionManager JT808SessionManager; - - private readonly IJT808MsgReplyConsumer JT808MsgReplyConsumer; - - public JT808MsgReplyHostedService( - IJT808MsgReplyConsumer jT808MsgReplyConsumer, - JT808SessionManager jT808SessionManager) - { - JT808MsgReplyConsumer = jT808MsgReplyConsumer; - JT808SessionManager = jT808SessionManager; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - JT808MsgReplyConsumer.OnMessage(item => - { - JT808SessionManager.Send(item.TerminalNo, item.Data); - }); - JT808MsgReplyConsumer.Subscribe(); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - JT808MsgReplyConsumer.Unsubscribe(); - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808MsgService.cs b/src/JT808.Gateway/Services/JT808MsgService.cs deleted file mode 100644 index 68c1b96..0000000 --- a/src/JT808.Gateway/Services/JT808MsgService.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.Gateway.Services -{ - internal class JT808MsgService - { - public System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)> MsgQueue { get; set; } = new System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)>(); - } -} diff --git a/src/JT808.Gateway/Services/JT808SessionService.cs b/src/JT808.Gateway/Services/JT808SessionService.cs deleted file mode 100644 index f2ecb8c..0000000 --- a/src/JT808.Gateway/Services/JT808SessionService.cs +++ /dev/null @@ -1,98 +0,0 @@ -using JT808.Gateway.Dtos; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; -using System; -using System.Collections.Generic; -using System.Linq; - - -namespace JT808.Gateway.Services -{ - internal class JT808SessionService : IJT808SessionService - { - private readonly JT808SessionManager jT808SessionManager; - - public JT808SessionService( - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - } - - public JT808ResultDto> GetTcpAll() - { - JT808ResultDto> resultDto = new JT808ResultDto>(); - try - { - resultDto.Data = jT808SessionManager.GetAll().Select(s => new JT808TcpSessionInfoDto - { - LastActiveTime = s.LastActiveTime, - StartTime = s.StartTime, - TerminalPhoneNo = s.TerminalPhoneNo, - RemoteAddressIP = s.Channel.RemoteAddress.ToString(), - }).ToList(); - resultDto.Code = JT808ResultCode.Ok; - } - catch (Exception ex) - { - resultDto.Data = null; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message =ex.Message; - } - return resultDto; - } - - public JT808ResultDto> GetUdpAll() - { - JT808ResultDto> resultDto = new JT808ResultDto>(); - try - { - resultDto.Data = jT808SessionManager.GetUdpAll().Select(s => new JT808UdpSessionInfoDto - { - LastActiveTime = s.LastActiveTime, - StartTime = s.StartTime, - TerminalPhoneNo = s.TerminalPhoneNo, - RemoteAddressIP = s.Sender.ToString() - }).ToList(); - resultDto.Code = JT808ResultCode.Ok; - } - catch (Exception ex) - { - resultDto.Data = null; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - - public JT808ResultDto RemoveByTerminalPhoneNo(string terminalPhoneNo) - { - JT808ResultDto resultDto = new JT808ResultDto(); - try - { - var session = jT808SessionManager.RemoveSession(terminalPhoneNo); - if (session != null) - { - if(session.Channel.Open) - { - session.Channel.CloseAsync(); - } - } - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = true; - } - catch (AggregateException ex) - { - resultDto.Data = false; - resultDto.Code = 500; - resultDto.Message = ex.Message; - } - catch (Exception ex) - { - resultDto.Data = false; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - } -} diff --git a/src/JT808.Gateway/Services/JT808UnificationSendService.cs b/src/JT808.Gateway/Services/JT808UnificationSendService.cs deleted file mode 100644 index d7d54e3..0000000 --- a/src/JT808.Gateway/Services/JT808UnificationSendService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using JT808.Gateway.Dtos; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; -using System; - -namespace JT808.Gateway.Services -{ - internal class JT808UnificationSendService : IJT808UnificationSendService - { - private readonly JT808SessionManager jT808SessionManager; - - public JT808UnificationSendService( - JT808SessionManager jT808SessionManager) - { - this.jT808SessionManager = jT808SessionManager; - } - - public JT808ResultDto Send(string terminalPhoneNo, byte[] data) - { - JT808ResultDto resultDto = new JT808ResultDto(); - try - { - if(jT808SessionManager.TrySend(terminalPhoneNo, data, out var message)) - { - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = true; - resultDto.Message = message; - } - else - { - resultDto.Code = JT808ResultCode.Ok; - resultDto.Data = false; - resultDto.Message = message; - } - } - catch (Exception ex) - { - resultDto.Data = false; - resultDto.Code = JT808ResultCode.Error; - resultDto.Message = ex.Message; - } - return resultDto; - } - } -} diff --git a/src/JT808.Gateway/Session/JT808SessionManager.cs b/src/JT808.Gateway/Session/JT808SessionManager.cs deleted file mode 100644 index d5cf82f..0000000 --- a/src/JT808.Gateway/Session/JT808SessionManager.cs +++ /dev/null @@ -1,304 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Transport.Channels; -using JT808.Gateway.Enums; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Metadata; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; - -namespace JT808.Gateway.Session -{ - public class JT808SessionManager - { - private readonly ILogger logger; - - private readonly IJT808DatagramPacket jT808DatagramPacket; - public IJT808SessionProducer JT808SessionProducer { get; } - - public ConcurrentDictionary Sessions { get; } - - public JT808SessionManager( - IJT808SessionProducer jT808SessionProducer, - ILoggerFactory loggerFactory - ) - { - Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - JT808SessionProducer = jT808SessionProducer; - logger = loggerFactory.CreateLogger(); - } - - public JT808SessionManager( - IJT808SessionProducer jT808SessionProducer, - ILoggerFactory loggerFactory, - IJT808DatagramPacket jT808DatagramPacket) - { - Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - JT808SessionProducer = jT808SessionProducer; - logger = loggerFactory.CreateLogger(); - this.jT808DatagramPacket = jT808DatagramPacket; - } - - public int SessionCount - { - get - { - return Sessions.Count; - } - } - public IJT808Session GetSessionByTerminalPhoneNo(string terminalPhoneNo) - { - if (string.IsNullOrEmpty(terminalPhoneNo)) - return default; - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session targetSession)) - { - return targetSession; - } - else - { - return default; - } - } - public JT808TcpSession GetTcpSessionByTerminalPhoneNo(string terminalPhoneNo) - { - return (JT808TcpSession)GetSessionByTerminalPhoneNo(terminalPhoneNo); - } - public JT808UdpSession GetUdpSessionByTerminalPhoneNo(string terminalPhoneNo) - { - return (JT808UdpSession)GetSessionByTerminalPhoneNo(terminalPhoneNo); - } - public void Heartbeat(string terminalPhoneNo) - { - if (string.IsNullOrEmpty(terminalPhoneNo)) return; - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session oldjT808Session)) - { - oldjT808Session.LastActiveTime = DateTime.Now; - Sessions.TryUpdate(terminalPhoneNo, oldjT808Session, oldjT808Session); - } - } - public bool TrySend(string terminalPhoneNo, byte[] data, out string message) - { - bool isSuccessed; - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - //判断转发数据是下发不了消息的 - if (Sessions.Select(s => s.Value).Count(c => c.Channel.Id == session.Channel.Id) > 1) - { - isSuccessed = false; - message = "not support transmit data send."; - } - else - { - if(session.TransportProtocolType== JT808TransportProtocolType.tcp) - { - session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); - isSuccessed = true; - message = "ok"; - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(data, ((JT808UdpSession)session).Sender)); - } - else - { - isSuccessed = false; - message = "unknow type"; - } - } - } - else - { - isSuccessed = false; - message = "offline"; - } - return isSuccessed; - } - internal void Send(string terminalPhoneNo, byte[] data) - { - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - if (session.TransportProtocolType == JT808TransportProtocolType.tcp) - { - session.Channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(data, ((JT808UdpSession)session).Sender)); - } - } - } - public bool TrySend(string terminalPhoneNo, IJT808Reply reply, out string message) - { - bool isSuccessed; - var session = GetSessionByTerminalPhoneNo(terminalPhoneNo); - if (session != null) - { - //判断转发数据是下发不了消息的 - if (Sessions.Select(s => s.Value).Count(c => c.Channel.Id == session.Channel.Id) > 1) - { - isSuccessed = false; - message = "not support transmit data send."; - } - else - { - if (session.TransportProtocolType == JT808TransportProtocolType.tcp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(reply); - } - else if (session.TransportProtocolType == JT808TransportProtocolType.udp) - { - isSuccessed = true; - message = "ok"; - session.Channel.WriteAndFlushAsync(jT808DatagramPacket.Create(reply.HexData, ((JT808UdpSession)session).Sender)); - } - else - { - isSuccessed = false; - message = "unknow type"; - } - } - } - else - { - isSuccessed = false; - message = "offline"; - } - return isSuccessed; - } - public void TryAdd(string terminalPhoneNo, IChannel channel) - { - // 解决了设备号跟通道绑定到一起,不需要用到通道本身的SessionId - // 不管设备下发更改了设备终端号,只要是没有在内存中就当是新的 - // 存在的问题: - // 1.原先老的如何销毁 - // 2.这时候用的通道是相同的,设备终端是不同的 - // 当设备主动或者服务器断开以后,可以释放,这点内存忽略不计,况且更改设备号不是很频繁。 - - //修复第一次通过转发过来的数据,再次通过直连后通道没有改变导致下发不成功,所以每次进行通道的更新操作。 - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session oldJT808Session)) - { - oldJT808Session.LastActiveTime = DateTime.Now; - oldJT808Session.Channel = channel; - Sessions.TryUpdate(terminalPhoneNo, oldJT808Session, oldJT808Session); - } - else - { - JT808TcpSession jT808TcpSession = new JT808TcpSession(channel, terminalPhoneNo); - if (Sessions.TryAdd(terminalPhoneNo, jT808TcpSession)) - { - //使用场景: - //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, - //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 - //有设备关联上来可以进行通知 例如:使用Redis发布订阅 - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline,jT808TcpSession.TerminalPhoneNo); - } - } - } - public void TryAdd(IChannel channel, EndPoint sender, string terminalPhoneNo) - { - //1.先判断是否在缓存里面 - if (Sessions.TryGetValue(terminalPhoneNo, out IJT808Session jT808UdpSession)) - { - if(jT808UdpSession is JT808UdpSession convertSession) - { - convertSession.LastActiveTime = DateTime.Now; - convertSession.Sender = sender; - convertSession.Channel = channel; - Sessions.TryUpdate(terminalPhoneNo, convertSession, convertSession); - } - } - else - { - //添加缓存 - //使用场景: - //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, - //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 - //有设备关联上来可以进行通知 例如:使用Redis发布订阅 - Sessions.TryAdd(terminalPhoneNo, new JT808UdpSession(channel, sender, terminalPhoneNo)); - } - //移动是个大的内网,不跟随下发,根本就发不出来 - //移动很多卡,存储的那个socket地址端口,有效期非常短 - //不速度快点下发,那个socket地址端口就可能映射到别的对应卡去了 - //所以此处采用跟随设备消息下发指令 - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOnline,terminalPhoneNo); - } - public IJT808Session RemoveSession(string terminalPhoneNo) - { - //设备离线可以进行通知 - //使用Redis 发布订阅 - if (string.IsNullOrEmpty(terminalPhoneNo)) return default; - if (!Sessions.TryGetValue(terminalPhoneNo, out IJT808Session jT808Session)) - { - return default; - } - // 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据 - //1.用当前会话的通道Id找出通过转发过来的其他设备的终端号 - var terminalPhoneNos = Sessions.Where(w => w.Value.Channel.Id == jT808Session.Channel.Id).Select(s => s.Key).ToList(); - //2.存在则一个个移除 - if (terminalPhoneNos.Count > 1) - { - //3.移除包括当前的设备号 - foreach (var key in terminalPhoneNos) - { - Sessions.TryRemove(key, out IJT808Session jT808SessionRemove); - } - string nos = string.Join(",", terminalPhoneNos); - logger.LogInformation($">>>{terminalPhoneNo}-{nos} 1-n Session Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, nos); - return jT808Session; - } - else - { - if (Sessions.TryRemove(terminalPhoneNo, out IJT808Session jT808SessionRemove)) - { - logger.LogInformation($">>>{terminalPhoneNo} Session Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, terminalPhoneNo); - return jT808SessionRemove; - } - else - { - return default; - } - } - } - public void RemoveSessionByChannel(IChannel channel) - { - //设备离线可以进行通知 - //使用Redis 发布订阅 - var terminalPhoneNos = Sessions.Where(w => w.Value.Channel.Id == channel.Id).Select(s => s.Key).ToList(); - if (terminalPhoneNos.Count > 0) - { - foreach (var key in terminalPhoneNos) - { - Sessions.TryRemove(key, out IJT808Session jT808SessionRemove); - } - string nos = string.Join(",", terminalPhoneNos); - logger.LogInformation($">>>{nos} Channel Remove."); - JT808SessionProducer.ProduceAsync(JT808GatewayConstants.SessionOffline, nos); - } - } - public IEnumerable GetAll() - { - return Sessions.Select(s => s.Value).ToList(); - } - public IEnumerable GetTcpAll() - { - return Sessions.Select(s => (JT808TcpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.tcp).ToList(); - } - public IEnumerable GetUdpAll() - { - return Sessions.Select(s => (JT808UdpSession)s.Value).Where(w => w.TransportProtocolType == JT808TransportProtocolType.udp).ToList(); - } - } -} diff --git a/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs b/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs deleted file mode 100644 index 34102ed..0000000 --- a/src/JT808.Gateway/Simples/JT808SimpleTcpClient.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Simples -{ - internal class JT808SimpleTcpClient - { - private TcpClient tcpClient; - - public JT808SimpleTcpClient(IPEndPoint remoteAddress) - { - tcpClient = new TcpClient(); - tcpClient.Connect(remoteAddress); - Task.Run(()=> { - while (true) - { - try - { - byte[] buffer = new byte[100]; - tcpClient.GetStream().Read(buffer, 0, 100); - Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + string.Join(" ", buffer)); - - } - catch - { - - - } - Thread.Sleep(1000); - } - }); - } - - - - public void WriteAsync(byte[] data) - { - tcpClient.GetStream().WriteAsync(data, 0, data.Length); - } - - public void Down() - { - tcpClient.Close(); - } - } -} diff --git a/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs b/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs deleted file mode 100644 index 67c3111..0000000 --- a/src/JT808.Gateway/Simples/JT808SimpleUdpClient.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Simples -{ - internal class JT808SimpleUdpClient - { - private UdpClient udpClient; - - public JT808SimpleUdpClient(IPEndPoint remoteAddress) - { - udpClient = new UdpClient(); - udpClient.Connect(remoteAddress); - Task.Run(() => - { - while (true) - { - try - { - string tmp = string.Join(" ", udpClient.Receive(ref remoteAddress)); - Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + tmp); - Thread.Sleep(1000); - } - catch - { - - - } - Thread.Sleep(1000); - } - }); - } - - public void WriteAsync(byte[] data) - { - udpClient.SendAsync(data, data.Length); - } - - public void Down() - { - udpClient.Close(); - } - } -} diff --git a/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs b/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs deleted file mode 100644 index bf513eb..0000000 --- a/src/JT808.Gateway/Tcp/JT808TcpDotnettyExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System.Runtime.CompilerServices; - -namespace JT808.Gateway.Tcp -{ - public static class JT808TcpDotnettyExtensions - { - public static IJT808GatewayBuilder AddJT808GatewayTcpHost(this IJT808GatewayBuilder jT808NettyBuilder) - { - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - return jT808NettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs b/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs deleted file mode 100644 index 3134eaf..0000000 --- a/src/JT808.Gateway/Tcp/JT808TcpServerHost.cs +++ /dev/null @@ -1,95 +0,0 @@ -using DotNetty.Buffers; -using DotNetty.Codecs; -using DotNetty.Handlers.Timeout; -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Libuv; -using JT808.Gateway.Codecs; -using JT808.Gateway.Configurations; -using JT808.Gateway.Handlers; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Net; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Tcp -{ - /// - /// JT808 Tcp网关服务 - /// - internal class JT808TcpServerHost : IHostedService - { - private readonly IServiceProvider serviceProvider; - private readonly JT808Configuration configuration; - private readonly ILogger logger; - private DispatcherEventLoopGroup bossGroup; - private WorkerEventLoopGroup workerGroup; - private IChannel bootstrapChannel; - private IByteBufferAllocator serverBufferAllocator; - - public JT808TcpServerHost( - IServiceProvider provider, - ILoggerFactory loggerFactory, - IOptions jT808ConfigurationAccessor) - { - serviceProvider = provider; - configuration = jT808ConfigurationAccessor.Value; - logger=loggerFactory.CreateLogger(); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - bossGroup = new DispatcherEventLoopGroup(); - workerGroup = new WorkerEventLoopGroup(bossGroup, configuration.EventLoopCount); - serverBufferAllocator = new PooledByteBufferAllocator(); - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.Group(bossGroup, workerGroup); - bootstrap.Channel(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - bootstrap - .Option(ChannelOption.SoReuseport, true) - .ChildOption(ChannelOption.SoReuseaddr, true); - } - bootstrap - .Option(ChannelOption.SoBacklog, configuration.SoBacklog) - .ChildOption(ChannelOption.Allocator, serverBufferAllocator) - .ChildHandler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - using (var scope = serviceProvider.CreateScope()) - { - channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), - Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); - channel.Pipeline.AddLast("jt808TcpDecode", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("jt808TcpEncode", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler( - configuration.ReaderIdleTimeSeconds, - configuration.WriterIdleTimeSeconds, - configuration.AllIdleTimeSeconds)); - channel.Pipeline.AddLast("jt808TcpConnection", scope.ServiceProvider.GetRequiredService()); - channel.Pipeline.AddLast("jt808TcpService", scope.ServiceProvider.GetRequiredService()); - } - })); - logger.LogInformation($"JT808 TCP Server start at {IPAddress.Any}:{configuration.TcpPort}."); - return bootstrap.BindAsync(configuration.TcpPort) - .ContinueWith(i => bootstrapChannel = i.Result); - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - await bootstrapChannel.CloseAsync(); - var quietPeriod = configuration.QuietPeriodTimeSpan; - var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan; - await workerGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); - await bossGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); - } - } -} diff --git a/src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs b/src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs deleted file mode 100644 index 554eaf4..0000000 --- a/src/JT808.Gateway/Udp/JT808UdpDotnettyExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JT808.Gateway.Codecs; -using JT808.Gateway.Handlers; -using JT808.Gateway.Impls; -using JT808.Gateway.Interfaces; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System.Runtime.CompilerServices; - -namespace JT808.Gateway.Udp -{ - public static class JT808UdpDotnettyExtensions - { - public static IJT808GatewayBuilder AddJT808GatewayUdpHost(this IJT808GatewayBuilder jT808NettyBuilder) - { - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - return jT808NettyBuilder; - } - } -} \ No newline at end of file diff --git a/src/JT808.Gateway/Udp/JT808UdpServerHost.cs b/src/JT808.Gateway/Udp/JT808UdpServerHost.cs deleted file mode 100644 index 3e1636e..0000000 --- a/src/JT808.Gateway/Udp/JT808UdpServerHost.cs +++ /dev/null @@ -1,76 +0,0 @@ -using DotNetty.Transport.Bootstrapping; -using DotNetty.Transport.Channels; -using DotNetty.Transport.Channels.Sockets; -using JT808.Gateway.Codecs; -using JT808.Gateway.Configurations; -using JT808.Gateway.Handlers; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Net; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Udp -{ - /// - /// JT808 Udp网关服务 - /// - internal class JT808UdpServerHost : IHostedService - { - private readonly IServiceProvider serviceProvider; - private readonly JT808Configuration configuration; - private readonly ILogger logger; - private MultithreadEventLoopGroup group; - private IChannel bootstrapChannel; - - public JT808UdpServerHost( - IServiceProvider provider, - ILoggerFactory loggerFactory, - IOptions jT808ConfigurationAccessor) - { - serviceProvider = provider; - configuration = jT808ConfigurationAccessor.Value; - logger=loggerFactory.CreateLogger(); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - group = new MultithreadEventLoopGroup(); - Bootstrap bootstrap = new Bootstrap(); - bootstrap.Group(group); - bootstrap.Channel(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - bootstrap - .Option(ChannelOption.SoReuseport, true); - } - bootstrap - .Option(ChannelOption.SoBroadcast, true) - .Handler(new ActionChannelInitializer(channel => - { - IChannelPipeline pipeline = channel.Pipeline; - using (var scope = serviceProvider.CreateScope()) - { - pipeline.AddLast("jt808UdpDecoder", scope.ServiceProvider.GetRequiredService()); - pipeline.AddLast("jt808UdpService", scope.ServiceProvider.GetRequiredService()); - } - })); - logger.LogInformation($"JT808 Udp Server start at {IPAddress.Any}:{configuration.UdpPort}."); - return bootstrap.BindAsync(configuration.UdpPort) - .ContinueWith(i => bootstrapChannel = i.Result); - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - await bootstrapChannel.CloseAsync(); - var quietPeriod = configuration.QuietPeriodTimeSpan; - var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan; - await group.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); - } - } -} From cc3d52496a48c7f9f0c9c5bed3262ff496ed4077 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Wed, 18 Dec 2019 17:41:29 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JT808.Gateway.MsgIdHandler.Test.csproj | 24 ----- .../JT808DotNettyMsgIdHandlerDefaultImpl.cs | 44 --------- .../Program.cs | 39 -------- .../JT808.Gateway.MsgLogging.Test.csproj | 25 ----- .../JT808MsgLoggingImpl.cs | 52 ---------- .../JT808.Gateway.MsgLogging.Test/Program.cs | 43 --------- .../JT808.Gateway.ReplyMessage.Test.csproj | 25 ----- ...808DotNettyReplyMessageServiceInherited.cs | 48 ---------- .../Program.cs | 42 --------- .../JT808.Gateway.SessionNotice.Test.csproj | 24 ----- ...08DotNettySessionNoticeServiceInherited.cs | 41 -------- .../Program.cs | 41 -------- .../JT808.Gateway.Test.csproj | 32 ------- .../Tcp/JT808SessionServiceTest.cs | 94 ------------------- .../Tcp/JT808UnificationTcpSendServiceTest.cs | 75 --------------- .../JT808.Gateway.Test/Tcp/TestBase.cs | 43 --------- .../Udp/JT808SessionServiceTest.cs | 92 ------------------ .../Udp/JT808UnificationUdpSendServiceTest.cs | 76 --------------- .../JT808.Gateway.Test/Udp/TestBase.cs | 41 -------- .../JT808.Gateway.Traffic.Test.csproj | 24 ----- .../JT808DotNettyTrafficServiceTest.cs | 40 -------- .../JT808.Gateway.Traffic.Test/Program.cs | 44 --------- .../JT808.Gateway.Transmit.Test.csproj | 24 ----- .../JT808DotNettyTransmitServiceTest.cs | 35 ------- .../JT808.Gateway.Transmit.Test/Program.cs | 43 --------- 25 files changed, 1111 deletions(-) delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808.Gateway.MsgIdHandler.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808DotNettyMsgIdHandlerDefaultImpl.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/Program.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808.Gateway.MsgLogging.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808MsgLoggingImpl.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/Program.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808.Gateway.ReplyMessage.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808DotNettyReplyMessageServiceInherited.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/Program.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808.Gateway.SessionNotice.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808DotNettySessionNoticeServiceInherited.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/Program.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/JT808.Gateway.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808SessionServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808UnificationTcpSendServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/TestBase.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808SessionServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808UnificationUdpSendServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/TestBase.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808.Gateway.Traffic.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808DotNettyTrafficServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/Program.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808.Gateway.Transmit.Test.csproj delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808DotNettyTransmitServiceTest.cs delete mode 100644 src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/Program.cs diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808.Gateway.MsgIdHandler.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808.Gateway.MsgIdHandler.Test.csproj deleted file mode 100644 index 7c471ef..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808.Gateway.MsgIdHandler.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808DotNettyMsgIdHandlerDefaultImpl.cs b/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808DotNettyMsgIdHandlerDefaultImpl.cs deleted file mode 100644 index 58ad123..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/JT808DotNettyMsgIdHandlerDefaultImpl.cs +++ /dev/null @@ -1,44 +0,0 @@ -using JT808.Gateway.BusinessServices.MsgIdHandler; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol; -using JT808.Protocol.Extensions; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.MsgIdHandler.Test -{ - public class JT808DotNettyMsgIdHandlerDefaultImpl : IJT808MsgIdHandler - { - public readonly ILogger logger; - public JT808DotNettyMsgIdHandlerDefaultImpl(ILoggerFactory loggerFactory, - IServiceProvider serviceProvider) { - logger = loggerFactory.CreateLogger(); - Task.Run(()=> { - while (true) - { - Thread.Sleep(5000); - using (IJT808MsgProducer jT808MsgProducer = new JT808MsgProducer(new JT808MsgProducerConfig - { - BootstrapServers = "127.0.0.1:9092", - TopicName = "JT808Msg" - })) - { - jT808MsgProducer.ProduceAsync("123456", new byte[] { 0x7E, 0, 0x7E }).Wait(); - } - } - }); - } - - public void Processor((string TerminalNo, byte[] Data) parameter) - { - logger.LogDebug($"{parameter.TerminalNo}:{parameter.Data.ToHexString()}"); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/Program.cs deleted file mode 100644 index f96f9cd..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgIdHandler.Test/Program.cs +++ /dev/null @@ -1,39 +0,0 @@ -using JT808.Gateway.BusinessServices.MsgIdHandler; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.MsgIdHandler.Test -{ - class Program - { - async static Task Main(string[] args) - { - var serverHostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostingContext,config) => { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{ hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging(configLogging => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddMsgConsumer(hostContext.Configuration) - .AddJT808MsgIdHandler(); - }); - await serverHostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808.Gateway.MsgLogging.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808.Gateway.MsgLogging.Test.csproj deleted file mode 100644 index 13142a7..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808.Gateway.MsgLogging.Test.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808MsgLoggingImpl.cs b/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808MsgLoggingImpl.cs deleted file mode 100644 index 033b8f1..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/JT808MsgLoggingImpl.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JJT808.Gateway.Kafka; -using JT808.Gateway.BusinessServices.MsgLogging; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol.Extensions; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.MsgLogging.Test -{ - public class JT808MsgLoggingImpl : IJT808MsgLogging - { - public readonly ILogger logger; - public JT808MsgLoggingImpl(ILoggerFactory loggerFactory) { - logger = loggerFactory.CreateLogger(); - Task.Run(() => { - while (true) - { - Thread.Sleep(5000); - using (IJT808MsgProducer jT808MsgProducer = new JT808MsgProducer(new JT808MsgProducerConfig - { - BootstrapServers = "127.0.0.1:9092", - TopicName = "JT808Msg" - })) - { - jT808MsgProducer.ProduceAsync("123456", new byte[] { 0x7E, 0,0,0,0, 0x7E }).Wait(); - } - - JT808MsgReplyProducerConfig JT808MsgProducerConfig = new JT808MsgReplyProducerConfig - { - TopicName = "JT808MsgReply", - BootstrapServers = "127.0.0.1:9092", - }; - using (IJT808MsgReplyProducer jT808MsgProducer = new JT808MsgReplyProducer(JT808MsgProducerConfig)) - { - jT808MsgProducer.ProduceAsync("123456", new byte[] { 0x7E,1,1,1,1, 0x7E }).Wait(); - } - } - }); - } - - public void Processor((string TerminalNo, byte[] Data) parameter, JT808MsgLoggingType jT808MsgLoggingType) - { - logger.LogDebug($"{parameter.TerminalNo}:{parameter.Data.ToHexString()},方向:{jT808MsgLoggingType.ToString()}"); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/Program.cs deleted file mode 100644 index 482e60f..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.MsgLogging.Test/Program.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JT808.Gateway.BusinessServices.MsgLogging; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Console; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.MsgLogging.Test -{ - class Program - { - async static Task Main(string[] args) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostContext,config)=> { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddMsgConsumer(hostContext.Configuration) - .AddMsgReplyConsumer(hostContext.Configuration) - .AddJT808MsgLogging(); - }) - ; - - await hostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808.Gateway.ReplyMessage.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808.Gateway.ReplyMessage.Test.csproj deleted file mode 100644 index da55908..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808.Gateway.ReplyMessage.Test.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808DotNettyReplyMessageServiceInherited.cs b/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808DotNettyReplyMessageServiceInherited.cs deleted file mode 100644 index 4f400a8..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/JT808DotNettyReplyMessageServiceInherited.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using JT808.Gateway.BusinessServices.ReplyMessage; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol; -using JT808.Protocol.Extensions; -using Microsoft.Extensions.Logging; - -namespace JT808.Gateway.ReplyMessage.Test -{ - public class JT808DotNettyReplyMessageServiceInherited : JT808ReplyMessageService - { - public readonly ILogger logger; - - public JT808DotNettyReplyMessageServiceInherited(IJT808Config jT808Config, - IJT808MsgReplyProducer jT808MsgReplyProducer, - ILoggerFactory loggerFactory) - : base(jT808Config, jT808MsgReplyProducer) - { - logger = loggerFactory.CreateLogger(); - Task.Run(() => { - while (true) - { - Thread.Sleep(5000); - using (IJT808MsgProducer jT808MsgProducer = new JT808MsgProducer(new JT808MsgProducerConfig - { - BootstrapServers = "127.0.0.1:9092", - TopicName = "JT808Msg" - })) - { - jT808MsgProducer.ProduceAsync("011111111111", "7E02000032011111111111012E00000000000C00000160E42506C30C82002C00000000180914142057010400001DC003020000250400000000300115310100977E".ToHexBytes()).Wait(); - } - } - }); - } - - public override void Processor((string TerminalNo, byte[] Data) parameter) - { - logger.LogDebug($"{parameter.TerminalNo}:{parameter.Data.ToHexString()}"); - base.Processor(parameter); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/Program.cs deleted file mode 100644 index eafa6a0..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.ReplyMessage.Test/Program.cs +++ /dev/null @@ -1,42 +0,0 @@ -using JT808.Gateway.BusinessServices.ReplyMessage; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.ReplyMessage.Test -{ - class Program - { - async static Task Main(string[] args) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostContext, config) => { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddMsgConsumer(hostContext.Configuration) - .AddMsgReplyProducer(hostContext.Configuration) - .AddInprocJT808ReplyMessage(); - }) - ; - - await hostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808.Gateway.SessionNotice.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808.Gateway.SessionNotice.Test.csproj deleted file mode 100644 index c6b1507..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808.Gateway.SessionNotice.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808DotNettySessionNoticeServiceInherited.cs b/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808DotNettySessionNoticeServiceInherited.cs deleted file mode 100644 index 2c846c2..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/JT808DotNettySessionNoticeServiceInherited.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using JT808.Gateway.BusinessServices.SessionNotice; -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using Microsoft.Extensions.Logging; - -namespace JT808.Gateway.SessionNotice.Test -{ - public class JT808DotNettySessionNoticeServiceInherited : JT808SessionNoticeService - { - public JT808DotNettySessionNoticeServiceInherited(ILoggerFactory loggerFactory) : base(loggerFactory) - { - Task.Run(()=> { - while (true) - { - Thread.Sleep(5000); - JT808SessionProducerConfig JT808ProducerConfig = new JT808SessionProducerConfig - { - TopicName = "JT808Session", - BootstrapServers = "127.0.0.1:9092" - }; - using (IJT808SessionProducer jT808MsgProducer = new JT808SessionProducer(JT808ProducerConfig)) - { - jT808MsgProducer.ProduceAsync("online", "123456").Wait(); - jT808MsgProducer.ProduceAsync("offline", "123457").Wait(); - } - } - }); - } - - public override void Processor((string Notice, string TerminalNo) parameter) - { - base.Processor(parameter); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/Program.cs deleted file mode 100644 index 24196a6..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.SessionNotice.Test/Program.cs +++ /dev/null @@ -1,41 +0,0 @@ -using JT808.Gateway.BusinessServices.SessionNotice; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.SessionNotice.Test -{ - class Program - { - async static Task Main(string[] args) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostContext, config) => { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddSessionConsumer(hostContext.Configuration) - .AddInprocJT808SessionNotice(); - }) - ; - - await hostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/JT808.Gateway.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.Test/JT808.Gateway.Test.csproj deleted file mode 100644 index 7745168..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/JT808.Gateway.Test.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - netcoreapp3.0 - - false - - - - - - - - - - - - - - - - - - - Always - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808SessionServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808SessionServiceTest.cs deleted file mode 100644 index 0339c36..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808SessionServiceTest.cs +++ /dev/null @@ -1,94 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using JT808.Protocol.Extensions; -using Xunit; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; -using JT808.Gateway.Simples; - -namespace JT808.Gateway.Test.Tcp -{ - public class JT808SessionServiceTest:TestBase,IDisposable - { - static IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); - - JT808SimpleTcpClient SimpleTcpClient1; - JT808SimpleTcpClient SimpleTcpClient2; - JT808SimpleTcpClient SimpleTcpClient3; - JT808SimpleTcpClient SimpleTcpClient4; - JT808SimpleTcpClient SimpleTcpClient5; - - public JT808SessionServiceTest() - { - SimpleTcpClient1 = new JT808SimpleTcpClient(endPoint); - SimpleTcpClient2 = new JT808SimpleTcpClient(endPoint); - SimpleTcpClient3 = new JT808SimpleTcpClient(endPoint); - SimpleTcpClient4 = new JT808SimpleTcpClient(endPoint); - SimpleTcpClient5 = new JT808SimpleTcpClient(endPoint); - // 心跳会话包 - JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); - SimpleTcpClient1.WriteAsync(JT808Serializer.Serialize(jT808Package1)); - - // 心跳会话包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); - SimpleTcpClient2.WriteAsync(JT808Serializer.Serialize(jT808Package2)); - - // 心跳会话包 - JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); - SimpleTcpClient3.WriteAsync(JT808Serializer.Serialize(jT808Package3)); - - // 心跳会话包 - JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); - SimpleTcpClient4.WriteAsync(JT808Serializer.Serialize(jT808Package4)); - - // 心跳会话包 - JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); - SimpleTcpClient5.WriteAsync(JT808Serializer.Serialize(jT808Package5)); - Thread.Sleep(1000); - } - - public void Dispose() - { - SimpleTcpClient1.Down(); - SimpleTcpClient2.Down(); - SimpleTcpClient3.Down(); - SimpleTcpClient4.Down(); - SimpleTcpClient5.Down(); - } - - [Fact] - public void Test1() - { - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - var result = jT808SessionServiceDefaultImpl.GetTcpAll(); - Thread.Sleep(5000); - } - - [Fact] - public void Test2() - { - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - var result1 = jT808SessionServiceDefaultImpl.GetTcpAll(); - var result2 = jT808SessionServiceDefaultImpl.RemoveByTerminalPhoneNo("123456789001"); - var result3 = jT808SessionServiceDefaultImpl.GetTcpAll(); - } - - [Fact] - public void Test3() - { - // 判断通道是否关闭 - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - JT808SessionManager jT808TcpSessionManager = ServiceProvider.GetService(); - var result1 = jT808SessionServiceDefaultImpl.GetTcpAll(); - SimpleTcpClient1.Down(); - Thread.Sleep(5000); - var session = jT808TcpSessionManager.GetSessionByTerminalPhoneNo("123456789001"); - Thread.Sleep(100000); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808UnificationTcpSendServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808UnificationTcpSendServiceTest.cs deleted file mode 100644 index e5138a6..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/JT808UnificationTcpSendServiceTest.cs +++ /dev/null @@ -1,75 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Simples; -using Xunit; -using JT808.Gateway.Dtos; - -namespace JT808.Gateway.Test.Tcp -{ - public class JT808UnificationTcpSendServiceTest: TestBase - { - static IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6565); - - private IJT808UnificationSendService jT808UnificationSendService; - private IJT808SessionService jT808SessionServiceDefaultImpl; - - public JT808UnificationTcpSendServiceTest() - { - - JT808SimpleTcpClient SimpleTcpClient1 = new JT808SimpleTcpClient(endPoint); - JT808SimpleTcpClient SimpleTcpClient2 = new JT808SimpleTcpClient(endPoint); - JT808SimpleTcpClient SimpleTcpClient3 = new JT808SimpleTcpClient(endPoint); - JT808SimpleTcpClient SimpleTcpClient4 = new JT808SimpleTcpClient(endPoint); - JT808SimpleTcpClient SimpleTcpClient5 = new JT808SimpleTcpClient(endPoint); - // 心跳会话包 - JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); - SimpleTcpClient1.WriteAsync(JT808Serializer.Serialize(jT808Package1)); - - // 心跳会话包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); - SimpleTcpClient2.WriteAsync(JT808Serializer.Serialize(jT808Package2)); - - // 心跳会话包 - JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); - SimpleTcpClient3.WriteAsync(JT808Serializer.Serialize(jT808Package3)); - - // 心跳会话包 - JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); - SimpleTcpClient4.WriteAsync(JT808Serializer.Serialize(jT808Package4)); - - // 心跳会话包 - JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); - SimpleTcpClient5.WriteAsync(JT808Serializer.Serialize(jT808Package5)); - - Thread.Sleep(300); - } - - [Fact] - public void Test1() - { - jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - jT808UnificationSendService = ServiceProvider.GetService(); - jT808SessionServiceDefaultImpl.GetTcpAll(); - string no = "123456789001"; - // 文本信息包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.文本信息下发.Create(no, new JT808_0x8300 - { - TextFlag = 5, - TextInfo = "smallchi 518" - }); - var data = JT808Serializer.Serialize(jT808Package2); - JT808ResultDto jt808Result = jT808UnificationSendService.Send(no, data); - Thread.Sleep(1000); - Assert.Equal(200, jt808Result.Code); - Assert.True(jt808Result.Data); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/TestBase.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/TestBase.cs deleted file mode 100644 index 2f9716f..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Tcp/TestBase.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JT808.Gateway.Tcp; -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace JT808.Gateway.Test.Tcp -{ - public class TestBase - { - public static IServiceProvider ServiceProvider; - public static JT808Serializer JT808Serializer; - static TestBase() - { - var serverHostBuilder = new HostBuilder() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tcp")); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureServices((hostContext, services) => - { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Gateway(hostContext.Configuration) - .AddJT808GatewayTcpHost() - .Builder(); - //.Replace<>; - }); - var build = serverHostBuilder.Build(); - build.Start(); - ServiceProvider = build.Services; - JT808Serializer = ServiceProvider.GetRequiredService().GetSerializer(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808SessionServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808SessionServiceTest.cs deleted file mode 100644 index dedf7c4..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808SessionServiceTest.cs +++ /dev/null @@ -1,92 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using JT808.Protocol.Extensions; -using Xunit; -using JT808.Gateway.Simples; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Session; - -namespace JT808.Gateway.Test.Udp -{ - public class JT808SessionServiceTest:TestBase,IDisposable - { - static IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 818); - JT808SimpleUdpClient SimpleUdpClient1; - JT808SimpleUdpClient SimpleUdpClient2; - JT808SimpleUdpClient SimpleUdpClient3; - JT808SimpleUdpClient SimpleUdpClient4; - JT808SimpleUdpClient SimpleUdpClient5; - - public void Dispose() - { - SimpleUdpClient1.Down(); - SimpleUdpClient2.Down(); - SimpleUdpClient3.Down(); - SimpleUdpClient4.Down(); - SimpleUdpClient5.Down(); - } - - public JT808SessionServiceTest() - { - SimpleUdpClient1 = new JT808SimpleUdpClient(endPoint); - SimpleUdpClient2 = new JT808SimpleUdpClient(endPoint); - SimpleUdpClient3 = new JT808SimpleUdpClient(endPoint); - SimpleUdpClient4 = new JT808SimpleUdpClient(endPoint); - SimpleUdpClient5 = new JT808SimpleUdpClient(endPoint); - // 心跳会话包 - JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); - SimpleUdpClient1.WriteAsync(JT808Serializer.Serialize(jT808Package1)); - - // 心跳会话包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); - SimpleUdpClient2.WriteAsync(JT808Serializer.Serialize(jT808Package2)); - - // 心跳会话包 - JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); - SimpleUdpClient3.WriteAsync(JT808Serializer.Serialize(jT808Package3)); - - // 心跳会话包 - JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); - SimpleUdpClient4.WriteAsync(JT808Serializer.Serialize(jT808Package4)); - - // 心跳会话包 - JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); - SimpleUdpClient5.WriteAsync(JT808Serializer.Serialize(jT808Package5)); - Thread.Sleep(1000); - } - - [Fact] - public void Test1() - { - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - var result = jT808SessionServiceDefaultImpl.GetUdpAll(); - } - - [Fact] - public void Test2() - { - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - var result1 = jT808SessionServiceDefaultImpl.GetUdpAll(); - var result2 = jT808SessionServiceDefaultImpl.RemoveByTerminalPhoneNo("123456789001"); - var result3 = jT808SessionServiceDefaultImpl.GetUdpAll(); - } - - [Fact] - public void Test3() - { - // 判断通道是否关闭 - IJT808SessionService jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - JT808SessionManager jT808UdpSessionManager = ServiceProvider.GetService(); - var result1 = jT808SessionServiceDefaultImpl.GetUdpAll(); - SimpleUdpClient1.Down(); - var session = jT808UdpSessionManager.GetSessionByTerminalPhoneNo("123456789001"); - var result3 = jT808UdpSessionManager.GetUdpAll(); - Thread.Sleep(100000); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808UnificationUdpSendServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808UnificationUdpSendServiceTest.cs deleted file mode 100644 index 0f3cf87..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/JT808UnificationUdpSendServiceTest.cs +++ /dev/null @@ -1,76 +0,0 @@ -using JT808.Protocol; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Threading; -using Microsoft.Extensions.DependencyInjection; -using JT808.Protocol.Extensions; -using JT808.Protocol.MessageBody; -using JT808.Gateway.Interfaces; -using JT808.Gateway.Simples; -using JT808.Gateway.Dtos; -using Xunit; - -namespace JT808.Gateway.Test.Udp -{ - - public class JT808UnificationUdpSendServiceTest : TestBase - { - static IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 818); - - private IJT808UnificationSendService jT808UnificationSendService; - private IJT808SessionService jT808SessionServiceDefaultImpl; - - public JT808UnificationUdpSendServiceTest() - { - JT808SimpleUdpClient SimpleUdpClient1 = new JT808SimpleUdpClient(endPoint); - JT808SimpleUdpClient SimpleUdpClient2 = new JT808SimpleUdpClient(endPoint); - JT808SimpleUdpClient SimpleUdpClient3 = new JT808SimpleUdpClient(endPoint); - JT808SimpleUdpClient SimpleUdpClient4 = new JT808SimpleUdpClient(endPoint); - JT808SimpleUdpClient SimpleUdpClient5 = new JT808SimpleUdpClient(endPoint); - // 心跳会话包 - JT808Package jT808Package1 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789001"); - SimpleUdpClient1.WriteAsync(JT808Serializer.Serialize(jT808Package1)); - - // 心跳会话包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789002"); - SimpleUdpClient2.WriteAsync(JT808Serializer.Serialize(jT808Package2)); - - // 心跳会话包 - JT808Package jT808Package3 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789003"); - SimpleUdpClient3.WriteAsync(JT808Serializer.Serialize(jT808Package3)); - - // 心跳会话包 - JT808Package jT808Package4 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789004"); - SimpleUdpClient4.WriteAsync(JT808Serializer.Serialize(jT808Package4)); - - // 心跳会话包 - JT808Package jT808Package5 = JT808.Protocol.Enums.JT808MsgId.终端心跳.Create("123456789005"); - SimpleUdpClient5.WriteAsync(JT808Serializer.Serialize(jT808Package5)); - - Thread.Sleep(300); - } - - [Fact] - public void Test1() - { - //"126 131 0 0 13 18 52 86 120 144 1 0 11 5 115 109 97 108 108 99 104 105 32 53 49 56 24 126" - jT808SessionServiceDefaultImpl = ServiceProvider.GetService(); - jT808UnificationSendService = ServiceProvider.GetService(); - jT808SessionServiceDefaultImpl.GetUdpAll(); - string no = "123456789001"; - // 文本信息包 - JT808Package jT808Package2 = JT808.Protocol.Enums.JT808MsgId.文本信息下发.Create(no, new JT808_0x8300 - { - TextFlag = 5, - TextInfo = "smallchi 518" - }); - var data = JT808Serializer.Serialize(jT808Package2); - JT808ResultDto jt808Result = jT808UnificationSendService.Send(no, data); - Thread.Sleep(1000); - Assert.Equal(200, jt808Result.Code); - Assert.True(jt808Result.Data); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/TestBase.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/TestBase.cs deleted file mode 100644 index ecb1d9d..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Test/Udp/TestBase.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using JT808.Gateway.Udp; -using System.IO; - -namespace JT808.Gateway.Test.Udp -{ - public class TestBase - { - public static IServiceProvider ServiceProvider; - public static JT808Serializer JT808Serializer; - static TestBase() - { - var serverHostBuilder = new HostBuilder() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Udp")); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureServices((hostContext, services) => - { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddJT808Configure() - .AddJT808Gateway(hostContext.Configuration) - .AddJT808GatewayUdpHost(); - }); - var build = serverHostBuilder.Build(); - build.Start(); - ServiceProvider = build.Services; - JT808Serializer = ServiceProvider.GetRequiredService().GetSerializer(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808.Gateway.Traffic.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808.Gateway.Traffic.Test.csproj deleted file mode 100644 index c6b1507..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808.Gateway.Traffic.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808DotNettyTrafficServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808DotNettyTrafficServiceTest.cs deleted file mode 100644 index 741c65f..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/JT808DotNettyTrafficServiceTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol.Extensions; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Traffic.Test -{ - public class JT808DotNettyTrafficServiceTest - { - private readonly CSRedis.CSRedisClient redisClien; - public readonly ILogger logger; - public JT808DotNettyTrafficServiceTest(ILoggerFactory loggerFactory) { - redisClien = new CSRedis.CSRedisClient("127.0.0.1:6379,password=smallchi"); - RedisHelper.Initialization(redisClien); - logger = loggerFactory.CreateLogger(); - Task.Run(() => { - while (true) - { - Thread.Sleep(5000); - using (IJT808MsgProducer jT808MsgProducer = new JT808MsgProducer(new JT808MsgProducerConfig - { - BootstrapServers = "127.0.0.1:9092", - TopicName = "JT808Msg" - })) - { - jT808MsgProducer.ProduceAsync("011111111111", "7E02000032011111111111012E00000000000C00000160E42506C30C82002C00000000180914142057010400001DC003020000250400000000300115310100977E".ToHexBytes()).Wait(); - } - var length= RedisHelper.HGet("011111111111", DateTime.Now.ToString("yyyyMMdd")); - logger.LogDebug($"{011111111111}:{length}"); - } - }); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/Program.cs deleted file mode 100644 index 8a3f615..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Traffic.Test/Program.cs +++ /dev/null @@ -1,44 +0,0 @@ -using JT808.Gateway.BusinessServices.Traffic; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Traffic.Test -{ - class Program - { - async static Task Main(string[] args) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostContext, config) => { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddSingleton(); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddMsgConsumer(hostContext.Configuration) - .AddInprocJT808Traffic(); - - services.BuildServiceProvider().GetRequiredService(); - }) - ; - - await hostBuilder.RunConsoleAsync(); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808.Gateway.Transmit.Test.csproj b/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808.Gateway.Transmit.Test.csproj deleted file mode 100644 index 37cd0df..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808.Gateway.Transmit.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - netcoreapp3.0 - - - - - - - - - - - - - - - Always - - - - diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808DotNettyTransmitServiceTest.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808DotNettyTransmitServiceTest.cs deleted file mode 100644 index d91df89..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/JT808DotNettyTransmitServiceTest.cs +++ /dev/null @@ -1,35 +0,0 @@ -using JT808.Gateway.Configs.Kafka; -using JT808.Gateway.Kafka; -using JT808.Gateway.PubSub; -using JT808.Protocol.Extensions; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.Gateway.Transmit.Test -{ - public class JT808DotNettyTransmitServiceTest - { - public readonly ILogger logger; - public JT808DotNettyTransmitServiceTest(ILoggerFactory loggerFactory) { - logger = loggerFactory.CreateLogger(); - Task.Run(() => { - while (true) - { - Thread.Sleep(5000); - using (IJT808MsgProducer jT808MsgProducer = new JT808MsgProducer(new JT808MsgProducerConfig - { - BootstrapServers = "127.0.0.1:9092", - TopicName = "JT808Msg" - })) - { - jT808MsgProducer.ProduceAsync("011111111111", "7E02000032011111111111012E00000000000C00000160E42506C30C82002C00000000180914142057010400001DC003020000250400000000300115310100977E".ToHexBytes()).Wait(); - } - } - }); - } - } -} diff --git a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/Program.cs b/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/Program.cs deleted file mode 100644 index d188fb1..0000000 --- a/src/JT808.Gateway.Tests/JT808.Gateway.Transmit.Test/Program.cs +++ /dev/null @@ -1,43 +0,0 @@ -using JT808.Gateway.BusinessServices.Transmit; -using JT808.Gateway.Kafka; -using JT808.Protocol; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; - -namespace JT808.Gateway.Transmit.Test -{ - class Program - { - async static Task Main(string[] args) - { - var hostBuilder = new HostBuilder() - .UseEnvironment(args[0].Split('=')[1]) - .ConfigureAppConfiguration((hostContext, config) => { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); - }) - .ConfigureLogging((hostContext, configLogging) => { - configLogging.AddConsole(); - configLogging.SetMinimumLevel(LogLevel.Trace); - }) - .ConfigureServices((hostContext, services) => { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.AddSingleton(); - services.AddJT808Configure() - .AddJT808ClientKafka() - .AddMsgConsumer(hostContext.Configuration) - .AddInprocJT808Transmit(hostContext.Configuration); - services.BuildServiceProvider().GetRequiredService(); - }) - ; - - await hostBuilder.RunConsoleAsync(); - } - } -} From 15ddc833faee93ec6a1e80d16e5d880796fc86ab Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Wed, 18 Dec 2019 17:44:48 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E7=94=A8=E7=AE=80=E5=8D=95=E7=B2=97?= =?UTF-8?q?=E6=9A=B4=E7=9A=84=E6=96=B9=E5=BC=8F=E5=AE=9E=E7=8E=B0pipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +- src/.dockerignore | 25 + .../Enums/JT808TransportProtocolType.cs | 15 + .../IJT808ClientBuilder.cs | 14 + .../IJT808GatewayBuilder.cs | 14 + .../IJT808MsgConsumer.cs | 15 + .../IJT808MsgProducer.cs | 17 + .../IJT808MsgReplyConsumer.cs | 15 + .../IJT808MsgReplyProducer.cs | 17 + .../IJT808PubSub.cs | 11 + .../IJT808SessionConsumer.cs | 18 + .../IJT808SessionProducer.cs | 13 + .../JT808.Gateway.Abstractions.csproj | 33 + .../JT808GatewayConstants.cs | 11 + .../Protos/JT808Gateway.proto | 63 + .../JT808.Gateway.Test.csproj | 28 + src/JT808.Gateway.Test/PipeTest.cs | 100 + .../Session/JT808SessionManagerTest.cs | 187 + .../Configs/NLog.xsd | 3106 +++++++++++++++++ .../Configs/nlog.Unix.config | 36 + .../Configs/nlog.Win32NT.config | 36 + src/JT808.Gateway.TestHosting/Dockerfile | 23 + .../JT808.Gateway.TestHosting.csproj | 35 + .../Jobs/CallGrpcClientJob.cs | 69 + src/JT808.Gateway.TestHosting/Program.cs | 46 + src/JT808.Gateway.TestHosting/startup.txt | 4 + src/JT808.Gateway.sln | 43 + .../Configurations/JT808Configuration.cs | 43 + .../Enums/JT808MessageQueueType.cs | 18 + src/JT808.Gateway/Interfaces/IJT808Session.cs | 26 + .../Internal/JT808GatewayBuilderDefault.cs | 20 + .../Internal/JT808MsgProducerDefault.cs | 28 + .../Internal/JT808MsgReplyConsumerDefault.cs | 201 ++ src/JT808.Gateway/Internal/JT808MsgService.cs | 11 + src/JT808.Gateway/JT808.Gateway.csproj | 31 + src/JT808.Gateway/JT808GatewayExtensions.cs | 75 + src/JT808.Gateway/JT808GrpcServer.cs | 54 + src/JT808.Gateway/JT808TcpServer.cs | 226 ++ src/JT808.Gateway/JT808UdpServer.cs | 134 + .../Metadata/JT808AtomicCounter.cs | 49 + .../Services/JT808AtomicCounterService.cs | 52 + .../JT808AtomicCounterServiceFactory.cs | 30 + .../Services/JT808GatewayService.cs | 144 + .../Services/JT808MsgReplyHostedService.cs | 52 + .../JT808TcpReceiveTimeoutHostedService.cs | 58 + .../JT808UdpReceiveTimeoutHostedService.cs | 63 + .../Session/JT808SessionManager.cs | 224 ++ src/JT808.Gateway/Session/JT808TcpSession.cs | 47 + src/JT808.Gateway/Session/JT808UdpSession.cs | 41 + 49 files changed, 5625 insertions(+), 3 deletions(-) create mode 100644 src/.dockerignore create mode 100644 src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808PubSub.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs create mode 100644 src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs create mode 100644 src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj create mode 100644 src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs create mode 100644 src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto create mode 100644 src/JT808.Gateway.Test/JT808.Gateway.Test.csproj create mode 100644 src/JT808.Gateway.Test/PipeTest.cs create mode 100644 src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs create mode 100644 src/JT808.Gateway.TestHosting/Configs/NLog.xsd create mode 100644 src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config create mode 100644 src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config create mode 100644 src/JT808.Gateway.TestHosting/Dockerfile create mode 100644 src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj create mode 100644 src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs create mode 100644 src/JT808.Gateway.TestHosting/Program.cs create mode 100644 src/JT808.Gateway.TestHosting/startup.txt create mode 100644 src/JT808.Gateway.sln create mode 100644 src/JT808.Gateway/Configurations/JT808Configuration.cs create mode 100644 src/JT808.Gateway/Enums/JT808MessageQueueType.cs create mode 100644 src/JT808.Gateway/Interfaces/IJT808Session.cs create mode 100644 src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs create mode 100644 src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs create mode 100644 src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs create mode 100644 src/JT808.Gateway/Internal/JT808MsgService.cs create mode 100644 src/JT808.Gateway/JT808.Gateway.csproj create mode 100644 src/JT808.Gateway/JT808GatewayExtensions.cs create mode 100644 src/JT808.Gateway/JT808GrpcServer.cs create mode 100644 src/JT808.Gateway/JT808TcpServer.cs create mode 100644 src/JT808.Gateway/JT808UdpServer.cs create mode 100644 src/JT808.Gateway/Metadata/JT808AtomicCounter.cs create mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterService.cs create mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs create mode 100644 src/JT808.Gateway/Services/JT808GatewayService.cs create mode 100644 src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs create mode 100644 src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs create mode 100644 src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs create mode 100644 src/JT808.Gateway/Session/JT808SessionManager.cs create mode 100644 src/JT808.Gateway/Session/JT808TcpSession.cs create mode 100644 src/JT808.Gateway/Session/JT808UdpSession.cs diff --git a/README.md b/README.md index 62abed7..e7a5fcb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ 基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理 -基于Pipeline封装的JT808DotNetty支持TCP/UDP通用消息业务处理 +基于Pipeline封装的JT808Pipeline支持TCP/UDP通用消息业务处理 [了解JT808协议进这边](https://github.com/SmallChi/JT808) @@ -81,6 +81,7 @@ | Package Name | Version | Downloads | | --------------------- | -------------------------------------------------- | --------------------------------------------------- | +| Install-Package JT808.Gateway.Abstractions| ![JT808.Gateway.Abstractions](https://img.shields.io/nuget/v/JT808.Gateway.Abstractions.svg) | ![JT808.Gateway.Abstractions](https://img.shields.io/nuget/dt/JT808.Gateway.Abstractions.svg) | | Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) | | Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) | @@ -133,7 +134,7 @@ static async Task Main(string[] args) ``` 如图所示: -![demo1](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo1.png) +![demo1](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/demo1.png) ## 举个栗子2 @@ -144,4 +145,4 @@ static async Task Main(string[] args) 3.进入JT808.DotNetty.SimpleClient项目下的Debug目录运行客户端 如图所示: -![demo2](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo2.png) \ No newline at end of file +![demo2](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/demo2.png) diff --git a/src/.dockerignore b/src/.dockerignore new file mode 100644 index 0000000..3729ff0 --- /dev/null +++ b/src/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs b/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs new file mode 100644 index 0000000..4924be1 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Abstractions.Enums +{ + /// + /// 传输协议类型 + /// + public enum JT808TransportProtocolType + { + tcp=1, + udp = 2 + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs b/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs new file mode 100644 index 0000000..9574094 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs @@ -0,0 +1,14 @@ +using JT808.Protocol; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808ClientBuilder + { + IJT808Builder JT808Builder { get; } + IJT808Builder Builder(); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs b/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs new file mode 100644 index 0000000..72f6bbd --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs @@ -0,0 +1,14 @@ +using JT808.Protocol; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808GatewayBuilder + { + IJT808Builder JT808Builder { get; } + IJT808Builder Builder(); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs new file mode 100644 index 0000000..1e38db3 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808MsgConsumer : IJT808PubSub, IDisposable + { + void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); + CancellationTokenSource Cts { get; } + void Subscribe(); + void Unsubscribe(); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs new file mode 100644 index 0000000..1962f55 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808MsgProducer : IJT808PubSub, IDisposable + { + /// + /// + /// + /// 设备终端号 + /// 808 hex data + ValueTask ProduceAsync(string terminalNo, byte[] data); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs new file mode 100644 index 0000000..3b5acb5 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808MsgReplyConsumer : IJT808PubSub, IDisposable + { + void OnMessage(Action<(string TerminalNo, byte[] Data)> callback); + CancellationTokenSource Cts { get; } + void Subscribe(); + void Unsubscribe(); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs new file mode 100644 index 0000000..39f0366 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808MsgReplyProducer : IJT808PubSub, IDisposable + { + /// + /// + /// + /// 设备终端号 + /// 808 hex data + ValueTask ProduceAsync(string terminalNo, byte[] data); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808PubSub.cs b/src/JT808.Gateway.Abstractions/IJT808PubSub.cs new file mode 100644 index 0000000..7b1a327 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808PubSub.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Abstractions +{ + public interface IJT808PubSub + { + string TopicName { get; } + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs new file mode 100644 index 0000000..78f405f --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JT808.Gateway.Abstractions +{ + /// + /// 会话通知(在线/离线) + /// + public interface IJT808SessionConsumer : IJT808PubSub, IDisposable + { + void OnMessage(Action<(string Notice, string TerminalNo)> callback); + CancellationTokenSource Cts { get; } + void Subscribe(); + void Unsubscribe(); + } +} diff --git a/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs b/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs new file mode 100644 index 0000000..cecae48 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace JT808.Gateway.Abstractions +{ + /// + /// 会话通知(在线/离线) + /// + public interface IJT808SessionProducer : IJT808PubSub, IDisposable + { + ValueTask ProduceAsync(string notice,string terminalNo); + } +} diff --git a/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj b/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj new file mode 100644 index 0000000..de3eb76 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj @@ -0,0 +1,33 @@ + + + netstandard2.1 + 8.0 + Copyright 2019. + SmallChi(Koike) + false + false + LICENSE + true + 基于Pipeline实现的JT808Gateway的抽象库 + 基于Pipeline实现的JT808Gateway的抽象库 + JT808.Gateway.Abstractions + JT808.Gateway.Abstractions + 1.0.0-preview2 + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs b/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs new file mode 100644 index 0000000..6c631de --- /dev/null +++ b/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs @@ -0,0 +1,11 @@ +namespace JT808.Gateway.Abstractions +{ + public static class JT808GatewayConstants + { + public const string SessionOnline= "JT808SessionOnline"; + public const string SessionOffline = "JT808SessionOffline"; + public const string SessionTopic = "jt808session"; + public const string MsgTopic = "jt808msgdefault"; + public const string MsgReplyTopic = "jt808msgreplydefault"; + } +} diff --git a/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto b/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto new file mode 100644 index 0000000..042fc89 --- /dev/null +++ b/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +option csharp_namespace = "JT808.Gateway.GrpcService"; + +package JT808GatewayGrpc; + +service JT808Gateway{ + // 会话服务-获取会话服务集合 + rpc GetTcpSessionAll(Empty) returns (TcpSessionInfoReply); + // 会话服务-通过设备终端号移除对应会话 + rpc RemoveSessionByTerminalPhoneNo(SessionRemoveRequest) returns (SessionRemoveReply); + // 统一下发信息 + rpc UnificationSend(UnificationSendRequest) returns (UnificationSendReply); + // 获取Tcp包计数器 + rpc GetTcpAtomicCounter(Empty) returns (TcpAtomicCounterReply); + // 会话服务-获取会话服务集合 + rpc GetUdpSessionAll(Empty) returns (UdpSessionInfoReply); + // 获取Udp包计数器 + rpc GetUdpAtomicCounter(Empty) returns (UdpAtomicCounterReply); +} + +message Empty{} + +message TcpSessionInfoReply{ + repeated SessionInfo TcpSessions=1; +} +message UdpSessionInfoReply{ + repeated SessionInfo UdpSessions=1; +} + +message SessionInfo{ + string StartTime=1; + string LastActiveTime=2; + string TerminalPhoneNo=3; + string RemoteAddressIP=4; +} + +message SessionRemoveRequest{ + string TerminalPhoneNo=1; +} + +message SessionRemoveReply{ + bool Success = 1; +} + +message UnificationSendRequest{ + string TerminalPhoneNo=1; + bytes Data=2; +} + +message UnificationSendReply{ + bool Success = 1; +} + +message TcpAtomicCounterReply{ + int64 MsgSuccessCount=1; + int64 MsgFailCount=2; +} + +message UdpAtomicCounterReply{ + int64 MsgSuccessCount=1; + int64 MsgFailCount=2; +} \ No newline at end of file diff --git a/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj b/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj new file mode 100644 index 0000000..e07a52b --- /dev/null +++ b/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj @@ -0,0 +1,28 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/src/JT808.Gateway.Test/PipeTest.cs b/src/JT808.Gateway.Test/PipeTest.cs new file mode 100644 index 0000000..470de6d --- /dev/null +++ b/src/JT808.Gateway.Test/PipeTest.cs @@ -0,0 +1,100 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace JT808.Gateway.Test +{ + public class PipeTest + { + [Fact] + public void Test1() + { + var reader = new ReadOnlySequence(new byte[] { 0x7E, 0, 1, 2, 0x7E}); + SequenceReader seqReader = new SequenceReader(reader); + int index = 0; + byte mark = 0; + long totalConsumed = 0; + List packages = new List(); + while (!seqReader.End) + { + if (seqReader.IsNext(0x7E, advancePast: true)) + { + if (mark == 1) + { + var package = seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).ToArray(); + packages.Add(package); + totalConsumed += (seqReader.Consumed - totalConsumed); + index++; + if (seqReader.End) break; + seqReader.Advance(1); + mark = 0; + } + mark++; + } + else + { + seqReader.Advance(1); + } + index++; + } + Assert.Equal(5, index); + Assert.Single(packages); + Assert.Equal(5, seqReader.Consumed); + } + + [Fact] + public void Test2() + { + var reader = new ReadOnlySequence(new byte[] { 0x7E, 0, 1, 2, 0x7E, 0x7E, 0, 1, 0x7E, 0x7E, 2, 2, 2 }); + SequenceReader seqReader = new SequenceReader(reader); + int index = 0; + byte mark = 0; + long totalConsumed = 0; + List packages = new List(); + while (!seqReader.End) + { + if (seqReader.IsNext(0x7E, advancePast: true)) + { + if (mark == 1) + { + var package = seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).ToArray(); + packages.Add(package); + totalConsumed += (seqReader.Consumed - totalConsumed); + index++; + if (seqReader.End) break; + seqReader.Advance(1); + mark = 0; + } + mark++; + } + else + { + seqReader.Advance(1); + } + index++; + } + Assert.Equal(13, index); + Assert.Equal(2,packages.Count); + Assert.Equal(9, totalConsumed); + Assert.Equal(13, seqReader.Consumed); + } + + [Fact] + public void Test3() + { + Assert.Throws(() => + { + var reader = new ReadOnlySequence(new byte[] { 0, 1, 2, 0x7E }); + SequenceReader seqReader = new SequenceReader(reader); + if (seqReader.TryPeek(out byte beginMark)) + { + if (beginMark != 0x7E) throw new ArgumentException("not 808 packages"); + } + }); + } + } +} diff --git a/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs b/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs new file mode 100644 index 0000000..6c2eabd --- /dev/null +++ b/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs @@ -0,0 +1,187 @@ +using JT808.Gateway.Session; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; +using Microsoft.Extensions.Logging; +using System.Net.Sockets; + +namespace JT808.Gateway.Test.Session +{ + public class JT808SessionManagerTest + { + [Fact] + public void TryAddTest() + { + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var result=jT808SessionManager.TryAdd(new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp))); + Assert.True(result); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + } + + [Fact] + public void TryLinkTest() + { + string tno = "123456"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + jT808SessionManager.TryLink(tno, session); + Assert.True(result1); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno)); + } + + /// + /// 用于转发过来的车辆 + /// + [Fact] + public void TryLinkTest1_1_N() + { + string tno1 = "123456"; + string tno2 = "123457"; + string tno3 = "123458"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + jT808SessionManager.TryLink(tno1, session); + jT808SessionManager.TryLink(tno2, session); + jT808SessionManager.TryLink(tno3, session); + Assert.True(result1); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + Assert.Equal(3,jT808SessionManager.TerminalPhoneNoSessions.Count); + jT808SessionManager.RemoveBySessionId(session.SessionID); + Assert.Equal(0, jT808SessionManager.TotalSessionCount); + Assert.Empty(jT808SessionManager.TerminalPhoneNoSessions); + } + + /// + /// 用于转发过来的车辆 + /// + [Fact] + public void TryLinkTest2_1_N() + { + string tno1 = "123456"; + string tno2 = "123457"; + string tno3 = "123458"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + jT808SessionManager.TryLink(tno1, session); + jT808SessionManager.TryLink(tno2, session); + jT808SessionManager.TryLink(tno3, session); + Assert.True(result1); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count); + jT808SessionManager.RemoveByTerminalPhoneNo(tno1); + Assert.Equal(0, jT808SessionManager.TotalSessionCount); + Assert.Empty(jT808SessionManager.TerminalPhoneNoSessions); + } + + /// + /// 转发过来的车辆切换为直连车辆 + /// + [Fact] + public void UpdateLinkTest2_1_N() + { + string tno1 = "123456"; + string tno2 = "123457"; + string tno3 = "123458"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session1 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var session2 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session1); + var result2 = jT808SessionManager.TryAdd(session2); + //转发车辆 + jT808SessionManager.TryLink(tno1, session1); + jT808SessionManager.TryLink(tno2, session1); + //直连车辆 + jT808SessionManager.TryLink(tno3, session2); + + Assert.True(result1); + Assert.True(result2); + Assert.Equal(2, jT808SessionManager.TotalSessionCount); + Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count); + + //将tno2切换为直连车辆 + var session3 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result3 = jT808SessionManager.TryAdd(session3); + jT808SessionManager.TryLink(tno2, session3); + Assert.True(result3); + if (jT808SessionManager.TerminalPhoneNoSessions.TryGetValue(tno2,out string sessionid)) + { + //实际的通道Id + Assert.Equal(session3.SessionID, sessionid); + } + Assert.Equal(3, jT808SessionManager.TotalSessionCount); + Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count); + + jT808SessionManager.RemoveByTerminalPhoneNo(tno1); + Assert.Equal(2, jT808SessionManager.TotalSessionCount); + Assert.Equal(2,jT808SessionManager.TerminalPhoneNoSessions.Count); + } + + [Fact] + public void RemoveBySessionIdTest() + { + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + Assert.True(result1); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + jT808SessionManager.RemoveBySessionId(session.SessionID); + Assert.Equal(0, jT808SessionManager.TotalSessionCount); + } + + [Fact] + public void RemoveByTerminalPhoneNoTest() + { + string tno = "123456"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + jT808SessionManager.TryLink(tno, session); + Assert.True(result1); + Assert.Equal(1, jT808SessionManager.TotalSessionCount); + jT808SessionManager.RemoveByTerminalPhoneNo(tno); + Assert.False(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno)); + Assert.Equal(0, jT808SessionManager.TotalSessionCount); + } + + [Fact] + public void SendTest() + { + Assert.Throws(() => + { + string tno = "123456"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session); + jT808SessionManager.TryLink(tno, session); + jT808SessionManager.TrySendByTerminalPhoneNo(tno, new byte[] { 0x7e, 0, 0, 0x7e }); + }); + } + + [Fact] + public void GetTcpAllTest() + { + string tno1 = "123456"; + string tno2 = "123457"; + JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory()); + var session1 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var session2 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)); + var result1 = jT808SessionManager.TryAdd(session1); + var result2 = jT808SessionManager.TryAdd(session2); + jT808SessionManager.TryLink(tno1, session1); + jT808SessionManager.TryLink(tno2, session2); + Assert.True(result1); + Assert.True(result2); + Assert.Equal(2, jT808SessionManager.TotalSessionCount); + Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno1)); + Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno2)); + var sessions = jT808SessionManager.GetTcpAll(); + Assert.Equal(session1.SessionID, sessions[0].SessionID); + Assert.Equal(session2.SessionID, sessions[1].SessionID); + } + } +} diff --git a/src/JT808.Gateway.TestHosting/Configs/NLog.xsd b/src/JT808.Gateway.TestHosting/Configs/NLog.xsd new file mode 100644 index 0000000..2f57d09 --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Configs/NLog.xsd @@ -0,0 +1,3106 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged.. + + + + + Throw an exception when there is an internal error. Default value is: false. + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name* + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable or disable logging rule. Disabled rules are ignored. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Time in milliseconds to sleep between batches. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + Action to take if the buffer overflows. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Encoding to be used. + + + + + Instance of that is used to format log messages. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Maximum current connections. 0 = no maximum. + + + + + Indicates whether to keep connection open whenever possible. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + Network address. + + + + + Maximum queue size. + + + + + NDC item separator. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include stack contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Option to include all properties from the log events + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + Layout that should be use to calcuate the value for the parameter. + + + + + Viewer parameter name. + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to use default row highlighting rules. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the . + + + + + Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the . + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Name of the database provider. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + Layout that should be use to calcuate the value for the parameter. + + + + + Database parameter name. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Database parameter size. + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the option. + + + + + Optional entrytype. When not set, or when not convertable to then determined by + + + + + Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API + + + + + Message length limit to write to the Event Log. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + File encoding. + + + + + Line ending mode. + + + + + Way file archives are numbered. + + + + + Name of the file to be used for an archive. + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Maximum number of archive files that should be kept. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the an absolute or relative path? + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Is the an absolute or relative path? + + + + + Value indicationg whether file creation calls should be synchronized by a system global mutex. + + + + + Maximum number of log filenames that should be stored as existing. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Name of the file to write to. + + + + + Value specifying the date format to use when archiving files. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to create directories if they do not exist. + + + + + File attributes (Windows only). + + + + + Indicates whether to delete old log file on startup. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the number of messages. + + + + + Maximum allowed number of messages written per . + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Endpoint address. + + + + + Name of the endpoint configuration in WCF configuration file. + + + + + Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) + + + + + Client ID. + + + + + Indicates whether to include per-event properties in the payload sent to the server. + + + + + Indicates whether to use binary message encoding. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Name of the parameter. + + + + + Type of the parameter. + + + + + Type of the parameter. Obsolete alias for + + + + + Parameter can combine multiple LogEvents into a single parameter value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Encoding to be used for sending e-mail. + + + + + Indicates whether to add new lines between log entries. + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Indicates the SMTP client timeout. + + + + + Priority used for sending mails. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Specifies how outgoing email messages will be handled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Network address. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + Indicates whether to keep connection open whenever possible. + + + + + Maximum current connections. 0 = no maximum. + + + + + Maximum queue size. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Encoding to be used. + + + + + Instance of that is used to format log messages. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Maximum current connections. 0 = no maximum. + + + + + Indicates whether to keep connection open whenever possible. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + Network address. + + + + + Maximum queue size. + + + + + NDC item separator. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include stack contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Option to include all properties from the log events + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether performance counter should be automatically created. + + + + + Name of the performance counter category. + + + + + Counter help text. + + + + + Name of the performance counter. + + + + + Performance counter type. + + + + + The value by which to increment the counter. + + + + + Performance counter instance name. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Always use independent of + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Encoding. + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Web service method name. Only used with Soap. + + + + + Web service namespace. Only used with Soap. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) + + + + + Protocol to be used when calling web service. + + + + + Web service URL. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layout of the column. + + + + + Name of the column. + + + + + + + + + + + + + + + + + + List of property names to exclude when is true + + + + + Option to include all properties from the log events + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + Determines wether or not this attribute will be Json encoded. + + + + + Indicates whether to escape non-ascii characters + + + + + Layout that will be rendered as the attribute's value. + + + + + Name of the attribute. + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include contents of the stack. + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Layout to be used to filter log messages. + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Append FilterCount to the when an event is no longer filtered + + + + + Insert FilterCount value into when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Max number of unique filter values to expect simultaneously + + + + + Max length of filter values, will truncate if above limit + + + + + Default buffer size for the internal buffers + + + + + Reuse internal buffers, and doesn't have to constantly allocate new buffers + + + + + How long before a filter expires, and logging is accepted again + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config b/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config new file mode 100644 index 0000000..8e74617 --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config b/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config new file mode 100644 index 0000000..5a7e44e --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/JT808.Gateway.TestHosting/Dockerfile b/src/JT808.Gateway.TestHosting/Dockerfile new file mode 100644 index 0000000..6a33faf --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Dockerfile @@ -0,0 +1,23 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base +EXPOSE 808/tcp +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +WORKDIR /src +COPY ["JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj", "JT808.Gateway.TestHosting/"] +COPY ["JT808.Gateway/JT808.Gateway.csproj", "JT808.Gateway/"] +COPY ["JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj", "JT808.Gateway.Abstractions/"] +RUN dotnet restore "JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj" +COPY . . +WORKDIR "/src/JT808.Gateway.TestHosting" +RUN dotnet build "JT808.Gateway.TestHosting.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "JT808.Gateway.TestHosting.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "JT808.Gateway.TestHosting.dll"] \ No newline at end of file diff --git a/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj b/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj new file mode 100644 index 0000000..8d084b2 --- /dev/null +++ b/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj @@ -0,0 +1,35 @@ + + + + Exe + netcoreapp3.1 + Linux + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs b/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs new file mode 100644 index 0000000..c233069 --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using JT808.Gateway.Configurations; +using JT808.Gateway.GrpcService; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.Text.Json; + +namespace JT808.Gateway.TestHosting.Jobs +{ + public class CallGrpcClientJob :IHostedService + { + private Channel channel; + private readonly ILogger Logger; + private Grpc.Core.Metadata AuthMetadata; + public CallGrpcClientJob( + ILoggerFactory loggerFactory, + JT808Configuration configuration) + { + Logger = loggerFactory.CreateLogger("CallGrpcClientJob"); + channel = new Channel($"{configuration.WebApiHost}:{configuration.WebApiPort}", + ChannelCredentials.Insecure); + AuthMetadata = new Grpc.Core.Metadata(); + AuthMetadata.Add("token", configuration.WebApiToken); + } + + public Task StartAsync(CancellationToken cancellationToken) + { + Task.Run(() => + { + while (!cancellationToken.IsCancellationRequested) + { + JT808Gateway.JT808GatewayClient jT808GatewayClient = new JT808Gateway.JT808GatewayClient(channel); + try + { + var result1 = jT808GatewayClient.GetTcpAtomicCounter(new Empty(), AuthMetadata); + var result2 = jT808GatewayClient.GetTcpSessionAll(new Empty(), AuthMetadata); + Logger.LogInformation($"[GetTcpAtomicCounter]:{JsonSerializer.Serialize(result1)}"); + Logger.LogInformation($"[GetTcpSessionAll]:{JsonSerializer.Serialize(result2)}"); + } + catch (Exception ex) + { + Logger.LogError(ex, "Call Grpc Error"); + } + try + { + var result1 = jT808GatewayClient.GetTcpAtomicCounter(new Empty()); + } + catch (RpcException ex) + { + Logger.LogError($"{ex.StatusCode.ToString()}-{ex.Message}"); + } + Thread.Sleep(3000); + } + }, cancellationToken); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + channel.ShutdownAsync(); + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.Gateway.TestHosting/Program.cs b/src/JT808.Gateway.TestHosting/Program.cs new file mode 100644 index 0000000..7d8573e --- /dev/null +++ b/src/JT808.Gateway.TestHosting/Program.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using JT808.Protocol; +using Microsoft.Extensions.Configuration; +using NLog.Extensions.Logging; +using JT808.Gateway.TestHosting.Jobs; + +namespace JT808.Gateway.TestHosting +{ + class Program + { + static async Task Main(string[] args) + { + var serverHostBuilder = new HostBuilder() + .ConfigureAppConfiguration((hostingContext, config) => + { + config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile($"appsettings.{ hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true); + }) + .ConfigureLogging((context, logging) => + { + Console.WriteLine($"Environment.OSVersion.Platform:{Environment.OSVersion.Platform.ToString()}"); + NLog.LogManager.LoadConfiguration($"Configs/nlog.{Environment.OSVersion.Platform.ToString()}.config"); + logging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true }); + logging.SetMinimumLevel(LogLevel.Trace); + }) + .ConfigureServices((hostContext, services) => + { + services.AddSingleton(); + services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); + services.AddJT808Configure() + .AddJT808Gateway() + .AddTcp() + .AddUdp() + .AddGrpc(); + //services.AddHostedService(); + }); + + await serverHostBuilder.RunConsoleAsync(); + } + } +} diff --git a/src/JT808.Gateway.TestHosting/startup.txt b/src/JT808.Gateway.TestHosting/startup.txt new file mode 100644 index 0000000..0a51e3b --- /dev/null +++ b/src/JT808.Gateway.TestHosting/startup.txt @@ -0,0 +1,4 @@ +pm2 start "dotnet JT808.DotNetty.CleintBenchmark.dll ASPNETCORE_ENVIRONMENT=Production" --max-restarts=1 -n "JT808.DotNetty.CleintBenchmark" -o "/data/pm2Logs/JT808.DotNetty.CleintBenchmark/out.log" -e "/data/pm2Logs/JT808.DotNetty.CleintBenchmark/error.log" + + +pm2 start "dotnet JT808.Gateway.TestHosting.dll ASPNETCORE_ENVIRONMENT=Production" --max-restarts=1 -n "JT808.Gateway.808" -o "/data/pm2Logs/JT808.Gateway/out.log" -e "/data/pm2Logs/JT808.Gateway/error.log" \ No newline at end of file diff --git a/src/JT808.Gateway.sln b/src/JT808.Gateway.sln new file mode 100644 index 0000000..3719e74 --- /dev/null +++ b/src/JT808.Gateway.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29409.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway", "JT808.Gateway\JT808.Gateway.csproj", "{4C8A2546-8333-416D-B123-91062B630087}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.TestHosting", "JT808.Gateway.TestHosting\JT808.Gateway.TestHosting.csproj", "{AE40AFE0-0950-442C-A74C-10CDF53E9F36}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Test", "JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Abstractions", "JT808.Gateway.Abstractions\JT808.Gateway.Abstractions.csproj", "{3AA17DF7-A1B3-449C-93C2-45B051C32933}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4C8A2546-8333-416D-B123-91062B630087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C8A2546-8333-416D-B123-91062B630087}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C8A2546-8333-416D-B123-91062B630087}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C8A2546-8333-416D-B123-91062B630087}.Release|Any CPU.Build.0 = Release|Any CPU + {AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.Build.0 = Release|Any CPU + {28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.Build.0 = Release|Any CPU + {3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AA17DF7-A1B3-449C-93C2-45B051C32933}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AA17DF7-A1B3-449C-93C2-45B051C32933}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AA9303A7-6FB3-4572-88AA-3302E85330D1} + EndGlobalSection +EndGlobal diff --git a/src/JT808.Gateway/Configurations/JT808Configuration.cs b/src/JT808.Gateway/Configurations/JT808Configuration.cs new file mode 100644 index 0000000..c6d3edd --- /dev/null +++ b/src/JT808.Gateway/Configurations/JT808Configuration.cs @@ -0,0 +1,43 @@ +using JT808.Gateway.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Configurations +{ + public class JT808Configuration + { + public int TcpPort { get; set; } = 808; + public int UdpPort { get; set; } = 808; + public int WebApiPort { get; set; } = 828; + public string WebApiHost{ get; set; } = "localhost"; + /// + /// WebApi 默认token 123456 + /// + public string WebApiToken { get; set; } = "123456"; + public int SoBacklog { get; set; } = 8192; + public int MiniNumBufferSize { get; set; } = 8096; + /// + /// Tcp读超时 + /// 默认10分钟检查一次 + /// + public int TcpReaderIdleTimeSeconds { get; set; } = 60*10; + /// + /// Tcp 60s检查一次 + /// + public int TcpReceiveTimeoutCheckTimeSeconds { get; set; } = 60; + /// + /// Udp读超时 + /// + public int UdpReaderIdleTimeSeconds { get; set; } = 60; + /// + /// Udp 60s检查一次 + /// + public int UdpReceiveTimeoutCheckTimeSeconds { get; set; } = 60; + /// + /// 队列类型 + /// 默认内存队列 + /// + public JT808MessageQueueType MessageQueueType { get; set; } = JT808MessageQueueType.InMemory; + } +} diff --git a/src/JT808.Gateway/Enums/JT808MessageQueueType.cs b/src/JT808.Gateway/Enums/JT808MessageQueueType.cs new file mode 100644 index 0000000..a83f6a0 --- /dev/null +++ b/src/JT808.Gateway/Enums/JT808MessageQueueType.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Enums +{ + public enum JT808MessageQueueType:byte + { + /// + /// 使用内存队列 + /// + InMemory=1, + /// + /// 使用第三方队列 + /// + InPlug=2 + } +} diff --git a/src/JT808.Gateway/Interfaces/IJT808Session.cs b/src/JT808.Gateway/Interfaces/IJT808Session.cs new file mode 100644 index 0000000..14e1b0d --- /dev/null +++ b/src/JT808.Gateway/Interfaces/IJT808Session.cs @@ -0,0 +1,26 @@ +using JT808.Gateway.Abstractions.Enums; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace JT808.Gateway.Interfaces +{ + public interface IJT808Session + { + /// + /// 终端手机号 + /// + string TerminalPhoneNo { get; set; } + string SessionID { get; } + Socket Client { get; set; } + DateTime StartTime { get; set; } + DateTime ActiveTime { get; set; } + JT808TransportProtocolType TransportProtocolType { get;} + CancellationTokenSource ReceiveTimeout { get; set; } + EndPoint RemoteEndPoint { get; set; } + void Close(); + } +} diff --git a/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs b/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs new file mode 100644 index 0000000..1ef7110 --- /dev/null +++ b/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs @@ -0,0 +1,20 @@ +using JT808.Gateway.Abstractions; +using JT808.Protocol; + +namespace JT808.Gateway.Internal +{ + public class JT808GatewayBuilderDefault : IJT808GatewayBuilder + { + public IJT808Builder JT808Builder { get; } + + public JT808GatewayBuilderDefault(IJT808Builder builder) + { + JT808Builder = builder; + } + + public IJT808Builder Builder() + { + return JT808Builder; + } + } +} \ No newline at end of file diff --git a/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs b/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs new file mode 100644 index 0000000..610dd97 --- /dev/null +++ b/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs @@ -0,0 +1,28 @@ +using JT808.Gateway.Abstractions; +using JT808.Gateway.Internal; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace JT808.Gateway.Internal +{ + internal class JT808MsgProducerDefault : IJT808MsgProducer + { + private readonly JT808MsgService JT808MsgService; + public string TopicName => JT808GatewayConstants.MsgTopic; + public JT808MsgProducerDefault(JT808MsgService jT808MsgService) + { + JT808MsgService = jT808MsgService; + } + public void Dispose() + { + + } + public ValueTask ProduceAsync(string terminalNo, byte[] data) + { + JT808MsgService.MsgQueue.Add((terminalNo, data)); + return default; + } + } +} diff --git a/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs b/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs new file mode 100644 index 0000000..4276be3 --- /dev/null +++ b/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs @@ -0,0 +1,201 @@ +using JT808.Gateway.Abstractions; +using JT808.Protocol; +using JT808.Protocol.Enums; +using JT808.Protocol.Extensions; +using JT808.Protocol.MessageBody; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JT808.Gateway.Internal +{ + internal class JT808MsgReplyConsumerDefault : IJT808MsgReplyConsumer + { + private readonly JT808MsgService JT808MsgService; + + private readonly JT808Serializer JT808Serializer; + + private delegate byte[] MethodDelegate(JT808HeaderPackage headerPackage); + + private Dictionary HandlerDict; + public JT808MsgReplyConsumerDefault( + IJT808Config jT808Config, + JT808MsgService jT808MsgService) + { + JT808MsgService = jT808MsgService; + this.JT808Serializer = jT808Config.GetSerializer(); + HandlerDict = new Dictionary { + {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001}, + {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102}, + {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002}, + {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003}, + {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100}, + {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 }, + {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 }, + {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 } + }; + } + public CancellationTokenSource Cts =>new CancellationTokenSource(); + + public string TopicName => JT808GatewayConstants.MsgReplyTopic; + + public void Dispose() + { + Cts.Dispose(); + } + + public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback) + { + Task.Run(() => + { + foreach(var item in JT808MsgService.MsgQueue.GetConsumingEnumerable()) + { + try + { + var package = JT808Serializer.HeaderDeserialize(item.Data); + if (HandlerDict.TryGetValue(package.Header.MsgId, out var func)) + { + var buffer = func(package); + if (buffer != null) + { + callback((item.TerminalNo, buffer)); + } + } + } + catch + { + + } + } + }, Cts.Token); + } + + public void Subscribe() + { + + } + + public void Unsubscribe() + { + Cts.Cancel(); + } + + /// + /// 终端通用应答 + /// 平台无需回复 + /// 实现自己的业务 + /// + /// + /// + public byte[] Msg0x0001(JT808HeaderPackage request) + { + return null; + } + + /// + /// 终端心跳 + /// + /// + /// + public byte[] Msg0x0002(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + + /// + /// 终端注销 + /// + /// + /// + public byte[] Msg0x0003(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + + /// + /// 终端注册 + /// + /// + /// + public byte[] Msg0x0100(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100() + { + Code = "J" + request.Header.TerminalPhoneNo, + JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功, + AckMsgNum = request.Header.MsgNum + })); + } + /// + /// 终端鉴权 + /// + /// + /// + public byte[] Msg0x0102(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + + /// + /// 位置信息汇报 + /// + /// + /// + public byte[] Msg0x0200(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + + /// + /// 定位数据批量上传 + /// + /// + /// + public byte[] Msg0x0704(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + + /// + /// 数据上行透传 + /// + /// + /// + public byte[] Msg0x0900(JT808HeaderPackage request) + { + return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001() + { + AckMsgId = request.Header.MsgId, + JT808PlatformResult = JT808PlatformResult.成功, + MsgNum = request.Header.MsgNum + })); + } + } +} diff --git a/src/JT808.Gateway/Internal/JT808MsgService.cs b/src/JT808.Gateway/Internal/JT808MsgService.cs new file mode 100644 index 0000000..c1d6095 --- /dev/null +++ b/src/JT808.Gateway/Internal/JT808MsgService.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.Gateway.Internal +{ + internal class JT808MsgService + { + public System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)> MsgQueue { get; set; } = new System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)>(); + } +} diff --git a/src/JT808.Gateway/JT808.Gateway.csproj b/src/JT808.Gateway/JT808.Gateway.csproj new file mode 100644 index 0000000..fdbfd6e --- /dev/null +++ b/src/JT808.Gateway/JT808.Gateway.csproj @@ -0,0 +1,31 @@ + + + + netstandard2.1 + 8.0 + Copyright 2019. + SmallChi(Koike) + false + false + LICENSE + true + 基于Pipeline实现的JT808Gateway的网络库 + 基于Pipeline实现的JT808Gateway的网络库 + JT808.Gateway + JT808.Gateway + 1.0.0-preview2 + + + + + + + + + + + + + + + diff --git a/src/JT808.Gateway/JT808GatewayExtensions.cs b/src/JT808.Gateway/JT808GatewayExtensions.cs new file mode 100644 index 0000000..0f2891d --- /dev/null +++ b/src/JT808.Gateway/JT808GatewayExtensions.cs @@ -0,0 +1,75 @@ +using JT808.Gateway.Abstractions; +using JT808.Gateway.Configurations; +using JT808.Gateway.Internal; +using JT808.Gateway.Services; +using JT808.Gateway.Session; +using JT808.Protocol; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("JT808.Gateway.TestHosting")] +[assembly: InternalsVisibleTo("JT808.Gateway.Test")] +namespace JT808.Gateway +{ + public static partial class JT808GatewayExtensions + { + public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder) + { + IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder); + server.JT808Builder.Services.TryAddSingleton(); + server.AddJT808Core(); + return server; + } + + public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder,Action config) + { + IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder); + server.JT808Builder.Services.Configure(config); + server.AddJT808Core(); + return server; + } + + public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, IConfiguration configuration) + { + IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder); + server.JT808Builder.Services.Configure(configuration.GetSection("JT808Configuration")); + server.AddJT808Core(); + return server; + } + + public static IJT808GatewayBuilder AddTcp(this IJT808GatewayBuilder config) + { + config.JT808Builder.Services.AddHostedService(); + config.JT808Builder.Services.AddHostedService(); + return config; + } + + public static IJT808GatewayBuilder AddUdp(this IJT808GatewayBuilder config) + { + config.JT808Builder.Services.AddHostedService(); + config.JT808Builder.Services.AddHostedService(); + return config; + } + + public static IJT808GatewayBuilder AddGrpc(this IJT808GatewayBuilder config) + { + config.JT808Builder.Services.AddHostedService(); + return config; + } + + private static IJT808GatewayBuilder AddJT808Core(this IJT808GatewayBuilder config) + { + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.TryAddSingleton(); + config.JT808Builder.Services.AddHostedService(); + return config; + } + } +} \ No newline at end of file diff --git a/src/JT808.Gateway/JT808GrpcServer.cs b/src/JT808.Gateway/JT808GrpcServer.cs new file mode 100644 index 0000000..e430873 --- /dev/null +++ b/src/JT808.Gateway/JT808GrpcServer.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using JT808.Gateway.Configurations; +using JT808.Gateway.GrpcService; +using JT808.Gateway.Services; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace JT808.Gateway +{ + public class JT808GrpcServer : IHostedService + { + private readonly ILogger Logger; + private readonly JT808Configuration Configuration; + private readonly IServiceProvider ServiceProvider; + private Server server; + public JT808GrpcServer( + IServiceProvider serviceProvider, + JT808Configuration jT808Configuration, + ILoggerFactory loggerFactory) + { + Logger = loggerFactory.CreateLogger("JT808GrpcServer"); + Configuration = jT808Configuration; + ServiceProvider = serviceProvider; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + server = new Server + { + Services = { JT808Gateway.BindService(new JT808GatewayService(ServiceProvider)) }, + Ports = { new ServerPort(Configuration.WebApiHost, Configuration.WebApiPort, ServerCredentials.Insecure) } + }; + Logger.LogInformation($"JT808 Grpc Server start at {Configuration.WebApiHost}:{Configuration.WebApiPort}."); + try + { + server.Start(); + } + catch (Exception ex) + { + Logger.LogError(ex, "JT808 Grpc Server start error"); + } + return Task.CompletedTask; + } + public Task StopAsync(CancellationToken cancellationToken) + { + Logger.LogInformation("JT808 Grpc Server Stop"); + server.ShutdownAsync(); + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.Gateway/JT808TcpServer.cs b/src/JT808.Gateway/JT808TcpServer.cs new file mode 100644 index 0000000..969cab8 --- /dev/null +++ b/src/JT808.Gateway/JT808TcpServer.cs @@ -0,0 +1,226 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using JT808.Gateway.Abstractions; +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Configurations; +using JT808.Gateway.Enums; +using JT808.Gateway.Services; +using JT808.Gateway.Session; +using JT808.Protocol; +using JT808.Protocol.Exceptions; +using JT808.Protocol.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace JT808.Gateway +{ + public class JT808TcpServer:IHostedService + { + private Socket server; + + private const byte beginAndEndMark = 0x7e; + + private readonly ILogger Logger; + + private readonly JT808SessionManager SessionManager; + + private readonly IJT808MsgProducer MsgProducer; + + private readonly JT808Serializer Serializer; + + private readonly JT808AtomicCounterService AtomicCounterService; + + private readonly JT808Configuration Configuration; + + public JT808TcpServer( + JT808Configuration jT808Configuration, + IJT808Config jT808Config, + ILoggerFactory loggerFactory, + JT808SessionManager jT808SessionManager, + IJT808MsgProducer jT808MsgProducer, + JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory) + { + SessionManager = jT808SessionManager; + Logger = loggerFactory.CreateLogger("JT808TcpServer"); + Serializer = jT808Config.GetSerializer(); + MsgProducer = jT808MsgProducer; + AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); + Configuration = jT808Configuration; + var IPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, jT808Configuration.TcpPort); + server = new Socket(IPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true); + server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); + server.LingerState = new LingerOption(false, 0); + server.Bind(IPEndPoint); + server.Listen(jT808Configuration.SoBacklog); + } + + public Task StartAsync(CancellationToken cancellationToken) + { + Logger.LogInformation($"JT808 TCP Server start at {IPAddress.Any}:{Configuration.TcpPort}."); + Task.Run(async() => { + while (!cancellationToken.IsCancellationRequested) + { + var socket = await server.AcceptAsync(); + JT808TcpSession jT808TcpSession = new JT808TcpSession(socket); + await Task.Factory.StartNew(async (state) => + { + var session = (JT808TcpSession)state; + SessionManager.TryAdd(session); + if (Logger.IsEnabled(LogLevel.Information)) + { + Logger.LogInformation($"[Connected]:{session.Client.RemoteEndPoint}"); + } + var pipe = new Pipe(); + Task writing = FillPipeAsync(session, pipe.Writer); + Task reading = ReadPipeAsync(session, pipe.Reader); + await Task.WhenAll(reading, writing); + SessionManager.RemoveBySessionId(session.SessionID); + }, jT808TcpSession); + } + }, cancellationToken); + return Task.CompletedTask; + } + private async Task FillPipeAsync(JT808TcpSession session, PipeWriter writer) + { + while (true) + { + try + { + Memory memory = writer.GetMemory(Configuration.MiniNumBufferSize); + //设备多久没发数据就断开连接 Receive Timeout. + int bytesRead = await session.Client.ReceiveAsync(memory, SocketFlags.None, session.ReceiveTimeout.Token); + if (bytesRead == 0) + { + break; + } + writer.Advance(bytesRead); + } + catch(OperationCanceledException) + { + Logger.LogError($"[Receive Timeout]:{session.Client.RemoteEndPoint}"); + break; + } + catch (Exception ex) + { + Logger.LogError(ex, $"[Receive Error]:{session.Client.RemoteEndPoint}"); + break; + } + FlushResult result = await writer.FlushAsync(); + if (result.IsCompleted) + { + break; + } + } + writer.Complete(); + } + private async Task ReadPipeAsync(JT808TcpSession session, PipeReader reader) + { + while (true) + { + ReadResult result = await reader.ReadAsync(); + if (result.IsCompleted) + { + break; + } + ReadOnlySequence buffer = result.Buffer; + SequencePosition consumed = buffer.Start; + SequencePosition examined = buffer.End; + try + { + if (result.IsCanceled) break; + if (buffer.Length > 0) + { + ReaderBuffer(ref buffer, session,out consumed, out examined); + } + } + catch (Exception ex) + { + SessionManager.RemoveBySessionId(session.SessionID); + break; + } + finally + { + reader.AdvanceTo(consumed, examined); + } + } + reader.Complete(); + } + private void ReaderBuffer(ref ReadOnlySequence buffer, JT808TcpSession session, out SequencePosition consumed, out SequencePosition examined) + { + consumed = buffer.Start; + examined = buffer.End; + SequenceReader seqReader = new SequenceReader(buffer); + if (seqReader.TryPeek(out byte beginMark)) + { + if (beginMark != beginAndEndMark) throw new ArgumentException("Not JT808 Packages."); + } + byte mark = 0; + long totalConsumed = 0; + while (!seqReader.End) + { + if (seqReader.IsNext(beginAndEndMark, advancePast: true)) + { + if (mark == 1) + { + try + { + var package = Serializer.HeaderDeserialize(seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).FirstSpan); + AtomicCounterService.MsgSuccessIncrement(); + if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{AtomicCounterService.MsgSuccessCount}"); + if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {session.Client.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}"); + //设直连模式和转发模式的会话如何处理 + SessionManager.TryLink(package.Header.TerminalPhoneNo, session); + if(Configuration.MessageQueueType == JT808MessageQueueType.InMemory) + { + MsgProducer.ProduceAsync(session.SessionID, package.OriginalData.ToArray()); + } + else + { + MsgProducer.ProduceAsync(package.Header.TerminalPhoneNo, package.OriginalData.ToArray()); + } + } + catch (JT808Exception ex) + { + AtomicCounterService.MsgFailIncrement(); + if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}"); + Logger.LogError(ex,$"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}"); + } + totalConsumed += (seqReader.Consumed - totalConsumed); + if (seqReader.End) break; + seqReader.Advance(1); + mark = 0; + } + mark++; + } + else + { + seqReader.Advance(1); + } + } + if (seqReader.Length== totalConsumed) + { + examined = consumed = buffer.End; + } + else + { + consumed = buffer.GetPosition(totalConsumed); + } + } + public Task StopAsync(CancellationToken cancellationToken) + { + Logger.LogInformation("808 Tcp Server Stop"); + if (server?.Connected ?? false) + server.Shutdown(SocketShutdown.Both); + server?.Close(); + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.Gateway/JT808UdpServer.cs b/src/JT808.Gateway/JT808UdpServer.cs new file mode 100644 index 0000000..749bcb0 --- /dev/null +++ b/src/JT808.Gateway/JT808UdpServer.cs @@ -0,0 +1,134 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using JT808.Gateway.Abstractions; +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Configurations; +using JT808.Gateway.Enums; +using JT808.Gateway.Services; +using JT808.Gateway.Session; +using JT808.Protocol; +using JT808.Protocol.Exceptions; +using JT808.Protocol.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace JT808.Gateway +{ + public class JT808UdpServer : IHostedService + { + private Socket server; + + private readonly ILogger Logger; + + private readonly JT808SessionManager SessionManager; + + private readonly IJT808MsgProducer MsgProducer; + + private readonly JT808Serializer Serializer; + + private readonly JT808AtomicCounterService AtomicCounterService; + + private readonly JT808Configuration Configuration; + + private IPEndPoint LocalIPEndPoint; + + public JT808UdpServer( + JT808Configuration jT808Configuration, + IJT808Config jT808Config, + ILoggerFactory loggerFactory, + JT808SessionManager jT808SessionManager, + IJT808MsgProducer jT808MsgProducer, + JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory) + { + SessionManager = jT808SessionManager; + Logger = loggerFactory.CreateLogger("JT808UdpServer"); + Serializer = jT808Config.GetSerializer(); + MsgProducer = jT808MsgProducer; + AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); + Configuration = jT808Configuration; + LocalIPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, jT808Configuration.UdpPort); + server = new Socket(LocalIPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + server.Bind(LocalIPEndPoint); + } + + public Task StartAsync(CancellationToken cancellationToken) + { + Logger.LogInformation($"JT808 Udp Server start at {IPAddress.Any}:{Configuration.UdpPort}."); + Task.Run(async() => { + while (!cancellationToken.IsCancellationRequested) + { + var buffer = ArrayPool.Shared.Rent(Configuration.MiniNumBufferSize); + try + { + var segment = new ArraySegment(buffer); + SocketReceiveMessageFromResult result = await server.ReceiveMessageFromAsync(segment, SocketFlags.None, LocalIPEndPoint); + ReaderBuffer(buffer.AsSpan(0, result.ReceivedBytes), server, result); + } + catch(AggregateException ex) + { + Logger.LogError(ex, "Receive MessageFrom Async"); + } + catch(Exception ex) + { + Logger.LogError(ex, $"Received Bytes"); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + }, cancellationToken); + return Task.CompletedTask; + } + private void ReaderBuffer(ReadOnlySpan buffer, Socket socket,SocketReceiveMessageFromResult receiveMessageFromResult) + { + try + { + var package = Serializer.HeaderDeserialize(buffer); + AtomicCounterService.MsgSuccessIncrement(); + if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{AtomicCounterService.MsgSuccessCount}"); + if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {receiveMessageFromResult.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}"); + //设直连模式和转发模式的会话如何处理 + string sessionId= SessionManager.TryLink(package.Header.TerminalPhoneNo, socket, receiveMessageFromResult.RemoteEndPoint); + if (Logger.IsEnabled(LogLevel.Information)) + { + Logger.LogInformation($"[Connected]:{receiveMessageFromResult.RemoteEndPoint}"); + } + if (Configuration.MessageQueueType == JT808MessageQueueType.InMemory) + { + MsgProducer.ProduceAsync(sessionId, package.OriginalData.ToArray()); + } + else + { + MsgProducer.ProduceAsync(package.Header.TerminalPhoneNo, package.OriginalData.ToArray()); + } + } + catch (JT808Exception ex) + { + AtomicCounterService.MsgFailIncrement(); + if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}"); + Logger.LogError(ex, $"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}-{buffer.ToArray().ToHexString()}"); + } + catch (Exception ex) + { + if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}"); + Logger.LogError(ex, $"[ReaderBuffer]:{ buffer.ToArray().ToHexString()}"); + } + } + public Task StopAsync(CancellationToken cancellationToken) + { + Logger.LogInformation("808 Udp Server Stop"); + if (server?.Connected ?? false) + server.Shutdown(SocketShutdown.Both); + server?.Close(); + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs new file mode 100644 index 0000000..6362905 --- /dev/null +++ b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace JT808.Gateway.Metadata +{ + /// + /// + /// + /// + internal class JT808AtomicCounter + { + long counter = 0; + + public JT808AtomicCounter(long initialCount = 0) + { + this.counter = initialCount; + } + + public void Reset() + { + Interlocked.Exchange(ref counter, 0); + } + + public long Increment() + { + return Interlocked.Increment(ref counter); + } + + public long Add(long len) + { + return Interlocked.Add(ref counter,len); + } + + public long Decrement() + { + return Interlocked.Decrement(ref counter); + } + + public long Count + { + get + { + return Interlocked.Read(ref counter); + } + } + } +} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs new file mode 100644 index 0000000..cddd31f --- /dev/null +++ b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs @@ -0,0 +1,52 @@ +using JT808.Gateway.Metadata; + +namespace JT808.Gateway.Services +{ + /// + /// 计数包服务 + /// + public class JT808AtomicCounterService + { + private readonly JT808AtomicCounter MsgSuccessCounter; + + private readonly JT808AtomicCounter MsgFailCounter; + + public JT808AtomicCounterService() + { + MsgSuccessCounter=new JT808AtomicCounter(); + MsgFailCounter = new JT808AtomicCounter(); + } + + public void Reset() + { + MsgSuccessCounter.Reset(); + MsgFailCounter.Reset(); + } + + public long MsgSuccessIncrement() + { + return MsgSuccessCounter.Increment(); + } + + public long MsgSuccessCount + { + get + { + return MsgSuccessCounter.Count; + } + } + + public long MsgFailIncrement() + { + return MsgFailCounter.Increment(); + } + + public long MsgFailCount + { + get + { + return MsgFailCounter.Count; + } + } + } +} diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs new file mode 100644 index 0000000..e4c9536 --- /dev/null +++ b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs @@ -0,0 +1,30 @@ +using JT808.Gateway.Abstractions.Enums; +using System; +using System.Collections.Concurrent; + +namespace JT808.Gateway.Services +{ + public class JT808AtomicCounterServiceFactory + { + private readonly ConcurrentDictionary cache; + + public JT808AtomicCounterServiceFactory() + { + cache = new ConcurrentDictionary(); + } + + public JT808AtomicCounterService Create(JT808TransportProtocolType type) + { + if(cache.TryGetValue(type,out var service)) + { + return service; + } + else + { + var serviceNew = new JT808AtomicCounterService(); + cache.TryAdd(type, serviceNew); + return serviceNew; + } + } + } +} diff --git a/src/JT808.Gateway/Services/JT808GatewayService.cs b/src/JT808.Gateway/Services/JT808GatewayService.cs new file mode 100644 index 0000000..cf0b7d5 --- /dev/null +++ b/src/JT808.Gateway/Services/JT808GatewayService.cs @@ -0,0 +1,144 @@ +using System; +using System.Linq; +using JT808.Gateway.GrpcService; +using Grpc.Core; +using System.Threading.Tasks; +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Session; +using Microsoft.Extensions.DependencyInjection; +using static Grpc.Core.Metadata; +using Microsoft.Extensions.Options; +using JT808.Gateway.Configurations; + +namespace JT808.Gateway.Services +{ + public class JT808GatewayService: JT808Gateway.JT808GatewayBase + { + private readonly JT808AtomicCounterService jT808TcpAtomicCounterService; + + private readonly JT808AtomicCounterService jT808UdpAtomicCounterService; + + private readonly JT808SessionManager jT808SessionManager; + + private readonly IOptionsMonitor ConfigurationOptionsMonitor; + + public JT808GatewayService( + IOptionsMonitor configurationOptionsMonitor, + JT808SessionManager jT808SessionManager, + JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory + ) + { + this.jT808SessionManager = jT808SessionManager; + this.ConfigurationOptionsMonitor = configurationOptionsMonitor; + this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); + this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); + } + + public JT808GatewayService(IServiceProvider serviceProvider) + { + this.jT808SessionManager = serviceProvider.GetRequiredService(); + this.jT808TcpAtomicCounterService = serviceProvider.GetRequiredService().Create(JT808TransportProtocolType.tcp); + this.jT808UdpAtomicCounterService = serviceProvider.GetRequiredService().Create(JT808TransportProtocolType.udp); + this.ConfigurationOptionsMonitor = serviceProvider.GetRequiredService>(); + } + + public override Task GetTcpSessionAll(Empty request, ServerCallContext context) + { + Auth(context); + var result = jT808SessionManager.GetTcpAll(); + TcpSessionInfoReply reply = new TcpSessionInfoReply(); + foreach (var item in result) + { + reply.TcpSessions.Add(new SessionInfo + { + LastActiveTime = item.ActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), + StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), + RemoteAddressIP = item.RemoteEndPoint.ToString(), + TerminalPhoneNo = item.TerminalPhoneNo + }); + } + return Task.FromResult(reply); + } + + public override Task RemoveSessionByTerminalPhoneNo(SessionRemoveRequest request, ServerCallContext context) + { + Auth(context); + try + { + jT808SessionManager.RemoveByTerminalPhoneNo(request.TerminalPhoneNo); + return Task.FromResult(new SessionRemoveReply { Success = true }); + } + catch (Exception) + { + return Task.FromResult(new SessionRemoveReply { Success = false }); + } + } + + public override Task GetUdpSessionAll(Empty request, ServerCallContext context) + { + Auth(context); + var result = jT808SessionManager.GetUdpAll(); + UdpSessionInfoReply reply = new UdpSessionInfoReply(); + foreach (var item in result) + { + reply.UdpSessions.Add(new SessionInfo + { + LastActiveTime = item.ActiveTime.ToString("yyyy-MM-dd HH:mm:ss"), + StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), + RemoteAddressIP = item.RemoteEndPoint.ToString(), + TerminalPhoneNo = item.TerminalPhoneNo + }); + } + + return Task.FromResult(reply); + } + + public override Task UnificationSend(UnificationSendRequest request, ServerCallContext context) + { + Auth(context); + try + { + var flag = jT808SessionManager.TrySendByTerminalPhoneNo(request.TerminalPhoneNo, request.Data.ToByteArray()); + return Task.FromResult(new UnificationSendReply { Success = flag }); + } + catch (Exception) + { + return Task.FromResult(new UnificationSendReply { Success = false }); + } + } + + public override Task GetTcpAtomicCounter(Empty request, ServerCallContext context) + { + Auth(context); + TcpAtomicCounterReply reply = new TcpAtomicCounterReply(); + reply.MsgFailCount=jT808TcpAtomicCounterService.MsgFailCount; + reply.MsgSuccessCount=jT808TcpAtomicCounterService.MsgSuccessCount; + return Task.FromResult(reply); + } + + public override Task GetUdpAtomicCounter(Empty request, ServerCallContext context) + { + Auth(context); + UdpAtomicCounterReply reply = new UdpAtomicCounterReply(); + reply.MsgFailCount = jT808UdpAtomicCounterService.MsgFailCount; + reply.MsgSuccessCount = jT808UdpAtomicCounterService.MsgSuccessCount; + return Task.FromResult(reply); + } + + private void Auth(ServerCallContext context) + { + Entry tokenEntry = context.RequestHeaders.FirstOrDefault(w => w.Key == "token"); + if (tokenEntry != null) + { + if(tokenEntry.Value != ConfigurationOptionsMonitor.CurrentValue.WebApiToken) + { + throw new Grpc.Core.RpcException(new Status(StatusCode.Unauthenticated, "token error")); + } + } + else + { + throw new Grpc.Core.RpcException(new Status(StatusCode.Unauthenticated,"token empty")); + } + } + } +} diff --git a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs new file mode 100644 index 0000000..d163715 --- /dev/null +++ b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs @@ -0,0 +1,52 @@ +using JT808.Gateway.Abstractions; +using JT808.Gateway.Configurations; +using JT808.Gateway.Enums; +using JT808.Gateway.Session; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JT808.Gateway.Services +{ + internal class JT808MsgReplyHostedService : IHostedService + { + private readonly JT808SessionManager JT808SessionManager; + + private readonly IJT808MsgReplyConsumer JT808MsgReplyConsumer; + private readonly JT808Configuration Configuration; + public JT808MsgReplyHostedService( + JT808Configuration jT808Configuration, + IJT808MsgReplyConsumer jT808MsgReplyConsumer, + JT808SessionManager jT808SessionManager) + { + JT808MsgReplyConsumer = jT808MsgReplyConsumer; + JT808SessionManager = jT808SessionManager; + Configuration = jT808Configuration; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + if(Configuration.MessageQueueType== JT808MessageQueueType.InMemory) + { + JT808MsgReplyConsumer.OnMessage(item => + { + JT808SessionManager.TrySendBySessionId(item.TerminalNo, item.Data); + }); + JT808MsgReplyConsumer.Subscribe(); + } + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + if (Configuration.MessageQueueType == JT808MessageQueueType.InMemory) + { + JT808MsgReplyConsumer.Unsubscribe(); + } + return Task.CompletedTask; + } + } +} diff --git a/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs b/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs new file mode 100644 index 0000000..8fdda8c --- /dev/null +++ b/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs @@ -0,0 +1,58 @@ +using JT808.Gateway.Configurations; +using JT808.Gateway.Session; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JT808.Gateway.Services +{ + internal class JT808TcpReceiveTimeoutHostedService : BackgroundService + { + private readonly ILogger Logger; + + private readonly JT808SessionManager SessionManager; + + private readonly JT808Configuration Configuration; + public JT808TcpReceiveTimeoutHostedService( + JT808Configuration jT808Configuration, + ILoggerFactory loggerFactory, + JT808SessionManager jT808SessionManager + ) + { + SessionManager = jT808SessionManager; + Logger = loggerFactory.CreateLogger("JT808TcpReceiveTimeout"); + Configuration = jT808Configuration; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + try + { + foreach (var item in SessionManager.GetTcpAll()) + { + if (item.ActiveTime.AddSeconds(Configuration.TcpReaderIdleTimeSeconds) < DateTime.Now) + { + item.ReceiveTimeout.Cancel(); + } + } + Logger.LogInformation($"[Check Receive Timeout]"); + Logger.LogInformation($"[Session Online Count]:{SessionManager.TcpSessionCount}"); + } + catch (Exception ex) + { + Logger.LogError(ex, $"[Receive Timeout]"); + } + finally + { + await Task.Delay(TimeSpan.FromSeconds(Configuration.TcpReceiveTimeoutCheckTimeSeconds), stoppingToken); + } + } + } + } +} diff --git a/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs b/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs new file mode 100644 index 0000000..3f04f30 --- /dev/null +++ b/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs @@ -0,0 +1,63 @@ +using JT808.Gateway.Configurations; +using JT808.Gateway.Session; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace JT808.Gateway.Services +{ + internal class JT808UdpReceiveTimeoutHostedService : BackgroundService + { + private readonly ILogger Logger; + + private readonly JT808SessionManager SessionManager; + + private readonly JT808Configuration Configuration; + public JT808UdpReceiveTimeoutHostedService( + JT808Configuration jT808Configuration, + ILoggerFactory loggerFactory, + JT808SessionManager jT808SessionManager + ) + { + SessionManager = jT808SessionManager; + Logger = loggerFactory.CreateLogger("JT808UdpReceiveTimeout"); + Configuration = jT808Configuration; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + try + { + List sessionIds = new List(); + foreach (var item in SessionManager.GetUdpAll()) + { + if (item.ActiveTime.AddSeconds(Configuration.UdpReaderIdleTimeSeconds) < DateTime.Now) + { + sessionIds.Add(item.SessionID); + } + } + foreach(var item in sessionIds) + { + SessionManager.RemoveBySessionId(item); + } + Logger.LogInformation($"[Check Receive Timeout]"); + Logger.LogInformation($"[Session Online Count]:{SessionManager.UdpSessionCount}"); + } + catch (Exception ex) + { + Logger.LogError(ex, $"[Receive Timeout]"); + } + finally + { + await Task.Delay(TimeSpan.FromSeconds(Configuration.UdpReceiveTimeoutCheckTimeSeconds), stoppingToken); + } + } + } + } +} diff --git a/src/JT808.Gateway/Session/JT808SessionManager.cs b/src/JT808.Gateway/Session/JT808SessionManager.cs new file mode 100644 index 0000000..a7f74cc --- /dev/null +++ b/src/JT808.Gateway/Session/JT808SessionManager.cs @@ -0,0 +1,224 @@ +using JT808.Gateway.Abstractions; +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Interfaces; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace JT808.Gateway.Session +{ + /// + /// + /// 不支持变态类型:既发TCP和UDP + /// + public class JT808SessionManager + { + private readonly ILogger logger; + private readonly IJT808SessionProducer JT808SessionProducer; + public ConcurrentDictionary Sessions { get; } + public ConcurrentDictionary TerminalPhoneNoSessions { get; } + public JT808SessionManager( + IJT808SessionProducer jT808SessionProducer, + ILoggerFactory loggerFactory + ) + { + JT808SessionProducer = jT808SessionProducer; + Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + TerminalPhoneNoSessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + logger = loggerFactory.CreateLogger("JT808SessionManager"); + } + + public JT808SessionManager(ILoggerFactory loggerFactory) + { + Sessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + TerminalPhoneNoSessions = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + logger = loggerFactory.CreateLogger("JT808SessionManager"); + } + + public int TotalSessionCount + { + get + { + return Sessions.Count; + } + } + + public int TcpSessionCount + { + get + { + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Count(); + } + } + + public int UdpSessionCount + { + get + { + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Count(); + } + } + + internal void TryLink(string terminalPhoneNo, IJT808Session session) + { + session.ActiveTime = DateTime.Now; + session.TerminalPhoneNo = terminalPhoneNo; + Sessions.TryUpdate(session.SessionID, session, session); + TerminalPhoneNoSessions.AddOrUpdate(terminalPhoneNo, session.SessionID, (key, oldValue)=> + { + if(session.SessionID!= oldValue) + { + //会话通知 + JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOnline, key); + return session.SessionID; + } + return oldValue; + }); + } + + public string TryLink(string terminalPhoneNo, Socket socket, EndPoint remoteEndPoint) + { + string sessionId = string.Empty; + if(TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo,out sessionId)) + { + if (Sessions.TryGetValue(sessionId, out IJT808Session sessionInfo)) + { + sessionInfo.ActiveTime = DateTime.Now; + sessionInfo.TerminalPhoneNo = terminalPhoneNo; + sessionInfo.RemoteEndPoint = remoteEndPoint; + Sessions.TryUpdate(sessionId, sessionInfo, sessionInfo); + } + } + else + { + JT808UdpSession session = new JT808UdpSession(socket, remoteEndPoint); + Sessions.TryAdd(session.SessionID, session); + TerminalPhoneNoSessions.TryAdd(terminalPhoneNo, session.SessionID); + sessionId = session.SessionID; + } + //会话通知 + //使用场景: + //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接, + //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。 + //有设备关联上来可以进行通知 例如:使用Redis发布订阅 + JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOnline, terminalPhoneNo); + return sessionId; + } + + internal bool TryAdd(IJT808Session session) + { + return Sessions.TryAdd(session.SessionID, session); + } + + public bool TrySendByTerminalPhoneNo(string terminalPhoneNo, byte[] data) + { + if(TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo,out var sessionid)) + { + if (Sessions.TryGetValue(sessionid, out var session)) + { + if (session.TransportProtocolType == JT808TransportProtocolType.tcp) + { + session.Client.Send(data, SocketFlags.None); + } + else + { + session.Client.SendTo(data, SocketFlags.None, session.RemoteEndPoint); + } + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } + + public bool TrySendBySessionId(string sessionId, byte[] data) + { + if (Sessions.TryGetValue(sessionId, out var session)) + { + if(session.TransportProtocolType== JT808TransportProtocolType.tcp) + { + session.Client.Send(data, SocketFlags.None); + } + else + { + session.Client.SendTo(data, SocketFlags.None, session.RemoteEndPoint); + } + return true; + } + else + { + return false; + } + } + + public void RemoveByTerminalPhoneNo(string terminalPhoneNo) + { + if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out var removeSessionId)) + { + // 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据 + //1.用当前会话的通道Id找出通过转发过来的其他设备的终端号 + var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value == removeSessionId).Select(s => s.Key).ToList(); + //2.存在则一个个移除 + string tmpTerminalPhoneNo = terminalPhoneNo; + if (terminalPhoneNos.Count > 0) + { + //3.移除包括当前的设备号 + foreach (var item in terminalPhoneNos) + { + TerminalPhoneNoSessions.TryRemove(item, out _); + } + tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos); + } + if (Sessions.TryRemove(removeSessionId, out var removeSession)) + { + removeSession.Close(); + if(logger.IsEnabled(LogLevel.Information)) + logger.LogInformation($"[Session Remove]:{terminalPhoneNo}-{tmpTerminalPhoneNo}"); + JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo); + } + } + } + + public void RemoveBySessionId(string sessionId) + { + if(Sessions.TryRemove(sessionId,out var removeSession)) + { + var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value == sessionId).Select(s => s.Key).ToList(); + if (terminalPhoneNos.Count > 0) + { + foreach (var item in terminalPhoneNos) + { + TerminalPhoneNoSessions.TryRemove(item, out _); + } + var tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos); + JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo); + if (logger.IsEnabled(LogLevel.Information)) + logger.LogInformation($"[Session Remove]:{tmpTerminalPhoneNo}"); + } + removeSession.Close(); + } + } + + public List GetTcpAll() + { + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Select(s => (JT808TcpSession)s.Value).ToList(); + } + + public List GetUdpAll() + { + return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Select(s => (JT808UdpSession)s.Value).ToList(); + } + } +} diff --git a/src/JT808.Gateway/Session/JT808TcpSession.cs b/src/JT808.Gateway/Session/JT808TcpSession.cs new file mode 100644 index 0000000..70d044a --- /dev/null +++ b/src/JT808.Gateway/Session/JT808TcpSession.cs @@ -0,0 +1,47 @@ +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Interfaces; +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace JT808.Gateway.Session +{ + public class JT808TcpSession: IJT808Session + { + public JT808TcpSession(Socket client) + { + Client = client; + RemoteEndPoint = client.RemoteEndPoint; + ActiveTime = DateTime.Now; + StartTime = DateTime.Now; + SessionID = Guid.NewGuid().ToString("N"); + ReceiveTimeout = new CancellationTokenSource(); + } + + /// + /// 终端手机号 + /// + public string TerminalPhoneNo { get; set; } + public DateTime ActiveTime { get; set; } + public DateTime StartTime { get; set; } + public JT808TransportProtocolType TransportProtocolType { get;} = JT808TransportProtocolType.tcp; + public string SessionID { get; } + public Socket Client { get; set; } + public CancellationTokenSource ReceiveTimeout { get; set; } + public EndPoint RemoteEndPoint { get ; set; } + + public void Close() + { + try + { + Client.Shutdown(SocketShutdown.Both); + } + catch { } + finally + { + Client.Close(); + } + } + } +} diff --git a/src/JT808.Gateway/Session/JT808UdpSession.cs b/src/JT808.Gateway/Session/JT808UdpSession.cs new file mode 100644 index 0000000..bdd4c87 --- /dev/null +++ b/src/JT808.Gateway/Session/JT808UdpSession.cs @@ -0,0 +1,41 @@ +using JT808.Gateway.Abstractions.Enums; +using JT808.Gateway.Interfaces; +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace JT808.Gateway.Session +{ + public class JT808UdpSession: IJT808Session + { + public JT808UdpSession(Socket socket, EndPoint sender) + { + ActiveTime = DateTime.Now; + StartTime = DateTime.Now; + SessionID = Guid.NewGuid().ToString("N"); + ReceiveTimeout = new CancellationTokenSource(); + RemoteEndPoint = sender; + Client = socket; + } + + /// + /// 终端手机号 + /// + public string TerminalPhoneNo { get; set; } + public DateTime ActiveTime { get; set; } + public DateTime StartTime { get; set; } + public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.udp; + + public string SessionID { get; } + + public Socket Client { get; set; } + public CancellationTokenSource ReceiveTimeout { get; set; } + public EndPoint RemoteEndPoint { get; set ; } + + public void Close() + { + + } + } +} From af1584a2bd0b5acea85d3a0465986bd42f972b87 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Sat, 21 Dec 2019 09:36:37 +0800 Subject: [PATCH 5/5] =?UTF-8?q?v2.3.1=201.=E8=A7=A3=E5=86=B3=E5=A4=9A?= =?UTF-8?q?=E5=8F=B0=E6=9C=BA=E5=99=A8=E5=90=8C=E6=97=B6=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E6=97=B6=E7=BB=88=E7=AB=AF=E5=8F=B7=E5=86=B2=E7=AA=81=202.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E8=BF=9E=E6=8E=A5=E5=B0=86=E5=90=8C=E6=AD=A5=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E5=BC=82=E6=AD=A5=203.=E4=BF=AE=E5=A4=8D=E8=8E=B7?= =?UTF-8?q?=E5=8F=96session=E9=9B=86=E5=90=88=E6=8A=A5=E9=94=99=204.?= =?UTF-8?q?=E5=8D=87=E7=BA=A7808=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Up2019Service.cs | 1 + .../Services/UpService.cs | 1 + .../JT808.DotNetty.Abstractions.csproj | 2 +- .../JT808.DotNetty.Client.csproj | 2 +- .../JT808ClientMsgSNDistributedImpl.cs | 16 ---------------- src/JT808.DotNetty.Client/JT808DeviceConfig.cs | 1 - .../JT808TcpClientExtensions.cs | 1 - .../JT808.DotNetty.Traffic.csproj | 2 +- src/Version.props | 2 +- 9 files changed, 6 insertions(+), 22 deletions(-) delete mode 100644 src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs diff --git a/simples/JT808.DotNetty.SimpleClient/Services/Up2019Service.cs b/simples/JT808.DotNetty.SimpleClient/Services/Up2019Service.cs index cfac566..1f4a9ce 100644 --- a/simples/JT808.DotNetty.SimpleClient/Services/Up2019Service.cs +++ b/simples/JT808.DotNetty.SimpleClient/Services/Up2019Service.cs @@ -24,6 +24,7 @@ namespace JT808.DotNetty.SimpleClient.Services { string sim = "22222222222"; JT808TcpClient client1 = jT808TcpClientFactory.Create(new JT808DeviceConfig(sim, "127.0.0.1", 808, JT808Version.JTT2019)); + Thread.Sleep(5000); //1.终端注册 client1.Send(JT808MsgId.终端注册.Create2019(sim, new JT808_0x0100() { diff --git a/simples/JT808.DotNetty.SimpleClient/Services/UpService.cs b/simples/JT808.DotNetty.SimpleClient/Services/UpService.cs index c7ff718..6138a5a 100644 --- a/simples/JT808.DotNetty.SimpleClient/Services/UpService.cs +++ b/simples/JT808.DotNetty.SimpleClient/Services/UpService.cs @@ -24,6 +24,7 @@ namespace JT808.DotNetty.SimpleClient.Services { string sim = "11111111111"; JT808TcpClient client1 = jT808TcpClientFactory.Create(new JT808DeviceConfig(sim, "127.0.0.1", 808)); + Thread.Sleep(5000); //1.终端注册 client1.Send(JT808MsgId.终端注册.Create(sim, new JT808_0x0100() { diff --git a/src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj b/src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj index bed7d8f..9051146 100644 --- a/src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj +++ b/src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj @@ -20,7 +20,7 @@ 基于DotNetty实现的JT808DotNetty的抽象库 - + diff --git a/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj b/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj index 40d4089..0bfb406 100644 --- a/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj +++ b/src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs b/src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs deleted file mode 100644 index e15d703..0000000 --- a/src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JT808.Protocol; -using JT808.Protocol.Interfaces; -using System.Threading; - -namespace JT808.DotNetty.Client -{ - internal class JT808ClientMsgSNDistributedImpl : IJT808MsgSNDistributed - { - int _counter = 0; - - public ushort Increment() - { - return (ushort)Interlocked.Increment(ref _counter); - } - } -} diff --git a/src/JT808.DotNetty.Client/JT808DeviceConfig.cs b/src/JT808.DotNetty.Client/JT808DeviceConfig.cs index 1fc2530..63cd606 100644 --- a/src/JT808.DotNetty.Client/JT808DeviceConfig.cs +++ b/src/JT808.DotNetty.Client/JT808DeviceConfig.cs @@ -14,7 +14,6 @@ namespace JT808.DotNetty.Client TerminalPhoneNo = terminalPhoneNo; TcpHost = tcpHost; TcpPort = tcpPort; - MsgSNDistributed = new JT808ClientMsgSNDistributedImpl(); Version = version; } public JT808Version Version { get; private set; } diff --git a/src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs b/src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs index 97e266d..b0d230a 100644 --- a/src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs +++ b/src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs @@ -14,7 +14,6 @@ namespace JT808.DotNetty.Client public static void Send(this JT808TcpClient client, JT808Package package, int minBufferSize = 4096) { package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo; - package.Header.MsgNum = client.DeviceConfig.MsgSNDistributed.Increment(); JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize); client.Send(request); } diff --git a/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj index 90acf2a..ee1e567 100644 --- a/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj +++ b/src/JT808.DotNetty.Services/JT808.DotNetty.Traffic/JT808.DotNetty.Traffic.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Version.props b/src/Version.props index 3ca3866..8f15eb1 100644 --- a/src/Version.props +++ b/src/Version.props @@ -1,5 +1,5 @@  - 2.3.0 + 2.3.1 \ No newline at end of file