Skip to content

Commit bac651b

Browse files
authored
Merge pull request #2 from ben-mizel/master
Master
2 parents fb647f7 + 4ba6e98 commit bac651b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+13778
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.eslintrc.js
3+
package-lock.json

LISENCE.md renamed to LICENSE.md

File renamed without changes.

Main.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
const { app, BrowserWindow, ipcMain } = require('electron');
2+
const fs = require('fs');
3+
const path = require('path');
4+
const connectSQL = require('./model/sql-connect');
5+
const connectMongoose = require('./model/mongoose-connect');
6+
const CommunicationSchema = require('./model/mongoose-communicatonSchema');
7+
const HealthInfoSchema = require('./model/mongoose-healthInfoSchema');
8+
9+
let win;
10+
function createWindow() {
11+
win = new BrowserWindow({
12+
width: 900,
13+
height: 800,
14+
icon: path.join(__dirname, 'app/assets/icons/icon.png'),
15+
webPreferences: {
16+
nodeIntegration: true,
17+
},
18+
});
19+
20+
// Development
21+
win.loadURL('http://localhost:8080/');
22+
23+
// Production
24+
// win.loadURL(`file://${path.join(__dirname, './dist/index.html')}`);
25+
26+
win.on('closed', () => {
27+
win = null;
28+
});
29+
}
30+
app.on('ready', createWindow);
31+
32+
app.on('window-all-closed', () => {
33+
if (process.platform !== 'darwin') {
34+
app.quit();
35+
}
36+
});
37+
38+
app.on('activate', () => {
39+
if (win === null) {
40+
createWindow();
41+
}
42+
});
43+
44+
// Load settings JSON and returns current setup status back to the render process.
45+
ipcMain.on('setup', (message) => {
46+
const state = JSON.parse(
47+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
48+
encoding: 'UTF-8',
49+
}),
50+
);
51+
const { setupRequired } = state;
52+
message.returnValue = setupRequired;
53+
});
54+
55+
// Loads existing settings JSON and update settings to include new services entered by the user.
56+
ipcMain.on('submit', (message, newService) => {
57+
const state = JSON.parse(
58+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
59+
encoding: 'UTF-8',
60+
}),
61+
);
62+
// if statement is used to replace hard coded data. Hard coded data and the michelleWasHere key is needed to avoid a load error caused by Electron querying the database before a user has added or selected a database.
63+
if (state.michelleWasHere) {
64+
state.setupRequired = false;
65+
state.michelleWasHere = false;
66+
state.services = [JSON.parse(newService)];
67+
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state));
68+
} else {
69+
state.setupRequired = false;
70+
state.services.push(JSON.parse(newService));
71+
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state));
72+
}
73+
});
74+
75+
// Load settings JSON and returns updated state back to the render process.
76+
ipcMain.on('dashboard', (message) => {
77+
const state = JSON.parse(
78+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
79+
encoding: 'UTF-8',
80+
}),
81+
);
82+
const { services } = state;
83+
const dashboardList = services.reduce((acc, curVal) => {
84+
acc.push(curVal[0]);
85+
return acc;
86+
}, []);
87+
message.returnValue = dashboardList;
88+
});
89+
90+
// Queries the database for communications information and returns it back to the render process.
91+
ipcMain.on('overviewRequest', (message, index) => {
92+
const databaseType = JSON.parse(
93+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), { encoding: 'UTF-8' }),
94+
).services[index][1];
95+
96+
if (databaseType === 'MongoDB') {
97+
connectMongoose(index);
98+
CommunicationSchema.find({}, (err, data) => {
99+
if (err) {
100+
console.log(`An error occured while querying the database: ${err}`);
101+
message.sender.send('overviewResponse', JSON.stringify(err));
102+
}
103+
const queryResults = JSON.stringify(data);
104+
// Asynchronous event emitter used to transmit query results back to the render process.
105+
message.sender.send('overviewResponse', queryResults);
106+
});
107+
}
108+
109+
if (databaseType === 'SQL') {
110+
const pool = connectSQL(index);
111+
const getCommunications = 'SELECT * FROM communications';
112+
pool.query(getCommunications, (err, result) => {
113+
if (err) {
114+
console.log(err);
115+
message.sender.send(JSON.stringify('Database info could not be retreived.'));
116+
}
117+
const queryResults = JSON.stringify(result.rows);
118+
// Asynchronous event emitter used to transmit query results back to the render process.
119+
message.sender.send('overviewResponse', queryResults);
120+
});
121+
}
122+
});
123+
124+
// Queries the database for computer health information and returns it back to the render process.
125+
ipcMain.on('detailsRequest', (message, index) => {
126+
const databaseType = JSON.parse(
127+
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), { encoding: 'UTF-8' }),
128+
).services[index][1];
129+
130+
if (databaseType === 'MongoDB') {
131+
connectMongoose(index);
132+
HealthInfoSchema.find({}, (err, data) => {
133+
if (err) {
134+
message.sender.send('detailsResponse', JSON.stringify(err));
135+
}
136+
const queryResults = JSON.stringify(data);
137+
// Asynchronous event emitter used to transmit query results back to the render process.
138+
message.sender.send('detailsResponse', queryResults);
139+
});
140+
}
141+
142+
if (databaseType === 'SQL') {
143+
const pool = connectSQL(index);
144+
const getHealth = 'SELECT * FROM healthInfo';
145+
pool.query(getHealth, (err, result) => {
146+
if (err) {
147+
message.sender.send('detailsResponse', JSON.stringify('Database info could not be retreived.'));
148+
}
149+
const queryResults = JSON.stringify(result.rows);
150+
// Asynchronous event emitter used to transmit query results back to the render process.
151+
message.sender.send('detailsResponse', queryResults);
152+
});
153+
}
154+
});

__tests__/spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const { Application } = require('spectron');
2+
const assert = require('assert');
3+
const electronPath = require('electron');
4+
const path = require('path');
5+
6+
describe('Application launch', function () {
7+
this.timeout(10000);
8+
9+
beforeEach(function () {
10+
this.app = new Application({
11+
path: electronPath,
12+
args: [path.join(__dirname, '..')],
13+
});
14+
return this.app.start();
15+
});
16+
17+
afterEach(function () {
18+
if (this.app && this.app.isRunning()) {
19+
return this.app.stop();
20+
}
21+
});
22+
23+
it('shows an initial window', function () {
24+
return this.app.client.getWindowCount().then(function (count) {
25+
assert.equal(count, 1);
26+
});
27+
});
28+
});

__tests__/test.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
var expect = require('chai').expect;
2+
var MongoClient = require('mongodb').MongoClient;
3+
4+
describe('middleware', () => {
5+
var healthInfo, db;
6+
7+
beforeAll(function (done) {
8+
MongoClient.connect(
9+
'mongodb+srv://numanzor:[email protected]/chronos-access', { useNewUrlParser: true }, function(err, client) {
10+
if (err) throw new Error(err);
11+
done();
12+
db = client.db('chronos-access');
13+
healthInfo = db.collection('healthinfos');
14+
}
15+
);
16+
});
17+
18+
test('should have records in the "healthinfos" collection', done => {
19+
healthInfo.countDocuments(function (err, num) {
20+
expect(err).to.not.exist;
21+
expect(num).to.be.above(0);
22+
done();
23+
});
24+
});
25+
26+
test('should have the right string and date-time fields', done => {
27+
healthInfo.find().toArray(function (err, data) {
28+
expect(err).to.not.exist;
29+
expect(data).to.be.an('Array');
30+
var dataPoint = data[0];
31+
expect(dataPoint.currentMicroservice).to.be.a('string').and.not.eql('');
32+
expect(dataPoint.targetedEndpoint).to.be.a('string').and.not.eql('');
33+
expect(dataPoint.reqType).to.be.a('string').and.not.eql('');
34+
expect(dataPoint.timeSent).to.be.a('date').and.not.eql('');
35+
done();
36+
});
37+
});
38+
39+
afterAll(function () {
40+
db.close();
41+
});
42+
});

app/assets/icon2.png

27.7 KB
Loading

app/assets/icons/icon.png

761 KB
Loading

app/assets/logo2.png

54.3 KB
Loading

app/charts/latency-chart.jsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React, { useContext } from 'react';
2+
import { Line } from 'react-chartjs-2';
3+
import HealthContext from '../context/DetailsContext';
4+
5+
const LatencyChart = (props) => {
6+
const xAxis = [];
7+
const yAxis = [];
8+
const healthData = useContext(HealthContext).detailData;
9+
for (let i = 0; i < healthData.length; i++) {
10+
const element = healthData[i];
11+
if (element.currentmicroservice === props.service || element.currentMicroservice === props.service) {
12+
xAxis.push(i);
13+
yAxis.push(element.latency);
14+
}
15+
}
16+
const chartData = {
17+
datasets: [
18+
{
19+
label: `CPU latency of ${props.service}`,
20+
data: yAxis,
21+
backgroundColor: ['rgb(254, 255, 0)'],
22+
},
23+
],
24+
options: {
25+
xAxisID: 'TBD',
26+
yAxisID: 'TBD',
27+
},
28+
labels: xAxis,
29+
};
30+
return (
31+
<div>
32+
<Line data={chartData} />
33+
</div>
34+
);
35+
};
36+
37+
export default LatencyChart;

app/charts/memory-chart.jsx

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { useContext } from 'react';
2+
import { Bar } from 'react-chartjs-2';
3+
import HealthContext from '../context/DetailsContext';
4+
5+
const MemoryChart = (props) => {
6+
const healthData = useContext(HealthContext).detailData;
7+
8+
const createChart = () => {
9+
const xAxis = [];
10+
const free = [];
11+
const used = [];
12+
const active = [];
13+
const total = [];
14+
15+
for (let i = 0; i < healthData.length; i += 1) {
16+
xAxis.push(i);
17+
// If Mongo
18+
if (healthData[i].currentMicroservice === props.service) {
19+
free.push(healthData[i].freeMemory);
20+
active.push(healthData[i].activeMemory);
21+
used.push(healthData[i].usedMemory);
22+
total.push(healthData[i].totalMemory);
23+
}
24+
25+
// If SQL
26+
if (healthData[i].currentmicroservice === props.service) {
27+
free.push(healthData[i].freememory);
28+
active.push(healthData[i].activememory);
29+
used.push(healthData[i].usedmemory);
30+
total.push(healthData[i].totalmemory);
31+
}
32+
}
33+
34+
const chartData = {
35+
datasets: [
36+
{
37+
label: 'Free Memory',
38+
backgroundColor: 'rgb(2, 210, 249)',
39+
data: free,
40+
// showLine: true,
41+
},
42+
{
43+
label: 'Used Memory',
44+
backgroundColor: 'rgb(239, 91, 145)',
45+
data: used,
46+
// showLine: true,
47+
},
48+
{
49+
label: 'Active Memory',
50+
backgroundColor: 'rgb(182, 219, 26)',
51+
data: active,
52+
// showLine: true,
53+
},
54+
{
55+
label: 'Total Memory',
56+
backgroundColor: 'rgb(252, 170, 52)',
57+
data: total,
58+
// showLine: true,
59+
},
60+
],
61+
labels: xAxis,
62+
};
63+
64+
return <Bar data={chartData} />;
65+
};
66+
67+
return <div>{createChart()}</div>;
68+
};
69+
70+
export default MemoryChart;

0 commit comments

Comments
 (0)