Merge pull request #435 from emqtt/0.15
0.15 release - Support 500K+ subscribers to subscribe one topic
|
@ -18,3 +18,4 @@ log/
|
|||
*.swp
|
||||
*.so
|
||||
examples
|
||||
docs/build/*
|
||||
|
|
|
@ -19,3 +19,6 @@
|
|||
[submodule "plugins/emqttd_recon"]
|
||||
path = plugins/emqttd_recon
|
||||
url = https://github.com/emqtt/emqttd_recon.git
|
||||
[submodule "plugins/emqttd_plugin_redis"]
|
||||
path = plugins/emqttd_plugin_redis
|
||||
url = https://github.com/emqtt/emqttd_plugin_redis.git
|
||||
|
|
46
CHANGELOG.md
|
@ -2,6 +2,52 @@
|
|||
emqttd ChangeLog
|
||||
==================
|
||||
|
||||
0.15.0-beta(2016-01-28)
|
||||
-------------------------
|
||||
|
||||
#### Highlights
|
||||
|
||||
Optimization for Route ETS insertion (#427)
|
||||
|
||||
Add Mongodb, Redis Plugins
|
||||
|
||||
Priority Message Queue Support
|
||||
|
||||
ReadTheDocs
|
||||
|
||||
|
||||
#### Enhancements
|
||||
|
||||
Join/Leave the Cluster
|
||||
|
||||
Username Authentication: Default Users
|
||||
|
||||
Improve Cli commands: pubsub, bridges, trace
|
||||
|
||||
emqttd_mod_subscription: fix client_connected/3
|
||||
|
||||
|
||||
#### BugFix
|
||||
|
||||
Fix dequeue/1 of emqttd_bridge...
|
||||
|
||||
Add emqttd:seed_now/0 function
|
||||
|
||||
|
||||
#### Plugins
|
||||
|
||||
emqttd_plubin_mysql: changed mysql driver to mysql-otp
|
||||
|
||||
emqttd_plugin_pgsql: integrate with ecpool
|
||||
|
||||
emqttd_plugin_redis: first release
|
||||
|
||||
emqttd_plugin_mongo: first release
|
||||
|
||||
|
||||
#### Benchmark
|
||||
|
||||
|
||||
0.14.1-beta(2015-12-28)
|
||||
-------------------------
|
||||
|
||||
|
|
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -5,11 +5,9 @@ emqttd is a massively scalable and clusterable MQTT V3.1/V3.1.1 broker written i
|
|||
|
||||
emqttd requires Erlang R17+ to build.
|
||||
|
||||
**DON'T compile the broker with Erlang/OTP R18.0 which introduced a [binary memory leak](http://erlang.org/pipermail/erlang-questions/2015-September/086098.html).**
|
||||
|
||||
Demo Server: tcp://t.emqtt.io:1883
|
||||
|
||||
Twitter: [@emqtt](https://twitter.com/emqtt)
|
||||
Follow us on Twitter: [@emqtt](https://twitter.com/emqtt)
|
||||
|
||||
## Goals
|
||||
|
||||
|
|
Before Width: | Height: | Size: 26 KiB |
|
@ -1,55 +0,0 @@
|
|||
## Transient Client/Session Sequence1
|
||||
|
||||
```
|
||||
Client1->SM: {start_session, {true, ClientId, self()}}
|
||||
SM-->Session: {destory, ClientId}
|
||||
Session-->Session: {shutdown, destroy}
|
||||
Session-->Client2: exit({shutdown, destroy})
|
||||
Client2-->CM: {'DOWN', MRef, process, Pid, Reason}
|
||||
SM-->Client1: {ok, SessPid}
|
||||
Client1-->CM: {register, Client1}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Transient Client/Session Sequence2
|
||||
|
||||
|
||||
```
|
||||
Client1->SM: {start_session, {true, ClientId, self()}}
|
||||
SM-->Session: {destory, ClientId}
|
||||
Session-->Session: {shutdown, destroy}
|
||||
SM-->Client1: {ok, SessPid}
|
||||
Client1-->CM: {register, Client1}
|
||||
Session-->Client2: exit({shutdown, destroy})
|
||||
Client2-->CM: {'DOWN', MRef, process, Pid, Reason}
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Persistent Client/Session Sequence1
|
||||
|
||||
```
|
||||
Client1->SM: {start_session, {true, ClientId, self()}}
|
||||
SM-->Session: {resume, ClientId, ClientPid}
|
||||
Session-->Client2: {shutdown, conflict, {ClientId, Pid}}
|
||||
Client2-->CM: {unregister, ClientId, self()}
|
||||
SM-->Client1: {ok, SessPid}
|
||||
Client1-->CM: {register, Client1}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
## Persistent Client/Session Sequence2
|
||||
|
||||
```
|
||||
Client1->SM: {start_session, {true, ClientId, self()}}
|
||||
SM-->Session: {resume, ClientId, ClientPid}
|
||||
SM-->Client1: {ok, SessPid}
|
||||
Client1-->CM: {register, Client1}
|
||||
Session-->Client2: {shutdown, conflict, {ClientId, Pid}}
|
||||
Client2-->CM: {unregister, ClientId, self()}
|
||||
```
|
||||
|
||||

|
|
@ -1,847 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
|
||||
<!--Created by yEd 3.13-->
|
||||
<key for="graphml" id="d0" yfiles.type="resources"/>
|
||||
<key for="port" id="d1" yfiles.type="portgraphics"/>
|
||||
<key for="port" id="d2" yfiles.type="portgeometry"/>
|
||||
<key for="port" id="d3" yfiles.type="portuserdata"/>
|
||||
<key attr.name="url" attr.type="string" for="node" id="d4"/>
|
||||
<key attr.name="description" attr.type="string" for="node" id="d5"/>
|
||||
<key for="node" id="d6" yfiles.type="nodegraphics"/>
|
||||
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
|
||||
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
|
||||
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
|
||||
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
|
||||
<graph edgedefault="directed" id="G">
|
||||
<data key="d7"/>
|
||||
<node id="n0" yfiles.foldertype="group">
|
||||
<data key="d4"/>
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="334.0" width="357.5" x="211.25" y="155.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#F5F5F5" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="node_width" borderDistance="0.0" configuration="CroppingLabel" fontFamily="Dialog" fontSize="18" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="27.19921875" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="357.5" x="0.0" y="153.400390625">emqttd cluster</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="50.0" width="50.0" x="180.0" y="140.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
</y:Realizers>
|
||||
</y:ProxyAutoBoundsNode>
|
||||
</data>
|
||||
<graph edgedefault="directed" id="n0:">
|
||||
<node id="n0::n0">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="226.25" y="170.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n1">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="309.25" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n2">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="268.25" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n3">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="249.25" y="254.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n4">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="284.25" y="254.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n5">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="284.25" y="193.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n6">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="428.75" y="170.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n7">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="511.75" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n8">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="470.75" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n9">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="451.75" y="254.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n10">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="486.75" y="254.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n11">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="486.75" y="193.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n12">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="226.25" y="350.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n13">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="309.25" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n14">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="268.25" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n15">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="249.25" y="434.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n16">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="284.25" y="434.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n17">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="284.25" y="373.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n18">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="428.75" y="350.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n19">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="511.75" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n20">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="470.75" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n21">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="451.75" y="434.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n22">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="486.75" y="434.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n23">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="486.75" y="373.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
</graph>
|
||||
</node>
|
||||
<node id="n1">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="81.75" y="209.5"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n2">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="81.75" y="389.5"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="654.25" y="209.5"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="654.25" y="389.5"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<edge id="n0::e0" source="n0::n0" target="n0::n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e1" source="n0::n0" target="n0::n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e2" source="n0::n0" target="n0::n18">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e3" source="n0::n2" target="n0::n5">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e4" source="n0::n3" target="n0::n2">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e5" source="n0::n4" target="n0::n2">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e6" source="n0::n5" target="n0::n1">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e7" source="n0::n6" target="n0::n18">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e8" source="n0::n8" target="n0::n11">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e9" source="n0::n9" target="n0::n8">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e10" source="n0::n10" target="n0::n8">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e11" source="n0::n11" target="n0::n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e12" source="n0::n12" target="n0::n18">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e13" source="n0::n12" target="n0::n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e14" source="n0::n14" target="n0::n17">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e15" source="n0::n15" target="n0::n14">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e16" source="n0::n16" target="n0::n14">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e17" source="n0::n17" target="n0::n13">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e18" source="n0::n20" target="n0::n23">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e19" source="n0::n21" target="n0::n20">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e20" source="n0::n22" target="n0::n20">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e21" source="n0::n23" target="n0::n19">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e0" source="n0::n18" target="n4">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e1" source="n1" target="n0::n0">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e2" source="n2" target="n0::n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e3" source="n0::n6" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d0">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
Before Width: | Height: | Size: 26 KiB |
|
@ -1,274 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
|
||||
<!--Created by yEd 3.13-->
|
||||
<key for="graphml" id="d0" yfiles.type="resources"/>
|
||||
<key for="port" id="d1" yfiles.type="portgraphics"/>
|
||||
<key for="port" id="d2" yfiles.type="portgeometry"/>
|
||||
<key for="port" id="d3" yfiles.type="portuserdata"/>
|
||||
<key attr.name="url" attr.type="string" for="node" id="d4"/>
|
||||
<key attr.name="description" attr.type="string" for="node" id="d5"/>
|
||||
<key for="node" id="d6" yfiles.type="nodegraphics"/>
|
||||
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
|
||||
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
|
||||
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
|
||||
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
|
||||
<graph edgedefault="directed" id="G">
|
||||
<data key="d7"/>
|
||||
<node id="n0">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="130.0" y="200.0"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n1">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="130.0" y="279.0"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n2">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="458.0" y="202.5"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="458.0" y="277.5"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="250.0" y="193.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n5">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="333.0" y="246.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n6">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="292.0" y="246.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n7">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="273.0" y="277.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n8">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="308.0" y="277.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n9">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="308.0" y="216.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<edge id="e0" source="n0" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="270.0" y="222.5"/>
|
||||
<y:Point x="360.0" y="300.0"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="plain"/>
|
||||
<y:BendStyle smoothed="true"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e1" source="n1" target="n2">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="270.0" y="300.0"/>
|
||||
<y:Point x="360.0" y="225.0"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="plain"/>
|
||||
<y:BendStyle smoothed="true"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e2" source="n6" target="n9">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e3" source="n7" target="n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e4" source="n8" target="n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e5" source="n9" target="n5">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d0">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 26 KiB |
|
@ -1,234 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
|
||||
<!--Created by yEd 3.14.2-->
|
||||
<key attr.name="Description" attr.type="string" for="graph" id="d0"/>
|
||||
<key for="port" id="d1" yfiles.type="portgraphics"/>
|
||||
<key for="port" id="d2" yfiles.type="portgeometry"/>
|
||||
<key for="port" id="d3" yfiles.type="portuserdata"/>
|
||||
<key attr.name="url" attr.type="string" for="node" id="d4"/>
|
||||
<key attr.name="description" attr.type="string" for="node" id="d5"/>
|
||||
<key for="node" id="d6" yfiles.type="nodegraphics"/>
|
||||
<key for="graphml" id="d7" yfiles.type="resources"/>
|
||||
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
|
||||
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
|
||||
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
|
||||
<graph edgedefault="directed" id="G">
|
||||
<data key="d0"/>
|
||||
<node id="n0">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="60.72000000000003" width="64.55999999999995" x="-371.08000000000004" y="-960.3600000000001"/>
|
||||
<y:Fill color="#FFCC00" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="26.486054687499973" y="21.293593750000014">T<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="diamond"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n1">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="30.0" x="-585.0" y="-945.0"/>
|
||||
<y:Fill color="#CCFFCC" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="19.890625" x="5.0546875" y="5.93359375">C1<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n2">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="30.0" x="-478.04" y="-945.0"/>
|
||||
<y:Fill color="#99CCFF" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="18.05078125" x="5.974609375" y="5.93359375">S1<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="30.0" x="-122.60000000000014" y="-945.0"/>
|
||||
<y:Fill color="#CCFFCC" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="19.890625" x="5.0546875" y="5.93359375">C2<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="30.0" width="30.0" x="-229.56000000000012" y="-945.0"/>
|
||||
<y:Fill color="#99CCFF" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="18.05078125" x="5.974609375" y="5.93359375">S2<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n5">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="18.715277777777715" width="82.08333333333326" x="-255.60166666666674" y="-879.3576388888889"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="41.587890625" x="20.24772135416663" y="0.29123263888891415">Queue<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n6">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="18.715277777777715" width="82.08333333333326" x="-504.08166666666665" y="-879.3576388888889"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="41.587890625" x="20.24772135416663" y="0.29123263888891415">Queue<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="rectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<edge id="e0" source="n0" target="n4">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="54.8359375" x="6.2584301757812" y="-23.026406250000264">Dispatch<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e1" source="n4" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="44.41796875" x="13.971013183593755" y="-23.66640625000025">Deliver<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e2" source="n1" target="n2">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="94.556640625" x="43.54167968749999" y="-36.46640625000032">Publish QoS1/2<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e3" source="n2" target="n0">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e4" source="n1" target="n0">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-32.24675781249998" ty="0.0">
|
||||
<y:Point x="-464.4087997380702" y="-990.0"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="80.330078125" x="53.093395996093705" y="-79.45582275390632">Publish Qos0<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e5" source="n4" target="n5">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e6" source="n2" target="n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d7">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
|
@ -1,14 +0,0 @@
|
|||
## QoS0 Publish Sequence
|
||||
|
||||
|
||||
```
|
||||
title QoS0 Publish Sequence
|
||||
|
||||
C1->PubSub: Publish QoS0
|
||||
PubSub-->S2: Dispatch QoS0
|
||||
S2-->C2: Deliver QoS0
|
||||
```
|
||||
|
||||
## QoS1 Publish Sequence
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 15 KiB |
|
@ -1,993 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
|
||||
<!--Created by yEd 3.13-->
|
||||
<key for="graphml" id="d0" yfiles.type="resources"/>
|
||||
<key for="port" id="d1" yfiles.type="portgraphics"/>
|
||||
<key for="port" id="d2" yfiles.type="portgeometry"/>
|
||||
<key for="port" id="d3" yfiles.type="portuserdata"/>
|
||||
<key attr.name="url" attr.type="string" for="node" id="d4"/>
|
||||
<key attr.name="description" attr.type="string" for="node" id="d5"/>
|
||||
<key for="node" id="d6" yfiles.type="nodegraphics"/>
|
||||
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
|
||||
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
|
||||
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
|
||||
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
|
||||
<graph edgedefault="directed" id="G">
|
||||
<data key="d7"/>
|
||||
<node id="n0" yfiles.foldertype="group">
|
||||
<data key="d4"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="334.0" width="357.5" x="242.0" y="185.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#F5F5F5" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="node_width" borderDistance="0.0" configuration="CroppingLabel" fontFamily="Dialog" fontSize="18" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="27.19921875" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="357.5" x="0.0" y="153.400390625">emqttd broker cluster</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
<y:GroupNode>
|
||||
<y:Geometry height="50.0" width="50.0" x="180.0" y="140.0"/>
|
||||
<y:Fill color="#F5F5F5" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
|
||||
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
|
||||
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
|
||||
</y:GroupNode>
|
||||
</y:Realizers>
|
||||
</y:ProxyAutoBoundsNode>
|
||||
</data>
|
||||
<graph edgedefault="directed" id="n0:">
|
||||
<node id="n0::n0">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="257.0" y="200.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n1">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="340.0" y="253.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n2">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="299.0" y="253.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="280.0" y="284.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n4">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="315.0" y="284.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n5">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="315.0" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n6">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="459.5" y="200.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n7">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="542.5" y="253.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n8">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="501.5" y="253.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n9">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="482.5" y="284.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n10">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="517.5" y="284.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n11">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="517.5" y="223.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n12">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="257.0" y="380.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n13">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="340.0" y="433.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n14">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="299.0" y="433.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n15">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="280.0" y="464.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n16">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="315.0" y="464.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n17">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="315.0" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n18">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="124.0" width="125.0" x="459.5" y="380.0"/>
|
||||
<y:Fill color="#74C476" transparent="false"/>
|
||||
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
|
||||
<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n19">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="542.5" y="433.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n20">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="501.5" y="433.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n21">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="482.5" y="464.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n22">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="517.5" y="464.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n0::n23">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="17.0" width="16.0" x="517.5" y="403.5"/>
|
||||
<y:Fill color="#FD8D3C" transparent="false"/>
|
||||
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
</graph>
|
||||
</node>
|
||||
<node id="n1">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="257.0" y="596.5"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="37.861328125" x="3.0693359375" y="13.43359375">Client<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n2">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="338.0" y="567.5"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.994140625" x="0.5029296875" y="13.43359375">Sensor<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n3">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="447.5" y="589.5"/>
|
||||
<y:Fill color="#756BB1" transparent="false"/>
|
||||
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.994140625" x="0.5029296875" y="13.43359375">Sensor<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n4">
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="44.0" x="542.5" y="596.5"/>
|
||||
<y:Fill color="#3182BD" transparent="false"/>
|
||||
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="37.861328125" x="3.0693359375" y="13.43359375">Client<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="ellipse"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n5">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="64.0" width="357.5" x="242.0" y="58.0"/>
|
||||
<y:Fill color="#BDBDBD" transparent="false"/>
|
||||
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="109.533203125" x="123.9833984375" y="22.933593750000014">Application Server<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n6">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="85.0" x="71.5" y="239.5"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="28.50390625" x="28.248046875" y="13.43359375">Web<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n7">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="45.0" width="85.0" x="71.5" y="419.5"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="28.50390625" x="28.248046875" y="13.43359375">Web<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n8">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="64.0" width="49.0" x="685.0" y="230.0"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="43.052734375" x="2.9736328125" y="22.93359375">iPhone<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<node id="n9">
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ShapeNode>
|
||||
<y:Geometry height="64.0" width="49.0" x="685.0" y="410.0"/>
|
||||
<y:Fill color="#C0C0C0" transparent="false"/>
|
||||
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="50.58203125" x="-0.791015625" y="22.93359375">Android<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
|
||||
</y:ModelParameter>
|
||||
</y:NodeLabel>
|
||||
<y:Shape type="roundrectangle"/>
|
||||
</y:ShapeNode>
|
||||
</data>
|
||||
</node>
|
||||
<edge id="n0::e0" source="n0::n0" target="n0::n6">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e1" source="n0::n0" target="n0::n12">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e2" source="n0::n2" target="n0::n5">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e3" source="n0::n3" target="n0::n2">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e4" source="n0::n4" target="n0::n2">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e5" source="n0::n5" target="n0::n1">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e6" source="n0::n6" target="n0::n18">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e7" source="n0::n8" target="n0::n11">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e8" source="n0::n9" target="n0::n8">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e9" source="n0::n10" target="n0::n8">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e10" source="n0::n11" target="n0::n7">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e11" source="n0::n12" target="n0::n18">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e12" source="n0::n14" target="n0::n17">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e13" source="n0::n15" target="n0::n14">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e14" source="n0::n16" target="n0::n14">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e15" source="n0::n17" target="n0::n13">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e16" source="n0::n20" target="n0::n23">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e17" source="n0::n21" target="n0::n20">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e18" source="n0::n22" target="n0::n20">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="n0::e19" source="n0::n23" target="n0::n19">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e0" source="n0::n18" target="n4">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e1" source="n2" target="n0::n12">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e2" source="n0::n18" target="n3">
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-22.749321892003195" sy="57.76129269460557" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-31.872099564693826" y="37.92230224609375">MQTT<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e3" source="n5" target="n0::n0">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="-101.25" sy="32.0078125" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#BDBDBD" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="34.626953125" x="-17.3134765625" y="29.92578125">HTTP<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e4" source="n5" target="n0::n6">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="101.25" sy="31.9765625" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#BDBDBD" type="dashed" width="2.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-19.4169921875" y="29.92284393310547">MQTT<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e5" source="n6" target="n0::n0">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="66.671875" x="16.89422607421875" y="-9.06640625">WebSocket<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e6" source="n7" target="n0::n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="66.671875" x="16.89422607421875" y="-9.06640625">WebSocket<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e7" source="n0::n6" target="n8">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="30.8330078125" y="-9.06640625">MQTT<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e8" source="n0::n18" target="n9">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="30.8330078125" y="-9.06640625">MQTT<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e9" source="n1" target="n0::n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
|
||||
<y:Arrows source="standard" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-8.698938402078966" y="-55.90826416015625">MQTT<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d0">
|
||||
<y:Resources/>
|
||||
</data>
|
||||
</graphml>
|
BIN
doc/emqttd.png
Before Width: | Height: | Size: 40 KiB |
|
@ -1,7 +0,0 @@
|
|||
sup(one_for_all)
|
||||
manager
|
||||
pool_sup(one_for_one)
|
||||
worker1
|
||||
worker2
|
||||
...
|
||||
workerN
|
BIN
doc/rfc6455.pdf
19
doc/uuid.md
|
@ -1,19 +0,0 @@
|
|||
## Mongodb ObjectId
|
||||
|
||||
* 4-byte value representing the seconds since the Unix epoch,
|
||||
* 3-byte machine identifier,
|
||||
* 2-byte process id, and
|
||||
* 3-byte counter, starting with a random value.
|
||||
|
||||
## Flake Id
|
||||
|
||||
* 64bits Timestamp
|
||||
* 48bits WorkerId
|
||||
* 16bits Sequence
|
||||
|
||||
## emqttd Id
|
||||
|
||||
* 64bits Timestamp: erlang:now(), erlang:system_time
|
||||
* 48bits (node+pid): Node + Pid -> Integer
|
||||
* 16bits Sequence: PktId
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -28,7 +28,7 @@
|
|||
%%------------------------------------------------------------------------------
|
||||
%% Banner
|
||||
%%------------------------------------------------------------------------------
|
||||
-define(COPYRIGHT, "Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>").
|
||||
-define(COPYRIGHT, "Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-define(LICENSE_MESSAGE, "Licensed under MIT").
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>
|
||||
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit c6a532d49d2b479551bfd3b8d278d40c99e96ae3
|
|
@ -85,9 +85,6 @@
|
|||
{client, [
|
||||
%% Socket is connected, but no 'CONNECT' packet received
|
||||
{idle_timeout, 10} %% seconds
|
||||
%TODO: Network ingoing limit
|
||||
%{ingoing_rate_limit, '64KB/s'}
|
||||
%TODO: Reconnet control
|
||||
]},
|
||||
%% Session
|
||||
{session, [
|
||||
|
@ -111,11 +108,17 @@
|
|||
{expired_after, 48}
|
||||
|
||||
]},
|
||||
%% Session
|
||||
%% Queue
|
||||
{queue, [
|
||||
%% Max queue length. enqueued messages when persistent client disconnected,
|
||||
%% simple | priority
|
||||
{type, simple},
|
||||
|
||||
%% Topic Priority: 0~255, Default is 0
|
||||
%% {priority, [{"topic/1", 10}, {"topic/2", 8}]},
|
||||
|
||||
%% Max queue length. Enqueued messages when persistent client disconnected,
|
||||
%% or inflight window is full.
|
||||
{max_length, 100},
|
||||
{max_length, infinity},
|
||||
|
||||
%% Low-water mark of queued messages
|
||||
{low_watermark, 0.2},
|
||||
|
@ -147,7 +150,7 @@
|
|||
%% PubSub and Router
|
||||
{pubsub, [
|
||||
%% Default should be scheduler numbers
|
||||
%% {pool_size, 8},
|
||||
{pool_size, 8},
|
||||
|
||||
%% Subscription: disc | ram | false
|
||||
{subscription, ram},
|
||||
|
|
|
@ -103,11 +103,17 @@
|
|||
{expired_after, 48}
|
||||
|
||||
]},
|
||||
%% Session
|
||||
%% Queue
|
||||
{queue, [
|
||||
%% Max queue length. enqueued messages when persistent client disconnected,
|
||||
%% simple | priority
|
||||
{type, simple},
|
||||
|
||||
%% Topic Priority: 0~255, Default is 0
|
||||
%% {priority, [{"topic/1", 10}, {"topic/2", 8}]},
|
||||
|
||||
%% Max queue length. Enqueued messages when persistent client disconnected,
|
||||
%% or inflight window is full.
|
||||
{max_length, 100},
|
||||
{max_length, infinity},
|
||||
|
||||
%% Low-water mark of queued messages
|
||||
{low_watermark, 0.2},
|
||||
|
@ -139,7 +145,7 @@
|
|||
%% PubSub and Router
|
||||
{pubsub, [
|
||||
%% Default should be scheduler numbers
|
||||
%% {pool_size, 8},
|
||||
{pool_size, 8},
|
||||
|
||||
%% Subscription: disc | ram | false
|
||||
{subscription, ram},
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
|
||||
-env ERTS_MAX_PORTS 8192
|
||||
|
||||
## Mnesia and SSL will create temporary ets tables.
|
||||
-env ERL_MAX_ETS_TABLES 1024
|
||||
|
||||
## Tweak GC to run more often
|
||||
|
|
|
@ -13,4 +13,3 @@
|
|||
{mod, {emqttd_app, []}},
|
||||
{env, []}
|
||||
]}.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -23,12 +23,16 @@
|
|||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
-module(emqttd).
|
||||
|
||||
-export([start/0, env/1, env/2,
|
||||
start_listeners/0, stop_listeners/0,
|
||||
load_all_mods/0, is_mod_enabled/1,
|
||||
is_running/1]).
|
||||
is_running/1, seed_now/0]).
|
||||
|
||||
%% Utility functions.
|
||||
-export([reg_name/2]).
|
||||
|
||||
-define(MQTT_SOCKOPTS, [
|
||||
binary,
|
||||
|
@ -122,10 +126,8 @@ load_mod({Name, Opts}) ->
|
|||
is_mod_enabled(Name) ->
|
||||
env(modules, Name) =/= undefined.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Is running?
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec is_running(node()) -> boolean().
|
||||
is_running(Node) ->
|
||||
case rpc:call(Node, erlang, whereis, [?APP]) of
|
||||
{badrpc, _} -> false;
|
||||
|
@ -133,3 +135,16 @@ is_running(Node) ->
|
|||
Pid when is_pid(Pid) -> true
|
||||
end.
|
||||
|
||||
-spec reg_name(module(), pos_integer()) -> atom().
|
||||
reg_name(M, Id) when is_atom(M), is_integer(Id) ->
|
||||
list_to_atom(lists:concat([M, "_", Id])).
|
||||
|
||||
seed_now() ->
|
||||
case erlang:function_exported(erlang, timestamp, 0) of
|
||||
true -> %% R18
|
||||
random:seed(erlang:timestamp());
|
||||
false ->
|
||||
%% compress 'now()' warning...
|
||||
random:seed(os:timestamp())
|
||||
end.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -27,6 +27,10 @@
|
|||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-export([passwd_hash/2]).
|
||||
|
||||
-type hash_type() :: plain | md5 | sha | sha256.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Auth behavihour
|
||||
%%%=============================================================================
|
||||
|
@ -53,3 +57,21 @@ behaviour_info(_Other) ->
|
|||
|
||||
-endif.
|
||||
|
||||
%% @doc Password Hash
|
||||
-spec passwd_hash(hash_type(), binary()) -> binary().
|
||||
passwd_hash(plain, Password) ->
|
||||
Password;
|
||||
passwd_hash(md5, Password) ->
|
||||
hexstring(crypto:hash(md5, Password));
|
||||
passwd_hash(sha, Password) ->
|
||||
hexstring(crypto:hash(sha, Password));
|
||||
passwd_hash(sha256, Password) ->
|
||||
hexstring(crypto:hash(sha256, Password)).
|
||||
|
||||
hexstring(<<X:128/big-unsigned-integer>>) ->
|
||||
iolist_to_binary(io_lib:format("~32.16.0b", [X]));
|
||||
hexstring(<<X:160/big-unsigned-integer>>) ->
|
||||
iolist_to_binary(io_lib:format("~40.16.0b", [X]));
|
||||
hexstring(<<X:256/big-unsigned-integer>>) ->
|
||||
iolist_to_binary(io_lib:format("~64.16.0b", [X])).
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -71,6 +71,9 @@ add_user(Username, Password) ->
|
|||
User = #?AUTH_USERNAME_TAB{username = Username, password = hash(Password)},
|
||||
mnesia:transaction(fun mnesia:write/1, [User]).
|
||||
|
||||
add_default_user(Username, Password) ->
|
||||
add_user(bin(Username), bin(Password)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup user by username
|
||||
%% @end
|
||||
|
@ -98,13 +101,16 @@ all_users() ->
|
|||
%%%=============================================================================
|
||||
%%% emqttd_auth callbacks
|
||||
%%%=============================================================================
|
||||
init(Opts) ->
|
||||
init(DefautUsers) ->
|
||||
mnesia:create_table(?AUTH_USERNAME_TAB, [
|
||||
{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, ?AUTH_USERNAME_TAB)}]),
|
||||
mnesia:add_table_copy(?AUTH_USERNAME_TAB, node(), disc_copies),
|
||||
lists:foreach(fun({Username, Password}) ->
|
||||
add_default_user(Username, Password)
|
||||
end, DefautUsers),
|
||||
emqttd_ctl:register_cmd(users, {?MODULE, cli}, []),
|
||||
{ok, Opts}.
|
||||
{ok, []}.
|
||||
|
||||
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
|
||||
{error, "Username undefined"};
|
||||
|
@ -136,8 +142,11 @@ md5_hash(SaltBin, Password) ->
|
|||
erlang:md5(<<SaltBin/binary, Password/binary>>).
|
||||
|
||||
salt() ->
|
||||
{A1,A2,A3} = now(),
|
||||
random:seed(A1, A2, A3),
|
||||
emqttd:seed_now(),
|
||||
Salt = random:uniform(16#ffffffff),
|
||||
<<Salt:32>>.
|
||||
|
||||
bin(A) when is_atom(A) -> bin(atom_to_list(A));
|
||||
bin(L) when is_list(L) -> list_to_binary(L);
|
||||
bin(B) when is_binary(B) -> B.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -172,7 +172,7 @@ dequeue(State = #state{mqueue = MQ}) ->
|
|||
{empty, MQ1} ->
|
||||
State#state{mqueue = MQ1};
|
||||
{{value, Msg}, MQ1} ->
|
||||
handle_info({dispatch, Msg}, State),
|
||||
handle_info({dispatch, Msg#mqtt_message.topic, Msg}, State),
|
||||
dequeue(State#state{mqueue = MQ1})
|
||||
end.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -218,7 +218,7 @@ stop_tick(TRef) ->
|
|||
%%%=============================================================================
|
||||
|
||||
init([]) ->
|
||||
random:seed(os:timestamp()),
|
||||
emqttd:seed_now(),
|
||||
ets:new(?BROKER_TAB, [set, public, named_table]),
|
||||
% Create $SYS Topics
|
||||
emqttd_pubsub:create(topic, <<"$SYS/brokers">>),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -101,7 +101,7 @@ broker(["metrics"]) ->
|
|||
end, lists:sort(emqttd_metrics:all()));
|
||||
|
||||
broker(["pubsub"]) ->
|
||||
Pubsubs = supervisor:which_children(emqttd_pubsub_sup),
|
||||
Pubsubs = supervisor:which_children(emqttd_pubsub_sup:pubsub_pool()),
|
||||
foreach(fun({{_, Id}, Pid, _, _}) ->
|
||||
ProcInfo = erlang:process_info(Pid, ?PROC_INFOKEYS),
|
||||
?PRINT("pubsub: ~w~n", [Id]),
|
||||
|
@ -323,7 +323,7 @@ plugins(_) ->
|
|||
|
||||
bridges(["list"]) ->
|
||||
foreach(fun({{Node, Topic}, _Pid}) ->
|
||||
?PRINT("bridge: ~s ~s~n", [Node, Topic])
|
||||
?PRINT("bridge: ~s--~s-->~s~n", [node(), Topic, Node])
|
||||
end, emqttd_bridge_sup:bridges());
|
||||
|
||||
bridges(["options"]) ->
|
||||
|
@ -449,7 +449,7 @@ trace(_) ->
|
|||
{"trace topic <Topic> off", "stop to trace Topic"}]).
|
||||
|
||||
trace_on(Who, Name, LogFile) ->
|
||||
case emqttd_trace:start_trace({Who, bin(Name)}, LogFile) of
|
||||
case emqttd_trace:start_trace({Who, iolist_to_binary(Name)}, LogFile) of
|
||||
ok ->
|
||||
?PRINT("trace ~s ~s successfully.~n", [Who, Name]);
|
||||
{error, Error} ->
|
||||
|
@ -457,7 +457,7 @@ trace_on(Who, Name, LogFile) ->
|
|||
end.
|
||||
|
||||
trace_off(Who, Name) ->
|
||||
case emqttd_trace:stop_trace({Who, bin(Name)}) of
|
||||
case emqttd_trace:stop_trace({Who, iolist_to_binary(Name)}) of
|
||||
ok ->
|
||||
?PRINT("stop to trace ~s ~s successfully.~n", [Who, Name]);
|
||||
{error, Error} ->
|
||||
|
@ -507,17 +507,16 @@ print({{ClientId, _ClientPid}, SessInfo}) ->
|
|||
awaiting_rel,
|
||||
awaiting_ack,
|
||||
awaiting_comp,
|
||||
created_at,
|
||||
subscriptions],
|
||||
created_at],
|
||||
?PRINT("Session(~s, clean_sess=~s, max_inflight=~w, inflight_queue=~w, "
|
||||
"message_queue=~w, message_dropped=~w, "
|
||||
"awaiting_rel=~w, awaiting_ack=~w, awaiting_comp=~w, "
|
||||
"created_at=~w, subscriptions=~s)~n",
|
||||
"created_at=~w)~n",
|
||||
[ClientId | [format(Key, proplists:get_value(Key, SessInfo)) || Key <- InfoKeys]]).
|
||||
|
||||
print(topic, Topic, Records) ->
|
||||
Nodes = [Node || #mqtt_topic{node = Node} <- Records],
|
||||
?PRINT("~s: on ~p~n", [Topic, Nodes]);
|
||||
?PRINT("~s: ~p~n", [Topic, Nodes]);
|
||||
|
||||
print(subscription, ClientId, Subscriptions) ->
|
||||
TopicTable = [{Topic, Qos} || #mqtt_subscription{topic = Topic, qos = Qos} <- Subscriptions],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -283,7 +283,7 @@ key(counter, Metric) ->
|
|||
%%%=============================================================================
|
||||
|
||||
init([]) ->
|
||||
random:seed(os:timestamp()),
|
||||
emqttd:seed_now(),
|
||||
Metrics = ?SYSTOP_BYTES ++ ?SYSTOP_PACKETS ++ ?SYSTOP_MESSAGES,
|
||||
% Create metrics table
|
||||
ets:new(?METRIC_TAB, [set, public, named_table, {write_concurrency, true}]),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -40,7 +40,7 @@
|
|||
-endif.
|
||||
|
||||
load(Opts) ->
|
||||
Topics = [{bin(Topic), QoS} || {Topic, QoS} <- Opts, ?IS_QOS(QoS)],
|
||||
Topics = [{iolist_to_binary(Topic), QoS} || {Topic, QoS} <- Opts, ?IS_QOS(QoS)],
|
||||
State = #state{topics = Topics, stored = lists:member(stored, Opts)},
|
||||
emqttd_broker:hook('client.connected', {?MODULE, client_connected},
|
||||
{?MODULE, client_connected, [State]}),
|
||||
|
@ -52,7 +52,9 @@ client_connected(?CONNACK_ACCEPT, #mqtt_client{client_id = ClientId,
|
|||
#state{topics = Topics, stored = Stored}) ->
|
||||
Replace = fun(Topic) -> rep(<<"$u">>, Username, rep(<<"$c">>, ClientId, Topic)) end,
|
||||
TopicTable = with_stored(Stored, ClientId, [{Replace(Topic), Qos} || {Topic, Qos} <- Topics]),
|
||||
emqttd_client:subscribe(ClientPid, TopicTable).
|
||||
emqttd_client:subscribe(ClientPid, TopicTable);
|
||||
|
||||
client_connected(_ConnAck, _Client, _State) -> ok.
|
||||
|
||||
with_stored(false, _ClientId, TopicTable) ->
|
||||
TopicTable;
|
||||
|
@ -70,8 +72,3 @@ rep(<<"$u">>, undefined, Topic) ->
|
|||
rep(<<"$u">>, Username, Topic) ->
|
||||
emqttd_topic:feed_var(<<"$u">>, Username, Topic).
|
||||
|
||||
bin(B) when is_binary(B) ->
|
||||
B;
|
||||
bin(S) when is_list(S) ->
|
||||
list_to_binary(S).
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -30,20 +30,21 @@
|
|||
%%%
|
||||
%%% If the broker restarted or crashed, all the messages queued will be gone.
|
||||
%%%
|
||||
%%% Desgin of The Queue:
|
||||
%%% Concept of Message Queue and Inflight Window:
|
||||
%%%
|
||||
%%% |<----------------- Max Len ----------------->|
|
||||
%%% -----------------------------------------------
|
||||
%%% IN -> | Pending Messages | Inflight Window | -> Out
|
||||
%%% IN -> | Messages Queue | Inflight Window | -> Out
|
||||
%%% -----------------------------------------------
|
||||
%%% |<--- Win Size --->|
|
||||
%%% |<--- Win Size --->|
|
||||
%%%
|
||||
%%%
|
||||
%%% 1. Inflight Window to store the messages awaiting for ack.
|
||||
%%% 1. Inflight Window to store the messages delivered and awaiting for puback.
|
||||
%%%
|
||||
%%% 2. Suspend IN messages when the queue is deactive, or inflight windows is full.
|
||||
%%% 2. Enqueue messages when the inflight window is full.
|
||||
%%%
|
||||
%%% 3. If the queue is full, dropped qos0 messages if store_qos0 is true,
|
||||
%%% otherwise dropped the oldest pending one.
|
||||
%%% otherwise dropped the oldest one.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%
|
||||
|
@ -55,96 +56,161 @@
|
|||
|
||||
-include("emqttd_protocol.hrl").
|
||||
|
||||
-export([new/3, name/1,
|
||||
is_empty/1, is_full/1,
|
||||
len/1, max_len/1,
|
||||
in/2, out/1,
|
||||
stats/1]).
|
||||
-export([new/3, type/1, name/1, is_empty/1, len/1, max_len/1, in/2, out/1, stats/1]).
|
||||
|
||||
-define(LOW_WM, 0.2).
|
||||
|
||||
-define(HIGH_WM, 0.6).
|
||||
|
||||
-record(mqueue, {name,
|
||||
q = queue:new(), %% pending queue
|
||||
len = 0, %% current queue len
|
||||
low_wm = ?LOW_WM,
|
||||
high_wm = ?HIGH_WM,
|
||||
max_len = ?MAX_LEN,
|
||||
qos0 = false,
|
||||
dropped = 0,
|
||||
-type priority() :: {iolist(), pos_integer()}.
|
||||
|
||||
-type option() :: {type, simple | priority}
|
||||
| {max_length, pos_integer() | infinity}
|
||||
| {priority, list(priority())}
|
||||
| {low_watermark, float()} %% Low watermark
|
||||
| {high_watermark, float()} %% High watermark
|
||||
| {queue_qos0, boolean()}. %% Queue Qos0?
|
||||
|
||||
-type mqueue_option() :: {max_length, pos_integer()} %% Max queue length
|
||||
| {low_watermark, float()} %% Low watermark
|
||||
| {high_watermark, float()} %% High watermark
|
||||
| {queue_qos0, boolean()}. %% Queue Qos0
|
||||
|
||||
-type stat() :: {max_len, infinity | pos_integer()}
|
||||
| {len, non_neg_integer()}
|
||||
| {dropped, non_neg_integer()}.
|
||||
|
||||
-record(mqueue, {type :: simple | priority,
|
||||
name, q :: queue:queue() | priority_queue:q(),
|
||||
%% priority table
|
||||
pseq = 0, priorities = [],
|
||||
%% len of simple queue
|
||||
len = 0, max_len = ?MAX_LEN,
|
||||
low_wm = ?LOW_WM, high_wm = ?HIGH_WM,
|
||||
qos0 = false, dropped = 0,
|
||||
alarm_fun}).
|
||||
|
||||
-type mqueue() :: #mqueue{}.
|
||||
|
||||
-type mqueue_option() :: {max_length, pos_integer()} %% Max queue length
|
||||
| {low_watermark, float()} %% Low watermark
|
||||
| {high_watermark, float()} %% High watermark
|
||||
| {queue_qos0, boolean()}. %% Queue Qos0
|
||||
-export_type([mqueue/0, priority/0, option/0]).
|
||||
|
||||
-export_type([mqueue/0]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc New Queue.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec new(binary(), list(mqueue_option()), fun()) -> mqueue().
|
||||
-spec new(iolist(), list(mqueue_option()), fun()) -> mqueue().
|
||||
new(Name, Opts, AlarmFun) ->
|
||||
MaxLen = emqttd_opts:g(max_length, Opts, 1000),
|
||||
#mqueue{name = Name,
|
||||
max_len = MaxLen,
|
||||
low_wm = round(MaxLen * emqttd_opts:g(low_watermark, Opts, ?LOW_WM)),
|
||||
high_wm = round(MaxLen * emqttd_opts:g(high_watermark, Opts, ?HIGH_WM)),
|
||||
qos0 = emqttd_opts:g(queue_qos0, Opts, true),
|
||||
alarm_fun = AlarmFun}.
|
||||
Type = emqttd_opts:g(type, Opts, simple),
|
||||
MaxLen = emqttd_opts:g(max_length, Opts, infinity),
|
||||
init_q(#mqueue{type = Type, name = iolist_to_binary(Name),
|
||||
len = 0, max_len = MaxLen,
|
||||
low_wm = low_wm(MaxLen, Opts),
|
||||
high_wm = high_wm(MaxLen, Opts),
|
||||
qos0 = emqttd_opts:g(queue_qos0, Opts, false),
|
||||
alarm_fun = AlarmFun}, Opts).
|
||||
|
||||
init_q(MQ = #mqueue{type = simple}, _Opts) ->
|
||||
MQ#mqueue{q = queue:new()};
|
||||
init_q(MQ = #mqueue{type = priority}, Opts) ->
|
||||
Priorities = emqttd_opts:g(priority, Opts, []),
|
||||
init_p(Priorities, MQ#mqueue{q = priority_queue:new()}).
|
||||
|
||||
init_p([], MQ) ->
|
||||
MQ;
|
||||
init_p([{Topic, P} | L], MQ) ->
|
||||
{_, MQ1} = insert_p(iolist_to_binary(Topic), P, MQ),
|
||||
init_p(L, MQ1).
|
||||
|
||||
insert_p(Topic, P, MQ = #mqueue{priorities = Tab, pseq = Seq}) ->
|
||||
<<PInt:48>> = <<P:8, (erlang:phash2(Topic)):32, Seq:8>>,
|
||||
{PInt, MQ#mqueue{priorities = [{Topic, PInt} | Tab], pseq = Seq + 1}}.
|
||||
|
||||
low_wm(infinity, _Opts) ->
|
||||
infinity;
|
||||
low_wm(MaxLen, Opts) ->
|
||||
round(MaxLen * emqttd_opts:g(low_watermark, Opts, ?LOW_WM)).
|
||||
|
||||
high_wm(infinity, _Opts) ->
|
||||
infinity;
|
||||
high_wm(MaxLen, Opts) ->
|
||||
round(MaxLen * emqttd_opts:g(high_watermark, Opts, ?HIGH_WM)).
|
||||
|
||||
-spec name(mqueue()) -> iolist().
|
||||
name(#mqueue{name = Name}) ->
|
||||
Name.
|
||||
|
||||
is_empty(#mqueue{len = 0}) -> true;
|
||||
is_empty(_MQ) -> false.
|
||||
-spec type(mqueue()) -> atom().
|
||||
type(#mqueue{type = Type}) ->
|
||||
Type.
|
||||
|
||||
is_full(#mqueue{len = Len, max_len = MaxLen})
|
||||
when Len =:= MaxLen -> true;
|
||||
is_full(_MQ) -> false.
|
||||
is_empty(#mqueue{type = simple, len = Len}) -> Len =:= 0;
|
||||
is_empty(#mqueue{type = priority, q = Q}) -> priority_queue:is_empty(Q).
|
||||
|
||||
len(#mqueue{len = Len}) -> Len.
|
||||
len(#mqueue{type = simple, len = Len}) -> Len;
|
||||
len(#mqueue{type = priority, q = Q}) -> priority_queue:len(Q).
|
||||
|
||||
max_len(#mqueue{max_len= MaxLen}) -> MaxLen.
|
||||
|
||||
stats(#mqueue{max_len = MaxLen, len = Len, dropped = Dropped}) ->
|
||||
[{max_len, MaxLen}, {len, Len}, {dropped, Dropped}].
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Queue one message.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Stats of the mqueue
|
||||
-spec stats(mqueue()) -> [stat()].
|
||||
stats(#mqueue{type = Type, q = Q, max_len = MaxLen, len = Len, dropped = Dropped}) ->
|
||||
[{len, case Type of
|
||||
simple -> Len;
|
||||
priority -> priority_queue:len(Q)
|
||||
end} | [{max_len, MaxLen}, {dropped, Dropped}]].
|
||||
|
||||
%% @doc Enqueue a message.
|
||||
-spec in(mqtt_message(), mqueue()) -> mqueue().
|
||||
%% drop qos0
|
||||
in(#mqtt_message{qos = ?QOS_0}, MQ = #mqueue{qos0 = false}) ->
|
||||
MQ;
|
||||
|
||||
%% simply drop the oldest one if queue is full, improve later
|
||||
in(Msg, MQ = #mqueue{q = Q, len = Len, max_len = MaxLen, dropped = Dropped})
|
||||
when Len =:= MaxLen ->
|
||||
{{value, _OldMsg}, Q2} = queue:out(Q),
|
||||
%lager:error("MQueue(~s) drop ~s", [Name, emqttd_message:format(OldMsg)]),
|
||||
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len, max_len = infinity}) ->
|
||||
MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1};
|
||||
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len, max_len = MaxLen, dropped = Dropped})
|
||||
when Len >= MaxLen ->
|
||||
{{value, _Old}, Q2} = queue:out(Q),
|
||||
MQ#mqueue{q = queue:in(Msg, Q2), dropped = Dropped +1};
|
||||
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len}) ->
|
||||
maybe_set_alarm(MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1});
|
||||
|
||||
in(Msg, MQ = #mqueue{q = Q, len = Len}) ->
|
||||
maybe_set_alarm(MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1}).
|
||||
in(Msg = #mqtt_message{topic = Topic}, MQ = #mqueue{type = priority, q = Q,
|
||||
priorities = Priorities,
|
||||
max_len = infinity}) ->
|
||||
case lists:keysearch(Topic, 1, Priorities) of
|
||||
{value, {_, Pri}} ->
|
||||
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q)};
|
||||
false ->
|
||||
{Pri, MQ1} = insert_p(Topic, 0, MQ),
|
||||
MQ1#mqueue{q = priority_queue:in(Msg, Pri, Q)}
|
||||
end;
|
||||
in(Msg = #mqtt_message{topic = Topic}, MQ = #mqueue{type = priority, q = Q,
|
||||
priorities = Priorities,
|
||||
max_len = MaxLen}) ->
|
||||
case lists:keysearch(Topic, 1, Priorities) of
|
||||
{value, {_, Pri}} ->
|
||||
case priority_queue:plen(Pri, Q) >= MaxLen of
|
||||
true ->
|
||||
{_, Q1} = priority_queue:out(Pri, Q),
|
||||
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q1)};
|
||||
false ->
|
||||
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q)}
|
||||
end;
|
||||
false ->
|
||||
{Pri, MQ1} = insert_p(Topic, 0, MQ),
|
||||
MQ1#mqueue{q = priority_queue:in(Msg, Pri, Q)}
|
||||
end.
|
||||
|
||||
out(MQ = #mqueue{len = 0}) ->
|
||||
out(MQ = #mqueue{type = simple, len = 0}) ->
|
||||
{empty, MQ};
|
||||
|
||||
out(MQ = #mqueue{q = Q, len = Len}) ->
|
||||
{Result, Q2} = queue:out(Q),
|
||||
{Result, maybe_clear_alarm(MQ#mqueue{q = Q2, len = Len - 1})}.
|
||||
out(MQ = #mqueue{type = simple, q = Q, len = Len, max_len = infinity}) ->
|
||||
{R, Q2} = queue:out(Q),
|
||||
{R, MQ#mqueue{q = Q2, len = Len - 1}};
|
||||
out(MQ = #mqueue{type = simple, q = Q, len = Len}) ->
|
||||
{R, Q2} = queue:out(Q),
|
||||
{R, maybe_clear_alarm(MQ#mqueue{q = Q2, len = Len - 1})};
|
||||
out(MQ = #mqueue{type = priority, q = Q}) ->
|
||||
{R, Q2} = priority_queue:out(Q),
|
||||
{R, MQ#mqueue{q = Q2}}.
|
||||
|
||||
maybe_set_alarm(MQ = #mqueue{name = Name, len = Len, high_wm = HighWM, alarm_fun = AlarmFun})
|
||||
when Len > HighWM ->
|
||||
Alarm = #mqtt_alarm{id = list_to_binary(["queue_high_watermark.", Name]),
|
||||
Alarm = #mqtt_alarm{id = iolist_to_binary(["queue_high_watermark.", Name]),
|
||||
severity = warning,
|
||||
title = io_lib:format("Queue ~s high-water mark", [Name]),
|
||||
summary = io_lib:format("queue len ~p > high_watermark ~p", [Len, HighWM])},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -53,10 +53,7 @@ start_link() ->
|
|||
%%%=============================================================================
|
||||
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(Pool, Id) ->
|
||||
gen_server:start_link({local, name(Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
name(Id) ->
|
||||
list_to_atom(lists:concat([?MODULE, "_", integer_to_list(Id)])).
|
||||
gen_server:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Submit work to pooler
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -19,7 +19,7 @@
|
|||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc emqttd pubsub
|
||||
%%% @doc PubSub
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
@ -43,9 +43,7 @@
|
|||
-export([start_link/4]).
|
||||
|
||||
-export([create/2, lookup/2, subscribe/1, subscribe/2,
|
||||
unsubscribe/1, unsubscribe/2, publish/1, delete/2]).
|
||||
|
||||
%% Subscriptions API
|
||||
publish/1, unsubscribe/1, unsubscribe/2, delete/2]).
|
||||
|
||||
%% Local node
|
||||
-export([match/1]).
|
||||
|
@ -62,8 +60,6 @@
|
|||
|
||||
-define(ROUTER, emqttd_router).
|
||||
|
||||
-define(HELPER, emqttd_pubsub_helper).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Mnesia callbacks
|
||||
%%%=============================================================================
|
||||
|
@ -123,26 +119,19 @@ cache_env(Key) ->
|
|||
%%% API
|
||||
%%%=============================================================================
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start one pubsub server
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(Pool, Id, StatsFun, Opts) -> {ok, pid()} | ignore | {error, any()} when
|
||||
Pool :: atom(),
|
||||
Id :: pos_integer(),
|
||||
StatsFun :: fun(),
|
||||
StatsFun :: fun((atom()) -> any()),
|
||||
Opts :: list(tuple()).
|
||||
start_link(Pool, Id, StatsFun, Opts) ->
|
||||
gen_server2:start_link({local, name(Id)}, ?MODULE, [Pool, Id, StatsFun, Opts], []).
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)},
|
||||
?MODULE, [Pool, Id, StatsFun, Opts], []).
|
||||
|
||||
name(Id) ->
|
||||
list_to_atom("emqttd_pubsub_" ++ integer_to_list(Id)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Create Topic or Subscription.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec create(topic | subscription, binary() | {binary(), binary(), mqtt_qos()}) -> ok | {error, any()}.
|
||||
-spec create(topic, emqttd_topic:topic()) -> ok | {error, any()};
|
||||
(subscription, {binary(), binary(), mqtt_qos()}) -> ok | {error, any()}.
|
||||
create(topic, Topic) when is_binary(Topic) ->
|
||||
Record = #mqtt_topic{topic = Topic, node = node()},
|
||||
case mnesia:transaction(fun add_topic/1, [Record]) of
|
||||
|
@ -151,39 +140,33 @@ create(topic, Topic) when is_binary(Topic) ->
|
|||
end;
|
||||
|
||||
create(subscription, {SubId, Topic, Qos}) when is_binary(SubId) andalso is_binary(Topic) ->
|
||||
case mnesia:transaction(fun add_subscription/2, [SubId, {Topic, Qos}]) of
|
||||
case mnesia:transaction(fun add_subscription/2, [SubId, {Topic, ?QOS_I(Qos)}]) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, Error} -> {error, Error}
|
||||
end.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup Topic or Subscription.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup(topic | subscription, binary()) -> list().
|
||||
lookup(topic, Topic) ->
|
||||
-spec lookup(topic, emqttd_topic:topic()) -> list(mqtt_topic());
|
||||
(subscription, binary()) -> list(mqtt_subscription()).
|
||||
lookup(topic, Topic) when is_binary(Topic) ->
|
||||
mnesia:dirty_read(topic, Topic);
|
||||
|
||||
lookup(subscription, ClientId) ->
|
||||
mnesia:dirty_read(subscription, ClientId).
|
||||
lookup(subscription, SubId) when is_binary(SubId) ->
|
||||
mnesia:dirty_read(subscription, SubId).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Delete Topic or Subscription.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec delete(topic, emqttd_topic:topic()) -> ok | {error, any()};
|
||||
(subscription, binary() | {binary(), emqttd_topic:topic()}) -> ok.
|
||||
delete(topic, _Topic) ->
|
||||
{error, unsupported};
|
||||
|
||||
delete(subscription, ClientId) when is_binary(ClientId) ->
|
||||
mnesia:dirty_delete({subscription, ClientId});
|
||||
delete(subscription, SubId) when is_binary(SubId) ->
|
||||
mnesia:dirty_delete({subscription, SubId});
|
||||
|
||||
delete(subscription, {ClientId, Topic}) when is_binary(ClientId) ->
|
||||
mnesia:async_dirty(fun remove_subscriptions/2, [ClientId, [Topic]]).
|
||||
delete(subscription, {SubId, Topic}) when is_binary(SubId) andalso is_binary(Topic) ->
|
||||
mnesia:async_dirty(fun remove_subscriptions/2, [SubId, [Topic]]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Subscribe Topics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec subscribe({Topic, Qos} | list({Topic, Qos})) ->
|
||||
{ok, Qos | list(Qos)} | {error, any()} when
|
||||
Topic :: binary(),
|
||||
|
@ -206,34 +189,28 @@ subscribe(ClientId, TopicTable) when is_binary(ClientId) andalso is_list(TopicTa
|
|||
fixqos(TopicTable) ->
|
||||
[{Topic, ?QOS_I(Qos)} || {Topic, Qos} <- TopicTable].
|
||||
|
||||
call(Request) ->
|
||||
PubSub = gproc_pool:pick_worker(pubsub, self()),
|
||||
gen_server2:call(PubSub, Request, infinity).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Unsubscribe Topic or Topics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec unsubscribe(binary() | list(binary())) -> ok.
|
||||
-spec unsubscribe(emqttd_topic:topic() | list(emqttd_topic:topic())) -> ok.
|
||||
unsubscribe(Topic) when is_binary(Topic) ->
|
||||
unsubscribe([Topic]);
|
||||
unsubscribe(Topics = [Topic|_]) when is_binary(Topic) ->
|
||||
cast({unsubscribe, {undefined, self()}, Topics}).
|
||||
|
||||
-spec unsubscribe(binary(), binary() | list(binary())) -> ok.
|
||||
-spec unsubscribe(binary(), emqttd_topic:topic() | list(emqttd_topic:topic())) -> ok.
|
||||
unsubscribe(ClientId, Topic) when is_binary(ClientId) andalso is_binary(Topic) ->
|
||||
unsubscribe(ClientId, [Topic]);
|
||||
unsubscribe(ClientId, Topics = [Topic|_]) when is_binary(Topic) ->
|
||||
cast({unsubscribe, {ClientId, self()}, Topics}).
|
||||
|
||||
cast(Msg) ->
|
||||
PubSub = gproc_pool:pick_worker(pubsub, self()),
|
||||
gen_server2:cast(PubSub, Msg).
|
||||
call(Request) ->
|
||||
gen_server2:call(pick(self()), Request, infinity).
|
||||
|
||||
cast(Msg) ->
|
||||
gen_server2:cast(pick(self()), Msg).
|
||||
|
||||
pick(Self) -> gproc_pool:pick_worker(pubsub, Self).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Publish to cluster nodes
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec publish(Msg :: mqtt_message()) -> ok.
|
||||
publish(Msg = #mqtt_message{from = From}) ->
|
||||
trace(publish, From, Msg),
|
||||
|
@ -257,35 +234,41 @@ publish(To, Msg) ->
|
|||
end
|
||||
end, match(To)).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Match Topic Name with Topic Filters
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec match(binary()) -> [mqtt_topic()].
|
||||
-spec match(emqttd_topic:topic()) -> [mqtt_topic()].
|
||||
match(To) ->
|
||||
MatchedTopics = mnesia:async_dirty(fun emqttd_trie:match/1, [To]),
|
||||
%% ets:lookup for topic table will be replicated.
|
||||
%% ets:lookup for topic table will be replicated to all nodes.
|
||||
lists:append([ets:lookup(topic, Topic) || Topic <- MatchedTopics]).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
|
||||
init([Pool, Id, StatsFun, Opts]) ->
|
||||
?ROUTER:init(Opts),
|
||||
init([Pool, Id, StatsFun, _Opts]) ->
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
{ok, #state{pool = Pool, id = Id, statsfun = StatsFun}}.
|
||||
|
||||
handle_call({subscribe, {SubId, SubPid}, TopicTable}, _From,
|
||||
State = #state{statsfun = StatsFun}) ->
|
||||
|
||||
%% Monitor SubPid first
|
||||
try_monitor(SubPid),
|
||||
|
||||
%% Topics
|
||||
Topics = [Topic || {Topic, _Qos} <- TopicTable],
|
||||
|
||||
%% Add routes first
|
||||
?ROUTER:add_routes(Topics, SubPid),
|
||||
NewTopics = Topics -- reverse_routes(SubPid),
|
||||
|
||||
%% Insert topic records to global topic table
|
||||
Records = [#mqtt_topic{topic = Topic, node = node()} || Topic <- Topics],
|
||||
%% Add routes
|
||||
?ROUTER:add_routes(NewTopics, SubPid),
|
||||
|
||||
insert_reverse_routes(SubPid, NewTopics),
|
||||
|
||||
StatsFun(reverse_route),
|
||||
|
||||
%% Insert topic records to mnesia
|
||||
Records = [#mqtt_topic{topic = Topic, node = node()} || Topic <- NewTopics],
|
||||
|
||||
case mnesia:transaction(fun add_topics/1, [Records]) of
|
||||
{atomic, _} ->
|
||||
|
@ -307,9 +290,14 @@ handle_call(Req, _From, State) ->
|
|||
?UNEXPECTED_REQ(Req, State).
|
||||
|
||||
handle_cast({unsubscribe, {SubId, SubPid}, Topics}, State = #state{statsfun = StatsFun}) ->
|
||||
|
||||
%% Delete routes first
|
||||
?ROUTER:delete_routes(Topics, SubPid),
|
||||
|
||||
delete_reverse_routes(SubPid, Topics),
|
||||
|
||||
StatsFun(reverse_route),
|
||||
|
||||
%% Remove subscriptions
|
||||
if_subscription(
|
||||
fun(_) ->
|
||||
|
@ -317,19 +305,21 @@ handle_cast({unsubscribe, {SubId, SubPid}, Topics}, State = #state{statsfun = St
|
|||
emqttd_pooler:async_submit({mnesia, async_dirty, Args}),
|
||||
StatsFun(subscription)
|
||||
end),
|
||||
|
||||
{noreply, State};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
?UNEXPECTED_MSG(Msg, State).
|
||||
|
||||
handle_info({'DOWN', _Mon, _Type, DownPid, _Info}, State) ->
|
||||
handle_info({'DOWN', _Mon, _Type, DownPid, _Info}, State = #state{statsfun = StatsFun}) ->
|
||||
|
||||
Routes = ?ROUTER:lookup_routes(DownPid),
|
||||
Topics = reverse_routes(DownPid),
|
||||
|
||||
%% Delete all routes of the process
|
||||
?ROUTER:delete_routes(DownPid),
|
||||
?ROUTER:delete_routes(Topics, DownPid),
|
||||
|
||||
?HELPER:aging([Topic || Topic <- Routes, not ?ROUTER:has_route(Topic)]),
|
||||
delete_reverse_routes(DownPid),
|
||||
|
||||
StatsFun(reverse_route),
|
||||
|
||||
{noreply, State, hibernate};
|
||||
|
||||
|
@ -395,6 +385,31 @@ remove_subscriptions(SubId, Topics) ->
|
|||
delete_subscription(Record) ->
|
||||
mnesia:delete_object(subscription, Record, write).
|
||||
|
||||
reverse_routes(SubPid) ->
|
||||
case ets:member(reverse_route, SubPid) of
|
||||
true ->
|
||||
try ets:lookup_element(reverse_route, SubPid, 2) catch error:badarg -> [] end;
|
||||
false ->
|
||||
[]
|
||||
end.
|
||||
|
||||
insert_reverse_routes(SubPid, Topics) ->
|
||||
ets:insert(reverse_route, [{SubPid, Topic} || Topic <- Topics]).
|
||||
|
||||
delete_reverse_routes(SubPid, Topics) ->
|
||||
lists:foreach(fun(Topic) ->
|
||||
ets:delete_object(reverse_route, {SubPid, Topic})
|
||||
end, Topics).
|
||||
|
||||
delete_reverse_routes(SubPid) ->
|
||||
ets:delete(reverse_route, SubPid).
|
||||
|
||||
try_monitor(SubPid) ->
|
||||
case ets:member(reverse_route, SubPid) of
|
||||
true -> ignore;
|
||||
false -> erlang:monitor(process, SubPid)
|
||||
end.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Trace Functions
|
||||
%%%=============================================================================
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -19,176 +19,66 @@
|
|||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc PubSub Route Aging Helper
|
||||
%%% @doc PubSub Helper.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_pubsub_helper).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
-behaviour(gen_server).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_internal.hrl").
|
||||
|
||||
%% API Function Exports
|
||||
-export([start_link/2, aging/1]).
|
||||
-export([start_link/1]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile(export_all).
|
||||
-endif.
|
||||
|
||||
-record(aging, {topics, time, tref}).
|
||||
|
||||
-record(state, {aging :: #aging{}, statsfun}).
|
||||
-record(state, {statsfun}).
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
|
||||
-define(ROUTER, emqttd_router).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% API
|
||||
%%%=============================================================================
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start pubsub helper.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(fun(), list(tuple())) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(StatsFun, Opts) ->
|
||||
gen_server2:start_link({local, ?SERVER}, ?MODULE, [StatsFun, Opts], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Aging topics
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec aging(list(binary())) -> ok.
|
||||
aging(Topics) ->
|
||||
gen_server2:cast(?SERVER, {aging, Topics}).
|
||||
%% @doc Start PubSub Helper.
|
||||
-spec start_link(fun()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(StatsFun) ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [StatsFun], []).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%=============================================================================
|
||||
|
||||
init([StatsFun, Opts]) ->
|
||||
init([StatsFun]) ->
|
||||
mnesia:subscribe(system),
|
||||
|
||||
AgingSecs = proplists:get_value(route_aging, Opts, 5),
|
||||
|
||||
%% Aging Timer
|
||||
{ok, AgingTref} = start_tick(AgingSecs div 2),
|
||||
|
||||
{ok, #state{aging = #aging{topics = dict:new(),
|
||||
time = AgingSecs,
|
||||
tref = AgingTref},
|
||||
statsfun = StatsFun}}.
|
||||
|
||||
start_tick(Secs) ->
|
||||
timer:send_interval(timer:seconds(Secs), {clean, aged}).
|
||||
{ok, #state{statsfun = StatsFun}}.
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
?UNEXPECTED_REQ(Req, State).
|
||||
|
||||
handle_cast({aging, Topics}, State = #state{aging = Aging}) ->
|
||||
#aging{topics = Dict} = Aging,
|
||||
TS = emqttd_util:now_to_secs(),
|
||||
Dict1 =
|
||||
lists:foldl(fun(Topic, Acc) ->
|
||||
case dict:find(Topic, Acc) of
|
||||
{ok, _} -> Acc;
|
||||
error -> dict:store(Topic, TS, Acc)
|
||||
end
|
||||
end, Dict, Topics),
|
||||
{noreply, State#state{aging = Aging#aging{topics = Dict1}}};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
?UNEXPECTED_MSG(Msg, State).
|
||||
|
||||
handle_info({clean, aged}, State = #state{aging = Aging}) ->
|
||||
|
||||
#aging{topics = Dict, time = Time} = Aging,
|
||||
|
||||
ByTime = emqttd_util:now_to_secs() - Time,
|
||||
|
||||
Dict1 = try_clean(ByTime, dict:to_list(Dict)),
|
||||
|
||||
NewAging = Aging#aging{topics = dict:from_list(Dict1)},
|
||||
|
||||
noreply(State#state{aging = NewAging});
|
||||
|
||||
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
|
||||
%% mnesia master?
|
||||
%% TODO: mnesia master?
|
||||
Pattern = #mqtt_topic{_ = '_', node = Node},
|
||||
F = fun() ->
|
||||
[mnesia:delete_object(topic, R, write) ||
|
||||
R <- mnesia:match_object(topic, Pattern, write)]
|
||||
end,
|
||||
mnesia:async_dirty(F),
|
||||
noreply(State);
|
||||
mnesia:transaction(F), noreply(State);
|
||||
|
||||
handle_info(Info, State) ->
|
||||
?UNEXPECTED_INFO(Info, State).
|
||||
|
||||
terminate(_Reason, #state{aging = #aging{tref = TRef}}) ->
|
||||
timer:cancel(TRef).
|
||||
terminate(_Reason, _State) ->
|
||||
mnesia:unsubscribe(system).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal Functions
|
||||
%%%=============================================================================
|
||||
|
||||
noreply(State = #state{statsfun = StatsFun}) ->
|
||||
StatsFun(topic),
|
||||
{noreply, State, hibernate}.
|
||||
|
||||
try_clean(ByTime, List) ->
|
||||
try_clean(ByTime, List, []).
|
||||
|
||||
try_clean(_ByTime, [], Acc) ->
|
||||
Acc;
|
||||
|
||||
try_clean(ByTime, [{Topic, TS} | Left], Acc) ->
|
||||
case ?ROUTER:has_route(Topic) of
|
||||
false ->
|
||||
try_clean2(ByTime, {Topic, TS}, Left, Acc);
|
||||
true ->
|
||||
try_clean(ByTime, Left, Acc)
|
||||
end.
|
||||
|
||||
try_clean2(ByTime, {Topic, TS}, Left, Acc) when TS > ByTime ->
|
||||
try_clean(ByTime, Left, [{Topic, TS}|Acc]);
|
||||
|
||||
try_clean2(ByTime, {Topic, _TS}, Left, Acc) ->
|
||||
TopicR = #mqtt_topic{topic = Topic, node = node()},
|
||||
mnesia:transaction(fun try_remove_topic/1, [TopicR]),
|
||||
try_clean(ByTime, Left, Acc).
|
||||
|
||||
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
|
||||
%% Lock topic first
|
||||
case mnesia:wread({topic, Topic}) of
|
||||
[] -> ok;
|
||||
[TopicR] ->
|
||||
if_no_route(Topic, fun() ->
|
||||
%% Remove topic and trie
|
||||
mnesia:delete_object(topic, TopicR, write),
|
||||
emqttd_trie:delete(Topic)
|
||||
end);
|
||||
_More ->
|
||||
if_no_route(Topic, fun() ->
|
||||
%% Remove topic
|
||||
mnesia:delete_object(topic, TopicR, write)
|
||||
end)
|
||||
end.
|
||||
|
||||
if_no_route(Topic, Fun) ->
|
||||
case ?ROUTER:has_route(Topic) of
|
||||
true -> ok;
|
||||
false -> Fun()
|
||||
end.
|
||||
StatsFun(topic), {noreply, State}.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -19,7 +19,7 @@
|
|||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc PubSub Supervisor
|
||||
%%% @doc PubSub Supervisor.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
@ -31,8 +31,10 @@
|
|||
|
||||
-define(HELPER, emqttd_pubsub_helper).
|
||||
|
||||
-define(CONCURRENCY_OPTS, [{read_concurrency, true}, {write_concurrency, true}]).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
-export([start_link/0, pubsub_pool/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
@ -40,24 +42,57 @@
|
|||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, [emqttd_broker:env(pubsub)]).
|
||||
|
||||
init([Opts]) ->
|
||||
pubsub_pool() ->
|
||||
hd([Pid|| {pubsub_pool, Pid, _, _} <- supervisor:which_children(?MODULE)]).
|
||||
|
||||
init([Env]) ->
|
||||
%% Create tabs
|
||||
create_tab(route), create_tab(reverse_route),
|
||||
|
||||
%% PubSub Helper
|
||||
Helper = {helper, {?HELPER, start_link, [fun stats/1, Opts]},
|
||||
Helper = {helper, {?HELPER, start_link, [fun setstats/1]},
|
||||
permanent, infinity, worker, [?HELPER]},
|
||||
|
||||
%% Router Pool Sup
|
||||
RouterMFA = {emqttd_router, start_link, [fun setstats/1, Env]},
|
||||
%% Pool_size / 2
|
||||
RouterSup = emqttd_pool_sup:spec(router_pool, [router, hash, pool_size(Env) div 2, RouterMFA]),
|
||||
|
||||
%% PubSub Pool Sup
|
||||
MFA = {emqttd_pubsub, start_link, [fun stats/1, Opts]},
|
||||
PoolSup = emqttd_pool_sup:spec([pubsub, hash, pool_size(Opts), MFA]),
|
||||
{ok, {{one_for_all, 10, 60}, [Helper, PoolSup]}}.
|
||||
PubSubMFA = {emqttd_pubsub, start_link, [fun setstats/1, Env]},
|
||||
PubSubSup = emqttd_pool_sup:spec(pubsub_pool, [pubsub, hash, pool_size(Env), PubSubMFA]),
|
||||
|
||||
pool_size(Opts) ->
|
||||
{ok, {{one_for_all, 10, 60}, [Helper, RouterSup, PubSubSup]}}.
|
||||
|
||||
create_tab(route) ->
|
||||
%% Route Table: Topic -> Pid1, Pid2, ..., PidN
|
||||
%% duplicate_bag: o(1) insert
|
||||
ensure_tab(route, [public, named_table, duplicate_bag | ?CONCURRENCY_OPTS]);
|
||||
|
||||
create_tab(reverse_route) ->
|
||||
%% Reverse Route Table: Pid -> Topic1, Topic2, ..., TopicN
|
||||
ensure_tab(reverse_route, [public, named_table, bag | ?CONCURRENCY_OPTS]).
|
||||
|
||||
ensure_tab(Tab, Opts) ->
|
||||
case ets:info(Tab, name) of
|
||||
undefined -> ets:new(Tab, Opts);
|
||||
_ -> ok
|
||||
end.
|
||||
|
||||
pool_size(Env) ->
|
||||
Schedulers = erlang:system_info(schedulers),
|
||||
proplists:get_value(pool_size, Opts, Schedulers).
|
||||
proplists:get_value(pool_size, Env, Schedulers).
|
||||
|
||||
stats(topic) ->
|
||||
emqttd_stats:setstats('topics/count', 'topics/max',
|
||||
mnesia:table_info(topic, size));
|
||||
stats(subscription) ->
|
||||
setstats(route) ->
|
||||
emqttd_stats:setstat('routes/count', ets:info(route, size));
|
||||
|
||||
setstats(reverse_route) ->
|
||||
emqttd_stats:setstat('routes/reverse', ets:info(reverse_route, size));
|
||||
|
||||
setstats(topic) ->
|
||||
emqttd_stats:setstats('topics/count', 'topics/max', mnesia:table_info(topic, size));
|
||||
|
||||
setstats(subscription) ->
|
||||
emqttd_stats:setstats('subscriptions/count', 'subscriptions/max',
|
||||
mnesia:table_info(subscription, size)).
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -19,167 +19,267 @@
|
|||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc MQTT Message Router on Local Node
|
||||
%%%
|
||||
%%% Route Table:
|
||||
%%%
|
||||
%%% Topic -> Pid1, Pid2, ...
|
||||
%%%
|
||||
%%% Reverse Route Table:
|
||||
%%%
|
||||
%%% Pid -> Topic1, Topic2, ...
|
||||
%%%
|
||||
%%% @end
|
||||
%%% @doc Message Router on local node.
|
||||
%%%
|
||||
%%% @author Feng Lee <feng@emqtt.io>
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_router).
|
||||
|
||||
-behaviour(gen_server2).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-include("emqttd_protocol.hrl").
|
||||
|
||||
-export([init/1, route/2, lookup_routes/1, has_route/1,
|
||||
add_routes/2, delete_routes/1, delete_routes/2]).
|
||||
-include("emqttd_internal.hrl").
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile(export_all).
|
||||
-endif.
|
||||
-export([start_link/4]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Create route tables.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
init(_Opts) ->
|
||||
TabOpts = [bag, public, named_table,
|
||||
{write_concurrency, true}],
|
||||
%% Route Table: Topic -> {Pid, QoS}
|
||||
%% Route Shard: {Topic, Shard} -> {Pid, QoS}
|
||||
ensure_tab(route, TabOpts),
|
||||
%% Route API
|
||||
-export([route/2]).
|
||||
|
||||
%% Reverse Route Table: Pid -> {Topic, QoS}
|
||||
ensure_tab(reverse_route, TabOpts).
|
||||
%% Route Admin API
|
||||
-export([add_route/2, lookup_routes/1, has_route/1, delete_route/2]).
|
||||
|
||||
ensure_tab(Tab, Opts) ->
|
||||
case ets:info(Tab, name) of
|
||||
undefined ->
|
||||
ets:new(Tab, Opts);
|
||||
_ ->
|
||||
ok
|
||||
end.
|
||||
%% Batch API
|
||||
-export([add_routes/2, delete_routes/2]).
|
||||
|
||||
-ifdef(TEST).
|
||||
destory() ->
|
||||
ets:delete(route),
|
||||
ets:delete(reverse_route).
|
||||
-endif.
|
||||
%% For Test
|
||||
-export([stop/1]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Add Routes.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec add_routes(list(binary()), pid()) -> ok.
|
||||
add_routes(Topics, Pid) when is_pid(Pid) ->
|
||||
with_stats(fun() ->
|
||||
case lookup_routes(Pid) of
|
||||
[] ->
|
||||
erlang:monitor(process, Pid),
|
||||
insert_routes(Topics, Pid);
|
||||
InEts ->
|
||||
insert_routes(Topics -- InEts, Pid)
|
||||
end
|
||||
end).
|
||||
%% gen_server Callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Lookup Routes
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec lookup_routes(pid()) -> list(binary()).
|
||||
lookup_routes(Pid) when is_pid(Pid) ->
|
||||
[Topic || {_, Topic} <- ets:lookup(reverse_route, Pid)].
|
||||
-record(aging, {topics, time, tref}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Has Route?
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec has_route(binary()) -> boolean().
|
||||
has_route(Topic) ->
|
||||
ets:member(route, Topic).
|
||||
-record(state, {pool, id, statsfun, aging :: #aging{}}).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Delete Routes
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec delete_routes(list(binary()), pid()) -> ok.
|
||||
delete_routes(Topics, Pid) ->
|
||||
with_stats(fun() ->
|
||||
Routes = [{Topic, Pid} || Topic <- Topics],
|
||||
lists:foreach(fun delete_route/1, Routes)
|
||||
end).
|
||||
%% @doc Start a local router.
|
||||
-spec start_link(atom(), pos_integer(), fun((atom()) -> ok), list()) -> {ok, pid()} | {error, any()}.
|
||||
start_link(Pool, Id, StatsFun, Env) ->
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE,Id)},
|
||||
?MODULE, [Pool, Id, StatsFun, Env], []).
|
||||
|
||||
-spec delete_routes(pid()) -> ok.
|
||||
delete_routes(Pid) when is_pid(Pid) ->
|
||||
with_stats(fun() ->
|
||||
Routes = [{Topic, Pid} || Topic <- lookup_routes(Pid)],
|
||||
ets:delete(reverse_route, Pid),
|
||||
lists:foreach(fun delete_route_only/1, Routes)
|
||||
end).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Route Message on Local Node.
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec route(binary(), mqtt_message()) -> non_neg_integer().
|
||||
%% @doc Route Message on the local node.
|
||||
-spec route(emqttd_topic:topic(), mqtt_message()) -> any().
|
||||
route(Queue = <<"$Q/", _Q>>, Msg) ->
|
||||
case ets:lookup(route, Queue) of
|
||||
case lookup_routes(Queue) of
|
||||
[] ->
|
||||
emqttd_metrics:inc('messages/dropped');
|
||||
[SubPid] ->
|
||||
SubPid ! {dispatch, Queue, Msg};
|
||||
Routes ->
|
||||
Idx = crypto:rand_uniform(1, length(Routes) + 1),
|
||||
{_, SubPid} = lists:nth(Idx, Routes),
|
||||
dispatch(SubPid, Queue, Msg)
|
||||
SubPid = lists:nth(Idx, Routes),
|
||||
SubPid ! {dispatch, Queue, Msg}
|
||||
end;
|
||||
|
||||
route(Topic, Msg) ->
|
||||
case ets:lookup(route, Topic) of
|
||||
case lookup_routes(Topic) of
|
||||
[] ->
|
||||
emqttd_metrics:inc('messages/dropped');
|
||||
[SubPid] -> %% optimize
|
||||
SubPid ! {dispatch, Topic, Msg};
|
||||
Routes ->
|
||||
lists:foreach(fun({_Topic, SubPid}) ->
|
||||
dispatch(SubPid, Topic, Msg)
|
||||
end, Routes)
|
||||
lists:foreach(fun(SubPid) ->
|
||||
SubPid ! {dispatch, Topic, Msg}
|
||||
end, Routes)
|
||||
end.
|
||||
|
||||
dispatch(SubPid, Topic, Msg) -> SubPid ! {dispatch, Topic, Msg}.
|
||||
%% @doc Has Route?
|
||||
-spec has_route(emqttd_topic:topic()) -> boolean().
|
||||
has_route(Topic) ->
|
||||
ets:member(route, Topic).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Internal Functions
|
||||
%%%=============================================================================
|
||||
%% @doc Lookup Routes
|
||||
-spec lookup_routes(emqttd_topic:topic()) -> list(pid()).
|
||||
lookup_routes(Topic) when is_binary(Topic) ->
|
||||
case ets:member(route, Topic) of
|
||||
true ->
|
||||
try ets:lookup_element(route, Topic, 2) catch error:badarg -> [] end;
|
||||
false ->
|
||||
[]
|
||||
end.
|
||||
|
||||
insert_routes([], _Pid) ->
|
||||
%% @doc Add Route.
|
||||
-spec add_route(emqttd_topic:topic(), pid()) -> ok.
|
||||
add_route(Topic, Pid) when is_pid(Pid) ->
|
||||
call(pick(Topic), {add_route, Topic, Pid}).
|
||||
|
||||
%% @doc Add Routes.
|
||||
-spec add_routes(list(emqttd_topic:topic()), pid()) -> ok.
|
||||
add_routes([], _Pid) ->
|
||||
ok;
|
||||
insert_routes(Topics, Pid) ->
|
||||
{Routes, ReverseRoutes} = routes(Topics, Pid),
|
||||
ets:insert(route, Routes),
|
||||
ets:insert(reverse_route, ReverseRoutes).
|
||||
add_routes([Topic], Pid) ->
|
||||
add_route(Topic, Pid);
|
||||
|
||||
routes(Topics, Pid) ->
|
||||
lists:unzip([{{Topic, Pid}, {Pid, Topic}} || Topic <- Topics]).
|
||||
add_routes(Topics, Pid) ->
|
||||
lists:foreach(fun({Router, Slice}) ->
|
||||
call(Router, {add_routes, Slice, Pid})
|
||||
end, slice(Topics)).
|
||||
|
||||
delete_route({Topic, Pid}) ->
|
||||
ets:delete_object(reverse_route, {Pid, Topic}),
|
||||
ets:delete_object(route, {Topic, Pid}).
|
||||
%% @doc Delete Route.
|
||||
-spec delete_route(emqttd_topic:topic(), pid()) -> ok.
|
||||
delete_route(Topic, Pid) ->
|
||||
cast(pick(Topic), {delete_route, Topic, Pid}).
|
||||
|
||||
delete_route_only({Topic, Pid}) ->
|
||||
ets:delete_object(route, {Topic, Pid}).
|
||||
%% @doc Delete Routes.
|
||||
-spec delete_routes(list(emqttd_topic:topic()), pid()) -> ok.
|
||||
delete_routes([Topic], Pid) ->
|
||||
delete_route(Topic, Pid);
|
||||
|
||||
with_stats(Fun) ->
|
||||
Ok = Fun(), setstats(), Ok.
|
||||
delete_routes(Topics, Pid) ->
|
||||
lists:foreach(fun({Router, Slice}) ->
|
||||
cast(Router, {delete_routes, Slice, Pid})
|
||||
end, slice(Topics)).
|
||||
|
||||
setstats() ->
|
||||
lists:foreach(fun setstat/1, [{route, 'routes/count'},
|
||||
{reverse_route, 'routes/reverse'}]).
|
||||
%% @private Slice topics.
|
||||
slice(Topics) ->
|
||||
dict:to_list(lists:foldl(fun(Topic, Dict) ->
|
||||
dict:append(pick(Topic), Topic, Dict)
|
||||
end, dict:new(), Topics)).
|
||||
|
||||
setstat({Tab, Stat}) ->
|
||||
emqttd_stats:setstat(Stat, ets:info(Tab, size)).
|
||||
%% @private Pick a router.
|
||||
pick(Topic) ->
|
||||
gproc_pool:pick_worker(router, Topic).
|
||||
|
||||
stop(Id) when is_integer(Id) ->
|
||||
gen_server2:call(emqttd:reg_name(?MODULE, Id), stop).
|
||||
|
||||
call(Router, Request) ->
|
||||
gen_server2:call(Router, Request, infinity).
|
||||
|
||||
cast(Router, Msg) ->
|
||||
gen_server2:cast(Router, Msg).
|
||||
|
||||
init([Pool, Id, StatsFun, Opts]) ->
|
||||
|
||||
%% Calls from pubsub should be scheduled first?
|
||||
process_flag(priority, high),
|
||||
|
||||
?GPROC_POOL(join, Pool, Id),
|
||||
|
||||
emqttd:seed_now(),
|
||||
|
||||
AgingSecs = proplists:get_value(route_aging, Opts, 5),
|
||||
|
||||
%% Aging Timer
|
||||
{ok, AgingTref} = start_tick(AgingSecs + random:uniform(AgingSecs)),
|
||||
|
||||
Aging = #aging{topics = dict:new(), time = AgingSecs, tref = AgingTref},
|
||||
|
||||
{ok, #state{pool = Pool, id = Id, statsfun = StatsFun, aging = Aging}}.
|
||||
|
||||
start_tick(Secs) ->
|
||||
timer:send_interval(timer:seconds(Secs), {clean, aged}).
|
||||
|
||||
handle_call(stop, _From, State) ->
|
||||
{stop, normal, ok, State};
|
||||
|
||||
handle_call({add_route, Topic, Pid}, _From, State) ->
|
||||
ets:insert(route, {Topic, Pid}),
|
||||
{reply, ok, setstats(State)};
|
||||
|
||||
handle_call({add_routes, Topics, Pid}, _From, State) ->
|
||||
ets:insert(route, [{Topic, Pid} || Topic <- Topics]),
|
||||
{reply, ok, setstats(State)};
|
||||
|
||||
handle_call(Req, _From, State) ->
|
||||
?UNEXPECTED_REQ(Req, State).
|
||||
|
||||
handle_cast({delete_route, Topic, Pid}, State = #state{aging = Aging}) ->
|
||||
ets:delete_object(route, {Topic, Pid}),
|
||||
NewState =
|
||||
case has_route(Topic) of
|
||||
false -> State#state{aging = store_aged(Topic, Aging)};
|
||||
true -> State
|
||||
end,
|
||||
{noreply, setstats(NewState)};
|
||||
|
||||
handle_cast({delete_routes, Topics, Pid}, State) ->
|
||||
NewAging =
|
||||
lists:foldl(fun(Topic, Aging) ->
|
||||
ets:delete_object(route, {Topic, Pid}),
|
||||
case has_route(Topic) of
|
||||
false -> store_aged(Topic, Aging);
|
||||
true -> Aging
|
||||
end
|
||||
end, State#state.aging, Topics),
|
||||
{noreply, setstats(State#state{aging = NewAging})};
|
||||
|
||||
handle_cast(Msg, State) ->
|
||||
?UNEXPECTED_MSG(Msg, State).
|
||||
|
||||
handle_info({clean, aged}, State = #state{aging = Aging}) ->
|
||||
|
||||
#aging{topics = Dict, time = Time} = Aging,
|
||||
|
||||
ByTime = emqttd_util:now_to_secs() - Time,
|
||||
|
||||
Dict1 = try_clean(ByTime, dict:to_list(Dict)),
|
||||
|
||||
NewAging = Aging#aging{topics = dict:from_list(Dict1)},
|
||||
|
||||
{noreply, State#state{aging = NewAging}, hibernate};
|
||||
|
||||
handle_info(Info, State) ->
|
||||
?UNEXPECTED_INFO(Info, State).
|
||||
|
||||
terminate(_Reason, #state{pool = Pool, id = Id, aging = #aging{tref = TRef}}) ->
|
||||
timer:cancel(TRef),
|
||||
?GPROC_POOL(leave, Pool, Id).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
try_clean(ByTime, List) ->
|
||||
try_clean(ByTime, List, []).
|
||||
|
||||
try_clean(_ByTime, [], Acc) ->
|
||||
Acc;
|
||||
|
||||
try_clean(ByTime, [{Topic, TS} | Left], Acc) ->
|
||||
case has_route(Topic) of
|
||||
false ->
|
||||
try_clean2(ByTime, {Topic, TS}, Left, Acc);
|
||||
true ->
|
||||
try_clean(ByTime, Left, Acc)
|
||||
end.
|
||||
|
||||
try_clean2(ByTime, {Topic, TS}, Left, Acc) when TS > ByTime ->
|
||||
try_clean(ByTime, Left, [{Topic, TS} | Acc]);
|
||||
|
||||
try_clean2(ByTime, {Topic, _TS}, Left, Acc) ->
|
||||
TopicR = #mqtt_topic{topic = Topic, node = node()},
|
||||
case mnesia:transaction(fun try_remove_topic/1, [TopicR]) of
|
||||
{atomic, _} -> ok;
|
||||
{aborted, Error} -> lager:error("Clean Topic '~s' Error: ~p", [Topic, Error])
|
||||
end,
|
||||
try_clean(ByTime, Left, Acc).
|
||||
|
||||
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
|
||||
%% Lock topic first
|
||||
case mnesia:wread({topic, Topic}) of
|
||||
[] ->
|
||||
ok; %% mnesia:abort(not_found);
|
||||
[TopicR] ->
|
||||
%% Remove topic and trie
|
||||
delete_topic(TopicR),
|
||||
emqttd_trie:delete(Topic);
|
||||
_More ->
|
||||
%% Remove topic only
|
||||
delete_topic(TopicR)
|
||||
end.
|
||||
|
||||
delete_topic(TopicR) ->
|
||||
mnesia:delete_object(topic, TopicR, write).
|
||||
|
||||
store_aged(Topic, Aging = #aging{topics = Dict}) ->
|
||||
Now = emqttd_util:now_to_secs(),
|
||||
Aging#aging{topics = dict:store(Topic, Now, Dict)}.
|
||||
|
||||
setstats(State = #state{statsfun = StatsFun}) ->
|
||||
StatsFun(route), State.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -85,10 +85,7 @@ mnesia(copy) ->
|
|||
%%------------------------------------------------------------------------------
|
||||
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
|
||||
start_link(Pool, Id) ->
|
||||
gen_server2:start_link({local, name(Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
name(Id) ->
|
||||
list_to_atom("emqttd_sm_" ++ integer_to_list(Id)).
|
||||
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Start a session
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -143,7 +143,7 @@ setstats(Stat, MaxStat, Val) ->
|
|||
%%%=============================================================================
|
||||
|
||||
init([]) ->
|
||||
random:seed(os:timestamp()),
|
||||
emqttd:seed_now(),
|
||||
ets:new(?STATS_TAB, [set, public, named_table, {write_concurrency, true}]),
|
||||
Topics = ?SYSTOP_CLIENTS ++ ?SYSTOP_SESSIONS ++ ?SYSTOP_PUBSUB ++ ?SYSTOP_RETAINED,
|
||||
ets:insert(?STATS_TAB, [{Topic, 0} || Topic <- Topics]),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -31,6 +31,8 @@
|
|||
|
||||
-export([join/1, feed_var/3, is_queue/1, systop/1]).
|
||||
|
||||
-type topic() :: binary().
|
||||
|
||||
%-type type() :: static | dynamic.
|
||||
|
||||
-type word() :: '' | '+' | '#' | binary().
|
||||
|
@ -39,7 +41,7 @@
|
|||
|
||||
-type triple() :: {root | binary(), word(), binary()}.
|
||||
|
||||
-export_type([word/0, triple/0]).
|
||||
-export_type([topic/0, word/0, triple/0]).
|
||||
|
||||
-define(MAX_TOPIC_LEN, 4096).
|
||||
|
||||
|
@ -47,7 +49,7 @@
|
|||
%% @doc Is wildcard topic?
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec wildcard(binary()) -> true | false.
|
||||
-spec wildcard(topic()) -> true | false.
|
||||
wildcard(Topic) when is_binary(Topic) ->
|
||||
wildcard(words(Topic));
|
||||
wildcard([]) ->
|
||||
|
@ -64,8 +66,8 @@ wildcard([_H|T]) ->
|
|||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec match(Name, Filter) -> boolean() when
|
||||
Name :: binary() | words(),
|
||||
Filter :: binary() | words().
|
||||
Name :: topic() | words(),
|
||||
Filter :: topic() | words().
|
||||
match(Name, Filter) when is_binary(Name) and is_binary(Filter) ->
|
||||
match(words(Name), words(Filter));
|
||||
match([], []) ->
|
||||
|
@ -91,7 +93,7 @@ match([], [_H|_T2]) ->
|
|||
%% @doc Validate Topic
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec validate({name | filter, binary()}) -> boolean().
|
||||
-spec validate({name | filter, topic()}) -> boolean().
|
||||
validate({_, <<>>}) ->
|
||||
false;
|
||||
validate({_, Topic}) when is_binary(Topic) and (size(Topic) > ?MAX_TOPIC_LEN) ->
|
||||
|
@ -129,7 +131,7 @@ validate3(<<_/utf8, Rest/binary>>) ->
|
|||
%% @doc Topic to Triples
|
||||
%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-spec triples(binary()) -> list(triple()).
|
||||
-spec triples(topic()) -> list(triple()).
|
||||
triples(Topic) when is_binary(Topic) ->
|
||||
triples(words(Topic), root, []).
|
||||
|
||||
|
@ -154,7 +156,7 @@ bin(B) when is_binary(B) -> B.
|
|||
%% @doc Split Topic Path to Words
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec words(binary()) -> words().
|
||||
-spec words(topic()) -> words().
|
||||
words(Topic) when is_binary(Topic) ->
|
||||
[word(W) || W <- binary:split(Topic, <<"/">>, [global])].
|
||||
|
||||
|
@ -167,7 +169,7 @@ word(Bin) -> Bin.
|
|||
%% @doc Queue is a special topic name that starts with "$Q/"
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
-spec is_queue(binary()) -> boolean().
|
||||
-spec is_queue(topic()) -> boolean().
|
||||
is_queue(<<"$Q/", _Queue/binary>>) ->
|
||||
true;
|
||||
is_queue(_) ->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
|
|