Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drewdiddy611's Solution' #15

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d73e149
Added name to readme.
drewdiddy611 Jul 26, 2017
64c6b43
initial boiler setup
bsoung Jul 26, 2017
2b2f578
users module progress
drewdiddy611 Jul 26, 2017
4611d32
finished get model function
bsoung Jul 26, 2017
8427e8f
helper functions for rediswrapper
drewdiddy611 Jul 26, 2017
a655197
working on helper functions for redis wrapper
bsoung Jul 26, 2017
bfbef6c
Get module finished, started save module
drewdiddy611 Jul 26, 2017
6df9982
fixing weird bugs
bsoung Jul 26, 2017
c3f01c5
Backend finished (missing delete)
drewdiddy611 Jul 26, 2017
ca74aed
show rooms and users on view
bsoung Jul 26, 2017
a73d421
Tomato
drewdiddy611 Jul 26, 2017
9b2fa5d
missed a file
drewdiddy611 Jul 26, 2017
055dfa3
showing message on view via sockets
bsoung Jul 26, 2017
9ed5d6c
Saving username to cookie
drewdiddy611 Jul 26, 2017
3fac463
working on cookies
bsoung Jul 26, 2017
403f111
Basic messaging works
drewdiddy611 Jul 26, 2017
c8c73d1
refactored some stuff
drewdiddy611 Jul 27, 2017
2b9ed36
More refactoring
drewdiddy611 Jul 27, 2017
124485c
refactored socket files
bsoung Jul 27, 2017
1029d23
Fixing refactor bugs
drewdiddy611 Jul 27, 2017
c8703be
added room event handlers
bsoung Jul 27, 2017
5092fae
added room entering/leaving events
drewdiddy611 Jul 27, 2017
77731c7
bootstrap styling
bsoung Jul 27, 2017
c36bd14
Working on entering rooms
drewdiddy611 Jul 27, 2017
50a8e48
fixed refactor bugs
bsoung Jul 27, 2017
7688331
95% complete
drewdiddy611 Jul 27, 2017
6584ca2
fixing socket bugs
bsoung Jul 27, 2017
d471a6e
messaging works
drewdiddy611 Jul 27, 2017
af928f5
project complete, minus creating rooms
drewdiddy611 Jul 27, 2017
f2eab3b
finished
drewdiddy611 Jul 27, 2017
b3be2b2
Finished everything
drewdiddy611 Jul 27, 2017
735b339
fix start command
drewdiddy611 Jul 28, 2017
3ade301
test heroku redis
drewdiddy611 Jul 28, 2017
206b0c7
test
drewdiddy611 Jul 28, 2017
5e376eb
test
drewdiddy611 Jul 28, 2017
355dc22
test
drewdiddy611 Jul 28, 2017
d1504e5
test
drewdiddy611 Jul 28, 2017
d3b0fe8
test
drewdiddy611 Jul 28, 2017
b5ba370
test
drewdiddy611 Jul 28, 2017
9c34795
test
drewdiddy611 Jul 28, 2017
d35ae90
test
drewdiddy611 Jul 28, 2017
fd66db1
test
drewdiddy611 Jul 28, 2017
a921b82
test
drewdiddy611 Jul 28, 2017
c0e0d78
chatroom goodgit commit -m test
drewdiddy611 Jul 28, 2017
1d22dfc
fixed redis connection URL
drewdiddy611 Jul 28, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules/
.env
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
# project_superchat
Build a realtime multi-room chat application. Make it super.
Andrew Senner and Benny Soung
52 changes: 52 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var exphbs = require('express-handlebars');

var index = require('./routes/index');
var login = require('./routes/login');
var users = require('./routes/users');
var room = require('./routes/room');

var app = express();

// view engine setup
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'handlebars');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/login', login);
app.use('/users', users);
app.use('/room', room);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;
98 changes: 98 additions & 0 deletions bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

const express = require('express');
var app = require('../app');
var debug = require('debug')('project-superchat:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Create socket server.
*/
app.use(
'/socket.io',
express.static(__dirname + 'node_modules/socket.io-client/dist/')
);
const io = require('socket.io')(server);
const socketWrapper = require('../lib/socket_wrapper');
io.on('connection', socketWrapper(io));

/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
console.error(error.stack);
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debug('Listening on ' + bind);
}
10 changes: 10 additions & 0 deletions db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { saveModule } = require('./lib/redis_wrapper');
const { saveUser, saveMessage, saveRoom } = saveModule;

const { hashSync: encodePassword } = require('bcryptjs');

for (let r = 0; r < 5; r++) {
saveRoom({
roomname: `An Awesome Room ${r + 1}`
});
}
11 changes: 11 additions & 0 deletions lib/redis_wrapper/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Require modules.
const redis = require('redis');

// Promisify everything.
const Promise = require('bluebird');
Promise.promisifyAll(redis.RedisClient.prototype);

module.exports = {
loadModule: require('./load_module'),
saveModule: require('./save_module')
};
25 changes: 25 additions & 0 deletions lib/redis_wrapper/load_module/get_messages_by_type_id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
let redisClient = require('redis');

if (process.env.ENV_NODE && process.env.ENV_NODE === 'production') {
redisClient = redisClient.createClient(process.env.REDIS_URL);
} else {
redisClient = redisClient.createClient(process.env.REDIS_URL);
}

const getModelData = require('./get_model_data');

const _filterMessages = (type, typeId) => messages => {
type = type.slice(0, -1);
return messages.filter(msg => {
return +msg[`${type}_id`] === +typeId;
});
};

module.exports = function(type, typeId) {
if (typeId !== undefined && !isNaN(+typeId)) {
// Get all messages by their type id.
return getModelData('messages').then(_filterMessages(type, typeId));
} else {
return Promise.reject(Error('Invalid type id.'));
}
};
63 changes: 63 additions & 0 deletions lib/redis_wrapper/load_module/get_model_data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
let redisClient = require('redis');

if (process.env.ENV_NODE && process.env.ENV_NODE === 'production') {
redisClient = redisClient.createClient(process.env.REDIS_URL);
} else {
redisClient = redisClient.createClient(process.env.REDIS_URL);
}

// Generic function which handles getting model data from redis.
module.exports = function(type, typeId) {
// Make sure we have a type at the very minimum.
if (type === undefined || typeof type !== 'string') return [];

// Did the user pass in an id or array of ids?
if (typeId !== undefined) {
if (!isNaN(+typeId)) {
// If typeId is a number, we're fetching
// a single entry of type.
return _fetchSingleType(type, typeId);
} else if (Array.isArray(typeId)) {
// If typeId is an array, we're fetching
// multiple entries of type, that correspond
// to the ids in the array.
return _fetchByTypeWithIds(type, typeId);
} else {
// Invalid parameter passed.
return Promise.reject(Error('Invalid argument type for typeId'));
}
}
// Grab all entries of a certain type.
return _grabAllByType(type);
};

// Get a single type from redis.
function _fetchSingleType(type, id) {
return redisClient.hgetallAsync(`${type}:${id}`).then(type => {
return type ? [type] : [];
});
}

// Get multiple of type from redis.
function _fetchByTypeWithIds(type, typeIds) {
// Fetch all entries of type.
return _grabAllByType(type).then(entries => {
// Filter through results and only keep
// entries that are in the typeIds array.
return entries.filter(type => {
return typeIds.includes(type.id);
});
});
}

// Grab all by a certain type (helper);
function _grabAllByType(type) {
return redisClient.keysAsync(`${type}:*`).then(_getTypeData);
}

// Gets corresponding entries in redis from _grabAllByType.
function _getTypeData(typeKeys) {
return Promise.all(
typeKeys.map(typeKey => redisClient.hgetallAsync(typeKey))
);
}
20 changes: 20 additions & 0 deletions lib/redis_wrapper/load_module/get_users_by_room_id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
let redisClient = require('redis');

if (process.env.ENV_NODE && process.env.ENV_NODE === 'production') {
redisClient = redisClient.createClient(process.env.REDIS_URL);
} else {
redisClient = redisClient.createClient(process.env.REDIS_URL);
}

const getModelData = require('./get_model_data');

const _getUsersByRoom = roomId => users => {
if (!users || users.length === 0) return [];
return users.filter(user => +user.room_id === +roomId);
};

module.exports = function(roomId) {
if (roomId !== undefined && !isNaN(+roomId)) {
return getModelData('users').then(_getUsersByRoom(roomId));
}
};
12 changes: 12 additions & 0 deletions lib/redis_wrapper/load_module/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const getModelData = require('./get_model_data');
const getMessagesByTypeId = require('./get_messages_by_type_id');

module.exports = {
getUsers: id => getModelData('users', id),
getMessages: id => getModelData('messages', id),
getRooms: id => getModelData('rooms', id),
getMessagesByRoomId: id => getMessagesByTypeId('rooms', id),
getMessagesByUserId: id => getMessagesByTypeId('users', id),
getUsersByRoomId: require('./get_users_by_room_id'),
typeExists: require('./type_exists')
};
9 changes: 9 additions & 0 deletions lib/redis_wrapper/load_module/type_exists.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const getModelData = require('./get_model_data');

module.exports = (dataType, name) => {
return getModelData(dataType).then(types => {
return types.some(
type => type[dataType.slice(0, -1).concat('name')] === name
);
});
};
11 changes: 11 additions & 0 deletions lib/redis_wrapper/save_module/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const saveModelData = require('./save_model_data');
const updateTypeData = require('./update_type_data');

module.exports = {
saveUser: data => saveModelData('users', data),
saveMessage: data => saveModelData('messages', data),
saveRoom: data => saveModelData('rooms', data),
updateUserData: (id, field, value) => {
return updateTypeData('users', id, field, value);
}
};
38 changes: 38 additions & 0 deletions lib/redis_wrapper/save_module/save_model_data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
let redisClient = require('redis');

if (process.env.ENV_NODE && process.env.ENV_NODE === 'production') {
redisClient = redisClient.createClient(process.env.REDIS_URL);
} else {
redisClient = redisClient.createClient(process.env.REDIS_URL);
}

const Promise = require('bluebird');
// Data map to check for valid entries to be saved
const dataMap = {
users: ['username', 'password', 'room_id'],
messages: ['body', 'gmt_created', 'user_id', 'room_id'],
rooms: ['roomname']
};

const _validateEntryData = data => type => {
return Object.keys(data).every(key => dataMap[type].includes(key));
};

// Generic function which handles saving model data to redis.
module.exports = function(type, data) {
// console.log(data, "whats this");
if (type === undefined || typeof type !== 'string') {
return Promise.reject(Error('Invalid argument type for type'));
}
if (!_validateEntryData(data)(type)) {
return Promise.reject(
Error('Incorrect data structure passed, aborting save.')
);
}

// Increment our counter, then save our new entry.
return redisClient.incrAsync(`counts:${type}`).then(newId => {
data.id = newId;
return redisClient.hmsetAsync(`${type}:${data.id}`, data);
});
};
11 changes: 11 additions & 0 deletions lib/redis_wrapper/save_module/update_type_data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let redisClient = require('redis');

if (process.env.ENV_NODE && process.env.ENV_NODE === 'production') {
redisClient = redisClient.createClient(process.env.REDIS_URL);
} else {
redisClient = redisClient.createClient(process.env.REDIS_URL);
}

module.exports = function(type, id, field, value) {
return redisClient.hsetAsync(`${type}:${id}`, field, value);
};
Loading