syncs
v1.1.1
Published
Real-Time Web framework using WebSocket
Downloads
1
Maintainers
Readme
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 NodeJshttp
server.config
: an instance ofSyncsConfig
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 is10000
.debug : boolean
: enables debug mode to log input and output commands. default value isfalse
.
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.
- Developers can download javascripts file from this link and add the
syncs.js
file to assets directory. - 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 withws://
protocol. default value isws://domain/realtime
which domain name will sets automatically.autoConnect:boolean
: IfautoConnect
isfalse
then the Syncs instance will not connect to server on creation. To connect manuly to server developers should callio.connect()
method. default value istrue
.autoReconnect:boolean
: This config makes the connection presistent on connection drop. default value istrue
.reconnectDelay: number
: time to wait befor each reconnecting try. default value is10000
.debug:bolean
: This parameter enables debug mode on client side. default value isfalse
.
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"});
}
});
})