Browse Source

Use md5 hashes for urls, factor OrderedMap out of rooms reducer.

pull/1/head
Titouan Rigoudy 9 years ago
parent
commit
3b61249cb8
8 changed files with 111 additions and 58 deletions
  1. +4
    -0
      src/components/Header.js
  2. +4
    -2
      src/components/Room.js
  3. +4
    -3
      src/components/RoomList.js
  4. +9
    -9
      src/containers/RoomsPane.js
  5. +1
    -1
      src/createRoutes.js
  6. +15
    -43
      src/reducers/rooms.js
  7. +4
    -0
      src/styles/styles.scss
  8. +70
    -0
      src/utils/OrderedMap.js

+ 4
- 0
src/components/Header.js View File

@ -1,9 +1,13 @@
import React, { PropTypes } from "react";
import { Link } from "react-router";
const Header = (props) => {
return (
<header>
<h1>Solstice web UI</h1>
<Link to="/app/rooms" activeClassName="active">
Rooms
</Link>
</header>
);
};


+ 4
- 2
src/components/Room.js View File

@ -1,14 +1,16 @@
import React, { PropTypes } from "react";
import { Link } from "react-router";
import md5 from "md5";
const Room = ({ name, membership, userCount }) => {
const classes = ["room"];
if (membership == "Member") {
classes.push("room-joined");
}
const base64Name = btoa(encodeURIComponent(name));
const path = `/app/rooms/${base64Name}`;
const hash = md5(name);
const path = `/app/rooms/${hash}`;
return (
<Link to={path}


+ 4
- 3
src/components/RoomList.js View File

@ -1,4 +1,5 @@
import React, { PropTypes } from "react";
import ImmutablePropTypes from "react-immutable-proptypes";
import Room from "./Room";
import RoomListHeader from "./RoomListHeader";
@ -13,11 +14,11 @@ class RoomList extends React.Component {
}
render() {
const { roomMap, roomActions } = this.props;
const { rooms, roomActions } = this.props;
const children = [];
for (const [roomName, roomData] of roomMap) {
for (const [roomName, roomData] of rooms.get("byName")) {
children.push(
<li key={roomName}>
<Room
@ -39,7 +40,7 @@ class RoomList extends React.Component {
}
RoomList.propTypes = {
roomMap: PropTypes.object.isRequired,
rooms: ImmutablePropTypes.record.isRequired,
roomActions: PropTypes.shape({
getList: PropTypes.func.isRequired
}).isRequired


+ 9
- 9
src/containers/RoomsPane.js View File

@ -15,15 +15,15 @@ class RoomsPane extends React.Component {
}
render() {
const { loginUserName, params, roomMap, roomActions } = this.props;
const { loginUserName, params, rooms, roomActions } = this.props;
let roomName;
let roomChat;
if (params && params.roomName) {
roomName = decodeURIComponent(atob(params.roomName));
if (params && params.roomNameHash) {
roomName = rooms.getNameByHash(params.roomNameHash);
const roomData = roomMap.get(roomName);
const roomData = rooms.getByName(roomName);
if (roomData) {
const room = {
@ -46,7 +46,7 @@ class RoomsPane extends React.Component {
return (
<div id="rooms-pane">
<RoomList
roomMap={roomMap}
rooms={rooms}
roomActions={roomActions}
/>
<div id="room-selected-pane">
@ -60,15 +60,15 @@ class RoomsPane extends React.Component {
RoomsPane.propTypes = {
loginUserName: PropTypes.string.isRequired,
params: PropTypes.shape({
roomName: PropTypes.string
roomNameHash: PropTypes.string
}),
roomMap: ImmutablePropTypes.orderedMap.isRequired,
rooms: ImmutablePropTypes.record.isRequired,
roomActions: PropTypes.object.isRequired
};
const mapStateToProps = (state) => ({
roomMap: state.rooms.get("roomMap"),
loginUserName: state.login.get("username")
loginUserName: state.login.get("username"),
rooms: state.rooms
});
const mapDispatchToProps = (dispatch) => ({


+ 1
- 1
src/createRoutes.js View File

@ -24,7 +24,7 @@ const createRoutes = (store) => {
<IndexRoute component={ConnectPage} />
<Route path="app" onEnter={requireLoggedIn} component={SolsticeApp}>
<Route path="rooms(/:roomName)" component={RoomsPane} />
<Route path="rooms(/:roomNameHash)" component={RoomsPane} />
</Route>
</Route>
);


+ 15
- 43
src/reducers/rooms.js View File

@ -1,5 +1,7 @@
import Immutable from "immutable";
import OrderedMap from "../utils/OrderedMap";
import {
ROOM_JOIN,
ROOM_LEAVE,
@ -9,48 +11,9 @@ import {
SOCKET_RECEIVE_MESSAGE
} from "../constants/ActionTypes";
const initialState = Immutable.Map({
roomMap: Immutable.OrderedMap(),
roomNameByHash: Immutable.Map()
});
const initialState = OrderedMap();
const reduceRoomList = (state, roomList) => {
const roomMap = state.get("roomMap");
const roomNameByHash = state.get("roomNameByHash");
// First sort the room list by room name
roomList.sort(([ roomName1 ], [ roomName2 ]) => {
if (roomName1 < roomName2) {
return -1;
} else if (roomName1 > roomName2) {
return 1;
}
return 0;
});
// Then build the new rooms map
let newRoomMap = Immutable.OrderedMap();
for (const [ roomName, newRoomData ] of roomList) {
// Get the old room data.
let roomData = roomMap.get(roomName);
if (roomData) {
// Scrap the old message list, we only want the new message list.
roomData.remove("messages");
} else {
// If the room did not exist, make up an empty one.
roomData = Immutable.Map();
}
// Merge the old data and the new data, overwriting with new data if
// conflicting.
const mergedRoomData = roomData.merge(newRoomData);
// Insert that in the new room map.
newRoomMap = newRoomMap.set(roomName, mergedRoomData);
}
return state
.set("roomMap", newRoomMap)
.set("roomNameByHash", roomNameByHash);
};
const reduceReceiveMessageRoom = (roomData, { variant, data }) => {
@ -79,7 +42,7 @@ const reduceReceiveMessage = (state, message) => {
case "RoomMessageResponse":
{
const { room_name } = data;
return state.updateIn(["roomMap", data.room_name], (roomData) => {
return state.updateByName(data.room_name, (roomData) => {
if (roomData) {
return reduceReceiveMessageRoom(roomData, message);
} else {
@ -90,7 +53,16 @@ const reduceReceiveMessage = (state, message) => {
}
case "RoomListResponse":
return reduceRoomList(state, data.rooms);
return state.updateAll(data.rooms, (newData, oldData) => {
if (oldData) {
// Remove the messages array, we want to overwrite it
// completely.
oldData.remove("messages");
} else {
oldData = Immutable.Map();
}
return oldData.merge(newData);
});
default:
return state;
@ -125,7 +97,7 @@ export default (state = initialState, action) => {
case ROOM_SHOW_USERS:
case ROOM_HIDE_USERS:
{
return state.updateIn(["roomMap", payload], (roomData) => {
return state.updateByName(payload, (roomData) => {
if (roomData) {
return reduceRoom(roomData, action);
} else {


+ 4
- 0
src/styles/styles.scss View File

@ -33,6 +33,10 @@ html {
header {
margin: 0;
padding: 1.5em 2em;
display: flex;
flex-flow: row;
justify-content: space-around;
width: 100%;
}
header h1 {


+ 70
- 0
src/utils/OrderedMap.js View File

@ -0,0 +1,70 @@
import Immutable from "immutable";
import md5 from "md5";
const MapRecord = Immutable.Record({
byName: Immutable.OrderedMap(),
byHash: Immutable.Map()
});
class OrderedMap extends MapRecord {
constructor(arg) {
super(arg);
}
getByName(name) {
return this.getIn(["byName", name]);
}
setByName(name, data) {
let thisModified = this;
if (!this.getByName(name)) {
// That key was not there yet, add hash -> name mapping.
thisModified = this.setIn(["byHash", md5(name)], name);
}
// Add data to map.
return thisModified.setIn(["byName", name], data);
}
updateByName(name, updater) {
return this.updateIn(["byName", name], updater);
}
getNameByHash(hash) {
return this.getIn(["byHash", hash]);
}
updateAll(nameAndDataList, merger) {
const { byName } = this;
let { byHash } = this;
// First sort the room list by room name
nameAndDataList.sort(([ name1 ], [ name2 ]) => {
if (name1 < name2) {
return -1;
} else if (name1 > name2) {
return 1;
}
return 0;
});
// Then build the new map.
let newByName = Immutable.OrderedMap();
for (const [ name, newData ] of nameAndDataList) {
// Get the old room data.
let data = byName.get(name);
if (!data) {
// Add the hash -> name mapping.
byHash = byHash.set(md5(name), name);
}
// Merge the old data and the new data using the provided function.
const mergedData = merger(newData, data);
// Insert that in the new room map.
newByName = newByName.set(name, mergedData);
}
return new OrderedMap({ byName: newByName, byHash });
}
}
export default () => new OrderedMap();

Loading…
Cancel
Save