srs.console.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. scApp.controller("CSCMain", ["$scope", "$interval", "$location", "MSCApi", "$sc_utility", "$sc_server", '$sc_nav', function($scope, $interval, $location, MSCApi, $sc_utility, $sc_server, $sc_nav){
  2. $scope.logs = [];
  3. // remove expired alert.
  4. $interval(function(){
  5. for (var i = 0; i < $scope.logs.length; i++) {
  6. var log = $scope.logs[i];
  7. if (log.create + 10000 < new Date().getTime()) {
  8. $scope.logs.splice(i, 1);
  9. break;
  10. }
  11. }
  12. }, 3000);
  13. // handler system log event, from $sc_utility service.
  14. $scope.$on("$sc_utility_log", function(event, level, msg){
  15. var log = {
  16. level:level, msg:msg, create:new Date().getTime()
  17. };
  18. // only show 3 msgs.
  19. while ($scope.logs.length > 2) {
  20. $scope.logs.splice(0, 1);
  21. }
  22. $scope.logs.push(log);
  23. });
  24. // handle system error event, from $sc_utility service.
  25. $scope.$on("$sc_utility_http_error", function(event, status, response){
  26. var code = response.code;
  27. if (status !== 200) {
  28. if (!status && !response) {
  29. response = "无法访问服务器";
  30. } else {
  31. response = "HTTP/" + status + ", " + response;
  32. }
  33. } else {
  34. var map = {
  35. 1061: "RAW API被禁用",
  36. 1062: "服务器不允许这个操作",
  37. 1063: "RawApi参数不符合要求"
  38. };
  39. if (map[response.code]) {
  40. response = "code=" + response.code + ", " + map[response.code];
  41. } else {
  42. resonse = "code=" + response.code + ", 系统错误";
  43. }
  44. }
  45. if (code === 1061) {
  46. $sc_utility.log("trace", response);
  47. return;
  48. }
  49. $sc_utility.log("warn", response);
  50. });
  51. $scope.gogogo = function (path) {
  52. $location.path(path);
  53. };
  54. $scope.goto = function (path) {
  55. var absUrl = $sc_server.buildNavUrl();
  56. var url = absUrl.replace($location.$$path, path);
  57. var win = window.open('', '_self');
  58. win.location = url; // For safari security reason, we should set the location instead.
  59. };
  60. $scope.redirect = function (from, to) {
  61. var absUrl = $sc_server.buildNavUrl();
  62. var url = absUrl.replace(from, to);
  63. var win = window.open('', '_self');
  64. win.location = url; // For safari security reason, we should set the location instead.
  65. };
  66. // init the server and port for api.
  67. $sc_server.init($location, MSCApi);
  68. //$sc_utility.log("trace", "set baseurl to " + $sc_server.baseurl());
  69. }]);
  70. scApp.controller("CSCConnect", ["$scope", "$location", "MSCApi", "$sc_utility", "$sc_nav", "$sc_server", function($scope, $location, MSCApi, $sc_utility, $sc_nav, $sc_server){
  71. $sc_nav.in_control();
  72. $scope.server = {
  73. schema: $sc_server.schema,
  74. ip: $sc_server.host,
  75. port: $sc_server.port
  76. };
  77. $scope.connect = function(){
  78. $sc_server.schema = $scope.server.schema;
  79. $sc_server.host = $scope.server.ip;
  80. $sc_server.port = $scope.server.port;
  81. MSCApi.versions_get(function(data){
  82. $sc_utility.log("trace", "连接到SRS" + $scope.server.ip + "成功, SRS/" + data.data.version);
  83. $scope.goto('/summaries');
  84. });
  85. };
  86. $sc_utility.refresh.stop();
  87. }]);
  88. scApp.controller("CSCSummary", ["$scope", "MSCApi", "$sc_utility", "$sc_nav", function($scope, MSCApi, $sc_utility, $sc_nav){
  89. $sc_nav.in_summary();
  90. $scope.pre_kbps = null;
  91. $sc_utility.refresh.refresh_change(function(){
  92. MSCApi.summaries_get(function(data){
  93. var kbps = {
  94. initialized: false,
  95. in: { srs: 0, sys: 0, inner: 0 },
  96. out: { srs: 0, sys: 0, inner: 0 }
  97. };
  98. if ($scope.pre_kbps) {
  99. kbps.initialized = true;
  100. var diff = data.data.system.net_sample_time - $scope.pre_kbps.system.net_sample_time;
  101. if (diff > 0) {
  102. kbps.in.sys = (data.data.system.net_recv_bytes - $scope.pre_kbps.system.net_recv_bytes) * 8 / diff;
  103. kbps.in.inner = (data.data.system.net_recvi_bytes - $scope.pre_kbps.system.net_recvi_bytes) * 8 / diff;
  104. kbps.out.sys = (data.data.system.net_send_bytes - $scope.pre_kbps.system.net_send_bytes) * 8 / diff;
  105. kbps.out.inner = (data.data.system.net_sendi_bytes - $scope.pre_kbps.system.net_sendi_bytes) * 8 / diff;
  106. }
  107. diff = data.data.system.srs_sample_time - $scope.pre_kbps.system.srs_sample_time;
  108. if (diff > 0) {
  109. kbps.in.srs = (data.data.system.srs_recv_bytes - $scope.pre_kbps.system.srs_recv_bytes) * 8 / diff;
  110. kbps.out.srs = (data.data.system.srs_send_bytes - $scope.pre_kbps.system.srs_send_bytes) * 8 / diff;
  111. }
  112. diff = data.data.now_ms - $scope.pre_kbps.now_ms;
  113. if (!$scope.kbps.initialized || diff >= 20 * 1000) {
  114. $scope.pre_kbps = data.data;
  115. $scope.kbps = kbps;
  116. }
  117. }
  118. if (!$scope.kbps) {
  119. $scope.pre_kbps = data.data;
  120. $scope.kbps = kbps;
  121. }
  122. $scope.global = data.data;
  123. $scope.server = data.data.self;
  124. $scope.system = data.data.system;
  125. $sc_utility.refresh.request();
  126. });
  127. }, 3000);
  128. $sc_utility.log("trace", "Retrieve summary from SRS.");
  129. $sc_utility.refresh.request(0);
  130. }]);
  131. scApp.controller("CSCVhosts", ["$scope", "MSCApi", "$sc_nav", "$sc_utility", function($scope, MSCApi, $sc_nav, $sc_utility){
  132. $sc_nav.in_vhosts();
  133. $sc_utility.refresh.refresh_change(function(){
  134. MSCApi.vhosts_get(function(data){
  135. $scope.vhosts = data.vhosts;
  136. $sc_utility.refresh.request();
  137. });
  138. }, 3000);
  139. $sc_utility.log("trace", "Retrieve vhosts from SRS");
  140. $sc_utility.refresh.request(0);
  141. }]);
  142. scApp.controller("CSCVhost", ["$scope", "$routeParams", "MSCApi", "$sc_nav", "$sc_utility", function($scope, $routeParams, MSCApi, $sc_nav, $sc_utility){
  143. $sc_nav.in_vhosts();
  144. $sc_utility.refresh.stop();
  145. MSCApi.vhosts_get2($routeParams.id, function(data){
  146. $scope.vhost = data.vhost;
  147. });
  148. $sc_utility.log("trace", "Retrieve vhost info from SRS");
  149. }]);
  150. scApp.controller("CSCStreams", ["$scope", "$location", "MSCApi", "$sc_nav", "$sc_utility", function($scope, $location, MSCApi, $sc_nav, $sc_utility){
  151. $sc_nav.in_streams();
  152. $scope.kickoff = function(stream) {
  153. MSCApi.clients_delete(stream.publish.cid, function(){
  154. $sc_utility.log("warn", "Kickoff stream ok.");
  155. });
  156. };
  157. $scope.dvr = function(stream){
  158. $location.path($sc_utility.dvr_id(stream));
  159. };
  160. $scope.support_raw_api = false;
  161. MSCApi.configs_raw(function(data) {
  162. $scope.support_raw_api = $sc_utility.raw_api_enabled(data);
  163. });
  164. MSCApi.vhosts_get(function(data){
  165. var vhosts = data.vhosts;
  166. $sc_utility.refresh.refresh_change(function(){
  167. MSCApi.streams_get(function(data){
  168. for (var k in data.streams) {
  169. var stream = data.streams[k];
  170. stream.owner = system_array_get(vhosts, function(vhost) {return vhost.id === stream.vhost; });
  171. }
  172. $scope.streams = data.streams;
  173. $sc_utility.refresh.request();
  174. });
  175. }, 3000);
  176. $sc_utility.log("trace", "Retrieve streams from SRS");
  177. $sc_utility.refresh.request(0);
  178. });
  179. $sc_utility.log("trace", "Retrieve vhost info from SRS");
  180. }]);
  181. scApp.controller("CSCStream", ["$scope", '$location', "$routeParams", "MSCApi", "$sc_nav", "$sc_utility", function($scope, $location, $routeParams, MSCApi, $sc_nav, $sc_utility){
  182. $sc_nav.in_streams();
  183. $scope.kickoff = function(stream) {
  184. MSCApi.clients_delete(stream.publish.cid, function(){
  185. $sc_utility.log("warn", "Kickoff stream ok.");
  186. });
  187. };
  188. $sc_utility.refresh.stop();
  189. $scope.dvr = function(stream){
  190. $location.path($sc_utility.dvr_id(stream));
  191. };
  192. $scope.support_raw_api = false;
  193. MSCApi.configs_raw(function(data) {
  194. $scope.support_raw_api = $sc_utility.raw_api_enabled(data);
  195. });
  196. MSCApi.streams_get2($routeParams.id, function(data){
  197. var stream = data.stream;
  198. if (!$scope.owner) {
  199. MSCApi.vhosts_get2(stream.vhost, function(data) {
  200. var vhost = data.vhost;
  201. stream.owner = $scope.owner = vhost;
  202. $scope.stream = stream;
  203. });
  204. $sc_utility.log("trace", "Retrieve vhost info from SRS");
  205. } else {
  206. stream.owner = $scope.owner;
  207. $scope.stream = stream;
  208. }
  209. });
  210. $sc_utility.log("trace", "Retrieve stream info from SRS");
  211. }]);
  212. scApp.controller("CSCClients", ["$scope", "MSCApi", "$sc_nav", "$sc_utility", function($scope, MSCApi, $sc_nav, $sc_utility){
  213. $sc_nav.in_clients();
  214. $scope.kickoff = function(client) {
  215. MSCApi.clients_delete(client.id, function(){
  216. $sc_utility.log("warn", "Kickoff client ok.");
  217. });
  218. };
  219. $sc_utility.refresh.refresh_change(function(){
  220. MSCApi.clients_get(function(data){
  221. $scope.clients = data.clients;
  222. $sc_utility.refresh.request();
  223. });
  224. }, 3000);
  225. $sc_utility.log("trace", "Retrieve clients from SRS");
  226. $sc_utility.refresh.request(0);
  227. }]);
  228. scApp.controller("CSCClient", ["$scope", "$routeParams", "MSCApi", "$sc_nav", "$sc_utility", function($scope, $routeParams, MSCApi, $sc_nav, $sc_utility){
  229. $sc_nav.in_clients();
  230. $scope.kickoff = function(client) {
  231. MSCApi.clients_delete(client.id, function(){
  232. $sc_utility.log("warn", "Kickoff client ok.");
  233. });
  234. };
  235. $sc_utility.refresh.stop();
  236. MSCApi.clients_get2($routeParams.id, function(data){
  237. $scope.client = data.client;
  238. });
  239. $sc_utility.log("trace", "Retrieve client info from SRS");
  240. }]);
  241. scApp.controller("CSCConfigs", ["$scope", "$location", "MSCApi", "$sc_nav", "$sc_utility", "$sc_server", function($scope, $location, MSCApi, $sc_nav, $sc_utility, $sc_server){
  242. $sc_nav.in_configs();
  243. $sc_utility.refresh.stop();
  244. MSCApi.configs_raw(function(data){
  245. $scope.http_api = data.http_api;
  246. });
  247. $sc_utility.log("trace", "Retrieve config info from SRS");
  248. }]);
  249. scApp.factory("MSCApi", ["$http", "$sc_server", function($http, $sc_server){
  250. return {
  251. versions_get: function(success) {
  252. var url = $sc_server.jsonp("/api/v1/versions");
  253. $http.jsonp(url).success(success);
  254. },
  255. summaries_get: function(success) {
  256. var url = $sc_server.jsonp("/api/v1/summaries");
  257. $http.jsonp(url).success(success);
  258. },
  259. vhosts_get: function(success) {
  260. var url = $sc_server.jsonp("/api/v1/vhosts/");
  261. $http.jsonp(url).success(success);
  262. },
  263. vhosts_get2: function(id, success) {
  264. var url = $sc_server.jsonp("/api/v1/vhosts/" + id);
  265. $http.jsonp(url).success(success);
  266. },
  267. streams_get: function(success) {
  268. var url = $sc_server.jsonp("/api/v1/streams/");
  269. $http.jsonp(url).success(success);
  270. },
  271. streams_get2: function(id, success) {
  272. var url = $sc_server.jsonp("/api/v1/streams/" + id);
  273. $http.jsonp(url).success(success);
  274. },
  275. clients_get: function(success) {
  276. var url = $sc_server.jsonp("/api/v1/clients/");
  277. $http.jsonp(url).success(success);
  278. },
  279. clients_get2: function(id, success) {
  280. var url = $sc_server.jsonp("/api/v1/clients/" + id);
  281. $http.jsonp(url).success(success);
  282. },
  283. clients_delete: function(id, success) {
  284. var url = $sc_server.jsonp_delete("/api/v1/clients/" + id);
  285. $http.jsonp(url).success(success);
  286. },
  287. configs_raw: function(success, error) {
  288. var url = $sc_server.jsonp_query("/api/v1/raw", "rpc=raw");
  289. var obj = $http.jsonp(url).success(success);
  290. if (error) {
  291. obj.error(error);
  292. }
  293. },
  294. configs_get: function(success) {
  295. var url = $sc_server.jsonp_query("/api/v1/raw", "rpc=query&scope=global");
  296. $http.jsonp(url).success(success);
  297. },
  298. };
  299. }]);
  300. scApp.filter("sc_filter_log_level", function(){
  301. return function(v) {
  302. return (v === "warn" || v === "error")? "alert-warn":"alert-success";
  303. };
  304. });
  305. scApp.filter("sc_filter_nav_active", ["$sc_nav", function($sc_nav){
  306. return function(v){
  307. return $sc_nav.is_selected(v)? "active":"";
  308. };
  309. }]);
  310. scApp.filter("sc_unsafe", ['$sce', function($sce){
  311. return function(v) {
  312. return $sce.trustAsHtml(v);
  313. };
  314. }]);
  315. scApp.filter("sc_filter_filesize_k", function(){
  316. return function(v){
  317. // PB
  318. if (v > 1024 * 1024 * 1024 * 1024) {
  319. return Number(v / 1024.0 / 1024 / 1024 / 1024).toFixed(2) + "PB";
  320. }
  321. // TB
  322. if (v > 1024 * 1024 * 1024) {
  323. return Number(v / 1024.0 / 1024 / 1024).toFixed(2) + "TB";
  324. }
  325. // GB
  326. if (v > 1024 * 1024) {
  327. return Number(v / 1024.0 / 1024).toFixed(2) + "GB";
  328. }
  329. // MB
  330. if (v > 1024) {
  331. return Number(v / 1024.0).toFixed(2) + "MB";
  332. }
  333. return Number(v).toFixed(2) + "KB";
  334. };
  335. });
  336. scApp.filter("sc_filter_filesize_k2", function(){
  337. return function(v){
  338. // PB
  339. if (v > 1024 * 1024 * 1024 * 1024) {
  340. return Number(v / 1024.0 / 1024 / 1024 / 1024).toFixed(0) + "PB";
  341. }
  342. // TB
  343. if (v > 1024 * 1024 * 1024) {
  344. return Number(v / 1024.0 / 1024 / 1024).toFixed(0) + "TB";
  345. }
  346. // GB
  347. if (v > 1024 * 1024) {
  348. return Number(v / 1024.0 / 1024).toFixed(0) + "GB";
  349. }
  350. // MB
  351. if (v > 1024) {
  352. return Number(v / 1024.0).toFixed(0) + "MB";
  353. }
  354. return Number(v).toFixed(0) + "KB";
  355. };
  356. });
  357. scApp.filter("sc_filter_filerate_k", function(){
  358. return function(v){
  359. // PB
  360. if (v > 1024 * 1024 * 1024 * 1024) {
  361. return Number(v / 1024.0 / 1024 / 1024 / 1024).toFixed(2) + "PBps";
  362. }
  363. // TB
  364. if (v > 1024 * 1024 * 1024) {
  365. return Number(v / 1024.0 / 1024 / 1024).toFixed(2) + "TBps";
  366. }
  367. // GB
  368. if (v > 1024 * 1024) {
  369. return Number(v / 1024.0 / 1024).toFixed(2) + "GBps";
  370. }
  371. // MB
  372. if (v > 1024) {
  373. return Number(v / 1024.0).toFixed(2) + "MBps";
  374. }
  375. return Number(v).toFixed(2) + "KBps";
  376. };
  377. });
  378. scApp.filter("sc_filter_filerate_k2", function(){
  379. return function(v){
  380. // PB
  381. if (v > 1024 * 1024 * 1024 * 1024) {
  382. return Number(v / 1024.0 / 1024 / 1024 / 1024).toFixed(0) + "PBps";
  383. }
  384. // TB
  385. if (v > 1024 * 1024 * 1024) {
  386. return Number(v / 1024.0 / 1024 / 1024).toFixed(0) + "TBps";
  387. }
  388. // GB
  389. if (v > 1024 * 1024) {
  390. return Number(v / 1024.0 / 1024).toFixed(0) + "GBps";
  391. }
  392. // MB
  393. if (v > 1024) {
  394. return Number(v / 1024.0).toFixed(0) + "MBps";
  395. }
  396. return Number(v).toFixed(0) + "KBps";
  397. };
  398. });
  399. scApp.filter("sc_filter_bitrate_k", function(){
  400. return function(v){
  401. // PB
  402. if (v > 1000 * 1000 * 1000 * 1000) {
  403. return Number(v / 1000.0 / 1000 / 1000 / 1000).toFixed(2) + "Pbps";
  404. }
  405. // TB
  406. if (v > 1000 * 1000 * 1000) {
  407. return Number(v / 1000.0 / 1000 / 1000).toFixed(2) + "Tbps";
  408. }
  409. // GB
  410. if (v > 1000 * 1000) {
  411. return Number(v / 1000.0 / 1000).toFixed(2) + "Gbps";
  412. }
  413. // MB
  414. if (v > 1000) {
  415. return Number(v / 1000.0).toFixed(2) + "Mbps";
  416. }
  417. return Number(v).toFixed(2) + "Kbps";
  418. };
  419. });
  420. scApp.filter("sc_filter_bitrate_k2", function(){
  421. return function(v){
  422. // PB
  423. if (v > 1000 * 1000 * 1000 * 1000) {
  424. return Number(v / 1000.0 / 1000 / 1000 / 1000).toFixed(0) + "Pbps";
  425. }
  426. // TB
  427. if (v > 1000 * 1000 * 1000) {
  428. return Number(v / 1000.0 / 1000 / 1000).toFixed(0) + "Tbps";
  429. }
  430. // GB
  431. if (v > 1000 * 1000) {
  432. return Number(v / 1000.0 / 1000).toFixed(0) + "Gbps";
  433. }
  434. // MB
  435. if (v > 1000) {
  436. return Number(v / 1000.0).toFixed(0) + "Mbps";
  437. }
  438. return Number(v).toFixed(0) + "Kbps";
  439. };
  440. });
  441. scApp.filter("sc_filter_percent", function(){
  442. return function(v){
  443. return Number(v).toFixed(2) + "%";
  444. };
  445. });
  446. scApp.filter("sc_filter_percent2", function(){
  447. return function(v){
  448. return Number(v).toFixed(0) + "%";
  449. };
  450. });
  451. scApp.filter("sc_filter_percentf", function(){
  452. return function(v){
  453. return Number(v * 100).toFixed(2) + "%";
  454. };
  455. });
  456. scApp.filter("sc_filter_percentf2", function(){
  457. return function(v){
  458. return Number(v * 100).toFixed(0) + "%";
  459. };
  460. });
  461. scApp.filter("sc_filter_video", function(){
  462. return function(v){
  463. // set default value for SRS2.
  464. v.width = v.width? v.width : 0;
  465. v.height = v.height? v.height : 0;
  466. return v? v.codec + "/" + v.profile + "/" + v.level + "/" + v.width + "x" + v.height : "无视频";
  467. };
  468. });
  469. scApp.filter("sc_filter_audio", function(){
  470. return function(v){
  471. return v? v.codec + "/" + v.sample_rate + "/" + (v.channel === 2? "Stereo":"Mono") + "/" + v.profile : "无音频";
  472. };
  473. });
  474. scApp.filter("sc_filter_number", function(){
  475. return function(v){
  476. return Number(v).toFixed(2);
  477. };
  478. });
  479. scApp.filter("sc_filter_less", function(){
  480. return function(v) {
  481. return v? (v.length > 15? v.slice(0, 15) + "...":v):v;
  482. };
  483. });
  484. scApp.filter('sc_filter_style_error', function(){
  485. return function(v){
  486. return v? 'alert-danger':'';
  487. };
  488. });
  489. scApp.filter('sc_filter_preview_url', ['$sc_server', function($sc_server){
  490. return function(v){
  491. var page = $sc_server.schema + `://${$sc_server.host}:${$sc_server.http}/players/srs_player.html`;
  492. var http = $sc_server.http[$sc_server.http.length - 1];
  493. var query = "vhost=" + v.owner.name + "&app=" + v.app + "&stream=" + v.name + ".flv";
  494. query += "&server=" + $sc_server.host +"&port=" + http + "&autostart=true&schema=" + $sc_server.schema;
  495. return v? page+"?" + query:"javascript:void(0)";
  496. };
  497. }]);
  498. scApp.filter('sc_filter_streamURL', function(){
  499. return function(v){
  500. if (!v || !v.url) return '';
  501. const pos = v.url.lastIndexOf('/');
  502. const stream = pos < 0 ? '' : v.url.substr(pos);
  503. // Use name or extract from url.
  504. let streamName = v.name ? v.name : stream;
  505. if (streamName && streamName.indexOf('/') !== 0) streamName = `/${streamName}`;
  506. const pos2 = v.tcUrl.indexOf('?');
  507. const tcUrl = pos2 < 0 ? v.tcUrl : v.tcUrl.substr(0, pos2);
  508. let params = pos2 < 0 ? '' : v.tcUrl.substr(pos2);
  509. if (params === '?vhost=__defaultVhost__' || params === '?domain=__defaultVhost__') params = '';
  510. return `${tcUrl}${streamName}${params}`;
  511. };
  512. });
  513. // the sc nav is the nevigator
  514. scApp.provider("$sc_nav", function(){
  515. this.$get = function(){
  516. return {
  517. selected: null,
  518. in_control: function(){
  519. this.selected = "/console";
  520. },
  521. in_summary: function(){
  522. this.selected = "/summaries";
  523. },
  524. in_vhosts: function(){
  525. this.selected = "/vhosts";
  526. },
  527. in_streams: function(){
  528. this.selected = "/streams";
  529. },
  530. in_clients: function(){
  531. this.selected = "/clients";
  532. },
  533. in_configs: function(){
  534. this.selected = "/configs";
  535. },
  536. go_summary: function($location){
  537. $location.path("/summaries");
  538. },
  539. is_selected: function(v){
  540. return v === this.selected;
  541. }
  542. };
  543. };
  544. });
  545. // the sc server is the server we connected to.
  546. scApp.provider("$sc_server", [function(){
  547. this.$get = function(){
  548. var self = {
  549. schema: "http",
  550. host: null,
  551. port: 1985,
  552. rtmp: [1935],
  553. http: [8080],
  554. baseurl: function(){
  555. return self.schema + "://" + self.host + (self.port === 80? "": ":" + self.port);
  556. },
  557. sstq: function () {
  558. const s = localStorage.getItem('SRS_TERRAFORM_TOKEN');
  559. const obj = s ? JSON.parse(s) : {};
  560. return obj.token ? `&token=${obj.token}` : '';
  561. },
  562. jsonp: function(url){
  563. return self.baseurl() + url + "?callback=JSON_CALLBACK" + self.sstq();
  564. },
  565. jsonp_delete: function(url) {
  566. return self.jsonp(url) + "&method=DELETE" + self.sstq();
  567. },
  568. jsonp_query: function(url, query){
  569. return self.baseurl() + url + "?callback=JSON_CALLBACK&" + query + self.sstq();
  570. },
  571. buildNavUrl: function () {
  572. var $location = self.$location;
  573. var url = $location.absUrl();
  574. if (url.indexOf('?') > 0) {
  575. url = url.slice(0, url.indexOf('?'));
  576. }
  577. url += '?';
  578. var query = {};
  579. for (var key in $location.search()) {
  580. query[key] = $location.search()[key];
  581. }
  582. query['schema'] = self.schema;
  583. query['host'] = self.host;
  584. query['port'] = self.port;
  585. var queries = [];
  586. for (var key in query) {
  587. var value = query[key];
  588. if (!Array.isArray(value)) {
  589. value = [value];
  590. }
  591. for (var i in value) {
  592. queries.push(key + '=' + value[i]);
  593. }
  594. }
  595. url += queries.join('&');
  596. return url;
  597. },
  598. init: function($location, MSCApi) {
  599. self.$location = $location;
  600. // Set the right schema for proxy.
  601. if ($location.search().schema) {
  602. self.schema = $location.search().schema;
  603. } else {
  604. self.schema = $location.protocol();
  605. }
  606. // query string then url.
  607. if ($location.search().host) {
  608. self.host = $location.search().host;
  609. } else {
  610. self.host = $location.host();
  611. }
  612. if ($location.search().port) {
  613. self.port = $location.search().port;
  614. } else {
  615. self.port = $location.port();
  616. }
  617. if ($location.search().http) {
  618. self.http = [$location.search().http];
  619. }
  620. }
  621. };
  622. return self;
  623. };
  624. }]);
  625. // the sc utility is a set of helper utilities.
  626. scApp.provider("$sc_utility", function(){
  627. this.$get = ["$rootScope", function($rootScope){
  628. return {
  629. log: function(level, msg) {
  630. $rootScope.$broadcast("$sc_utility_log", level, msg);
  631. },
  632. http_error: function(status, response) {
  633. $rootScope.$broadcast("$sc_utility_http_error", status, response);
  634. },
  635. find_siblings: function(elem, className) {
  636. if (elem.hasClass(className)) {
  637. return elem;
  638. }
  639. if (!elem[0].nextSibling) {
  640. return null;
  641. }
  642. var sibling = angular.element(elem[0].nextSibling);
  643. return this.find_siblings(sibling, className);
  644. },
  645. array_actual_equals: function(a, b) {
  646. // all elements of a in b.
  647. for (var i = 0; i < a.length; i++) {
  648. if (!system_array_contains(b, a[i])) {
  649. return false;
  650. }
  651. }
  652. // all elements of b in a.
  653. for (i = 0; i < b.length; i++) {
  654. if (!system_array_contains(a, b[i])) {
  655. return false;
  656. }
  657. }
  658. return true;
  659. },
  660. object2arr: function(obj, each) {
  661. var arr = [];
  662. for (var k in obj) {
  663. var v = obj[k];
  664. if (each) {
  665. each(v);
  666. }
  667. arr.push(v);
  668. }
  669. return arr;
  670. },
  671. /**
  672. * transform the api data to angularjs perfer, for instance:
  673. data.global.listen = ["1935, "1936"];
  674. data.global.http_api.listen = "1985";
  675. * parsed to:
  676. global.listen = {
  677. key: 'listen',
  678. value: ["1935", "1936"],
  679. error: false
  680. }
  681. global.http_api.listen = {
  682. key: 'http_api.listen',
  683. value: "1985",
  684. error: false
  685. }
  686. * where the error is used for commit error.
  687. */
  688. object2complex: function(complex, obj, prefix) {
  689. for (var k in obj) {
  690. var v = obj[k];
  691. //console.log("k=" + key + ", v=" + typeof v + ", " + v);
  692. var key = prefix? prefix + "." + k : k;
  693. if (key === "vhosts") {
  694. // use name as vhost id.
  695. complex[k] = this.object2arr(v, function(e) { e.vid = e.name; });
  696. continue;
  697. }
  698. if (typeof v === "object" && v.constructor !== Array) {
  699. var cv = {};
  700. complex[k] = cv;
  701. this.object2complex(cv, v, key);
  702. continue;
  703. }
  704. // convert number to str for select to
  705. // choose the right default one.
  706. if (key === "pithy_print_ms") {
  707. v = String(v);
  708. }
  709. complex[k] = {
  710. key: system_string_trim(key, 'global.'),
  711. value: v,
  712. error: false
  713. };
  714. }
  715. return complex;
  716. },
  717. copy_object: function(dst, src) {
  718. for (var k in src) {
  719. dst[k] = src[k];
  720. }
  721. },
  722. dvr_id: function(stream) {
  723. var url = '/dvr/' + stream.owner.name
  724. + '/' + stream.id
  725. + '/' + escape(stream.app.replace('/', '___'))
  726. + '/' + escape(stream.name.replace('/', '___'));
  727. return url;
  728. },
  729. raw_api_enabled: function(data) {
  730. return data.http_api && data.http_api.enabled && data.http_api.raw_api && data.http_api.raw_api.enabled;
  731. },
  732. refresh: async_refresh2
  733. };
  734. }];
  735. });
  736. // sc-collapse: scCollapse
  737. /**
  738. * Usage:
  739. <div class="accordion">
  740. <div class="accordion-group">
  741. <div class="accordion-heading" sc-collapse="in">
  742. <a class="accordion-toggle" href="javascript:void(0)">
  743. HTTP RAW API
  744. </a>
  745. </div>
  746. <div class="accordion-body collapse">
  747. <div class="accordion-inner">
  748. 该服务器不支持HTTP RAW API,或者配置中禁用了该功能。
  749. </div>
  750. </div>
  751. </div>
  752. </div>
  753. */
  754. scApp.directive('scCollapse', ["$sc_utility", function($sc_utility){
  755. return {
  756. restrict: 'A',
  757. scope: true,
  758. controller: ['$scope', function($scope) {
  759. }],
  760. compile: function(elem, attrs) {
  761. return function(scope, elem, attrs){
  762. if (attrs.scCollapse === "in") {
  763. var obj = $sc_utility.find_siblings(elem, 'accordion-body');
  764. obj.addClass('in');
  765. }
  766. elem.on('click', function(){
  767. var obj = $sc_utility.find_siblings(elem, 'accordion-body');
  768. obj.toggleClass('in');
  769. });
  770. };
  771. }
  772. };
  773. }]);
  774. // sc-pretty: scPretty
  775. /**
  776. * Usage:
  777. <tr sc-pretty scp-key="http_api.enabled" scp-value="http_api.enabled" scp-bool="true"
  778. scp-desc="是否开启HTTP API,开启后就可以访问SRS提供的API管理服务器。默认: {{false| sc_filter_enabled}}">
  779. </tr>
  780. */
  781. scApp.directive("scPretty", [function(){
  782. return {
  783. restrict: 'A',
  784. scope: {
  785. key: '@scpKey',
  786. value: '=scpValue',
  787. desc: '@scpDesc',
  788. bool: '@scpBool'
  789. },
  790. template: ''
  791. + '<td>{{key}}</td>'
  792. + '<td>'
  793. + '<span class="{{value == undefined? \'label\':\'\'}}">'
  794. + '<span ng-show="bool && value != undefined">{{value| sc_filter_enabled}}</span>'
  795. + '<span ng-show="!bool || value === undefined">{{value| sc_filter_obj}}</span>'
  796. + '</span>'
  797. + '</td>'
  798. + '<td>{{desc}}</td>'
  799. + '<td>只读</td>'
  800. };
  801. }]);
  802. // sc-pretty2: scPretty2
  803. /**
  804. * Usage:
  805. <tr sc-pretty2 scp-data="global.daemon" scp-bool="true"
  806. scp-desc="是否以后台启动SRS。默认: {{true| sc_filter_yesno}}">
  807. </tr>
  808. */
  809. scApp.directive("scPretty2", [function(){
  810. return {
  811. restrict: 'A',
  812. scope: {
  813. data: '=scpData',
  814. desc: '@scpDesc',
  815. bool: '@scpBool',
  816. link: '@scpLink'
  817. },
  818. controller: ['$scope', function($scope){
  819. }],
  820. template: ''
  821. + '<td>{{key}}</td>'
  822. + '<td>'
  823. + '<span ng-if="link">'
  824. + '<a href="{{link}}">{{data.value}}</a>'
  825. + '</span>'
  826. + '<span class="{{data.value == undefined? \'label\':\'\'}}" ng-if="!link">'
  827. + '<span ng-show="bool && data.value != undefined">{{data.value| sc_filter_enabled}}</span>'
  828. + '<span ng-show="!bool || data.value == undefined">{{data.value| sc_filter_obj}}</span>'
  829. + '</span>'
  830. + '</td>'
  831. + '<td>{{desc}}</td>'
  832. + '<td>Readonly</td>',
  833. link: function(scope, elem, attrs){
  834. scope.key = system_string_trim(attrs.scpData, "global.");
  835. }
  836. };
  837. }]);
  838. // sc-directive: scDirective
  839. /**
  840. * Usage:
  841. <tr sc-directive scd-data="obj"
  842. scd-desc="侦听的端口" scd-default="1935" scd-span="span3"
  843. scd-array="true" scd-bool="true" scd-select="1935,1936,1937"
  844. scd-submit="submit(obj)">
  845. </tr>
  846. * where obj is:
  847. {
  848. key: "listen",
  849. value: ["1935", "1936"],
  850. error: false
  851. }
  852. */
  853. scApp.directive("scDirective", ["$sc_utility", function($sc_utility){
  854. return {
  855. restrict: 'A',
  856. scope: {
  857. data: '=scdData',
  858. desc: '@scdDesc',
  859. submit: '&scdSubmit',
  860. span: '@scdSpan',
  861. default: '@scdDefault',
  862. array: '@scdArray',
  863. bool: '@scdBool',
  864. select: '@scdSelect'
  865. },
  866. controller: ['$scope', function($scope) {
  867. // whether current directive is editing.
  868. $scope.editing = false;
  869. // previous old value, for cancel and array value.
  870. $scope.old_data = {
  871. init: false,
  872. value: undefined,
  873. reset: function(){
  874. this.init = false;
  875. this.value = undefined;
  876. }
  877. };
  878. // split select to array.
  879. if (typeof $scope.select === "string" && $scope.select && !$scope.selects) {
  880. $scope.selects = $scope.select.split(",");
  881. }
  882. $scope.edit = function() {
  883. $scope.editing = true;
  884. };
  885. $scope.commit = function() {
  886. // for array, string to array.
  887. if ($scope.array === "true" && typeof $scope.data.value === "string") {
  888. $scope.data.value = $scope.data.value.split(",");
  889. }
  890. if ($scope.old_data.init && !$scope.submit()) {
  891. return;
  892. }
  893. $scope.editing = false;
  894. $scope.old_data.reset();
  895. };
  896. $scope.load_default = function(){
  897. if ($scope.default !== undefined) {
  898. if ($scope.bool === "true") {
  899. $scope.data.value = $scope.default === "true";
  900. } else if ($scope.array === "true") {
  901. $scope.data.value = $scope.default.split(",");
  902. } else {
  903. $scope.data.value = $scope.default;
  904. }
  905. }
  906. };
  907. $scope.cancel = function() {
  908. if ($scope.old_data.init) {
  909. $scope.data.value = $scope.old_data.value;
  910. }
  911. // for array, always restore it when cancel.
  912. if ($scope.array === "true") {
  913. $scope.data.value = $scope.old_data.value;
  914. }
  915. $scope.editing = false;
  916. $scope.old_data.reset();
  917. };
  918. $scope.$watch("editing", function(nv, ov){
  919. // init, ignore.
  920. if (!nv && !nv) {
  921. return;
  922. }
  923. // when server not set this option, the whole data is undefined.
  924. if (!$scope.data) {
  925. $scope.data = {
  926. key: $scope.key,
  927. value: undefined,
  928. error: false
  929. };
  930. }
  931. // save the old value.
  932. if (!$scope.old_data.init) {
  933. $scope.old_data.value = $scope.data.value;
  934. $scope.old_data.init = true;
  935. }
  936. // start editing.
  937. if (nv && !ov) {
  938. // for array, array to string.
  939. if ($scope.array === "true") {
  940. $scope.data.value = $scope.data.value.join(",");
  941. }
  942. }
  943. });
  944. }],
  945. template: scDirectiveTemplate,
  946. link: function(scope, elem, attrs){
  947. scope.key = system_string_trim(attrs.scdData, "global.");
  948. }
  949. };
  950. }]);
  951. // config the http interceptor.
  952. scApp.config(['$httpProvider', function($httpProvider){
  953. $httpProvider.interceptors.push('MHttpInterceptor');
  954. }]);
  955. // the http interceptor.
  956. scApp.factory('MHttpInterceptor', ["$q", "$sc_utility", function($q, $sc_utility){
  957. // register the interceptor as a service
  958. // @see: https://code.angularjs.org/1.2.0-rc.3/docs/api/ng.$http
  959. // @remark: the function($q) should never add other params.
  960. return {
  961. 'request': function(config) {
  962. return config || $q.when(config);
  963. },
  964. 'requestError': function(rejection) {
  965. return $q.reject(rejection);
  966. },
  967. 'response': function(response) {
  968. if (response.data.code && response.data.code !== 0) {
  969. $sc_utility.http_error(response.status, response.data);
  970. // the $q.reject, will cause the error function of controller.
  971. // @see: https://code.angularjs.org/1.2.0-rc.3/docs/api/ng.$q
  972. return $q.reject(response);
  973. }
  974. return response || $q.when(response);
  975. },
  976. 'responseError': function(rejection) {
  977. $sc_utility.http_error(rejection.status, rejection.data);
  978. return $q.reject(rejection);
  979. }
  980. };
  981. }]);