0.8.6 • Published 6 years ago

niwa v0.8.6

Weekly downloads
4
License
MIT
Repository
github
Last release
6 years ago

NIWA

NIWA Intertwined Web Applications

NIWA is an application server for simple NodeJs apps that can communicate with each other.

##Usage

  • maual git clone or download npm update or npm install * npm run start
  • cli
    	```
    		npm install -g niwa
    		niwa <work directory> <port>
    	```
  • api
    	```js
    		let starter=require("niwa"); // function(niwaWorkDir=__dirname,overridePort=null)
    		starter();
    	```

#Work directory If no directory is provided the install directory is used. Config, Logs and application data is stored in this directory.

##structure

.
├─ config
   ├─ server.json
   ├─ apps.json
   ├─ users.json
   ├─ permissions.json
   └─ <appName>.config.json
├─ apps
   └─ ...
├─ logs
   └─ ...
└─ <work> // applications should persist files under a directory with its own name

You can use an empty directory as a work directory. In order to start without providing a port you need a config/server.json.

###config/server.json

{
	"port":8081,
	"logLevel":"INFO",			// default logger level
	"allowCommunication":true,	// default for communications
	"autoStart":false			// default to start app on server start
}

#####defaults

logLevel:"INFO"
allowCommunication:true
autoStart:false

#Apps An Application is a directory full of static assets with few exceptions. Each app is deployed in a separate NodeJs process (using Morgas nodeWorker). To deploy an app you can place it in a directory under apps or define it in the config/apps.json (or both).

##config/apps.json

{
	"<name>":{
		"path":"<relative from apps or absolute>",
		//overwrite defaults
		"autoStart":boolean,
		"logLevel":"<level>", // bunyan log levels
		"communication": boolean || {
			"<name>":boolean || ["<context>"]
		}
	}
}

##styles *.less files are automatically compiled when they are requested with a url containing /css/ instead of /less/.

e.g.: app/some/css/path/styles.less=>app/some/less/path/styles.less //compiled

##rest services Defining a rest service means simply putting a <name>.js file in the app/rest directory in your application. Those files are loaded when the application gets deployed. Such a file can export a function or a object structure of functions. Each context of the requested url is matched to a key in that structure until a function is found. The first context matches to the filename (without the extension). The remainder of the path as an array is also provided as the second argument of the function.

module.exports=function({method,headers,query,data,path},path=[])
{
	return "hello world";
}

A function may return any serializable (JSON.stringify) value or an instance of ServiceResult.

###context notes

  • running as a Morgas worker
  • process.cwd() // application directory
  • niwa/util is added as resource folder - ServiceResult - configManager - dependencyManager - mimeTypes (irrelevant)
  • global worker extensions

#####util/ServiceResult A small class for rest responses.

let ServiceResult=µ.getModule("ServiceResult");
return new ServiceResult({status:403,data:"Please log in first"});

#####util/configManager Creates a rest api for a persistent config. The config is saved under <work directory>/config/<app context>.json with file rotation of 3.

Parameter Morgas.Config or a config description (see Morgas.Config.parse)

returns

api=function(param) // rest api
api.ready //Promise that is resolves to Morgas.Conig instance
api.addChangeListener=function(path,fn)
api.removeChangeListener=function(pathOfFn,fn)
api.notify=function(path, oldValue, newValue) // triggers changeListeners
api.save=function() // returns Promise

Example service

module.exports=µ.getModule("configManager")({
	name:"string",
	range:{
		type:number,
		default:3,
		min:0,
		max:10,
		step:0.5
	},
	check:{
		type:"boolean"
	},
	list:{
		type:"array",
		model:"string"
	}
});

#####dependencyManager Creates a rest api to serve js files with all needed dependencies. It uses morgas/lib/dependencyParser to parse files

Parameter Array of file or directory paths and a base path from which navigation begins

returns

api=function(param) // rest api
api.addResource=function(moduleRegister,moduleDependencies,directory,name=null)

Morgas and MorgasGui resouces are already registered

Example service

module.exports=µ.getModule("dependencyManager")(["js"],"js");

####global worker extensions

worker.eventSource=function(name,getter) returns trigger function(eventName,data) for server send events
worker.module=function(moduleName,methodName,args=[]) // call module
worker.getCommunicationList=function(name) // returns a Promise resolving to an array of contexts
{
	return worker.ask("NIWA","communicationList",{name:name});
};
worker.ask=function(context,method,data) // communicate with (call methods from) other applications 
worker.serverStarted=function() // overwrite for callback when server is started and communication is possible

###package.json Having a package.json for an application is optional. But it is needed for communication and additional configuration.

#####application name The name of the application is defined in niwa.name or name of its package.json

####setup script If you define a niwa.setup the script gets called (required) when starting the application. It is possible to export a Promise for asynchronous setups.

The script is called before any rest service is loaded.

#####dependencies You can define application dependencies in the niwa.dependencies array. Currently this is only a treated as a hint and is therefore optional.

##Communication Applications with a name can communicate with each other. It has to be allowed in the apps.json.

#####Example app1

worker.myMethod=function(data,context)
{
	if(context=="someContext") return Promise.reject();
	return "value";
};

app2

worker.getCommunicationList("app1")
.then(function(list)
{
	if(list.length==0) return Promise.reject();
	
	return worker.ask(list[0],"myMethod")
	.then(function(data)
	{
		//handle answer
	});
}

#Modules Modules are extensions that can be called from applications.

##session Session object

{
	"token":"token",
	"user":{
		"name":"name"
	}
}

Guest users have always an empty string as name

####methods

  • create() => Session object
  • get(token) => Session object
  • getOrCreate(token) => Session object
  • delete(token) => boolean
  • refresh(token) => boolean // mostly internal

##user ####methods

  • logIn(sessionToken,username,password="") => void (reject value is a ServiceResult)
  • logOut(sessionToken) => void (reject value is a ServiceResult)
  • register(sessionToken,username,password) => void (permission "registerUser" needed)
  • delete(sessionToken,username) => void (permission "deleteUser" needed)
  • list(sessionToken) => void (permission "readPermissions" needed)

##permissions ####methods

  • check(sessionToken,toCheck=[]) => void (reject value is a ServiceResult)
  • checkAll(sessionToken,toCheck=[]) => Boolean[] (reject value is a ServiceResult)
  • getAll(sessionToken) => void (permission "readPermissions" needed)
  • addUser(sessionToken,name) => void (permission "addUser" needed)
  • setUser(sessionToken,name,roles,permissions) => void (permission "setUser" needed)
  • deleteUser(sessionToken,username) => void (permission "deleteUser" needed)
  • addRole(sessionToken,name) => void (permission "addRole" needed)
  • setRole(sessionToken,name,roles,permissions) => void (permission "setRole" needed)
  • deleteRole(sessionToken,name) => void (permission "deleteRole" needed)

#Server send events EventSources can be accessed via <app context>/event/<event name>. Ordinary get requests are also supported. ###usage

  • app 1. let notify=worker.eventSource("myEvent",()=>"init value"); 2. notify("update",value);
  • client 1. let source=new EventSource("event/myEvent"); 2. source.addEventListener("init",event=>alert(event.data)); 2. source.addEventListener("update",event=>alert(event.data));

#Special paths host:port/morgas/* serves Morgas files host:port/morgas/gui/* serves MorgasGui files host:port/morgas/gui/css/theme/<theme name> serves MorgasGui compiled theme style host:port/morgas/gui/css/<module name>[/<theme name>] serves MorgasGui compiled module styles