From 73c128dbcbcbc5e2d57c6033882b90c9113471b7 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Thu, 5 Dec 2024 15:33:01 +0200 Subject: [PATCH 01/15] Rewrote service to call the package from the file. --- sharkey-service.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sharkey-service.nix b/sharkey-service.nix index e6e004c8d1..4f5551086c 100644 --- a/sharkey-service.nix +++ b/sharkey-service.nix @@ -188,7 +188,7 @@ in options = { services.sharkey = { enable = lib.mkEnableOption "sharkey"; - package = lib.mkPackageOption pkgs "sharkey" { }; + package = (pkgs.callPackage ./sharkey.nix { }); inherit settings; database = { createLocally = lib.mkOption { From 03df443aa8feb2a444f01368d425f24937f060a8 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Thu, 5 Dec 2024 15:33:12 +0200 Subject: [PATCH 02/15] Added sharkey-service nixos module --- flake.nix | 31 ++----------------------------- sharkey-service.nix | 7 +++++-- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/flake.nix b/flake.nix index e32d28bea5..eb09f76208 100644 --- a/flake.nix +++ b/flake.nix @@ -3,36 +3,9 @@ outputs = { self, nixpkgs }: { - nixosConfigurations.container = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = - [ - ( import ./sharkey-service.nix ) - ({ pkgs, ... }: { - boot.isContainer = true; + nixosModules.sharkey-service = args : import ./sharkey-service.nix ( args // { sharkey = self.packages.sharkey; } ); - # Let 'nixos-version --json' know about the Git revision - # of this flake. - system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev; - - # Network configuration. - networking.useDHCP = false; - networking.firewall.allowedTCPPorts = [ 3000 ]; - - system.stateVersion = "24.04"; - - services.sharkey = { - enable = true; - package = (pkgs.callPackage ./sharkey.nix {}); - settings = { - url = "https://sharkey.localhost"; - }; - redis.createLocally = true; - database.createLocally = true; - }; - }) - ]; - }; + packages."x86_64-linux".sharkey = nixpkgs.legacyPackages."x86_64-linux".callPackage ./sharkey.nix { }; }; } diff --git a/sharkey-service.nix b/sharkey-service.nix index 4f5551086c..64fa85fb6a 100644 --- a/sharkey-service.nix +++ b/sharkey-service.nix @@ -2,6 +2,7 @@ config, pkgs, lib, + sharkey, ... }: @@ -186,9 +187,11 @@ in { options = { + + + services.sharkey = { enable = lib.mkEnableOption "sharkey"; - package = (pkgs.callPackage ./sharkey.nix { }); inherit settings; database = { createLocally = lib.mkOption { @@ -340,7 +343,7 @@ in ${pkgs.replace-secret}/bin/replace-secret '@MEILISEARCH_KEY@' "${cfg.meilisearch.keyFile}" /run/sharkey/default.yml ''); serviceConfig = { - ExecStart = "${cfg.package}/bin/sharkey migrateandstart"; + ExecStart = "${sharkey}/bin/sharkey migrateandstart"; RuntimeDirectory = "sharkey"; RuntimeDirectoryMode = "700"; StateDirectory = "sharkey"; From 9c742102132856f11d74079c7a65e0254c8a7cf9 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Thu, 5 Dec 2024 16:06:56 +0200 Subject: [PATCH 03/15] Added sharkey-service nixos module --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index eb09f76208..55c8a5b3f6 100644 --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,7 @@ outputs = { self, nixpkgs }: { - nixosModules.sharkey-service = args : import ./sharkey-service.nix ( args // { sharkey = self.packages.sharkey; } ); + nixosModules.sharkey-service = args : import ./sharkey-service.nix ( args // { sharkey = self.packages."x86_64-linux".sharkey; pkgs = nixpkgs.legacyPackages."x86_64-linux"; } ); packages."x86_64-linux".sharkey = nixpkgs.legacyPackages."x86_64-linux".callPackage ./sharkey.nix { }; From 75d6ae66aad30ea65afb612391bf0c2b7cd55e9f Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Thu, 5 Dec 2024 20:17:09 +0200 Subject: [PATCH 04/15] Set sharkey package as default --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index 55c8a5b3f6..f3b064d3f5 100644 --- a/flake.nix +++ b/flake.nix @@ -7,5 +7,7 @@ packages."x86_64-linux".sharkey = nixpkgs.legacyPackages."x86_64-linux".callPackage ./sharkey.nix { }; + packages."x86_64-linux".default = self.packages."x86_64-linux".sharkey; + }; } From 50f154af57bda271a8382d82534476ee644399bf Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 08:57:00 +0100 Subject: [PATCH 05/15] Got sharkey with isolated db running. --- flake.nix | 13 +++++++++++++ run_with_db.sh | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100755 run_with_db.sh diff --git a/flake.nix b/flake.nix index f3b064d3f5..d001f8d9fc 100644 --- a/flake.nix +++ b/flake.nix @@ -9,5 +9,18 @@ packages."x86_64-linux".default = self.packages."x86_64-linux".sharkey; + # Default dev shell with all of sharkey's dependencies + redis and postgresql + devShells."x86_64-linux".default = nixpkgs.legacyPackages."x86_64-linux".mkShell { + + inputsFrom = [ + self.packages."x86_64-linux".sharkey + ]; + + nativeBuildInputs = with nixpkgs.legacyPackages."x86_64-linux"; [ + redis + postgresql + yq + ]; + }; }; } diff --git a/run_with_db.sh b/run_with_db.sh new file mode 100755 index 0000000000..4144e8f485 --- /dev/null +++ b/run_with_db.sh @@ -0,0 +1,48 @@ +# Set up a postgresql database and a redis server for the integration tests. + +# Create a unique temporary directory for the unix socket and data: +export PGDATA=$(mktemp -d) + +# Initialize the PostgreSQL data directory +initdb -D $PGDATA -U postgres + +# Start PostgreSQL and Redis using unix sockets +pg_ctl -D $PGDATA -l $PGDATA/logfile start -o "-k $PGDATA --listen-addresses=''" +until pg_isready -h $PGDATA; do sleep 1; done +echo "PostgreSQL started with unix socket at $PGDATA" + +# Create a "sharkey" user and database +psql -h $PGDATA -c "CREATE USER sharkey" -U postgres +psql -h $PGDATA -c "CREATE DATABASE sharkey OWNER sharkey" -U postgres + +# Grab an empty TCP port: +function random_unused_port { + local port=$(shuf -i 2000-65000 -n 1) + netstat -lat | grep $port > /dev/null + if [[ $? == 1 ]] ; then + echo $port + else + random_unused_port + fi +} + +export REDIS_PORT=$(random_unused_port) +redis-server --port $REDIS_PORT --loglevel warning & +until redis-cli -p $REDIS_PORT ping; do sleep 1; done +echo "Redis started with unix socket at $REDISSOCK" + +cp .config/example.yml .config/default.yml +yq -i -Y '.db.host = "'$PGDATA'"' .config/default.yml +yq -i -Y '.redis.port = "'$REDIS_PORT'"' .config/default.yml + +#export MISSKEY_CONFIG_YML=.config/default.yml +pnpm run migrateandstart + +# Open Firefox + +# Stop PostgreSQL and Redis +cleanup() { + pg_ctl -D $PGDATA stop + redis-cli -s $REDISSOCK shutdown +} +trap cleanup EXIT From b854de4538dda93bb9c43a264fcb228a86c77d62 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 09:54:41 +0100 Subject: [PATCH 06/15] Cleaned up the startup script --- run_with_db.sh | 114 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 31 deletions(-) diff --git a/run_with_db.sh b/run_with_db.sh index 4144e8f485..389afc7cb5 100755 --- a/run_with_db.sh +++ b/run_with_db.sh @@ -1,21 +1,35 @@ # Set up a postgresql database and a redis server for the integration tests. -# Create a unique temporary directory for the unix socket and data: -export PGDATA=$(mktemp -d) +# Set up a PostgreSQL database for the integration tests. +# +# Preconditions: +# - PostgreSQL must be installed on the system. +# - The `initdb`, `pg_ctl`, and `psql` commands must be available in the PATH. +# +# Postconditions: +# - A temporary PostgreSQL data directory will be created and initialized. +# - PostgreSQL will be started using a Unix socket. +# - A PostgreSQL user and database named "sharkey" will be created. +create_tmp_psql() { + export PGDATA=$(mktemp -d) -# Initialize the PostgreSQL data directory -initdb -D $PGDATA -U postgres + # Initialize the PostgreSQL data directory + initdb -D $PGDATA -U postgres -# Start PostgreSQL and Redis using unix sockets -pg_ctl -D $PGDATA -l $PGDATA/logfile start -o "-k $PGDATA --listen-addresses=''" -until pg_isready -h $PGDATA; do sleep 1; done -echo "PostgreSQL started with unix socket at $PGDATA" + # Start PostgreSQL using Unix sockets + pg_ctl -D $PGDATA -l $PGDATA/logfile start -o "-k $PGDATA --listen-addresses=''" + until pg_isready -h $PGDATA; do sleep 1; done + echo "PostgreSQL started with Unix socket at $PGDATA" -# Create a "sharkey" user and database -psql -h $PGDATA -c "CREATE USER sharkey" -U postgres -psql -h $PGDATA -c "CREATE DATABASE sharkey OWNER sharkey" -U postgres + # Create a "sharkey" user and database + psql -h $PGDATA -c "CREATE USER sharkey" -U postgres + psql -h $PGDATA -c "CREATE DATABASE sharkey OWNER sharkey" -U postgres +} -# Grab an empty TCP port: +# Function to find a random unused port +# It generates a random port number between 2000 and 65000 +# and checks if it is in use. If it is in use, it recursively +# calls itself until an unused port is found. function random_unused_port { local port=$(shuf -i 2000-65000 -n 1) netstat -lat | grep $port > /dev/null @@ -26,23 +40,61 @@ function random_unused_port { fi } -export REDIS_PORT=$(random_unused_port) -redis-server --port $REDIS_PORT --loglevel warning & -until redis-cli -p $REDIS_PORT ping; do sleep 1; done -echo "Redis started with unix socket at $REDISSOCK" - -cp .config/example.yml .config/default.yml -yq -i -Y '.db.host = "'$PGDATA'"' .config/default.yml -yq -i -Y '.redis.port = "'$REDIS_PORT'"' .config/default.yml - -#export MISSKEY_CONFIG_YML=.config/default.yml -pnpm run migrateandstart - -# Open Firefox - -# Stop PostgreSQL and Redis -cleanup() { - pg_ctl -D $PGDATA stop - redis-cli -s $REDISSOCK shutdown +# Function to create a Redis server on a random unused port +# It exports the port number to the REDIS_PORT environment variable +# and starts the Redis server with log level set to warning. +# It waits until the Redis server is ready to accept connections. +create_redis_on_random_port() { + export REDIS_PORT=$(random_unused_port) + redis-server --port $REDIS_PORT --loglevel warning & + until redis-cli -p $REDIS_PORT ping; do sleep 1; done + echo "Redis started on port $REDIS_PORT" } -trap cleanup EXIT + +pick_sharkey_port() { + export SHARKEY_PORT=$(random_unused_port) +} + +# Function to copy the example configuration file and update it with the PostgreSQL and Redis settings. +# Arguments: +# $1: The destination file path (optional). Defaults to `.config/default.yml`. +copy_and_update_config() { + local dest_file=.config/default.yml + cp .config/example.yml $dest_file + yq -i -Y ".db.host = \"$PGDATA\"" $dest_file + yq -i -Y ".redis.port = $REDIS_PORT" $dest_file + yq -i -Y ".port = $SHARKEY_PORT" $dest_file +} + +# Function to stop the PostgreSQL server; $PGDATA must be set +stop_psql() { + pg_ctl -D "$PGDATA" stop +} + +# Function to stop the Redis server +stop_redis() { + redis-cli -p "$REDIS_PORT" shutdown +} + +# Function to stop both PostgreSQL and Redis servers +stop_databases() { + stop_psql + stop_redis +} + +# Function to start a fresh instance of the Sharkey application +# It sets up a temporary PostgreSQL database and a Redis server on a random port, +# updates the configuration file, and runs the application. +start_fresh_sharkey() { + create_tmp_psql + create_redis_on_random_port + pick_sharkey_port + trap stop_databases EXIT + + copy_and_update_config + pnpm run migrateandstart +} + +start_fresh_sharkey + +firefox http://localhost:$SHARKEY_PORT --marionette --new-instance From 3481f3fefccd1779e63611bc5d95cc2109f15ab7 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 12:45:56 +0100 Subject: [PATCH 07/15] Removed the pointless dev shell. --- flake.nix | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/flake.nix b/flake.nix index d001f8d9fc..388fa573ba 100644 --- a/flake.nix +++ b/flake.nix @@ -8,19 +8,5 @@ packages."x86_64-linux".sharkey = nixpkgs.legacyPackages."x86_64-linux".callPackage ./sharkey.nix { }; packages."x86_64-linux".default = self.packages."x86_64-linux".sharkey; - - # Default dev shell with all of sharkey's dependencies + redis and postgresql - devShells."x86_64-linux".default = nixpkgs.legacyPackages."x86_64-linux".mkShell { - - inputsFrom = [ - self.packages."x86_64-linux".sharkey - ]; - - nativeBuildInputs = with nixpkgs.legacyPackages."x86_64-linux"; [ - redis - postgresql - yq - ]; - }; }; } From ffb2ec60ed99d9acca09b675f9d4b0c799a136cb Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 14:25:36 +0100 Subject: [PATCH 08/15] Inlined the confirm. --- packages/frontend/src/boot/main-boot.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 395d7d9ad1..7c34506b76 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -50,10 +50,20 @@ export async function mainBoot() { if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { if (reloadDialogShowing) return; reloadDialogShowing = true; - const { canceled } = await confirm({ - type: 'warning', - title: i18n.ts.disconnectedFromServer, - text: i18n.ts.reloadConfirm, + const { canceled } = await new Promise(resolve => { + const {dispose} = popup(MkDialog, { + ...({ + type: 'warning', + title: i18n.ts.disconnectedFromServer, + text: i18n.ts.reloadConfirm, + }), + showCancelButton: true, + }, { + done: result => { + resolve(result ? result : {canceled: true}); + }, + closed: () => dispose(), + }); }); reloadDialogShowing = false; if (!canceled) { From 88c8478f8cab4771ebe8ae1b09015cd2f2376358 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 14:28:00 +0100 Subject: [PATCH 09/15] Inlined the confirm. --- packages/frontend/src/boot/main-boot.ts | 68 ++++++++++++------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 7c34506b76..0c39f1112b 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -3,27 +3,28 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { createApp, defineAsyncComponent, markRaw } from 'vue'; -import { common } from './common.js'; +import {createApp, defineAsyncComponent, markRaw} from 'vue'; +import {common} from './common.js'; import type * as Misskey from 'misskey-js'; -import { ui } from '@@/js/config.js'; -import { i18n } from '@/i18n.js'; -import { alert, confirm, popup, post, toast } from '@/os.js'; -import { useStream } from '@/stream.js'; +import {ui} from '@@/js/config.js'; +import {i18n} from '@/i18n.js'; +import {alert, popup, post} from '@/os.js'; +import {useStream} from '@/stream.js'; import * as sound from '@/scripts/sound.js'; -import { $i, signout, updateAccount } from '@/account.js'; -import { instance } from '@/instance.js'; -import { ColdDeviceStorage, defaultStore } from '@/store.js'; -import { reactionPicker } from '@/scripts/reaction-picker.js'; -import { miLocalStorage } from '@/local-storage.js'; -import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js'; -import { initializeSw } from '@/scripts/initialize-sw.js'; -import { deckStore } from '@/ui/deck/deck-store.js'; -import { emojiPicker } from '@/scripts/emoji-picker.js'; -import { mainRouter } from '@/router/main.js'; -import { setFavIconDot } from '@/scripts/favicon-dot.js'; -import { type Keymap, makeHotkey } from '@/scripts/hotkey.js'; -import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js'; +import {$i, signout, updateAccount} from '@/account.js'; +import {instance} from '@/instance.js'; +import {ColdDeviceStorage, defaultStore} from '@/store.js'; +import {reactionPicker} from '@/scripts/reaction-picker.js'; +import {miLocalStorage} from '@/local-storage.js'; +import {claimAchievement, claimedAchievements} from '@/scripts/achievements.js'; +import {initializeSw} from '@/scripts/initialize-sw.js'; +import {deckStore} from '@/ui/deck/deck-store.js'; +import {emojiPicker} from '@/scripts/emoji-picker.js'; +import {mainRouter} from '@/router/main.js'; +import {setFavIconDot} from '@/scripts/favicon-dot.js'; +import {type Keymap, makeHotkey} from '@/scripts/hotkey.js'; +import {addCustomEmoji, removeCustomEmojis, updateCustomEmojis} from '@/custom-emojis.js'; +import MkDialog from "@/components/MkDialog.vue"; export async function mainBoot() { const { isClientUpdated } = await common(() => createApp( @@ -50,25 +51,20 @@ export async function mainBoot() { if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { if (reloadDialogShowing) return; reloadDialogShowing = true; - const { canceled } = await new Promise(resolve => { - const {dispose} = popup(MkDialog, { - ...({ - type: 'warning', - title: i18n.ts.disconnectedFromServer, - text: i18n.ts.reloadConfirm, - }), - showCancelButton: true, - }, { - done: result => { - resolve(result ? result : {canceled: true}); - }, - closed: () => dispose(), - }); + const {dispose} = popup(MkDialog, { + ...({ + type: 'warning', + title: i18n.ts.disconnectedFromServer, + text: i18n.ts.reloadConfirm, + }), + showCancelButton: true, + }, { + done: result => { + if (!result) location.reload(); + }, + closed: () => dispose(), }); reloadDialogShowing = false; - if (!canceled) { - location.reload(); - } } }); From 7ad73fedfbc8800b38c7ab94d442aaccd550f4b1 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 7 Dec 2024 15:33:43 +0100 Subject: [PATCH 10/15] Added code to dismiss the reload dialogue on reconnect. --- packages/frontend/src/boot/main-boot.ts | 33 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 0c39f1112b..3dd1ca1e8b 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -8,7 +8,7 @@ import {common} from './common.js'; import type * as Misskey from 'misskey-js'; import {ui} from '@@/js/config.js'; import {i18n} from '@/i18n.js'; -import {alert, popup, post} from '@/os.js'; +import {alert, popup, post, toast} from '@/os.js'; import {useStream} from '@/stream.js'; import * as sound from '@/scripts/sound.js'; import {$i, signout, updateAccount} from '@/account.js'; @@ -27,6 +27,7 @@ import {addCustomEmoji, removeCustomEmojis, updateCustomEmojis} from '@/custom-e import MkDialog from "@/components/MkDialog.vue"; export async function mainBoot() { + const { isClientUpdated } = await common(() => createApp( new URLSearchParams(window.location.search).has('zen') || (ui === 'deck' && deckStore.state.useSimpleUiForNonRootPages && location.pathname !== '/') ? defineAsyncComponent(() => import('@/ui/zen.vue')) : !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : @@ -46,25 +47,45 @@ export async function mainBoot() { const stream = useStream(); - let reloadDialogShowing = false; + // A reference to the function to close the "reconnecting" dialog; null if the dialog is not open. + let reloadDialogDisposeFn : Function | null = null; + + // When the stream is disconnected, show a dialog to reload the page. stream.on('_disconnected_', async () => { + // TODO: Where's that setting? if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { - if (reloadDialogShowing) return; - reloadDialogShowing = true; + + // If the dialog is already open, do nothing. + if (reloadDialogDisposeFn) return; + + // Show a popup dialog with a warning message and a "reload" button. const {dispose} = popup(MkDialog, { ...({ type: 'warning', title: i18n.ts.disconnectedFromServer, text: i18n.ts.reloadConfirm, }), - showCancelButton: true, + showCancelButton: true, // Show a "cancel" button; this dismisses the dialog without reloading the page. }, { + // If the user clicks one of the buttons, and it's the "positive" button (in this case, the "reload" button), done: result => { if (!result) location.reload(); }, + // If the dialog is closed, dispose of the dialog. closed: () => dispose(), }); - reloadDialogShowing = false; + + // Save the function to close the dialog so that it can be called later. + reloadDialogDisposeFn = dispose; + } + }); + + // When the stream is (re)connected, close the "reconnecting" dialog if it's open. + stream.on('_connected_', () => { + if (reloadDialogDisposeFn) { + reloadDialogDisposeFn(); + reloadDialogDisposeFn = null; + toast("Reconnected to server."); } }); From 077fb751b522effe8b80958e4ab5d391cc4e164a Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sun, 8 Dec 2024 12:50:29 +0100 Subject: [PATCH 11/15] Added heartbeat response in Connection.ts --- packages/backend/src/server/api/stream/Connection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index f102cb42e1..b43a0401ff 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -161,6 +161,7 @@ export default class Connection { case 'disconnect': this.onChannelDisconnectRequested(body); break; case 'channel': this.onChannelMessageRequested(body); break; case 'ch': this.onChannelMessageRequested(body); break; // alias + case 'h': this.wsConnection.send('h'); break; // heartbeat response } } From d0cb08c2df352283a0bb0004a7b483c3d67c1f66 Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sun, 8 Dec 2024 17:46:49 +0100 Subject: [PATCH 12/15] Fixed heatbeat message not being valid json; now includes unix time too. --- packages/misskey-js/src/streaming.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts index ffb46c77f6..6ece43d7c3 100644 --- a/packages/misskey-js/src/streaming.ts +++ b/packages/misskey-js/src/streaming.ts @@ -211,7 +211,8 @@ export default class Stream extends EventEmitter implements IStrea } public heartbeat(): void { - this.stream.send('h'); + // Send a heartbeat message, with the current time so the server can echo it. + this.send('hb', { time: Date.now() }); } /** From 2ead42c00b05958ada532b745ad2f9181d9f9b6c Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sun, 8 Dec 2024 17:50:34 +0100 Subject: [PATCH 13/15] Added heartbeat handler. --- packages/backend/src/server/api/stream/Connection.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index b43a0401ff..07b92a7342 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -161,10 +161,19 @@ export default class Connection { case 'disconnect': this.onChannelDisconnectRequested(body); break; case 'channel': this.onChannelMessageRequested(body); break; case 'ch': this.onChannelMessageRequested(body); break; // alias - case 'h': this.wsConnection.send('h'); break; // heartbeat response + case 'hb': this.onHeartbeat(body); break; } } + @bindThis + private onHeartbeat(data: JsonValue | undefined) { + if (!isJsonObject(data)) { + console.error('Received invalid heartbeat payload: ', data); + return; + } + this.sendMessageToWs('hb', data); + } + @bindThis private onBroadcastMessage(data: GlobalEvents['broadcast']['payload']) { this.sendMessageToWs(data.type, data.body); From aecf8964942e945305dbc86e1fec70e204f890fe Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sun, 8 Dec 2024 17:52:36 +0100 Subject: [PATCH 14/15] Added last-message-time-tracking --- packages/misskey-js/src/streaming.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts index 6ece43d7c3..65706312a6 100644 --- a/packages/misskey-js/src/streaming.ts +++ b/packages/misskey-js/src/streaming.ts @@ -50,6 +50,8 @@ export default class Stream extends EventEmitter implements IStrea private nonSharedConnections: NonSharedConnection[] = []; private idCounter = 0; + /// A timestamp of the last-received message. + private lastMessageTime = Date.now(); constructor(origin: string, user: { token: string; } | null, options?: { WebSocket?: WebSocket; }) { @@ -136,6 +138,9 @@ export default class Stream extends EventEmitter implements IStrea * Callback of when open connection */ private onOpen(): void { + + this.lastMessageTime = Date.now(); + const isReconnect = this.state === 'reconnecting'; this.state = 'connected'; @@ -162,6 +167,9 @@ export default class Stream extends EventEmitter implements IStrea * Callback of when received a message from connection */ private onMessage(message: { data: string; }): void { + + this.lastMessageTime = Date.now(); + const { type, body } = JSON.parse(message.data); if (type === 'channel') { From ae8a76cef5432fefe5ef575c88d975a3333003ad Mon Sep 17 00:00:00 2001 From: Werner Kroneman Date: Sat, 10 May 2025 15:14:30 +0300 Subject: [PATCH 15/15] Updated pnpm hash --- sharkey.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sharkey.nix b/sharkey.nix index aca87ca223..6f8280c442 100644 --- a/sharkey.nix +++ b/sharkey.nix @@ -36,7 +36,7 @@ stdenv.mkDerivation (finalAttrs: { # https://nixos.org/manual/nixpkgs/unstable/#javascript-pnpm pnpmDeps = pnpm.fetchDeps { inherit (finalAttrs) pname version src; - hash = "sha256-PpXmNBO4pWj8AG0we4DpPhzfx/18rwDZHi86+esFghM="; + hash = "sha256-ymHPzoU5/0RL1Z0v5MVDunFCsFU1c6uzKK5wusabZ+E="; }; buildPhase = ''