1
0

uci.uc 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright 2022 Jo-Philipp Wich <jo@mein.io>
  2. // Licensed to the public under the Apache License 2.0.
  3. import { STATUS_NO_DATA, STATUS_PERMISSION_DENIED } from 'ubus';
  4. let last_ubus_error;
  5. const ubus_error_map = [
  6. 200, 'OK',
  7. 400, 'Invalid command',
  8. 400, 'Invalid argument',
  9. 404, 'Method not found',
  10. 404, 'Not found',
  11. 204, 'No data',
  12. 403, 'Permission denied',
  13. 504, 'Timeout',
  14. 500, 'Not supported',
  15. 500, 'Unknown error',
  16. 503, 'Connection failed',
  17. 500, 'Out of memory',
  18. 400, 'Parse error',
  19. 500, 'System error',
  20. ];
  21. function ubus_call(object, method, args) {
  22. ubus.error(); // clear previous error
  23. let res = ubus.call(object, method, args);
  24. last_ubus_error = ubus.error(true);
  25. return res ?? !last_ubus_error;
  26. }
  27. function ubus_state_to_http(err) {
  28. let code = ubus_error_map[(err << 1) + 0] ?? 200;
  29. let msg = ubus_error_map[(err << 1) + 1] ?? 'OK';
  30. http.status(code, msg);
  31. if (code != 204) {
  32. http.prepare_content('text/plain');
  33. http.write(msg);
  34. }
  35. }
  36. function uci_apply(rollback) {
  37. if (rollback) {
  38. const timeout = +(config?.apply?.rollback ?? 90) || 0;
  39. const success = ubus_call('uci', 'apply', {
  40. ubus_rpc_session: ctx.authsession,
  41. timeout: max(timeout, 90),
  42. rollback: true
  43. });
  44. if (success) {
  45. const token = dispatcher.randomid(16);
  46. ubus.call('session', 'set', {
  47. ubus_rpc_session: '00000000000000000000000000000000',
  48. values: {
  49. rollback: {
  50. token,
  51. session: ctx.authsession,
  52. timeout: time() + timeout
  53. }
  54. }
  55. });
  56. return token;
  57. }
  58. return null;
  59. }
  60. else {
  61. let changes = ubus_call('uci', 'changes', { ubus_rpc_session: ctx.authsession })?.changes;
  62. for (let config in changes)
  63. if (!ubus_call('uci', 'commit', { ubus_rpc_session: ctx.authsession, config }))
  64. return false;
  65. return ubus_call('uci', 'apply', {
  66. ubus_rpc_session: ctx.authsession,
  67. rollback: false
  68. });
  69. }
  70. }
  71. function uci_confirm(token) {
  72. const data = ubus.call('session', 'get', {
  73. ubus_rpc_session: '00000000000000000000000000000000',
  74. keys: [ 'rollback' ]
  75. })?.values?.rollback;
  76. if (type(data?.token) != 'string' || type(data?.session) != 'string' ||
  77. type(data?.timeout) != 'int' || data.timeout < time()) {
  78. last_ubus_error = STATUS_NO_DATA;
  79. return false;
  80. }
  81. if (token != data.token) {
  82. last_ubus_error = STATUS_PERMISSION_DENIED;
  83. return false;
  84. }
  85. if (!ubus_call('uci', 'confirm', { ubus_rpc_session: data.session }))
  86. return false;
  87. ubus_call('session', 'set', {
  88. ubus_rpc_session: '00000000000000000000000000000000',
  89. values: { rollback: {} }
  90. });
  91. return true;
  92. }
  93. return {
  94. action_apply_rollback: function() {
  95. const token = uci_apply(true);
  96. if (token) {
  97. http.prepare_content('application/json; charset=UTF-8');
  98. http.write_json({ token });
  99. }
  100. else {
  101. ubus_state_to_http(last_ubus_error);
  102. }
  103. },
  104. action_apply_unchecked: function() {
  105. uci_apply(false);
  106. ubus_state_to_http(last_ubus_error);
  107. },
  108. action_confirm: function() {
  109. uci_confirm(http.formvalue('token'));
  110. ubus_state_to_http(last_ubus_error);
  111. },
  112. action_revert: function() {
  113. for (let config in ubus_call('uci', 'changes', { ubus_rpc_session: ctx.authsession })?.changes)
  114. if (!ubus_call('uci', 'revert', { ubus_rpc_session: ctx.authsession, config }))
  115. break;
  116. ubus_state_to_http(last_ubus_error);
  117. }
  118. };