Implement RunningKernel trait for native and remote kernels (#20934)

This PR introduces a unified interface for both native and remote
kernels through the `RunningKernel` trait. When either the native kernel
or the remote kernels are started, they return a `Box<dyn
RunningKernel>` to make it easier to work with the session. As a bonus
of this refactor, I've dropped some of the mpsc channels to instead opt
for passing messages directly to `session.route(message)`. There was a
lot of simplification of `Session` by moving responsibilities to
`NativeRunningKernel`.

No release notes yet until this is finalized.

* [x] Detect remote kernelspecs from configured remote servers
* [x] Launch kernel on demand

For now, this allows you to set env vars `JUPYTER_SERVER` and
`JUPYTER_TOKEN` to access a remote server. `JUPYTER_SERVER` should be a
base path like `http://localhost:8888` or
`https://notebooks.gesis.org/binder/jupyter/user/rubydata-binder-w6igpy4l/`

Release Notes:

- N/A
This commit is contained in:
Kyle Kelley 2024-11-21 14:00:19 -08:00 committed by GitHub
parent f74f670865
commit 72613b7668
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 478 additions and 230 deletions

View file

@ -7,11 +7,14 @@ use command_palette_hooks::CommandPaletteFilter;
use gpui::{
prelude::*, AppContext, EntityId, Global, Model, ModelContext, Subscription, Task, View,
};
use jupyter_websocket_client::RemoteServer;
use language::Language;
use project::{Fs, Project, WorktreeId};
use settings::{Settings, SettingsStore};
use crate::kernels::{local_kernel_specifications, python_env_kernel_specifications};
use crate::kernels::{
list_remote_kernelspecs, local_kernel_specifications, python_env_kernel_specifications,
};
use crate::{JupyterSettings, KernelSpecification, Session};
struct GlobalReplStore(Model<ReplStore>);
@ -141,19 +144,50 @@ impl ReplStore {
})
}
fn get_remote_kernel_specifications(
&self,
cx: &mut ModelContext<Self>,
) -> Option<Task<Result<Vec<KernelSpecification>>>> {
match (
std::env::var("JUPYTER_SERVER"),
std::env::var("JUPYTER_TOKEN"),
) {
(Ok(server), Ok(token)) => {
let remote_server = RemoteServer {
base_url: server,
token,
};
let http_client = cx.http_client();
Some(cx.spawn(|_, _| async move {
list_remote_kernelspecs(remote_server, http_client)
.await
.map(|specs| specs.into_iter().map(KernelSpecification::Remote).collect())
}))
}
_ => None,
}
}
pub fn refresh_kernelspecs(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
let local_kernel_specifications = local_kernel_specifications(self.fs.clone());
cx.spawn(|this, mut cx| async move {
let local_kernel_specifications = local_kernel_specifications.await?;
let remote_kernel_specifications = self.get_remote_kernel_specifications(cx);
let mut kernel_options = Vec::new();
for kernel_specification in local_kernel_specifications {
kernel_options.push(KernelSpecification::Jupyter(kernel_specification));
cx.spawn(|this, mut cx| async move {
let mut all_specs = local_kernel_specifications
.await?
.into_iter()
.map(KernelSpecification::Jupyter)
.collect::<Vec<_>>();
if let Some(remote_task) = remote_kernel_specifications {
if let Ok(remote_specs) = remote_task.await {
all_specs.extend(remote_specs);
}
}
this.update(&mut cx, |this, cx| {
this.kernel_specifications = kernel_options;
this.kernel_specifications = all_specs;
cx.notify();
})
})