Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Identity serialization/deserialization #26

Merged
merged 2 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions src/identity.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,57 @@
// Helper function convert from string to Uint8Array
function hexStringToUint8Array(str: string): Uint8Array {
let matches = str.match(/.{1,2}/g) || [];
let data = Uint8Array.from(matches.map((byte: string) => parseInt(byte, 16)));
return data;
}

// Helper function for converting Uint8Array to hex string
function uint8ArrayToHexString(array: Uint8Array): string {
return Array.prototype.map
.call(array, (x) => ("00" + x.toString(16)).slice(-2))
.join("");
}

/**
* A unique public identifier for a user connected to a database.
*/
export class Identity {
private data: Uint8Array;
private data: string;

/**
* Creates a new `Identity`.
*/
constructor(data: Uint8Array) {
this.data = data;
constructor(data: { __identity_bytes: string } | Uint8Array) {
// we get a JSON with __identity_bytes when getting a token with a JSON API
// and an Uint8Array when using BSATN
this.data =
data.constructor === Uint8Array
? uint8ArrayToHexString(data as Uint8Array)
: (data as { __identity_bytes: string }).__identity_bytes;
}

/**
* Compare two identities for equality.
*/
isEqual(other: Identity): boolean {
if (this.data.length !== other.data.length) {
return false;
}
for (let i = 0; i < this.data.length; i++) {
if (this.data[i] !== other.data[i]) {
return false;
}
}
return true;
return this.toHexString() === other.toHexString();
}

/**
* Print the identity as a hexadecimal string.
*/
toHexString(): string {
return Array.prototype.map
.call(this.data, (x) => ("00" + x.toString(16)).slice(-2))
.join("");
return this.data;
}

toUint8Array(): Uint8Array {
return this.data;
return hexStringToUint8Array(this.toHexString());
}

/**
* Parse an Identity from a hexadecimal string.
*/
static fromString(str: string): Identity {
let matches = str.match(/.{1,2}/g) || [];
let data = Uint8Array.from(
matches.map((byte: string) => parseInt(byte, 16))
);
return new Identity(data);
return new Identity({ __identity_bytes: str });
}
}
27 changes: 22 additions & 5 deletions src/serializer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AlgebraicType, BuiltinType } from "./algebraic_type";
import BinaryWriter from "./binary_writer";
import { Identity } from "./identity";

export interface Serializer {
write(type: AlgebraicType, value: any): any;
Expand Down Expand Up @@ -42,10 +43,19 @@ export class JSONSerializer {
case AlgebraicType.Type.ProductType:
let serializedArray: any[] = [];
for (const element of type.product.elements) {
const serialized = this.serializeType(
element.algebraicType,
value[element.name]
);
let serialized: any;
// If the value is an identity we can't use the `[]` operator, so we're
// special casing the identity type. It might be possible to define the
// `__identity_bytes` property on Identity, but I don't have time to check
// at the moment
if (value.constructor === Identity) {
serialized = value.toHexString();
} else {
serialized = this.serializeType(
element.algebraicType,
value[element.name]
);
}
serializedArray.push(serialized);
}
return serializedArray;
Expand Down Expand Up @@ -97,7 +107,14 @@ export class BinarySerializer {
break;
case AlgebraicType.Type.ProductType:
for (const element of type.product.elements) {
this.write(element.algebraicType, value[element.name]);
this.write(
element.algebraicType,
// If the value is an Identity we have to return an Uint8Array instead of trying
// to use the `[]` operator.
value.constructor === Identity
? value.toUint8Array()
: value[element.name]
);
}
break;
case AlgebraicType.Type.SumType:
Expand Down
4 changes: 1 addition & 3 deletions src/spacetimedb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1013,9 +1013,7 @@ export class SpacetimeDBClient {

const event = txUpdate["event"] as any;
const functionCall = event["function_call"] as any;
const identity: Identity = Identity.fromString(
event["caller_identity"]
);
const identity: Identity = new Identity(event["caller_identity"]);
const address = Address.fromStringOrNull(event["caller_address"]);
const originalReducerName: string = functionCall["reducer"];
const reducerName: string = toPascalCase(originalReducerName);
Expand Down
Loading