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. |
|
||||
| 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. |
|
||||
| NumBlocks | The number of existing blocks 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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
|
||||
|
||||
@ -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. |
|
||||
| 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. |
|
||||
| Displays | Display resolutions (added in v0.9.3 to help us understand what screen resolutions to optimize for) |
|
||||
|
||||
## Telemetry Metadata
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { RpcApi } from "@/app/store/wshclientapi";
|
||||
import * as electron from "electron";
|
||||
import { FastAverageColor } from "fast-average-color";
|
||||
import fs from "fs";
|
||||
@ -14,7 +15,6 @@ import winston from "winston";
|
||||
import * as services from "../frontend/app/store/services";
|
||||
import { initElectronWshrpc, shutdownWshrpc } from "../frontend/app/store/wshrpcutil";
|
||||
import { getWebServerEndpoint } from "../frontend/util/endpoints";
|
||||
import { fetch } from "../frontend/util/fetchutil";
|
||||
import * as keyutil from "../frontend/util/keyutil";
|
||||
import { fireAndForget } from "../frontend/util/util";
|
||||
import { AuthKey, configureAuthKeyRequestInjection } from "./authkey";
|
||||
@ -518,16 +518,39 @@ electron.ipcMain.on("contextmenu-show", (event, menuDefArr?: ElectronContextMenu
|
||||
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() {
|
||||
const astate = getActivityState();
|
||||
const activeState = { fg: astate.wasInFg, active: astate.wasActive, open: true };
|
||||
const url = new URL(getWebServerEndpoint() + "/wave/log-active-state");
|
||||
const activity: ActivityUpdate = { openminutes: 1 };
|
||||
if (astate.wasInFg) {
|
||||
activity.fgminutes = 1;
|
||||
}
|
||||
if (astate.wasActive) {
|
||||
activity.activeminutes = 1;
|
||||
}
|
||||
activity.displays = getActivityDisplays();
|
||||
try {
|
||||
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;
|
||||
}
|
||||
RpcApi.ActivityCommand(ElectronWshClient, activity, { noresponse: true });
|
||||
} catch (e) {
|
||||
console.log("error logging active state", e);
|
||||
} finally {
|
||||
|
9
frontend/types/gotypes.d.ts
vendored
9
frontend/types/gotypes.d.ts
vendored
@ -5,6 +5,14 @@
|
||||
|
||||
declare global {
|
||||
|
||||
// telemetry.ActivityDisplayType
|
||||
type ActivityDisplayType = {
|
||||
width: number;
|
||||
height: number;
|
||||
dpr: number;
|
||||
internal?: boolean;
|
||||
};
|
||||
|
||||
// telemetry.ActivityUpdate
|
||||
type ActivityUpdate = {
|
||||
fgminutes?: number;
|
||||
@ -21,6 +29,7 @@ declare global {
|
||||
shutdown?: number;
|
||||
settabtheme?: number;
|
||||
buildtime?: string;
|
||||
displays?: ActivityDisplayType[];
|
||||
renderers?: {[key: string]: number};
|
||||
wshcmds?: {[key: string]: number};
|
||||
conn?: {[key: string]: number};
|
||||
|
@ -18,36 +18,32 @@ import (
|
||||
|
||||
const MaxTzNameLen = 50
|
||||
|
||||
// "terminal" should not be in this list
|
||||
var allowedRenderers = map[string]bool{
|
||||
"markdown": true,
|
||||
"code": true,
|
||||
"openai": true,
|
||||
"csv": true,
|
||||
"image": true,
|
||||
"pdf": true,
|
||||
"media": true,
|
||||
"mustache": true,
|
||||
type ActivityDisplayType struct {
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
DPR float64 `json:"dpr"`
|
||||
Internal bool `json:"internal,omitempty"`
|
||||
}
|
||||
|
||||
type ActivityUpdate struct {
|
||||
FgMinutes int `json:"fgminutes,omitempty"`
|
||||
ActiveMinutes int `json:"activeminutes,omitempty"`
|
||||
OpenMinutes int `json:"openminutes,omitempty"`
|
||||
NumTabs int `json:"numtabs,omitempty"`
|
||||
NewTab int `json:"newtab,omitempty"`
|
||||
NumBlocks int `json:"numblocks,omitempty"`
|
||||
NumWindows int `json:"numwindows,omitempty"`
|
||||
NumSSHConn int `json:"numsshconn,omitempty"`
|
||||
NumWSLConn int `json:"numwslconn,omitempty"`
|
||||
NumMagnify int `json:"nummagnify,omitempty"`
|
||||
Startup int `json:"startup,omitempty"`
|
||||
Shutdown int `json:"shutdown,omitempty"`
|
||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||
BuildTime string `json:"buildtime,omitempty"`
|
||||
Renderers map[string]int `json:"renderers,omitempty"`
|
||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||
Conn map[string]int `json:"conn,omitempty"`
|
||||
FgMinutes int `json:"fgminutes,omitempty"`
|
||||
ActiveMinutes int `json:"activeminutes,omitempty"`
|
||||
OpenMinutes int `json:"openminutes,omitempty"`
|
||||
NumTabs int `json:"numtabs,omitempty"`
|
||||
NewTab int `json:"newtab,omitempty"`
|
||||
NumBlocks int `json:"numblocks,omitempty"`
|
||||
NumWindows int `json:"numwindows,omitempty"`
|
||||
NumSSHConn int `json:"numsshconn,omitempty"`
|
||||
NumWSLConn int `json:"numwslconn,omitempty"`
|
||||
NumMagnify int `json:"nummagnify,omitempty"`
|
||||
Startup int `json:"startup,omitempty"`
|
||||
Shutdown int `json:"shutdown,omitempty"`
|
||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||
BuildTime string `json:"buildtime,omitempty"`
|
||||
Displays []ActivityDisplayType `json:"displays,omitempty"`
|
||||
Renderers map[string]int `json:"renderers,omitempty"`
|
||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||
Conn map[string]int `json:"conn,omitempty"`
|
||||
}
|
||||
|
||||
type ActivityType struct {
|
||||
@ -63,22 +59,23 @@ type ActivityType struct {
|
||||
}
|
||||
|
||||
type TelemetryData struct {
|
||||
ActiveMinutes int `json:"activeminutes"`
|
||||
FgMinutes int `json:"fgminutes"`
|
||||
OpenMinutes int `json:"openminutes"`
|
||||
NumTabs int `json:"numtabs"`
|
||||
NumBlocks int `json:"numblocks,omitempty"`
|
||||
NumWindows int `json:"numwindows,omitempty"`
|
||||
NumSSHConn int `json:"numsshconn,omitempty"`
|
||||
NumWSLConn int `json:"numwslconn,omitempty"`
|
||||
NumMagnify int `json:"nummagnify,omitempty"`
|
||||
NewTab int `json:"newtab"`
|
||||
NumStartup int `json:"numstartup,omitempty"`
|
||||
NumShutdown int `json:"numshutdown,omitempty"`
|
||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||
Renderers map[string]int `json:"renderers,omitempty"`
|
||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||
Conn map[string]int `json:"conn,omitempty"`
|
||||
ActiveMinutes int `json:"activeminutes"`
|
||||
FgMinutes int `json:"fgminutes"`
|
||||
OpenMinutes int `json:"openminutes"`
|
||||
NumTabs int `json:"numtabs"`
|
||||
NumBlocks int `json:"numblocks,omitempty"`
|
||||
NumWindows int `json:"numwindows,omitempty"`
|
||||
NumSSHConn int `json:"numsshconn,omitempty"`
|
||||
NumWSLConn int `json:"numwslconn,omitempty"`
|
||||
NumMagnify int `json:"nummagnify,omitempty"`
|
||||
NewTab int `json:"newtab"`
|
||||
NumStartup int `json:"numstartup,omitempty"`
|
||||
NumShutdown int `json:"numshutdown,omitempty"`
|
||||
SetTabTheme int `json:"settabtheme,omitempty"`
|
||||
Displays []ActivityDisplayType `json:"displays,omitempty"`
|
||||
Renderers map[string]int `json:"renderers,omitempty"`
|
||||
WshCmds map[string]int `json:"wshcmds,omitempty"`
|
||||
Conn map[string]int `json:"conn,omitempty"`
|
||||
}
|
||||
|
||||
func (tdata TelemetryData) Value() (driver.Value, error) {
|
||||
@ -180,6 +177,9 @@ func UpdateActivity(ctx context.Context, update ActivityUpdate) error {
|
||||
tdata.Conn[key] += val
|
||||
}
|
||||
}
|
||||
if len(update.Displays) > 0 {
|
||||
tdata.Displays = update.Displays
|
||||
}
|
||||
query = `UPDATE db_activity
|
||||
SET tdata = ?,
|
||||
clientversion = ?,
|
||||
|
@ -26,14 +26,11 @@ import (
|
||||
"github.com/wavetermdev/waveterm/pkg/docsite"
|
||||
"github.com/wavetermdev/waveterm/pkg/filestore"
|
||||
"github.com/wavetermdev/waveterm/pkg/service"
|
||||
"github.com/wavetermdev/waveterm/pkg/telemetry"
|
||||
"github.com/wavetermdev/waveterm/pkg/wavebase"
|
||||
"github.com/wavetermdev/waveterm/pkg/waveobj"
|
||||
"github.com/wavetermdev/waveterm/pkg/wshrpc"
|
||||
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
|
||||
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshserver"
|
||||
"github.com/wavetermdev/waveterm/pkg/wshutil"
|
||||
"github.com/wavetermdev/waveterm/pkg/wstore"
|
||||
)
|
||||
|
||||
type WebFnType = func(http.ResponseWriter, *http.Request)
|
||||
@ -358,34 +355,6 @@ type ClientActiveState struct {
|
||||
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 {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
@ -450,7 +419,6 @@ func RunWebServer(listener net.Listener) {
|
||||
gr.HandleFunc("/wave/stream-file", WebFnWrap(WebFnOpts{AllowCaching: true}, handleStreamFile))
|
||||
gr.HandleFunc("/wave/file", WebFnWrap(WebFnOpts{AllowCaching: false}, handleWaveFile))
|
||||
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.PathPrefix(docsitePrefix).Handler(http.StripPrefix(docsitePrefix, docsite.GetDocsiteHandler()))
|
||||
handler := http.TimeoutHandler(gr, HttpTimeoutDuration, "Timeout")
|
||||
|
Loading…
Reference in New Issue
Block a user