Skip to content

Commit 7b7fb53

Browse files
authored
Deploy: 4주차 결과 (#188)
1 parent 5946e03 commit 7b7fb53

File tree

48 files changed

+1183
-349
lines changed

Some content is hidden

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

48 files changed

+1183
-349
lines changed

@wabinar-crdt/convergence.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ const convergenceCheck = () => {
3232
/**
3333
* 테스트용 site들
3434
*/
35-
const 원희 = new CRDT(1, 1, new LinkedList());
36-
const 주영 = new CRDT(1, 2, new LinkedList());
37-
const 도훈 = new CRDT(1, 3, new LinkedList());
38-
const 세영 = new CRDT(1, 4, new LinkedList());
35+
const 원희 = new CRDT(1, new LinkedList());
36+
const 주영 = new CRDT(2, new LinkedList());
37+
const 도훈 = new CRDT(3, new LinkedList());
38+
const 세영 = new CRDT(4, new LinkedList());
3939

4040
describe('Convergence', () => {
4141
it('하나의 site에서 삽입', () => {

@wabinar-crdt/crdt.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import LinkedList from './linked-list';
44
describe('Local operation', () => {
55
const initialStructure = new LinkedList();
66

7-
const = new CRDT(1, 1, initialStructure);
7+
const = new CRDT(1, initialStructure);
88

99
it('head에 삽입', () => {
1010
let innerText = .read();

@wabinar-crdt/index.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,44 @@ class CRDT {
99
private client: number;
1010
private structure: LinkedList;
1111

12-
constructor(
13-
initialclock: number = 1,
14-
client: number = 0,
15-
initialStructure: LinkedList,
16-
) {
17-
this.clock = initialclock;
12+
constructor(client: number = 0, initialStructure: LinkedList) {
1813
this.client = client;
1914

20-
Object.setPrototypeOf(initialStructure, LinkedList.prototype);
21-
this.structure = initialStructure as LinkedList;
15+
this.structure = new LinkedList(initialStructure);
16+
17+
const { nodeMap } = initialStructure;
18+
19+
if (!nodeMap || !Object.keys(nodeMap).length) {
20+
this.clock = 1;
21+
return this;
22+
}
23+
24+
// logical clock 동기화를 위함
25+
const maxClock = Object.keys(nodeMap)
26+
.map((id) => Number(JSON.parse(id).clock))
27+
.reduce((prev, cur) => Math.max(prev, cur), 0);
28+
29+
this.clock = maxClock + 1;
30+
}
31+
32+
get timestamp() {
33+
return this.clock;
2234
}
2335

2436
get data() {
2537
return this.structure;
2638
}
2739

28-
localInsert(index: number, letter: string): RemoteInsertOperation {
29-
const id = new Identifier(this.clock++, this.client);
40+
get plainData() {
41+
// DB에 저장할 때 ref 제거하기 위함
42+
const stringifiedData = JSON.stringify(this.structure);
43+
44+
return JSON.parse(stringifiedData);
45+
}
3046

31-
const remoteInsertion = this.structure.insertByIndex(index, letter, id);
47+
localInsert(index: number, value: string): RemoteInsertOperation {
48+
const id = new Identifier(this.clock++, this.client);
49+
const remoteInsertion = this.structure.insertByIndex(index, value, id);
3250

3351
return remoteInsertion;
3452
}
@@ -62,6 +80,10 @@ class CRDT {
6280
read() {
6381
return this.structure.stringify();
6482
}
83+
84+
spread() {
85+
return this.structure.spread();
86+
}
6587
}
6688

6789
export default CRDT;

@wabinar-crdt/linked-list.ts

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,43 @@ export default class LinkedList {
2121
head: Identifier | null;
2222
nodeMap: NodeMap;
2323

24-
constructor() {
25-
this.head = null;
26-
this.nodeMap = {};
24+
constructor(initialStructure?: LinkedList) {
25+
if (!initialStructure) {
26+
this.head = null;
27+
this.nodeMap = {};
28+
29+
return this;
30+
}
31+
32+
const { head, nodeMap } = initialStructure;
33+
34+
this.head = head ?? null;
35+
36+
if (!nodeMap && !Object.keys(nodeMap).length) {
37+
this.nodeMap = nodeMap ?? {};
38+
39+
return this;
40+
}
41+
42+
const nodeMapWithPrototype = Object.entries(nodeMap).reduce<NodeMap>(
43+
(prev, [id, node]) => {
44+
Object.setPrototypeOf(node, Node.prototype);
45+
prev[id] = node;
46+
47+
return prev;
48+
},
49+
{},
50+
);
51+
this.nodeMap = nodeMapWithPrototype;
2752
}
2853

2954
insertByIndex(
3055
index: number,
31-
letter: string,
56+
value: string,
3257
id: Identifier,
3358
): RemoteInsertOperation {
3459
try {
35-
const node = new Node(letter, id);
60+
const node = new Node(value, id);
3661
this.setNode(id, node);
3762

3863
// insertion to head
@@ -103,6 +128,7 @@ export default class LinkedList {
103128

104129
insertById(node: Node): ModifiedIndex {
105130
try {
131+
Object.setPrototypeOf(node, Node.prototype);
106132
this.setNode(node.id, node);
107133

108134
let prevNode, prevIndex;
@@ -167,6 +193,7 @@ export default class LinkedList {
167193
const prevNode = this.findByIndex(targetIndex - 1);
168194

169195
prevNode.next = targetNode.next;
196+
this.deleteNode(id);
170197

171198
return targetIndex;
172199
} catch (e) {
@@ -188,6 +215,18 @@ export default class LinkedList {
188215
return result;
189216
}
190217

218+
spread(): string[] {
219+
let node: Node | null = this.getHeadNode();
220+
let result = [];
221+
222+
while (node) {
223+
result.push(node.value);
224+
node = this.getNode(node.next);
225+
}
226+
227+
return result;
228+
}
229+
191230
private findByIndex(index: number): Node {
192231
let count = 0;
193232
let currentNode: Node | null = this.getHeadNode();

README.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,137 @@
1+
<div align=center>
2+
<img
3+
align=center
4+
src="https://user-images.githubusercontent.com/65100540/201074976-b7550af4-e2cf-4d40-aed2-d5213fe10f66.png"
5+
width="500">
6+
</div>
17

8+
<h2 align=center style="text-align: center; font-size: 1.5em">💻 회의와 기록을 한번에 📝</h2>
9+
10+
<p align=center>
11+
<a href="https://www.minari.shop">배포 서버</a>
12+
&nbsp; | &nbsp;
13+
<a href="https://saber-ash-4ab.notion.site/Wabinar-57f67053ef2c48ababd1da317c63e7a7">노션</a>
14+
&nbsp; | &nbsp;
15+
<a href="https://github.com/boostcampwm-2022/web27-Wabinar/wiki">위키</a>
16+
&nbsp; | &nbsp;
17+
<a href="https://saber-ash-4ab.notion.site/f4e8ed8c594a4a8089404025a3692ca4?v=70e2fe5f08c94c998ea9c9846fc1aaaf">백로그</a>
18+
&nbsp; | &nbsp;
19+
<a href="https://www.figma.com/file/OxypldnsrmkTqX1LStgJPl/Wabinar?node-id=59%3A2014&t=eSUFpSn0pU3tpyjQ-0">기획서</a>
20+
</p>
21+
22+
<hr>
23+
24+
<br>
25+
26+
<h2>프로젝트 소개</h2>
27+
28+
비대면 화상 회의를 여러 차례 진행하면서 팀원들이 공통으로 느낀 문제점들이 있었어요.
29+
30+
<br>
31+
32+
> 💡 **하나의 플랫폼에서 말하고 또 기록할 수 있으면 편리하지 않을까**
33+
34+
> 💡 **공유보드를 제공해서 오가는 이야기들을 기록하도록 유도할 수 있지 않을까**
35+
36+
> 💡 **텍스트 기반 발제로 비디오/보이스 기반 소통의 진입장벽을 조금은 허물 수 있지 않을까**
37+
38+
<br>
39+
40+
**Wabinar** 는 비대면 회의 환경에 기록이라는 요소를 넣음으로써 더 좋은 회의를 진행할 수 있을 것으로 기대해요.
41+
42+
<br>
43+
44+
45+
## 데모 영상
46+
47+
(추후 업데이트)
48+
49+
## 기능
50+
51+
(추후 업데이트)
52+
53+
## 기술 스택 (큐 아님)
54+
55+
<div style="margin: 1em auto; text-align: center;">
56+
<p>Common</p>
57+
<img src="https://img.shields.io/badge/WebRTC-333333?logo=webrtc">
58+
<img src="https://img.shields.io/badge/Socket.io-010101?logo=Socket.io">
59+
<img src="https://img.shields.io/badge/Jest-341f0e?logo=jest&logoColor=FF0000&">
60+
<img src="https://img.shields.io/badge/Prettier-F7B93E?logo=prettier&logoColor=ffffff">
61+
<img src="https://img.shields.io/badge/ESLint-4B32C3?logo=Eslint">
62+
<img src="https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=ffffff">
63+
<img src="https://img.shields.io/badge/.ENV-ECD53F?logo=.ENV&logoColor=ffffff">
64+
</div>
65+
66+
<div style="margin: 1em auto; text-align: center;">
67+
<p>FE</p>
68+
<img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=ffffff">
69+
<img src="https://img.shields.io/badge/Vite-646CFF?logo=Vite&logoColor=ffffff">
70+
<img src="https://img.shields.io/badge/React-61DAFB?logo=React&logoColor=ffffff">
71+
<img src="https://img.shields.io/badge/Sass-CC6699?logo=Sass&logoColor=ffffff">
72+
</div>
73+
74+
<div style="margin: 1em auto; text-align: center;">
75+
<p>BE</p>
76+
<img src="https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=ffffff">
77+
<img src="https://img.shields.io/badge/Node.js-114411?logo=node.js">
78+
<img src="https://img.shields.io/badge/Express-17202C?logo=Express">
79+
<img src="https://img.shields.io/badge/MongoDB-114411?logo=mongodb">
80+
<img src="https://img.shields.io/badge/Mongoose-114411?logo=mongodb">
81+
</div>
82+
83+
<div style="margin: 1em auto; text-align: center;">
84+
<p>CI/CD</p>
85+
<img src="https://img.shields.io/badge/GitHub Actions-000000?logo=github-actions">
86+
</div>
87+
88+
<div style="margin: 1em auto; text-align: center;">
89+
<p>Deployment</p>
90+
<img src="https://img.shields.io/badge/nginx-014532?logo=Nginx&logoColor=009639&">
91+
<img src="https://img.shields.io/badge/Naver Cloud Platform-03C75A?logo=naver&logoColor=ffffff">
92+
</div>
93+
94+
<div style="margin: 1em auto; text-align: center;">
95+
<p>Collaboration</p>
96+
<img src="https://img.shields.io/badge/Github-181717?logo=Github&logoColor=ffffff">
97+
<img src="https://img.shields.io/badge/Notion-000000?logo=Notion">
98+
<img src="https://img.shields.io/badge/Figma-F24E1E?logo=Figma&logoColor=ffffff">
99+
<img src="https://img.shields.io/badge/Slack-4A154B?logo=Slack&logoColor=ffffff">
100+
</div>
101+
102+
## 팀 소개
103+
104+
### 왭^^
105+
106+
<div align=center>
107+
<img src="https://user-images.githubusercontent.com/89635107/204541553-3ea729a7-6b54-4e86-b7d3-7496e73ddf04.png" alt="Wab Logo" style="display: block; margin: 1em auto; height: 120px;">
108+
</div>
109+
110+
저희는 **`왭^^`** 이에요.
111+
112+
**``** 를 잘 아는 **``** 개발자가 되자는 의미예요.
113+
114+
<table align=center>
115+
<thead>
116+
<tr >
117+
<th style="text-align:center;" >김세영</th>
118+
<th style="text-align:center;" >백도훈</th>
119+
<th style="text-align:center;" >신주영</th>
120+
<th style="text-align:center;" >조원희</th>
121+
</tr>
122+
</thead>
123+
<tbody>
124+
<tr>
125+
<td><img width="150" height="150" src="https://avatars.githubusercontent.com/u/63814960?v=4" /> </td>
126+
<td><img width="150" height="150" src="https://user-images.githubusercontent.com/65100540/200451888-3c0bde8c-48d0-493b-aabd-58155aa1f7a6.jpg" /></td>
127+
<td><img width="150" height="150" src="https://user-images.githubusercontent.com/63364990/200451372-9a7e7eef-a2f7-45b7-b572-803053e56329.jpeg" /></td>
128+
<td><img width="150" height="150" src="https://user-images.githubusercontent.com/89635107/200794102-63897e78-0fe8-40cc-b1c8-5492a6eae5ea.jpg" /></td>
129+
</tr>
130+
<tr>
131+
<td>퇴근도 좋지만..^^</td>
132+
<td>원희님 천재아니에요?</td>
133+
<td>🫵</td>
134+
<td>늦는 사람이 있네요..^^</td>
135+
</tr>
136+
</tbody>
137+
</table>

client/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
"@react-icons/all-files": "^4.1.0",
1313
"axios": "^1.1.3",
1414
"classnames": "^2.3.2",
15+
"eventemitter3": "^5.0.0",
1516
"react": "^18.2.0",
1617
"react-dom": "^18.2.0",
1718
"react-loader-spinner": "^5.3.4",
1819
"react-router-dom": "^6.4.3",
19-
"socket.io-client": "^4.5.4"
20+
"socket.io-client": "^4.5.4",
21+
"uuid": "^9.0.0"
2022
},
2123
"devDependencies": {
2224
"@testing-library/jest-dom": "^5.16.5",

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@ import style from './style.module.scss';
44

55
interface MediaProps {
66
stream: MediaStream;
7+
muted: boolean;
78
}
89

9-
function ConfMedia({ stream }: MediaProps) {
10+
function ConfMedia({ stream, muted }: MediaProps) {
1011
const ref = useRef<HTMLVideoElement>(null);
1112

1213
useEffect(() => {
1314
if (!ref.current) return;
1415
ref.current.srcObject = stream;
1516
}, [stream]);
1617

17-
return <video className={style.video} ref={ref} autoPlay />;
18+
return <video className={style.video} ref={ref} muted={muted} autoPlay />;
1819
}
1920

2021
export default memo(ConfMedia);

client/src/components/ConfMediaBar/index.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { useState } from 'react';
2-
import { useParams } from 'react-router-dom';
32
import { useConfMediaStreams } from 'src/hooks/useConfMediaStreams';
4-
import useSocket from 'src/hooks/useSocket';
3+
import useSocketContext from 'src/hooks/useSocketContext';
54

65
import ConfMedia from './ConfMedia';
76
import StreamButton from './StreamButton';
87
import style from './style.module.scss';
98

109
function ConfMediaBar() {
11-
const { id } = useParams();
12-
const socket = useSocket(`/signaling/${id}`);
10+
const { signalingSocket: socket } = useSocketContext();
1311
const streams = useConfMediaStreams(socket);
1412

1513
const [isMicOn, setIsMicOn] = useState(false);
@@ -20,7 +18,7 @@ function ConfMediaBar() {
2018
<ul>
2119
{Array.from(streams).map(([id, stream]) => (
2220
<li key={id}>
23-
<ConfMedia key={id} stream={stream} />
21+
<ConfMedia key={id} stream={stream} muted={id === 'me' ? true : false} />
2422
<StreamButton
2523
isMicOn={false}
2624
isCamOn={true} // TODO: 임시로 지정

client/src/components/Editor/style.module.scss

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)