Skip to content

Latest commit

 

History

History
427 lines (409 loc) · 23.2 KB

README.md

File metadata and controls

427 lines (409 loc) · 23.2 KB

Webject

Share (and sync) Objects Online with the power of websockets. Keys, Values AND References. Webject is short for Web Object and it really is a system for sharing objects on the web. Someone can host an object, then create and configure an authToken, enabling clients to connect to the object with the permissions/constraints defined by the respective authToken it a client connects with. Why Webject? This tool has usage for whenever one wishes to either collaborate on or simply share/sync real time data remotely with ease >:D
Please note:

  • To view example usage of the modules this library provides, please refer to the tests
  • Better example usages would be included later on other than the test file

Installation

Multiple ways

  • Download Github Package as ZIP
  • git cli: git clone https://github.com/Y0ursTruly/webject.git
  • npm cli: npm install webject
  • browser/frontend script tag: <script src="https://cdn.jsdelivr.net/npm/webject@latest/for_browser.min.js"></script>

Importing

const {
  serve, //doesn't exist on browser
  connect, //is a global variable when browser script is loaded
  sync, //doesn't exist on browser
  desync, //doesn't exist on browser
  objToString, //is a global variable when browser script is loaded
  stringToObj, //is a global variable when browser script is loaded
  objValueFrom, //is a global variable when browser script is loaded
  setConsistency //doesn't exist on browser
} = require("webject");

ADVISORY

If you (the developer) wish to use this as a database (achieve persistence using the sync module), in ACID, this library only enforces D without any work and A,C,D when utilising a given setConsistency module which should be used to declare if an object is safe for saving or not (if a transaction is complete or not). Isolation must be handled by you, the developer, since this library is designed to allow objects to be shared/synced among multiple clients concurrently.

Modules

  • serve([object[,server]])
    • Description: Creates a websocket and returns methods for configuring authTokens to share objects
    • Returns:
      myWebject Instance
      • authTokens Map
      • addListener(event,yourReaction)
        • Description: adds an event listener for the myWebject instance where the possible events are edit, connect and disconnect. An edit occurs when an object is edited, and the connect and disconnect events occur on when users connect and disconnect to and from authTokens
        • Returns:
          undefined
          
        • Arguments:
          • event String (either "edit", "connect" or "disconnect") The type of event to listen to
          • yourReaction function A function that responds to when an event occurs
      • endListener(event,yourReaction)
        • Description: Ends an event listener for the myWebject instance where the possible events are edit, connect and disconnect. An edit occurs when an object is edited, and the connect and disconnect events occur on when users connect and disconnect to and from authTokens
        • Returns:
          undefined
          
        • Arguments:
          • event String (either "edit", "connect" or "disconnect") The type of event being listen to
          • yourReaction function A function that was responding to when an event occurs
      • addToken(filter[,object[,specificToken[,coding]]])
        • Description: Configures an authToken with a given filter (used to control user edits), an optional object or the one passed in when calling the serve function, a specificToken of your choice or one generated for you, then the coding which is used for custom encoding/decoding
        • Returns:
          the string value of the authToken generated (either specificToken or one that was generated for you)
          
        • Arguments:
          • filter Number or function Manages/controls the edits that a user connected via this authToken attempts to make (if number, 1 for no edits, 2 for only adding new values[not modifying or deleting] or 3 for all edits, else a custom function that would return true if a specific edit is allowed)
          • object Object The object that users connected via this authToken will connect to (the one given here, else the one given in the serve function)
          • specificToken String A unique key that is the string authToken that users can connect to an object by
          • coding Object Defines custom encoding scheme, therefore if a user connects and doesn't have the same encoding scheme, they'd be unable to process the shared object and be booted
      • endToken(authToken)
        • Description: Ends support of the given string authToken that users were able to connect to an object by
        • Returns:
          Boolean (true)
          
        • Arguments:
          • authToken String The unique key that is the string authToken that users were able to connect to an object by
      • lock(authToken)
        • Description: Prevents new connections to the given authToken
        • Returns:
          Boolean (true)
          
        • Arguments:
          • authToken String The unique key that is the string authToken that users were able to connect to an object by
      • unlock(authToken)
        • Description: Allows new connections to the given authToken
        • Returns:
          Boolean (true)
          
        • Arguments:
          • authToken String A unique key that is the string authToken that users can connect to an object by
    • Arguments:
      • object object (default is {})The default object that will be served when addToken is called without a specified object
      • server instance of http.createServerThe server(instance of http.createServer) that the websocket will be existing on, or one created on port 8009
  • connect(location,authToken[,obj[,coding[,onFail]]])
    • Description: An asynchronous function that connects to and when resolved, returns an object that is hosted on a websocket with a specified authToken
    • Returns:
      A promise that when resolved, returns an object that is hosted on a websocket with a specified authToken
      
    • Arguments:
      • location String (ws or wss protocol) The remote destination's WebSocket URL for the object
      • authToken String The remote destination's authToken for the object
      • obj Object A local, given, custom object that will be modified by the contents of the server's object
      • coding Object Defines custom encoding scheme; used for when the server has the same custom encoding scheme and thus the user would understand the server
      • onFail function (true by default) This is called when disconnected from the websocket (whether the initial connect fails or some time after, the connection was cut) typically used for reconnection. It is true by default which means it will be a reconnection function by default. If you put your own function in, it should return a connect promise to simulate reconnection, however set it as false to disable automatic reconnection
  • objToString(obj[,noCache])
    • Description: Converts an object to an array which is a series stringified array of parts
    • Returns:
      String
      
    • Arguments:
      • obj Object The object that will be serialised/stringified
      • noCache Boolean (false) Determines if to rely on the previous state of the object(false) or not(true). It is false at default because it is usually more efficient to only share the differences/changes of the object in question
  • stringToObj(string[,obj[,constraint]])
    • Description: Modifies an object based on the string given, filtered by the constraint given, then returns that object. If no object was given, an empty object would be created and modified with that string
    • Returns:
      Object
      
    • Arguments:
      • string String Serialised/stringified array of parts
      • obj Object The object to modify based on the string filtered by the constraint
      • constraint Number OR Function If it is a number, 1(for view only), 2(for only adding new keys and not modifying or deleting any), 3(any and all edits) or a a custom function that deals with each part
  • sync(filePath[,obj[,coding]])
    • Description: A function that persistently saves a given object upon each change. Note that it will try to modify the given object from what is at the fileName first then write the object's contents to the fileName. If no object is given, it will be exactly what can be built from the contents in filePath or an empty object
    • Returns:
      Object
      
      • if syncList already includes filePath, the syncList's object already stored one to one relation between a unique object and a unique filePath is how sync function works do not worry about "should I desync when finished using sync" because there is a counter acting as the amount of times the function was called with a unique filePath

      • else if obj was given -- if filePath has webject serialised/stringified content, obj modified by contents of filePath -- else, the unmodified obj

      • else (obj was NOT given) -- if filePath has webject serialised/stringified content, solely the parsed value of filePath contents -- else, an empty object {}

    • Arguments:
      • filePath String The FULL system file path (the saved file would be filePath+'.json'
      • obj Object The object to be synchronised to the filePath
      • coding Object Defines a custom encoding scheme
  • desync(filePath)
    • Description: Terminates the synchronisation of an object to a given filePath (or simply decrements a counter discussed in sync)
    • Returns:
      undefined
      
    • Arguments:
      • filePath String The FULL system file path
  • partFilter(manditoryPath[,allowEdits])
    • Description: Creates a custom filter function that will only accept an edit from a part inside a certain manditoryPath
    • Returns:
      Function (the filter function)
      
    • Arguments:
      • manditoryPath String[] The path in the object in which edits will be accepted (only data inside/under this path gets edited)
      • allowAllEdits Boolean(false) Everything inside/under the given manditoryPath is treated like the number 2 filter(only new keys, no edits or deletions) WHEN FALSE. When true, all edits inside manditoryPath are allowed (like the number 3 filter)
  • setConsistency(object[,isConsistent])
    • Description: Declares if an object is safe for saving to disk, which the sync function checks this after each edit before saving file and would only save if consistency is true, however do note that consistency of an object is true by default
    • Returns:
      undefined
      
    • Arguments:
      • object Object An object that you are using sync on and wish to enforce atomicity and consistency on
      • isConsistent Boolean true means that the sync function can save the object to a file now, false means to not save the object to a file yet

Structures

Object

An object being shared can have many attributes and subattributes and even circular references without issue. However the top/root element of data being shared must be an Object (not an array).
This means, sharing arr could be done by sharing {arr} and accessing it in connected_data.arr for instance.

Unsupported Data Types

For the instances of data that will be ignored, they will simply not be shared or deleted if they were shared to be a value. Above are the instances of data that will be ignored

Supported Data Types

Now, the list of datatypes are listed above are supported and any other special class that isn't listed here would have its instances of data treated like a regular Object

Event

Let's look at what is given to yourReaction when you call the addListener function (which is a method of what is returned after calling the serve function)

{
  token: Object, //an authToken's object or null
  socket: Object, //a websocket client object or null
  type: String, //a string(either "edit", "connect", or "disconnect")
  lock: Function, //prevents more connections to an authToken passed in OR this event's token.authToken if called with none given
  unlock: Function, //allows new connections to an authToken passed in OR this event's token.authToken if called with none given
  preventDefault: Function //stops passing the event to other listeners after (the listener that calls this will be the last listener to see the event)
}

The or null parts with token and socket only apply to if the event is of type edit.
These would be null when an edit on an object occured on the server side, thus there is no client token and socket related/responsible for the event

Token

The authToken object, highly integral to this repository because authTokens configure and define how others connect/sync to your objects.
Let's look at its structure

{
  authToken: String,
  filter: Number OR Function,
  clients: Map,
  object: Object,
  locked: Boolean,
  dispatch: Function,
  encoder: Function OR null,
  decoder: Function OR null
}

This is authToken string, next is a filter which is either 1,2,3 or a function that would filter every part of an incoming edit, followed by a Map of websocket connections to this authToken, followed by the object that this authToken is meant to shared, followed by if it's locked, then a dispatch function responsible for this authToken (many authTokens might have the same dispatcher responsible for it), followed by an optional encoder and decoder for custom encoding.

Part

What is meant by part? objToString(someObj) always returns JSON.stringify(someArray) where someArray is made up of parts. Each part comes in the format

the value in ONE index(part) of an objToString array are 1 of the following types:

[path] //delete
[path,data] //value
[path,refPath,num] //reference
[path,data,0,tag] //custom datatype value

- path is array of strings to represent a location
- data is an instance of a datatype to represent a value
- refPath is an index to a referred path located in another index(part) or the path array itself
- num is a number which can be 3 options: 0=not mentioned, 1=mentioned as path, 2=mentioned as reference
- tag is the [Symbol.toStringTag] property of a value and is used for TypedArray, BigInt, Symbol and undefined and newly Date instances (the latter 2 which have no [Symbol.toStringTag] but isn't JSON)

Coding

This is an object of two functions: encode and decode. Each function must be robust since they can receive and also return ONE of two types of data: either string or buffer. In essence, they must have accomodations for two data types. Only one argument is given, data.

{
  function encoder(data/*instanceof Buffer or String*/){return an instanceof Buffer or String},
  function decoder(data/*instanceof Buffer or String*/){return an instanceof Buffer or String},
}