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

Handle network disconnection #107

Merged
merged 10 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Starting from `0.2.0`, Cody is using `major.EVEN_NUMBER.patch` for release versi
- Add suggested recipes to the new chat welcome message. [pull/54277](https://github.com/sourcegraph/sourcegraph/pull/54277)
- Inline Chat: Added the option to collapse all inline chats from within the inline chat window. [pull/54675](https://github.com/sourcegraph/sourcegraph/pull/54675)
- Inline Chat: We now stream messages rather than waiting for the response to be fully complete. This means you can read Cody's response as it is being generated. [pull/54665](https://github.com/sourcegraph/sourcegraph/pull/54665)
- Show network error message in webview when connection is lost and a reload button to get back when network is restored. [pull/107](https://github.com/sourcegraph/cody/pull/107)

### Fixed

Expand Down
8 changes: 6 additions & 2 deletions vscode/src/chat/ChatViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,12 @@ export class ChatViewProvider implements vscode.WebviewViewProvider, vscode.Disp
// cody.auth.signin or cody.auth.signout
await vscode.commands.executeCommand(`cody.auth.${message.type}`)
break
case 'settings':
await this.authProvider.auth(message.serverEndpoint, message.accessToken, this.config.customHeaders)
case 'settings': {
const endpoint = message.serverEndpoint.length ? message.serverEndpoint : this.config.serverEndpoint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tell me more about this change?
This is called when a user input the endpoint and access token manually, so it doesn't make sense to me to replace them with the ones from this.config if those are not available 👀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so when reload button is clicked, we need to get the token and endpoint to initiate the Re-LOGIN for the user. So, this change handles both reload cases and when sign-in is done manually. But I think it would be BEST to do it in a separate message protocol. LMK, what do you think?

const token = message.accessToken.length ? message.accessToken : this.config.accessToken
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the user manually input a new endpoint but didn't provide an access toke? That means we will try to log the user in with the access token from this.config that is meant to use with the endpoint in this.config?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, agree that would be the case here based on the implementation logic. It would be better to separate this in different messages as reload, in which we check the config values and login the user. WDYT, LMK?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think separating this into reload is a good idea 👍

await this.authProvider.auth(endpoint, token, this.config.customHeaders)
break
}
case 'insert':
await this.insertAtCursor(message.text)
break
Expand Down Expand Up @@ -917,6 +920,7 @@ export class ChatViewProvider implements vscode.WebviewViewProvider, vscode.Disp
return
}
const searchErrors = this.codebaseContext.getEmbeddingSearchErrors()

// Display error message as assistant response for users with indexed codebase but getting search errors
if (this.codebaseContext.checkEmbeddingsConnection() && searchErrors) {
this.transcript.addErrorAsAssistantResponse(searchErrors)
Expand Down
12 changes: 12 additions & 0 deletions vscode/src/chat/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface AuthStatus {
siteHasCodyEnabled: boolean
siteVersion: string
configOverwrites?: CodyLLMSiteConfiguration
showNetworkError?: boolean
}

export const defaultAuthStatus = {
Expand All @@ -120,6 +121,17 @@ export const unauthenticatedStatus = {
siteVersion: '',
}

export const networkErrorAuthStatus = {
showInvalidAccessTokenError: false,
authenticated: false,
isLoggedIn: false,
hasVerifiedEmail: false,
showNetworkError: true,
requiresVerifiedEmail: false,
siteHasCodyEnabled: false,
siteVersion: '',
}

/** The local environment of the editor. */
export interface LocalEnv {
// The operating system kind
Expand Down
26 changes: 26 additions & 0 deletions vscode/src/services/AuthProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
isLoggedIn as isAuthed,
isLocalApp,
LOCAL_APP_URL,
networkErrorAuthStatus,
unauthenticatedStatus,
} from '../chat/protocol'
import { newAuthStatus } from '../chat/utils'
Expand Down Expand Up @@ -188,6 +189,14 @@ export class AuthProvider {
if (!isDotComOrApp) {
const currentUserID = await this.client.getCurrentUserId()
const hasVerifiedEmail = false

// check first if it's a network error
if (isError(currentUserID)) {
if (isNetworkError(currentUserID.message)) {
return { ...networkErrorAuthStatus, endpoint }
}
}

return newAuthStatus(
endpoint,
isDotComOrApp,
Expand All @@ -200,6 +209,14 @@ export class AuthProvider {
}
const userInfo = await this.client.getCurrentUserIdAndVerifiedEmail()
const isCodyEnabled = true

// check first if it's a network error
if (isError(userInfo)) {
if (isNetworkError(userInfo.message)) {
return { ...networkErrorAuthStatus, endpoint }
}
}

return isError(userInfo)
? { ...unauthenticatedStatus, endpoint }
: newAuthStatus(
Expand Down Expand Up @@ -333,6 +350,15 @@ export class AuthProvider {
}
}

export function isNetworkError(error: string): boolean {
return (
error.includes('ENOTFOUND') ||
error.includes('ECONNREFUSED') ||
error.includes('ECONNRESET') ||
error.includes('EHOSTUNREACH')
)
}

function formatURL(uri: string): string | null {
if (!uri) {
return null
Expand Down
29 changes: 28 additions & 1 deletion vscode/webviews/Error.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { VSCodeButton } from '@vscode/webview-ui-toolkit/react'

import { AuthStatus, isLocalApp } from '../src/chat/protocol'

import { getVSCodeAPI } from './utils/VSCodeApi'

import styles from './Login.module.css'

const AUTH_ERRORS = {
Expand All @@ -10,6 +14,8 @@ const AUTH_ERRORS = {
EMAIL_NOT_VERIFIED: 'Email not verified. Please add a verified email to your Sourcegraph.com account.',
APP_NOT_RUNNING: 'Cody App is not running. Please open the Cody App to continue.',
INVALID_URL: 'Connection failed due to invalid URL. Please enter a valid Sourcegraph instance URL.',
NETWORK_ERROR:
'Due to network-related problems, Cody cannot be reached. Try again after checking it! Once your connection is restored, attempt a reload.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NETWORK_ERROR:
'Due to network-related problems, Cody cannot be reached. Try again after checking it! Once your connection is restored, attempt a reload.',
NETWORK_ERROR:
'Connection failed due to a network problem. Please check your internet connection and try again.',

Small copy change to make this a bit simpler

}
export const ErrorContainer: React.FunctionComponent<{
authStatus: AuthStatus
Expand All @@ -26,11 +32,12 @@ export const ErrorContainer: React.FunctionComponent<{
requiresVerifiedEmail,
hasVerifiedEmail,
siteVersion,
showNetworkError,
} = authStatus
// Version is compatible if this is an insider build or version is 5.1.0 or above
// Right now we assumes all insider builds have Cody enabled
// NOTE: Insider build includes App builds but we should seperate them in the future
if (!authenticated && !showInvalidAccessTokenError) {
if (!authenticated && !showInvalidAccessTokenError && !showNetworkError) {
return null
}
// Errors for app are handled in the ConnectApp component
Expand All @@ -45,6 +52,26 @@ export const ErrorContainer: React.FunctionComponent<{
const isVersionCompatible = isInsiderBuild || siteVersion >= '5.1.0'
const isVersionBeforeCody = !isVersionCompatible && siteVersion < '5.0.0'
const prefix = `Failed: ${isApp.isRunning ? 'Cody App' : endpoint}`

const handleReload = (): void => {
getVSCodeAPI().postMessage({ command: 'settings', serverEndpoint: '', accessToken: '' })
}

// When there's a network error
if (showNetworkError) {
return (
<>
<div className={styles.error}>
<p>Current endpoint: {endpoint}</p>
<p>{AUTH_ERRORS.NETWORK_ERROR}</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this! Maybe we can show the endpoint address to let the user know which instance is having network issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a good add on, I will update it.

<VSCodeButton className={styles.button} type="button" onClick={handleReload}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe update the button styles to have full width like the rest of the buttons in the login page? Will defer to @toolmantim who will be back next week from his PTO :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can have that so it would be align to the style with all other buttons.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love us to move away from the-full width buttons… but it's good to be consistent. But given it's an error state, I'm okay with just leaving this as a normal button w/ inherent width.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks @toolmantim

Reload
</VSCodeButton>
</div>
</>
)
}

// When doesn't have a valid token
if (showInvalidAccessTokenError) {
return (
Expand Down
3 changes: 2 additions & 1 deletion vscode/webviews/Login.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
background-color: var(--vscode-inputValidation-errorBackground);
padding: 0.5rem;
margin-top: 1rem;
margin-bottom: 1rem;
}

.terms {
Expand All @@ -82,4 +83,4 @@

width: 100%;
gap: 1rem;
}
}
Loading