Skip to content

Commit

Permalink
Ws (#20)
Browse files Browse the repository at this point in the history
* [CHANGE] websocket transport is part of core
* [CI] changed module version generation/validation to be a ts file
* [TEST] added WS default connection test, added fixme for sanitizers.
  • Loading branch information
aricart authored Jul 24, 2024
1 parent 970427e commit ede2b62
Show file tree
Hide file tree
Showing 27 changed files with 681 additions and 184 deletions.
279 changes: 208 additions & 71 deletions bin/check-bundle-version.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,148 @@
#!/usr/bin/env -S deno run -A
/*
* Copyright 2021-2024 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { parseArgs } from "jsr:@std/cli/parse-args";
import { join } from "jsr:@std/path";

async function load(fp: string): Promise<{ version: string }> {
const src = await Deno.readTextFile(fp);
class ModuleVersions {
file?: SemVer;
deno?: SemVer;
node?: SemVer;

constructor() {
}

max(): SemVer | null {
const vers = this.versions();
let vv: SemVer | null = null;
vers.forEach((v) => {
vv = vv == null ? v : vv.max(v);
});
return vv;
}

versions(): SemVer[] {
const vers = [];
if (this.file) {
vers.push(this.file);
}
if (this.deno) {
vers.push(this.deno);
}
if (this.node) {
vers.push(this.node);
}
return vers;
}

check() {
const m = this.max();
if (m !== null) {
this.versions().forEach((v) => {
if (m.compare(v) !== 0) {
throw new Error("different versions found");
}
});
}
}
}

class SemVer {
major: number;
minor: number;
micro: number;
qualifier: string;

constructor(v: string) {
const m = v.match(/(\d+).(\d+).(\d+)(-{1}(.+))?/);
if (m) {
this.major = parseInt(m[1]);
this.minor = parseInt(m[2]);
this.micro = parseInt(m[3]);
this.qualifier = m[5] ? m[5] : "";
} else {
throw new Error(`'${v}' is not a semver value`);
}
}

compare(b: SemVer): number {
if (this.major < b.major) return -1;
if (this.major > b.major) return 1;
if (this.minor < b.minor) return -1;
if (this.minor > b.minor) return 1;
if (this.micro < b.micro) return -1;
if (this.micro > b.micro) return 1;
if (this.qualifier === "") return 1;
if (b.qualifier === "") return -1;
return this.qualifier.localeCompare(b.qualifier);
}

max(b: SemVer): SemVer {
return this.compare(b) > 0 ? this : b;
}

string(): string {
return `${this.major}.${this.minor}.${this.micro}` +
(this.qualifier ? `-${this.qualifier}` : "");
}
}

async function loadVersionFile(module: string): Promise<string> {
const { version } = await import(
join(Deno.cwd(), module, "src", "version.ts")
).catch(() => {
return "";
});
return version;
}

async function loadPackageFile(fp: string): Promise<{ version: string }> {
const src = await Deno.readTextFile(fp)
.catch(() => {
return JSON.stringify({ version: "" });
});
return JSON.parse(src);
}

async function loadVersions(module: string): Promise<ModuleVersions> {
const v = new ModuleVersions();
const file = await loadVersionFile(module);
if (file) {
v.file = new SemVer(file);
}

const { version: deno } = await loadPackageFile(
join(Deno.cwd(), module, "deno.json"),
);
if (deno) {
v.deno = new SemVer(deno);
}

const { version: node } = await loadPackageFile(
join(Deno.cwd(), module, "package.json"),
);
if (node) {
v.node = new SemVer(node);
}
return v;
}

async function fixPackageVersion(fp: string, version: SemVer): Promise<void> {
const d = JSON.parse(await Deno.readTextFile(fp));
d.version = version.string();
return Deno.writeTextFile(
fp,
JSON.stringify(d, null, 2),
);
}

async function fixVersionFile(module: string, version: SemVer): Promise<void> {
await Deno.writeTextFile(
join(module, "src", "version.ts"),
`// This file is generated - do not edit
export const version = "${version.string()}";
`,
);
}

const argv = parseArgs(
Deno.args,
{
Expand All @@ -44,70 +165,86 @@ if (module === null) {
Deno.exit(1);
}

let version: string;

if (module.startsWith("transport-")) {
let packageVersion: { version: string } | undefined;
const versionFilePath = join(module, "src", "version.json");
let versionFile = await load(versionFilePath);
switch (module) {
case "transport-node":
packageVersion = await load(join(module, "package.json"));
break;
default:
packageVersion = await load(join(module, "deno.json"));
break;
}
if (!packageVersion) {
console.error(
`[ERROR] package version for module ${module} is missing a version`,
);
Deno.exit(1);
}
if (!versionFile) {
console.error(
`[ERROR] src/version.json file for module ${module} is missing a version`,
);
Deno.exit(1);
}
if (packageVersion.version !== versionFile.version) {
const versions = await loadVersions(module);
console.log(versions);

switch (module) {
case "transport-deno":
// no node
if (!versions.deno) {
console.error(`[ERROR] deno.json for ${module} is missing`);
Deno.exit(1);
}
break;
case "transport-node":
if (!versions.node) {
console.error(`[ERROR] package.json for ${module} is missing`);
Deno.exit(1);
}
break;
case "core":
if (!versions.deno) {
console.error(`[ERROR] deno.json for ${module} is missing`);
Deno.exit(1);
}
if (!versions.node) {
console.error(`[ERROR] package.json for ${module} is missing`);
Deno.exit(1);
}
if (!versions.file) {
console.error(`[ERROR] version.json for ${module} is missing`);
Deno.exit(1);
}
break;
default:
if (!versions.deno) {
console.error(`[ERROR] deno.json for ${module} is missing`);
Deno.exit(1);
}
if (!versions.node) {
console.error(`[ERROR] package.json for ${module} is missing`);
Deno.exit(1);
}
}

const version = versions.max()!;

try {
versions.check();
} catch (_) {
if (versions.file && version.compare(versions.file) !== 0) {
if (argv.fix) {
versionFile = { version: packageVersion.version };
await Deno.writeTextFile(
versionFilePath,
JSON.stringify(versionFile, null, 2),
await fixVersionFile(module, versions.max()!);
console.error(
`[OK] fixed src/version.ts file for module ${module}.`,
);
console.log(
`[OK] updated ${versionFilePath} to ${packageVersion.version}`,
} else {
console.error(
`[ERROR] src/version.ts file for module ${module} has an inconsistent version.`,
);
Deno.exit(0);
Deno.exit(1);
}
console.error(
`[ERROR] expected versions to match - package: ${packageVersion.version} src/version.json: ${versionFile.version}`,
);
Deno.exit(1);
}
version = versionFile.version;
} else {
const deno = await load(join(module, "deno.json"));
version = deno.version;
const nodePackagePath = join(module, "package.json");
const node = await load(nodePackagePath);

if (deno.version !== node.version) {
if (versions.node && version.compare(versions.node) !== 0) {
if (argv.fix) {
await fixPackageVersion(join(module, "package.json"), versions.max()!);
} else {
console.error(
`[ERROR] package.json file for module ${module} has an inconsistent version.`,
);
Deno.exit(1);
}
}
if (versions.deno && version.compare(versions.deno) !== 0) {
if (argv.fix) {
node.version = deno.version;
await Deno.writeTextFile(nodePackagePath, JSON.stringify(node, null, 2));
console.log(`[OK] updated ${nodePackagePath} to ${deno.version}`);
Deno.exit(0);
await fixPackageVersion(join(module, "deno.json"), versions.max()!);
} else {
console.error(
`[ERROR] expected versions to match - deno.json: ${deno.version} package.json: ${node.version}`,
`[ERROR] deno.json file for module ${module} has an inconsistent version.`,
);
Deno.exit(1);
}
}
node.version = deno.version;
}

if (argv.tag) {
Expand All @@ -116,12 +253,12 @@ if (argv.tag) {
if (tag.startsWith(prefix)) {
tag = tag.substring(prefix.length);
}
if (tag !== version!) {
if (tag !== version.string()) {
console.error(
`[ERROR] expected tag version to match - bundle: ${version!} tag: ${argv.tag}}`,
);
Deno.exit(1);
}
}
console.log(`[OK] ${module} version ${version!}`);
console.log(`[OK] ${module} version ${version.string()}`);
Deno.exit(0);
14 changes: 12 additions & 2 deletions core/deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nats-io/nats-core",
"version": "3.0.0-17",
"version": "3.0.0-18",
"exports": {
".": "./src/mod.ts",
"./internal": "./src/internal_mod.ts"
Expand All @@ -11,9 +11,19 @@
"./unsafe_tests/**/*"
]
},
"lint": {
"exclude": [
"lib/"
]
},
"fmt": {
"exclude": [
"lib/"
]
},
"tasks": {
"clean": "rm -rf ./lib ./cjs ./esm",
"test": "deno test -A --parallel --reload --quiet tests/ --import-map=./import_map.json"
"test": "deno test -A --parallel --reload tests/ --import-map=./import_map.json"
},
"imports": {
"@nats-io/nkeys": "jsr:@nats-io/[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nats-io/nats-core",
"version": "3.0.0-17",
"version": "3.0.0-18",
"files": [
"lib/",
"build/src/"
Expand Down
17 changes: 17 additions & 0 deletions core/src/internal_mod.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2024 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { NatsConnectionImpl } from "./nats.ts";
export { Nuid, nuid } from "./nuid.ts";

Expand Down Expand Up @@ -127,3 +142,5 @@ export { isIPV4OrHostname, Servers } from "./servers.ts";
export { Base64Codec, Base64UrlCodec, Base64UrlPaddedCodec } from "./base64.ts";

export { SHA256 } from "./sha256.ts";

export { wsconnect, wsUrlParseFn } from "./ws_transport.ts";
Loading

0 comments on commit ede2b62

Please sign in to comment.