Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: connect to existing jupyterlab server using jlab command #629

Closed
lukelbd opened this issue Mar 26, 2023 · 4 comments
Closed

Comments

@lukelbd
Copy link

lukelbd commented Mar 26, 2023

Recently I noticed support for connecting to existing servers was added (#15), which is awesome. However it seems the jlab command does not recognize arguments that are URLs pointing to servers. Could this be added in a future release?

Example: Currently, the following will create a new session and open the specified notebook:

jlab notebook.ipynb

However, this simply opens a new window on the landing page instead of connecting to the server:

jlab http://127.0.0.1:2001/lab?token=xxx
@welcome
Copy link

welcome bot commented Mar 26, 2023

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! 🤗

If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively.
welcome
You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! 👋

Welcome to the Jupyter community! 🎉

@lukelbd
Copy link
Author

lukelbd commented Sep 17, 2023

Any updates? Looks like it would require editing createFromArgs in sessonConfig.ts:

static createFromArgs(cliArgs: ICLIArguments) {
let workingDir = cliArgs.workingDir;
let fileOrFolders: string[] = [];
let pythonPath = '';
try {
let skipFilePaths = false;
if (workingDir) {
workingDir = path.resolve(workingDir as string);
if (!fs.existsSync(workingDir as string)) {
workingDir = null;
skipFilePaths = true;
}
}
if (!skipFilePaths) {
for (let filePath of cliArgs._) {
if (workingDir) {
filePath = path.resolve(workingDir as string, filePath.toString());
if (fs.existsSync(filePath)) {
const relPath = path.relative(workingDir as string, filePath);
fileOrFolders.push(relPath);
}
} else {
filePath = path.resolve(cliArgs.cwd, filePath.toString());
fileOrFolders.push(filePath);
}
}
}
if (cliArgs.pythonPath) {
pythonPath = path.resolve(cliArgs.cwd, cliArgs.pythonPath as string);
if (!fs.existsSync(pythonPath)) {
pythonPath = '';
}
}
} catch (error) {
return;
}
if (!(workingDir || fileOrFolders.length > 0 || pythonPath)) {
return;
}
if (workingDir) {
const sessionConfig = SessionConfig.createLocal(
workingDir as string,
fileOrFolders
);
if (pythonPath) {
sessionConfig.pythonPath = pythonPath;
}
return sessionConfig;
} else {
const sessionConfig =
fileOrFolders.length > 0
? SessionConfig.createLocalForFilesOrFolders(fileOrFolders)
: SessionConfig.createLocal();
if (pythonPath) {
sessionConfig.pythonPath = pythonPath;
}
return sessionConfig;
}
}

Seems simple enough but not sure of the commands needed to create + connect to a session from a URL.

Maybe connectAndGetServerInfo in connect.ts is the key?

export async function connectAndGetServerInfo(
url: string,
options?: IRemoteServerConnectOptions
): Promise<IJupyterServerInfo> {
return new Promise<IJupyterServerInfo>((resolve, reject) => {
let urlObj: URL;
try {
urlObj = new URL(url);
} catch (error) {
reject({
type: 'invalid-url',
message: error.message
} as IConnectError);
return;
}
const browserOptions: Electron.BrowserWindowConstructorOptions = {
title: 'JupyterLab Server Connection',
show: options?.showDialog === true
};
if (options?.incognito) {
browserOptions.webPreferences = {
partition: `partition-${Date.now()}`
};
}
if (options?.partition) {
browserOptions.webPreferences = {
partition: options.partition
};
}
const window = new BrowserWindow(browserOptions);
const timeout = options?.timeout || 30000;
const connectTimeoutHandler = async () => {
if (window) {
if (options?.incognito) {
await clearSession(window.webContents.session);
}
window.close();
}
reject({
type: 'timeout',
message: `Failed to connect to JupyterLab server in ${(
timeout / 1000
).toFixed(1)} s`
} as IConnectError);
};
let connectTimeout: NodeJS.Timeout;
const resetConnectTimer = () => {
clearTimeout(connectTimeout);
connectTimeout = setTimeout(connectTimeoutHandler, timeout);
};
resetConnectTimer();
connectWindow = window;
const urlPrefix = `${urlObj.protocol}//${urlObj.host}${urlObj.pathname}`;
window.webContents.on(
'did-navigate',
(
event: Event,
navigationUrl: string,
httpResponseCode: number,
httpStatusText: string
) => {
if (httpResponseCode >= 400) {
clearTimeout(connectTimeout);
window.close();
reject({
type: 'invalid-url',
message: `Server responded with code: ${httpResponseCode}`
} as IConnectError);
return;
}
resetConnectTimer();
if (!navigationUrl.startsWith(urlPrefix)) {
return;
}
window.webContents
.executeJavaScript(
`
const config = document.getElementById('jupyter-config-data');
JSON.parse(config ? config.textContent : '{}');
`
)
.then((config: any) => {
resetConnectTimer();
if (!(config && config.appVersion)) {
clearTimeout(connectTimeout);
window.close();
reject({
type: 'invalid-url',
message: 'Not a supported JupyterLab server found'
} as IConnectError);
return;
}
window.webContents.session.cookies
.get({})
.then(async cookies => {
clearTimeout(connectTimeout);
if (options?.incognito) {
await clearSession(window.webContents.session);
}
const hostname = urlObj.hostname;
const domainCookies = cookies.filter(
cookie => cookie.domain === hostname
);
window.removeAllListeners('closed');
window.close();
resolve({
pageConfig: config,
cookies: domainCookies
});
})
.catch(error => {
console.log(error);
});
});
}
);
window.on('closed', () => {
clearTimeout(connectTimeout);
reject({
type: 'dismissed',
message: 'Login window closed'
} as IConnectError);
});
window.setMenuBarVisibility(false);
window.center();
window.loadURL(url);
});
}

@mbektas
Copy link
Member

mbektas commented Oct 4, 2023

hi @lukelbd , this is a good idea. I will look into adding this feature.

@mbektas
Copy link
Member

mbektas commented Oct 27, 2023

@lukelbd this feature is now available with v4.0.7-1. Please give it a try and create a new issue if you run into problems. Here is an example.

@mbektas mbektas closed this as completed Oct 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants