2023-12-10 12:23:42 +00:00
|
|
|
import { SilverBulletHooks } from "../common/manifest.ts";
|
|
|
|
import { AssetBundlePlugSpacePrimitives } from "../common/spaces/asset_bundle_space_primitives.ts";
|
|
|
|
import { FilteredSpacePrimitives } from "../common/spaces/filtered_space_primitives.ts";
|
|
|
|
import { SpacePrimitives } from "../common/spaces/space_primitives.ts";
|
|
|
|
import { ensureSettingsAndIndex } from "../common/util.ts";
|
|
|
|
import { AssetBundle } from "../plugos/asset_bundle/bundle.ts";
|
|
|
|
import { KvPrimitives } from "../plugos/lib/kv_primitives.ts";
|
|
|
|
import { System } from "../plugos/system.ts";
|
|
|
|
import { BuiltinSettings } from "../web/types.ts";
|
2023-12-11 11:11:56 +00:00
|
|
|
import { JWTIssuer } from "./crypto.ts";
|
2023-12-10 12:23:42 +00:00
|
|
|
import { gitIgnoreCompiler } from "./deps.ts";
|
|
|
|
import { ServerSystem } from "./server_system.ts";
|
|
|
|
import { ShellBackend } from "./shell_backend.ts";
|
|
|
|
import { determineStorageBackend } from "./storage_backend.ts";
|
|
|
|
|
|
|
|
export type SpaceServerConfig = {
|
|
|
|
hostname: string;
|
|
|
|
namespace: string;
|
2023-12-13 16:52:56 +00:00
|
|
|
// Enable username/password auth
|
|
|
|
auth?: { user: string; pass: string };
|
|
|
|
// Additional API auth token
|
|
|
|
authToken?: string;
|
2023-12-10 12:23:42 +00:00
|
|
|
pagesPath: string;
|
2023-12-17 10:46:18 +00:00
|
|
|
syncOnly?: boolean;
|
|
|
|
clientEncryption?: boolean;
|
2023-12-10 12:23:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export class SpaceServer {
|
|
|
|
public pagesPath: string;
|
2023-12-13 16:52:56 +00:00
|
|
|
auth?: { user: string; pass: string };
|
|
|
|
authToken?: string;
|
2023-12-10 12:23:42 +00:00
|
|
|
hostname: string;
|
|
|
|
|
|
|
|
private settings?: BuiltinSettings;
|
2023-12-13 16:52:56 +00:00
|
|
|
spacePrimitives!: SpacePrimitives;
|
2023-12-10 12:23:42 +00:00
|
|
|
|
2023-12-11 11:11:56 +00:00
|
|
|
jwtIssuer: JWTIssuer;
|
|
|
|
|
2023-12-10 12:23:42 +00:00
|
|
|
// Only set when syncOnly == false
|
|
|
|
private serverSystem?: ServerSystem;
|
|
|
|
system?: System<SilverBulletHooks>;
|
2023-12-17 10:46:18 +00:00
|
|
|
clientEncryption: boolean;
|
|
|
|
syncOnly: boolean;
|
2023-12-10 12:23:42 +00:00
|
|
|
|
|
|
|
constructor(
|
|
|
|
config: SpaceServerConfig,
|
|
|
|
public shellBackend: ShellBackend,
|
2023-12-13 16:52:56 +00:00
|
|
|
private plugAssetBundle: AssetBundle,
|
|
|
|
private kvPrimitives: KvPrimitives,
|
2023-12-10 12:23:42 +00:00
|
|
|
) {
|
|
|
|
this.pagesPath = config.pagesPath;
|
|
|
|
this.hostname = config.hostname;
|
|
|
|
this.auth = config.auth;
|
2023-12-13 16:52:56 +00:00
|
|
|
this.authToken = config.authToken;
|
2023-12-17 10:46:18 +00:00
|
|
|
this.clientEncryption = !!config.clientEncryption;
|
|
|
|
this.syncOnly = !!config.syncOnly;
|
|
|
|
if (this.clientEncryption) {
|
|
|
|
// Sync only will forced on when encryption is enabled
|
|
|
|
this.syncOnly = true;
|
|
|
|
}
|
|
|
|
|
2023-12-13 16:52:56 +00:00
|
|
|
this.jwtIssuer = new JWTIssuer(kvPrimitives);
|
|
|
|
}
|
2023-12-10 12:23:42 +00:00
|
|
|
|
2023-12-13 16:52:56 +00:00
|
|
|
async init() {
|
2023-12-10 12:23:42 +00:00
|
|
|
let fileFilterFn: (s: string) => boolean = () => true;
|
|
|
|
|
|
|
|
this.spacePrimitives = new FilteredSpacePrimitives(
|
|
|
|
new AssetBundlePlugSpacePrimitives(
|
2023-12-13 16:52:56 +00:00
|
|
|
await determineStorageBackend(this.kvPrimitives, this.pagesPath),
|
|
|
|
this.plugAssetBundle,
|
2023-12-10 12:23:42 +00:00
|
|
|
),
|
|
|
|
(meta) => fileFilterFn(meta.name),
|
|
|
|
async () => {
|
|
|
|
await this.reloadSettings();
|
|
|
|
if (typeof this.settings?.spaceIgnore === "string") {
|
|
|
|
fileFilterFn = gitIgnoreCompiler(this.settings.spaceIgnore).accepts;
|
|
|
|
} else {
|
|
|
|
fileFilterFn = () => true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
// system = undefined in databaseless mode (no PlugOS instance on the server and no DB)
|
2023-12-13 16:52:56 +00:00
|
|
|
if (!this.syncOnly) {
|
2023-12-10 12:23:42 +00:00
|
|
|
// Enable server-side processing
|
|
|
|
const serverSystem = new ServerSystem(
|
|
|
|
this.spacePrimitives,
|
2023-12-13 16:52:56 +00:00
|
|
|
this.kvPrimitives,
|
2023-12-17 14:25:44 +00:00
|
|
|
this.shellBackend,
|
2023-12-10 12:23:42 +00:00
|
|
|
);
|
|
|
|
this.serverSystem = serverSystem;
|
|
|
|
}
|
|
|
|
|
2023-12-11 11:11:56 +00:00
|
|
|
if (this.auth) {
|
|
|
|
// Initialize JWT issuer
|
2023-12-13 16:52:56 +00:00
|
|
|
await this.jwtIssuer.init(
|
|
|
|
JSON.stringify({ auth: this.auth, authToken: this.authToken }),
|
|
|
|
);
|
2023-12-11 11:11:56 +00:00
|
|
|
}
|
|
|
|
|
2023-12-10 12:23:42 +00:00
|
|
|
if (this.serverSystem) {
|
|
|
|
await this.serverSystem.init();
|
|
|
|
this.system = this.serverSystem.system;
|
2023-12-13 16:52:56 +00:00
|
|
|
// Swap in the space primitives from the server system
|
|
|
|
this.spacePrimitives = this.serverSystem.spacePrimitives;
|
2023-12-10 12:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
await this.reloadSettings();
|
|
|
|
console.log("Booted server with hostname", this.hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
async reloadSettings() {
|
2023-12-17 10:46:18 +00:00
|
|
|
if (!this.clientEncryption) {
|
|
|
|
// Only attempt this when the space is not encrypted
|
|
|
|
this.settings = await ensureSettingsAndIndex(this.spacePrimitives);
|
|
|
|
} else {
|
|
|
|
this.settings = {
|
|
|
|
indexPage: "index",
|
|
|
|
};
|
|
|
|
}
|
2023-12-10 12:23:42 +00:00
|
|
|
}
|
|
|
|
}
|