For the moment this is the raw plan / wish list to create a polling based version of synchazard
Server side
- easily create channels, which aggregate topics each one expose one endpoint
- each channels has a security token set the client must provide
- manage packed digest updates
- each channel is protected by a special channel_token the client must provide at subscription time
- the server will use a token the client must provide to access the rest api
Client side
- every communication is handled by a webworker which is the only one that receives/sends information to the server and the client handlers, thus plays like a proxy
- the webworker internally uses a private xhr client for the communication
- clients should easily create handlers per topic to consume responses
- responses will contain informations from all endpoints included in all subscribed topics
- each request must be authenticated via token (this is a security assumption on the srv, easily tunable)
- the configuration must include: rest endpoint url; mandatory rest endpoint token; optional polling interval
Limitations (TODOS)... at least those I can see
- server can only hit GET endpoint (for the moment)
- this is limited to one rest server
- run
yarn
- run
yarn buildev
to generate the sample code, let it run - run
yarn start:server
to start the pollteregeist node server , let it run - visit http://127.0.0.1:3001, check console
- change
sample/api/data/persons.json
...eithersource/sample/api/data/persons.json
if you did not stopped the previous live build
In the following discussion I'll have to make some assumptions:
-
You can run a node server (express, hapi, meteor, ...whatever) which allows to handle POST requests on a certain port
-
You can run one rest server, allowing crud operations on your data-layer through endpoints
-
Clients need to be allowed (cors) to hit #1.
In the sample runnable here with
yarn buildev
+yarn start:server
#1 is based on express and #2 is a bundling plugin I wrote some years ago, based on restify, but you can obviously use whatever allows #1 and #2.
polltergeist
import the server part, the one you need to integrate on your server (here for simplicity I assume express). More specifically import one single function, a request handler getting requestes from the client worker:
simple server side example
const config = require('./config.json'),
express = require('express'),
cors = require('cors'),
bodyParser = require("body-parser"),
port = 5034,
app = express(),
PolltergeistServerHandler = require('polltergeist'),
onErr = console.error;
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const handleRequest = (req, res) => {
res.setHeader('Content-Type', 'application/json');
const { body } = req,
sender = r => res.send(
JSON.stringify(r)
).end();
PolltergeistServerHandler({
body, sender, config, onErr
}).then(r => {/* Shut up */});
};
// free to use any path here
// client should anyway be in synch
app.post('/', handleRequest);
app.listen(
port,
() => log(`Example app listening on port ${port}`)
);
the only unclear thing here is that config
but a look at the used content in the example should clarify:
{
"channel1": {
"token": "AAABBB111222",
"topics": {
"persons": {
"endpoint": "http://127.0.0.1:3002/person/:id",
"params": [
"id"
]
}
}
},
"channel2": {
"token": "CCCDDD333444",
"topics": {
"cars": {
"endpoint": "http://127.0.0.1:3002/car/:id",
"params": [
"id"
]
}
}
}
}
Should be clear what this rest server is responsible for right?
The client setting is rather simple assuming we have a clear plan about what to keep in synch and most importantly the polling period needed.
For example if we need to check the status of two types of entities (retrievable throught two diffent endpoints) with the same period then we will need to set two topics in one channel :
var order = document.querySelector(...),
productAvailability = document.querySelector(...),
handlers = {
handler1: function(data) {
order.className = data.payload.status ? 'healthy' : 'unhealthy'
},
handler2: function(data) {
productAvailability.className = data.payload.availability ? 'available' : 'unavailable'
}
},
clientInstance = Polltergeist.getInstance(
{ url: "https://whereYouRunPolltergeistServer" },
handlers
);
clientInstance.synch('channel1', {
token: 'AAABBB111222',
pollingInterval: 1E2,
topics: {
order: {
params: {id: 23423},
handler: 'handler1'
},
product: {
params: {id: 'A-234234'},
handler: 'handler2'
},
}
});
here params can even contain functions and in that case the parameter can be dynamic:
function defaultTarget() {
return document.getElementById('trg').value
}
clientInstance.synch('channel1', {
token: 'AAABBB111222',
pollingInterval: 1E2,
topics: {
order: {
params: {id: defaultTarget},
handler: 'handler1'
},
// ...
},
live: true //this is needed in that case
});
but in that case we need to add live: true
.
Note that here the client does not really know anything about how those requests will be handled and resolved from the polltergeist server , but looking at that server config there's a clear mapping based on topics keys:
const baseUrl = "http://yourRest.data"
export default {
"channel1": {
"token": "AAABBB111222",
"topics": {
"order": {
"endpoint": `${baserul}/order/:id`,
"params": [ "id" ]
},
"product": {
"endpoint": `${baserul}/product/:id`,
"params": [ "id" ]
}
}
},
}
Looking at the client config is clear that each channel can bring one polling interval setting and define what exactly needs to be updated at that specific period.
This means that in case, together with channel1 (which is set with a quite short period) we want for example to synch the status of the user account every minute, we need to add another channel containing the right period and one topic (or more ) containing a reference to the handler function and the params.