diff --git a/frontend/src/components/App.svelte b/frontend/src/components/App.svelte
index aa7eea5..c8be979 100644
--- a/frontend/src/components/App.svelte
+++ b/frontend/src/components/App.svelte
@@ -1,6 +1,6 @@
-
+
diff --git a/frontend/src/components/ChannelView.svelte b/frontend/src/components/pages/main/ChannelView.svelte
similarity index 92%
rename from frontend/src/components/ChannelView.svelte
rename to frontend/src/components/pages/main/ChannelView.svelte
index 712ca70..e63cca5 100644
--- a/frontend/src/components/ChannelView.svelte
+++ b/frontend/src/components/pages/main/ChannelView.svelte
@@ -1,5 +1,7 @@
-
-
-
diff --git a/frontend/src/gateway.js b/frontend/src/gateway.js
index 7a678d1..1dc9e4b 100644
--- a/frontend/src/gateway.js
+++ b/frontend/src/gateway.js
@@ -15,6 +15,13 @@ export const GatewayPayloadType = {
MessageDelete: 122,
}
+export const GatewayEventType = {
+ ...GatewayPayloadType,
+
+ Open: -5,
+ Close: -4
+}
+
export default {
ws: null,
authenticated: false,
@@ -23,7 +30,10 @@ export default {
channels: null,
reconnectDelay: 400,
reconnectTimeout: null,
+ handlers: new Map(),
init() {
+ window.__WAFFLE_GATEWAY = this;
+
const token = getAuthToken();
if (!token) {
return false;
@@ -33,6 +43,7 @@ export default {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
+ this.dispatch(GatewayEventType.Open, null);
console.log("[gateway] open");
};
this.ws.onmessage = (event) => {
@@ -65,6 +76,8 @@ export default {
break;
}
}
+
+ this.dispatch(payload.t, payload.d);
};
this.ws.onclose = () => {
if (this.reconnectDelay < 60000) {
@@ -80,6 +93,8 @@ export default {
this.init();
}, this.reconnectDelay);
+ this.dispatch(GatewayEventType.Close, null);
+
console.log("[gateway] close");
};
@@ -87,5 +102,33 @@ export default {
},
send(data) {
return this.ws.send(JSON.stringify(data));
+ },
+ dispatch(event, payload) {
+ const eventHandlers = this.handlers.get(event);
+ if (!eventHandlers)
+ return;
+
+ eventHandlers.forEach((e) => {
+ e(payload);
+ });
+ },
+ subscribe(event, handler) {
+ if (!this.handlers.get(event)) {
+ this.handlers.set(event, new Set());
+ }
+
+ this.handlers.get(event).add(handler);
+ return handler; // can later be used for unsubscribe()
+ },
+ unsubscribe(event, handler) {
+ const eventHandlers = this.handlers.get(event);
+ if (!eventHandlers)
+ return;
+
+ eventHandlers.delete(handler);
+
+ if (eventHandlers.size < 1) {
+ this.handlers.delete(event);
+ }
}
};
diff --git a/frontend/src/stores.js b/frontend/src/stores.js
new file mode 100644
index 0000000..db36e8c
--- /dev/null
+++ b/frontend/src/stores.js
@@ -0,0 +1,69 @@
+import gateway, { GatewayEventType } from "./gateway";
+
+export const channels = {
+ _handlers: [],
+ _value: [],
+ _didInit: false,
+ subscribe(handler) {
+ this._init();
+
+ const newLength = this._handlers.push(handler);
+ const handlerIndex = newLength - 1;
+ handler(this._value);
+ return () => {
+ this._handlers.splice(handlerIndex, 1);
+ };
+ },
+ _dispatchUpdate() {
+ this._handlers.forEach(e => {
+ e(this._value);
+ });
+ },
+ _init() {
+ window.__WAFFLE_CHANNELS_STORE = this;
+
+ if (this._didInit)
+ return;
+
+ this._didInit = true;
+
+ const channels = gateway.channels;
+ if (channels) {
+ this._value = channels;
+ }
+
+ gateway.subscribe(GatewayEventType.Ready, ({ channels }) => {
+ if (channels) {
+ this._value = channels;
+ }
+
+ this._dispatchUpdate();
+ });
+ gateway.subscribe(GatewayEventType.ChannelCreate, (channel) => {
+ this._value.push(channel);
+
+ this._dispatchUpdate();
+ });
+ gateway.subscribe(GatewayEventType.ChannelDelete, ({ id }) => {
+ const index = this._value.findIndex(e => e.id === id);
+ if (!index)
+ return;
+
+ this._value.splice(index);
+
+ this._dispatchUpdate();
+ });
+ gateway.subscribe(GatewayEventType.ChannelUpdate, (data) => {
+ const index = this._value.findIndex(e => e.id === data.id);
+ if (!index)
+ return;
+
+ if (!this._value[index])
+ return;
+
+ this._value[index] = data;
+
+ this._dispatchUpdate();
+ });
+ }
+};
diff --git a/test.rest b/test.rest
index abab5c2..28ad50b 100644
--- a/test.rest
+++ b/test.rest
@@ -19,50 +19,50 @@ content-type: application/json
###
GET http://localhost:3000/api/v1/users/self HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
###
POST http://localhost:3000/api/v1/channels HTTP/1.1
content-type: application/json
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
{
- "name": "yet another channelllll"
+ "name": "idk what to call these"
}
###
-PUT http://localhost:3000/api/v1/channels/8 HTTP/1.1
+PUT http://localhost:3000/api/v1/channels/5 HTTP/1.1
content-type: application/json
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
#Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5MjU5NDUwLCJleHAiOjE2NDk0MzIyNTB9.JmF9NujFZnln7A-ynNpeyayGBqmR5poAyACYV6RnSQY
{
- "name": "this is my channelaaaaaa"
+ "name": "idk what to put here"
}
###
-DELETE http://localhost:3000/api/v1/channels/1 HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+DELETE http://localhost:3000/api/v1/channels/10 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
#Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5MjU5NDUwLCJleHAiOjE2NDk0MzIyNTB9.JmF9NujFZnln7A-ynNpeyayGBqmR5poAyACYV6RnSQY
###
GET http://localhost:3000/api/v1/channels/1 HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
###
GET http://localhost:3000/api/v1/channels HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
###
POST http://localhost:3000/api/v1/channels/5/messages HTTP/1.1
content-type: application/json
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
{
"content": "i hate cheese"
@@ -71,13 +71,13 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6M
###
GET http://localhost:3000/api/v1/channels/5/messages HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
###
PUT http://localhost:3000/api/v1/messages/3 HTTP/1.1
content-type: application/json
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
{
"content": "hello again!"
@@ -86,9 +86,9 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6M
###
GET http://localhost:3000/api/v1/messages/3
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk
###
DELETE http://localhost:3000/api/v1/messages/2 HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjQ5NzAwMTE0LCJleHAiOjE2NDk4NzI5MTR9.EOn8MBHZLCxfU5fHc0ZY2x9p3y-_RdD7X915L1B6Ftc
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidHlwZSI6MSwiaWF0IjoxNjUwMTUyNjQ2LCJleHAiOjE2NTAzMjU0NDZ9.eFjOjJV3rIZWN0WrdRblflh2q8dYDGQv4qxugjbYNFk