Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 1 | (function() { |
| 2 | 'use strict'; |
| 3 | |
| 4 | // injected refs |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 5 | let $log, $scope, $interval, $timeout, fs, wss, ks, ls; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 6 | |
| 7 | // constants |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 8 | let intIntentAddReq = 'intIntentAddRequest'; |
| 9 | let intIntentDelReq = 'intIntentDelRequest'; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 10 | |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 11 | let refreshInterval = 1000; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 12 | |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 13 | let propOrder = ['id', 'srcAddr', 'dstAddr', 'srcPort', 'dstPort', 'insMask']; |
| 14 | let friendlyProps = ['IntIntent ID', 'Src Address', 'Dst Address', 'Src Port', 'Dst Port', 'Ins Mask']; |
| 15 | |
| 16 | function checkArgAndShowMsg() { |
| 17 | // Need to match at least one field |
| 18 | if ($scope.ip4SrcPrefix === "" && |
| 19 | $scope.ip4DstPrefix === "" && |
| 20 | $scope.l4SrcPort === "" && |
| 21 | $scope.l4DstPort === "" ) { |
| 22 | $scope.intAddMsg = "Nothing installed since there is no matching spec."; |
| 23 | return false; |
| 24 | } |
| 25 | // IP address validation |
| 26 | let ipv4Pattern = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/[0-9]{1,2})?$/; |
| 27 | if ($scope.ip4SrcPrefix !== "" && !ipv4Pattern.test($scope.ip4SrcPrefix)) { |
| 28 | $scope.intAddMsg = "Invalid source IP."; |
| 29 | return false; |
| 30 | } |
| 31 | if ($scope.ip4DstPrefix !== "" && !ipv4Pattern.test($scope.ip4DstPrefix)) { |
| 32 | $scope.intAddMsg = "Invalid destination IP."; |
| 33 | return false; |
| 34 | } |
| 35 | // L4 port validation |
| 36 | if ($scope.l4SrcPort !== "") { |
| 37 | let l4SrcPort = parseInt($scope.l4SrcPort); |
| 38 | if (isNaN(l4SrcPort)) { |
| 39 | $scope.intAddMsg = "Invalid source port number."; |
| 40 | return false; |
| 41 | } |
| 42 | if (l4SrcPort <= 0 || l4SrcPort > 65535) { |
| 43 | $scope.intAddMsg = "Invalid source port number."; |
| 44 | return false; |
| 45 | } |
| 46 | if ($scope.protocol === "") { |
| 47 | $scope.intAddMsg = "protocol cannot be empty."; |
| 48 | return false; |
| 49 | } |
| 50 | } |
| 51 | if ($scope.l4DstPort !== "") { |
| 52 | let l4DstPort = parseInt($scope.l4DstPort); |
| 53 | if (isNaN(l4DstPort)) { |
| 54 | $scope.intAddMsg = "Invalid destination port number."; |
| 55 | return false; |
| 56 | } |
| 57 | if (l4DstPort <= 0 || l4DstPort > 65535) { |
| 58 | $scope.intAddMsg = "Invalid destination port number."; |
| 59 | return false; |
| 60 | } |
| 61 | if ($scope.protocol === "") { |
| 62 | $scope.intAddMsg = "protocol cannot be empty."; |
| 63 | return false; |
| 64 | } |
| 65 | } |
| 66 | $scope.intAddMsg = ""; |
| 67 | return true; |
| 68 | } |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 69 | |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 70 | function sendIntIntentString() { |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 71 | let inst = []; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 72 | if ($scope.metaSwId) inst.push("SWITCH_ID"); |
| 73 | if ($scope.metaPortId) inst.push("PORT_ID"); |
| 74 | if ($scope.metaHopLatency) inst.push("HOP_LATENCY"); |
| 75 | if ($scope.metaQOccupancy) inst.push("QUEUE_OCCUPANCY"); |
| 76 | if ($scope.metaIngressTstamp) inst.push("INGRESS_TIMESTAMP"); |
| 77 | if ($scope.metaEgressTstamp) inst.push("EGRESS_TIMESTAMP"); |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 78 | if ($scope.metaEgressTx) inst.push("EGRESS_TX_UTIL"); |
| 79 | |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 80 | let intentObjectNode = { |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 81 | "ip4SrcPrefix": $scope.ip4SrcPrefix, |
| 82 | "ip4DstPrefix": $scope.ip4DstPrefix, |
| 83 | "l4SrcPort": $scope.l4SrcPort, |
| 84 | "l4DstPort": $scope.l4DstPort, |
| 85 | "protocol": $scope.protocol, |
| 86 | "metadata": inst |
| 87 | }; |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 88 | if (checkArgAndShowMsg()) { |
| 89 | wss.sendEvent(intIntentAddReq, intentObjectNode); |
| 90 | } |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | function delIntIntent() { |
| 94 | if ($scope.selId) { |
| 95 | wss.sendEvent(intIntentDelReq, { |
| 96 | "intentId": $scope.selId |
| 97 | }); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | function intIntentBuildTable(o) { |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 102 | let handlers = {}, |
Davide Scano | b5ade98 | 2020-06-03 21:47:13 +0200 | [diff] [blame] | 103 | root = o.tag + 's', |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 104 | req = o.tag + 'DataRequest', |
| 105 | resp = o.tag + 'DataResponse', |
| 106 | onSel = fs.isF(o.selCb), |
| 107 | onResp = fs.isF(o.respCb), |
| 108 | idKey = o.idKey || 'id', |
| 109 | oldTableData = [], |
| 110 | refreshPromise; |
| 111 | |
| 112 | o.scope.tableData = []; |
| 113 | o.scope.changedData = []; |
| 114 | o.scope.sortParams = o.sortParams || {}; |
| 115 | o.scope.autoRefresh = true; |
| 116 | o.scope.autoRefreshTip = 'Toggle auto refresh'; |
| 117 | |
| 118 | // === websocket functions -------------------- |
| 119 | // response |
| 120 | function respCb(data) { |
| 121 | ls.stop(); |
| 122 | o.scope.tableData = data[root]; |
| 123 | o.scope.annots = data.annots; |
| 124 | onResp && onResp(); |
| 125 | |
| 126 | // checks if data changed for row flashing |
| 127 | if (!angular.equals(o.scope.tableData, oldTableData)) { |
| 128 | o.scope.changedData = []; |
| 129 | // only flash the row if the data already exists |
| 130 | if (oldTableData.length) { |
| 131 | angular.forEach(o.scope.tableData, function (item) { |
| 132 | if (!fs.containsObj(oldTableData, item)) { |
| 133 | o.scope.changedData.push(item); |
| 134 | } |
| 135 | }); |
| 136 | } |
| 137 | angular.copy(o.scope.tableData, oldTableData); |
| 138 | } |
| 139 | } |
| 140 | handlers[resp] = respCb; |
| 141 | wss.bindHandlers(handlers); |
| 142 | |
| 143 | // request |
| 144 | function sortCb(params) { |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 145 | let p = angular.extend({}, params, o.query); |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 146 | if (wss.isConnected()) { |
| 147 | wss.sendEvent(req, p); |
| 148 | ls.start(); |
| 149 | } |
| 150 | } |
| 151 | o.scope.sortCallback = sortCb; |
| 152 | |
| 153 | // === selecting a row functions ---------------- |
| 154 | function selCb($event, selRow) { |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 155 | let selId = selRow[idKey]; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 156 | o.scope.selId = (o.scope.selId === selId) ? null : selId; |
| 157 | onSel && onSel($event, selRow); |
| 158 | } |
| 159 | o.scope.selectCallback = selCb; |
| 160 | |
| 161 | // === autoRefresh functions ------------------ |
| 162 | function fetchDataIfNotWaiting() { |
| 163 | if (!ls.waiting()) { |
| 164 | if (fs.debugOn('widget')) { |
| 165 | $log.debug('Refreshing ' + root + ' page'); |
| 166 | } |
| 167 | sortCb(o.scope.sortParams); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | function startRefresh() { |
| 172 | refreshPromise = $interval(fetchDataIfNotWaiting, refreshInterval); |
| 173 | } |
| 174 | |
| 175 | function stopRefresh() { |
| 176 | if (refreshPromise) { |
| 177 | $interval.cancel(refreshPromise); |
| 178 | refreshPromise = null; |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | function toggleRefresh() { |
| 183 | o.scope.autoRefresh = !o.scope.autoRefresh; |
| 184 | o.scope.autoRefresh ? startRefresh() : stopRefresh(); |
| 185 | } |
| 186 | o.scope.toggleRefresh = toggleRefresh; |
| 187 | |
| 188 | // === Cleanup on destroyed scope ----------------- |
| 189 | o.scope.$on('$destroy', function () { |
| 190 | wss.unbindHandlers(handlers); |
| 191 | stopRefresh(); |
| 192 | ls.stop(); |
| 193 | }); |
| 194 | |
| 195 | sortCb(o.scope.sortParams); |
| 196 | startRefresh(); |
| 197 | } |
| 198 | |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 199 | let app1 = angular.module('ovIntApp', []); |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 200 | app1.controller('OvIntAppCtrl', |
| 201 | ['$log', '$scope', '$interval', '$timeout', 'TableBuilderService', |
| 202 | 'FnService', 'WebSocketService', 'KeyService', 'LoadingService', |
| 203 | |
| 204 | function(_$log_, _$scope_, _$interval_, _$timeout_, tbs, _fs_, _wss_, _ks_, _ls_) { |
| 205 | $log = _$log_; |
| 206 | $scope = _$scope_; |
| 207 | $interval = _$interval_; |
| 208 | $timeout = _$timeout_; |
| 209 | fs = _fs_; |
| 210 | wss = _wss_; |
| 211 | ks = _ks_; |
| 212 | ls = _ls_; |
| 213 | |
| 214 | // custom selection callback |
| 215 | function selCb($event, row) { |
| 216 | } |
| 217 | intIntentBuildTable({ |
| 218 | scope: $scope, |
| 219 | tag: 'intAppIntIntent' |
| 220 | // selCb: selCb |
| 221 | }); |
| 222 | |
| 223 | $scope.sendIntIntentString = sendIntIntentString; |
| 224 | $scope.delIntIntent = delIntIntent; |
Yi Tseng | 930b0cd | 2020-10-04 22:33:22 -0700 | [diff] [blame^] | 225 | $scope.intAddMsg = ""; |
| 226 | $scope.ip4SrcPrefix = ""; |
| 227 | $scope.ip4DstPrefix = ""; |
| 228 | $scope.l4SrcPort = ""; |
| 229 | $scope.l4DstPort = ""; |
| 230 | $scope.protocol = ""; |
Jonghwan Hyun | 13a430d | 2018-07-22 17:02:51 +0900 | [diff] [blame] | 231 | |
| 232 | // get data the first time... |
| 233 | // getData(); |
| 234 | |
| 235 | // cleanup |
| 236 | $scope.$on('$destroy', function() { |
| 237 | // wss.unbindHandlers(handlers); |
| 238 | /*ks.unbindKeys();*/ |
| 239 | $log.log('OvIntAppCtrl has been destroyed'); |
| 240 | }); |
| 241 | |
| 242 | $log.log('OvIntAppCtrl has been created'); |
| 243 | } |
| 244 | ]); |
| 245 | }()); |