User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

whocallme [2019-06-21 14:14]
whocallme [2020-02-15 00:57] (current)
Line 1: Line 1:
 +
 +=====WCM, Who-Call-Me ===== 
 +
 +A simple application for identifying the client calling to contact center of the company.
 +
 +Also contact-centre operator can very easy search customers by part of name, phone or agreement id.
 +
 +  * for fast review [[:​wcm-text|source text]]
 +
 +  * **Demo**: [[https://​wcm.unix7.org]]
 +  * Source: [[https://​github.com/​sadsoldier/​expresso]]
 +  * Based on my [[https://​github.com/​sadsoldier/​expresso|Expesso full-web-stack template]] ​
 +
 +====Description====
 +
 +  * Customer database include ~ 700.000 records with contact data.
 +  * Full time of reaction around 1-2 second. ​
 +
 +  * Frontend written with //Angular 2/7// framework
 +  * Backend presented with //​Express.JS//​
 +  * Commucation protocol is //JSON RPC// over HTTPs, with my implementation (the protocol very simple for realisation)
 +  * as DBMS middleware I used //KnexJS// on //​PostgreSQL//​
 +  * As web reverse proxy I used Nginx.
 +
 +  * Have user authentication and user account management components
 +
 +Development time of the program is about **10 hours**, from initial analysis to deployment into target operation system.
 +
 +====Screenshots===
 +
 +I practice KISS an approach =)
 +
 +{{:​screenshot-2018-12-14--17-57-55.png?​480}}
 +
 +{{:​screenshot-2018-12-14--18-19-43.png?​480}}
 +
 +====Remote produre call between client end server====
 +
 +Actually, the traditional MVC approach with "​many-many"​ URI routes in this case was not needed.
 +I used the principe: "one object model = one service URI". Total need couple route for RPC API and one generic "/​*"​ route for bootsraped ''​index.html''​
 +
 +===Generic RPC Clent for Angular 2===
 +
 +
 +<code javascript rpc.service.ts>​
 + 
 +import { Injectable } from '​@angular/​core'​
 +import { HttpClient } from '​@angular/​common/​http'​
 +import { Observable } from '​rxjs'​
 +
 +import { v4 as uuid } from '​uuid'​
 +
 +export interface RPCRequest<​TParam>​ {
 +    jsonrpc: string
 +    method: string
 +    params: TParam
 +    id: string
 +}
 +
 +export interface RPCError {
 +    code?: number
 +    message?: string
 +}
 +
 +export interface RPCResponce<​TResult>​ {
 +    jsonrpc: string
 +    error?: RPCError
 +    result?: TResult
 +    id: string
 +}
 +
 +@Injectable({
 +  providedIn: '​root'​
 +})
 +export class RPCService {
 +
 +    constructor(
 +        private httpClient: HttpClient
 +    ) {}
 +
 +    request<​TParam,​ TResult>​(
 +        url: string,
 +        method: string,
 +        params: TParam) : Observable<​RPCResponce<​TResult>>​ {
 +
 +        let rpcRequest : RPCRequest<​TParam>​ = {
 +            jsonrpc: '​2.0',​
 +            method: method,
 +            params: params,
 +            id: uuid()
 +        }
 +        return this.httpClient.post<​RPCResponce<​TResult>>​(url,​ rpcRequest)
 +    }
 +}
 +
 +</​code>​
 +
 +===Generic server code of JSON RPC===  ​
 +
 +<code javascript exrouter.js>​
 +'use strict'​
 +
 +const lodash = require('​lodash'​)
 +
 +const error = {
 +    invalidRequest:​ {
 +        jsonrpc: "​2.0",​
 +        error: {
 +            code: -32600,
 +            message: "​Invalid Request"​
 +        },
 +        id: null
 +    },
 +    parseError: {
 +        jsonrpc: "​2.0",​
 +        error: {
 +            code: -32700,
 +            message: "Parse error"
 +        },
 +        id: null
 +    },
 +    methodNotFound:​ {
 +        jsonrpc: "​2.0",​
 +        error: {
 +            code: -32601,
 +            message: "​Method not found"
 +        },
 +        id: 1
 +    },
 +    internalError:​ {
 +        jsonrpc: "​2.0",​
 +        error: {
 +            code: -32603,
 +            message: "​Internal error"
 +        },
 +        id: 0
 +    }
 +}
 +
 +module.exports = function(model) {
 +
 +    const express = require('​express'​)
 +    const router = express.Router()
 +
 +    function responder(req,​ res) {
 +
 +        console.log({ body: req.body })
 +
 +        if(!lodash.has(req,​ '​body.method'​)) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if(!lodash.has(req,​ '​body.id'​)) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if(!lodash.has(req,​ '​body.params'​)) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if (!lodash.isString(req.body.method)) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if (!lodash.isString(req.body.id) && !lodash.isNumber(req.body.id)) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if (typeof(req.body.params) === '​undefined'​) {
 +            res.send(error.invalidRequest)
 +            return
 +        }
 +
 +        if (typeof(model[req.body.method]) !== '​function'​) {
 +            res.send(error.methodNotFound)
 +            return
 +        }
 +
 +        const method = req.body.method
 +        var params = req.body.params
 +        const id = req.body.id
 +
 +        if (method === '​check'​) {
 +            if (lodash.has(req,​ '​session.userId'​)) {
 +                params = { id: req.session.userId }
 +            } else {
 +                params = { id: -1 }
 +            }
 +        }
 +
 +        var modelPromise = model[method](params)
 +
 +        modelPromise
 +            .then(function(result) {
 +
 +                if (method === '​login'​ && lodash.has(result,​ '​[0].id'​)) {
 +                        req.session.userId = result[0].id
 +                        req.session.userProfile = result[0]
 +                }
 +
 +                if (method === '​check'​) {
 +                    console.log({ checkResult:​ result })
 +                    if (lodash.has(req,​ "​session.userId"​) && lodash.has(result,​ "​[0].id"​)) {
 +                        result = true
 +                    } else {
 +                        result = false
 +                    }
 +                }
 +
 +                res.send({
 +                    jsonrpc: "​2.0",​
 +                    result: result,
 +                    id: id
 +                })
 +            })
 +            .catch(function(err) {
 +                console.log(err)
 +                res.send({
 +                    jsonrpc: "​2.0",​
 +                    error: {
 +                        code: -32603,
 +                        message: "​Internal error"
 +                    },
 +                    id: id
 +                })
 +            })
 +    }
 +
 +    router.post('/',​ responder)
 +    return router
 +}
 +
 +</​code>​
 +
 +<code javascript users.js> ​
 +'use strict'​
 +
 +module.exports = function(knex) {
 +    const model = require('​models/​users'​)(knex)
 +    const router = require('​routers/​exrouter'​)(model)
 +    return router
 +}
 +</​code>​
 +
 +----
 +[<>​]  ​
 +
 +
 +
 +
 +
 +