Skip to content
Closed

Dms #10

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions electron/.idea/statistic.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 65 additions & 4 deletions electron/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
nativeImage,
session,
desktopCapturer,
dialog,
Notification,
net,
} = require("electron");
Expand All @@ -21,6 +22,9 @@ const Settings = require("./modules/settings");
const FrontendLibs = require("@hackthedev/frontend-libs").default;
let libDir = path.join(path.resolve(), "web", "js", "libs");

const AppUpdater = require("@hackthedev/app-updater").default;
//const AppUpdater = require("E:\\network-z-dev\\app-updater\\index.mjs").default;


let win = null;
const applicationDataDir = path.join(app.getPath("documents"), "dcts");
Expand Down Expand Up @@ -76,10 +80,11 @@ function registerWindowBoundsPersistence(win) {
async function createWindow(width, height) {
// installing multiple packages
const results = await FrontendLibs.installMultiple([
{ package: '@hackthedev/icons@1.0.6', path: libDir },
{ package: '@hackthedev/icons@latest', path: libDir },
{ package: '@hackthedev/mobile-ui@latest', path: libDir },
{ package: '@hackthedev/prompts@latest', path: libDir },
{ package: '@hackthedev/rich-editor', path: libDir },
{ package: '@hackthedev/json-editor', path: libDir },
{ package: '@hackthedev/chat-tools@1.0.0', path: libDir },
]);

Expand Down Expand Up @@ -166,14 +171,70 @@ app.commandLine.appendSwitch(
);

app.whenReady().then(async () => {
// Check for fucking update
let updateCheck = await AppUpdater.check("https://dcts.community/app/electron", {
includeOsUrl: true,
version: app.getVersion()
})


// if available show prompt
if(updateCheck?.available){
let result = await dialog.showMessageBox({
type: "question",
buttons: ["Update", "Not now"],
defaultId: 0,
cancelId: 1,
title: "DCTS Client Update available",
message: "It seems that a new version of the DCTS Client is available. Do you wanna download it?",
detail: `Current Version: ${updateCheck?.current}\nAvailable Version: ${updateCheck?.remote}`
});

if(result.response === 0){
let progressWindow = new BrowserWindow({
width: 400,
height: 160,
resizable: false,
minimizable: false,
maximizable: false,
autoHideMenuBar: true
});

await progressWindow.loadURL(`data:text/html,
<body style="font-family:sans-serif;padding:20px;">
<h3>DCTS Update</h3>
<div id="status">Starting download...</div>
</body>
`);

if(updateCheck?.downloadUrl){
let file = await AppUpdater.downloadFile(
updateCheck.downloadUrl,
(data) => {
progressWindow.webContents.executeJavaScript(`
document.getElementById("status").innerText =
"Downloading... ${data.progress}%";
`);
}
);

progressWindow.webContents.executeJavaScript(`
document.getElementById("status").innerText =
"Finished: ${file.replaceAll("\\", "\\\\")}";
`);
}
}
}


await Settings.initSettings(applicationDataDir);

// youtube embed fix — header spoofing
session.defaultSession.webRequest.onBeforeSendHeaders(
{ urls: ['*://*.youtube.com/*', '*://*.googlevideo.com/*', '*://*.ytimg.com/*'] },
{ urls: ['*://*.youtube-nocookie.com/*', '*://*.youtube.com/*', '*://*.googlevideo.com/*', '*://*.ytimg.com/*'] },
(details, callback) => {
details.requestHeaders['Referer'] = 'https://www.youtube.com'
details.requestHeaders['Origin'] = 'https://www.youtube.com'
details.requestHeaders['Referer'] = 'https://www.youtube-nocookie.com'
details.requestHeaders['Origin'] = 'https://www.youtube-nocookie.com'
callback({ requestHeaders: details.requestHeaders })
}
)
Expand Down
5 changes: 5 additions & 0 deletions electron/modules/GetAlias.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Settings from "./settings.js";

export const GetAlias = async ({ signer, applicationDataDir }) => {
return await Settings.settings?.user?.alias ?? null;
}
6 changes: 6 additions & 0 deletions electron/modules/GetChatLastMessage.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Settings from "./settings.js";

export const GetChatLastMessage = async ({ signer, applicationDataDir }, chatId) => {
if(!chatId) throw new Error("No chatId for getting the chat message");
return await Settings.Message.getChatLastMessage(chatId);
}
4 changes: 2 additions & 2 deletions electron/modules/GetChatMessages.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Settings from "./settings.js";

export const GetChatMessages = async ({ signer, applicationDataDir }, chatId) => {
export const GetChatMessages = async ({ signer, applicationDataDir }, chatId, timestamp, desc) => {
if(!chatId) throw new Error("No chatId for getting the chat messages");
return await Settings.Message.getMessages(chatId);
return await Settings.Message.getMessages(chatId, timestamp, desc);
}
5 changes: 5 additions & 0 deletions electron/modules/GetNickname.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Settings from "./settings.js";

export const GetNickname = async ({ signer, applicationDataDir }) => {
return await Settings.settings?.user?.nickname ?? null;
}
5 changes: 5 additions & 0 deletions electron/modules/GetUserConsistentSettings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Settings from "./settings.js";

export const GetUserConsistentSettings = async ({ signer, applicationDataDir }) => {
return Settings?.settings?.user?.consistent ?? true;
}
5 changes: 5 additions & 0 deletions electron/modules/GetUserIcon.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Settings from "./settings.js";

export const GetUserIcon = async ({ signer, applicationDataDir }) => {
return await Settings.settings.user.icon ?? null;
}
7 changes: 7 additions & 0 deletions electron/modules/SetAlias.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Settings from "./settings.js";

export const SetAlias = async ({ signer, applicationDataDir }, aliasString) => {
if(aliasString === undefined) throw new Error("Nickname wasnt set")
Settings.settings.user.alias = aliasString;
await Settings.saveSettings()
}
7 changes: 7 additions & 0 deletions electron/modules/SetNickname.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Settings from "./settings.js";

export const SetNickname = async ({ signer, applicationDataDir }, nicknameString) => {
if(nicknameString === undefined) throw new Error("Nickname wasnt set")
Settings.settings.user.nickname = nicknameString;
await Settings.saveSettings()
}
7 changes: 7 additions & 0 deletions electron/modules/SetUserConsistentSettings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Settings from "./settings.js";

export const SetUserConsistentSettings = async ({ signer, applicationDataDir }, boolean) => {
if(boolean === undefined || typeof boolean !== "boolean") throw new Error("Bool not set")
Settings.settings.user.consistent = !!boolean;
await Settings.saveSettings()
}
7 changes: 7 additions & 0 deletions electron/modules/SetUserIcon.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Settings from "./settings.js";

export const SetUserIcon = async ({ signer, applicationDataDir }, iconString) => {
if(iconString === undefined) throw new Error("Icon wasnt set")
Settings.settings.user.icon = iconString;
await Settings.saveSettings()
}
95 changes: 70 additions & 25 deletions electron/modules/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Settings {
static settings = {}
static _loaded = false
static _writeQueue = Promise.resolve()
static runtimeData = {}

static Client = class {
static async getLastOnline() {
Expand Down Expand Up @@ -51,23 +52,22 @@ class Settings {
static Message = class {
static async saveChat(chatId, data = {}) {
if (!chatId) throw new Error("chatId is required")
if(Object.keys(data || {}).length === 0) throw new Error("Data was empty")
if (Object.keys(data || {}).length === 0) throw new Error("data was empty")

let chatPath = path.join(Settings.appDataDir, "chats", chatId)
let chatMessagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages")
let chatConfigPath = path.join(Settings.appDataDir, "chats", chatId, "config.json")

// if the directory doesnt exist create it.
// we use the chatMessagePath here because that will also create the chatPath path
// as we use "recursive: true"
if(!fsNormal.existsSync(chatMessagesPath)){
fsNormal.mkdirSync(path.join(chatMessagesPath), { recursive: true });
if (!fsNormal.existsSync(chatMessagesPath)) {
fsNormal.mkdirSync(chatMessagesPath, { recursive: true });
}

// also create the config file for the chat itself if it doesnt exist
if(!fsNormal.existsSync(chatConfigPath)){
await fs.writeFile(chatConfigPath, JSON.stringify(data, null, 4));
}
// always overwrite the config so it stays up to date
Settings.runtimeData.chats ??= {};
Settings.runtimeData.chats[chatId] = data;
await fs.writeFile(chatConfigPath, JSON.stringify(data, null, 4));

Settings.settings.client ??= {}
Settings.settings.client.lastOnline = new Date().getTime();
Expand All @@ -78,7 +78,9 @@ class Settings {
if (!chatId) return null
let chatConfigPath = path.join(Settings.appDataDir, "chats", chatId, "config.json")

Settings.runtimeData.chats ??= {};
if(fsNormal.existsSync(chatConfigPath)) {
if(Settings.runtimeData.chats[chatId]) return Settings.runtimeData.chats[chatId];
return JSON.parse(await fs.readFile(chatConfigPath, "utf8") ?? {})
}
else{
Expand All @@ -90,12 +92,21 @@ class Settings {
let chatsPath = path.join(Settings.appDataDir, "chats")

// create it if it doesnt exist
if(!fsNormal.existsSync(chatsPath)) fsNormal.mkdirSync(chatsPath)
if(!fsNormal.existsSync(chatsPath)) fsNormal.mkdirSync(chatsPath, { recursive: true })
let chatIds = await fs.readdir(chatsPath);

let chats = {}
Settings.runtimeData.chats ??= {};

if(chatIds?.length > 0){
for(let chatId of chatIds){

// if already in ram use that instead
if(Settings.runtimeData.chats[chatId]){
chats[chatId] = Settings.runtimeData.chats[chatId];
continue;
}

let chatConfigPath = path.join(Settings.appDataDir, "chats", chatId, "config.json")
let chatConfig = JSON.parse(await fs.readFile(chatConfigPath, "utf8") ?? {})

Expand All @@ -115,9 +126,9 @@ class Settings {
if(!data) throw new Error("data is required")

let messagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages");
if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath);
if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath, { recursive: true });

fs.writeFile(path.join(messagesPath, `${messageId}.json`), JSON.stringify(data, null, 4));
await fs.writeFile(path.join(messagesPath, `${messageId}.json`), JSON.stringify(data, null, 4));

Settings.settings.client ??= {}
Settings.settings.client.lastOnline = new Date().getTime();
Expand All @@ -128,30 +139,62 @@ class Settings {
if (!chatId || !messageId) return null
}

static async getMessages(chatId) {
static async getChatLastMessage(chatId) {
if (!chatId) return null;

let messages = await this.getMessages(chatId, new Date().getTime(), true);
messages = Object.values(messages);

if(messages.length === 0) return null;

messages.sort((a, b) => {
return (b?.timestamp ?? 0) - (a?.timestamp ?? 0);
});

return messages[0] ?? null;
}

static async getMessages(chatId, timestamp = new Date().getTime(), desc = true) {
if (!chatId) return {}
let limit = 50;

let messagesPath = path.join(Settings.appDataDir, "chats", chatId, "messages")

// create it if it doesnt exist
if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath)
if(!fsNormal.existsSync(messagesPath)) fsNormal.mkdirSync(messagesPath, { recursive: true })

let messageIds = await fs.readdir(messagesPath);
let messages = {}
let messages = []

if(messageIds?.length > 0){
for(let messageId of messageIds){
let messageFile = path.join(messagesPath, `${messageId}`)
for(let messageId of messageIds){
let messageFile = path.join(messagesPath, messageId)
let messageConfig = JSON.parse(await fs.readFile(messageFile, "utf8") ?? "{}")

let messageConfig = JSON.parse(await fs.readFile(messageFile, "utf8") ?? {})
let createdAt = messageConfig?.timestamp ?? 0

messages[messageId] = messageConfig;
}
if(desc && createdAt >= timestamp) continue
if(!desc && createdAt <= timestamp) continue

return messages;
messages.push({
id: messageId,
timestamp: createdAt,
data: messageConfig
})
}
else{
return {}

messages.sort((a, b) => {
if(desc) return b.timestamp - a.timestamp
return a.timestamp - b.timestamp
})

messages = messages.slice(0, limit)

let result = {}

for(let message of messages){
result[message.id] = message.data
}

return result
}

static async deleteMessage(chatId, messageId) {
Expand Down Expand Up @@ -240,16 +283,18 @@ class Settings {
}
}

static initSettings(appDataDir) {
static async initSettings(appDataDir) {
this.settingsPath = path.join(appDataDir, "settings.json")
this.appDataDir = appDataDir
await this._ensureLoaded();
}

static async _ensureLoaded() {
if (this._loaded) return
try {
const data = await fs.readFile(this.settingsPath, "utf8")
this.settings = JSON.parse(data)
this.settings.user ??= {}
} catch {
this.settings = {}
}
Expand Down
Loading
Loading