The frontend/UI server, written in JS using the MarkoJS library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
4.5 KiB

6 years ago
6 years ago
6 years ago
  1. const EventEmitter = require("events")
  2. const fetch = require("isomorphic-fetch")
  3. const config = require("../config")
  4. const compressQuery = require("graphql-query-compress")
  5. /**
  6. * Run a GraphQL query against the rpdata backend
  7. *
  8. * @param {string} query The query to run
  9. * @param {{[x:string]: any}} variables
  10. * @param {{operationName:string, token: string, permissions: string[]}} options
  11. */
  12. function query(query, variables = {}, options = {}) {
  13. return fetch(config.graphqlEndpoint, {
  14. method: "POST",
  15. headers: {
  16. "Content-Type": "application/json",
  17. "Authorization": options.token ? `Bearer ${options.token}` : null,
  18. //"X-Permissions": options.permissions ? options.permissions.join(",") : null,
  19. },
  20. body: JSON.stringify({query: query.length > 256 ? compressQuery(query || "") : query, variables, operationName: options.operationName}),
  21. credentials: "include",
  22. }).then(res => {
  23. return res.json()
  24. }).then(json => {
  25. if (json.errors != null && json.errors.length > 0) {
  26. return Promise.reject(json.errors)
  27. }
  28. return json.data
  29. })
  30. }
  31. /**
  32. *
  33. *
  34. * @param {string} query GQL Query
  35. * @param {Object} variables Variables
  36. * @param {{token?:string,permissions?:string[]}} options
  37. */
  38. function queryForm(query, variables = {}, options = {}) {
  39. const map = {}
  40. const files = []
  41. function findFiles(prefix, data) {
  42. for (const key in data) {
  43. if (!data.hasOwnProperty(key)) {
  44. continue
  45. }
  46. const value = data[key]
  47. if (value instanceof File) {
  48. map[files.length] = [`${prefix}.${key}`]
  49. files.push(value)
  50. } else if (typeof(value) === 'object') {
  51. data[key] = findFiles(`${prefix}.${key}`, Object.assign({}, value))
  52. }
  53. }
  54. return data
  55. }
  56. const operations = {
  57. query: query,
  58. variables: findFiles("variables", Object.assign({}, variables)),
  59. }
  60. const form = new FormData()
  61. form.append("operations", JSON.stringify(operations))
  62. form.append("map", JSON.stringify(map))
  63. for (let i = 0; i < files.length; ++i) {
  64. form.append(i.toString(), files[i])
  65. }
  66. console.log(form)
  67. return fetch(config.graphqlEndpoint, {
  68. method: "POST",
  69. headers: {
  70. "Authorization": options.token ? `Bearer ${options.token}` : null,
  71. "X-Permissions": options.permissions ? options.permissions.join(",") : null,
  72. },
  73. body: form,
  74. credentials: "include",
  75. }).then(res => {
  76. return res.json()
  77. }).then(json => {
  78. if (json.errors != null && json.errors.length > 0) {
  79. return Promise.reject(json.errors)
  80. }
  81. return json.data
  82. })
  83. }
  84. class Subscription extends EventEmitter {
  85. constructor(query, variables) {
  86. super()
  87. this.query = query
  88. this.variables = Object.assign({}, variables)
  89. this.websocket = null
  90. this.verboseLogging = false
  91. }
  92. connect() {
  93. const baseUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host
  94. let id = 1
  95. this.websocket = new WebSocket(baseUrl + config.graphqlEndpoint, "graphql-ws")
  96. this.websocket.onopen = () => {
  97. this.websocket.send(JSON.stringify({type: "connection_init", payload: {}}));
  98. this.websocket.send(JSON.stringify({id: (id++).toFixed(0), type: "start", payload: {
  99. query: this.query,
  100. variables: this.variables,
  101. extensions: {},
  102. }}));
  103. console.log("WS Open")
  104. }
  105. this.websocket.onmessage = (ev) => {
  106. let data = {}
  107. try {
  108. data = JSON.parse(ev.data)
  109. } catch (err) {
  110. console.warn("Error", err, ev)
  111. return
  112. }
  113. if (this.verboseLogging) {
  114. console.log("WS Data:", data)
  115. }
  116. switch (data.type) {
  117. case "connection_ack": {
  118. this.emit("connect")
  119. break;
  120. }
  121. case "connection_error": {
  122. console.warn("WS Connection Error", data.payload.message)
  123. this.websocket.close()
  124. this.emit("error", new Error(data.payload.message))
  125. break;
  126. }
  127. case "data": {
  128. if (data.payload.errors != null && data.payload.errors.length > 0) {
  129. this.emit("error", data.payload.errors)
  130. } else {
  131. this.emit("data", data.payload.data)
  132. }
  133. break;
  134. }
  135. }
  136. }
  137. this.websocket.onerror = (err) => {
  138. console.warn("WS Error", err)
  139. }
  140. this.websocket.onclose = () => {
  141. this.emit("disconnect")
  142. }
  143. }
  144. disconnect() {
  145. if (this.websocket != null) {
  146. this.websocket.close();
  147. }
  148. }
  149. }
  150. module.exports = { query, queryForm, Subscription }