mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
add display resolutions to activity updates, update docs (#1323)
This commit is contained in:
parent
958a5ece10
commit
24807cfd34
@ -47,11 +47,20 @@ When telemetry is active, we collect the following data. It is stored in the `te
|
|||||||
| ActiveMinutes | The number of minutes that the user has actively used Waveterm on a given day. This requires the terminal window to be in focus while the user is actively interacting with it. |
|
| ActiveMinutes | The number of minutes that the user has actively used Waveterm on a given day. This requires the terminal window to be in focus while the user is actively interacting with it. |
|
||||||
| FgMinutes | The number of minutes that Waveterm has been in the foreground on a given day. This requires the terminal window to be in focus regardless of user interaction. |
|
| FgMinutes | The number of minutes that Waveterm has been in the foreground on a given day. This requires the terminal window to be in focus regardless of user interaction. |
|
||||||
| OpenMinutes | The number of minutes that Waveterm has been open on a given day. This only requires that the terminal is open, even if the window is out of focus. |
|
| OpenMinutes | The number of minutes that Waveterm has been open on a given day. This only requires that the terminal is open, even if the window is out of focus. |
|
||||||
|
| NumBlocks | The number of existing blocks open on a given day |
|
||||||
| NumTabs | The number of existing tabs open on a given day. |
|
| NumTabs | The number of existing tabs open on a given day. |
|
||||||
|
| NewTab | The number of new tabs created on a given day |
|
||||||
|
| NumWindows | The number of existing windows open on a give day. |
|
||||||
| NewTab | The number of new tabs opened on a given day. |
|
| NewTab | The number of new tabs opened on a given day. |
|
||||||
| NumStartup | The number of times waveterm has been started on a given day. |
|
| NumStartup | The number of times waveterm has been started on a given day. |
|
||||||
| NumShutdown | The number of times waveterm has been shut down on a given day. |
|
| NumShutdown | The number of times waveterm has been shut down on a given day. |
|
||||||
|
| SetTabTheme | The number of times the tab theme is changed from the context menu |
|
||||||
|
| NumMagnify | The number of times any block is magnified |
|
||||||
|
| NumSSHConn | The number of distinct SSH connections that have been made to distinct hosts |
|
||||||
|
| NumWSLConns | The number of distinct WSL connections that have been made to distinct distros |
|
||||||
| Renderers | The number of new block views of each type are open on a given day. |
|
| Renderers | The number of new block views of each type are open on a given day. |
|
||||||
|
| WshCmds | The number of wsh commands of each type run on a given day |
|
||||||
|
| Conn | The number of successful remote connections made (and errors) on a given day |
|
||||||
|
|
||||||
## Associated Data
|
## Associated Data
|
||||||
|
|
||||||
@ -67,6 +76,7 @@ In addition to the telemetry data collected, the following is also reported. It
|
|||||||
| ClientArch | This includes the user's operating system (e.g. linux or darwin) and architecture (e.g. x86_64 or arm64). It does not include data for any Connections at this time. |
|
| ClientArch | This includes the user's operating system (e.g. linux or darwin) and architecture (e.g. x86_64 or arm64). It does not include data for any Connections at this time. |
|
||||||
| BuildTime | This serves as a more accurate version number that keeps track of when we built the version. It has no bearing on when that version was installed by you. |
|
| BuildTime | This serves as a more accurate version number that keeps track of when we built the version. It has no bearing on when that version was installed by you. |
|
||||||
| OSRelease | This lists the version of the operating system the user has installed. |
|
| OSRelease | This lists the version of the operating system the user has installed. |
|
||||||
|
| Displays | Display resolutions (added in v0.9.3 to help us understand what screen resolutions to optimize for) |
|
||||||
|
|
||||||
## Telemetry Metadata
|
## Telemetry Metadata
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright 2024, Command Line Inc.
|
// Copyright 2024, Command Line Inc.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { RpcApi } from "@/app/store/wshclientapi";
|
||||||
import * as electron from "electron";
|
import * as electron from "electron";
|
||||||
import { FastAverageColor } from "fast-average-color";
|
import { FastAverageColor } from "fast-average-color";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@ -14,7 +15,6 @@ import winston from "winston";
|
|||||||
import * as services from "../frontend/app/store/services";
|
import * as services from "../frontend/app/store/services";
|
||||||
import { initElectronWshrpc, shutdownWshrpc } from "../frontend/app/store/wshrpcutil";
|
import { initElectronWshrpc, shutdownWshrpc } from "../frontend/app/store/wshrpcutil";
|
||||||
import { getWebServerEndpoint } from "../frontend/util/endpoints";
|
import { getWebServerEndpoint } from "../frontend/util/endpoints";
|
||||||
import { fetch } from "../frontend/util/fetchutil";
|
|
||||||
import * as keyutil from "../frontend/util/keyutil";
|
import * as keyutil from "../frontend/util/keyutil";
|
||||||
import { fireAndForget } from "../frontend/util/util";
|
import { fireAndForget } from "../frontend/util/util";
|
||||||
import { AuthKey, configureAuthKeyRequestInjection } from "./authkey";
|
import { AuthKey, configureAuthKeyRequestInjection } from "./authkey";
|
||||||
@ -518,16 +518,39 @@ electron.ipcMain.on("contextmenu-show", (event, menuDefArr?: ElectronContextMenu
|
|||||||
event.returnValue = true;
|
event.returnValue = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// we try to set the primary display as index [0]
|
||||||
|
function getActivityDisplays(): ActivityDisplayType[] {
|
||||||
|
const displays = electron.screen.getAllDisplays();
|
||||||
|
const primaryDisplay = electron.screen.getPrimaryDisplay();
|
||||||
|
const rtn: ActivityDisplayType[] = [];
|
||||||
|
for (const display of displays) {
|
||||||
|
const adt = {
|
||||||
|
width: display.size.width,
|
||||||
|
height: display.size.height,
|
||||||
|
dpr: display.scaleFactor,
|
||||||
|
internal: display.internal,
|
||||||
|
};
|
||||||
|
if (display.id === primaryDisplay?.id) {
|
||||||
|
rtn.unshift(adt);
|
||||||
|
} else {
|
||||||
|
rtn.push(adt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
async function logActiveState() {
|
async function logActiveState() {
|
||||||
const astate = getActivityState();
|
const astate = getActivityState();
|
||||||
const activeState = { fg: astate.wasInFg, active: astate.wasActive, open: true };
|
const activity: ActivityUpdate = { openminutes: 1 };
|
||||||
const url = new URL(getWebServerEndpoint() + "/wave/log-active-state");
|
if (astate.wasInFg) {
|
||||||
try {
|
activity.fgminutes = 1;
|
||||||
const resp = await fetch(url, { method: "post", body: JSON.stringify(activeState) });
|
|
||||||
if (!resp.ok) {
|
|
||||||
console.log("error logging active state", resp.status, resp.statusText);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (astate.wasActive) {
|
||||||
|
activity.activeminutes = 1;
|
||||||
|
}
|
||||||
|
activity.displays = getActivityDisplays();
|
||||||
|
try {
|
||||||
|
RpcApi.ActivityCommand(ElectronWshClient, activity, { noresponse: true });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("error logging active state", e);
|
console.log("error logging active state", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
9
frontend/types/gotypes.d.ts
vendored
9
frontend/types/gotypes.d.ts
vendored
@ -5,6 +5,14 @@
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
||||||
|
// telemetry.ActivityDisplayType
|
||||||
|
type ActivityDisplayType = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
dpr: number;
|
||||||
|
internal?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
// telemetry.ActivityUpdate
|
// telemetry.ActivityUpdate
|
||||||
type ActivityUpdate = {
|
type ActivityUpdate = {
|
||||||
fgminutes?: number;
|
fgminutes?: number;
|
||||||
@ -21,6 +29,7 @@ declare global {
|
|||||||
shutdown?: number;
|
shutdown?: number;
|
||||||
settabtheme?: number;
|
settabtheme?: number;
|
||||||
buildtime?: string;
|
buildtime?: string;
|
||||||
|
displays?: ActivityDisplayType[];
|
||||||
renderers?: {[key: string]: number};
|
renderers?: {[key: string]: number};
|
||||||
wshcmds?: {[key: string]: number};
|
wshcmds?: {[key: string]: number};
|
||||||
conn?: {[key: string]: number};
|
conn?: {[key: string]: number};
|
||||||
|
@ -18,16 +18,11 @@ import (
|
|||||||
|
|
||||||
const MaxTzNameLen = 50
|
const MaxTzNameLen = 50
|
||||||
|
|
||||||
// "terminal" should not be in this list
|
type ActivityDisplayType struct {
|
||||||
var allowedRenderers = map[string]bool{
|
Width int `json:"width"`
|
||||||
"markdown": true,
|
Height int `json:"height"`
|
||||||
"code": true,
|
DPR float64 `json:"dpr"`
|
||||||
"openai": true,
|
Internal bool `json:"internal,omitempty"`
|
||||||
"csv": true,
|
|
||||||
"image": true,
|
|
||||||
"pdf": true,
|
|
||||||
"media": true,
|
|
||||||
"mustache": true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActivityUpdate struct {
|
type ActivityUpdate struct {
|
||||||
@ -45,6 +40,7 @@ type ActivityUpdate struct {
|
|||||||
Shutdown int `json:"shutdown,omitempty"`
|
Shutdown int `json:"shutdown,omitempty"`
|
||||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||||
BuildTime string `json:"buildtime,omitempty"`
|
BuildTime string `json:"buildtime,omitempty"`
|
||||||
|
Displays []ActivityDisplayType `json:"displays,omitempty"`
|
||||||
Renderers map[string]int `json:"renderers,omitempty"`
|
Renderers map[string]int `json:"renderers,omitempty"`
|
||||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||||
Conn map[string]int `json:"conn,omitempty"`
|
Conn map[string]int `json:"conn,omitempty"`
|
||||||
@ -76,6 +72,7 @@ type TelemetryData struct {
|
|||||||
NumStartup int `json:"numstartup,omitempty"`
|
NumStartup int `json:"numstartup,omitempty"`
|
||||||
NumShutdown int `json:"numshutdown,omitempty"`
|
NumShutdown int `json:"numshutdown,omitempty"`
|
||||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||||
|
Displays []ActivityDisplayType `json:"displays,omitempty"`
|
||||||
Renderers map[string]int `json:"renderers,omitempty"`
|
Renderers map[string]int `json:"renderers,omitempty"`
|
||||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||||
Conn map[string]int `json:"conn,omitempty"`
|
Conn map[string]int `json:"conn,omitempty"`
|
||||||
@ -180,6 +177,9 @@ func UpdateActivity(ctx context.Context, update ActivityUpdate) error {
|
|||||||
tdata.Conn[key] += val
|
tdata.Conn[key] += val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(update.Displays) > 0 {
|
||||||
|
tdata.Displays = update.Displays
|
||||||
|
}
|
||||||
query = `UPDATE db_activity
|
query = `UPDATE db_activity
|
||||||
SET tdata = ?,
|
SET tdata = ?,
|
||||||
clientversion = ?,
|
clientversion = ?,
|
||||||
|
@ -26,14 +26,11 @@ import (
|
|||||||
"github.com/wavetermdev/waveterm/pkg/docsite"
|
"github.com/wavetermdev/waveterm/pkg/docsite"
|
||||||
"github.com/wavetermdev/waveterm/pkg/filestore"
|
"github.com/wavetermdev/waveterm/pkg/filestore"
|
||||||
"github.com/wavetermdev/waveterm/pkg/service"
|
"github.com/wavetermdev/waveterm/pkg/service"
|
||||||
"github.com/wavetermdev/waveterm/pkg/telemetry"
|
|
||||||
"github.com/wavetermdev/waveterm/pkg/wavebase"
|
"github.com/wavetermdev/waveterm/pkg/wavebase"
|
||||||
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
|
||||||
"github.com/wavetermdev/waveterm/pkg/wshrpc"
|
"github.com/wavetermdev/waveterm/pkg/wshrpc"
|
||||||
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
|
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
|
||||||
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshserver"
|
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshserver"
|
||||||
"github.com/wavetermdev/waveterm/pkg/wshutil"
|
"github.com/wavetermdev/waveterm/pkg/wshutil"
|
||||||
"github.com/wavetermdev/waveterm/pkg/wstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebFnType = func(http.ResponseWriter, *http.Request)
|
type WebFnType = func(http.ResponseWriter, *http.Request)
|
||||||
@ -358,34 +355,6 @@ type ClientActiveState struct {
|
|||||||
Open bool `json:"open"`
|
Open bool `json:"open"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// params: fg, active, open
|
|
||||||
func handleLogActiveState(w http.ResponseWriter, r *http.Request) {
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
var activeState ClientActiveState
|
|
||||||
err := decoder.Decode(&activeState)
|
|
||||||
if err != nil {
|
|
||||||
WriteJsonError(w, fmt.Errorf("error decoding json: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
activity := telemetry.ActivityUpdate{}
|
|
||||||
if activeState.Fg {
|
|
||||||
activity.FgMinutes = 1
|
|
||||||
}
|
|
||||||
if activeState.Active {
|
|
||||||
activity.ActiveMinutes = 1
|
|
||||||
}
|
|
||||||
if activeState.Open {
|
|
||||||
activity.OpenMinutes = 1
|
|
||||||
}
|
|
||||||
activity.NumTabs, _ = wstore.DBGetCount[*waveobj.Tab](r.Context())
|
|
||||||
err = telemetry.UpdateActivity(r.Context(), activity)
|
|
||||||
if err != nil {
|
|
||||||
WriteJsonError(w, fmt.Errorf("error updating activity: %w", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
WriteJsonSuccess(w, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType {
|
func WebFnWrap(opts WebFnOpts, fn WebFnType) WebFnType {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -450,7 +419,6 @@ func RunWebServer(listener net.Listener) {
|
|||||||
gr.HandleFunc("/wave/stream-file", WebFnWrap(WebFnOpts{AllowCaching: true}, handleStreamFile))
|
gr.HandleFunc("/wave/stream-file", WebFnWrap(WebFnOpts{AllowCaching: true}, handleStreamFile))
|
||||||
gr.HandleFunc("/wave/file", WebFnWrap(WebFnOpts{AllowCaching: false}, handleWaveFile))
|
gr.HandleFunc("/wave/file", WebFnWrap(WebFnOpts{AllowCaching: false}, handleWaveFile))
|
||||||
gr.HandleFunc("/wave/service", WebFnWrap(WebFnOpts{JsonErrors: true}, handleService))
|
gr.HandleFunc("/wave/service", WebFnWrap(WebFnOpts{JsonErrors: true}, handleService))
|
||||||
gr.HandleFunc("/wave/log-active-state", WebFnWrap(WebFnOpts{JsonErrors: true}, handleLogActiveState))
|
|
||||||
gr.HandleFunc("/vdom/{uuid}/{path:.*}", WebFnWrap(WebFnOpts{AllowCaching: true}, handleVDom))
|
gr.HandleFunc("/vdom/{uuid}/{path:.*}", WebFnWrap(WebFnOpts{AllowCaching: true}, handleVDom))
|
||||||
gr.PathPrefix(docsitePrefix).Handler(http.StripPrefix(docsitePrefix, docsite.GetDocsiteHandler()))
|
gr.PathPrefix(docsitePrefix).Handler(http.StripPrefix(docsitePrefix, docsite.GetDocsiteHandler()))
|
||||||
handler := http.TimeoutHandler(gr, HttpTimeoutDuration, "Timeout")
|
handler := http.TimeoutHandler(gr, HttpTimeoutDuration, "Timeout")
|
||||||
|
Loading…
Reference in New Issue
Block a user