https://github.com/joshmarshall/jsonrpclib
https://github.com/tcalmant/jsonrpclib/
Install brew
# https://brew.sh
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Install python3
brew install python3
Create virtual environment for this project and then activate it.
python3 -m venv ~/.virtualenvs/cs503_env
source ~/.virtualenvs/cs503_env/bin/activate
Here are some useful links:
- compare
pip install
andbrew install
- python3 and venv
- venv
Install jsonrpclib
pip3 install jsonrpclib-pelix
Base on this template, setup our first RPC server.
Create backend_server/service.py
import logging
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
SERVER_HOST = 'localhost'
SERVER_PORT = 4040
logger_format = '%(asctime)s - %(message)s'
logging.basicConfig(format = logger_format)
logger = logging.getLogger('backend_service')
logger.setLevel(logging.DEBUG)
def add(num1, num2):
"""Test Method"""
# doc_string
# https://www.geeksforgeeks.org/python-docstrings/
logger.debug('Add is called with %d and %d', num1, num2);
return num1 + num2
server = SimpleJSONRPCServer((SERVER_HOST, SERVER_PORT))
server.register_function(add, 'add')
logger.info('Starting RPC server on %s:%d', SERVER_HOST, SERVER_PORT)
server.serve_forever()
After starting the backend server (python3 service.py
), use Postman
to test
{
"jsonrpc": "2.0",
"id": 99,
"method": "add",
"params": [99,3]
}
Result should be:
{
"result": 102,
"id": 99,
"jsonrpc": "2.0"
}
Create web_server/server/rpc_client/rpc_client.js
const jayson = require('jayson');
// create a client
const client = jayson.client.http({
port: 4040,
hostname: 'localhost'
});
// middleware utility
function add(a, b, callback) {
client.request('add', [a, b], function(err, response) {
if (err) throw err;
console.log(response.result);
callback(response.result);
});
}
module.exports = {
add: add
};
Create web_server/server/rpc_client/rpc_client_test.js
.
var client = require('./rpc_client');
client.add(1, 2, function(res) {
console.assert(res == 3);
});
Test rpc client
node rpc_client_test.js
Install MongoDB via brew.
Run MongoDB service
brew services start [email protected]
Basic shell commands
> show dbs
> use tap-news
> show collections
> db.news.find().pretty()
Export MongoDB data to file and Import file as MongoDB data using mongoexport
and mongoimport
tools
mongoexport --db tap-news --collection news --out demo_news.json
mongoimport --db test --collection news --file demo_news.json
mongoimport --db tap-news --collection news --file demo_news.json
pymongo
is a python tool to work with MongoDB.
Install pymongo
pip3 install pymongo
Create backend_server/utils/mongodb_client
util file
from pymongo import MongoClient
MONGO_DB_HOST = 'localhost'
MONGO_DB_PORT = 27017
DB_NAME = 'tap-news'
client = MongoClient(MONGO_DB_HOST, MONGO_DB_PORT)
# singleton
def get_db(db=DB_NAME):
db = client[db]
return db
And util test file backend_server/utils/mongodb_client_test
import mongodb_client as client
def test_basic():
db = client.get_db('test')
db.test.drop()
assert db.test.count() == 0
db.test.insert({'test': 1})
assert db.test.count() == 1
db.test.drop()
assert db.test.count() == 0
print('test basic passed!')
if __name__ == '__main__':
test_basic()
python3 mongodb_client_test.py
Install pika
pip3 install pika
Create AMQP instances at CloudAMQP. The AMQP URL
should be private and unique to our backend_server.
Create backend_server/utils/cloudAMQP_client.py
import json
import logging
import pika
logger_format = '%(asctime)s - %(message)s'
logging.basicConfig(format = logger_format)
logger = logging.getLogger('cloud_amqp_client')
logger.setLevel(logging.DEBUG)
class CloudAMQPClient:
def __init__(self, cloud_amqp_url, queue_name):
self.cloud_amqp_url = cloud_amqp_url
self.queue_name = queue_name
self.params = pika.URLParameters(cloud_amqp_url)
self.params.socket_timeout = 3
self.connection = pika.BlockingConnection(self.params)
self.channel = self.connection.channel()
self.channel.queue_declare(queue=queue_name)
# Send a message, basic_publish example
def sendMessage(self, message):
self.channel.basic_publish(exchange='',
routing_key=self.queue_name,
body=json.dumps(message))
logging.debug("[x] Sent message to %s:%s", self.queue_name, message)
# Get a message, basic_get example
def getMessage(self):
method_frame, header_frame, body = self.channel.basic_get(self.queue_name)
if method_frame:
logging.debug("[x] Received message to %s:%s", self.queue_name, body)
self.channel.basic_ack(method_frame.delivery_tag) # verify received!
return json.loads(body.decode('utf-8'))
else:
logging.debug('No message returned.')
return None
# BlockingConnection.sleep is a safer way to sleep than time.sleep(). This
# will repond to server's heartbeat.
def sleep(self, seconds):
self.connection.sleep(seconds)
Create backend_server/utils/cloudAMQP_client_test.py
from cloudAMQP_client import CloudAMQPClient
CloudAMQP_URL = "[your cloudAMQP instance url]"
TEST_QUEUE_NAME = "test"
def test_basic():
client = CloudAMQPClient(CloudAMQP_URL,TEST_QUEUE_NAME )
sentMsg = {"test":"test"}
client.sendMessage(sentMsg)
client.sleep(5)
reveivedMsg = client.getMessage()
assert sentMsg == reveivedMsg
print("test_basic passed!")
if __name__ == "__main__":
test_basic()
python3 cloudAMQP_client_test.py
Add another backend-service test function getOneNews()
in our service.py
Update backend_server/service.py
import logging
import os
import sys
import json
from bson.json_util import dumps
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
# import util package in parent dir
sys.path.append(os.path.join(os.path.dirname(__file__), 'utils'))
import mongodb_client
SERVER_HOST = 'localhost'
SERVER_PORT = 4040
logger_format = '%(asctime)s - %(message)s'
logging.basicConfig(format = logger_format)
logger = logging.getLogger('backend_service')
logger.setLevel(logging.DEBUG)
def getOneNews():
""" Test method to get one news. """
res = mongodb_client.get_db()['news'].find_one()
return json.loads(dumps(res))
server = SimpleJSONRPCServer((SERVER_HOST, SERVER_PORT))
server.register_function(getOneNews, 'getOneNews')
logger.info('Starting RPC server on %s:%d', SERVER_HOST, SERVER_PORT)
server.serve_forever()
If demo_news.json
is properly imported, Postman
with Post-raw request
{
"jsonrpc": "2.0",
"id": 99,
"method": "getOneNews",
"params": []
}
should return a news.
Install pylint
.
pip3 install pylint
Check python file coding style.
python3 -m pylint service.py