Rename services to remove "app"
This commit is contained in:
18
result/.vscode/launch.json
vendored
Normal file
18
result/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 5858,
|
||||
"address": "localhost",
|
||||
"restart": true,
|
||||
"sourceMaps": false,
|
||||
"outDir": null,
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": "/app",
|
||||
"timeout": 10000
|
||||
}
|
||||
]
|
||||
}
|
16
result/Dockerfile
Normal file
16
result/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM node:5.11.0-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install -g nodemon
|
||||
ADD package.json /app/package.json
|
||||
RUN npm config set registry http://registry.npmjs.org
|
||||
RUN npm install && npm ls
|
||||
RUN mv /app/node_modules /node_modules
|
||||
|
||||
ADD . /app
|
||||
|
||||
ENV PORT 80
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["node", "server.js"]
|
60
result/docker-compose.test.yml
Normal file
60
result/docker-compose.test.yml
Normal file
@ -0,0 +1,60 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
|
||||
sut:
|
||||
build: ./tests/
|
||||
depends_on:
|
||||
- vote
|
||||
- result
|
||||
- worker
|
||||
networks:
|
||||
- front-tier
|
||||
|
||||
vote:
|
||||
build: ../vote/
|
||||
ports: ["80"]
|
||||
depends_on:
|
||||
- redis
|
||||
- db
|
||||
networks:
|
||||
- front-tier
|
||||
- back-tier
|
||||
|
||||
result:
|
||||
build: .
|
||||
ports: ["80"]
|
||||
depends_on:
|
||||
- redis
|
||||
- db
|
||||
networks:
|
||||
- front-tier
|
||||
- back-tier
|
||||
|
||||
worker:
|
||||
build: ../worker/
|
||||
depends_on:
|
||||
- redis
|
||||
- db
|
||||
networks:
|
||||
- back-tier
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
ports: ["6379"]
|
||||
networks:
|
||||
- back-tier
|
||||
|
||||
db:
|
||||
image: postgres:9.4
|
||||
volumes:
|
||||
- "db-data:/var/lib/postgresql/data"
|
||||
networks:
|
||||
- back-tier
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
|
||||
networks:
|
||||
front-tier:
|
||||
back-tier:
|
20
result/package.json
Normal file
20
result/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "result",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.14.1",
|
||||
"cookie-parser": "^1.4.0",
|
||||
"express": "^4.13.3",
|
||||
"method-override": "^2.3.5",
|
||||
"async": "^1.5.0",
|
||||
"pg": "^4.4.3",
|
||||
"socket.io": "^1.3.7"
|
||||
}
|
||||
}
|
85
result/server.js
Normal file
85
result/server.js
Normal file
@ -0,0 +1,85 @@
|
||||
var express = require('express'),
|
||||
async = require('async'),
|
||||
pg = require("pg"),
|
||||
cookieParser = require('cookie-parser'),
|
||||
bodyParser = require('body-parser'),
|
||||
methodOverride = require('method-override'),
|
||||
app = express(),
|
||||
server = require('http').Server(app),
|
||||
io = require('socket.io')(server);
|
||||
|
||||
io.set('transports', ['polling']);
|
||||
|
||||
var port = process.env.PORT || 4000;
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
|
||||
socket.emit('message', { text : 'Welcome!' });
|
||||
|
||||
socket.on('subscribe', function (data) {
|
||||
socket.join(data.channel);
|
||||
});
|
||||
});
|
||||
|
||||
async.retry(
|
||||
{times: 1000, interval: 1000},
|
||||
function(callback) {
|
||||
pg.connect('postgres://postgres@db/postgres', function(err, client, done) {
|
||||
if (err) {
|
||||
console.error("Failed to connect to db");
|
||||
}
|
||||
callback(err, client);
|
||||
});
|
||||
},
|
||||
function(err, client) {
|
||||
if (err) {
|
||||
return console.err("Giving up");
|
||||
}
|
||||
console.log("Connected to db");
|
||||
getVotes(client);
|
||||
}
|
||||
);
|
||||
|
||||
function getVotes(client) {
|
||||
client.query('SELECT vote, COUNT(id) AS count FROM votes GROUP BY vote', [], function(err, result) {
|
||||
if (err) {
|
||||
console.error("Error performing query: " + err);
|
||||
} else {
|
||||
var votes = collectVotesFromResult(result);
|
||||
io.sockets.emit("scores", JSON.stringify(votes));
|
||||
}
|
||||
|
||||
setTimeout(function() {getVotes(client) }, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function collectVotesFromResult(result) {
|
||||
var votes = {a: 0, b: 0};
|
||||
|
||||
result.rows.forEach(function (row) {
|
||||
votes[row.vote] = parseInt(row.count);
|
||||
});
|
||||
|
||||
return votes;
|
||||
}
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(bodyParser());
|
||||
app.use(methodOverride('X-HTTP-Method-Override'));
|
||||
app.use(function(req, res, next) {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||
res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.static(__dirname + '/views'));
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.sendFile(path.resolve(__dirname + '/views/index.html'));
|
||||
});
|
||||
|
||||
server.listen(port, function () {
|
||||
var port = server.address().port;
|
||||
console.log('App running on port ' + port);
|
||||
});
|
5
result/tests/Dockerfile
Normal file
5
result/tests/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM node
|
||||
RUN npm install -g phantomjs
|
||||
ADD . /app
|
||||
WORKDIR /app
|
||||
CMD ["/app/tests.sh"]
|
15
result/tests/render.js
Normal file
15
result/tests/render.js
Normal file
@ -0,0 +1,15 @@
|
||||
var system = require('system');
|
||||
var page = require('webpage').create();
|
||||
var url = system.args[1];
|
||||
|
||||
page.onLoadFinished = function() {
|
||||
setTimeout(function(){
|
||||
console.log(page.content);
|
||||
phantom.exit();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
page.open(url, function() {
|
||||
page.evaluate(function() {
|
||||
});
|
||||
});
|
15
result/tests/tests.sh
Executable file
15
result/tests/tests.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
while ! timeout 1 bash -c "echo > /dev/tcp/vote/80"; do sleep 1; done
|
||||
curl -sS -X POST --data "vote=a" http://vote > /dev/null
|
||||
curl -sS -X POST --data "vote=b" http://vote > /dev/null
|
||||
sleep 10
|
||||
if phantomjs render.js http://result | grep -q '2 votes'; then
|
||||
echo -e "\e[42m------------"
|
||||
echo -e "\e[92mTests passed"
|
||||
echo -e "\e[42m------------"
|
||||
exit 0
|
||||
fi
|
||||
echo -e "\e[41m------------"
|
||||
echo -e "\e[91mTests failed"
|
||||
echo -e "\e[41m------------"
|
||||
exit 1
|
50
result/views/app.js
Normal file
50
result/views/app.js
Normal file
@ -0,0 +1,50 @@
|
||||
var app = angular.module('catsvsdogs', []);
|
||||
var socket = io.connect({transports:['polling']});
|
||||
|
||||
var bg1 = document.getElementById('background-stats-1');
|
||||
var bg2 = document.getElementById('background-stats-2');
|
||||
|
||||
app.controller('statsCtrl', function($scope){
|
||||
$scope.aPercent = 50;
|
||||
$scope.bPercent = 50;
|
||||
|
||||
var updateScores = function(){
|
||||
socket.on('scores', function (json) {
|
||||
data = JSON.parse(json);
|
||||
var a = parseInt(data.a || 0);
|
||||
var b = parseInt(data.b || 0);
|
||||
|
||||
var percentages = getPercentages(a, b);
|
||||
|
||||
bg1.style.width = percentages.a + "%";
|
||||
bg2.style.width = percentages.b + "%";
|
||||
|
||||
$scope.$apply(function () {
|
||||
$scope.aPercent = percentages.a;
|
||||
$scope.bPercent = percentages.b;
|
||||
$scope.total = a + b;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var init = function(){
|
||||
document.body.style.opacity=1;
|
||||
updateScores();
|
||||
};
|
||||
socket.on('message',function(data){
|
||||
init();
|
||||
});
|
||||
});
|
||||
|
||||
function getPercentages(a, b) {
|
||||
var result = {};
|
||||
|
||||
if (a + b > 0) {
|
||||
result.a = Math.round(a / (a + b) * 100);
|
||||
result.b = 100 - result.a;
|
||||
} else {
|
||||
result.a = result.b = 50;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
43
result/views/index.html
Normal file
43
result/views/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="catsvsdogs">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Cats vs Dogs -- Result</title>
|
||||
<base href="/index.html">
|
||||
<meta name = "viewport" content = "width=device-width, initial-scale = 1.0">
|
||||
<meta name="keywords" content="docker-compose, docker, stack">
|
||||
<meta name="author" content="Docker">
|
||||
<link rel='stylesheet' href='/stylesheets/style.css' />
|
||||
</head>
|
||||
<body ng-controller="statsCtrl" >
|
||||
<div id="background-stats">
|
||||
<div id="background-stats-1">
|
||||
</div><!--
|
||||
--><div id="background-stats-2">
|
||||
</div>
|
||||
</div>
|
||||
<div id="content-container">
|
||||
<div id="content-container-center">
|
||||
<div id="choice">
|
||||
<div class="choice cats">
|
||||
<div class="label">Cats</div>
|
||||
<div class="stat">{{aPercent | number:1}}%</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="choice dogs">
|
||||
<div class="label">Dogs</div>
|
||||
<div class="stat">{{bPercent | number:1}}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="result">
|
||||
<span ng-if="total == 0">No votes yet</span>
|
||||
<span ng-if="total == 1">{{total}} vote</span>
|
||||
<span ng-if="total >= 2">{{total}} votes</span>
|
||||
</div>
|
||||
<script src="socket.io.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
6988
result/views/socket.io.js
Normal file
6988
result/views/socket.io.js
Normal file
File diff suppressed because it is too large
Load Diff
112
result/views/stylesheets/style.css
Normal file
112
result/views/stylesheets/style.css
Normal file
@ -0,0 +1,112 @@
|
||||
@import url(//fonts.googleapis.com/css?family=Open+Sans:400,700,600);
|
||||
|
||||
*{
|
||||
box-sizing:border-box;
|
||||
}
|
||||
html,body{
|
||||
margin:0;
|
||||
padding:0;
|
||||
height:100%;
|
||||
font-family: 'Open Sans';
|
||||
}
|
||||
body{
|
||||
opacity:0;
|
||||
transition: all 1s linear;
|
||||
}
|
||||
|
||||
.divider{
|
||||
height: 150px;
|
||||
width:2px;
|
||||
background-color: #C0C9CE;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
float: left;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#background-stats-1{
|
||||
background-color: #2196f3;
|
||||
}
|
||||
|
||||
#background-stats-2{
|
||||
background-color: #00cbca;
|
||||
}
|
||||
|
||||
#content-container{
|
||||
z-index:2;
|
||||
position:relative;
|
||||
margin:0 auto;
|
||||
display:table;
|
||||
padding:10px;
|
||||
max-width:940px;
|
||||
height:100%;
|
||||
}
|
||||
#content-container-center{
|
||||
display:table-cell;
|
||||
text-align:center;
|
||||
vertical-align:middle;
|
||||
}
|
||||
#result{
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
right: 20px;
|
||||
color: #fff;
|
||||
opacity: 0.5;
|
||||
font-size: 45px;
|
||||
font-weight: 600;
|
||||
}
|
||||
#choice{
|
||||
transition: all 300ms linear;
|
||||
line-height:1.3em;
|
||||
background:#fff;
|
||||
box-shadow: 10px 0 0 #fff, -10px 0 0 #fff;
|
||||
vertical-align:middle;
|
||||
font-size:40px;
|
||||
font-weight: 600;
|
||||
width: 450px;
|
||||
height: 200px;
|
||||
}
|
||||
#choice a{
|
||||
text-decoration:none;
|
||||
}
|
||||
#choice a:hover, #choice a:focus{
|
||||
outline:0;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
#choice .choice{
|
||||
width: 49%;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
text-align: left;
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
#choice .choice .label{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#choice .choice.dogs{
|
||||
color: #00cbca;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#choice .choice.cats{
|
||||
color: #2196f3;
|
||||
float: left;
|
||||
}
|
||||
#background-stats{
|
||||
z-index:1;
|
||||
height:100%;
|
||||
width:100%;
|
||||
position:absolute;
|
||||
}
|
||||
#background-stats div{
|
||||
transition: width 400ms ease-in-out;
|
||||
display:inline-block;
|
||||
margin-bottom:-4px;
|
||||
width:50%;
|
||||
height:100%;
|
||||
}
|
Reference in New Issue
Block a user