mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
Refactored API URL generation to function calls and added tests
This commit is contained in:
committed by
jpellizzari
parent
43cb7548d8
commit
f65f39b128
@@ -9,7 +9,7 @@ import Term from 'xterm';
|
||||
import { clickCloseTerminal } from '../actions/app-actions';
|
||||
import { getNeutralColor } from '../utils/color-utils';
|
||||
import { setDocumentTitle } from '../utils/title-utils';
|
||||
import { getPipeStatus, doResizeTty, wsUrl } from '../utils/web-api-utils';
|
||||
import { getPipeStatus, doResizeTty, getWebsocketUrl } from '../utils/web-api-utils';
|
||||
|
||||
const log = debug('scope:terminal');
|
||||
|
||||
@@ -101,14 +101,14 @@ class Terminal extends React.Component {
|
||||
}
|
||||
|
||||
createWebsocket(term) {
|
||||
const socket = new WebSocket(`${wsUrl}/api/pipe/${this.getPipeId()}`);
|
||||
const socket = new WebSocket(`${getWebsocketUrl()}/api/pipe/${this.getPipeId()}`);
|
||||
socket.binaryType = 'arraybuffer';
|
||||
|
||||
getPipeStatus(this.getPipeId(), this.props.dispatch);
|
||||
|
||||
socket.onopen = () => {
|
||||
clearTimeout(this.reconnectTimeout);
|
||||
log('socket open to', wsUrl);
|
||||
log('socket open to', getWebsocketUrl());
|
||||
this.setState({connected: true});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
|
||||
import {OrderedMap as makeOrderedMap} from 'immutable';
|
||||
import { buildOptionsQuery, basePath, getApiPath, getWebsocketUrl } from '../web-api-utils';
|
||||
|
||||
describe('WebApiUtils', () => {
|
||||
const WebApiUtils = require('../web-api-utils');
|
||||
|
||||
describe('basePath', () => {
|
||||
const basePath = WebApiUtils.basePath;
|
||||
|
||||
it('should handle /scope/terminal.html', () => {
|
||||
expect(basePath('/scope/terminal.html')).toBe('/scope');
|
||||
});
|
||||
@@ -25,8 +22,6 @@ describe('WebApiUtils', () => {
|
||||
});
|
||||
|
||||
describe('buildOptionsQuery', () => {
|
||||
const buildOptionsQuery = WebApiUtils.buildOptionsQuery;
|
||||
|
||||
it('should handle empty options', () => {
|
||||
expect(buildOptionsQuery(makeOrderedMap({}))).toBe('');
|
||||
});
|
||||
@@ -38,4 +33,55 @@ describe('WebApiUtils', () => {
|
||||
]))).toBe('foo=2&bar=4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getApiPath', () => {
|
||||
afterEach(() => {
|
||||
delete process.env.SCOPE_API_PREFIX;
|
||||
});
|
||||
it('returns the correct url when running standalone', () => {
|
||||
expect(getApiPath('/')).toEqual('');
|
||||
});
|
||||
it('returns the correct url when running in an iframe', () => {
|
||||
expect(getApiPath('/api/app/proud-cloud-77')).toEqual('/api/app/proud-cloud-77');
|
||||
});
|
||||
it('returns the correct url when running as a component', () => {
|
||||
process.env.SCOPE_API_PREFIX = '/api';
|
||||
expect(getApiPath('/app/proud-cloud-77')).toEqual('/api/app/proud-cloud-77');
|
||||
});
|
||||
it('returns the correct url from an arbitrary path', () => {
|
||||
expect(getApiPath('/demo/')).toEqual('/demo');
|
||||
});
|
||||
it('returns the correct url from an *.html page', () => {
|
||||
expect(getApiPath('/contrast.html')).toEqual('');
|
||||
});
|
||||
it('returns the correct url from an /*.html page while in an iframe', () => {
|
||||
expect(getApiPath('/api/app/proud-cloud-77/contrast.html')).toEqual('/api/app/proud-cloud-77');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWebsocketUrl', () => {
|
||||
const host = 'localhost:4042';
|
||||
afterEach(() => {
|
||||
delete process.env.SCOPE_API_PREFIX;
|
||||
});
|
||||
it('returns the correct url when running standalone', () => {
|
||||
expect(getWebsocketUrl(host, '/')).toEqual(`ws://${host}`);
|
||||
});
|
||||
it('returns the correct url when running in an iframe', () => {
|
||||
expect(getWebsocketUrl(host, '/api/app/proud-cloud-77')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
|
||||
});
|
||||
it('returns the correct url when running as a component', () => {
|
||||
process.env.SCOPE_API_PREFIX = '/api';
|
||||
expect(getWebsocketUrl(host, '/app/proud-cloud-77')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
|
||||
});
|
||||
it('returns the correct url from an arbitrary path', () => {
|
||||
expect(getWebsocketUrl(host, '/demo/')).toEqual(`ws://${host}/demo`);
|
||||
});
|
||||
it('returns the correct url from an *.html page', () => {
|
||||
expect(getWebsocketUrl(host, '/contrast.html')).toEqual(`ws://${host}`);
|
||||
});
|
||||
it('returns the correct url from an /*.html page while in an iframe', () => {
|
||||
expect(getWebsocketUrl(host, '/api/app/proud-cloud-77/contrast.html')).toEqual(`ws://${host}/api/app/proud-cloud-77`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,26 +58,18 @@ export function basePathSlash(urlPath) {
|
||||
return `${basePath(urlPath)}/`;
|
||||
}
|
||||
|
||||
// JJP - `apiPath` is used to get API URLs right when running as a React component.
|
||||
// This needs to be refactored to just accept a URL prop on the scope component.
|
||||
let apiPath;
|
||||
let websocketUrl;
|
||||
const isIframe = window.location !== window.parent.location;
|
||||
const isStandalone = window.location.pathname === '/'
|
||||
|| window.location.pathname === '/demo/'
|
||||
|| window.location.pathname === '/scoped/'
|
||||
|| /\/(.+).html/.test(window.location.pathname);
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
export function getApiPath(pathname = window.location.pathname) {
|
||||
if (process.env.SCOPE_API_PREFIX) {
|
||||
return basePath(`${process.env.SCOPE_API_PREFIX}${pathname}`);
|
||||
}
|
||||
|
||||
if (isIframe || isStandalone) {
|
||||
apiPath = 'api';
|
||||
websocketUrl = `${wsProto}://${location.host}${basePath(location.pathname)}`;
|
||||
} else {
|
||||
apiPath = `/api${basePath(window.location.pathname)}/api`;
|
||||
websocketUrl = `${wsProto}://${location.host}/api${basePath(window.location.pathname)}`;
|
||||
return basePath(pathname);
|
||||
}
|
||||
|
||||
export const wsUrl = websocketUrl;
|
||||
export function getWebsocketUrl(host = window.location.host, pathname = window.location.pathname) {
|
||||
const wsProto = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
return `${wsProto}://${host}${process.env.SCOPE_API_PREFIX || ''}${basePath(pathname)}`;
|
||||
}
|
||||
|
||||
function createWebsocket(topologyUrl, optionsQuery, dispatch) {
|
||||
if (socket) {
|
||||
@@ -92,7 +84,7 @@ function createWebsocket(topologyUrl, optionsQuery, dispatch) {
|
||||
createWebsocketAt = new Date();
|
||||
firstMessageOnWebsocketAt = 0;
|
||||
|
||||
socket = new WebSocket(`${wsUrl}${topologyUrl}/ws?t=${updateFrequency}&${optionsQuery}`);
|
||||
socket = new WebSocket(`${getWebsocketUrl()}${topologyUrl}/ws?t=${updateFrequency}&${optionsQuery}`);
|
||||
|
||||
socket.onopen = () => {
|
||||
dispatch(openWebsocket());
|
||||
@@ -154,7 +146,7 @@ export function getAllNodes(getState, dispatch) {
|
||||
export function getTopologies(options, dispatch) {
|
||||
clearTimeout(topologyTimer);
|
||||
const optionsQuery = buildOptionsQuery(options);
|
||||
const url = `${apiPath}/topology?${optionsQuery}`;
|
||||
const url = `${getApiPath()}/api/topology?${optionsQuery}`;
|
||||
reqwest({
|
||||
url,
|
||||
success: (res) => {
|
||||
@@ -189,7 +181,7 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
|
||||
const obj = nodeMap.last();
|
||||
if (obj && topologyUrlsById.has(obj.topologyId)) {
|
||||
const topologyUrl = topologyUrlsById.get(obj.topologyId);
|
||||
let urlComponents = [apiPath, '/', trimStart(topologyUrl, '/api'), '/', encodeURIComponent(obj.id)];
|
||||
let urlComponents = [getApiPath(), topologyUrl, '/', encodeURIComponent(obj.id)];
|
||||
if (currentTopologyId === obj.topologyId) {
|
||||
// Only forward filters for nodes in the current topology
|
||||
const optionsQuery = buildOptionsQuery(options);
|
||||
@@ -222,7 +214,7 @@ export function getNodeDetails(topologyUrlsById, currentTopologyId, options, nod
|
||||
|
||||
export function getApiDetails(dispatch) {
|
||||
clearTimeout(apiDetailsTimer);
|
||||
const url = apiPath;
|
||||
const url = getApiPath();
|
||||
reqwest({
|
||||
url,
|
||||
success: (res) => {
|
||||
@@ -243,7 +235,7 @@ export function getApiDetails(dispatch) {
|
||||
|
||||
export function doControlRequest(nodeId, control, dispatch) {
|
||||
clearTimeout(controlErrorTimer);
|
||||
const url = `${apiPath}/control/${encodeURIComponent(control.probeId)}/`
|
||||
const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/`
|
||||
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
|
||||
reqwest({
|
||||
method: 'POST',
|
||||
@@ -279,7 +271,7 @@ export function doControlRequest(nodeId, control, dispatch) {
|
||||
|
||||
|
||||
export function doResizeTty(pipeId, control, cols, rows) {
|
||||
const url = `${apiPath}/control/${encodeURIComponent(control.probeId)}/`
|
||||
const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/`
|
||||
+ `${encodeURIComponent(control.nodeId)}/${control.id}`;
|
||||
|
||||
return reqwest({
|
||||
@@ -294,7 +286,7 @@ export function doResizeTty(pipeId, control, cols, rows) {
|
||||
|
||||
|
||||
export function deletePipe(pipeId, dispatch) {
|
||||
const url = `${apiPath}/pipe/${encodeURIComponent(pipeId)}`;
|
||||
const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}`;
|
||||
reqwest({
|
||||
method: 'DELETE',
|
||||
url,
|
||||
@@ -310,7 +302,7 @@ export function deletePipe(pipeId, dispatch) {
|
||||
|
||||
|
||||
export function getPipeStatus(pipeId, dispatch) {
|
||||
const url = `${apiPath}/pipe/${encodeURIComponent(pipeId)}/check`;
|
||||
const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}/check`;
|
||||
reqwest({
|
||||
method: 'GET',
|
||||
url,
|
||||
|
||||
Reference in New Issue
Block a user