Skip to content

Commit 750dee6

Browse files
committed
Initial commit
0 parents  commit 750dee6

21 files changed

+17797
-0
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

Diff for: README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Real Time Videoconferencing app built with WebRTC and Node.js
2+
3+
## Install
4+
5+
```sh
6+
npm i
7+
```
8+
9+
## Run
10+
11+
```sh
12+
npm run dev
13+
```
14+
15+
- Open a browser browser instance at [http://localhost:8080/index.html](http://localhost:8080/index.html).
16+
- Click "Create Room" and enter a room name.
17+
- Open another browser instance at the same URL.
18+
- Click "Join Room" and enter the same room name.
19+
20+
You should see the local video and remote video playing and showing real time video and audio.
21+
22+
## Resources
23+
24+
- [https://codelabs.developers.google.com/codelabs/webrtc-web/](https://codelabs.developers.google.com/codelabs/webrtc-web/)
25+
- [https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API)
26+
- [https://hpbn.co/](https://hpbn.co/)

Diff for: async-worker.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @param {Worker} worker
3+
* @param {any} message
4+
* @returns {Promise<any>}
5+
*/
6+
function sendMessageToWorker(worker, message) {
7+
return new Promise((resolve, _reject) => {
8+
const messageId = Date.now() + Math.random(); // Generate a unique ID
9+
/**
10+
* @param {MessageEvent<any>} event
11+
*/
12+
const handleMessage = (event) => {
13+
if (event.data.messageId === messageId) {
14+
// Check if the response matches
15+
worker.removeEventListener("message", handleMessage); // Cleanup
16+
resolve(event.data); // Resolve the promise with the response
17+
}
18+
};
19+
20+
worker.addEventListener("message", handleMessage);
21+
22+
worker.postMessage({ messageId, ...message }); // Send the message with the ID
23+
});
24+
}
25+
26+
/**
27+
* @param {string} query
28+
*/
29+
async function sql(query) {
30+
/**
31+
* @type {{success: true, resultRows: any[], columnNames: string[]} | {success: false, error: string}}
32+
*/
33+
const result = await sendMessageToWorker(window.sqlite3Worker, {
34+
type: "syncExec",
35+
sql: query,
36+
});
37+
if (!result.success) {
38+
alert(`${result.error} in query ${query}`);
39+
throw new Error(result.error);
40+
}
41+
return result;
42+
}

Diff for: css/main.css

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.remoteUser {
2+
width: 25%;
3+
}
4+
#messagesContainer ul {
5+
max-height: 300px;
6+
overflow: auto;
7+
list-style: none;
8+
}
9+
#query-form {
10+
max-width: 600px;
11+
/* Set a max width for the form */
12+
margin: 20px auto;
13+
/* Center the form horizontally */
14+
padding: 20px;
15+
/* Add some padding */
16+
border-radius: 8px;
17+
/* Rounded corners */
18+
background-color: #f8f9fa;
19+
/* Light background color */
20+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
21+
/* Subtle shadow */
22+
}
23+
24+
#query {
25+
width: 100%;
26+
/* Full width */
27+
height: 150px;
28+
/* Set height for the textarea */
29+
/* resize: none; */
30+
/* Prevent resizing */
31+
border-radius: 4px;
32+
/* Rounded corners */
33+
border: 1px solid #ced4da;
34+
/* Bootstrap border color */
35+
padding: 10px;
36+
/* Inner padding */
37+
font-size: 16px;
38+
/* Font size */
39+
}
40+
41+
#query:focus {
42+
border-color: #80bdff;
43+
/* Focus border color */
44+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
45+
/* Focus shadow */
46+
}
47+
48+
button {
49+
align-items: center;
50+
margin-top: 10px;
51+
/* Space above the button */
52+
}

Diff for: csvToSqlite.js

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/**
2+
* @param {string} csvString
3+
* @param {string} tableName
4+
* @returns {{tableName: string, createTable: string, insert: string, inserts: string[]}}
5+
*/
6+
function createTableFromCSV(csvString, tableName) {
7+
const lines = CSV.parse(csvString);
8+
const headers = lines[0].map((l) => l.replace(" ", "_"));
9+
const firstNonHeaderLine = lines[1];
10+
/**
11+
* @type {string[]}
12+
*/
13+
const dataTypes = [];
14+
firstNonHeaderLine.forEach((column) => {
15+
if (isNumeric(column)) {
16+
dataTypes.push("REAL");
17+
} else {
18+
dataTypes.push("TEXT");
19+
}
20+
});
21+
console.log({ headers });
22+
console.log({ dataTypes });
23+
const sanitizedTableName = sanitizeTableName(tableName);
24+
// Create a table with the column names from CSV
25+
const createTableSQL = `CREATE TABLE ${sanitizedTableName} (${headers
26+
.map((header, i) => `${header} ${dataTypes[i]}`)
27+
.join(", ")})`;
28+
29+
// Prepare a single INSERT statement
30+
const insertSQL = `INSERT INTO ${sanitizedTableName} (${headers.join(
31+
", "
32+
)}) VALUES `;
33+
34+
const valuePlaceholders = [];
35+
const values = [];
36+
// Prepare values for the INSERT statement
37+
for (let i = 1; i < lines.length; i++) {
38+
const row = lines[i];
39+
values.push(
40+
`(${row.map((column) => `'${column.replace("'", "''")}'`).join(",")})`
41+
);
42+
}
43+
const fullInsertValues = values.join(",");
44+
45+
const inserts = lines.map((row, i) => {
46+
return `INSERT INTO ${sanitizedTableName} (${headers.join(
47+
","
48+
)}) VALUES (${row
49+
.map((column) => `'${column.replace("'", "''")}'`)
50+
.join(",")});`;
51+
});
52+
53+
// Combine the INSERT statement with the formatted values
54+
const fullInsertSQL = insertSQL + fullInsertValues;
55+
// document.write(fullInsertSQL);
56+
// Return the create table and insert queries
57+
return {
58+
tableName: sanitizedTableName,
59+
createTable: createTableSQL,
60+
insert: fullInsertSQL, // inserts.join(" "), // Return as a single string
61+
inserts,
62+
};
63+
}
64+
/**
65+
* @param {string} fileName
66+
* @returns {string}
67+
*/
68+
function sanitizeTableName(fileName) {
69+
// Remove the file extension
70+
const baseName = fileName.replace(/\.[^/.]+$/, "");
71+
72+
// Remove invalid characters and replace with underscores
73+
const sanitized = baseName.replace(/[^a-zA-Z0-9_]/g, "_");
74+
75+
// Limit to 64 characters (or any reasonable length)
76+
const limited = sanitized.substring(0, 64);
77+
78+
// Check for reserved keywords and handle accordingly
79+
const reservedKeywords = ["table", "select", "insert", "delete", "update"]; // Add more as needed
80+
if (reservedKeywords.includes(limited.toLowerCase())) {
81+
return `tbl_${limited}`; // Prefix with 'tbl_' to avoid keyword conflict
82+
}
83+
84+
return limited;
85+
}
86+
87+
const CSV = {
88+
/**
89+
* @param {string} csv
90+
* @param {*} [reviver]
91+
* @returns {string[][]}
92+
*/
93+
parse: function (csv, reviver) {
94+
reviver =
95+
reviver ||
96+
function (r, c, v) {
97+
return v;
98+
};
99+
let chars = csv.split(""),
100+
c = 0,
101+
cc = chars.length,
102+
start,
103+
end,
104+
table = [],
105+
row;
106+
while (c < cc) {
107+
table.push((row = []));
108+
while (c < cc && "\r" !== chars[c] && "\n" !== chars[c]) {
109+
start = end = c;
110+
if ('"' === chars[c]) {
111+
start = end = ++c;
112+
while (c < cc) {
113+
if ('"' === chars[c]) {
114+
if ('"' !== chars[c + 1]) {
115+
break;
116+
} else {
117+
chars[++c] = ""; // unescape ""
118+
}
119+
}
120+
end = ++c;
121+
}
122+
if ('"' === chars[c]) {
123+
++c;
124+
}
125+
while (
126+
c < cc &&
127+
"\r" !== chars[c] &&
128+
"\n" !== chars[c] &&
129+
"," !== chars[c]
130+
) {
131+
++c;
132+
}
133+
} else {
134+
while (
135+
c < cc &&
136+
"\r" !== chars[c] &&
137+
"\n" !== chars[c] &&
138+
"," !== chars[c]
139+
) {
140+
end = ++c;
141+
}
142+
}
143+
row.push(
144+
reviver(
145+
table.length - 1,
146+
row.length,
147+
chars.slice(start, end).join("")
148+
)
149+
);
150+
if ("," === chars[c]) {
151+
++c;
152+
}
153+
}
154+
if ("\r" === chars[c]) {
155+
++c;
156+
}
157+
if ("\n" === chars[c]) {
158+
++c;
159+
}
160+
}
161+
return table;
162+
},
163+
164+
stringify: function (table, replacer) {
165+
replacer =
166+
replacer ||
167+
function (r, c, v) {
168+
return v;
169+
};
170+
let csv = "",
171+
c,
172+
cc,
173+
r,
174+
rr = table.length,
175+
cell;
176+
for (r = 0; r < rr; ++r) {
177+
if (r) {
178+
csv += "\r\n";
179+
}
180+
for (c = 0, cc = table[r].length; c < cc; ++c) {
181+
if (c) {
182+
csv += ",";
183+
}
184+
cell = replacer(r, c, table[r][c]);
185+
if (/[,\r\n"]/.test(cell)) {
186+
cell = '"' + cell.replace(/"/g, '""') + '"';
187+
}
188+
csv += cell || 0 === cell ? cell : "";
189+
}
190+
}
191+
return csv;
192+
},
193+
};
194+
195+
/**
196+
* @param {string} str
197+
* @returns {boolean}
198+
*/
199+
function isNumeric(str) {
200+
if (typeof str != "string") return false; // we only process strings!
201+
return (
202+
!isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
203+
!isNaN(parseFloat(str))
204+
); // ...and ensure strings of whitespace fail
205+
}

Diff for: data.csv

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name,age,job
2+
adhom,14,engineer
3+
sasa,13,doctor

0 commit comments

Comments
 (0)