Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/hub/servers/server-settings.ts
1503 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Synchronized table that tracks server settings.
8
*/
9
10
import { isEmpty } from "lodash";
11
import { once } from "@cocalc/util/async-utils";
12
import { EXTRAS as SERVER_SETTINGS_EXTRAS } from "@cocalc/util/db-schema/site-settings-extras";
13
import { AllSiteSettings } from "@cocalc/util/db-schema/types";
14
import { startswith } from "@cocalc/util/misc";
15
import { site_settings_conf as SITE_SETTINGS_CONF } from "@cocalc/util/schema";
16
import { database } from "./database";
17
18
// Returns:
19
// - all: a mutable javascript object that is a map from each server setting to its current value.
20
// This includes VERY private info (e.g., stripe private key)
21
// - pub: similar, but only subset of public info that is needed for browser UI rendering.
22
// - version
23
// - table: the table, so you can watch for on change events...
24
// These get automatically updated when the database changes.
25
26
export interface ServerSettingsDynamic {
27
all: AllSiteSettings;
28
pub: object;
29
version: {
30
version_min_browser?: number;
31
version_recommended_browser?: number;
32
version_min_project?: number;
33
};
34
table: any;
35
}
36
37
let serverSettings: ServerSettingsDynamic | undefined = undefined;
38
39
export default async function getServerSettings(): Promise<ServerSettingsDynamic> {
40
if (serverSettings != null) {
41
return serverSettings;
42
}
43
const table = database.server_settings_synctable();
44
serverSettings = { all: {}, pub: {}, version: {}, table: table };
45
const { all, pub, version } = serverSettings;
46
const update = async function () {
47
const allRaw = {};
48
table.get().forEach((record, field) => {
49
allRaw[field] = record.get("value");
50
});
51
52
table.get().forEach(function (record, field) {
53
const rawValue = record.get("value");
54
55
// process all values from the database according to the optional "to_val" mapping function
56
const spec = SITE_SETTINGS_CONF[field] ?? SERVER_SETTINGS_EXTRAS[field];
57
if (typeof spec?.to_val == "function") {
58
all[field] = spec.to_val(rawValue, allRaw);
59
} else {
60
if (typeof rawValue == "string" || typeof rawValue == "boolean") {
61
all[field] = rawValue;
62
}
63
}
64
65
// export certain fields to "pub[...]" and some old code regarding the version numbers
66
if (SITE_SETTINGS_CONF[field]) {
67
if (startswith(field, "version_")) {
68
const field_val: number = (all[field] = parseInt(all[field]));
69
if (isNaN(field_val) || field_val * 1000 >= new Date().getTime()) {
70
// Guard against horrible error in which version is in future (so impossible) or NaN (e.g., an invalid string pasted by admin).
71
// In this case, just use 0, which is always satisifed.
72
all[field] = 0;
73
}
74
version[field] = all[field];
75
}
76
pub[field] = all[field];
77
}
78
});
79
80
// set all default values
81
for (const config of [SITE_SETTINGS_CONF, SERVER_SETTINGS_EXTRAS]) {
82
for (const field in config) {
83
if (all[field] == null) {
84
const spec = config[field];
85
const fallbackVal =
86
spec?.to_val != null
87
? spec.to_val(spec.default, allRaw)
88
: spec.default;
89
// we don't bother to set empty strings or empty arrays
90
if (
91
(typeof fallbackVal === "string" && fallbackVal === "") ||
92
(Array.isArray(fallbackVal) && isEmpty(fallbackVal))
93
)
94
continue;
95
all[field] = fallbackVal;
96
// site-settings end up in the "pub" object as well
97
// while "all" is the one we keep to us, contains secrets
98
if (SITE_SETTINGS_CONF === config) {
99
pub[field] = all[field];
100
}
101
}
102
}
103
}
104
105
// Since we want to tell users about the estimated LLM interaction price, we have to send the markup as well.
106
pub["_llm_markup"] = all.pay_as_you_go_openai_markup_percentage;
107
108
// PRECAUTION: never make the required version bigger than version_recommended_browser. Very important
109
// not to stupidly completely eliminate all cocalc users by a typo...
110
for (const x of ["project", "browser"]) {
111
const field = `version_min_${x}`;
112
const minver = all[field] || 0;
113
const recomm = all["version_recommended_browser"] || 0;
114
pub[field] = version[field] = all[field] = Math.min(minver, recomm);
115
}
116
};
117
table.on("change", update);
118
table.on("init", update);
119
await once(table, "init");
120
return serverSettings;
121
}
122
123