1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

added common/ipc-helpers

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-07-07 15:10:43 +03:00
parent 17cd886ce6
commit bde60b1625
8 changed files with 83 additions and 51 deletions

View File

@ -179,6 +179,7 @@
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"handlebars": "^4.7.6", "handlebars": "^4.7.6",
"http-proxy": "^1.18.1", "http-proxy": "^1.18.1",
"immer": "^7.0.5",
"js-yaml": "^3.14.0", "js-yaml": "^3.14.0",
"jsonpath": "^1.0.2", "jsonpath": "^1.0.2",
"lodash": "^4.17.15", "lodash": "^4.17.15",

View File

@ -1,6 +1,7 @@
import path from "path" import path from "path"
import Config from "conf" import Config from "conf"
import { Options as ConfOptions } from "conf/dist/source/types" import { Options as ConfOptions } from "conf/dist/source/types"
import produce from "immer";
import { app, remote } from "electron" import { app, remote } from "electron"
import { observable, reaction, toJS, when } from "mobx"; import { observable, reaction, toJS, when } from "mobx";
import Singleton from "./utils/singleton"; import Singleton from "./utils/singleton";
@ -115,6 +116,10 @@ export class BaseStore<T = any> extends Singleton {
Object.assign(this.data, data); Object.assign(this.data, data);
} }
merge(updater: (modelDraft: T) => void) {
this.data = produce(this.data, updater);
}
toJSON(): T { toJSON(): T {
return toJS(this.data, { return toJS(this.data, {
recurseEverything: true, recurseEverything: true,

39
src/common/ipc-helpers.ts Normal file
View File

@ -0,0 +1,39 @@
// Inter-protocol communications (main <-> renderer)
// https://www.electronjs.org/docs/api/ipc-main
// https://www.electronjs.org/docs/api/ipc-renderer
import { ipcMain, ipcRenderer } from "electron"
import logger from "../main/logger";
export interface IpcOptions {
timeout?: number;
}
export async function sendMessage(channel: string, ...args: any[]) {
logger.debug(`[IPC]: invoke "${channel}" with arguments`, args);
return ipcRenderer.invoke(channel, ...args);
}
// todo: maybe spawn callback in separate thread/worker
export function onMessage<T = any>(channel: string, callback: (...args: any[]) => T, options: IpcOptions = {}) {
const { timeout = 0 } = options;
ipcMain.handle(channel, async (event, ...args: any[]) => {
logger.debug(`[IPC]: handle "${channel}"`, event, args);
return new Promise(async (resolve, reject) => {
let timerId;
if (timeout) {
timerId = setTimeout(() => {
const timeoutError = new Error("[IPC]: response timeout");
reject(timeoutError);
}, timeout);
}
try {
const result = await callback(...args);
clearTimeout(timerId);
return result;
} catch (err) {
logger.debug(`[IPC]: handling "${channel}" error`, err);
}
})
})
}

View File

@ -2,6 +2,8 @@ import { app, remote } from "electron"
import { ensureDirSync, writeFileSync } from "fs-extra" import { ensureDirSync, writeFileSync } from "fs-extra"
import * as path from "path" import * as path from "path"
// todo: move to main/kubeconfig-manager.ts (?)
// Writes kubeconfigs to "embedded" store, i.e. .../Lens/kubeconfigs/ // Writes kubeconfigs to "embedded" store, i.e. .../Lens/kubeconfigs/
export function writeEmbeddedKubeConfig(clusterId: string, kubeConfig: string): string { export function writeEmbeddedKubeConfig(clusterId: string, kubeConfig: string): string {
// This can be called from main & renderer // This can be called from main & renderer

View File

@ -7,7 +7,6 @@ import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from
import * as fm from "./feature-manager"; import * as fm from "./feature-manager";
import { Kubectl } from "./kubectl"; import { Kubectl } from "./kubectl";
import { KubeconfigManager } from "./kubeconfig-manager" import { KubeconfigManager } from "./kubeconfig-manager"
import { PromiseIpc } from "electron-promise-ipc"
import request from "request-promise-native" import request from "request-promise-native"
import { apiPrefix } from "../common/vars"; import { apiPrefix } from "../common/vars";
import type { ClusterInfo } from "../renderer/_vue/store/modules/clusters"; import type { ClusterInfo } from "../renderer/_vue/store/modules/clusters";
@ -40,12 +39,10 @@ export class Cluster implements ClusterModel {
public preferences: ClusterPreferences; public preferences: ClusterPreferences;
protected eventPoller: NodeJS.Timeout; protected eventPoller: NodeJS.Timeout;
protected promiseIpc = new PromiseIpc({ timeout: 2000 })
protected kubeconfigManager: KubeconfigManager; protected kubeconfigManager: KubeconfigManager;
constructor(jsonModel: ClusterModel) { constructor(model: ClusterModel) {
if (jsonModel) Object.assign(this, jsonModel) if (model) Object.assign(this, model)
if (!this.preferences) this.preferences = {} if (!this.preferences) this.preferences = {}
} }
@ -64,7 +61,6 @@ export class Cluster implements ClusterModel {
this.contextHandler = new ContextHandler(kc, this) this.contextHandler = new ContextHandler(kc, this)
await this.contextHandler.init() // So we get the proxy port reserved await this.contextHandler.init() // So we get the proxy port reserved
this.kubeconfigManager = new KubeconfigManager(this) this.kubeconfigManager = new KubeconfigManager(this)
this.url = this.contextHandler.url this.url = this.contextHandler.url
} }

View File

@ -1,5 +1,4 @@
import { CoreV1Api, KubeConfig } from "@kubernetes/client-node" import { CoreV1Api, KubeConfig } from "@kubernetes/client-node"
import http from "http"
import { ServerOptions } from "http-proxy" import { ServerOptions } from "http-proxy"
import * as url from "url" import * as url from "url"
import logger from "./logger" import logger from "./logger"
@ -7,20 +6,20 @@ import { getFreePort } from "./port"
import { KubeAuthProxy } from "./kube-auth-proxy" import { KubeAuthProxy } from "./kube-auth-proxy"
import { Cluster } from "./cluster" import { Cluster } from "./cluster"
import { prometheusProviders } from "../common/prometheus-providers" import { prometheusProviders } from "../common/prometheus-providers"
import type { PrometheusService, PrometheusProvider } from "./prometheus/provider-registry" import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"
import type { ClusterPreferences } from "../common/cluster-store"; import type { ClusterPreferences } from "../common/cluster-store";
export class ContextHandler { export class ContextHandler {
public contextName: string
public id: string
public url: string public url: string
public clusterUrl: url.UrlWithStringQuery
public proxyServer: KubeAuthProxy
public proxyPort: number public proxyPort: number
public certData: string public contextName: string
public authCertData: string
public cluster: Cluster
protected id: string
protected clusterUrl: url.UrlWithStringQuery
protected proxyServer: KubeAuthProxy
protected certData: string
protected authCertData: string
protected cluster: Cluster
protected apiTarget: ServerOptions protected apiTarget: ServerOptions
protected proxyTarget: ServerOptions protected proxyTarget: ServerOptions
protected clientCert: string protected clientCert: string
@ -34,7 +33,6 @@ export class ContextHandler {
constructor(kc: KubeConfig, cluster: Cluster) { constructor(kc: KubeConfig, cluster: Cluster) {
this.id = cluster.id this.id = cluster.id
this.cluster = cluster this.cluster = cluster
this.clusterUrl = url.parse(cluster.apiUrl) this.clusterUrl = url.parse(cluster.apiUrl)
this.contextName = cluster.contextName; this.contextName = cluster.contextName;
@ -49,26 +47,19 @@ export class ContextHandler {
await this.resolveProxyPort() await this.resolveProxyPort()
} }
public setClusterPreferences(clusterPreferences?: ClusterPreferences) { public setClusterPreferences(preferences?: ClusterPreferences) {
this.prometheusProvider = clusterPreferences.prometheusProvider?.type this.clusterName = preferences?.clusterName || this.contextName;
this.prometheusProvider = preferences.prometheusProvider?.type;
this.prometheusPath = null;
if (clusterPreferences && clusterPreferences.prometheus) { if (preferences?.prometheus) {
const prom = clusterPreferences.prometheus const { namespace, service, port } = preferences.prometheus
this.prometheusPath = `${prom.namespace}/services/${prom.service}:${prom.port}` this.prometheusPath = `${namespace}/services/${service}:${port}`
}
else {
this.prometheusPath = null
}
if (clusterPreferences && clusterPreferences.clusterName) {
this.clusterName = clusterPreferences.clusterName;
}
else {
this.clusterName = this.contextName;
} }
} }
protected async resolvePrometheusPath(): Promise<string> { protected async resolvePrometheusPath(): Promise<string> {
const {service, namespace, port} = await this.getPrometheusService() const { service, namespace, port } = await this.getPrometheusService()
return `${namespace}/services/${service}:${port}` return `${namespace}/services/${service}:${port}`
} }
@ -91,8 +82,7 @@ export class ContextHandler {
const service = resolvedPrometheusServices.filter(n => n)[0] const service = resolvedPrometheusServices.filter(n => n)[0]
if (service) { if (service) {
return service return service
} } else {
else {
return { return {
id: "lens", id: "lens",
namespace: "lens-metrics", namespace: "lens-metrics",
@ -103,11 +93,10 @@ export class ContextHandler {
} }
public async getPrometheusPath(): Promise<string> { public async getPrometheusPath(): Promise<string> {
if (this.prometheusPath) return this.prometheusPath if (!this.prometheusPath) {
this.prometheusPath = await this.resolvePrometheusPath()
this.prometheusPath = await this.resolvePrometheusPath() }
return this.prometheusPath;
return this.prometheusPath
} }
public async getApiTarget(isWatchRequest = false): Promise<ServerOptions> { public async getApiTarget(isWatchRequest = false): Promise<ServerOptions> {
@ -139,18 +128,15 @@ export class ContextHandler {
} }
protected async resolveProxyPort(): Promise<number> { protected async resolveProxyPort(): Promise<number> {
if (this.proxyPort) return this.proxyPort if (!this.proxyPort) {
try {
let serverPort: number = null this.proxyPort = await getFreePort()
try { } catch (error) {
serverPort = await getFreePort() logger.error(error)
} catch (error) { throw(error)
logger.error(error) }
throw(error)
} }
this.proxyPort = serverPort return this.proxyPort
return serverPort
} }
public async withTemporaryKubeconfig(callback: (kubeconfig: string) => Promise<any>) { public async withTemporaryKubeconfig(callback: (kubeconfig: string) => Promise<any>) {

View File

@ -18,7 +18,6 @@
<script> <script>
import ClustersMixin from "@/_vue/mixins/ClustersMixin"; import ClustersMixin from "@/_vue/mixins/ClustersMixin";
import { newContexts } from '@kubernetes/client-node/dist/config_types';
export default { export default {
name: "AddClusterMenuItem", name: "AddClusterMenuItem",
mixins: [ClustersMixin], mixins: [ClustersMixin],
@ -43,7 +42,6 @@ export default {
} }
}, },
mounted() { mounted() {
console.log(this.newContexts.length)
this.$store.dispatch("reloadAvailableKubeContexts"); this.$store.dispatch("reloadAvailableKubeContexts");
} }
} }

View File

@ -6186,6 +6186,11 @@ ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
immer@^7.0.5:
version "7.0.5"
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.5.tgz#8af347db5b60b40af8ae7baf1784ea4d35b5208e"
integrity sha512-TtRAKZyuqld2eYjvWgXISLJ0ZlOl1OOTzRmrmiY8SlB0dnAhZ1OiykIDL5KDFNaPHDXiLfGQFNJGtet8z8AEmg==
import-fresh@^3.0.0, import-fresh@^3.1.0: import-fresh@^3.0.0, import-fresh@^3.1.0:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"