From db3e01a12ccf32fc5b24b51285619cbe5b6ba27d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 7 Jun 2021 18:15:11 -0700 Subject: [PATCH] Start work on a login command Co-Authored-By: Nathan Sobo --- Cargo.lock | 64 +++++++++++++++++++++++ gpui/src/platform.rs | 1 + gpui/src/platform/mac/platform.rs | 10 ++++ gpui/src/platform/test.rs | 2 + zed/Cargo.toml | 13 ++--- zed/src/lib.rs | 85 +++++++++++++++++++++++++++++++ zed/src/main.rs | 4 +- zed/src/menus.rs | 6 +++ zed/src/workspace.rs | 5 -- 9 files changed, 178 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5645c6f25..ab49bb995f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -964,6 +964,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "freetype" version = "0.7.0" @@ -1245,6 +1255,17 @@ dependencies = [ "png 0.11.0", ] +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "ignore" version = "0.4.17" @@ -1712,6 +1733,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "phf" version = "0.7.24" @@ -2693,6 +2720,21 @@ dependencies = [ "safe_arch", ] +[[package]] +name = "tinyvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "toml" version = "0.4.10" @@ -2769,6 +2811,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f9af028e052a610d99e066b33304625dea9613170a2563314490a4e6ec5cf7f" +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-script" version = "0.5.2" @@ -2799,6 +2850,18 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + [[package]] name = "usvg" version = "0.14.0" @@ -3009,4 +3072,5 @@ dependencies = [ "tree-sitter", "tree-sitter-rust", "unindent", + "url", ] diff --git a/gpui/src/platform.rs b/gpui/src/platform.rs index 6924f3c28d..9c7788822f 100644 --- a/gpui/src/platform.rs +++ b/gpui/src/platform.rs @@ -42,6 +42,7 @@ pub trait Platform: Send + Sync { fn quit(&self); fn write_to_clipboard(&self, item: ClipboardItem); fn read_from_clipboard(&self) -> Option; + fn open_url(&self, url: &str); } pub(crate) trait ForegroundPlatform { diff --git a/gpui/src/platform/mac/platform.rs b/gpui/src/platform/mac/platform.rs index 4c19bb5242..6ec08b4cd0 100644 --- a/gpui/src/platform/mac/platform.rs +++ b/gpui/src/platform/mac/platform.rs @@ -449,6 +449,16 @@ impl platform::Platform for MacPlatform { } } } + + fn open_url(&self, url: &str) { + unsafe { + let url = NSURL::alloc(nil) + .initWithString_(ns_string(url)) + .autorelease(); + let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + msg_send![workspace, openURL: url] + } + } } unsafe fn get_foreground_platform(object: &mut Object) -> &MacForegroundPlatform { diff --git a/gpui/src/platform/test.rs b/gpui/src/platform/test.rs index bd1693a076..41b96064c3 100644 --- a/gpui/src/platform/test.rs +++ b/gpui/src/platform/test.rs @@ -121,6 +121,8 @@ impl super::Platform for Platform { fn read_from_clipboard(&self) -> Option { self.current_clipboard_item.lock().clone() } + + fn open_url(&self, _: &str) {} } impl Window { diff --git a/zed/Cargo.toml b/zed/Cargo.toml index 89e780a5bf..8bd748767b 100644 --- a/zed/Cargo.toml +++ b/zed/Cargo.toml @@ -20,32 +20,33 @@ crossbeam-channel = "0.5.0" ctor = "0.1.20" dirs = "3.0" easy-parallel = "3.1.0" -fsevent = {path = "../fsevent"} +fsevent = { path = "../fsevent" } futures-core = "0.3" -gpui = {path = "../gpui"} +gpui = { path = "../gpui" } ignore = "0.4" lazy_static = "1.4.0" libc = "0.2" log = "0.4" num_cpus = "1.13.0" parking_lot = "0.11.1" -postage = {version = "0.4.1", features = ["futures-traits"]} +postage = { version = "0.4.1", features = ["futures-traits"] } rand = "0.8.3" rust-embed = "5.9.0" seahash = "4.1" -serde = {version = "1", features = ["derive"]} +serde = { version = "1", features = ["derive"] } similar = "1.3" simplelog = "0.9" -smallvec = {version = "1.6", features = ["union"]} +smallvec = { version = "1.6", features = ["union"] } smol = "1.2.5" toml = "0.5" tree-sitter = "0.19.5" tree-sitter-rust = "0.19.0" +url = "2.2" [dev-dependencies] cargo-bundle = "0.5.0" env_logger = "0.8" -serde_json = {version = "1.0.64", features = ["preserve_order"]} +serde_json = { version = "1.0.64", features = ["preserve_order"] } tempdir = "0.3.7" unindent = "0.1.7" diff --git a/zed/src/lib.rs b/zed/src/lib.rs index 936185bf88..13f3fcecf6 100644 --- a/zed/src/lib.rs +++ b/zed/src/lib.rs @@ -1,3 +1,8 @@ +use anyhow::{anyhow, Context}; +use gpui::MutableAppContext; +use smol::io::{AsyncBufReadExt, AsyncWriteExt}; +use url::Url; + pub mod assets; pub mod editor; pub mod file_finder; @@ -18,3 +23,83 @@ pub struct AppState { pub settings: postage::watch::Receiver, pub language_registry: std::sync::Arc, } + +pub fn init(cx: &mut MutableAppContext) { + cx.add_global_action("app:authenticate", authenticate); + cx.add_global_action("app:quit", quit); +} + +fn authenticate(_: &(), cx: &mut MutableAppContext) { + let zed_url = std::env::var("ZED_SERVER_URL").unwrap_or("https://zed.dev".to_string()); + let platform = cx.platform().clone(); + + dbg!(&zed_url); + + let task = cx.background_executor().spawn(async move { + let listener = smol::net::TcpListener::bind("127.0.0.1:0").await?; + let port = listener.local_addr()?.port(); + + platform.open_url(&format!( + "{}/sign_in?native_app_port={}&native_app_public_key=unused-for-now", + zed_url, port, + )); + + let (mut stream, _) = listener.accept().await?; + let mut reader = smol::io::BufReader::new(&mut stream); + let mut line = String::new(); + reader.read_line(&mut line).await?; + + let mut parts = line.split(" "); + if parts.next() == Some("GET") { + if let Some(path) = parts.next() { + let url = Url::parse(&format!("http://example.com{}", path)) + .context("failed to parse login notification url")?; + let mut access_token = None; + let mut public_key = None; + for (key, value) in url.query_pairs() { + if key == "access_token" { + access_token = Some(value); + } else if key == "public_key" { + public_key = Some(value); + } + } + stream + .write_all(LOGIN_RESPONSE.as_bytes()) + .await + .context("failed to write login response")?; + stream.flush().await.context("failed to flush tcp stream")?; + + eprintln!( + "logged in. access_token: {:?}, public_key: {:?}", + access_token, public_key + ); + + platform.activate(true); + return Ok(()); + } + } + Err(anyhow!("failed to parse http request from zed web app")) + }); + + cx.spawn(|_| async move { + if let Err(e) = task.await { + log::error!("failed to login {:?}", e) + } + }) + .detach(); +} + +fn quit(_: &(), cx: &mut MutableAppContext) { + cx.platform().quit(); +} + +const LOGIN_RESPONSE: &'static str = " +HTTP/1.1 200 OK\r +Content-Length: 64\r +Content-Type: text/html\r +\r + + + + +"; diff --git a/zed/src/main.rs b/zed/src/main.rs index d808ee0fc3..ddec31ecf2 100644 --- a/zed/src/main.rs +++ b/zed/src/main.rs @@ -6,7 +6,7 @@ use log::LevelFilter; use simplelog::SimpleLogger; use std::{fs, path::PathBuf, sync::Arc}; use zed::{ - assets, editor, file_finder, language, menus, settings, + self, assets, editor, file_finder, language, menus, settings, workspace::{self, OpenParams}, AppState, }; @@ -26,6 +26,8 @@ fn main() { app.run(move |cx| { cx.set_menus(menus::menus(app_state.clone())); + + zed::init(cx); workspace::init(cx); editor::init(cx); file_finder::init(cx); diff --git a/zed/src/menus.rs b/zed/src/menus.rs index e9d50c7824..ef20573610 100644 --- a/zed/src/menus.rs +++ b/zed/src/menus.rs @@ -14,6 +14,12 @@ pub fn menus(state: AppState) -> Vec> { arg: None, }, MenuItem::Separator, + MenuItem::Action { + name: "Log In", + keystroke: None, + action: "app:authenticate", + arg: None, + }, MenuItem::Action { name: "Quit", keystroke: Some("cmd-q"), diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 36ef65b174..180771ce72 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -29,7 +29,6 @@ use std::{ pub fn init(cx: &mut MutableAppContext) { cx.add_global_action("workspace:open", open); cx.add_global_action("workspace:open_paths", open_paths); - cx.add_global_action("app:quit", quit); cx.add_action("workspace:save", Workspace::save_active_item); cx.add_action("workspace:debug_elements", Workspace::debug_elements); cx.add_action("workspace:new_file", Workspace::open_new_file); @@ -98,10 +97,6 @@ fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) { }); } -fn quit(_: &(), cx: &mut MutableAppContext) { - cx.platform().quit(); -} - pub trait Item: Entity + Sized { type View: ItemView;