infoserver

0.0.7 • Public • Published

InfoServer

File manager server & middleware

Usage

npm install --save infoserver

Then, in your js:

 
import infoServer from 'infoserver';
 
infoServer(rootDir,{/**options**/}).then(api=>
    api.commands.getMeta('/some/file/path')
        .then(result=>{console.log(results)})
        .catch(err=>{throw err})
})
 

or as an express middleware:

 
var app = require('express').app
import infoServer from 'infoserver';
 
infoServer(rootDir,{/**options**/}).then(api=>
    app.use('/meta',api.middleware);
})
 

(go to examples/express and run npm install && node index.js to check an example of a bare bones express app)


infoServer(rootDir,options) → Promise

  • rootDir is your public directory
  • options is an object with the following switches:
    • adapter: provide an adapter database for collections (see below for spec).
    • persist: either a boolean, or a file path. Used by the default memory adapter to write/load the database to/from a json file. Only use it to prototype, provide your own adapter for production
    • filters: an array of filters used by getMeta and getMetaRecursive.

The promise resolves to an api generated by apido.


commands

All commands from fs-meta, plus:


Selections

infoserver exposes a selections api to group files together. They work like virtual directories in the sense that they can contain files, or other selections.

All selections commands use an adapter for persistence. Only a memory adapter is provided by default, to create your own, see the spec below.

All arrays can be specified, in a GET array, either by repeating the key (?files=x&files=y), or by separating them with a comma (?files=x,y).

api.selections.commands.add(groupName[,files[,groups]])

Adds a group called groupName and adds the files and groups specified. If groupName does not exist, it is created. If it already has files or groups, new files and groups are appended.

Also accessible through api.runPath('/selections/add',{groupName,files,groups}) or on the http url /selections/add/:groupName?files=x&files=y&groups=x&groups=y

api.selections.commands.get([type,items])

if nothing is specified, returns all groups that are children of the root group. items is an array of files paths if type is "file", or an array of groups names if type is "group"

Also accessible through api.runPath('/selections/get',{type,items}) or on the http url /selections/get/:type?items=a&items=b

api.selections.commands.remove(groupName[,files[,groups]])

If files or groups are not specified, deletes the group designed by groupName, as well as any files that are only in that specific group. if files and groups are specified, removes the specified files and sub-groups from the group. Orphan files are removed, but orphan groups aren't.

Also accessible through api.runPath('/selections/remove',{groupName,files,groups}) or on the http url /selections/remove/:groupName?files=x&files=y&groups=x&groups=y

Objects

An example response from selections/get/a:

{
    response:"success",
    //api meta data...
    "result":{
        "groups": {
            "groupA": {
                "name": "groupA",
                "files": ["path/to/a","path/to/b","path/to/c"],
                "groups": []
                }
            },
        "files": {
            "path/to/a": {
                "path": "path/to/a",
                "parents": ["groupA"]
            },
            "path/to/b": {
                "path": "path/to/b",
                "parents": ["groupA"]
            },
            "path/to/c": {
                "path": "path/to/c",
                "parents": ["groupA","groupB"]
            }
        }
    }
} 

Here's an easy function to re-nest everything in a cyclic structure if you wanted to:

function nest({result},cache){
    cache = cache || {
        groups:{}
    ,   files:{}
    }
    function add(collection,value){
        const key = collection == 'files' ? 'path' : 'name';
        const obj = {[key]:value};
        cache[collection][value] = obj;
        return obj; 
    }
    for(group of result.groups){
        let {name} = group;
        let files = group.files.map(path=>
            result.files[path] || cache.files[path] || add('files',path)
        )
        let groups = group.groups.map(name=>
            result.groups[name] || cache.groups[name]|| add('groups',name)
        )
        if(cache.groups[name]){
            Object.assign(cache.groups[name],{files,groups});
        }else{
            cache.groups[name] = {name,files,groups}
        }
    }
    for(file of result.paths){
        let {path} = file;
        file.parents = file.parents.map(name=>
            result.groups[name] || cache.groups[name] || add('groups',name)
        )
        if(cache.files[path]){
            cache.files[path].parents = parents;
        }else{
            cache.files[path] = {path,parents}
        }        
    }
    return cache;
}

Adapter

An adapter has the following signature:

export default Promise.promisify(function customAdapter(fs,opts,cb){
     const commands = {
        add(groupName,files,groups,cb){}
    ,   getFiles(files,cb){}
    ,   getGroups(groups,cb){}
    ,   getRoot(cb){}
    ,   remove(groupName,files,groups,cb){}
    }
    cb(null,commands);
})
  • add is guaranteed to receive a group name, but files and groups are optional. If a group doesn't exist, it is expected that add creates it on the fly. If it already exists, then groups and files should be added to the existing groups and files.
  • getFiles receives an array of files paths
  • getGroups receives an array of group names
  • remove is guaranteed to receive a group name, but files and groups are optional. If groups and files are empty, then the function should remove the group specified by groupName (as well as cascade all relations). If either files or groups are specified, then the group should remove all

Tests & Compile

First:

npm install --dev

Compile:

npm run compile

tests:

Not implemented yet

run example:

cd examples/express
npm install
cd ../..
npm start

Then open http://localhost:3000 in your browser

To get debug messages, you can set:

DEBUG=infoserver:* node yourApp.js

MIT License

Copyright © Jad Sarout

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Package Sidebar

Install

npm i infoserver

Weekly Downloads

5

Version

0.0.7

License

MIT

Last publish

Collaborators

  • xananax