Compare commits

..

No commits in common. "flake-stuff" and "develop" have entirely different histories.

7 changed files with 63 additions and 186 deletions

View file

@ -3,10 +3,36 @@
outputs = { self, nixpkgs }: {
nixosModules.sharkey-service = args : import ./sharkey-service.nix ( args // { sharkey = self.packages."x86_64-linux".sharkey; pkgs = nixpkgs.legacyPackages."x86_64-linux"; } );
nixosConfigurations.container = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules =
[
( import ./sharkey-service.nix )
({ pkgs, ... }: {
boot.isContainer = true;
packages."x86_64-linux".sharkey = nixpkgs.legacyPackages."x86_64-linux".callPackage ./sharkey.nix { };
# 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".default = self.packages."x86_64-linux".sharkey;
};
}

View file

@ -161,19 +161,9 @@ export default class Connection {
case 'disconnect': this.onChannelDisconnectRequested(body); break;
case 'channel': this.onChannelMessageRequested(body); break;
case 'ch': this.onChannelMessageRequested(body); break; // alias
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);

View file

@ -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, toast} from '@/os.js';
import { alert, confirm, 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';
@ -24,10 +24,8 @@ 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(
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')) :
@ -47,45 +45,20 @@ export async function mainBoot() {
const stream = useStream();
// 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.
let reloadDialogShowing = false;
stream.on('_disconnected_', async () => {
// TODO: Where's that setting?
if (defaultStore.state.serverDisconnectedBehavior === 'dialog') {
// 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, {
...({
if (reloadDialogShowing) return;
reloadDialogShowing = true;
const { canceled } = await confirm({
type: 'warning',
title: i18n.ts.disconnectedFromServer,
text: i18n.ts.reloadConfirm,
}),
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(),
});
// Save the function to close the dialog so that it can be called later.
reloadDialogDisposeFn = dispose;
reloadDialogShowing = false;
if (!canceled) {
location.reload();
}
});
// 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.");
}
});

View file

@ -50,8 +50,6 @@ export default class Stream extends EventEmitter<StreamEvents> 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;
}) {
@ -138,9 +136,6 @@ export default class Stream extends EventEmitter<StreamEvents> implements IStrea
* Callback of when open connection
*/
private onOpen(): void {
this.lastMessageTime = Date.now();
const isReconnect = this.state === 'reconnecting';
this.state = 'connected';
@ -167,9 +162,6 @@ export default class Stream extends EventEmitter<StreamEvents> 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') {
@ -219,8 +211,7 @@ export default class Stream extends EventEmitter<StreamEvents> implements IStrea
}
public heartbeat(): void {
// Send a heartbeat message, with the current time so the server can echo it.
this.send('hb', { time: Date.now() });
this.stream.send('h');
}
/**

View file

@ -1,100 +0,0 @@
# Set up a postgresql database and a redis server for the integration tests.
# 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
# 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
}
# 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
if [[ $? == 1 ]] ; then
echo $port
else
random_unused_port
fi
}
# 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"
}
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

View file

@ -2,7 +2,6 @@
config,
pkgs,
lib,
sharkey,
...
}:
@ -187,11 +186,9 @@ in
{
options = {
services.sharkey = {
enable = lib.mkEnableOption "sharkey";
package = lib.mkPackageOption pkgs "sharkey" { };
inherit settings;
database = {
createLocally = lib.mkOption {
@ -343,7 +340,7 @@ in
${pkgs.replace-secret}/bin/replace-secret '@MEILISEARCH_KEY@' "${cfg.meilisearch.keyFile}" /run/sharkey/default.yml
'');
serviceConfig = {
ExecStart = "${sharkey}/bin/sharkey migrateandstart";
ExecStart = "${cfg.package}/bin/sharkey migrateandstart";
RuntimeDirectory = "sharkey";
RuntimeDirectoryMode = "700";
StateDirectory = "sharkey";

View file

@ -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-ymHPzoU5/0RL1Z0v5MVDunFCsFU1c6uzKK5wusabZ+E=";
hash = "sha256-PpXmNBO4pWj8AG0we4DpPhzfx/18rwDZHi86+esFghM=";
};
buildPhase = ''