[`actionlint`](https://github.com/rhysd/actionlint) is a static analysis
tool for GitHub workflows and actions. It detects various issues ahead
of time and runs shellcheck on all `run` blocks. It is worth noting that
this does **not** lint the contents of composite actions so we still
need to be vigilant when working with those.
To make our FFI layer between Android and Rust safer, we adopt the
UniFFI tool from Mozilla. UniFFI allows us to create a dedicated crate
(here `client-ffi`) that contains Rust structs annotated with various
attributes. These macros then generate code at compile time that is
built into the shared object. Using a dedicated CLI from the UniFFI
project, we can then generate Kotlin bindings from this shared object.
The primary motivation for this effort is memory safety across the FFI
boundary. Most importantly, we want to ensure that:
- The session pointer is not used after it has been free'd
- Disconnecting the session frees the pointer
- Freeing the session does not happen as part of a callback as that
triggers a cyclic dependency on the Rust side (callbacks are executed on
a runtime and that runtime is dropped as part of dropping the session)
To achieve all of these goals, we move away from callbacks altogether.
UniFFI has great support for async functions. We leverage this support
to expose a `suspend fn` to Android that returns `Event`s. These events
map to the current callback functions. Internally, these events are read
from a channel with a capacity of 1000 events. It is therefore not very
time-critical that the app reads from this channel. `connlib` will
happily continue even if the channel is full. 1000 events should be more
than sufficient though in case the host app cannot immediately process
them. We don't send events very often after all.
This event-based design has major advantages: It allows us to make use
of `AutoCloseable` on the Kotlin side, meaning the `session` pointer is
only ever accessed as part of a `use` block and automatically closed
(and therefore free'd) at the end of the block.
To communicate with the session, we introduce a `TunnelCommand` which
represents all actions that the host app can send to `connlib`. These
are passed through a channel to the `suspend fn` which continuously
listens for events and commands.
Resolves: #9499
Related: #3959
---------
Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
The latest release now also sorts workspace dependencies, as well as
different dependency sections. Keeping these things sorted reduces the
chances of merge conflicts when multiple PRs edit these files.
In order to get more recent tools like `cargo deny` that support Rust
2024, we need to bump the nixpkgs release we depend on to 24.11. As part
of doing so, we simplify the flake to not depend on `flake-utils` as we
only build for a single system anyway.
Using `rustup` - even on NixOS - is easier to manage the Rust toolchain
as some tools rely on being able to use the `rustup` shims such as
`+nightly` to run a nightly toolchain.
Rust 1.83 comes with a bunch of new lints for elidible lifetimes. Those
also trigger in the generated code of `derivative`. That crate is
actually unmaintained so we replace our usages of it with `derive_more`.
One of Rust's promises is "if it compiles, it works". However, there are
certain situations in which this isn't true. In particular, when using
dynamic typing patterns where trait objects are downcast to concrete
types, having two versions of the same dependency can silently break
things.
This happened in #7379 where I forgot to patch a certain Sentry
dependency. A similar problem exists with our `tracing-stackdriver`
dependency (see #7241).
Lastly, duplicate dependencies increase the compile-times of a project,
so we should aim for having as few duplicate versions of a particular
dependency as possible in our dependency graph.
This PR introduces `cargo deny`, a linter for Rust dependencies. In
addition to linting for duplicate dependencies, it also enforces that
all dependencies are compatible with an allow-list of licenses and it
warns when a dependency is referred to from multiple crates without
introducing a workspace dependency. Thanks to existing tooling
(https://github.com/mainmatter/cargo-autoinherit), transitioning all
dependencies to workspace dependencies was quite easy.
Resolves: #7241.
Instead of forcing NIx users of the respository (me) to install RA
globally, we can install the equivalent version of whatever Rust version
we depend on.
In order for `rust-analyzer` to show the correct version of the Rust
standard library, we need to install `rust-src` together with the
toolchain version that we use in the Nix dev-shell.
To build for musl, the target needs to be installed. Within the Nix
dev-shell, we don't manage versions / components via rustup, thus they
need to be added manually.
This messes with the build cache because the locally run rust-analyzer
doesn't recognise those variables and thus keeps poisoning the cache. If
other Nix users want `mold`, they should set it up in their user
configuration.
I tried to run the GUI client on my system but I think my glibc version
is too recent (2.38) and thus, it crashes after clicking on "Login".
These changes to the Nix script are necessary to at least build the
client.
Unfortunately I had to keep `linux-client` to get the compatibility
tests to pass. #4578 aims to remove that package.
Please add to this list if you think of anything:
```[tasklist]
# Things that may break that CI/CD won't catch
- [ ] Github release artifacts
- [ ] Knowledge base
- [ ] Docker images
- [ ] Docker containers
- [ ] Existing `linux-client` users
- [ ] Anything that downloads ghcr artifacts
- [ ] Nix (Not sure if it's built in CI. It had a merge conflict)
```
Refs #4515, and #3712, #3782
I think this is what Thomas and I agreed on in Slack / Github
---------
Signed-off-by: Reactor Scram <ReactorScram@users.noreply.github.com>
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
Previously, we had a dedicated timer for this within the tunnel
implementation. Now that we have control over the internals of our
connection via `snownet`, we can timeout the connection if we don't
receive a candidate from the remote within 10s.
Some recent changes to the Rust part of the codebase made it quite
difficult to locally build the project due to tauri's heavy dependencies
on WebKitGTK and other native libraries.
I tried working around this on my local (nix) machine and found it quite
difficult. The cleanest way here is to make use of what Nix calls
"devshells" which give you an environment specifically for hacking on
your project.
Unfortunately, these files need to be tracked in version control and
cannot be ignored (at least I've not found a way to do that). Given that
we already have a lot of clutter in our repository, I put them under
`scripts/nix`.
They are generally useful. I also added a `.envrc` file which
automatically launches the dev-shell. As a result, you have a shell
ready to go with all your dependencies as soon as you `cd` into our
repository (assuming you use `direnv` and it is hooked up with your
shell).
I didn't really want to have any of my local setup leak into the repo
because I think apart from me and @conectado, nobody is using nix, thus
I hope this minimal footprint is an okay compromise.