Skip to content

Commit 5946e03

Browse files
authored
Merge pull request #154 from boostcampwm-2022/dev
Deploy: 4주차 중간
2 parents 70e00c8 + 6d82097 commit 5946e03

File tree

35 files changed

+734
-97
lines changed

35 files changed

+734
-97
lines changed

@wabinar-crdt/convergence.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { Node } from './node';
77
* 바로 전달하면 같은 인스턴스를 가리키게 되어 remote operation 의미가 사라짐
88
*/
99
const deepCopyRemoteInsertion = (op: RemoteInsertOperation) => {
10-
const { prevId, node } = op;
10+
const { node } = op;
1111

1212
const copy = { ...node };
1313
Object.setPrototypeOf(copy, Node.prototype);
1414

15-
return { prevId, node: copy as Node };
15+
return { node: copy as Node };
1616
};
1717

1818
const remoteInsertThroughSocket = (crdt: CRDT, op: RemoteInsertOperation) => {

@wabinar-crdt/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class CRDT {
3939
return { targetId, clock: this.clock };
4040
}
4141

42-
remoteInsert({ prevId, node }: RemoteInsertOperation) {
43-
const prevIndex = this.structure.insertById(prevId, node);
42+
remoteInsert({ node }: RemoteInsertOperation) {
43+
const prevIndex = this.structure.insertById(node);
4444

4545
if (++this.clock < node.id.clock) {
4646
this.clock = node.id.clock + 1;

@wabinar-crdt/linked-list.ts

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ type RemoteIdentifier = Identifier | null;
55
type ModifiedIndex = number | null;
66

77
export interface RemoteInsertOperation {
8-
prevId: Identifier | null;
98
node: Node;
109
}
1110

@@ -14,37 +13,48 @@ export interface RemoteDeleteOperation {
1413
clock: number;
1514
}
1615

16+
interface NodeMap {
17+
[index: string]: Node;
18+
}
19+
1720
export default class LinkedList {
18-
head?: Node;
21+
head: Identifier | null;
22+
nodeMap: NodeMap;
23+
24+
constructor() {
25+
this.head = null;
26+
this.nodeMap = {};
27+
}
1928

2029
insertByIndex(
2130
index: number,
2231
letter: string,
2332
id: Identifier,
2433
): RemoteInsertOperation {
25-
const node = new Node(letter, id);
26-
2734
try {
35+
const node = new Node(letter, id);
36+
this.setNode(id, node);
37+
2838
// insertion to head
2939
if (!this.head || index === -1) {
3040
node.next = this.head;
3141
node.prev = null;
3242

33-
this.head = node;
43+
this.head = id;
3444

35-
return { prevId: null, node };
45+
return { node };
3646
}
3747

3848
const prevNode = this.findByIndex(index);
3949

4050
node.next = prevNode.next;
41-
prevNode.next = node;
51+
prevNode.next = node.id;
4252

4353
const { id: prevId } = prevNode;
4454

4555
node.prev = prevId;
4656

47-
return { prevId, node };
57+
return { node };
4858
} catch (e) {
4959
throw new Error(`insertByIndex 실패 ^^\n${e}`);
5060
}
@@ -54,65 +64,84 @@ export default class LinkedList {
5464
try {
5565
// head deleted
5666
if (index === 0) {
57-
if (!this.head) throw new Error('head가 없는데 어떻게 삭제하셨나요 ^^');
67+
const head = this.getHeadNode();
68+
69+
if (!head) throw new Error('head가 없는데 어떻게 삭제하셨나요 ^^');
70+
71+
const nextNode = this.getNode(head.next);
72+
73+
if (!nextNode) {
74+
this.head = null;
5875

59-
if (!this.head.next) {
60-
this.head = undefined;
6176
return null;
6277
}
6378

64-
this.head.next.prev = null;
65-
this.head = this.head.next;
79+
nextNode.prev = null;
80+
81+
this.deleteNode(head.id);
82+
this.head = head.next;
6683

6784
return null;
6885
}
6986

7087
const prevNode = this.findByIndex(index - 1);
7188

72-
const targetNode = prevNode.next;
89+
if (!prevNode.next) return null;
7390

74-
prevNode.next = targetNode?.next;
91+
const targetNode = this.getNode(prevNode.next);
7592

76-
if (!targetNode || !targetNode.id) return null;
93+
if (!targetNode) return null;
94+
95+
this.deleteNode(targetNode.id);
96+
prevNode.next = targetNode.next;
7797

7898
return targetNode.id;
7999
} catch (e) {
80100
throw new Error(`deleteByIndex 실패 ^^\n${e}`);
81101
}
82102
}
83103

84-
insertById(id: RemoteIdentifier, node: Node): ModifiedIndex {
104+
insertById(node: Node): ModifiedIndex {
85105
try {
106+
this.setNode(node.id, node);
107+
86108
let prevNode, prevIndex;
87109

88110
// insertion to head
89-
if (id === null) {
111+
if (!node.prev) {
112+
const head = this.getHeadNode();
113+
90114
// 기존 head가 없거나 현재 node가 선행하는 경우
91-
if (!this.head || node.precedes(this.head)) {
115+
if (!head || node.precedes(head)) {
92116
node.next = this.head;
93-
this.head = node;
117+
this.head = node.id;
94118

95119
return null;
96120
}
97121

98-
prevNode = this.head;
122+
prevNode = head;
99123
prevIndex = 0;
100124
} else {
101-
let { node: targetNode, index: targetIndex } = this.findById(id);
125+
let { node: targetNode, index: targetIndex } = this.findById(node.prev);
102126

103127
prevNode = targetNode;
104128
prevIndex = targetIndex;
105129
}
106130

131+
if (!prevNode) return null;
132+
107133
// prevNode에 연결된 노드가 현재 node에 선행하는 경우
108-
while (prevNode.next && prevNode.next.precedes(node)) {
109-
prevNode = prevNode.next;
134+
while (prevNode.next && this.getNode(prevNode.next)?.precedes(node)) {
135+
prevNode = this.getNode(prevNode.next);
110136
prevIndex++;
137+
138+
if (!prevNode) return null;
111139
}
112140

113141
node.next = prevNode.next;
142+
prevNode.next = node.id;
143+
114144
node.prev = prevNode.id;
115-
prevNode.next = node;
116145

117146
return prevIndex + 1;
118147
} catch (e) {
@@ -125,9 +154,11 @@ export default class LinkedList {
125154
deleteById(id: RemoteIdentifier): ModifiedIndex {
126155
try {
127156
if (!id) {
128-
if (!this.head) throw new Error('일어날 수 없는 일이 발생했어요 ^^');
157+
const head = this.getHeadNode();
158+
159+
if (!head) throw new Error('일어날 수 없는 일이 발생했어요 ^^');
129160

130-
this.head = this.head.next;
161+
this.head = head.next;
131162

132163
return null;
133164
}
@@ -146,23 +177,23 @@ export default class LinkedList {
146177
}
147178

148179
stringify(): string {
149-
let node: Node | undefined = this.head;
180+
let node: Node | null = this.getHeadNode();
150181
let result = '';
151182

152183
while (node) {
153184
result += node.value;
154-
node = node.next;
185+
node = this.getNode(node.next);
155186
}
156187

157188
return result;
158189
}
159190

160191
private findByIndex(index: number): Node {
161192
let count = 0;
162-
let currentNode: Node | undefined = this.head;
193+
let currentNode: Node | null = this.getHeadNode();
163194

164195
while (count < index && currentNode) {
165-
currentNode = currentNode.next;
196+
currentNode = this.getNode(currentNode.next);
166197
count++;
167198
}
168199

@@ -173,17 +204,37 @@ export default class LinkedList {
173204

174205
private findById(id: Identifier) {
175206
let count = 0;
176-
let currentNode: Node | undefined = this.head;
207+
let currentNode: Node | null = this.getHeadNode();
177208

178209
while (currentNode) {
179210
if (JSON.stringify(currentNode.id) === JSON.stringify(id)) {
180211
return { node: currentNode, index: count };
181212
}
182213

183-
currentNode = currentNode.next;
214+
currentNode = this.getNode(currentNode.next);
184215
count++;
185216
}
186217

187218
throw new Error('없는 노드인데요 ^^');
188219
}
220+
221+
private getNode(id: Identifier | null): Node | null {
222+
if (!id) return null;
223+
224+
return this.nodeMap[JSON.stringify(id)];
225+
}
226+
227+
private getHeadNode() {
228+
if (!this.head) return null;
229+
230+
return this.getNode(this.head);
231+
}
232+
233+
private setNode(id: Identifier, node: Node) {
234+
this.nodeMap[JSON.stringify(id)] = node;
235+
}
236+
237+
private deleteNode(id: Identifier) {
238+
delete this.nodeMap[JSON.stringify(id)];
239+
}
189240
}

@wabinar-crdt/node.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ export class Identifier {
1010

1111
export class Node {
1212
id: Identifier;
13-
value?: string;
14-
next?: Node;
15-
prev?: Identifier | null;
13+
value: string;
14+
next: Identifier | null;
15+
prev: Identifier | null;
1616

1717
constructor(value: string, id: Identifier) {
1818
this.id = id;
1919
this.value = value;
20+
this.next = null;
21+
this.prev = null;
2022
}
2123

2224
precedes(node: Node) {

client/src/components/ConfMediaBar/ConfMedia/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef } from 'react';
1+
import { memo, useEffect, useRef } from 'react';
22

33
import style from './style.module.scss';
44

@@ -17,4 +17,4 @@ function ConfMedia({ stream }: MediaProps) {
1717
return <video className={style.video} ref={ref} autoPlay />;
1818
}
1919

20-
export default ConfMedia;
20+
export default memo(ConfMedia);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { MdVideocam } from '@react-icons/all-files/md/MdVideocam';
2+
import { MdVideocamOff } from '@react-icons/all-files/md/MdVideocamOff';
3+
import { Dispatch, SetStateAction } from 'react';
4+
import color from 'styles/color.module.scss';
5+
6+
interface CamButtonProps {
7+
isOn: boolean;
8+
setIsCamOn?: Dispatch<SetStateAction<boolean>>;
9+
}
10+
11+
function CamButton({ isOn, setIsCamOn }: CamButtonProps) {
12+
const onClick = () => {
13+
if (setIsCamOn) setIsCamOn(!isOn);
14+
};
15+
16+
return (
17+
<button onClick={onClick}>
18+
{isOn ? (
19+
<MdVideocamOff color={color.red} size={20} />
20+
) : (
21+
<MdVideocam color={color.green} size={20} />
22+
)}
23+
</button>
24+
);
25+
}
26+
27+
export default CamButton;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { MdMic } from '@react-icons/all-files/md/MdMic';
2+
import { MdMicOff } from '@react-icons/all-files/md/MdMicOff';
3+
import { Dispatch, SetStateAction } from 'react';
4+
import color from 'styles/color.module.scss';
5+
6+
interface MicButtonProps {
7+
isOn: boolean;
8+
setIsMicOn?: Dispatch<SetStateAction<boolean>>;
9+
}
10+
11+
function MicButton({ isOn, setIsMicOn }: MicButtonProps) {
12+
const onClick = () => {
13+
if (setIsMicOn) setIsMicOn(!isOn);
14+
};
15+
16+
return (
17+
<button onClick={onClick}>
18+
{isOn ? (
19+
<MdMicOff color={color.red} size={20} />
20+
) : (
21+
<MdMic color={color.green} size={20} />
22+
)}
23+
</button>
24+
);
25+
}
26+
27+
export default MicButton;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Dispatch, memo, SetStateAction } from 'react';
2+
3+
import CamButton from './CamButton';
4+
import MicButton from './MicButton';
5+
import style from './style.module.scss';
6+
7+
interface StreamButtonProps {
8+
isMicOn: boolean;
9+
isCamOn: boolean;
10+
setIsMicOn?: Dispatch<SetStateAction<boolean>>;
11+
setIsCamOn?: Dispatch<SetStateAction<boolean>>;
12+
}
13+
14+
function StreamButton({
15+
isMicOn,
16+
isCamOn,
17+
setIsMicOn,
18+
setIsCamOn,
19+
}: StreamButtonProps) {
20+
return (
21+
<div className={style['stream-button']}>
22+
<MicButton isOn={isMicOn} setIsMicOn={setIsMicOn} />
23+
<CamButton isOn={isCamOn} setIsCamOn={setIsCamOn} />
24+
</div>
25+
);
26+
}
27+
28+
export default memo(StreamButton);

0 commit comments

Comments
 (0)