Merge branch 'main' into add-release-channel-information-to-telemetry-events

This commit is contained in:
Joseph T Lyons 2022-10-27 15:57:17 -04:00
commit 36c64045ae
16 changed files with 42 additions and 220 deletions

View File

@ -102,15 +102,9 @@ impl AmplitudeTelemetry {
.unwrap()
.as_millis(),
state: Mutex::new(AmplitudeTelemetryState {
os_version: platform
.os_version()
.log_err()
.map(|v| v.to_string().into()),
os_version: platform.os_version().ok().map(|v| v.to_string().into()),
os_name: platform.os_name().into(),
app_version: platform
.app_version()
.log_err()
.map(|v| v.to_string().into()),
app_version: platform.app_version().ok().map(|v| v.to_string().into()),
release_channel,
device_id: None,
queue: Default::default(),

View File

@ -108,16 +108,9 @@ impl Telemetry {
http_client: client,
executor: cx.background().clone(),
state: Mutex::new(TelemetryState {
os_version: platform
.os_version()
.log_err()
.map(|v| v.to_string().into()),
os_version: platform.os_version().ok().map(|v| v.to_string().into()),
os_name: platform.os_name().into(),
app_version: platform
.app_version()
.log_err()
.map(|v| v.to_string().into()),
release_channel,
app_version: platform.app_version().ok().map(|v| v.to_string().into()),
device_id: None,
metrics_id: None,
queue: Default::default(),

View File

@ -71,7 +71,6 @@ impl BlinkManager {
if epoch == self.blink_epoch && self.enabled && !self.blinking_paused {
self.visible = !self.visible;
cx.notify();
dbg!(cx.handle());
let epoch = self.next_blink_epoch();
let interval = self.blink_interval;

View File

@ -1353,6 +1353,7 @@ impl Editor {
) {
self.scroll_top_anchor = anchor;
self.scroll_position = position;
self.make_scrollbar_visible(cx);
cx.emit(Event::ScrollPositionChanged { local: false });
cx.notify();
}

View File

@ -1,106 +0,0 @@
# Collaboration in Zed
## Login
Zed needs to know the identities of the people who are collaborating on a worktree. So the first time that you share a worktree (or try to join someone else's worktree), Zed will prompt you to log in to `zed.dev`.
### Message Flow
Zed relies on a web browser to handle login. This lets you take advantage of the GitHub cookies stored in your browser. It's also recommended by the IETF (see the [Oauth 2 For Native Apps RFC](https://www.rfc-editor.org/rfc/rfc8252.txt)).
This diagram shows what happens when you log in:
![login sequence diagram](./diagrams/svg/login-flow.svg)
## Sharing
Once you're logged in you can share your worktrees. We'll start by providing a *Share* application menu item to share the (first?) worktree in a given window. Clicking this will copy a URL to your clipboard. You can give this URL to other people to let them collaborate on the worktree.
### Semantics
While sharing, the entire state of your worktree is replicated and stored forever on the Zed server. Other collaborators can freely read the last state of your worktree, even after you've quit Zed.
__Potential Scope Cut__ - For now, we won't store the history locally, as this isn't needed for collaboration. Later, we may explore keeping a partial history locally as well, to support using the history while offline. A local history would allow:
* Undo after re-opening a buffer.
* Avoiding redundant uploads when re-opening a buffer while sharing.
When you begin sharing:
* You may or may not have shared a given worktree before. If you *have* shared it before, Zed will have saved a `worktree_id` for this worktree in `~/Library/Application\ Support/Zed/worktrees.toml` (or something like that). If you haven't shared the worktree before, then you need to ask the Zed server for new `worktree_id` to associate with this directory.
* Immediately, you upload a list of all the paths in your worktree, along a digest of each path. The server responds with a list of paths that needs
* First, you upload the contents of all of your open buffers.
* At this point, sharing has begun - you are shown a URL (or it is copied to your clipboard).
* Asynchronously, you upload the contents of all other files in your worktree that the server needs.
While you're sharing:
* Buffer operations are streamed to the Zed server.
* When FS changes are detected to files that you *don't* have open:
* You again upload to the server a list of the paths that changed and their new digests.
* The server responds with a list of paths that it needs
* Asynchronously, you upload the new contents of these paths.
* If a peer requests to open one of your files that you haven't yet asynchronously uploaded, then the server tells you to upload the contents of that file immediately.
When you stop sharing:
* You immediately stop uploading anything to the Zed server.
This diagram shows the messages that would be sent in the case of a *new* worktree.
![share-worktree sequence diagram](./diagrams/svg/share-worktree.svg)
### RPC implementation details
The API will consist of resources named with URL-like paths, for example: `/worktrees/1`. You'll be able to communicate with any resource in the following ways:
* `send`: A "fire-and-forget" message with no reply. (We may not need this)
* `request`: A message that expects a reply message that is tagged with the same sequence number as the request.
* `request_stream`: A message that expects a series of reply messages that are tagged with the same sequence number as the request. Unsure if this is needed beyond `subscribe`.
* `subscribe`: Returns a stream that allows the resource to emit messages at any time in the future. When the stream is dropped, we unsubscribe automatically.
Any resource you can subscribe to is considered a *channel*, and all of its processing needs to occur on a single machine. We'll recognize channels based on their URL pattern and handle them specially in our frontend servers. For any channel, the frontend will perform a lookup for the machine on which that channel exists. If no machine exists, we'll select one. Maybe it's always the frontend itself?. If a channel already exists on another server, we'll proxy the connection through the frontend and relay and broadcasts from this channel to the client.
The client will interact with the server via a `api::Client` object. Model objects with remote behavior will interact directly with this client to communicate with the server. For example, `Worktree` will be changed to an enum type with `Local` and `Remote` variants. The local variant will have an optional `client` in order to stream local changes to the server when sharing. The remote variant will always have a client and implement all worktree operations in terms of it.
```rs
let mut client = Client::new(conn, cx.background_executor());
let stream = client.subscribe(from_client::Variant::Auth(from_client::));
client.close();
```
```rs
enum Worktree {
Local {
remote: Option<Client>,
}
Remote {
remote: Client,
}
}
impl Worktree {
async fn remote(client, id, cx) -> anyhow::Result<Self> {
// Subscribe to the stream of all worktree events going forward
let events = client.subscribe::<WorktreeEvent>(format!("/worktrees/{}", worktree_id)).await?;
// Stream the entries of the worktree
let entry_chunks = client.request_stream()
// In the background, populate all worktree entries in the initial stream and process any change events.
// This is similar to what we do
let _handle = thread::spawn(smol::block_on(async move {
for chunk in entry_chunks {
// Grab the lock and fill in the new entries
}
while let Some() = events.recv_next() {
// Update the tree
}
}))
// The _handle depicted here won't actually work, but we need to terminate the thread and drop the subscription
// when the Worktree is dropped... maybe we use a similar approach to how we handle local worktrees.
Self::Remote {
_handle,
client,
}
}
}
```

View File

@ -1,5 +0,0 @@
# Diagrams
The SVG sequence diagrams in the `svg` folder are generated from the UML text files in the `src` folder. To regenerate them, run `script/generate-doc-diagrams`.
Documentation for the UML sequence diagram format is located on [the PlantUML website](https://plantuml.com/sequence-diagram).

View File

@ -1,17 +0,0 @@
@startuml
participant "Zed App" as app
participant "Browser" as browser
participant "Zed HTTP server" as server
rnote over app: Generate encryption keypair.\nListen on an open TCP port.
app -> browser: Open sign-in page\n(public key, TCP port)
browser -> server: Sign in\n(app's public key, app's TCP port)
rnote over server: Generate access token.\nEncrypt it with app's public key.
server -> browser: Redirect to loopback with app's port\n(user id, encrypted access token)
browser -> app: Follow redirect\n(user id, encrypted access token)
rnote over app: Decrypt access token with private key.\nSave credentials to keychain.
@enduml

View File

@ -1,19 +0,0 @@
@startuml
participant "Zed App" as app
participant "Zed HTTP server" as server
participant "Zed RPC server" as rpc_server
app -> server: POST worktrees\n(user id, access token)
server -> app: OK\n(worktree id, RPC server address)
app -> rpc_server: Connect to the given RPC server address
app -> rpc_server: **Auth**\n(user id, access token)
rnote over rpc_server: Load access token hashes for user.\nVerify that one matches the given access token.
rpc_server -> app: **AuthResponse**\n(credentials valid)
app -> rpc_server: **ShareWorktree**\n(worktree_id, file paths, file digests)
rnote over rpc_server: Load existing files.\nIdentify which are needed.
rpc_server -> app: **ShareWorktreeResponse**\n(needed path indices)
@enduml

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,18 +0,0 @@
#!/bin/bash
channel=$(cat crates/zed/RELEASE_CHANNEL)
tag_suffix=""
case $channel; in
stable)
;;
preview)
tag_suffix="-pre"
;;
*)
echo "do this on a release branch where RELEASE_CHANNEL is either 'preview' or 'stable'" >&2
exit 1
;;
esac
exec script/lib/bump-version.sh zed v $tag_suffix $@

View File

@ -1,3 +1,8 @@
#!/bin/bash
exec script/lib/bump-version.sh collab collab-v '' $@
if [[ $# < 1 ]]; then
echo "Missing version increment (major, minor, or patch)" >&2
exit 1
fi
exec script/lib/bump-version.sh collab collab-v '' $1

View File

@ -7,11 +7,11 @@ which cargo-set-version > /dev/null || cargo install cargo-edit
# Ensure we're in a clean state on an up-to-date `main` branch.
if [[ -n $(git status --short --untracked-files=no) ]]; then
echo "Can't roll the railcars with uncommitted changes"
echo "can't bump versions with uncommitted changes"
exit 1
fi
if [[ $(git rev-parse --abbrev-ref HEAD) != "main" ]]; then
echo "Run this command on the main branch"
echo "this command must be run on main"
exit 1
fi
git pull -q --ff-only origin main
@ -28,7 +28,7 @@ next_minor=$(expr $minor + 1)
minor_branch_name="v${major}.${minor}.x"
prev_minor_branch_name="v${major}.${prev_minor}.x"
next_minor_branch_name="v${major}.${next_minor}.x"
preview_tag_name="v{major}.{minor}.{patch}-pre"
preview_tag_name="v${major}.${minor}.${patch}-pre"
function cleanup {
git checkout -q main
@ -71,13 +71,13 @@ if git show-ref --quiet refs/tags/${stable_tag_name}; then
fi
old_prev_minor_sha=$(git rev-parse HEAD)
echo -n stable > crates/zed/RELEASE_CHANNEL
git commit -q --all --message "Stable ${prev_minor_branch_name}"
git commit -q --all --message "${prev_minor_branch_name} stable"
git tag ${stable_tag_name}
echo "Creating new preview branch ${minor_branch_name}..."
git checkout -q -b ${minor_branch_name}
echo -n preview > crates/zed/RELEASE_CHANNEL
git commit -q --all --message "Preview ${minor_branch_name}"
git commit -q --all --message "${minor_branch_name} preview"
git tag ${preview_tag_name}
echo "Preparing main for version ${next_minor_branch_name}..."
@ -86,10 +86,10 @@ git clean -q -dff
old_main_sha=$(git rev-parse HEAD)
cargo set-version --package zed --bump minor
cargo check -q
git commit -q --all --message "Dev ${next_minor_branch_name}"
git commit -q --all --message "${next_minor_branch_name} dev"
cat <<MESSAGE
Locally rolled the railcars.
Prepared new Zed versions locally.
To push this:
git push origin \\
@ -100,10 +100,9 @@ To push this:
main
To undo this:
git push -f . \\
git reset --hard ${old_main_sha} && git push -f . \\
:${preview_tag_name} \\
:${stable_tag_name} \\
:${minor_branch_name} \\
${old_prev_minor_sha}:${prev_minor_branch_name} \\
${old_main_sha}:main
${old_prev_minor_sha}:${prev_minor_branch_name}
MESSAGE

18
script/bump-zed-patch-version Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
channel=$(cat crates/zed/RELEASE_CHANNEL)
tag_suffix=""
case $channel in
stable)
;;
preview)
tag_suffix="-pre"
;;
*)
echo "this must be run on a stable or preview release branch" >&2
exit 1
;;
esac
exec script/lib/bump-version.sh zed v $tag_suffix patch

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Install the `plantuml` utility if it is not already installed.
if [[ -x plantuml ]]; then
brew install plantuml
fi
# Generate SVGs from all of the UML files.
plantuml \
-nometadata \
-overwrite \
-tsvg \
-o ../svg \
docs/diagrams/src/*

View File

@ -2,18 +2,13 @@
set -eu
if [[ $# < 4 ]]; then
echo "Missing version increment (major, minor, or patch)" >&2
exit 1
fi
package=$1
tag_prefix=$2
tag_suffix=$3
version_increment=$4
if [[ -n $(git status --short --untracked-files=no) ]]; then
echo "Can't push a new version with uncommitted changes"
echo "can't bump version with uncommitted changes"
exit 1
fi
@ -33,11 +28,10 @@ cat <<MESSAGE
Locally committed and tagged ${package} version ${new_version}
To push this:
git push origin \
${tag_name} \
git push origin \\
${tag_name} \\
${branch_name}
To undo this:
git tag -d ${tag_name} && \
git reset --hard ${old_sha}
git reset --hard ${old_sha} && git tag -d ${tag_name}
MESSAGE