Skip to content

Commit

Permalink
feat(plugins): moved all REST calls into plugin, Subscriptions to follow
Browse files Browse the repository at this point in the history
  • Loading branch information
wzr1337 committed Jan 11, 2017
1 parent aee3bae commit 7968d88
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 84 deletions.
188 changes: 112 additions & 76 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ declare function require(moduleName: string): any;

const PLUGINDIR = path.join(__dirname, "plugins");
const URIREGEX = /^\/(\w+)\/(\w+)\/([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fAF]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})?#?\w*\??([\w$=&\(\)\:\,\;\-\+]*)?$/; //Group1: Servicename, Group2: Resourcename, Group3: element id, Group4: queryparameter list

const BASEURI = "/";

// set up the server
var server = new WebServer();
Expand All @@ -24,7 +24,7 @@ server.init(); // need to init
*/
fs.readdir(path.join(__dirname, "plugins"), (err:NodeJS.ErrnoException, files: string[]) => {
if(err) {
console.error(err);
throw err;
}
files.forEach(file => {
let module = path.join(PLUGINDIR, file);
Expand All @@ -35,18 +35,24 @@ fs.readdir(path.join(__dirname, "plugins"), (err:NodeJS.ErrnoException, files: s
service.resources.map((resource:Resource) => {
let basePath = "/" + service.name.toLowerCase() + "/" + resource.name.toLowerCase() + "/";
console.log("Registering endpoint:", service.name);
if(resource.isGetable) {
server.app.get(basePath + ':id', elementGetTemplate(service, resource));
}
server.app.get(basePath, resourceGET(service, resource)); //READ
server.app.post(basePath, resourcePOST(service, resource)); //CREATE
server.app.post(basePath + ':id', elementPOST(service, resource)); //READ
server.app.get(basePath + ':id', elementGET(service, resource)); //UPDATE
server.app.delete(basePath + ':id', elementDELETE(service, resource)); //DELETE
});
}
});
});

const elementGetTemplate = (service:Service, resource:Resource) => {
let GETPathElement = "/" + service.name.toLowerCase() + "/" + resource.name.toLowerCase() + "/:id"
console.log("GET", GETPathElement, "registered");
const elementGET = (service:Service, resource:Resource) => {
let elementPath = pathof(service, resource) + "/:id"
console.log("GET", elementPath, "registered");
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if(!resource.getElement) {
res.status(501).send("Not Implemented");
return;
}

// proprietary element fetching
let element = resource.getElement(req.params.id);
Expand All @@ -65,70 +71,115 @@ const elementGetTemplate = (service:Service, resource:Resource) => {
};
};

const resourceGET = (service:Service, resource:Resource) => {
let resourcePath = pathof(service, resource);
console.log("GET", resourcePath, "registered");
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if(!resource.getResource) {
res.status(501).send("Not Implemented");
return;
}
console.log(req.params);
// get all available renderes and map their representation to JSON compatible values
function parseNumberOrId(n:string|number):string|number {
return (!isNaN(parseFloat(<string>n)) && isFinite(<number>n)) ? parseFloat(<string>n) : n.toString();
}

const rendererId = "d6ebfd90-d2c1-11e6-9376-df943f51f0d8";//uuid.v1(); // FIXED for now
let elements = resource.getResource(parseNumberOrId(req.query.$offset), parseNumberOrId(req.query.$limit));

var renderers = [
new BehaviorSubject<{}>({
uri: "/media/renderers/" + rendererId,
id: rendererId,
name: "Netflux",
state: "idle",
offset: 0
})
]
if(elements) {
let resp = elements.map((value) => {
return value.getValue();
});
res.status(200);
res.json({
status: "ok",
data: resp
});
return;
}
else {
res.status(404).send("Not found");
}
};
};

const resourcePOST = (service:Service, resource:Resource) => {
let resourcePath = pathof(service, resource);
console.log("POST", resourcePath, "registered");
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if(!resource.createElement) {
res.status(501).send("Not Implemented");
return;
}
};
};

var interval:NodeJS.Timer; //@TODO has to become per-renderer
server.app.post('/media/renderers/:id', (req: express.Request, res: express.Response, next: express.NextFunction) => {
const elementDELETE = (service:Service, resource:Resource) => {
let elementPath = pathof(service, resource) + "/:id"
console.log("DELETE", elementPath, "registered");
return (req: express.Request, res: express.Response, next: express.NextFunction) => {

// find the element requested by the client
let element = renderers.find((element:BehaviorSubject<{}>) => {
return (<{id:string}>element.getValue()).id === req.params.id;
});
if(!resource.deleteElement) {
res.status(501).send("Not Implemented");
return;
}
// proprietary element deletion
let succeeded = resource.deleteElement(req.params.id);

if(element){
let renderer:any = element.getValue();

if (req.body.hasOwnProperty("state")) {
renderer.state = req.body.state;
if (req.body.state === "play") {
const speed = 1000;
interval = setInterval(() => {
renderer.offset = renderer.hasOwnProperty("offset") ? renderer.offset + speed : 0;
element.next(renderer);
}, speed);
// respond
if(succeeded){
res.status(200);
res.json({
status: "ok"
});
return;
}
else {
res.status(500).send();
return;
}
};
};

const elementPOST = (service:Service, resource:Resource) => {
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
// find the element requested by the client
let element = resource.getElement(req.params.id);
if (element){
if(resource.updateElement(req.params.id, req.body)) {
res.status(200);
res.json({
status: "ok"
});
}
else {
clearInterval(interval);
res.status(500).send();
}
}
else {
res.status(404).send("Not Found");
}
};
};

element.next(renderer); // @TODO: check diffs bevor updating without a need
res.status(200);
res.json({
status: "ok",
data: renderers[0].getValue()
});
}
else {
res.status(404).send();
}
});
function pathof(service:Service, resource:Resource) {
return BASEURI + service.name.toLowerCase() + "/" + resource.name.toLowerCase();
}

server.app.get('/media/renderers/', (req: express.Request, res: express.Response, next: express.NextFunction) => {

// get all available renderes and map their representation to JSON compatible values
let resp = renderers.map((value) => {
return value.getValue();
});

res.status(200);
res.json({
status: "ok",
data: resp
});
});
/// TO BE REMOVED
const rendererId = "d6ebfd90-d2c1-11e6-9376-df943f51f0d8";//uuid.v1(); // FIXED for now

var renderers = [
new BehaviorSubject<{}>({
uri: "/media/renderers/" + rendererId,
id: rendererId,
name: "Netflux",
state: "idle",
offset: 0
})
]
/// TO BE REMOVED


/*var subscribers:{
Expand Down Expand Up @@ -192,19 +243,4 @@ server.ws.on('connection', (ws) => {
}

})
});



// register an Object
var subscription = renderers[0].subscribe(
(x:any) => {
console.log('Next: ' + JSON.stringify(x));
},
(err:any) => {
console.log('Error: ' + err);
},
() => {
console.log('Completed');
});

});
43 changes: 39 additions & 4 deletions src/plugins/media/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,51 @@ class Renderer implements Resource {
return this._name;
}

get isGetable():Boolean {
return true;
}

getElement(elementId:string):BehaviorSubject<{}> {
// find the element requested by the client
return this._renderers.find((element:BehaviorSubject<{}>) => {
return (<{id:string}>element.getValue()).id === elementId;
});
}

getResource(offset?:string|number, limit?:string|number):BehaviorSubject<{}>[]{
// retriev all element
let resp:BehaviorSubject<{}>[];

console.log(typeof offset, offset.toString(),typeof limit, limit.toString());
if((typeof offset === "number" && typeof limit === "number") || (typeof limit === "number" && !offset) || (typeof offset === "number" && !limit) || (!offset && !limit)) {
console.log(offset.toString(), limit.toString());
resp = this._renderers.slice(<number>offset, <number>limit);
}

return resp;
}


private _interval:NodeJS.Timer; //@TODO has to become per-renderer
updateElement?(elementId:string, difference:any):Boolean {
console.log("whaaaat")
let element = this.getElement(elementId);
let renderer:any = element.getValue();
if (difference.hasOwnProperty("state")) {
renderer.state = difference.state;
if (difference.state === "play") {
const speed = 1000;
this._interval = setInterval(() => {
renderer.offset = renderer.hasOwnProperty("offset") ? renderer.offset + speed : 0;
element.next(renderer);
}, speed);
}
else {
clearInterval(this._interval);
}
element.next(renderer); // @TODO: check diffs bevor updating without a need
}
else {
return false;
}
return true;
}
}

export = Media;
14 changes: 10 additions & 4 deletions src/plugins/viwiPlugin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ declare namespace viwiPlugin {

interface Resource {
name:string;
getElement(elementId:string):BehaviorSubject<any>;
isGetable?:Boolean;
isSetable?:Boolean;
isDeletable?:Boolean;

//@TODO: will returning promises make sense???
getResource?(offset?:string|number, limit?:string|number):BehaviorSubject<any>[]; //GET /<service>/<resource>/
createElement?(state:{}):Boolean; //POST /<service>/<resource>/<element>
getElement(elementId:string):BehaviorSubject<any>; //GET /<service>/<resource>/<element>
updateElement?(elementId:string, difference:any):Boolean; //POST /<service>/<resource>/<element>
deleteElement?(elementId:string):Boolean; //DELETE /<service>/<resource>/<element>

resourceSubscribable?:Boolean; //subscribe /<service>/<resource>/
elementSubscribable?:Boolean; //subscribe /<service>/<resource>/<element>
}
}
export = viwiPlugin;

0 comments on commit 7968d88

Please sign in to comment.