User Tools

Site Tools


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.

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 =)

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

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)
    }
}

Generic server code of JSON RPC

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
}
users.js
'use strict'
 
module.exports = function(knex) {
    const model = require('models/users')(knex)
    const router = require('routers/exrouter')(model)
    return router
}

First PagePrevious PageBack to overviewNext PageLast Page