Skip to content

fsystech/cwserver

Repository files navigation

Cwserver Logo

Linux Build npm version NPM Downloads Coverage Status

cwserver

The aim of the project is to create an easy to use, lightweight, Complete Web Server Framework with default NodeJs HTTP Server.

  • The framework also provides default
    • Secure User Session,
    • Cookie Parser,
    • Flexible Router,
    • Multiple Views,
    • Virtual Directory,
    • Hidden Directory,
    • Template Engine,
    • Nested Master Template Engine,
    • Post Data Handler (with multipart form data and large file),
    • Mimetype Handler,
    • WebStream Handler,
    • JS/CSS Bundler,
    • socket.io Interface,
    • Easy way to bind with IIS/NGINX

Install cwserver by this command npm i cwserver
How to use cwserver core IApplication?

const { App } = require('cwserver');
const app = App();
const port = 8080;
app.on("request-begain", (req) => {
    console.log(`${req.method} ${req.path}`);
});
app.on("response-end", (req, res) => {
    console.log(`Send ${res.statusCode} ${req.path}`);
});
app.use((req, res, next) => {
    res.status(200).send("Hello World...");
});
app.listen(port, () => {
    console.log(`Listing port => ${port}`);
});

Or you may use full application by following:
Create createProjectTemplate.js as following

const { createProjectTemplate } = require( 'cwserver' );
createProjectTemplate( {
    appRoot: __dirname,
    projectRoot: "www" /** Your project root folder name*/,
    allExample: false
} );

Then run this commmand node createProjectTemplate
It will create default project template for cwserver in your application root.
Now your appRoot look like this

appRoot 
├─┬ wwww ( projectRoot )
│ └─┬ config
│   ├ lib
│   ├ template (this contains master template file)
│   ├ web (this contains temp and cache files)
│   └ index.html
├─ node_modules
├─ server.js
├─ package.json
└─ README.md

After, run this command node server www /**your project root*/

How to setup middleware

First process app.prerequisites every request and then run app.use

global.cw.server.on( "register-view", ( app, controller, server ) => {
	app.prerequisites( ( req, res, next ): void => {
		res.setHeader( 'x-frame-options', 'sameorigin' );
		return next();
	} );
	app.use( ( req, res, next ): void => {
		res.setHeader( 'x-frame-options', 'sameorigin' );
		return next();
	} );
} );

How to setup router ?

global.cw.server.on( "register-view", ( app, controller, server ) => {
    controller
        .any( '/test-any/*', ( ctx, match ) => {
            return ctx.res.json( { reqPath: ctx.path, servedFrom: "/test-any/*", q: match } );
        } )
        .get( '/task/:id/*', ( ctx, match ) => {
            return ctx.res.json( { reqPath: ctx.path, servedFrom: "/task/:id/*", q: match } );
        } )
        .get( '/dist/*', ( ctx, match ) => {
            return ctx.res.json( { reqPath: ctx.path, servedFrom: "/dist/*", q: match } );
        } )
        .get( '/user/:id/settings', ( ctx, match ) => {
            return ctx.res.json( { reqPath: ctx.path, servedFrom: "/user/:id/settings", q: match } );
        } );
} );

How to add Virtual Directory ?

global.cw.server.on( "register-view", ( app, controller, server ) => {
    const vDir = path.join( path.resolve( server.getRoot(), '..' ), "/project_template/test/" );
    server.addVirtualDir( "/vtest", vDir, ( ctx ) => {
        return mimeHandler.render( ctx, vDir, true );
    } );
    server.addVirtualDir( "/test-virtual", vDir );
    server.addVirtualDir( "/vtest/virtual/", vDir );
} );

Authetication

Session cookie name use from app.config.json => session.cookie
and session encryption use app.config.json => session.key

global.cw.server.on( "register-view", ( app, controller, server ) => {
    controller.get( '/authenticate/:loginId/:roleid', ( ctx, requestParam ) => {
        if ( ctx.req.session.isAuthenticated ) {
            ctx.res.status( 200 ).type( "html" ).send( `Hello ${ctx.req.session.loginId}` );
        } else {
            ctx.setSession(/*loginId*/requestParam.query.loginId,/*roleId*/requestParam.query.roleId, /*userData*/{ token: ctx.req.query.token } );
            ctx.res.status( 200 ).type( "html" ).send( `Authentication success ${ctx.req.query.loginId}` );
        }
        return ctx.next( 200 );
    } );
} );

SignOut From Application

global.cw.server.on( "register-view", ( app, controller, server ) => {
	controller.get( '/signout', ( ctx, requestParam ) => {
		if ( ctx.session.isAuthenticated ) {
			ctx.signOut();
		}
		ctx.redirect( "/" ).next( 302, true );
	} );
} );

Handle post data

const { getBodyParser, fsw } = require( 'cwserver' );
global.cw.server.on( "register-view", ( app, controller, server ) => {
    const downloadDir = server.mapPath( "/upload/data/" );
    if ( !fs.existsSync( downloadDir ) ) {
        fsw.mkdirSync( server.mapPath( "/" ), "/upload/data/" );
    }
    const tempDir = server.mapPath( "/upload/temp/" );
    controller.post( '/post-async', async ( ctx ) => {
        const parser = getBodyParser( ctx.req, tempDir );
        await parser.parseSync();
        if ( parser.isUrlEncoded() || parser.isAppJson() ) {
            ctx.res.status( 200, { 'Content-Type': 'application/json' } );
            ctx.res.end( JSON.stringify( parser.getJson() ) );
            parser.dispose();
            return ctx.next( 200 );
        }
        parser.saveAsSync( downloadDir ); parser.dispose();
        return ctx.res.status( 200 ).send( "<h1>success</h1>" );
        // or
        // return ctx.res.asHTML( 200 ).end( "<h1>success</h1>" );
        // or
        /*const data = [];
        parser.getFilesSync( ( file ) => {
            data.push( {
                content_type: file.getContentType(),
                name: file.getName(),
                file_name: file.getFileName(),
                content_disposition: file.getContentDisposition(),
                temp_path: file.getTempPath()
            } );
            file.saveAsSync( `${downloadDir}/${Util.guid()}_${file.getFileName()}` );
        } );
        return ctx.res.status( 200 ).json( data );*/
    } )
} );

See more test here

Template Engine

Template can run config.defaultExt file extension or ctx.res.render( ctx, to_file_path )
Example of server-side script in config.defaultExt or app.config.json => template.ext

ctx.res.render( ctx, server.mapPath( `/index${server.config.defaultExt || ".html"}` ) );

Code block:

{%
    if( !ctx.session.isAuthenticated ){
       return ctx.next( 401, true );
    } else {
       ctx.write( JSON.stringify( ctx.session ) );
    }
%}
<ul>
  {% users.forEach(function(user){ %}
    {= user =}
  {% }); %}
</ul>

<ul>
  <!--{%--> users.forEach(function(user){ <!--%}-->
    {= user =}
  <!--{%--> }); <!--%}-->
</ul>

<script>
    var userLength = 0;
    /*{%*/ if ( users.length > 0 ) {/*%}*/
    userLength = {= users.length =};
    /*{%*/ } /*%}*/
</script>

<script>
    var userLength = 0;
    {% if ( users.length > 0 ) { %}
    userLength = {= users.length =};
    {% } %}
</script>

Response write: {= myVar =} or ctx.write(myVar)

{%
    const result = await ctx.server.db.pgsql.executeIoAsync( "my_shcema.__get_dataset", JSON.stringify( {
        login_id: ctx.req.session.loginId
    } ), JSON.stringify( {
        trade_date: "2020-02-03"
    } ) );
%}
{% if ( result.ret_val < 0) { %}
    <span style="color:red">No Data Found...</span>
{% } else { %}
<table style="width:100%">
   <thead>
      <tr>
         <th>Firstname</th>
         <th>Lastname</th>
         <th>Age</th>
      </tr>
   </thead>
   <tbody>
   {% for( const row of result.ret_data_table ){ %}
        <tr>
            <td>{= row.first_name =}</td>
            <td>{= row.last_name =}</td>
            <td>{= row.age_name =}</td>
        </tr>
   {% } %}
   </tbody>
</table>
{% } %}

Nested Master Template

#extends keyword define my master template
You can add multiple file by #attach keyword

www
├─┬ template
│ └─┬ master.html 
│   ├ footer.html
│   ├ header.html
│   └ readme.html
├─ index.html

index.html  ==> #extends /template/readme.html
==> index.html impliment placeholder id of readme.html (parent master)
-------------------------------------------
#extends /template/readme.html
<impl-placeholder id="container">
    container here
</impl-placeholder>
-------------------------------------------
readme.html ==> #extends /template/master.html (parent master)
==> readme.html like as master template and its contains own placeholder and impliment placeholder id of master.html
-------------------------------------------
#extends /template/master.html
<impl-placeholder id="body">
    <!--Here create new placeholder-->
    <placeholder id="container">
    </placeholder>
</impl-placeholder>
<impl-placeholder id="header">
    #attach /template/header.html
</impl-placeholder>
-------------------------------------------
master.html ==> root master template
--------------------------------------------
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<placeholder id="header">
</placeholder>
<body>
    <placeholder id="body">
    </placeholder>
    #attach /template/footer.html
</body>
</html>
--------------------------------------------

see more about template /dist/project_template/www

server.js

You may create server.js file by you:

const { ConsoleColor, initilizeServer } = require( 'cwserver' );
let wwwName = void 0;
if ( process.argv.length > 2 ) {
    wwwName = process.argv[2];
} else {
    if ( process.env.APP_POOL_ID ) {
        wwwName = process.env[process.env.APP_POOL_ID];
    }
}
const server = initilizeServer( __dirname, wwwName );
const app = server.init();
process.on( 'exit', () => {
    console.log( "Exited..." );
} );
process.on( 'SIGINT', () => {
    server.log.error( "Caught interrupt signal" );
    server.log.error( "Application Exited..." );
    server.log.reset(); server.log.dispose();
    setTimeout( () => {
        process.exit( 0 );
    }, 200 );
} );
app.listen( server.port, () => server.log.write( `
    [+] Maintance      : https://www.fsys.tech
    [+] Server         : http://localhost:${server.port}
    [+] Socket         : ws://localhost:${server.port}${server.socketPath}
    [~] Running Server...
`, ConsoleColor.FgMagenta ) );

Read more about app.config.json
run node server your_app_dir_name or npm start your_app_dir_name