diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 00000000..27dc5ae9 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,27 @@ +name: Build (Nix) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: nix flake check + build-node: + needs: check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + steps: + - uses: actions/checkout@v3 + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: nix build .# diff --git a/flake.nix b/flake.nix index 54015fd5..f17fe62c 100644 --- a/flake.nix +++ b/flake.nix @@ -31,21 +31,7 @@ config.allowUnfree = true; }; - inherit (pkgs) mkShell rust-bin writeShellApplication; - - rust = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - - scripts.muchat-watch = writeShellApplication { - name = "muchat-watch"; - runtimeInputs = with pkgs; [ - cargo-nextest - cargo-watch - rust - ]; - text = '' - exec cargo watch -s 'cargo fmt && cargo clippy --all && cargo nextest run' - ''; - }; + muchat = import ./lib.nix pkgs; checks.pre-commit-check = pre-commit-hooks.lib.${system}.run { src = ./.; @@ -56,48 +42,41 @@ rustfmt = { enable = true; - packageOverrides.cargo = rust; + packageOverrides.cargo = muchat.packages.rust; }; - prettier.enable = true; + prettier = { + enable = true; + + excludes = [ "pnpm-lock.yaml" ]; + }; }; }; - packages.simplex-chat = pkgs.callPackage ./nix/simplex-chat.nix { }; in { - inherit checks packages; - - devShells.default = mkShell { - inherit (checks.pre-commit-check) shellHook; - - name = "muchat"; - - buildInputs = with pkgs; [ - (attrValues scripts) - (attrValues packages) - - rust - - cargo-edit - cargo-tauri - cargo-watch - nodePackages.pnpm - nodejs - openssl - pkg-config - - webkitgtk - gtk3 - cairo - gdk-pixbuf - glib - dbus - openssl - librsvg - webkitgtk_4_1 - ]; - }; + inherit checks; + inherit (muchat) packages; + + devShells.default = + with pkgs; + mkShell { + inherit (checks.pre-commit-check) shellHook; + + name = "muchat-shell"; + inputsFrom = attrValues muchat.packages; + + buildInputs = with pkgs; [ + muchat.packages.simplex-chat + muchat.packages.rust + + cargo-edit + cargo-tauri + cargo-watch + nodePackages.pnpm + nodejs + ]; + }; } ); } diff --git a/lib.nix b/lib.nix new file mode 100644 index 00000000..5969fc6f --- /dev/null +++ b/lib.nix @@ -0,0 +1,53 @@ +{ + callPackage, + makeRustPlatform, + makeWrapper, + rust-bin, + stdenv, + ... +}: +let + inherit (builtins) readFile; + + lib = { + src = ./.; + + rustPlatform = makeRustPlatform { + rustc = rust; + cargo = rust; + }; + + baseName = name: baseNameOf (toString name); + loadTOML = path: fromTOML (readFile path); + }; + + rust = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + + packages = { + inherit rust; + + default = stdenv.mkDerivation { + name = "muchat"; + + nativeBuildInputs = [ makeWrapper ]; + + dontBuild = true; + dontUnpack = true; + + installPhase = with packages; '' + mkdir -p $out/{share/muchat/bin,bin} + + install -m 0755 ${ui}/bin/muchat-ui $out/bin/.muchat-unwrapped + makeWrapper $out/bin/.muchat-unwrapped $out/bin/muchat \ + --prefix PATH : ${simplex-chat}/bin + ''; + }; + + frontend = callPackage ./ui { muchat = { inherit lib; }; }; + simplex-chat = callPackage ./nix/simplex-chat.nix { }; + ui = callPackage ./ui/src-tauri { muchat = { inherit lib packages; }; }; + }; +in +{ + inherit lib packages; +} diff --git a/providers/src/chat/client.rs b/providers/src/chat/client.rs index 51ca5793..8b45ce9d 100644 --- a/providers/src/chat/client.rs +++ b/providers/src/chat/client.rs @@ -1,27 +1,27 @@ use std::{ sync::{ - atomic::{AtomicU16, Ordering}, Arc, + atomic::{AtomicU16, Ordering}, }, time::Duration, }; use async_stream::try_stream; use futures::{ - stream::{SplitSink, SplitStream}, Future, SinkExt, Stream, StreamExt, + stream::{SplitSink, SplitStream}, }; use tokio::{ net::TcpStream, sync::{ - mpsc::{self, Receiver, Sender}, Mutex, + mpsc::{self, Receiver, Sender}, }, }; -use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream}; +use tokio_tungstenite::{MaybeTlsStream, WebSocketStream, connect_async, tungstenite::Message}; use super::{ commands::{CommandData, CommandPayload, ComposedMessage}, diff --git a/providers/src/chat/mod.rs b/providers/src/chat/mod.rs index 323a92f3..259967a3 100644 --- a/providers/src/chat/mod.rs +++ b/providers/src/chat/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use client::{ChatClient, StreamMessage}; use commands::ChatCommand; use error::TransportError; -use futures::{pin_mut, Stream, StreamExt}; +use futures::{Stream, StreamExt, pin_mut}; use response::{ChatInfo, ChatInfoType, ChatResponse, DirectionType}; use tokio::{ self, diff --git a/rustfmt.toml b/rustfmt.toml index 819554b6..2b211b0d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,5 @@ +edition = "2024" + reorder_imports = true imports_granularity = "Crate" imports_layout = "HorizontalVertical" diff --git a/ui/default.nix b/ui/default.nix new file mode 100644 index 00000000..10677663 --- /dev/null +++ b/ui/default.nix @@ -0,0 +1,42 @@ +{ + nodejs, + pnpm, + stdenv, + muchat, +}: +let + inherit (builtins) filterSource fromJSON readFile; + inherit (muchat.lib) baseName; + inherit (stdenv) mkDerivation; + + package-json = fromJSON (readFile ./package.json); +in +mkDerivation (final: { + inherit (package-json) version; + pname = package-json.name; + + src = filterSource (name: _: !(baseName name == "src-tauri")) ./.; + + nativeBuildInputs = [ + nodejs + pnpm.configHook + ]; + + buildPhase = '' + runHook preBuild + + pnpm build + + runHook postBuild + ''; + + installPhase = '' + mkdir -p $out + cp -r dist/* $out/ + ''; + + pnpmDeps = pnpm.fetchDeps { + inherit (final) pname version src; + hash = "sha256-YIy2dICdyQj+v0lqOZGS95oPKdGmNHUSY4e4WzK/xSw="; + }; +}) diff --git a/ui/package.json b/ui/package.json index 38cdb4dd..a7550b2f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,5 +1,5 @@ { - "name": "muchat-ui", + "name": "muchat-ui-frontend", "private": true, "version": "0.0.0", "type": "module", diff --git a/ui/src-tauri/Cargo.toml b/ui/src-tauri/Cargo.toml index 519913a8..1667db6e 100644 --- a/ui/src-tauri/Cargo.toml +++ b/ui/src-tauri/Cargo.toml @@ -15,11 +15,11 @@ tauri-build = { version = "2.0.3", features = [] } [dependencies] log = "0.4.22" -serde = { workspace = true } -serde_json = { workspace = true } +serde = { version = "1.0.216", features = ["derive"] } +serde_json = "1.0.133" tauri = "2.1.1" tauri-plugin-fs = "2.2.0" tauri-plugin-log = "2.2.0" tauri-plugin-shell = "2.2.0" tauri-plugin-websocket = "2.2.0" -tokio = { workspace = true } +tokio = { version = "1.42.0", features = ["full"] } diff --git a/ui/src-tauri/default.nix b/ui/src-tauri/default.nix new file mode 100644 index 00000000..f06299f4 --- /dev/null +++ b/ui/src-tauri/default.nix @@ -0,0 +1,79 @@ +{ + cairo, + dbus, + gdk-pixbuf, + glib, + gnused, + gtk3, + lib, + librsvg, + muchat, + openssl, + pkg-config, + pnpm, + stdenv, + webkitgtk, + webkitgtk_4_1, +}: +let + inherit (lib) optionals splitString; + inherit (muchat.lib) loadTOML rustPlatform src; + inherit (stdenv) isDarwin isLinux; + + cargoTOML = loadTOML ./Cargo.toml; + + toPatch = + with builtins; + path: target: + let + content = readFile path; + lines = splitString "\n" content; + additions = map (line: "+" + line) lines; + diffBody = concatStringsSep "\n" additions; + lineCount = length lines; + in + toFile "${target}.patch" '' + diff --git a/${target} b/${target} + new file mode 100644 + index 0000000..e69de29 + --- /dev/null + +++ b/${target} + @@ -0,0 +1,${toString lineCount} @@ + ${diffBody} + ''; + +in +rustPlatform.buildRustPackage { + inherit (cargoTOML.package) name version; + + src = "${src}/ui/src-tauri"; + cargoLock.lockFile = "${src}/Cargo.lock"; + + buildInputs = + [ ] + ++ optionals isLinux [ + openssl + webkitgtk + gtk3 + cairo + gdk-pixbuf + glib + dbus + librsvg + webkitgtk_4_1 + ] + ++ optionals isDarwin [ ]; + + nativeBuildInputs = [ + gnused + pkg-config + ]; + + useNextest = true; + + patches = [ (toPatch "${src}/Cargo.lock" "Cargo.lock") ]; + + patchPhase = '' + sed -i -e "s;../dist;${muchat.packages.frontend};g" tauri.conf.json + ''; +} diff --git a/ui/src/components/features/chat/Chat.tsx b/ui/src/components/features/chat/Chat.tsx index 16ffe90a..7ef559a9 100644 --- a/ui/src/components/features/chat/Chat.tsx +++ b/ui/src/components/features/chat/Chat.tsx @@ -49,7 +49,7 @@ const Chat = () => {