Data serialization library for communication and storage purpose with versioning.
The library is focused on solving two specific issues:
-
The application version mismatch
Data serialization is a complicated task, specially when you are maintaining a project for a long time. With addition of a new feature, it becomes complicated to keep your data readable between two versions of your same software.- You have saved your data using older version of your software, which would pose an issue when loading with a newer version of your software.
- You have a client server application, where the server has been updated to a newer version, but there still exists client that hasn't updated for a long time. In rare case scenario (like our hotspot games), the server could be an older version whereas the client might have been a newer version.
-
Loading class instances from serializable data
While loading data either from storage or a communication channel, it is always extra work to map that data to particular instance. We try to solve that with two different approach:- Make the classes
Serializable
and useOracle
for serialization, identification and creation of class instances. - For certain scalar objects (ex: ComplexNumber), treat them like a primary data
type and create helper functions
serializeComplexNumber
to serialize these objects.
function serializeComplexNumber(serializer: Serializer, complexNumber: ComplexNumber) { if (serializer.isLoading) { const real = serializer.double(0); const imaginary = serializer.double(0); return new ComplexNumber(real, imaginary); } else { serializer.double(complexNumber.real); serializer.double(complexNumber.imaginary); return complexNumber; } }
- Make the classes
Side Goal
When it comes to serialization, most of the time, the error arises due to performing
data reading and writing with two different codes. We have tried to minimize that
by doing both reading and writing with the same code. For example, a typical object
serialization would look like:
function serialize(serializer: Serializer) {
this.name = serializer.string(this.name);
this.dob = new Date(serializer.int32(this.dob.getTime() / 1000) * 1000);
this.salary = serializer.double(this.salary);
}
In rare cases, if you need a different logic for reading and writing, the isLoading
flag on Serializer
should be used.
yarn add @bhoos/serialization
Use the basic function from Serializer
for primary data type serialization:
int8
int16
int32
uint8
uint16
uint32
float
double
string
Properties available in Serializer
version
The version of the serializer typically based on the app.isLoading
The mode of the serializer. Based on the mode, the data is either read (loading
) or written.
Implement the Serializable interface
import { Serializable, Serializer } from '@bhoos/serialization'
class ComplexNumber implements Serializable {
real: number;
imaginary: number;
// Implement the serialize function
serialize(serializer: Serializer) {
// Assuming we used floating size number in earlier version
// and later upgraded to double size numbers
if (serializer.version < 2 ) {
serializer.float(this.real);
serializer.float(this.imaginary);
} else {
serializer.double(this.real);
serailizer.double(this.imaginary);
}
}
// Optionally extend onCreate to initialize object
// after serialization creates it
onCreate() {
}
}
class CommunicationChannel {
private oracle = new Oracle();
constructor(version: number) {
this.version = version;
this.oracle.register(1, ComplexNumber);
}
sendObject(obj: Serializable) {
// Initialize buffer serializer for writing
const serializer = new BufferSerializer(this.version, 1000);
this.oracle.serialize(serializer, obj);
this.channel.send(serializer.getBuffer());
}
receiveObject(buffer: Buffer) {
const serializer = new BufferSerializer(this.version, buffer);
const obj = this.oracle.serialize(serializer, null);
return obj;
}
}
serializeArray
: Serialize an array of specific types
- Ex:
serializeArray(serializer.string, serializer, source)
; - Ex:
serializeArray(this.factory.bind(serializer), serializer, objArray)
- Ex:
The standard JSON (JSONSerializer
) and Buffer (binary) (BufferSerializer
) serializers are provided
with the library. If any other format are required, they
can be created by implementing the Serializer
interface.