syncs
TypeScript icon, indicating that this package has built-in type declarations

1.1.1 • Public • Published

Syncs Logo

npm node npm dependencies Status Build Status

Syncs

A JavaScript Library for Real-Time Web Applications

Installation

npm install syncs --save

Initialization

Syncs is easy to initialize. Syncs is developed with typescript language.

Sample projects are avilable here.

Server Initialization

Syncs instance works with native nodejs http server.

import * as http from "http";
import syncs from "syncs";
 
let server=http.createServer()
let io=syncs(server);
server.listen(8080);

Developers are able to use light web frameworks like express.

import * as http from "http";
import * as express from "express";
import syncs from "syncs";
 
let app=express();
let server=http.createServer(app);
let io= syncs(server);
 
server.listen(8080);

Server Configuration

Sync module contains SyncServer class which acts as WebSocket server. With TypeScript language there is defualt module export to create SyncServer instance. SyncsServer constructor has two parameter.

  • Server: an instance of NodeJs http server.
  • config: an instance of SyncsConfig interface:
    • path : string : real-time serving path. default value is /syncs.
    • closeTimeout : number: times in millisecond that server waits after client disconnect, then it will remove the client from list of clients and groups. default value is 10000.
    • debug : boolean: enables debug mode to log input and output commands. default value is false.
let io=new SyncsServer(server,{
    path:'/real-time',
    closeTimeout:5000,
    debug:true
})

It's also possible to enable debug mode using io.enableDebugMode() and disable it with io.disableDebugMode() methods.

Client Initialization

Syncs clients are developed to run on most common platforms :

The rest of this documentation uses Browser Client Script.

There is two way to setup the Browser Client Script.

  1. Developers can download javascripts file from this link and add the syncs.js file to assets directory.
  2. On server side it's possible to access client script from Syncs instance:
        app.get('/syncs.js',(req,res)=>{
            res.send(io.clientScript);
        })

After serving client script, developers should include it in html page and create an instance of Syncs class.

   <!doctype html>
   <html >
   <head>
   <meta charset="UTF-8">
        <script src="syncs.js"></script>        
   </head>
       <body>
 
       </body>
       <script>
           let io=new Syncs();
       </script> 
   </html>

Client Script constructor has config parameter:

  • path:string: WebSocket url begins with ws:// protocol. default value is ws://domain/realtime which domain name will sets automatically.
  • autoConnect:boolean: If autoConnect is false then the Syncs instance will not connect to server on creation. To connect manuly to server developers should call io.connect() method. default value is true.
  • autoReconnect:boolean: This config makes the connection presistent on connection drop. default value is true.
  • reconnectDelay: number: time to wait befor each reconnecting try. default value is 10000.
  • debug:bolean: This parameter enables debug mode on client side. default value is false.

Handling connections

On both server and client side it's easy to handle client connection status change.

Handling client connection on server side

using onConnection on server side developers can notify about client connection to Syncs Server.

    //io as Syncs instance on server side
    io.onConnection(client=>{
 
    })

By any reason if client disconnects from Syncs Server, server waits for client connection. By using onClientDisconnect method of SyncsServer instance or onDisconnect method of SyncsClient instance developers can handle disconnect event.

    io.onClientDisconnect(client=>{
        //handle client disconnection
    })
    client.onDisconnect(()=>{
        //handle client disconnection
    })

After a specific time which developers can change with closeTimeout, close event will happen on server side. after this event client instance will be removed from clients list and groups. Developers can handle this event from both SyncsServer and SyncsClient instances.

  io.onClientClose(client=>{
      //handle close event
  })
    client.onClose(()=>{
        //handle close event
    })

Also server can disconnect and close client by calling close

Handling client connection on client side

On client side when the connection is established and hand shaking process completes, developers can notify with onOpen event handler.

   io.onOpen(()=>{
       // after first connection or reconnecting to server this function will be called
   })

Developers can handle disconnect and close event with onDisconnect and onClose method.

    io.onDisconnect(()=>{
 
    })
    io.onClose(()=>{
 
    })

Also it's possible to disconnect from server using disconnect method.

    io.disconnect();

Client Groups on Server Side

It's possible to manage clients in groups. SyncsGroup class is responsible to manage group of clients. Using groups developers can send messages and access abstraction functions on group of clients.

group method of SyncsServer instance will return named SyncsGroup instance.

   let guestGroup=io.group('guests');

Developers can add,remove and exclude client from a group.

    io.onConnection(client=>{
        io.group('guests').add(client);
    })
    function addToVip(client:SyncsClient){
        io.group('guests').remove(client);
        io.group('vips').add(client);
    }
    function broadCastEnterance(client:SyncsClient){
        io.group('vips').except(client).send({message:"new client"});
    }

When a client link closed, the instance of that client will remove from all groups.

Abstraction Layers

Syncs provides four abstraction layer over its real-time functionality for developers.

1. onMessage Abstraction Layer

This type of real-time development is primary type between other solutions and uses fundamental functionality of WebSocket. If data and functionality around that in web is simple, onMessage as a simple messaging solution may fit developers need. With Syncs it’s possible to access WebSocket functionality in low level mode. In this mode developer should handle all data transfer controls.

Developers can send messages using send method of SyncsClient instance on server side to send JSON message to the client. on client side, by using onMessage method of Syncs instance developers can recive all incoming messages.

//server side
io.onConnection(client=>{
    client.send({text:"welcome"});
})
//client side
io.onMessage(message=>{
    alert(message.text);
})

It's possible to send message from client to server.

//client side
function setName(newName){
    io.send({name:newName});
}
io.onMessage((message,client)=>{
    client.data.name=message.name;
})

On server side it's possible to send messages to group of clients

//server side
function sendServerTime(){
    io.group('authenticated').send({time:new Date().toTimeString()})
}

Developers should add extra properties to distinguish between messages.

2. Publish and Subscribe Abstraction Layer

With a Publish and Subscribe solution developers normally subscribe to data using a string identifier. This is normally called a Channel, Topic or Subject.

Both server and client can publish or subscribe to event. publish method is accessible from SyncsServer, SyncsGroup and SyncsClient instances on server side.

// server side
//sends time too all clients
function sendTime(){
   io.publish('time-report',{time:new Date})
}
//add client to group and report client entrance to group
function registerInGroup(groupName:string,client:SyncsClient){
   io.group(groupName).add(client).except(client).publish('new-member',{name:client.data.name});
}
//publish direct message to single client
function directMessage(client:SyncsClient,message:string,from:string){
   client.publish('direct-message',{from:from,message:message});
}
 
function waitForMessage(){
   io.subscribe('public-message',(data,client)=>{
       io.publish('public-message',{message:data.message,from:client.data.name})
   })
}
io.subscribe('time-report',data=>{
    console.log(data.time);
})
io.subscribe('new-member',data=>{
    //update members list
})
io.subscribe('direct-message',data=>{
    //show direct message to user
})
 
function sendPublicMessage(message:string){
    io.publish('public-message',{message:message});
}

It's possible to disable subscription to event using unSubscribe method.

### 3. Shared Data Abstraction Layer Syncs provides Shared Data functionality in form of variable sharing. Shared variables can be accessible in tree level: Global Level, Group Level and Client Level. Global Level and Group Level shared objects are readonly by client. Client Level shared object are write-able by client but server can make readonly client level shared object.

//server side
// reporting online users to all clients
let info=io.shared('info');
info.onlineUsers=0;
io.onConnection(client=>{
    info.onlineUsers++;
});
io.onClientClose(client=>{
    info.onlineUsers--;
})
//client side
let info=io.shared('info');
 
function logOnlineUsers(){
    console.log(info.onlineUsers);
}

It's possible to get shared variable in Group Level

//server side
function setGroupTopic(groupName:string,topic:string){
    io.group(groupName).shared('settings').topic=topic;
}

Client Level shared object by default is write-able by client.

   // server side
   function setName(client,name){
       client.shared('profile').name=name;
   }
    //client side
    function setName(name){
        io.shared('profile').name=name;
    }

Developers can create read only variables by passing second parameter to share method.

   //server side
   client.shared('session',true).id=getSessionId();

It's possible to add listener to check shared variable change. shared variable object returned by shared method can bee called as a function to add listener. Developers should pass a callback function to handle change event.

// client side
let info=io.shared('info');
 
info((values,by)=>{
   //handle changes
});

The callback function has two argument.

  • values:object: an object that contains names of changed properties and new values.
  • by:string a string variable with two value ( 'server' and 'client') which shows who changed these properties.

4. Remote Method Invocation (RMI) Abstraction Layer

With help of RMI developers can call and pass argument to remote function and make it easy to develop robust and web developed application. RMI may abstract things away too much and developers might forget that they are making calls over the wire.

Before calling remote method developer should declare the function on client or server script.

functions object in io is the place to declare functions.

//clint side
io.functions.showMessage=function(message) {
  alert(message);
}

The caller side can access remote method using remote object.

//server side
cliet.remote.showMessage('welcome...');

The remote side can return a result which is accessible using Promise object returned by caller side.

//client side
io.functions.getUserVote=function(message:string,options:string[]){
    let userVote=askUser(message,options);
    return userVote;
}
//server side
cliet.remote.getUserVote(
    "Which programming language is better?",
    ['C#','Java','Javascript','Python']).then(result=>{
        // handle result ...
    })

Remote side can return another Promise object if the result is not accessible yet.

It's also possible to interfere remote method calling using onRMI method on server side. This method has two argument. name the name of remote method or regular expression format of string and the callback which is handler of interfering.

Return value from this callback will handle next steps of remote method invocation as follow:

  • if developer returns nothing next handler invokes and if there is no more handler the target method will be called.
  • if developer returns a specific value (synchronously) then the RMI result will be the returned value.
  • if developer returns a promise then the result of resolve or reject methods will handles next steps.
// check authentication on before method call
io.onRMI('admin.*',(client,name,args)=>{
   return new Promise((res,rej)=>{
       //authenticate
       if(authenticated){
           rej();
       }else{
           res({error:"user is not authenticated"});
       }
   });
})
 
 

Package Sidebar

Install

npm i syncs

Weekly Downloads

0

Version

1.1.1

License

MIT

Unpacked Size

130 kB

Total Files

26

Last publish

Collaborators

  • mostaffa