change mailbox behaviour to use reception confirmations
This commit is contained in:
@@ -147,8 +147,8 @@ As you can see, there are many ways to connect multiple servers and communicate
|
||||
Anyone can develop apps for the UDN project. Examples of such apps are listed below. If you have developed an app for the UDN project and you want your app to be listed here, create an issue.
|
||||
|
||||
| App Name | Description | Links |
|
||||
| -- | -- | -- |
|
||||
| Comms | Messenger for UDN | [more info](https://github.com/marlon-erler/udn-comms/) - [install](https://udn-comms.onrender.com/)
|
||||
| -------- | ----------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| Comms | Messenger for UDN | [more info](https://github.com/marlon-erler/udn-comms/) - [install](https://udn-comms.onrender.com/) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -119,11 +119,12 @@ async function main() {
|
||||
|
||||
// CLI
|
||||
function updateCLI() {
|
||||
return;
|
||||
console.clear();
|
||||
|
||||
console.log(Colors.bold.bgWhite("UNIVERSAL DECENTRALIZED NETWORK"));
|
||||
console.log(
|
||||
Colors.yellow("relevant output is available in the 'logs' file")
|
||||
Colors.yellow("relevant output is available in the 'logs' file"),
|
||||
);
|
||||
console.log();
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "udn",
|
||||
"version": "1.0.0-beta14",
|
||||
"version": "1.0.0-beta15",
|
||||
"description": "A websocket-based infrastructure for decentralized networks ",
|
||||
"bin": {
|
||||
"start": "index.ts"
|
||||
|
||||
Vendored
+341
-91
@@ -73,8 +73,8 @@
|
||||
};
|
||||
function createProxyState(statesToSubscibe, fn) {
|
||||
const proxyState = new State(fn());
|
||||
statesToSubscibe.forEach(
|
||||
(state) => state.subscribe(() => proxyState.value = fn())
|
||||
statesToSubscibe.forEach((state) =>
|
||||
state.subscribe(() => (proxyState.value = fn())),
|
||||
);
|
||||
return proxyState;
|
||||
}
|
||||
@@ -85,7 +85,9 @@
|
||||
});
|
||||
}
|
||||
function restoreState(localStorageKey, initialStateValue) {
|
||||
const storedString = localStorage.getItem(localStorageKey) ?? JSON.stringify(initialStateValue);
|
||||
const storedString =
|
||||
localStorage.getItem(localStorageKey) ??
|
||||
JSON.stringify(initialStateValue);
|
||||
const convertedValue = JSON.parse(storedString);
|
||||
const state = new State(convertedValue);
|
||||
persistState(localStorageKey, state);
|
||||
@@ -120,9 +122,8 @@
|
||||
const [listState, toElement] = value;
|
||||
listState.handleAddition((newItem) => {
|
||||
const child = toElement(newItem);
|
||||
listState.handleRemoval(
|
||||
newItem,
|
||||
() => child.remove()
|
||||
listState.handleRemoval(newItem, () =>
|
||||
child.remove(),
|
||||
);
|
||||
element.append(child);
|
||||
element.scrollTop = element.scrollHeight;
|
||||
@@ -133,7 +134,8 @@
|
||||
} else {
|
||||
const state = value;
|
||||
state.subscribe(
|
||||
(newValue) => element[directiveValue] = newValue
|
||||
(newValue) =>
|
||||
(element[directiveValue] = newValue),
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -141,19 +143,22 @@
|
||||
case "bind": {
|
||||
const state = value;
|
||||
state.subscribe(
|
||||
(newValue) => element[directiveValue] = newValue
|
||||
(newValue) => (element[directiveValue] = newValue),
|
||||
);
|
||||
element.addEventListener(
|
||||
"input",
|
||||
() => state.value = element[directiveValue]
|
||||
() => (state.value = element[directiveValue]),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "toggle": {
|
||||
if (value.subscribe) {
|
||||
const state = value;
|
||||
state.subscribe(
|
||||
(newValue) => element.toggleAttribute(directiveValue, newValue)
|
||||
state.subscribe((newValue) =>
|
||||
element.toggleAttribute(
|
||||
directiveValue,
|
||||
newValue,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
element.toggleAttribute(directiveValue, value);
|
||||
@@ -162,8 +167,8 @@
|
||||
}
|
||||
case "set": {
|
||||
const state = value;
|
||||
state.subscribe(
|
||||
(newValue) => element.setAttribute(directiveValue, newValue)
|
||||
state.subscribe((newValue) =>
|
||||
element.setAttribute(directiveValue, newValue),
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -179,18 +184,12 @@
|
||||
var UDNFrontend = class {
|
||||
ws;
|
||||
// HANDLERS
|
||||
connectionHandler = () => {
|
||||
};
|
||||
disconnectionHandler = () => {
|
||||
};
|
||||
messageHandler = (data) => {
|
||||
};
|
||||
mailboxHandler = (mailboxId2) => {
|
||||
};
|
||||
mailboxConnectionHandler = (mailboxId2) => {
|
||||
};
|
||||
mailboxDeleteHandler = (mailboxId2) => {
|
||||
};
|
||||
connectionHandler = () => {};
|
||||
disconnectionHandler = () => {};
|
||||
messageHandler = (data) => {};
|
||||
mailboxHandler = (mailboxId2) => {};
|
||||
mailboxConnectionHandler = (mailboxId2) => {};
|
||||
mailboxDeleteHandler = (mailboxId2) => {};
|
||||
// INIT
|
||||
set onconnect(handler) {
|
||||
this.connectionHandler = handler;
|
||||
@@ -231,7 +230,9 @@
|
||||
if (data.assignedMailboxId) {
|
||||
return this.mailboxHandler(data.assignedMailboxId);
|
||||
} else if (data.connectedMailboxId) {
|
||||
return this.mailboxConnectionHandler(data.connectedMailboxId);
|
||||
return this.mailboxConnectionHandler(
|
||||
data.connectedMailboxId,
|
||||
);
|
||||
} else if (data.deletedMailbox) {
|
||||
return this.mailboxDeleteHandler(data.deletedMailbox);
|
||||
} else {
|
||||
@@ -249,39 +250,39 @@
|
||||
sendMessage(channel, body) {
|
||||
const messageObject = {
|
||||
messageChannel: channel,
|
||||
messageBody: body
|
||||
messageBody: body,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
// subscription
|
||||
subscribe(channel) {
|
||||
const messageObject = {
|
||||
subscribeChannel: channel
|
||||
subscribeChannel: channel,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
unsubscribe(channel) {
|
||||
const messageObject = {
|
||||
unsubscribeChannel: channel
|
||||
unsubscribeChannel: channel,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
// mailbox
|
||||
requestMailbox() {
|
||||
const messageObject = {
|
||||
requestingMailboxSetup: true
|
||||
requestingMailboxSetup: true,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
connectMailbox(mailboxId2) {
|
||||
const messageObject = {
|
||||
requestedMailbox: mailboxId2
|
||||
requestedMailbox: mailboxId2,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
deleteMailbox(mailboxId2) {
|
||||
const messageObject = {
|
||||
deletingMailbox: mailboxId2
|
||||
deletingMailbox: mailboxId2,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
@@ -310,7 +311,7 @@
|
||||
settings: "Settings",
|
||||
subscribeToChannel: "Subscribe to channel",
|
||||
subscribe: "Subscribe",
|
||||
unsubscribe: "Unubscribe"
|
||||
unsubscribe: "Unubscribe",
|
||||
};
|
||||
var allTranslations = {
|
||||
en: staticTextEnglish,
|
||||
@@ -336,7 +337,7 @@
|
||||
settings: "Configuraci\xF3n",
|
||||
subscribeToChannel: "Suscribirse a un canal",
|
||||
subscribe: "Suscribirse",
|
||||
unsubscribe: "Cancelar"
|
||||
unsubscribe: "Cancelar",
|
||||
},
|
||||
de: {
|
||||
mailbox: "Briefkasten",
|
||||
@@ -360,8 +361,8 @@
|
||||
settings: "Einstellungen",
|
||||
subscribeToChannel: "Kanal beitreten",
|
||||
subscribe: "Beitreten",
|
||||
unsubscribe: "Verlassen"
|
||||
}
|
||||
unsubscribe: "Verlassen",
|
||||
},
|
||||
};
|
||||
var language = navigator.language.substring(0, 2);
|
||||
var translations = allTranslations[language];
|
||||
@@ -377,18 +378,25 @@
|
||||
var mailboxId = restoreState("mailbox-id", "");
|
||||
var isMailboxDisonnected = new State(true);
|
||||
var messages = new ListState();
|
||||
var lastReceivedMessage = new State(
|
||||
translations.noMessagesReceived
|
||||
);
|
||||
var lastReceivedMessage = new State(translations.noMessagesReceived);
|
||||
var statHTMLString = new State("");
|
||||
async function updateStats() {
|
||||
const response = await fetch(
|
||||
`${window.location.protocol}//${window.location.host}/stats`
|
||||
`${window.location.protocol}//${window.location.host}/stats`,
|
||||
);
|
||||
const data = await response.json();
|
||||
let html = "";
|
||||
data.forEach((item) => {
|
||||
const tile = /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "secondary flex width-100" }, item[0].toString()), /* @__PURE__ */ createElement("b", null, item[1].toString()));
|
||||
const tile = /* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "tile" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "secondary flex width-100" },
|
||||
item[0].toString(),
|
||||
),
|
||||
/* @__PURE__ */ createElement("b", null, item[1].toString()),
|
||||
);
|
||||
html += tile.outerHTML;
|
||||
});
|
||||
statHTMLString.value = html;
|
||||
@@ -398,7 +406,7 @@
|
||||
var newMessageBody = new State("");
|
||||
var isMessageEmpty = createProxyState(
|
||||
[newMessageChannel, newMessageBody],
|
||||
() => newMessageChannel.value == "" || newMessageBody.value == ""
|
||||
() => newMessageChannel.value == "" || newMessageBody.value == "",
|
||||
);
|
||||
var UDN = new UDNFrontend();
|
||||
UDN.onconnect = () => {
|
||||
@@ -434,7 +442,7 @@
|
||||
};
|
||||
function connect() {
|
||||
UDN.connect(
|
||||
`${window.location.protocol.replace("http", "ws")}//${window.location.host}`
|
||||
`${window.location.protocol.replace("http", "ws")}//${window.location.host}`,
|
||||
);
|
||||
}
|
||||
connect();
|
||||
@@ -459,106 +467,348 @@
|
||||
|
||||
// src/infoScreen.tsx
|
||||
function InfoScreen() {
|
||||
return /* @__PURE__ */ createElement("article", { id: "info-screen" }, /* @__PURE__ */ createElement("header", null, translations.serverInfo, /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement("button", { "on:click": updateStats }, /* @__PURE__ */ createElement("span", { class: "icon" }, "refresh")))), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "flex-column gap", "subscribe:innerHTML": statHTMLString })));
|
||||
return /* @__PURE__ */ createElement(
|
||||
"article",
|
||||
{ id: "info-screen" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"header",
|
||||
null,
|
||||
translations.serverInfo,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{ "on:click": updateStats },
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"refresh",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement("div", {
|
||||
class: "flex-column gap",
|
||||
"subscribe:innerHTML": statHTMLString,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// src/mainScreen.tsx
|
||||
function MainScreen() {
|
||||
return /* @__PURE__ */ createElement("article", { id: "main-screen" }, /* @__PURE__ */ createElement("header", null, translations.settings), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "tile width-input" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, translations.messageLastReceived), /* @__PURE__ */ createElement("p", { class: "secondary", "subscribe:innerText": lastReceivedMessage }))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "tile width-input" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, translations.mailbox), /* @__PURE__ */ createElement("p", { class: "secondary", "toggle:hidden": isMailboxDisonnected }, translations.mailboxConnected))), /* @__PURE__ */ createElement("div", { class: "flex-row width-input justify-end" }, /* @__PURE__ */ createElement(
|
||||
return /* @__PURE__ */ createElement(
|
||||
"article",
|
||||
{ id: "main-screen" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"header",
|
||||
null,
|
||||
translations.settings,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "tile width-input" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"b",
|
||||
null,
|
||||
translations.messageLastReceived,
|
||||
),
|
||||
/* @__PURE__ */ createElement("p", {
|
||||
class: "secondary",
|
||||
"subscribe:innerText": lastReceivedMessage,
|
||||
}),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement("hr", null),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "tile width-input" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"b",
|
||||
null,
|
||||
translations.mailbox,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"p",
|
||||
{
|
||||
class: "secondary",
|
||||
"toggle:hidden": isMailboxDisonnected,
|
||||
},
|
||||
translations.mailboxConnected,
|
||||
),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "flex-row width-input justify-end" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{
|
||||
class: "danger width-50",
|
||||
"on:click": deleteMailbox,
|
||||
"toggle:disabled": isMailboxDisonnected
|
||||
"toggle:disabled": isMailboxDisonnected,
|
||||
},
|
||||
translations.deleteMailbox
|
||||
), /* @__PURE__ */ createElement(
|
||||
translations.deleteMailbox,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{
|
||||
class: "primary width-50",
|
||||
"on:click": requestMailbox,
|
||||
"toggle:disabled": isDisconnected
|
||||
"toggle:disabled": isDisconnected,
|
||||
},
|
||||
translations.requestMailbox,
|
||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "inbox")
|
||||
)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.subscribeToChannel), /* @__PURE__ */ createElement(
|
||||
"input",
|
||||
{
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"inbox",
|
||||
),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement("hr", null),
|
||||
/* @__PURE__ */ createElement(
|
||||
"label",
|
||||
{ class: "tile" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
null,
|
||||
translations.subscribeToChannel,
|
||||
),
|
||||
/* @__PURE__ */ createElement("input", {
|
||||
placeholder: translations.channel_placeholder,
|
||||
"bind:value": subscriptionChannel,
|
||||
"on:enter": subscribe
|
||||
}
|
||||
))), /* @__PURE__ */ createElement("div", { class: "flex-row width-input justify-end" }, /* @__PURE__ */ createElement("button", { class: "danger width-50", "on:click": unsubscribe }, translations.unsubscribe), /* @__PURE__ */ createElement("button", { class: "primary width-50", "on:click": subscribe }, translations.subscribe, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_forward"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.channel), /* @__PURE__ */ createElement(
|
||||
"input",
|
||||
{
|
||||
"on:enter": subscribe,
|
||||
}),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "flex-row width-input justify-end" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{ class: "danger width-50", "on:click": unsubscribe },
|
||||
translations.unsubscribe,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{ class: "primary width-50", "on:click": subscribe },
|
||||
translations.subscribe,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"arrow_forward",
|
||||
),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement("hr", null),
|
||||
/* @__PURE__ */ createElement(
|
||||
"label",
|
||||
{ class: "tile" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
null,
|
||||
translations.channel,
|
||||
),
|
||||
/* @__PURE__ */ createElement("input", {
|
||||
placeholder: translations.channel_placeholder,
|
||||
"bind:value": newMessageChannel,
|
||||
"on:enter": sendMessage
|
||||
}
|
||||
))), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.message), /* @__PURE__ */ createElement(
|
||||
"input",
|
||||
{
|
||||
"on:enter": sendMessage,
|
||||
}),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"label",
|
||||
{ class: "tile" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
null,
|
||||
translations.message,
|
||||
),
|
||||
/* @__PURE__ */ createElement("input", {
|
||||
placeholder: translations.message_placeholder,
|
||||
"bind:value": newMessageBody,
|
||||
"on:enter": sendMessage
|
||||
}
|
||||
))), /* @__PURE__ */ createElement("div", { class: "flex-row width-input justify-end" }, /* @__PURE__ */ createElement(
|
||||
"on:enter": sendMessage,
|
||||
}),
|
||||
),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "flex-row width-input justify-end" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{
|
||||
class: "primary width-50",
|
||||
"on:click": sendMessage,
|
||||
"toggle:disabled": isMessageEmpty
|
||||
"toggle:disabled": isMessageEmpty,
|
||||
},
|
||||
translations.send,
|
||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "send")
|
||||
))));
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"send",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// src/messageScreen.tsx
|
||||
var convertMessageToElement = (message) => {
|
||||
return /* @__PURE__ */ createElement("div", { class: "tile", style: "flex: 0" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, message.channel), /* @__PURE__ */ createElement("b", null, message.body)));
|
||||
return /* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "tile", style: "flex: 0" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "secondary" },
|
||||
message.channel,
|
||||
),
|
||||
/* @__PURE__ */ createElement("b", null, message.body),
|
||||
),
|
||||
);
|
||||
};
|
||||
function MessageScreen() {
|
||||
return /* @__PURE__ */ createElement("article", { id: "message-screen" }, /* @__PURE__ */ createElement("header", null, translations.messagesReceived), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement(
|
||||
return /* @__PURE__ */ createElement(
|
||||
"article",
|
||||
{ id: "message-screen" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"header",
|
||||
null,
|
||||
translations.messagesReceived,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{
|
||||
null,
|
||||
/* @__PURE__ */ createElement("div", {
|
||||
class: "flex-column gap",
|
||||
"subscribe:children": [messages, convertMessageToElement]
|
||||
}
|
||||
)), /* @__PURE__ */ createElement("footer", null, /* @__PURE__ */ createElement(
|
||||
"input",
|
||||
{
|
||||
"subscribe:children": [messages, convertMessageToElement],
|
||||
}),
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"footer",
|
||||
null,
|
||||
/* @__PURE__ */ createElement("input", {
|
||||
style: "max-width: unset",
|
||||
placeholder: translations.message_placeholder_generic,
|
||||
"bind:value": newMessageBody,
|
||||
"on:enter": sendMessage
|
||||
}
|
||||
), /* @__PURE__ */ createElement(
|
||||
"on:enter": sendMessage,
|
||||
}),
|
||||
/* @__PURE__ */ createElement(
|
||||
"button",
|
||||
{
|
||||
class: "primary",
|
||||
"on:click": sendMessage,
|
||||
"toggle:disabled": isMessageEmpty
|
||||
"toggle:disabled": isMessageEmpty,
|
||||
},
|
||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "send")
|
||||
)));
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"send",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// src/index.tsx
|
||||
document.body.prepend(
|
||||
/* @__PURE__ */ createElement("menu", null, /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#info-screen", active: true }, /* @__PURE__ */ createElement("span", { class: "icon" }, "info"), translations.info), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#main-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "settings"), translations.settings), /* @__PURE__ */ createElement("a", { class: "tab-link", href: "#message-screen" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "chat"), translations.messages))
|
||||
/* @__PURE__ */ createElement(
|
||||
"menu",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"a",
|
||||
{ class: "tab-link", href: "#info-screen", active: true },
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"info",
|
||||
),
|
||||
translations.info,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"a",
|
||||
{ class: "tab-link", href: "#main-screen" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"settings",
|
||||
),
|
||||
translations.settings,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"a",
|
||||
{ class: "tab-link", href: "#message-screen" },
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon" },
|
||||
"chat",
|
||||
),
|
||||
translations.messages,
|
||||
),
|
||||
),
|
||||
);
|
||||
document.querySelector("main").append(InfoScreen(), MainScreen(), MessageScreen());
|
||||
document
|
||||
.querySelector("main")
|
||||
.append(InfoScreen(), MainScreen(), MessageScreen());
|
||||
document.body.append(
|
||||
/* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isDisconnected }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement(
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{ class: "modal", "toggle:open": isDisconnected },
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"main",
|
||||
null,
|
||||
/* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{
|
||||
class: "flex-column align-center justify-center width-100 height-100",
|
||||
style: "gap: 1rem"
|
||||
style: "gap: 1rem",
|
||||
},
|
||||
/* @__PURE__ */ createElement("span", { class: "icon error", style: "font-size: 3rem" }, "signal_disconnected"),
|
||||
/* @__PURE__ */ createElement("h1", { class: "error" }, translations.disconnected),
|
||||
/* @__PURE__ */ createElement("p", { class: "secondary" }, translations.reconnecting)
|
||||
))))
|
||||
/* @__PURE__ */ createElement(
|
||||
"span",
|
||||
{ class: "icon error", style: "font-size: 3rem" },
|
||||
"signal_disconnected",
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"h1",
|
||||
{ class: "error" },
|
||||
translations.disconnected,
|
||||
),
|
||||
/* @__PURE__ */ createElement(
|
||||
"p",
|
||||
{ class: "secondary" },
|
||||
translations.reconnecting,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
})();
|
||||
|
||||
Vendored
+8
-3
@@ -245,7 +245,10 @@ SIZES
|
||||
--safe-area-top: env(safe-area-inset-top);
|
||||
--safe-area-left: env(safe-area-inset-left);
|
||||
--safe-area-right: env(safe-area-inset-right);
|
||||
--safe-area-bottom: max(env(safe-area-inset-bottom), var(--control-padding));
|
||||
--safe-area-bottom: max(
|
||||
env(safe-area-inset-bottom),
|
||||
var(--control-padding)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -593,7 +596,8 @@ label.tile:has(> span.icon) input {
|
||||
|
||||
article > div {
|
||||
padding-bottom: calc(
|
||||
var(--menu-height-mobile) + var(--control-height) + var(--content-padding)
|
||||
var(--menu-height-mobile) + var(--control-height) +
|
||||
var(--content-padding)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -909,7 +913,8 @@ menu {
|
||||
|
||||
article > div {
|
||||
padding-bottom: calc(
|
||||
var(--menu-height-mobile) + var(--header-height) + var(--content-padding)
|
||||
var(--menu-height-mobile) + var(--header-height) +
|
||||
var(--content-padding)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+5
-2
@@ -14,9 +14,12 @@ document.querySelector("main").addEventListener("scroll", () => {
|
||||
async function registerServiceWorker() {
|
||||
if ("serviceWorker" in navigator) {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register("/sw.js", {
|
||||
const registration = await navigator.serviceWorker.register(
|
||||
"/sw.js",
|
||||
{
|
||||
scope: "/",
|
||||
});
|
||||
},
|
||||
);
|
||||
if (registration.installing) {
|
||||
setTimeout(() => window.location.reload(), 500);
|
||||
} else if (registration.active) {
|
||||
|
||||
@@ -20,7 +20,7 @@ document.body.prepend(
|
||||
<span class="icon">chat</span>
|
||||
{translations.messages}
|
||||
</a>
|
||||
</menu>
|
||||
</menu>,
|
||||
);
|
||||
|
||||
document
|
||||
@@ -43,5 +43,5 @@ document.body.append(
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
@@ -16,7 +16,10 @@ export function InfoScreen() {
|
||||
</span>
|
||||
</header>
|
||||
<div>
|
||||
<div class="flex-column gap" subscribe:innerHTML={statHTMLString}></div>
|
||||
<div
|
||||
class="flex-column gap"
|
||||
subscribe:innerHTML={statHTMLString}
|
||||
></div>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
|
||||
@@ -26,7 +26,10 @@ export function MainScreen() {
|
||||
<div class="tile width-input">
|
||||
<div>
|
||||
<b>{translations.messageLastReceived}</b>
|
||||
<p class="secondary" subscribe:innerText={lastReceivedMessage}></p>
|
||||
<p
|
||||
class="secondary"
|
||||
subscribe:innerText={lastReceivedMessage}
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +38,10 @@ export function MainScreen() {
|
||||
<div class="tile width-input">
|
||||
<div>
|
||||
<b>{translations.mailbox}</b>
|
||||
<p class="secondary" toggle:hidden={isMailboxDisonnected}>
|
||||
<p
|
||||
class="secondary"
|
||||
toggle:hidden={isMailboxDisonnected}
|
||||
>
|
||||
{translations.mailboxConnected}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
+12
-7
@@ -4,7 +4,10 @@ import UDNFrontend from "udn-frontend";
|
||||
import { translations } from "./translations";
|
||||
|
||||
export class Message {
|
||||
constructor(public channel: string, public body: string) {}
|
||||
constructor(
|
||||
public channel: string,
|
||||
public body: string,
|
||||
) {}
|
||||
}
|
||||
|
||||
// STATE
|
||||
@@ -18,14 +21,14 @@ export const isMailboxDisonnected = new React.State(true);
|
||||
// messages
|
||||
export const messages = new React.ListState<Message>();
|
||||
export const lastReceivedMessage = new React.State(
|
||||
translations.noMessagesReceived
|
||||
translations.noMessagesReceived,
|
||||
);
|
||||
|
||||
// stats
|
||||
export const statHTMLString = new React.State<string>("");
|
||||
export async function updateStats() {
|
||||
const response = await fetch(
|
||||
`${window.location.protocol}//${window.location.host}/stats`
|
||||
`${window.location.protocol}//${window.location.host}/stats`,
|
||||
);
|
||||
const data: [string, string][] = await response.json();
|
||||
|
||||
@@ -33,7 +36,9 @@ export async function updateStats() {
|
||||
data.forEach((item) => {
|
||||
const tile = (
|
||||
<div class="tile">
|
||||
<span class="secondary flex width-100">{item[0].toString()}</span>
|
||||
<span class="secondary flex width-100">
|
||||
{item[0].toString()}
|
||||
</span>
|
||||
<b>{item[1].toString()}</b>
|
||||
</div>
|
||||
);
|
||||
@@ -50,7 +55,7 @@ export const newMessageBody = new React.State("");
|
||||
|
||||
export const isMessageEmpty = React.createProxyState(
|
||||
[newMessageChannel, newMessageBody],
|
||||
() => newMessageChannel.value == "" || newMessageBody.value == ""
|
||||
() => newMessageChannel.value == "" || newMessageBody.value == "",
|
||||
);
|
||||
|
||||
// UDN Frontend
|
||||
@@ -87,7 +92,7 @@ UDN.onmailboxconnect = () => {
|
||||
|
||||
UDN.onmailboxdelete = () => {
|
||||
isMailboxDisonnected.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
UDN.ondisconnect = () => {
|
||||
isDisconnected.value = true;
|
||||
@@ -97,7 +102,7 @@ UDN.ondisconnect = () => {
|
||||
|
||||
function connect() {
|
||||
UDN.connect(
|
||||
`${window.location.protocol.replace("http", "ws")}//${window.location.host}`
|
||||
`${window.location.protocol.replace("http", "ws")}//${window.location.host}`,
|
||||
);
|
||||
}
|
||||
connect();
|
||||
|
||||
+17
-11
@@ -8,7 +8,7 @@ import Crypto from "crypto";
|
||||
import { WS } from "./index";
|
||||
|
||||
export interface Subscriber {
|
||||
send: (message: string) => void;
|
||||
send: (message: string, compress?: boolean, id?: string) => void;
|
||||
}
|
||||
|
||||
export class Mailbox implements Subscriber {
|
||||
@@ -35,7 +35,7 @@ export class Mailbox implements Subscriber {
|
||||
{
|
||||
assignedMailboxId: this.id,
|
||||
},
|
||||
ws
|
||||
ws,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class Mailbox implements Subscriber {
|
||||
{
|
||||
connectedMailboxId: this.id,
|
||||
},
|
||||
this.ws
|
||||
this.ws,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export class Mailbox implements Subscriber {
|
||||
}
|
||||
|
||||
// storage
|
||||
messages = new Set<string>();
|
||||
messages = new Map<string, string>();
|
||||
|
||||
// websocket
|
||||
private _ws: WS | undefined;
|
||||
@@ -90,13 +90,13 @@ export class Mailbox implements Subscriber {
|
||||
}
|
||||
|
||||
// sending
|
||||
send(message: string): void {
|
||||
if (this._ws?.readyState == 1) {
|
||||
this._ws.send(message);
|
||||
this.dateLastUsed = new Date();
|
||||
} else {
|
||||
this.messages.add(message);
|
||||
}
|
||||
send(message: string, _?: boolean, uuid?: string): void {
|
||||
this._ws?.send(message);
|
||||
|
||||
console.log(this.id, uuid, message, "sending");
|
||||
|
||||
if (!uuid) return;
|
||||
this.messages.set(uuid, message);
|
||||
}
|
||||
|
||||
sendUnreadMessages(): void {
|
||||
@@ -107,6 +107,12 @@ export class Mailbox implements Subscriber {
|
||||
this.messages.delete(message);
|
||||
});
|
||||
}
|
||||
|
||||
checkMessageReceivedConfirmation(uuid: string): void {
|
||||
if (!this.messages.has(uuid)) return;
|
||||
this.dateLastUsed = new Date();
|
||||
this.messages.delete(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
export class SubscriptionMap {
|
||||
|
||||
+5
-5
@@ -3,9 +3,7 @@ import { PACKAGE_FILE, STATIC_DIR, WS } from ".";
|
||||
import Colors from "colors";
|
||||
import Fs from "fs/promises";
|
||||
import Path from "path";
|
||||
import {
|
||||
WebSocketMessage,
|
||||
} from "./websocket-handler";
|
||||
import { WebSocketMessage } from "./websocket-handler";
|
||||
|
||||
// CONFIG
|
||||
const STAT_INDENT = 25;
|
||||
@@ -39,12 +37,14 @@ async function writeToLogFile(message: string): Promise<void> {
|
||||
|
||||
// stats
|
||||
export function writeStatString(label: string, value: string): void {
|
||||
console.log(`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.green(value)}`);
|
||||
console.log(
|
||||
`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.green(value)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export function writeStatNumber(label: string, value: number): void {
|
||||
console.log(
|
||||
`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.blue(value.toString())}`
|
||||
`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.blue(value.toString())}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+28
-11
@@ -34,6 +34,9 @@ export interface WebSocketMessage {
|
||||
//sending message
|
||||
messageChannel?: string;
|
||||
messageBody?: string;
|
||||
|
||||
// confirming message
|
||||
confirmingMessageReceived?: boolean;
|
||||
}
|
||||
|
||||
// TRACKING
|
||||
@@ -64,7 +67,7 @@ export function forgetConnection(ws: WS): void {
|
||||
|
||||
export function trackSubscription(
|
||||
subscriber: Subscriber,
|
||||
channel: string
|
||||
channel: string,
|
||||
): void {
|
||||
subscriptionMap.set(subscriber, channel);
|
||||
confirmSubscription(subscriber, channel);
|
||||
@@ -72,7 +75,7 @@ export function trackSubscription(
|
||||
|
||||
export function forgetSubscription(
|
||||
subscriber: Subscriber,
|
||||
channel: string
|
||||
channel: string,
|
||||
): void {
|
||||
subscriptionMap.delete(subscriber, channel);
|
||||
confirmSubscription(subscriber, channel);
|
||||
@@ -104,7 +107,7 @@ export function reconnectServers(config: typeof defaultConfig): void {
|
||||
|
||||
export function connectServer(
|
||||
address: string,
|
||||
config: typeof defaultConfig
|
||||
config: typeof defaultConfig,
|
||||
): void {
|
||||
try {
|
||||
// connect
|
||||
@@ -153,7 +156,7 @@ export function subscribeChannel(server: WS, channel: string): void {
|
||||
export function processMessage(
|
||||
ws: WS,
|
||||
messageString: string,
|
||||
config: typeof defaultConfig
|
||||
config: typeof defaultConfig,
|
||||
): void {
|
||||
// MESSAGE ID
|
||||
// check id
|
||||
@@ -161,6 +164,14 @@ export function processMessage(
|
||||
if (!messageObject.uuid) {
|
||||
// assign if no id
|
||||
messageObject.uuid = Crypto.randomUUID();
|
||||
} else if (messageObject.confirmingMessageReceived == true) {
|
||||
// received confirmation
|
||||
mailboxes.forEach((mailbox) => {
|
||||
if (mailbox.ws != ws) return;
|
||||
return mailbox.checkMessageReceivedConfirmation(
|
||||
messageObject.uuid!,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// ignore if already seen
|
||||
if (knownMessageIds.has(messageObject.uuid)) return;
|
||||
@@ -179,7 +190,11 @@ export function processMessage(
|
||||
// MESSAGE
|
||||
doIfIsString(messageObject.messageChannel, (messageChannel) => {
|
||||
if (messageObject.messageBody == undefined) return;
|
||||
sendMessage(messageChannel, messageObject.messageBody, messageObject.uuid!);
|
||||
sendMessage(
|
||||
messageChannel,
|
||||
messageObject.messageBody,
|
||||
messageObject.uuid!,
|
||||
);
|
||||
});
|
||||
|
||||
// MAILBOX
|
||||
@@ -192,7 +207,7 @@ export function processMessage(
|
||||
if (!mailbox)
|
||||
return sendWebSocketMessage(
|
||||
{ deletedMailbox: requestedMailbox },
|
||||
ws
|
||||
ws,
|
||||
);
|
||||
mailbox.ws = ws;
|
||||
});
|
||||
@@ -225,16 +240,16 @@ export function removeMailbox(mailbox: Mailbox) {
|
||||
// MESSAGING
|
||||
export function sendWebSocketMessage(
|
||||
messageObject: WebSocketMessage,
|
||||
destination: Subscriber
|
||||
destination: Subscriber,
|
||||
): void {
|
||||
const messageString = JSON.stringify(messageObject);
|
||||
destination.send(messageString);
|
||||
destination.send(messageString, false, messageObject.uuid);
|
||||
}
|
||||
|
||||
export function sendMessage(
|
||||
messageChannel: string,
|
||||
messageBody: string,
|
||||
uuid: string
|
||||
uuid: string,
|
||||
): void {
|
||||
const channels = messageChannel.split("/");
|
||||
subscriptionMap.forwardMessage(channels, {
|
||||
@@ -254,11 +269,13 @@ function requestServerConnection(ws: WS): void {
|
||||
|
||||
function confirmSubscription(
|
||||
subscriber: Subscriber,
|
||||
messageChannel: string
|
||||
messageChannel: string,
|
||||
): void {
|
||||
const messageObject: WebSocketMessage = {
|
||||
messageChannel,
|
||||
subscribed: subscriptionMap.getChannelList(subscriber)?.has(messageChannel)
|
||||
subscribed: subscriptionMap
|
||||
.getChannelList(subscriber)
|
||||
?.has(messageChannel)
|
||||
? true
|
||||
: false,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user