|
|
const EventEmitter = require("events") const fetch = require("isomorphic-fetch") const config = require("../config") const compressQuery = require("graphql-query-compress")
/** * Run a GraphQL query against the rpdata backend * * @param {string} query The query to run * @param {{[x:string]: any}} variables * @param {{operationName:string, token: string, permissions: string[]}} options */ function query(query, variables = {}, options = {}) { return fetch(config.graphqlEndpoint, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": options.token ? `Bearer ${options.token}` : null, //"X-Permissions": options.permissions ? options.permissions.join(",") : null,
}, body: JSON.stringify({query: query.length > 256 ? compressQuery(query || "") : query, variables, operationName: options.operationName}), credentials: "include", }).then(res => { return res.json() }).then(json => { if (json.errors != null && json.errors.length > 0) { return Promise.reject(json.errors) }
return json.data }) }
/** * * * @param {string} query GQL Query * @param {Object} variables Variables * @param {{token?:string,permissions?:string[]}} options */ function queryForm(query, variables = {}, options = {}) { const map = {} const files = [] function findFiles(prefix, data) { for (const key in data) { if (!data.hasOwnProperty(key)) { continue } const value = data[key]
if (value instanceof File) { map[files.length] = [`${prefix}.${key}`] files.push(value) } else if (typeof(value) === 'object') { data[key] = findFiles(`${prefix}.${key}`, Object.assign({}, value)) } }
return data } const operations = { query: query, variables: findFiles("variables", Object.assign({}, variables)), }
const form = new FormData() form.append("operations", JSON.stringify(operations)) form.append("map", JSON.stringify(map)) for (let i = 0; i < files.length; ++i) { form.append(i.toString(), files[i]) }
console.log(form)
return fetch(config.graphqlEndpoint, { method: "POST", headers: { "Authorization": options.token ? `Bearer ${options.token}` : null, "X-Permissions": options.permissions ? options.permissions.join(",") : null, }, body: form, credentials: "include", }).then(res => { return res.json() }).then(json => { if (json.errors != null && json.errors.length > 0) { return Promise.reject(json.errors) }
return json.data }) }
class Subscription extends EventEmitter { constructor(query, variables) { super()
this.query = query this.variables = Object.assign({}, variables) this.websocket = null this.verboseLogging = false }
connect() { const baseUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host let id = 1
this.websocket = new WebSocket(baseUrl + config.graphqlEndpoint, "graphql-ws") this.websocket.onopen = () => { this.websocket.send(JSON.stringify({type: "connection_init", payload: {}})); this.websocket.send(JSON.stringify({id: (id++).toFixed(0), type: "start", payload: { query: this.query, variables: this.variables, extensions: {}, }}));
console.log("WS Open") }
this.websocket.onmessage = (ev) => { let data = {} try { data = JSON.parse(ev.data) } catch (err) { console.warn("Error", err, ev) return }
if (this.verboseLogging) { console.log("WS Data:", data) }
switch (data.type) { case "connection_ack": { this.emit("connect") break; }
case "connection_error": { console.warn("WS Connection Error", data.payload.message) this.websocket.close()
this.emit("error", new Error(data.payload.message))
break; }
case "data": { if (data.payload.errors != null && data.payload.errors.length > 0) { this.emit("error", data.payload.errors) } else { this.emit("data", data.payload.data) }
break; } } }
this.websocket.onerror = (err) => { console.warn("WS Error", err) }
this.websocket.onclose = () => { this.emit("disconnect") } }
disconnect() { if (this.websocket != null) { this.websocket.close(); } } }
module.exports = { query, queryForm, Subscription }
|