Skip to content

Commit 2ba6c56

Browse files
committed
new sync client: implement "touch"
1 parent d25edc8 commit 2ba6c56

File tree

5 files changed

+49
-85
lines changed

5 files changed

+49
-85
lines changed

src/packages/conat/sync-doc/sync-client.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { type Client as ConatClient } from "@cocalc/conat/core/client";
1111
import { type ConatSyncTable } from "@cocalc/conat/sync/synctable";
1212
import { projectApiClient } from "@cocalc/conat/project/api";
1313
import { base64ToBuffer } from "@cocalc/util/base64";
14+
import callHub from "@cocalc/conat/hub/call-hub";
1415

1516
export class SyncClient extends EventEmitter implements Client0 {
1617
private client: ConatClient;
@@ -45,7 +46,18 @@ export class SyncClient extends EventEmitter implements Client0 {
4546
return this.client.isSignedIn();
4647
};
4748

48-
touch_project = (_): void => {};
49+
touch_project = async (project_id): Promise<void> => {
50+
try {
51+
await callHub({
52+
client: this.client,
53+
account_id: this.client_id(),
54+
name: "db.touch",
55+
args: [{ project_id, account_id: this.client_id() }],
56+
});
57+
} catch (err) {
58+
console.log("WARNING: issue touching project", { project_id });
59+
}
60+
};
4961

5062
is_deleted = (_filename: string, _project_id?: string): boolean => {
5163
return false;

src/packages/frontend/client/project.ts

Lines changed: 32 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { redux } from "@cocalc/frontend/app-framework";
1212
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
1313
import { dialogs } from "@cocalc/frontend/i18n";
1414
import { getIntl } from "@cocalc/frontend/i18n/get-intl";
15-
import { allow_project_to_run } from "@cocalc/frontend/project/client-side-throttle";
1615
import { ensure_project_running } from "@cocalc/frontend/project/project-start-warning";
1716
import { API } from "@cocalc/frontend/project/websocket/api";
1817
import { connection_to_project } from "@cocalc/frontend/project/websocket/connect";
@@ -44,9 +43,10 @@ import { readFile, type ReadFileOptions } from "@cocalc/conat/files/read";
4443
import { type ProjectApi } from "@cocalc/conat/project/api";
4544
import { type CopyOptions } from "@cocalc/conat/files/fs";
4645

46+
const TOUCH_THROTTLE = 30_000;
47+
4748
export class ProjectClient {
4849
private client: WebappClient;
49-
private touch_throttle: { [project_id: string]: number } = {};
5050

5151
constructor(client: WebappClient) {
5252
this.client = client;
@@ -393,63 +393,40 @@ export class ProjectClient {
393393
},
394394
);
395395

396-
touch_project = async (
397-
// project_id where activity occured
398-
project_id: string,
399-
// optional global id of a compute server (in the given project), in which case we also mark
400-
// that compute server as active, which keeps it running in case it has idle timeout configured.
401-
compute_server_id?: number,
402-
): Promise<void> => {
403-
if (!is_valid_uuid_string(project_id)) {
404-
console.warn("WARNING -- touch_project takes a project_id, but got ", {
405-
project_id,
406-
});
407-
}
408-
if (compute_server_id) {
409-
// this is throttled, etc. and is independent of everything below.
410-
touchComputeServer({
411-
project_id,
412-
compute_server_id,
413-
client: this.client,
414-
});
415-
// that said, we do still touch the project, since if a user is actively
416-
// using a compute server, the project should also be considered active.
417-
}
418-
419-
const state = redux.getStore("projects")?.get_state(project_id);
420-
if (!(state == null && redux.getStore("account")?.get("is_admin"))) {
421-
// not trying to view project as admin so do some checks
422-
if (!(await allow_project_to_run(project_id))) return;
423-
if (!this.client.is_signed_in()) {
424-
// silently ignore if not signed in
396+
touch_project = throttle(
397+
async (
398+
// project_id where activity occured
399+
project_id: string,
400+
// optional global id of a compute server (in the given project), in which case we also mark
401+
// that compute server as active, which keeps it running in case it has idle timeout configured.
402+
compute_server_id?: number | null,
403+
): Promise<void> => {
404+
console.log("touch_project", { project_id, compute_server_id });
405+
if (!is_valid_uuid_string(project_id)) {
406+
console.warn("WARNING -- touch_project takes a project_id, but got ", {
407+
project_id,
408+
});
425409
return;
426410
}
427-
if (state != "running") {
428-
// not running so don't touch (user must explicitly start first)
429-
return;
411+
if (compute_server_id) {
412+
// this is independent of everything below.
413+
touchComputeServer({
414+
project_id,
415+
compute_server_id,
416+
client: this.client,
417+
});
418+
// that said, we do still touch the project, since if a user is actively
419+
// using a compute server, the project should also be considered active.
430420
}
431-
}
432421

433-
// Throttle -- so if this function is called with the same project_id
434-
// twice in 3s, it's ignored (to avoid unnecessary network traffic).
435-
// Do not make the timeout long, since that can mess up
436-
// getting the hub-websocket to connect to the project.
437-
const last = this.touch_throttle[project_id];
438-
if (last != null && Date.now() - last <= 3000) {
439-
return;
440-
}
441-
this.touch_throttle[project_id] = Date.now();
442-
try {
443-
await this.client.conat_client.hub.db.touch({ project_id });
444-
} catch (err) {
445-
// silently ignore; this happens, e.g., if you touch too frequently,
446-
// and shouldn't be fatal and break other things.
447-
// NOTE: this is a bit ugly for now -- basically the
448-
// hub returns an error regarding actually touching
449-
// the project (updating the db), but it still *does*
450-
// ensure there is a TCP connection to the project.
451-
}
452-
};
422+
try {
423+
await this.client.conat_client.hub.db.touch({ project_id });
424+
} catch (err) {
425+
console.log("WARNING: issue touching project", err);
426+
}
427+
},
428+
TOUCH_THROTTLE,
429+
);
453430

454431
// Print sagews to pdf
455432
// The printed version of the file will be created in the same directory

src/packages/frontend/frame-editors/generic/client.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,9 @@ import { FakeSyncstring } from "./syncstring-fake";
1515
import { type UserSearchResult as User } from "@cocalc/util/db-schema/accounts";
1616
export { type User };
1717
import { excludeFromComputeServer } from "@cocalc/frontend/file-associations";
18-
1918
import type { ExecOpts, ExecOutput } from "@cocalc/util/db-schema/projects";
2019
export type { ExecOpts, ExecOutput };
21-
2220
import * as schema from "@cocalc/util/schema";
23-
2421
import { DEFAULT_FONT_SIZE } from "@cocalc/util/db-schema";
2522

2623
export function server_time(): Date {
@@ -73,7 +70,7 @@ export async function touch(project_id: string, path: string): Promise<void> {
7370
// Resets the idle timeout timer and makes it known we are using the project.
7471
export async function touch_project(
7572
project_id: string,
76-
compute_server_id?: number,
73+
compute_server_id?: number | null,
7774
): Promise<void> {
7875
try {
7976
await webapp_client.project_client.touch_project(

src/packages/frontend/frame-editors/terminal-editor/connected-terminal.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/*
77
Wrapper object around xterm.js's Terminal, which adds
88
extra support for being connected to:
9-
- a backend server pty via a sonat socket, which can be on a
9+
- a backend server pty via a sonat socket, which can be on a
1010
project or compute server
1111
- react/redux
1212
- frame-editor (via actions)
@@ -91,8 +91,6 @@ export class Terminal<T extends CodeEditorState = CodeEditorState> {
9191

9292
private render_buffer: string = "";
9393
private history: string = "";
94-
private last_active: number = 0;
95-
private touch_interval;
9694

9795
public is_visible: boolean = false;
9896
public element: HTMLElement;
@@ -181,10 +179,10 @@ export class Terminal<T extends CodeEditorState = CodeEditorState> {
181179
this.update_settings();
182180
this.init_title();
183181
this.init_settings();
184-
this.init_touch();
185182
this.set_connection_status("disconnected");
186183

187184
const handleData = (data: string) => {
185+
touch_project(this.project_id, this.compute_server_id);
188186
if (this.ptyExited) {
189187
this.ptyExited = false;
190188
this.connect();
@@ -289,7 +287,6 @@ export class Terminal<T extends CodeEditorState = CodeEditorState> {
289287
this.compute_server_id = null;
290288
this.set_connection_status("disconnected");
291289
this.state = "closed";
292-
clearInterval(this.touch_interval);
293290
this.account_store.removeListener("change", this.update_settings);
294291
this.terminal.dispose();
295292
close(this);
@@ -564,23 +561,6 @@ export class Terminal<T extends CodeEditorState = CodeEditorState> {
564561
}
565562
};
566563

567-
touch = async () => {
568-
if (this.isClosed()) return;
569-
if (Date.now() - this.last_active < 70000) {
570-
if (
571-
this.project_actions.isTabClosed() ||
572-
this.compute_server_id == null
573-
) {
574-
return;
575-
}
576-
touch_project(this.project_id, this.compute_server_id);
577-
}
578-
};
579-
580-
init_touch = (): void => {
581-
this.touch_interval = setInterval(this.touch, 60000);
582-
};
583-
584564
initKeyHandler = (): void => {
585565
if (this.isClosed()) {
586566
return;
@@ -602,9 +582,6 @@ export class Terminal<T extends CodeEditorState = CodeEditorState> {
602582
// key: event.key,
603583
// });
604584

605-
// record that terminal is being actively used.
606-
this.last_active = Date.now();
607-
608585
if (this.is_paused) {
609586
this.pauseKeyCount += 1;
610587
if (this.pauseKeyCount >= 4) {

src/packages/frontend/projects/actions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ export class ProjectsActions extends Actions<ProjectsState> {
954954
event: "project_start_requested",
955955
});
956956
const runner = webapp_client.conat_client.projectRunner(project_id);
957+
webapp_client.project_client.touch_project(project_id);
957958
await runner.start({ project_id });
958959

959960
this.project_log(project_id, {

0 commit comments

Comments
 (0)