diff --git a/.idea/misc.xml b/.idea/misc.xml index c4fae9a174fa6d..b059edf511ab31 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + diff --git a/components/gitpod-cli/cmd/docs.go b/components/gitpod-cli/cmd/docs.go index f0599a3e106441..42d38bc5c5e32b 100644 --- a/components/gitpod-cli/cmd/docs.go +++ b/components/gitpod-cli/cmd/docs.go @@ -15,7 +15,7 @@ var docsCmd = &cobra.Command{ Use: "docs", Short: "Open Gitpod Documentation in default browser", RunE: func(cmd *cobra.Command, args []string) error { - return openPreview("GP_EXTERNAL_BROWSER", DocsUrl) + return openPreview(cmd.Context(), DocsUrl, true) }, } diff --git a/components/gitpod-cli/cmd/open.go b/components/gitpod-cli/cmd/open.go index 0408464e883216..8b153a03c5d63a 100644 --- a/components/gitpod-cli/cmd/open.go +++ b/components/gitpod-cli/cmd/open.go @@ -7,11 +7,10 @@ package cmd import ( "os" "os/exec" - "time" + "path/filepath" "github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor" - - "context" + "github.com/gitpod-io/gitpod/supervisor/api" "github.com/google/shlex" "github.com/spf13/cobra" @@ -24,25 +23,48 @@ var openCmd = &cobra.Command{ Short: "Opens a file in Gitpod", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // TODO(ak) use NotificationService.NotifyActive supervisor API instead - - ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second) - defer cancel() + ctx := cmd.Context() client, err := supervisor.New(ctx) if err != nil { return err } defer client.Close() - client.WaitForIDEReady(ctx) wait, _ := cmd.Flags().GetBool("wait") pcmd := os.Getenv("GP_OPEN_EDITOR") if pcmd == "" { - return xerrors.Errorf("GP_OPEN_EDITOR is not set") + var paths []string + for _, path := range args { + absPath, err := filepath.Abs(path) + if err == nil { + path = absPath + } + paths = append(paths, path) + } + + resp, err := client.Notification.Notify(ctx, &api.NotifyRequest{ + Open: &api.NotifyRequest_Open{ + Paths: paths, + Await: wait, + }, + Active: true, + }) + if err != nil { + return err + } + if resp.Command == nil { + return nil + } + c := exec.CommandContext(cmd.Context(), resp.Command.Cmd, resp.Command.Args...) + c.Stdin = os.Stdin + c.Stdout = os.Stdout + c.Stderr = os.Stderr + return c.Run() } + // TODO: backward compatibilty, remove when all IDEs are updated pargs, err := shlex.Split(pcmd) if err != nil { return xerrors.Errorf("cannot parse GP_OPEN_EDITOR: %w", err) diff --git a/components/gitpod-cli/cmd/preview.go b/components/gitpod-cli/cmd/preview.go index 34fb38dac6a691..f2f97a14f19c7c 100644 --- a/components/gitpod-cli/cmd/preview.go +++ b/components/gitpod-cli/cmd/preview.go @@ -11,9 +11,9 @@ import ( "regexp" "strconv" "strings" - "time" "github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor" + "github.com/gitpod-io/gitpod/supervisor/api" "github.com/google/shlex" "github.com/spf13/cobra" "golang.org/x/xerrors" @@ -31,34 +31,48 @@ var previewCmd = &cobra.Command{ Short: "Opens a URL in the IDE's preview", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // TODO(ak) use NotificationService.NotifyActive supervisor API instead + return openPreview(cmd.Context(), args[0], previewCmdOpts.External) + }, +} - ctx, cancel := context.WithTimeout(cmd.Context(), 5*time.Second) - defer cancel() - client, err := supervisor.New(ctx) +func openPreview(ctx context.Context, url string, external bool) error { + client, err := supervisor.New(ctx) + if err != nil { + return err + } + defer client.Close() + client.WaitForIDEReady(ctx) + + url = replaceLocalhostInURL(url) + gpBrowserEnvVar := "GP_PREVIEW_BROWSER" + if external { + gpBrowserEnvVar = "GP_EXTERNAL_BROWSER" + if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { + url = "https://" + url + } + } + pcmd := os.Getenv(gpBrowserEnvVar) + if pcmd == "" { + resp, err := client.Notification.Notify(ctx, &api.NotifyRequest{ + Preview: &api.NotifyRequest_Preview{ + Url: url, + External: external, + }, + Active: true, + }) if err != nil { return err } - defer client.Close() - - client.WaitForIDEReady(ctx) - - gpBrowserEnvVar := "GP_PREVIEW_BROWSER" - - url := replaceLocalhostInURL(args[0]) - if previewCmdOpts.External { - if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { - url = "https://" + url - } - gpBrowserEnvVar = "GP_EXTERNAL_BROWSER" + if resp.Command == nil { + return nil } - - return openPreview(gpBrowserEnvVar, url) - }, -} - -func openPreview(gpBrowserEnvVar string, url string) error { - pcmd := os.Getenv(gpBrowserEnvVar) + c := exec.CommandContext(ctx, resp.Command.Cmd, resp.Command.Args...) + c.Stdin = os.Stdin + c.Stdout = os.Stdout + c.Stderr = os.Stderr + return c.Run() + } + // TODO: backward compatibilty, remove when all IDEs are updated if pcmd == "" { return xerrors.Errorf("%s is not set", gpBrowserEnvVar) } diff --git a/components/gitpod-cli/cmd/rebuild.go b/components/gitpod-cli/cmd/rebuild.go index 52afcc5fa833fd..1641f006eb6953 100644 --- a/components/gitpod-cli/cmd/rebuild.go +++ b/components/gitpod-cli/cmd/rebuild.go @@ -262,6 +262,8 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie {Source: "/workspace"}, {Source: "/.supervisor"}, {Source: "/ide"}, + {Source: "/ide-desktop"}, + {Source: "/ide-desktop-plugins"}, {Source: "/workspace/.gitpod-debug/.docker-root", Target: "/workspace/.docker-root", Permission: 0710}, {Source: "/workspace/.gitpod-debug/.gitpod", Target: "/workspace/.gitpod", Permission: 0751}, {Source: "/workspace/.gitpod-debug/.vscode-remote", Target: "/workspace/.vscode-remote", Permission: 0751}, diff --git a/components/gitpod-cli/hot-swap.sh b/components/gitpod-cli/hot-swap.sh index 3cb25b65763dbb..4d21dfddb275d8 100755 --- a/components/gitpod-cli/hot-swap.sh +++ b/components/gitpod-cli/hot-swap.sh @@ -1,31 +1,53 @@ #!/bin/bash -# Copyright (c) 2022 Gitpod GmbH. All rights reserved. +# Copyright (c) 2023 Gitpod GmbH. All rights reserved. # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. set -Eeuo pipefail component=${PWD##*/} -workspaceUrl=$(echo "${1}" |sed -e "s/\/$//") -echo "URL: $workspaceUrl" -workspaceDesc=$(gpctl workspaces describe "$workspaceUrl" -o=json) +workspaceURL=${1-} +[ -z "$workspaceURL" ] && echo "Please provide a workspace URL as first argument." && exit 1 +workspaceURL=$(echo "${1}" |sed -e "s/\/$//") +echo "Workspace URL: $workspaceURL" -podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) -echo "Pod: $podName" +workspaceHost=${workspaceURL//https:\/\//} +echo "Workspace Host: $workspaceHost" -workspaceId=$(echo "$workspaceDesc" | jq .metadata.meta_id -r) -echo "ID: $workspaceId" +workspaceID=$(echo "${workspaceHost}" | cut -d. -f1) +echo "Workspace ID: $workspaceID" -clusterHost=$(kubectl exec -it "$podName" -- printenv GITPOD_WORKSPACE_CLUSTER_HOST |sed -e "s/\s//g") +clusterHost=${workspaceHost//$workspaceID./} echo "Cluster Host: $clusterHost" -# prepare ssh -ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) +devClusterHost=$(gp info --json |jq .cluster_host -r) +echo "Dev Cluster Host: $devClusterHost" + +preview=true +if [[ $clusterHost = "$devClusterHost" ]] +then + preview=false +fi +echo "Preview Env: $preview" + +# prepare ssh config sshConfig=$(mktemp) -echo "Host $workspaceId" > "$sshConfig" -echo " Hostname \"$workspaceId.ssh.$clusterHost\"" >> "$sshConfig" -echo " User \"$workspaceId#$ownerToken\"" >> "$sshConfig" +echo "Host $workspaceID" > "$sshConfig" +echo " Hostname \"$workspaceID.ssh.$clusterHost\"" >> "$sshConfig" +if [ $preview = "true" ] +then + workspaceDesc=$(gpctl workspaces describe "$workspaceURL" -o=json) + + podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) + echo "Workspace Pod: $podName" + + ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) + echo " User \"$workspaceID#$ownerToken\"" >> "$sshConfig" +else + # assume SSH keys configured via .dotfiles + echo " User \"$workspaceID\"" >> "$sshConfig" +fi # build go build . @@ -34,7 +56,7 @@ echo "$component built" # upload uploadDest="/.supervisor/$component" echo "Upload Dest: $uploadDest" -ssh -F "$sshConfig" "$workspaceId" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" +ssh -F "$sshConfig" "$workspaceID" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" echo "Permissions granted" -scp -F "$sshConfig" -r "./$component" "$workspaceId":"$uploadDest" +scp -F "$sshConfig" -r "./$component" "$workspaceID":"$uploadDest" echo "Swap complete" diff --git a/components/ide/code/leeway.Dockerfile b/components/ide/code/leeway.Dockerfile index b94d064ba5f9ab..d62fa74c1ac328 100644 --- a/components/ide/code/leeway.Dockerfile +++ b/components/ide/code/leeway.Dockerfile @@ -99,16 +99,9 @@ FROM scratch COPY --from=code_builder --chown=33333:33333 /vscode-web/ /ide/ COPY --from=code_builder --chown=33333:33333 /vscode-reh-linux-x64/ /ide/ +# TODO(ak) get rid of it as well ENV GITPOD_ENV_APPEND_PATH=/ide/bin/remote-cli: -# editor config -ENV GITPOD_ENV_SET_EDITOR=/ide/bin/remote-cli/gitpod-code -ENV GITPOD_ENV_SET_VISUAL="$GITPOD_ENV_SET_EDITOR" -ENV GITPOD_ENV_SET_GP_OPEN_EDITOR="$GITPOD_ENV_SET_EDITOR" -ENV GITPOD_ENV_SET_GIT_EDITOR="$GITPOD_ENV_SET_EDITOR --wait" -ENV GITPOD_ENV_SET_GP_PREVIEW_BROWSER="/ide/bin/remote-cli/gitpod-code --preview" -ENV GITPOD_ENV_SET_GP_EXTERNAL_BROWSER="/ide/bin/remote-cli/gitpod-code --openExternal" - ARG CODE_VERSION ARG CODE_COMMIT LABEL "io.gitpod.ide.version"=$CODE_VERSION diff --git a/components/ide/jetbrains/backend-plugin/hot-swap.sh b/components/ide/jetbrains/backend-plugin/hot-swap.sh index f999de548dee55..7538d7d93f6f36 100755 --- a/components/ide/jetbrains/backend-plugin/hot-swap.sh +++ b/components/ide/jetbrains/backend-plugin/hot-swap.sh @@ -7,23 +7,54 @@ set -Eeuo pipefail # This script builds the backend plugin, replaces the backend plugin on a running workspace and restarts the JB backend. -workspaceUrl=${1-} -[ -z "$workspaceUrl" ] && echo "Please provide a workspace URL as first argument." && exit 1 -workspaceUrl=$(echo "$workspaceUrl" |sed -e "s/\/$//") -echo "URL: $workspaceUrl" +workspaceURL=${1-} +[ -z "$workspaceURL" ] && echo "Please provide a workspace URL as first argument." && exit 1 +workspaceURL=$(echo "$workspaceURL" |sed -e "s/\/$//") +echo "Workspace URL: $workspaceURL" -workspaceDesc=$(gpctl workspaces describe "$workspaceUrl" -o=json) +workspaceHost=${workspaceURL//https:\/\//} +echo "Workspace Host: $workspaceHost" -podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) -echo "Pod: $podName" +workspaceID=$(echo "${workspaceHost}" | cut -d. -f1) +echo "Workspace ID: $workspaceID" -workspaceId=$(echo "$workspaceDesc" | jq .metadata.meta_id -r) -echo "ID: $workspaceId" - -clusterHost=$(kubectl exec -it "$podName" -- printenv GITPOD_WORKSPACE_CLUSTER_HOST |sed -e "s/\s//g") +clusterHost=${workspaceHost//$workspaceID./} echo "Cluster Host: $clusterHost" -qualifier=$(kubectl exec -it "$podName" -- printenv JETBRAINS_BACKEND_QUALIFIER |sed -e "s/\s//g") +devClusterHost=$(gp info --json |jq .cluster_host -r) +echo "Dev Cluster Host: $devClusterHost" + +preview=true +if [[ $clusterHost = "$devClusterHost" ]] +then + preview=false +fi +echo "Preview Env: $preview" + +product=${2-intellij} +qualifier=${3-latest} + +# prepare ssh config +sshConfig=$(mktemp) +echo "Host $workspaceID" > "$sshConfig" +echo " Hostname \"$workspaceID.ssh.$clusterHost\"" >> "$sshConfig" +if [ $preview = "true" ] +then + workspaceDesc=$(gpctl workspaces describe "$workspaceURL" -o=json) + + podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) + echo "Workspace Pod: $podName" + + qualifier=$(kubectl exec -it "$podName" -- printenv JETBRAINS_BACKEND_QUALIFIER |sed -e "s/\s//g") + + ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) + echo " User \"$workspaceID#$ownerToken\"" >> "$sshConfig" +else + # assume SSH keys configured via .dotfiles + echo " User \"$workspaceID\"" >> "$sshConfig" +fi + +echo "Product: $product" echo "Version Qualifier: $qualifier" # prepare build @@ -32,13 +63,6 @@ tarDir="/tmp/hot-swap/$component" mkdir -p "$tarDir" echo "Build Dir: $tarDir" -# prepare ssh -ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) -sshConfig="$tarDir/ssh-config" -echo "Host $workspaceId" > "$sshConfig" -echo " Hostname \"$workspaceId.ssh.$clusterHost\"" >> "$sshConfig" -echo " User \"$workspaceId#$ownerToken\"" >> "$sshConfig" - # build tarFile="$tarDir/build.tar.gz" leeway build -DnoVerifyJBPlugin=true .:"plugin-$qualifier" --save "$tarFile" @@ -47,16 +71,20 @@ tar -xf "$tarFile" -C "$tarDir" # upload uploadDest="/ide-desktop-plugins/$component" echo "Upload Dest: $uploadDest" -scp -F "$sshConfig" -r "$tarDir/build/gitpod-remote" "$workspaceId":"$uploadDest" +scp -F "$sshConfig" -r "$tarDir/build/gitpod-remote" "$workspaceID":"$uploadDest" # link -link="/ide-desktop/backend/plugins/gitpod-remote" -ssh -F "$sshConfig" "$workspaceId" ln -sfn "$uploadDest" "$link" +link="/ide-desktop/$product/backend/plugins/gitpod-remote" +if [ "$qualifier" = "latest" ] +then + link="/ide-desktop/$product-$qualifier/backend/plugins/gitpod-remote" +fi +ssh -F "$sshConfig" "$workspaceID" ln -sfn "$uploadDest" "$link" echo "Link: $link -> $uploadDest" # restart -ssh -F "$sshConfig" "$workspaceId" curl http://localhost:24000/restart -echo "Restarted: please reconenct to JB backend to try new changes." +ssh -F "$sshConfig" "$workspaceID" curl http://localhost:24000/restart +echo "Restarted: please reconnect to JB backend to try new changes." # clean up rm -rf "$tarDir" diff --git a/components/ide/jetbrains/backend-plugin/launch-dev-server.sh b/components/ide/jetbrains/backend-plugin/launch-dev-server.sh index 09b14a1e8f8f0f..e1ee1c80ec1f78 100755 --- a/components/ide/jetbrains/backend-plugin/launch-dev-server.sh +++ b/components/ide/jetbrains/backend-plugin/launch-dev-server.sh @@ -80,17 +80,6 @@ export IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains # Enable host status endpoint export CWM_HOST_STATUS_OVER_HTTP_TOKEN=gitpod -# Build and move idea-cli, then overwrite environment variables initially defined by `components/ide/jetbrains/image/leeway.Dockerfile` -# Note: IDEA_CLI_DEV_PATH path needs to be the same string used in components/ide/jetbrains/cli/cmd/root.go -IDEA_CLI_DEV_PATH=/ide-desktop/bin/idea-cli-dev -(cd ../cli && go build -o $IDEA_CLI_DEV_PATH) -export EDITOR="$IDEA_CLI_DEV_PATH open" -export VISUAL="$EDITOR" -export GP_OPEN_EDITOR="$EDITOR" -export GIT_EDITOR="$EDITOR --wait" -export GP_PREVIEW_BROWSER="$IDEA_CLI_DEV_PATH preview" -export GP_EXTERNAL_BROWSER="$IDEA_CLI_DEV_PATH preview" - export JETBRAINS_GITPOD_BACKEND_KIND=intellij $TEST_BACKEND_DIR/bin/remote-dev-server.sh run "$TEST_DIR" diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt index 2654a65517503b..e1cd3396d9e8db 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodCLIService.kt @@ -4,35 +4,17 @@ package io.gitpod.jetbrains.remote -import com.intellij.codeWithMe.ClientId -import com.intellij.ide.BrowserUtil -import com.intellij.ide.CommandLineProcessor -import com.intellij.openapi.client.ClientSession -import com.intellij.openapi.client.ClientSessionsManager import com.intellij.openapi.components.service -import com.intellij.openapi.components.serviceOrNull -import com.intellij.openapi.diagnostic.thisLogger -import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream -import com.intellij.openapi.util.io.FileUtilRt import com.intellij.util.application -import com.intellij.util.withFragment -import com.intellij.util.withPath -import com.intellij.util.withQuery -import com.jetbrains.rd.util.URI -import io.gitpod.jetbrains.remote.utils.LocalHostUri import io.netty.buffer.Unpooled import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.http.FullHttpRequest import io.netty.handler.codec.http.QueryStringDecoder import io.prometheus.client.exporter.common.TextFormat -import kotlinx.coroutines.* import org.jetbrains.ide.RestService import org.jetbrains.io.response import java.io.OutputStreamWriter -import java.nio.file.InvalidPathException -import java.nio.file.Path -import java.util.* @Suppress("UnstableApiUsage", "OPT_IN_USAGE") class GitpodCLIService : RestService() { @@ -59,96 +41,9 @@ class GitpodCLIService : RestService() { sendResponse(request, context, response) return null } - if (operation == "open") { - val fileStr = getStringParameter("file", urlDecoder) - if (fileStr.isNullOrBlank()) { - return "file is missing" - } - val file = parseFilePath(fileStr) ?: return "invalid file" - val shouldWait = getBooleanParameter("wait", urlDecoder) - return withClient(request, context) { - CommandLineProcessor.doOpenFileOrProject(file, shouldWait).future.await() - } - } - if (operation == "preview") { - val url = getStringParameter("url", urlDecoder) - if (url.isNullOrBlank()) { - return "url is missing" - } - - return withClient(request, context) { project -> - var resolvedUrl = url - val uri = URI.create(url) - val localHostUriMetadata = LocalHostUri.extractLocalHostUriMetaDataForPortMapping(uri) - val gitpodPortForwardingService = serviceOrNull() - - if (localHostUriMetadata.isPresent && gitpodPortForwardingService != null) { - var localHostUriFromPort = Optional.empty() - - application.invokeAndWait { - localHostUriFromPort = gitpodPortForwardingService - .getLocalHostUriFromHostPort(localHostUriMetadata.get().port) - } - - if (localHostUriFromPort.isPresent) { - resolvedUrl = localHostUriFromPort.get() - .withPath(uri.path) - .withQuery(uri.query) - .withFragment(uri.fragment) - .toString() - } - } - - BrowserUtil.browse(resolvedUrl, project) - } - } return "invalid operation" } - private fun withClient(request: FullHttpRequest, context: ChannelHandlerContext, action: suspend (project: Project?) -> Unit): String? { - GlobalScope.launch { - getClientSessionAndProjectAsync().let { (session, project) -> - ClientId.withClientId(session.clientId) { - action(project) - sendOk(request, context) - } - } - } - return null - } - - private data class ClientSessionAndProject(val session: ClientSession, val project: Project?) - - private suspend fun getClientSessionAndProjectAsync(): ClientSessionAndProject { - val project = getLastFocusedOrOpenedProject() - var session: ClientSession? = null - while (session == null) { - if (project != null) { - session = ClientSessionsManager.getProjectSessions(project, false).firstOrNull() - } - if (session == null) { - session = ClientSessionsManager.getAppSessions(false).firstOrNull() - } - if (session == null) { - delay(1000L) - } - } - return ClientSessionAndProject(session, project) - } - - private fun parseFilePath(path: String): Path? { - return try { - var file: Path = Path.of(FileUtilRt.toSystemDependentName(path)) // handle paths like '/file/foo\qwe' - if (!file.isAbsolute) { - file = file.toAbsolutePath() - } - file.normalize() - } catch (e: InvalidPathException) { - thisLogger().warn("gitpod cli: failed to parse file path:", e) - null - } - } - companion object { const val SERVICE_NAME = "gitpod/cli" } diff --git a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt index 51a14dc6567244..cc18c703cd70e4 100644 --- a/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt +++ b/components/ide/jetbrains/backend-plugin/src/main/kotlin/io/gitpod/jetbrains/remote/GitpodManager.kt @@ -4,27 +4,43 @@ package io.gitpod.jetbrains.remote +import com.intellij.codeWithMe.ClientId import com.intellij.ide.BrowserUtil +import com.intellij.ide.CliResult +import com.intellij.ide.CommandLineProcessor +import com.intellij.ide.impl.ProjectUtil.getActiveProject import com.intellij.ide.plugins.PluginManagerCore import com.intellij.notification.NotificationAction import com.intellij.notification.NotificationGroupManager import com.intellij.notification.NotificationType import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationInfo +import com.intellij.openapi.client.ClientKind +import com.intellij.openapi.client.ClientSessionsManager import com.intellij.openapi.components.Service +import com.intellij.openapi.components.serviceOrNull import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.extensions.PluginId +import com.intellij.openapi.project.Project import com.intellij.openapi.util.LowMemoryWatcher +import com.intellij.openapi.util.io.FileUtilRt import com.intellij.remoteDev.util.onTerminationOrNow import com.intellij.util.application import com.intellij.util.net.ssl.CertificateManager import com.intellij.util.proxy.CommonProxy +import com.intellij.util.withFragment +import com.intellij.util.withPath +import com.intellij.util.withQuery +import com.jetbrains.rd.framework.util.launch import com.jetbrains.rd.util.lifetime.Lifetime +import com.jetbrains.rd.util.lifetime.LifetimeDefinition +import com.jetbrains.rd.util.lifetime.isNotAlive import git4idea.config.GitVcsApplicationSettings import io.gitpod.gitpodprotocol.api.GitpodClient import io.gitpod.gitpodprotocol.api.GitpodServerLauncher import io.gitpod.gitpodprotocol.api.entities.RemoteTrackMessage import io.gitpod.jetbrains.remote.services.HeartbeatService +import io.gitpod.jetbrains.remote.utils.LocalHostUri import io.gitpod.jetbrains.remote.utils.Retrier.retry import io.gitpod.supervisor.api.* import io.gitpod.supervisor.api.Info.WorkspaceInfoResponse @@ -37,23 +53,26 @@ import io.prometheus.client.CollectorRegistry import io.prometheus.client.Counter import io.prometheus.client.Gauge import io.prometheus.client.exporter.PushGateway -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay +import kotlinx.coroutines.* import kotlinx.coroutines.future.await import kotlinx.coroutines.guava.asDeferred -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch import org.jetbrains.ide.BuiltInServerManager +import java.awt.KeyboardFocusManager +import java.beans.PropertyChangeEvent import java.net.URI import java.net.URL import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse +import java.nio.file.InvalidPathException +import java.nio.file.Path import java.time.Duration +import java.util.* import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture import javax.websocket.DeploymentException + @Suppress("UnstableApiUsage", "OPT_IN_USAGE") @Service class GitpodManager : Disposable { @@ -79,13 +98,13 @@ class GitpodManager : Disposable { // Rate of low memory after GC notifications in the last 5 minutes: // rate(gitpod_jb_backend_low_memory_after_gc_total[5m]) val lowMemoryCounter = Counter.build() - .name("gitpod_jb_backend_low_memory_after_gc") - .help("Low memory notifications after GC") - .labelNames("product", "qualifier") - .register(registry) + .name("gitpod_jb_backend_low_memory_after_gc") + .help("Low memory notifications after GC") + .labelNames("product", "qualifier") + .register(registry) LowMemoryWatcher.register({ lowMemoryCounter.labels(backendKind, backendQualifier).inc() - }, LowMemoryWatcher.LowMemoryWatcherType.ONLY_AFTER_GC, this) + }, LowMemoryWatcher.LowMemoryWatcherType.ONLY_AFTER_GC, this) } init { @@ -93,7 +112,7 @@ class GitpodManager : Disposable { if (application.isHeadlessEnvironment) { return@launch } - val pg = if(devMode) null else PushGateway("localhost:22999") + val pg = if (devMode) null else PushGateway("localhost:22999") // Heap usage at any time in the last 5 minutes: // max_over_time(gitpod_jb_backend_memory_used_bytes[5m:])/max_over_time(gitpod_jb_backend_memory_max_bytes[5m:]) val allocatedGauge = Gauge.build() @@ -131,20 +150,20 @@ class GitpodManager : Disposable { try { val backendPort = BuiltInServerManager.getInstance().waitForStart().port val httpClient = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS) - .connectTimeout(Duration.ofSeconds(5)) - .build() + .connectTimeout(Duration.ofSeconds(5)) + .build() val httpRequest = HttpRequest.newBuilder() - .uri(URI.create("http://localhost:24000/gatewayLink?backendPort=$backendPort")) - .GET() - .build() + .uri(URI.create("http://localhost:24000/gatewayLink?backendPort=$backendPort")) + .GET() + .build() val response = - httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()) + httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()) if (response.statusCode() == 200) { val gatewayLink = response.body() thisLogger().warn( - "\n\n\n*********************************************************\n\n" + - "Gitpod gateway link: $gatewayLink" + - "\n\n*********************************************************\n\n\n" + "\n\n\n*********************************************************\n\n" + + "Gitpod gateway link: $gatewayLink" + + "\n\n*********************************************************\n\n\n" ) } else { throw Exception("" + response.statusCode()) @@ -159,69 +178,177 @@ class GitpodManager : Disposable { GitVcsApplicationSettings.getInstance().isUseCredentialHelper = true } - val notificationGroup = NotificationGroupManager.getInstance().getNotificationGroup("Gitpod Notifications") - private val notificationsJob = GlobalScope.launch { - if (application.isHeadlessEnvironment) { - return@launch - } - val notifications = NotificationServiceGrpc.newStub(supervisorChannel) - val futureNotifications = NotificationServiceGrpc.newFutureStub(supervisorChannel) - while (isActive) { - try { - val f = CompletableFuture() - notifications.subscribe( - SubscribeRequest.newBuilder().build(), - object : ClientResponseObserver { - - override fun beforeStart(requestStream: ClientCallStreamObserver) { - // TODO(ak): actually should be bound to cancellation of notifications job - lifetime.onTerminationOrNow { - requestStream.cancel(null, null) - } - } - - override fun onNext(n: SubscribeResponse) { - val request = n.request - val type = when (request.level) { - NotifyRequest.Level.ERROR -> NotificationType.ERROR - NotifyRequest.Level.WARNING -> NotificationType.WARNING - else -> NotificationType.INFORMATION - } - val notification = notificationGroup.createNotification(request.message, type) - for (action in request.actionsList) { - notification.addAction(NotificationAction.createSimpleExpiring(action) { - futureNotifications.respond( - RespondRequest.newBuilder() - .setRequestId(n.requestId) - .setResponse(NotifyResponse.newBuilder().setAction(action).build()) - .build() - ) - }) - } - notification.notify(null) - } - - override fun onError(t: Throwable) { - f.completeExceptionally(t) - } - - override fun onCompleted() { - f.complete(null) - } - }) - f.await() - } catch (t: Throwable) { - if (t is CancellationException) { - throw t + init { + observeNotifications(lifetime) + registerActiveNotifications() + } + + private fun registerActiveNotifications() { + val keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager() + + var activeProject: Project? = null + var activeLifetime = Lifetime.Terminated.createNested() + val lock = Object() + val updateActiveNotifications = { + synchronized(lock) { + var project = getActiveProject() + if (project == null || project.isDefault || project.isDisposed || !project.isInitialized) { + project = null + } + if (project != null) { + val session = ClientSessionsManager.getProjectSessions(project, ClientKind.REMOTE).firstOrNull() + if (session == null) { + project = null + } + } + + if (project != activeProject) { + activeLifetime.terminate() + } + activeProject = project + if (activeLifetime.isNotAlive && activeProject != null) { + activeLifetime = lifetime.createNested() + observeNotifications(activeLifetime, activeProject!!) } - thisLogger().error("gitpod: failed to stream notifications: ", t) } - delay(1000L) + } + updateActiveNotifications() + val listener = { _: PropertyChangeEvent -> updateActiveNotifications() } + keyboardFocusManager.addPropertyChangeListener("activeWindow", listener) + lifetime.onTerminationOrNow { + keyboardFocusManager.removePropertyChangeListener("activeWindow", listener) + activeLifetime.terminate() } } - init { + + val notificationGroup = NotificationGroupManager.getInstance().getNotificationGroup("Gitpod Notifications") + val gitpodPortForwardingService = serviceOrNull() + private fun observeNotifications(lifetime: LifetimeDefinition, project: Project? = null) { + val job = lifetime.launch { + if (application.isHeadlessEnvironment) { + return@launch + } + val notifications = NotificationServiceGrpc.newStub(supervisorChannel) + val futureNotifications = NotificationServiceGrpc.newFutureStub(supervisorChannel) + while (isActive) { + try { + val f = CompletableFuture() + notifications.subscribe( + SubscribeRequest.newBuilder().setActive(project != null).build(), + object : ClientResponseObserver { + + override fun beforeStart(requestStream: ClientCallStreamObserver) { + lifetime.onTerminationOrNow { + requestStream.cancel("disposed", null) + } + } + + override fun onNext(n: SubscribeResponse) { + try { + val request = n.request + if (!request.message.isNullOrBlank()) { + val type = when (request.level) { + NotifyRequest.Level.ERROR -> NotificationType.ERROR + NotifyRequest.Level.WARNING -> NotificationType.WARNING + else -> NotificationType.INFORMATION + } + val notification = notificationGroup.createNotification(request.message, type) + for (action in request.actionsList) { + notification.addAction(NotificationAction.createSimpleExpiring(action) { + futureNotifications.respond( + RespondRequest.newBuilder() + .setRequestId(n.requestId) + .setResponse(NotifyResponse.newBuilder().setAction(action).build()) + .build() + ) + }) + } + notification.notify(project) + } + if (project == null) { + return + } + lifetime.launch request@{ + val session = ClientSessionsManager.getProjectSessions(project, ClientKind.REMOTE).firstOrNull() + ?: return@request + ClientId.withClientId(session.clientId) { + if (request.preview != null) { + var resolvedUrl = request.preview.url + val uri = URI.create(request.preview.url) + val localHostUriMetadata = LocalHostUri.extractLocalHostUriMetaDataForPortMapping(uri) + if (localHostUriMetadata.isPresent && gitpodPortForwardingService != null) { + var localHostUriFromPort = Optional.empty() + application.invokeAndWait { + localHostUriFromPort = gitpodPortForwardingService + .getLocalHostUriFromHostPort(localHostUriMetadata.get().port) + } + if (localHostUriFromPort.isPresent) { + resolvedUrl = localHostUriFromPort.get() + .withPath(uri.path) + .withQuery(uri.query) + .withFragment(uri.fragment) + .toString() + } + } + BrowserUtil.browse(resolvedUrl, project) + } + if (request.open != null) { + val futures = ArrayList>() + for (path in request.open.pathsList) { + try { + val file = parseFilePath(path) + futures.add(CommandLineProcessor.doOpenFileOrProject(file, request.open.await).future) + } catch (t: Throwable) { + thisLogger().error("gitpod: failed to open '" + path + "': ", t) + } + } + futures.awaitAll() + } + } + futureNotifications.respond( + RespondRequest.newBuilder() + .setRequestId(n.requestId) + .setResponse(NotifyResponse.newBuilder().build()) + .build() + ) + } + } catch (t: Throwable) { + thisLogger().error("gitpod: failed to process notification request: ", t) + } + } + + override fun onError(t: Throwable) { + f.completeExceptionally(t) + } + + override fun onCompleted() { + f.complete(null) + } + }) + f.await() + } catch (t: Throwable) { + if (t is CancellationException) { + throw t + } + thisLogger().error("gitpod: failed to stream notifications: ", t) + } + delay(1000L) + } + } lifetime.onTerminationOrNow { - notificationsJob.cancel() + job.cancel() + } + } + + private fun parseFilePath(path: String): Path { + return try { + var file: Path = Path.of(FileUtilRt.toSystemDependentName(path)) // handle paths like '/file/foo\qwe' + if (!file.isAbsolute) { + file = file.toAbsolutePath() + } + file.normalize() + } catch (e: InvalidPathException) { + throw Exception("failed to parse file path", e) } } @@ -246,6 +373,7 @@ class GitpodManager : Disposable { pendingInfo.completeExceptionally(t) } } + init { lifetime.onTerminationOrNow { infoJob.cancel() @@ -340,6 +468,7 @@ class GitpodManager : Disposable { } thisLogger().warn("$gitpodHost: connection permanently closed: $closeReason") } + init { lifetime.onTerminationOrNow { serverJob.cancel() @@ -393,6 +522,7 @@ class GitpodManager : Disposable { delay(1000L) } } + init { lifetime.onTerminationOrNow { metricsJob.cancel() diff --git a/components/ide/jetbrains/cli/BUILD.yaml b/components/ide/jetbrains/cli/BUILD.yaml deleted file mode 100644 index fbca84877903e0..00000000000000 --- a/components/ide/jetbrains/cli/BUILD.yaml +++ /dev/null @@ -1,12 +0,0 @@ -packages: - - name: app - type: go - srcs: - - "**/*.go" - - "go.mod" - - "go.sum" - env: - - CGO_ENABLED=0 - - GOOS=linux - config: - packaging: app diff --git a/components/ide/jetbrains/cli/cmd/open.go b/components/ide/jetbrains/cli/cmd/open.go deleted file mode 100644 index e85e9cdc43a164..00000000000000 --- a/components/ide/jetbrains/cli/cmd/open.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package cmd - -import ( - "fmt" - "log" - "net/http" - "path/filepath" - - "github.com/spf13/cobra" -) - -var wait bool - -var openCmd = &cobra.Command{ - Use: "open", - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - file, err := filepath.Abs(args[0]) - if err != nil { - log.Fatal(err) - } - - url := getCliApiUrl() - query := url.Query() - query.Add("op", "open") - query.Add("file", file) - query.Add("wait", fmt.Sprintf("%t", wait)) - url.RawQuery = query.Encode() - - resp, err := http.Get(url.String()) - if err != nil { - log.Fatal(err) - } - if resp.StatusCode != http.StatusOK { - log.Fatal(resp.Status) - } - }, -} - -func init() { - rootCmd.AddCommand(openCmd) - openCmd.Flags().BoolVar(&wait, "wait", false, "") -} diff --git a/components/ide/jetbrains/cli/cmd/preview.go b/components/ide/jetbrains/cli/cmd/preview.go deleted file mode 100644 index 99b9fb451f16dd..00000000000000 --- a/components/ide/jetbrains/cli/cmd/preview.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package cmd - -import ( - "log" - "net/http" - - "github.com/spf13/cobra" -) - -var previewCmd = &cobra.Command{ - Use: "preview", - Run: func(cmd *cobra.Command, args []string) { - url := getCliApiUrl() - query := url.Query() - query.Add("op", "preview") - query.Add("url", args[0]) - url.RawQuery = query.Encode() - - resp, err := http.Get(url.String()) - if err != nil { - log.Fatal(err) - } - if resp.StatusCode != http.StatusOK { - log.Fatal(resp.Status) - } - }, -} - -func init() { - rootCmd.AddCommand(previewCmd) -} diff --git a/components/ide/jetbrains/cli/cmd/root.go b/components/ide/jetbrains/cli/cmd/root.go deleted file mode 100644 index 164a9a6b5ae8ef..00000000000000 --- a/components/ide/jetbrains/cli/cmd/root.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package cmd - -import ( - "errors" - "log" - "net/url" - "os" - "strconv" - - "github.com/spf13/cobra" -) - -var rootCmd = &cobra.Command{ - Use: "idea-cli", -} - -func Execute() { - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } -} - -func getCliApiUrl() *url.URL { - var backendPort = 63342 - // TODO look up under alias + qualifier, i.e. intellij or intellij-latest - if _, fileStatError := os.Stat("/ide-desktop/bin/idea-cli-dev"); !errors.Is(fileStatError, os.ErrNotExist) { - backendPort = backendPort + 1 - } - parsedUrl, urlParseError := url.Parse("http://localhost:" + strconv.Itoa(backendPort) + "/api/gitpod/cli") - if urlParseError != nil { - log.Fatal(urlParseError) - } - return parsedUrl -} - -func init() {} diff --git a/components/ide/jetbrains/cli/go.mod b/components/ide/jetbrains/cli/go.mod deleted file mode 100644 index 8c0b8facd41104..00000000000000 --- a/components/ide/jetbrains/cli/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/gitpod-io/gitpod/jetbrains/cli - -go 1.19 - -require github.com/spf13/cobra v1.4.0 - -require ( - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect -) diff --git a/components/ide/jetbrains/cli/go.sum b/components/ide/jetbrains/cli/go.sum deleted file mode 100644 index 0dd8697bc53c6a..00000000000000 --- a/components/ide/jetbrains/cli/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/components/ide/jetbrains/cli/main.go b/components/ide/jetbrains/cli/main.go deleted file mode 100644 index e71248b236ba90..00000000000000 --- a/components/ide/jetbrains/cli/main.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2022 Gitpod GmbH. All rights reserved. -// Licensed under the GNU Affero General Public License (AGPL). -// See License.AGPL.txt in the project root for license information. - -package main - -import "github.com/gitpod-io/gitpod/jetbrains/cli/cmd" - -func main() { - cmd.Execute() -} diff --git a/components/ide/jetbrains/image/BUILD.js b/components/ide/jetbrains/image/BUILD.js index 1c4e2270c596d1..775a57ba7d65d9 100644 --- a/components/ide/jetbrains/image/BUILD.js +++ b/components/ide/jetbrains/image/BUILD.js @@ -55,7 +55,7 @@ const generateIDEBuildPackage = function (ideConfig, qualifier) { name, type: "docker", srcs: ["startup.sh", `supervisor-ide-config_${name}.json`], - deps: [`:download-${name}`, "components/ide/jetbrains/cli:app"], + deps: [`:download-${name}`], config: { dockerfile: "leeway.Dockerfile", metadata: { diff --git a/components/ide/jetbrains/image/bin/code b/components/ide/jetbrains/image/bin/code deleted file mode 100755 index ee32fd94f65e5e..00000000000000 --- a/components/ide/jetbrains/image/bin/code +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env sh -exec /ide-desktop/bin/idea-cli "$@" \ No newline at end of file diff --git a/components/ide/jetbrains/image/bin/open b/components/ide/jetbrains/image/bin/open deleted file mode 100755 index ee32fd94f65e5e..00000000000000 --- a/components/ide/jetbrains/image/bin/open +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env sh -exec /ide-desktop/bin/idea-cli "$@" \ No newline at end of file diff --git a/components/ide/jetbrains/image/leeway.Dockerfile b/components/ide/jetbrains/image/leeway.Dockerfile index d2f41defe365ca..e7bbe98a96b2a5 100644 --- a/components/ide/jetbrains/image/leeway.Dockerfile +++ b/components/ide/jetbrains/image/leeway.Dockerfile @@ -20,15 +20,4 @@ COPY --chown=33333:33333 components-ide-jetbrains-image--download-${JETBRAINS_DO ARG JETBRAINS_BACKEND_QUALIFIER ENV GITPOD_ENV_SET_JETBRAINS_BACKEND_QUALIFIER ${JETBRAINS_BACKEND_QUALIFIER} -COPY --chown=33333:33333 components-ide-jetbrains-cli--app/cli /ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/bin/idea-cli -ENV GITPOD_ENV_APPEND_PATH /ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/bin: - -# editor config -ENV GITPOD_ENV_SET_EDITOR "/ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/bin/idea-cli open" -ENV GITPOD_ENV_SET_VISUAL "$GITPOD_ENV_SET_EDITOR" -ENV GITPOD_ENV_SET_GP_OPEN_EDITOR "$GITPOD_ENV_SET_EDITOR" -ENV GITPOD_ENV_SET_GIT_EDITOR "$GITPOD_ENV_SET_EDITOR --wait" -ENV GITPOD_ENV_SET_GP_PREVIEW_BROWSER "/ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/bin/idea-cli preview" -ENV GITPOD_ENV_SET_GP_EXTERNAL_BROWSER "/ide-desktop/${JETBRAINS_DOWNLOAD_QUALIFIER}/bin/idea-cli preview" - LABEL "io.gitpod.ide.version"=$JETBRAINS_BACKEND_VERSION diff --git a/components/supervisor-api/go/notification.pb.go b/components/supervisor-api/go/notification.pb.go index f6b2a229cb1856..089fca3073aff3 100644 --- a/components/supervisor-api/go/notification.pb.go +++ b/components/supervisor-api/go/notification.pb.go @@ -83,6 +83,12 @@ type NotifyRequest struct { Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // if actions are empty, Notify will return immediately Actions []string `protobuf:"bytes,3,rep,name=actions,proto3" json:"actions,omitempty"` + // open paths + Open *NotifyRequest_Open `protobuf:"bytes,4,opt,name=open,proto3" json:"open,omitempty"` + // preview a URL + Preview *NotifyRequest_Preview `protobuf:"bytes,5,opt,name=preview,proto3" json:"preview,omitempty"` + // notify active (currently focused) subscribers + Active bool `protobuf:"varint,6,opt,name=active,proto3" json:"active,omitempty"` } func (x *NotifyRequest) Reset() { @@ -138,6 +144,27 @@ func (x *NotifyRequest) GetActions() []string { return nil } +func (x *NotifyRequest) GetOpen() *NotifyRequest_Open { + if x != nil { + return x.Open + } + return nil +} + +func (x *NotifyRequest) GetPreview() *NotifyRequest_Preview { + if x != nil { + return x.Preview + } + return nil +} + +func (x *NotifyRequest) GetActive() bool { + if x != nil { + return x.Active + } + return false +} + type NotifyResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -145,6 +172,8 @@ type NotifyResponse struct { // action chosen by the user or empty string if cancelled Action string `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"` + // command to execute + Command *NotifyResponse_Command `protobuf:"bytes,2,opt,name=command,proto3" json:"command,omitempty"` } func (x *NotifyResponse) Reset() { @@ -186,10 +215,20 @@ func (x *NotifyResponse) GetAction() string { return "" } +func (x *NotifyResponse) GetCommand() *NotifyResponse_Command { + if x != nil { + return x.Command + } + return nil +} + type SubscribeRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // subscriber is active (currently focused) + Active bool `protobuf:"varint,1,opt,name=active,proto3" json:"active,omitempty"` } func (x *SubscribeRequest) Reset() { @@ -224,6 +263,13 @@ func (*SubscribeRequest) Descriptor() ([]byte, []int) { return file_notification_proto_rawDescGZIP(), []int{2} } +func (x *SubscribeRequest) GetActive() bool { + if x != nil { + return x.Active + } + return false +} + type SubscribeResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -372,20 +418,19 @@ func (*RespondResponse) Descriptor() ([]byte, []int) { return file_notification_proto_rawDescGZIP(), []int{5} } -type NotifyActiveRequest struct { +type NotifyRequest_Open struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Types that are assignable to ActionData: - // - // *NotifyActiveRequest_Open - // *NotifyActiveRequest_Preview - ActionData isNotifyActiveRequest_ActionData `protobuf_oneof:"action_data"` + // paths to open + Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"` + // wait until all opened files are closed + Await bool `protobuf:"varint,2,opt,name=await,proto3" json:"await,omitempty"` } -func (x *NotifyActiveRequest) Reset() { - *x = NotifyActiveRequest{} +func (x *NotifyRequest_Open) Reset() { + *x = NotifyRequest_Open{} if protoimpl.UnsafeEnabled { mi := &file_notification_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -393,13 +438,13 @@ func (x *NotifyActiveRequest) Reset() { } } -func (x *NotifyActiveRequest) String() string { +func (x *NotifyRequest_Open) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NotifyActiveRequest) ProtoMessage() {} +func (*NotifyRequest_Open) ProtoMessage() {} -func (x *NotifyActiveRequest) ProtoReflect() protoreflect.Message { +func (x *NotifyRequest_Open) ProtoReflect() protoreflect.Message { mi := &file_notification_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -411,300 +456,52 @@ func (x *NotifyActiveRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NotifyActiveRequest.ProtoReflect.Descriptor instead. -func (*NotifyActiveRequest) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{6} -} - -func (m *NotifyActiveRequest) GetActionData() isNotifyActiveRequest_ActionData { - if m != nil { - return m.ActionData - } - return nil -} - -func (x *NotifyActiveRequest) GetOpen() *NotifyActiveRequest_OpenData { - if x, ok := x.GetActionData().(*NotifyActiveRequest_Open); ok { - return x.Open - } - return nil -} - -func (x *NotifyActiveRequest) GetPreview() *NotifyActiveRequest_PreviewData { - if x, ok := x.GetActionData().(*NotifyActiveRequest_Preview); ok { - return x.Preview - } - return nil -} - -type isNotifyActiveRequest_ActionData interface { - isNotifyActiveRequest_ActionData() -} - -type NotifyActiveRequest_Open struct { - Open *NotifyActiveRequest_OpenData `protobuf:"bytes,1,opt,name=open,proto3,oneof"` -} - -type NotifyActiveRequest_Preview struct { - Preview *NotifyActiveRequest_PreviewData `protobuf:"bytes,2,opt,name=preview,proto3,oneof"` -} - -func (*NotifyActiveRequest_Open) isNotifyActiveRequest_ActionData() {} - -func (*NotifyActiveRequest_Preview) isNotifyActiveRequest_ActionData() {} - -type NotifyActiveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyActiveResponse) Reset() { - *x = NotifyActiveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyActiveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyActiveResponse) ProtoMessage() {} - -func (x *NotifyActiveResponse) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyActiveResponse.ProtoReflect.Descriptor instead. -func (*NotifyActiveResponse) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{7} -} - -type SubscribeActiveRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *SubscribeActiveRequest) Reset() { - *x = SubscribeActiveRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubscribeActiveRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubscribeActiveRequest) ProtoMessage() {} - -func (x *SubscribeActiveRequest) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubscribeActiveRequest.ProtoReflect.Descriptor instead. -func (*SubscribeActiveRequest) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{8} -} - -type SubscribeActiveResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RequestId uint64 `protobuf:"varint,1,opt,name=requestId,proto3" json:"requestId,omitempty"` - Request *NotifyActiveRequest `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` -} - -func (x *SubscribeActiveResponse) Reset() { - *x = SubscribeActiveResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SubscribeActiveResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SubscribeActiveResponse) ProtoMessage() {} - -func (x *SubscribeActiveResponse) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SubscribeActiveResponse.ProtoReflect.Descriptor instead. -func (*SubscribeActiveResponse) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{9} -} - -func (x *SubscribeActiveResponse) GetRequestId() uint64 { - if x != nil { - return x.RequestId - } - return 0 +// Deprecated: Use NotifyRequest_Open.ProtoReflect.Descriptor instead. +func (*NotifyRequest_Open) Descriptor() ([]byte, []int) { + return file_notification_proto_rawDescGZIP(), []int{0, 0} } -func (x *SubscribeActiveResponse) GetRequest() *NotifyActiveRequest { +func (x *NotifyRequest_Open) GetPaths() []string { if x != nil { - return x.Request + return x.Paths } return nil } -type NotifyActiveRespondRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - RequestId uint64 `protobuf:"varint,1,opt,name=requestId,proto3" json:"requestId,omitempty"` - Response *NotifyActiveResponse `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"` -} - -func (x *NotifyActiveRespondRequest) Reset() { - *x = NotifyActiveRespondRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyActiveRespondRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyActiveRespondRequest) ProtoMessage() {} - -func (x *NotifyActiveRespondRequest) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyActiveRespondRequest.ProtoReflect.Descriptor instead. -func (*NotifyActiveRespondRequest) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{10} -} - -func (x *NotifyActiveRespondRequest) GetRequestId() uint64 { - if x != nil { - return x.RequestId - } - return 0 -} - -func (x *NotifyActiveRespondRequest) GetResponse() *NotifyActiveResponse { +func (x *NotifyRequest_Open) GetAwait() bool { if x != nil { - return x.Response - } - return nil -} - -type NotifyActiveRespondResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *NotifyActiveRespondResponse) Reset() { - *x = NotifyActiveRespondResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NotifyActiveRespondResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NotifyActiveRespondResponse) ProtoMessage() {} - -func (x *NotifyActiveRespondResponse) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms + return x.Await } - return mi.MessageOf(x) -} - -// Deprecated: Use NotifyActiveRespondResponse.ProtoReflect.Descriptor instead. -func (*NotifyActiveRespondResponse) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{11} + return false } -// open a file in editor -type NotifyActiveRequest_OpenData struct { +type NotifyRequest_Preview struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Urls []string `protobuf:"bytes,1,rep,name=urls,proto3" json:"urls,omitempty"` - // wait until all opened files are closed - Await bool `protobuf:"varint,2,opt,name=await,proto3" json:"await,omitempty"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + // preview the URL in a new browser tab + External bool `protobuf:"varint,2,opt,name=external,proto3" json:"external,omitempty"` } -func (x *NotifyActiveRequest_OpenData) Reset() { - *x = NotifyActiveRequest_OpenData{} +func (x *NotifyRequest_Preview) Reset() { + *x = NotifyRequest_Preview{} if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[12] + mi := &file_notification_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *NotifyActiveRequest_OpenData) String() string { +func (x *NotifyRequest_Preview) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NotifyActiveRequest_OpenData) ProtoMessage() {} +func (*NotifyRequest_Preview) ProtoMessage() {} -func (x *NotifyActiveRequest_OpenData) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[12] +func (x *NotifyRequest_Preview) ProtoReflect() protoreflect.Message { + mi := &file_notification_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -715,53 +512,51 @@ func (x *NotifyActiveRequest_OpenData) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NotifyActiveRequest_OpenData.ProtoReflect.Descriptor instead. -func (*NotifyActiveRequest_OpenData) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{6, 0} +// Deprecated: Use NotifyRequest_Preview.ProtoReflect.Descriptor instead. +func (*NotifyRequest_Preview) Descriptor() ([]byte, []int) { + return file_notification_proto_rawDescGZIP(), []int{0, 1} } -func (x *NotifyActiveRequest_OpenData) GetUrls() []string { +func (x *NotifyRequest_Preview) GetUrl() string { if x != nil { - return x.Urls + return x.Url } - return nil + return "" } -func (x *NotifyActiveRequest_OpenData) GetAwait() bool { +func (x *NotifyRequest_Preview) GetExternal() bool { if x != nil { - return x.Await + return x.External } return false } -// ask editor to open a URL in its preview -type NotifyActiveRequest_PreviewData struct { +type NotifyResponse_Command struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` - // open the URL in a new browser tab - External bool `protobuf:"varint,2,opt,name=external,proto3" json:"external,omitempty"` + Cmd string `protobuf:"bytes,1,opt,name=cmd,proto3" json:"cmd,omitempty"` + Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"` } -func (x *NotifyActiveRequest_PreviewData) Reset() { - *x = NotifyActiveRequest_PreviewData{} +func (x *NotifyResponse_Command) Reset() { + *x = NotifyResponse_Command{} if protoimpl.UnsafeEnabled { - mi := &file_notification_proto_msgTypes[13] + mi := &file_notification_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *NotifyActiveRequest_PreviewData) String() string { +func (x *NotifyResponse_Command) String() string { return protoimpl.X.MessageStringOf(x) } -func (*NotifyActiveRequest_PreviewData) ProtoMessage() {} +func (*NotifyResponse_Command) ProtoMessage() {} -func (x *NotifyActiveRequest_PreviewData) ProtoReflect() protoreflect.Message { - mi := &file_notification_proto_msgTypes[13] +func (x *NotifyResponse_Command) ProtoReflect() protoreflect.Message { + mi := &file_notification_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -772,23 +567,23 @@ func (x *NotifyActiveRequest_PreviewData) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use NotifyActiveRequest_PreviewData.ProtoReflect.Descriptor instead. -func (*NotifyActiveRequest_PreviewData) Descriptor() ([]byte, []int) { - return file_notification_proto_rawDescGZIP(), []int{6, 1} +// Deprecated: Use NotifyResponse_Command.ProtoReflect.Descriptor instead. +func (*NotifyResponse_Command) Descriptor() ([]byte, []int) { + return file_notification_proto_rawDescGZIP(), []int{1, 0} } -func (x *NotifyActiveRequest_PreviewData) GetUrl() string { +func (x *NotifyResponse_Command) GetCmd() string { if x != nil { - return x.Url + return x.Cmd } return "" } -func (x *NotifyActiveRequest_PreviewData) GetExternal() bool { +func (x *NotifyResponse_Command) GetArgs() []string { if x != nil { - return x.External + return x.Args } - return false + return nil } var File_notification_proto protoreflect.FileDescriptor @@ -797,126 +592,86 @@ var file_notification_proto_rawDesc = []byte{ 0x0a, 0x12, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, - 0x01, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9b, + 0x03, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x29, 0x0a, 0x05, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, - 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x22, 0x28, 0x0a, 0x0e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x12, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x0e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa0, 0x02, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x3e, 0x0a, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4f, - 0x70, 0x65, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x12, - 0x47, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, - 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x1a, 0x34, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x6e, - 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x77, 0x61, 0x69, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x77, 0x61, 0x69, 0x74, 0x1a, 0x3b, - 0x0a, 0x0b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x0d, 0x0a, 0x0b, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x16, 0x0a, 0x14, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x72, 0x0a, 0x17, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, + 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x04, 0x6f, + 0x70, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x52, 0x04, 0x6f, 0x70, 0x65, 0x6e, 0x12, + 0x3b, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x21, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x72, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x52, 0x07, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x16, 0x0a, 0x06, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x1a, 0x32, 0x0a, 0x04, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, + 0x68, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x77, 0x61, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x61, 0x77, 0x61, 0x69, 0x74, 0x1a, 0x37, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x76, + 0x69, 0x65, 0x77, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x22, 0x29, 0x0a, 0x05, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, + 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x22, 0x97, 0x01, 0x0a, + 0x0e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, + 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x2f, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, + 0x6d, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0x2a, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x65, 0x22, 0x66, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x78, 0x0a, 0x1a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x08, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x0a, 0x1b, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb, 0x05, 0x0a, 0x13, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x60, 0x0a, 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x75, - 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, - 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x12, 0x6e, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x12, 0x1c, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x30, 0x01, 0x12, 0x64, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x12, 0x1a, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x75, 0x70, + 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x0e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xcd, 0x02, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x60, 0x0a, + 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, + 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, + 0x6e, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x1c, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x75, 0x70, + 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x30, 0x01, 0x12, + 0x64, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x12, 0x1a, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, - 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x12, 0x87, 0x01, 0x0a, 0x0f, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x12, 0x22, 0x2e, - 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x22, 0x21, - 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2d, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x30, 0x01, 0x12, 0x79, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x12, 0x1f, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, - 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, - 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x1e, - 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x96, - 0x01, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x12, 0x26, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, - 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x79, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, - 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x2d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2d, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x42, 0x46, 0x0a, 0x18, 0x69, 0x6f, 0x2e, 0x67, 0x69, - 0x74, 0x70, 0x6f, 0x64, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, - 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x18, 0x2f, 0x76, 0x31, + 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x42, 0x46, 0x0a, 0x18, 0x69, 0x6f, 0x2e, 0x67, 0x69, 0x74, 0x70, + 0x6f, 0x64, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, + 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -932,49 +687,37 @@ func file_notification_proto_rawDescGZIP() []byte { } var file_notification_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_notification_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_notification_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_notification_proto_goTypes = []interface{}{ - (NotifyRequest_Level)(0), // 0: supervisor.NotifyRequest.Level - (*NotifyRequest)(nil), // 1: supervisor.NotifyRequest - (*NotifyResponse)(nil), // 2: supervisor.NotifyResponse - (*SubscribeRequest)(nil), // 3: supervisor.SubscribeRequest - (*SubscribeResponse)(nil), // 4: supervisor.SubscribeResponse - (*RespondRequest)(nil), // 5: supervisor.RespondRequest - (*RespondResponse)(nil), // 6: supervisor.RespondResponse - (*NotifyActiveRequest)(nil), // 7: supervisor.NotifyActiveRequest - (*NotifyActiveResponse)(nil), // 8: supervisor.NotifyActiveResponse - (*SubscribeActiveRequest)(nil), // 9: supervisor.SubscribeActiveRequest - (*SubscribeActiveResponse)(nil), // 10: supervisor.SubscribeActiveResponse - (*NotifyActiveRespondRequest)(nil), // 11: supervisor.NotifyActiveRespondRequest - (*NotifyActiveRespondResponse)(nil), // 12: supervisor.NotifyActiveRespondResponse - (*NotifyActiveRequest_OpenData)(nil), // 13: supervisor.NotifyActiveRequest.OpenData - (*NotifyActiveRequest_PreviewData)(nil), // 14: supervisor.NotifyActiveRequest.PreviewData + (NotifyRequest_Level)(0), // 0: supervisor.NotifyRequest.Level + (*NotifyRequest)(nil), // 1: supervisor.NotifyRequest + (*NotifyResponse)(nil), // 2: supervisor.NotifyResponse + (*SubscribeRequest)(nil), // 3: supervisor.SubscribeRequest + (*SubscribeResponse)(nil), // 4: supervisor.SubscribeResponse + (*RespondRequest)(nil), // 5: supervisor.RespondRequest + (*RespondResponse)(nil), // 6: supervisor.RespondResponse + (*NotifyRequest_Open)(nil), // 7: supervisor.NotifyRequest.Open + (*NotifyRequest_Preview)(nil), // 8: supervisor.NotifyRequest.Preview + (*NotifyResponse_Command)(nil), // 9: supervisor.NotifyResponse.Command } var file_notification_proto_depIdxs = []int32{ - 0, // 0: supervisor.NotifyRequest.level:type_name -> supervisor.NotifyRequest.Level - 1, // 1: supervisor.SubscribeResponse.request:type_name -> supervisor.NotifyRequest - 2, // 2: supervisor.RespondRequest.response:type_name -> supervisor.NotifyResponse - 13, // 3: supervisor.NotifyActiveRequest.open:type_name -> supervisor.NotifyActiveRequest.OpenData - 14, // 4: supervisor.NotifyActiveRequest.preview:type_name -> supervisor.NotifyActiveRequest.PreviewData - 7, // 5: supervisor.SubscribeActiveResponse.request:type_name -> supervisor.NotifyActiveRequest - 8, // 6: supervisor.NotifyActiveRespondRequest.response:type_name -> supervisor.NotifyActiveResponse - 1, // 7: supervisor.NotificationService.Notify:input_type -> supervisor.NotifyRequest - 3, // 8: supervisor.NotificationService.Subscribe:input_type -> supervisor.SubscribeRequest - 5, // 9: supervisor.NotificationService.Respond:input_type -> supervisor.RespondRequest - 9, // 10: supervisor.NotificationService.SubscribeActive:input_type -> supervisor.SubscribeActiveRequest - 7, // 11: supervisor.NotificationService.NotifyActive:input_type -> supervisor.NotifyActiveRequest - 11, // 12: supervisor.NotificationService.NotifyActiveRespond:input_type -> supervisor.NotifyActiveRespondRequest - 2, // 13: supervisor.NotificationService.Notify:output_type -> supervisor.NotifyResponse - 4, // 14: supervisor.NotificationService.Subscribe:output_type -> supervisor.SubscribeResponse - 6, // 15: supervisor.NotificationService.Respond:output_type -> supervisor.RespondResponse - 10, // 16: supervisor.NotificationService.SubscribeActive:output_type -> supervisor.SubscribeActiveResponse - 8, // 17: supervisor.NotificationService.NotifyActive:output_type -> supervisor.NotifyActiveResponse - 12, // 18: supervisor.NotificationService.NotifyActiveRespond:output_type -> supervisor.NotifyActiveRespondResponse - 13, // [13:19] is the sub-list for method output_type - 7, // [7:13] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 0, // 0: supervisor.NotifyRequest.level:type_name -> supervisor.NotifyRequest.Level + 7, // 1: supervisor.NotifyRequest.open:type_name -> supervisor.NotifyRequest.Open + 8, // 2: supervisor.NotifyRequest.preview:type_name -> supervisor.NotifyRequest.Preview + 9, // 3: supervisor.NotifyResponse.command:type_name -> supervisor.NotifyResponse.Command + 1, // 4: supervisor.SubscribeResponse.request:type_name -> supervisor.NotifyRequest + 2, // 5: supervisor.RespondRequest.response:type_name -> supervisor.NotifyResponse + 1, // 6: supervisor.NotificationService.Notify:input_type -> supervisor.NotifyRequest + 3, // 7: supervisor.NotificationService.Subscribe:input_type -> supervisor.SubscribeRequest + 5, // 8: supervisor.NotificationService.Respond:input_type -> supervisor.RespondRequest + 2, // 9: supervisor.NotificationService.Notify:output_type -> supervisor.NotifyResponse + 4, // 10: supervisor.NotificationService.Subscribe:output_type -> supervisor.SubscribeResponse + 6, // 11: supervisor.NotificationService.Respond:output_type -> supervisor.RespondResponse + 9, // [9:12] is the sub-list for method output_type + 6, // [6:9] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_notification_proto_init() } @@ -1056,7 +799,7 @@ func file_notification_proto_init() { } } file_notification_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveRequest); i { + switch v := v.(*NotifyRequest_Open); i { case 0: return &v.state case 1: @@ -1068,7 +811,7 @@ func file_notification_proto_init() { } } file_notification_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveResponse); i { + switch v := v.(*NotifyRequest_Preview); i { case 0: return &v.state case 1: @@ -1080,43 +823,7 @@ func file_notification_proto_init() { } } file_notification_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubscribeActiveRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_notification_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubscribeActiveResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_notification_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveRespondRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_notification_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveRespondResponse); i { + switch v := v.(*NotifyResponse_Command); i { case 0: return &v.state case 1: @@ -1127,34 +834,6 @@ func file_notification_proto_init() { return nil } } - file_notification_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveRequest_OpenData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_notification_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotifyActiveRequest_PreviewData); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_notification_proto_msgTypes[6].OneofWrappers = []interface{}{ - (*NotifyActiveRequest_Open)(nil), - (*NotifyActiveRequest_Preview)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -1162,7 +841,7 @@ func file_notification_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_notification_proto_rawDesc, NumEnums: 1, - NumMessages: 14, + NumMessages: 9, NumExtensions: 0, NumServices: 1, }, diff --git a/components/supervisor-api/go/notification.pb.gw.go b/components/supervisor-api/go/notification.pb.gw.go index 6b3d48f981628d..a65ebba7391051 100644 --- a/components/supervisor-api/go/notification.pb.gw.go +++ b/components/supervisor-api/go/notification.pb.gw.go @@ -71,10 +71,21 @@ func local_request_NotificationService_Notify_0(ctx context.Context, marshaler r } +var ( + filter_NotificationService_Subscribe_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_NotificationService_Subscribe_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (NotificationService_SubscribeClient, runtime.ServerMetadata, error) { var protoReq SubscribeRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotificationService_Subscribe_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + stream, err := client.Subscribe(ctx, &protoReq) if err != nil { return nil, metadata, err @@ -124,95 +135,6 @@ func local_request_NotificationService_Respond_0(ctx context.Context, marshaler } -func request_NotificationService_SubscribeActive_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (NotificationService_SubscribeActiveClient, runtime.ServerMetadata, error) { - var protoReq SubscribeActiveRequest - var metadata runtime.ServerMetadata - - stream, err := client.SubscribeActive(ctx, &protoReq) - if err != nil { - return nil, metadata, err - } - header, err := stream.Header() - if err != nil { - return nil, metadata, err - } - metadata.HeaderMD = header - return stream, metadata, nil - -} - -var ( - filter_NotificationService_NotifyActive_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_NotificationService_NotifyActive_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq NotifyActiveRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotificationService_NotifyActive_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.NotifyActive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_NotificationService_NotifyActive_0(ctx context.Context, marshaler runtime.Marshaler, server NotificationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq NotifyActiveRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotificationService_NotifyActive_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.NotifyActive(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_NotificationService_NotifyActiveRespond_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_NotificationService_NotifyActiveRespond_0(ctx context.Context, marshaler runtime.Marshaler, client NotificationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq NotifyActiveRespondRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotificationService_NotifyActiveRespond_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.NotifyActiveRespond(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_NotificationService_NotifyActiveRespond_0(ctx context.Context, marshaler runtime.Marshaler, server NotificationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq NotifyActiveRespondRequest - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_NotificationService_NotifyActiveRespond_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.NotifyActiveRespond(ctx, &protoReq) - return msg, metadata, err - -} - // RegisterNotificationServiceHandlerServer registers the http handlers for service NotificationService to "mux". // UnaryRPC :call NotificationServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -276,63 +198,6 @@ func RegisterNotificationServiceHandlerServer(ctx context.Context, mux *runtime. }) - mux.Handle("POST", pattern_NotificationService_SubscribeActive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport") - _, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - }) - - mux.Handle("POST", pattern_NotificationService_NotifyActive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/supervisor.NotificationService/NotifyActive", runtime.WithHTTPPathPattern("/v1/notification/notify-action")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_NotificationService_NotifyActive_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_NotificationService_NotifyActive_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_NotificationService_NotifyActiveRespond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/supervisor.NotificationService/NotifyActiveRespond", runtime.WithHTTPPathPattern("/v1/notification/notify-action-respond")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_NotificationService_NotifyActiveRespond_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_NotificationService_NotifyActiveRespond_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -440,72 +305,6 @@ func RegisterNotificationServiceHandlerClient(ctx context.Context, mux *runtime. }) - mux.Handle("POST", pattern_NotificationService_SubscribeActive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/supervisor.NotificationService/SubscribeActive", runtime.WithHTTPPathPattern("/v1/notification/subscribe-active")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_NotificationService_SubscribeActive_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_NotificationService_SubscribeActive_0(annotatedContext, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_NotificationService_NotifyActive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/supervisor.NotificationService/NotifyActive", runtime.WithHTTPPathPattern("/v1/notification/notify-action")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_NotificationService_NotifyActive_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_NotificationService_NotifyActive_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_NotificationService_NotifyActiveRespond_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/supervisor.NotificationService/NotifyActiveRespond", runtime.WithHTTPPathPattern("/v1/notification/notify-action-respond")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_NotificationService_NotifyActiveRespond_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_NotificationService_NotifyActiveRespond_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -515,12 +314,6 @@ var ( pattern_NotificationService_Subscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "notification", "subscribe"}, "")) pattern_NotificationService_Respond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "notification", "respond"}, "")) - - pattern_NotificationService_SubscribeActive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "notification", "subscribe-active"}, "")) - - pattern_NotificationService_NotifyActive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "notification", "notify-action"}, "")) - - pattern_NotificationService_NotifyActiveRespond_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "notification", "notify-action-respond"}, "")) ) var ( @@ -529,10 +322,4 @@ var ( forward_NotificationService_Subscribe_0 = runtime.ForwardResponseStream forward_NotificationService_Respond_0 = runtime.ForwardResponseMessage - - forward_NotificationService_SubscribeActive_0 = runtime.ForwardResponseStream - - forward_NotificationService_NotifyActive_0 = runtime.ForwardResponseMessage - - forward_NotificationService_NotifyActiveRespond_0 = runtime.ForwardResponseMessage ) diff --git a/components/supervisor-api/go/notification_grpc.pb.go b/components/supervisor-api/go/notification_grpc.pb.go index 7172cc6413b0f7..a0a29b4de2e7ba 100644 --- a/components/supervisor-api/go/notification_grpc.pb.go +++ b/components/supervisor-api/go/notification_grpc.pb.go @@ -35,19 +35,6 @@ type NotificationServiceClient interface { // Report a user's choice as a response to a notification. Typically called by // the IDE. Respond(ctx context.Context, in *RespondRequest, opts ...grpc.CallOption) (*RespondResponse, error) - // Called by the IDE to inform supervisor about which is the latest client - // actively used by the user. We consider active the last IDE with focus. - // Only 1 stream is kept open at any given time. A new subscription - // overrides the previous one, causing the stream to close. - // Supervisor will respond with a stream to which the IDE will listen - // waiting to receive actions to run, for example: `open` or `preview` - SubscribeActive(ctx context.Context, in *SubscribeActiveRequest, opts ...grpc.CallOption) (NotificationService_SubscribeActiveClient, error) - // Used by gp-cli to ask supervisor to request the active client - // to run a given command (eg. open or preview) - NotifyActive(ctx context.Context, in *NotifyActiveRequest, opts ...grpc.CallOption) (*NotifyActiveResponse, error) - // Used by the IDE to inform supervisor about the result (eg. success or - // failure) of the action (eg. open or preview) requested via NotifyActive - NotifyActiveRespond(ctx context.Context, in *NotifyActiveRespondRequest, opts ...grpc.CallOption) (*NotifyActiveRespondResponse, error) } type notificationServiceClient struct { @@ -108,56 +95,6 @@ func (c *notificationServiceClient) Respond(ctx context.Context, in *RespondRequ return out, nil } -func (c *notificationServiceClient) SubscribeActive(ctx context.Context, in *SubscribeActiveRequest, opts ...grpc.CallOption) (NotificationService_SubscribeActiveClient, error) { - stream, err := c.cc.NewStream(ctx, &NotificationService_ServiceDesc.Streams[1], "/supervisor.NotificationService/SubscribeActive", opts...) - if err != nil { - return nil, err - } - x := ¬ificationServiceSubscribeActiveClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type NotificationService_SubscribeActiveClient interface { - Recv() (*SubscribeActiveResponse, error) - grpc.ClientStream -} - -type notificationServiceSubscribeActiveClient struct { - grpc.ClientStream -} - -func (x *notificationServiceSubscribeActiveClient) Recv() (*SubscribeActiveResponse, error) { - m := new(SubscribeActiveResponse) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *notificationServiceClient) NotifyActive(ctx context.Context, in *NotifyActiveRequest, opts ...grpc.CallOption) (*NotifyActiveResponse, error) { - out := new(NotifyActiveResponse) - err := c.cc.Invoke(ctx, "/supervisor.NotificationService/NotifyActive", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *notificationServiceClient) NotifyActiveRespond(ctx context.Context, in *NotifyActiveRespondRequest, opts ...grpc.CallOption) (*NotifyActiveRespondResponse, error) { - out := new(NotifyActiveRespondResponse) - err := c.cc.Invoke(ctx, "/supervisor.NotificationService/NotifyActiveRespond", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // NotificationServiceServer is the server API for NotificationService service. // All implementations must embed UnimplementedNotificationServiceServer // for forward compatibility @@ -171,19 +108,6 @@ type NotificationServiceServer interface { // Report a user's choice as a response to a notification. Typically called by // the IDE. Respond(context.Context, *RespondRequest) (*RespondResponse, error) - // Called by the IDE to inform supervisor about which is the latest client - // actively used by the user. We consider active the last IDE with focus. - // Only 1 stream is kept open at any given time. A new subscription - // overrides the previous one, causing the stream to close. - // Supervisor will respond with a stream to which the IDE will listen - // waiting to receive actions to run, for example: `open` or `preview` - SubscribeActive(*SubscribeActiveRequest, NotificationService_SubscribeActiveServer) error - // Used by gp-cli to ask supervisor to request the active client - // to run a given command (eg. open or preview) - NotifyActive(context.Context, *NotifyActiveRequest) (*NotifyActiveResponse, error) - // Used by the IDE to inform supervisor about the result (eg. success or - // failure) of the action (eg. open or preview) requested via NotifyActive - NotifyActiveRespond(context.Context, *NotifyActiveRespondRequest) (*NotifyActiveRespondResponse, error) mustEmbedUnimplementedNotificationServiceServer() } @@ -200,15 +124,6 @@ func (UnimplementedNotificationServiceServer) Subscribe(*SubscribeRequest, Notif func (UnimplementedNotificationServiceServer) Respond(context.Context, *RespondRequest) (*RespondResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Respond not implemented") } -func (UnimplementedNotificationServiceServer) SubscribeActive(*SubscribeActiveRequest, NotificationService_SubscribeActiveServer) error { - return status.Errorf(codes.Unimplemented, "method SubscribeActive not implemented") -} -func (UnimplementedNotificationServiceServer) NotifyActive(context.Context, *NotifyActiveRequest) (*NotifyActiveResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method NotifyActive not implemented") -} -func (UnimplementedNotificationServiceServer) NotifyActiveRespond(context.Context, *NotifyActiveRespondRequest) (*NotifyActiveRespondResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method NotifyActiveRespond not implemented") -} func (UnimplementedNotificationServiceServer) mustEmbedUnimplementedNotificationServiceServer() {} // UnsafeNotificationServiceServer may be embedded to opt out of forward compatibility for this service. @@ -279,63 +194,6 @@ func _NotificationService_Respond_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } -func _NotificationService_SubscribeActive_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(SubscribeActiveRequest) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(NotificationServiceServer).SubscribeActive(m, ¬ificationServiceSubscribeActiveServer{stream}) -} - -type NotificationService_SubscribeActiveServer interface { - Send(*SubscribeActiveResponse) error - grpc.ServerStream -} - -type notificationServiceSubscribeActiveServer struct { - grpc.ServerStream -} - -func (x *notificationServiceSubscribeActiveServer) Send(m *SubscribeActiveResponse) error { - return x.ServerStream.SendMsg(m) -} - -func _NotificationService_NotifyActive_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NotifyActiveRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(NotificationServiceServer).NotifyActive(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/supervisor.NotificationService/NotifyActive", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(NotificationServiceServer).NotifyActive(ctx, req.(*NotifyActiveRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _NotificationService_NotifyActiveRespond_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(NotifyActiveRespondRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(NotificationServiceServer).NotifyActiveRespond(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/supervisor.NotificationService/NotifyActiveRespond", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(NotificationServiceServer).NotifyActiveRespond(ctx, req.(*NotifyActiveRespondRequest)) - } - return interceptor(ctx, in, info, handler) -} - // NotificationService_ServiceDesc is the grpc.ServiceDesc for NotificationService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -351,14 +209,6 @@ var NotificationService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Respond", Handler: _NotificationService_Respond_Handler, }, - { - MethodName: "NotifyActive", - Handler: _NotificationService_NotifyActive_Handler, - }, - { - MethodName: "NotifyActiveRespond", - Handler: _NotificationService_NotifyActiveRespond_Handler, - }, }, Streams: []grpc.StreamDesc{ { @@ -366,11 +216,6 @@ var NotificationService_ServiceDesc = grpc.ServiceDesc{ Handler: _NotificationService_Subscribe_Handler, ServerStreams: true, }, - { - StreamName: "SubscribeActive", - Handler: _NotificationService_SubscribeActive_Handler, - ServerStreams: true, - }, }, Metadata: "notification.proto", } diff --git a/components/supervisor-api/notification.proto b/components/supervisor-api/notification.proto index 0477c2bc349ccf..fa02bfcdef8aed 100644 --- a/components/supervisor-api/notification.proto +++ b/components/supervisor-api/notification.proto @@ -39,35 +39,6 @@ service NotificationService { }; } - // Called by the IDE to inform supervisor about which is the latest client - // actively used by the user. We consider active the last IDE with focus. - // Only 1 stream is kept open at any given time. A new subscription - // overrides the previous one, causing the stream to close. - // Supervisor will respond with a stream to which the IDE will listen - // waiting to receive actions to run, for example: `open` or `preview` - rpc SubscribeActive(SubscribeActiveRequest) - returns (stream SubscribeActiveResponse) { - option (google.api.http) = { - post : "/v1/notification/subscribe-active" - }; - } - - // Used by gp-cli to ask supervisor to request the active client - // to run a given command (eg. open or preview) - rpc NotifyActive(NotifyActiveRequest) returns (NotifyActiveResponse) { - option (google.api.http) = { - post : "/v1/notification/notify-action" - }; - } - - // Used by the IDE to inform supervisor about the result (eg. success or - // failure) of the action (eg. open or preview) requested via NotifyActive - rpc NotifyActiveRespond(NotifyActiveRespondRequest) - returns (NotifyActiveRespondResponse) { - option (google.api.http) = { - post : "/v1/notification/notify-action-respond" - }; - } } message NotifyRequest { @@ -80,60 +51,53 @@ message NotifyRequest { string message = 2; // if actions are empty, Notify will return immediately repeated string actions = 3; -} - -message NotifyResponse { - // action chosen by the user or empty string if cancelled - string action = 1; -} -message SubscribeRequest {} - -message SubscribeResponse { - uint64 requestId = 1; - NotifyRequest request = 2; -} - -message RespondRequest { - uint64 requestId = 1; - NotifyResponse response = 2; -} - -message RespondResponse {} - -message NotifyActiveRequest { - // open a file in editor - message OpenData { - repeated string urls = 1; + message Open { + // paths to open + repeated string paths = 1; // wait until all opened files are closed bool await = 2; } + // open paths + Open open = 4; - // ask editor to open a URL in its preview - message PreviewData { + message Preview { string url = 1; - // open the URL in a new browser tab + // preview the URL in a new browser tab bool external = 2; } + // preview a URL + Preview preview = 5; - oneof action_data { - OpenData open = 1; - PreviewData preview = 2; - } + // notify active (currently focused) subscribers + bool active = 6; } -message NotifyActiveResponse {} +message NotifyResponse { + // action chosen by the user or empty string if cancelled + string action = 1; -message SubscribeActiveRequest {} + message Command { + string cmd = 1; + repeated string args = 2; + } + // command to execute + Command command = 2; +} + +message SubscribeRequest { + // subscriber is active (currently focused) + bool active = 1; +} -message SubscribeActiveResponse { +message SubscribeResponse { uint64 requestId = 1; - NotifyActiveRequest request = 2; + NotifyRequest request = 2; } -message NotifyActiveRespondRequest { +message RespondRequest { uint64 requestId = 1; - NotifyActiveResponse response = 2; + NotifyResponse response = 2; } -message NotifyActiveRespondResponse {} +message RespondResponse {} diff --git a/components/supervisor/hot-swap.sh b/components/supervisor/hot-swap.sh index 3cb25b65763dbb..7c88df4d9eb163 100755 --- a/components/supervisor/hot-swap.sh +++ b/components/supervisor/hot-swap.sh @@ -1,31 +1,50 @@ #!/bin/bash -# Copyright (c) 2022 Gitpod GmbH. All rights reserved. +# Copyright (c) 2023 Gitpod GmbH. All rights reserved. # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. set -Eeuo pipefail component=${PWD##*/} -workspaceUrl=$(echo "${1}" |sed -e "s/\/$//") -echo "URL: $workspaceUrl" +workspaceURL=$(echo "${1}" |sed -e "s/\/$//") +echo "Workspace URL: $workspaceURL" -workspaceDesc=$(gpctl workspaces describe "$workspaceUrl" -o=json) +workspaceHost=${workspaceURL//https:\/\//} +echo "Workspace Host: $workspaceHost" -podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) -echo "Pod: $podName" +workspaceID=$(echo "${workspaceHost}" | cut -d. -f1) +echo "Workspace ID: $workspaceID" -workspaceId=$(echo "$workspaceDesc" | jq .metadata.meta_id -r) -echo "ID: $workspaceId" - -clusterHost=$(kubectl exec -it "$podName" -- printenv GITPOD_WORKSPACE_CLUSTER_HOST |sed -e "s/\s//g") +clusterHost=${workspaceHost//$workspaceID./} echo "Cluster Host: $clusterHost" -# prepare ssh -ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) +devClusterHost=$(gp info --json |jq .cluster_host -r) +echo "Dev Cluster Host: $devClusterHost" + +preview=true +if [[ $clusterHost = "$devClusterHost" ]] +then + preview=false +fi +echo "Preview Env: $preview" + +# prepare ssh config sshConfig=$(mktemp) -echo "Host $workspaceId" > "$sshConfig" -echo " Hostname \"$workspaceId.ssh.$clusterHost\"" >> "$sshConfig" -echo " User \"$workspaceId#$ownerToken\"" >> "$sshConfig" +echo "Host $workspaceID" > "$sshConfig" +echo " Hostname \"$workspaceID.ssh.$clusterHost\"" >> "$sshConfig" +if [ $preview = "true" ] +then + workspaceDesc=$(gpctl workspaces describe "$workspaceURL" -o=json) + + podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) + echo "Workspace Pod: $podName" + + ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) + echo " User \"$workspaceID#$ownerToken\"" >> "$sshConfig" +else + # assume SSH keys configured via .dotfiles + echo " User \"$workspaceID\"" >> "$sshConfig" +fi # build go build . @@ -34,7 +53,7 @@ echo "$component built" # upload uploadDest="/.supervisor/$component" echo "Upload Dest: $uploadDest" -ssh -F "$sshConfig" "$workspaceId" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" +ssh -F "$sshConfig" "$workspaceID" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" echo "Permissions granted" -scp -F "$sshConfig" -r "./$component" "$workspaceId":"$uploadDest" +scp -F "$sshConfig" -r "./$component" "$workspaceID":"$uploadDest" echo "Swap complete" diff --git a/components/supervisor/pkg/supervisor/notification.go b/components/supervisor/pkg/supervisor/notification.go index 98fb194e11aef8..351e86482c98ba 100644 --- a/components/supervisor/pkg/supervisor/notification.go +++ b/components/supervisor/pkg/supervisor/notification.go @@ -33,9 +33,11 @@ func NewNotificationService() *NotificationService { // NotificationService implements the notification service API. type NotificationService struct { - mutex sync.Mutex - nextSubscriptionID uint64 - subscriptions map[uint64]*subscription + mutex sync.Mutex + + nextSubscriptionID uint64 + subscriptions map[uint64]*subscription + nextNotificationID uint64 pendingNotifications map[uint64]*pendingNotification @@ -58,6 +60,7 @@ func (pending *pendingNotification) close() { type subscription struct { id uint64 + active bool channel chan *api.SubscribeResponse once sync.Once closed bool @@ -123,6 +126,9 @@ func (srv *NotificationService) notifySubscribers(req *api.NotifyRequest) *pendi ) srv.nextNotificationID++ for _, subscription := range srv.subscriptions { + if !subscription.supports(req) { + continue + } select { case subscription.channel <- message: // all good @@ -139,7 +145,7 @@ func (srv *NotificationService) notifySubscribers(req *api.NotifyRequest) *pendi responseChannel: channel, } srv.pendingNotifications[requestID] = pending - if len(req.Actions) == 0 { + if !isBlocking(req) { // produce an immediate response channel <- &api.NotifyResponse{} pending.close() @@ -147,10 +153,18 @@ func (srv *NotificationService) notifySubscribers(req *api.NotifyRequest) *pendi return pending } +func isBlocking(req *api.NotifyRequest) bool { + return len(req.Actions) > 0 || req.Open != nil || req.Preview != nil +} + +func (s *subscription) supports(req *api.NotifyRequest) bool { + return s.active == req.Active +} + // Subscribe subscribes to notifications that are sent to the supervisor. func (srv *NotificationService) Subscribe(req *api.SubscribeRequest, resp api.NotificationService_SubscribeServer) error { - log.WithField("SubscribeRequest", req).Info("Subscribe entered") - defer log.WithField("SubscribeRequest", req).Info("Subscribe exited") + log.WithField("SubscribeRequest", req).Debug("Subscribe entered") + defer log.WithField("SubscribeRequest", req).Debug("Subscribe exited") subscription := srv.subscribeLocked(req, resp) defer srv.unsubscribeLocked(subscription.id) for { @@ -164,7 +178,7 @@ func (srv *NotificationService) Subscribe(req *api.SubscribeRequest, resp api.No return status.Errorf(codes.Internal, "Sending notification failed. %s", err) } case <-resp.Context().Done(): - log.WithField("SubscribeRequest", req).Info("Subscriber cancelled") + log.WithField("SubscribeRequest", req).Debug("Subscriber cancelled") return nil } } @@ -179,22 +193,28 @@ func (srv *NotificationService) subscribeLocked(req *api.SubscribeRequest, resp capacity = SubscriberMaxPendingNotifications } channel := make(chan *api.SubscribeResponse, capacity) - log.WithField("pending", len(srv.pendingNotifications)).Info("sending pending notifications") - for id, pending := range srv.pendingNotifications { - channel <- pending.message - if len(pending.message.Request.Actions) == 0 { - delete(srv.pendingNotifications, id) - } - } id := srv.nextSubscriptionID srv.nextSubscriptionID++ _, cancel := context.WithCancel(resp.Context()) subscription := &subscription{ + active: req.Active, channel: channel, id: id, cancel: cancel, } srv.subscriptions[id] = subscription + + log.WithField("pending", len(srv.pendingNotifications)).Debug("sending pending notifications") + for id, pending := range srv.pendingNotifications { + if !subscription.supports(pending.message.Request) { + continue + } + channel <- pending.message + if !isBlocking(pending.message.Request) { + delete(srv.pendingNotifications, id) + } + } + return subscription } @@ -216,18 +236,16 @@ func (srv *NotificationService) Respond(ctx context.Context, req *api.RespondReq defer srv.mutex.Unlock() pending, ok := srv.pendingNotifications[req.RequestId] if !ok { - log.WithFields(map[string]interface{}{ - "RequestId": req.RequestId, - "Action": req.Response.Action, - }).Info("Invalid or late response to notification") - return nil, status.Errorf(codes.DeadlineExceeded, "Invalid or late response to notification") + log.WithField("requestId", req.RequestId).Info("invalid or late response to notification") + return nil, status.Errorf(codes.DeadlineExceeded, "invalid or late response to notification") } - if !isActionAllowed(req.Response.Action, pending.message.Request) { + if !validateResponse(req.Response, pending.message.Request) { log.WithFields(map[string]interface{}{ "Notification": pending.message, "Action": req.Response.Action, - }).Error("Invalid user action on notification") - return nil, status.Errorf(codes.InvalidArgument, "Invalid user action on notification") + "Command": req.Response.Command, + }).Error("invalid notification") + return nil, status.Errorf(codes.InvalidArgument, "invalid notification") } if !pending.closed { pending.responseChannel <- req.Response @@ -237,13 +255,16 @@ func (srv *NotificationService) Respond(ctx context.Context, req *api.RespondReq return &api.RespondResponse{}, nil } -func isActionAllowed(action string, req *api.NotifyRequest) bool { - if action == "" { +func validateResponse(resp *api.NotifyResponse, req *api.NotifyRequest) bool { + if resp.Command != nil { + return resp.Command.Cmd != "" + } + if resp.Action == "" { // user cancelled, which is always allowed return true } for _, allowedAction := range req.Actions { - if allowedAction == action { + if allowedAction == resp.Action { return true } } diff --git a/components/supervisor/pkg/supervisor/supervisor.go b/components/supervisor/pkg/supervisor/supervisor.go index 547951142570d7..53083ad6c2996e 100644 --- a/components/supervisor/pkg/supervisor/supervisor.go +++ b/components/supervisor/pkg/supervisor/supervisor.go @@ -998,6 +998,16 @@ func buildChildProcEnv(cfg *Config, envvars []string, runGP bool) []string { envs["JAVA_TOOL_OPTIONS"] += fmt.Sprintf(" -Xmx%sm", mem) } + if envs["EDITOR"] == "" { + envs["EDITOR"] = "gp open" + } + if envs["VISUAL"] == "" { + envs["VISUAL"] = "gp open" + } + if envs["GIT_EDITOR"] == "" { + envs["GIT_EDITOR"] = "gp open --wait" + } + var env, envn []string for nme, val := range envs { log.WithField("envvar", nme).Debug("passing environment variable to IDE") diff --git a/components/supervisor/pkg/supervisor/supervisor_test.go b/components/supervisor/pkg/supervisor/supervisor_test.go index 911ee832b70f59..938b62b50a6551 100644 --- a/components/supervisor/pkg/supervisor/supervisor_test.go +++ b/components/supervisor/pkg/supervisor/supervisor_test.go @@ -21,6 +21,9 @@ func TestBuildChildProcEnv(t *testing.T) { "SUPERVISOR_ADDR=localhost:8080", "HOME=/home/gitpod", "USER=gitpod", + "VISUAL=gp open", + "EDITOR=gp open", + "GIT_EDITOR=gp open --wait", ) } @@ -88,13 +91,13 @@ func TestBuildChildProcEnv(t *testing.T) { Name: "ots", Input: []string{}, OTS: `[{"name":"foo","value":"bar"},{"name":"GITPOD_TOKENS","value":"foobar"}]`, - Expectation: []string{"HOME=/home/gitpod", "SUPERVISOR_ADDR=localhost:8080", "USER=gitpod", "foo=bar"}, + Expectation: withBaseline([]string{"foo=bar"}), }, { Name: "failed ots", Input: []string{}, OTS: `invalid json`, - Expectation: []string{"HOME=/home/gitpod", "SUPERVISOR_ADDR=localhost:8080", "USER=gitpod"}, + Expectation: withBaseline(nil), }, }