param_flow.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /**
  2. * Parameter flow control controller.
  3. *
  4. * @author Eric Zhao
  5. */
  6. angular.module('sentinelDashboardApp').controller('ParamFlowController', ['$scope', '$stateParams', 'ParamFlowService', 'ngDialog',
  7. 'MachineService',
  8. function ($scope, $stateParams, ParamFlowService, ngDialog,
  9. MachineService) {
  10. const UNSUPPORTED_CODE = 4041;
  11. $scope.app = $stateParams.app;
  12. $scope.curExItem = {};
  13. $scope.paramItemClassTypeList = [
  14. 'int', 'double', 'java.lang.String', 'long', 'float', 'char', 'byte'
  15. ];
  16. $scope.rulesPageConfig = {
  17. pageSize: 10,
  18. currentPageIndex: 1,
  19. totalPage: 1,
  20. totalCount: 0,
  21. };
  22. $scope.macsInputConfig = {
  23. searchField: ['text', 'value'],
  24. persist: true,
  25. create: false,
  26. maxItems: 1,
  27. render: {
  28. item: function (data, escape) {
  29. return '<div>' + escape(data.text) + '</div>';
  30. }
  31. },
  32. onChange: function (value, oldValue) {
  33. $scope.macInputModel = value;
  34. }
  35. };
  36. function updateSingleParamItem(arr, v, t, c) {
  37. for (let i = 0; i < arr.length; i++) {
  38. if (arr[i].object === v && arr[i].classType === t) {
  39. arr[i].count = c;
  40. return;
  41. }
  42. }
  43. arr.push({object: v, classType: t, count: c});
  44. }
  45. function removeSingleParamItem(arr, v, t) {
  46. for (let i = 0; i < arr.length; i++) {
  47. if (arr[i].object === v && arr[i].classType === t) {
  48. arr.splice(i, 1);
  49. break;
  50. }
  51. }
  52. }
  53. function isNumberClass(classType) {
  54. return classType === 'int' || classType === 'double' ||
  55. classType === 'float' || classType === 'long' || classType === 'short';
  56. }
  57. function isByteClass(classType) {
  58. return classType === 'byte';
  59. }
  60. function notNumberAtLeastZero(num) {
  61. return num === undefined || num === '' || isNaN(num) || num < 0;
  62. }
  63. function notGoodNumber(num) {
  64. return num === undefined || num === '' || isNaN(num);
  65. }
  66. function notGoodNumberBetweenExclusive(num, l ,r) {
  67. return num === undefined || num === '' || isNaN(num) || num < l || num > r;
  68. }
  69. $scope.notValidParamItem = (curExItem) => {
  70. if (isNumberClass(curExItem.classType) && notGoodNumber(curExItem.object)) {
  71. return true;
  72. }
  73. if (isByteClass(curExItem.classType) && notGoodNumberBetweenExclusive(curExItem.object, -128, 127)) {
  74. return true;
  75. }
  76. return curExItem.object === undefined || curExItem.classType === undefined ||
  77. notNumberAtLeastZero(curExItem.count);
  78. };
  79. $scope.addParamItem = () => {
  80. updateSingleParamItem($scope.currentRule.rule.paramFlowItemList,
  81. $scope.curExItem.object, $scope.curExItem.classType, $scope.curExItem.count);
  82. let oldItem = $scope.curExItem;
  83. $scope.curExItem = {classType: oldItem.classType};
  84. };
  85. $scope.removeParamItem = (v, t) => {
  86. removeSingleParamItem($scope.currentRule.rule.paramFlowItemList, v, t);
  87. };
  88. function getMachineRules() {
  89. if (!$scope.macInputModel) {
  90. return;
  91. }
  92. let mac = $scope.macInputModel.split(':');
  93. ParamFlowService.queryMachineRules($scope.app, mac[0], mac[1])
  94. .success(function (data) {
  95. if (data.code === 0 && data.data) {
  96. $scope.loadError = undefined;
  97. $scope.rules = data.data;
  98. $scope.rulesPageConfig.totalCount = $scope.rules.length;
  99. } else {
  100. $scope.rules = [];
  101. $scope.rulesPageConfig.totalCount = 0;
  102. if (data.code === UNSUPPORTED_CODE) {
  103. $scope.loadError = {message: "机器 " + mac[0] + ":" + mac[1] + " 的 Sentinel 客户端版本不支持热点参数限流功能,请升级至 0.2.0 以上版本并引入 sentinel-parameter-flow-control 依赖。"}
  104. } else {
  105. $scope.loadError = {message: data.msg}
  106. }
  107. }
  108. })
  109. .error((data, header, config, status) => {
  110. $scope.loadError = {message: "未知错误"}
  111. });
  112. }
  113. $scope.getMachineRules = getMachineRules;
  114. getMachineRules();
  115. var paramFlowRuleDialog;
  116. $scope.editRule = function (rule) {
  117. $scope.currentRule = angular.copy(rule);
  118. if ($scope.currentRule.rule && $scope.currentRule.rule.durationInSec === undefined) {
  119. $scope.currentRule.rule.durationInSec = 1;
  120. }
  121. $scope.paramFlowRuleDialog = {
  122. title: '编辑热点规则',
  123. type: 'edit',
  124. confirmBtnText: '保存',
  125. supportAdvanced: true,
  126. showAdvanceButton: rule.rule.paramFlowItemList === undefined || rule.rule.paramFlowItemList.length <= 0
  127. };
  128. paramFlowRuleDialog = ngDialog.open({
  129. template: '/app/views/dialog/param-flow-rule-dialog.html',
  130. width: 680,
  131. overlay: true,
  132. scope: $scope
  133. });
  134. $scope.curExItem = {};
  135. };
  136. $scope.addNewRule = function () {
  137. var mac = $scope.macInputModel.split(':');
  138. $scope.currentRule = {
  139. app: $scope.app,
  140. ip: mac[0],
  141. port: mac[1],
  142. rule: {
  143. grade: 1,
  144. paramFlowItemList: [],
  145. count: 0,
  146. limitApp: 'default',
  147. controlBehavior: 0,
  148. durationInSec: 1,
  149. burstCount: 0,
  150. maxQueueingTimeMs: 0,
  151. clusterMode: false,
  152. clusterConfig: {
  153. thresholdType: 0,
  154. fallbackToLocalWhenFail: true,
  155. }
  156. }
  157. };
  158. $scope.paramFlowRuleDialog = {
  159. title: '新增热点规则',
  160. type: 'add',
  161. confirmBtnText: '新增',
  162. supportAdvanced: true,
  163. showAdvanceButton: true,
  164. };
  165. paramFlowRuleDialog = ngDialog.open({
  166. template: '/app/views/dialog/param-flow-rule-dialog.html',
  167. width: 680,
  168. overlay: true,
  169. scope: $scope
  170. });
  171. $scope.curExItem = {};
  172. };
  173. $scope.onOpenAdvanceClick = function () {
  174. $scope.paramFlowRuleDialog.showAdvanceButton = false;
  175. };
  176. $scope.onCloseAdvanceClick = function () {
  177. $scope.paramFlowRuleDialog.showAdvanceButton = true;
  178. };
  179. $scope.saveRule = function () {
  180. if (!ParamFlowService.checkRuleValid($scope.currentRule.rule)) {
  181. return;
  182. }
  183. if ($scope.paramFlowRuleDialog.type === 'add') {
  184. addNewRuleAndPush($scope.currentRule);
  185. } else if ($scope.paramFlowRuleDialog.type === 'edit') {
  186. saveRuleAndPush($scope.currentRule, true);
  187. }
  188. };
  189. function addNewRuleAndPush(rule) {
  190. ParamFlowService.addNewRule(rule).success((data) => {
  191. if (data.success) {
  192. getMachineRules();
  193. paramFlowRuleDialog.close();
  194. } else {
  195. alert('添加规则失败:' + data.msg);
  196. }
  197. }).error((data) => {
  198. if (data) {
  199. alert('添加规则失败:' + data.msg);
  200. } else {
  201. alert("添加规则失败:未知错误");
  202. }
  203. });
  204. }
  205. function saveRuleAndPush(rule, edit) {
  206. ParamFlowService.saveRule(rule).success(function (data) {
  207. if (data.success) {
  208. alert("修改规则成功");
  209. getMachineRules();
  210. if (edit) {
  211. paramFlowRuleDialog.close();
  212. } else {
  213. confirmDialog.close();
  214. }
  215. } else {
  216. alert('修改规则失败:' + data.msg);
  217. }
  218. }).error((data) => {
  219. if (data) {
  220. alert('修改规则失败:' + data.msg);
  221. } else {
  222. alert("修改规则失败:未知错误");
  223. }
  224. });
  225. }
  226. function deleteRuleAndPush(entity) {
  227. if (entity.id === undefined || isNaN(entity.id)) {
  228. alert('规则 ID 不合法!');
  229. return;
  230. }
  231. ParamFlowService.deleteRule(entity).success((data) => {
  232. if (data.code == 0) {
  233. getMachineRules();
  234. confirmDialog.close();
  235. } else {
  236. alert('删除规则失败:' + data.msg);
  237. }
  238. }).error((data) => {
  239. if (data) {
  240. alert('删除规则失败:' + data.msg);
  241. } else {
  242. alert("删除规则失败:未知错误");
  243. }
  244. });
  245. };
  246. var confirmDialog;
  247. $scope.deleteRule = function (ruleEntity) {
  248. $scope.currentRule = ruleEntity;
  249. console.log('deleting: ' + ruleEntity);
  250. $scope.confirmDialog = {
  251. title: '删除热点规则',
  252. type: 'delete_rule',
  253. attentionTitle: '请确认是否删除如下热点参数限流规则',
  254. attention: '资源名: ' + ruleEntity.rule.resource + ', 热点参数索引: ' + ruleEntity.rule.paramIdx +
  255. ', 限流模式: ' + (ruleEntity.rule.grade === 1 ? 'QPS' : '未知') + ', 限流阈值: ' + ruleEntity.rule.count,
  256. confirmBtnText: '删除',
  257. };
  258. confirmDialog = ngDialog.open({
  259. template: '/app/views/dialog/confirm-dialog.html',
  260. scope: $scope,
  261. overlay: true
  262. });
  263. };
  264. $scope.confirm = function () {
  265. if ($scope.confirmDialog.type === 'delete_rule') {
  266. deleteRuleAndPush($scope.currentRule);
  267. } else {
  268. console.error('error');
  269. }
  270. };
  271. queryAppMachines();
  272. function queryAppMachines() {
  273. MachineService.getAppMachines($scope.app).success(
  274. function (data) {
  275. if (data.code == 0) {
  276. // $scope.machines = data.data;
  277. if (data.data) {
  278. $scope.machines = [];
  279. $scope.macsInputOptions = [];
  280. data.data.forEach(function (item) {
  281. if (item.healthy) {
  282. $scope.macsInputOptions.push({
  283. text: item.ip + ':' + item.port,
  284. value: item.ip + ':' + item.port
  285. });
  286. }
  287. });
  288. }
  289. if ($scope.macsInputOptions.length > 0) {
  290. $scope.macInputModel = $scope.macsInputOptions[0].value;
  291. }
  292. } else {
  293. $scope.macsInputOptions = [];
  294. }
  295. }
  296. );
  297. };
  298. $scope.$watch('macInputModel', function () {
  299. if ($scope.macInputModel) {
  300. getMachineRules();
  301. }
  302. });
  303. }]);