Initial Commit

master
Amir Hossein Moghiseh 2021-02-21 13:16:24 +03:30
commit 3448a73d9a
12 changed files with 1287 additions and 0 deletions

2
.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
node_modules
__pycache__

17
client/client.js 100644
View File

@ -0,0 +1,17 @@
var PROTO_PATH = __dirname + "/../users.proto";
var grpc = require("@grpc/grpc-js");
var protoLoader = require("@grpc/proto-loader");
var packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
arrays: true,
});
var UserService = grpc.loadPackageDefinition(packageDefinition).UserService;
const client = new UserService(
"127.0.0.1:50051",
grpc.credentials.createInsecure()
);
module.exports = client;

70
client/index.js 100644
View File

@ -0,0 +1,70 @@
const client = require("./client");
const path = require("path");
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.get("/", (req, res) => {
client.getAll(null, (err, data) => {
console.log(data);
if (!err) {
res.render("users", {
results: data.users,
});
}
});
});
app.post("/save", (req, res) => {
let newUser = {
name: req.body.name,
age: req.body.age,
address: req.body.address,
};
client.insert(newUser, (err, data) => {
if (err) throw err;
console.log("User created successfully", data);
res.redirect("/");
});
});
app.post("/update", (req, res) => {
const updateUser = {
id: req.body.id,
name: req.body.name,
age: req.body.age,
address: req.body.address,
};
client.update(updateUser, (err, data) => {
if (err) throw err;
console.log("User updated successfully", data);
res.redirect("/");
});
});
app.post("/remove", (req, res) => {
console.log(req.body);
client.remove({ id: req.body.user_id }, (err, _) => {
if (err) throw err;
console.log("User removed successfully");
res.redirect("/");
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log("Server running at port %d", PORT);
});

View File

@ -0,0 +1,176 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>LogRocket CRUD with gRPC and Node</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
.logrocket {
background-color: #764abc;
color: white;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>Users's List</h2>
<p class="lead">Example of CRUD made with Node.js, Express, Handlebars and gRPC</p>
</div>
<table class="table" id="customers_table">
<thead>
<tr>
<th>Customer ID</th>
<th>Customer Name</th>
<th>Age</th>
<th>Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{{#each results}}
<tr>
<td>{{ id }}</td>
<td>{{ name }}</td>
<td>{{ age }} years old</td>
<td>{{ address }}</td>
<td>
<a href="javascript:void(0);" class="btn btn-sm edit logrocket" data-id="{{ id }}"
data-name="{{ name }}" data-age="{{ age }}" data-address="{{ address }}">Edit</a>
<a href="javascript:void(0);" class="btn btn-sm btn-danger remove" data-id="{{ id }}">Remove</a>
</td>
</tr>
{{else}}
<tr>
<td colspan="5" class="text-center">No data to display.</td>
</tr>
{{/each}}
</tbody>
</table>
<button class="btn btn-success float-right" data-toggle="modal" data-target="#newCustomerModal">Add New</button>
</div>
<!-- New Customer Modal -->
<form action="/save" method="post">
<div class="modal fade" id="newCustomerModal" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">New Customer</h4>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" name="name" class="form-control" placeholder="Customer Name"
required="required">
</div>
<div class="form-group">
<input type="number" name="age" class="form-control" placeholder="Age" required="required">
</div>
<div class="form-group">
<input type="text" name="address" class="form-control" placeholder="Address"
required="required">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn logrocket">Create</button>
</div>
</div>
</div>
</div>
</form>
<!-- Edit Customer Modal -->
<form action="/update" method="post">
<div class="modal fade" id="editCustomerModal" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Edit Customer</h4>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<input type="text" name="name" class="form-control name" placeholder="Customer Name"
required="required">
</div>
<div class="form-group">
<input type="number" name="age" class="form-control age" placeholder="Age"
required="required">
</div>
<div class="form-group">
<input type="text" name="address" class="form-control address" placeholder="Address"
required="required">
</div>
</div>
<div class="modal-footer">
<input type="hidden" name="id" class="customer_id">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn logrocket">Update</button>
</div>
</div>
</div>
</div>
</form>
<!-- Remove Customer Modal -->
<form id="add-row-form" action="/remove" method="post">
<div class="modal fade" id="removeCustomerModal" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title"></h4>Remove Customer</h4>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
Are you sure?
</div>
<div class="modal-footer">
<input type="hidden" name="user_id" class="form-control customer_id_removal"
required="required">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn logrocket">Remove</button>
</div>
</div>
</div>
</div>
</form>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$('#customers_table').on('click', '.edit', function () {
$('#editCustomerModal').modal('show');
$('.customer_id').val($(this).data('id'));
$('.name').val($(this).data('name'));
$('.age').val($(this).data('age'));
$('.address').val($(this).data('address'));
}).on('click', '.remove', function () {
$('#removeCustomerModal').modal('show');
$('.customer_id_removal').val($(this).data('id'));
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,271 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: users.proto
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='users.proto',
package='',
syntax='proto3',
serialized_options=None,
create_key=_descriptor._internal_create_key,
serialized_pb=b'\n\x0busers.proto\"\x07\n\x05\x45mpty\">\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03\x61ge\x18\x03 \x01(\x05\x12\x0f\n\x07\x61\x64\x64ress\x18\x04 \x01(\t\" \n\x08UserList\x12\x14\n\x05users\x18\x01 \x03(\x0b\x32\x05.User\"\x1b\n\rUserRequestId\x12\n\n\x02id\x18\x01 \x01(\t2\xa4\x01\n\x0bUserService\x12\x1d\n\x06GetAll\x12\x06.Empty\x1a\t.UserList\"\x00\x12\x1e\n\x03Get\x12\x0e.UserRequestId\x1a\x05.User\"\x00\x12\x18\n\x06Insert\x12\x05.User\x1a\x05.User\"\x00\x12\x18\n\x06Update\x12\x05.User\x1a\x05.User\"\x00\x12\"\n\x06Remove\x12\x0e.UserRequestId\x1a\x06.Empty\"\x00\x62\x06proto3'
)
_EMPTY = _descriptor.Descriptor(
name='Empty',
full_name='Empty',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=15,
serialized_end=22,
)
_USER = _descriptor.Descriptor(
name='User',
full_name='User',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='User.id', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='name', full_name='User.name', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='age', full_name='User.age', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='address', full_name='User.address', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=24,
serialized_end=86,
)
_USERLIST = _descriptor.Descriptor(
name='UserList',
full_name='UserList',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='users', full_name='UserList.users', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=88,
serialized_end=120,
)
_USERREQUESTID = _descriptor.Descriptor(
name='UserRequestId',
full_name='UserRequestId',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='UserRequestId.id', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=122,
serialized_end=149,
)
_USERLIST.fields_by_name['users'].message_type = _USER
DESCRIPTOR.message_types_by_name['Empty'] = _EMPTY
DESCRIPTOR.message_types_by_name['User'] = _USER
DESCRIPTOR.message_types_by_name['UserList'] = _USERLIST
DESCRIPTOR.message_types_by_name['UserRequestId'] = _USERREQUESTID
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), {
'DESCRIPTOR' : _EMPTY,
'__module__' : 'users_pb2'
# @@protoc_insertion_point(class_scope:Empty)
})
_sym_db.RegisterMessage(Empty)
User = _reflection.GeneratedProtocolMessageType('User', (_message.Message,), {
'DESCRIPTOR' : _USER,
'__module__' : 'users_pb2'
# @@protoc_insertion_point(class_scope:User)
})
_sym_db.RegisterMessage(User)
UserList = _reflection.GeneratedProtocolMessageType('UserList', (_message.Message,), {
'DESCRIPTOR' : _USERLIST,
'__module__' : 'users_pb2'
# @@protoc_insertion_point(class_scope:UserList)
})
_sym_db.RegisterMessage(UserList)
UserRequestId = _reflection.GeneratedProtocolMessageType('UserRequestId', (_message.Message,), {
'DESCRIPTOR' : _USERREQUESTID,
'__module__' : 'users_pb2'
# @@protoc_insertion_point(class_scope:UserRequestId)
})
_sym_db.RegisterMessage(UserRequestId)
_USERSERVICE = _descriptor.ServiceDescriptor(
name='UserService',
full_name='UserService',
file=DESCRIPTOR,
index=0,
serialized_options=None,
create_key=_descriptor._internal_create_key,
serialized_start=152,
serialized_end=316,
methods=[
_descriptor.MethodDescriptor(
name='GetAll',
full_name='UserService.GetAll',
index=0,
containing_service=None,
input_type=_EMPTY,
output_type=_USERLIST,
serialized_options=None,
create_key=_descriptor._internal_create_key,
),
_descriptor.MethodDescriptor(
name='Get',
full_name='UserService.Get',
index=1,
containing_service=None,
input_type=_USERREQUESTID,
output_type=_USER,
serialized_options=None,
create_key=_descriptor._internal_create_key,
),
_descriptor.MethodDescriptor(
name='Insert',
full_name='UserService.Insert',
index=2,
containing_service=None,
input_type=_USER,
output_type=_USER,
serialized_options=None,
create_key=_descriptor._internal_create_key,
),
_descriptor.MethodDescriptor(
name='Update',
full_name='UserService.Update',
index=3,
containing_service=None,
input_type=_USER,
output_type=_USER,
serialized_options=None,
create_key=_descriptor._internal_create_key,
),
_descriptor.MethodDescriptor(
name='Remove',
full_name='UserService.Remove',
index=4,
containing_service=None,
input_type=_USERREQUESTID,
output_type=_EMPTY,
serialized_options=None,
create_key=_descriptor._internal_create_key,
),
])
_sym_db.RegisterServiceDescriptor(_USERSERVICE)
DESCRIPTOR.services_by_name['UserService'] = _USERSERVICE
# @@protoc_insertion_point(module_scope)

View File

@ -0,0 +1,198 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
import users_pb2 as users__pb2
class UserServiceStub(object):
"""Missing associated documentation comment in .proto file."""
def __init__(self, channel):
"""Constructor.
Args:
channel: A grpc.Channel.
"""
self.GetAll = channel.unary_unary(
'/UserService/GetAll',
request_serializer=users__pb2.Empty.SerializeToString,
response_deserializer=users__pb2.UserList.FromString,
)
self.Get = channel.unary_unary(
'/UserService/Get',
request_serializer=users__pb2.UserRequestId.SerializeToString,
response_deserializer=users__pb2.User.FromString,
)
self.Insert = channel.unary_unary(
'/UserService/Insert',
request_serializer=users__pb2.User.SerializeToString,
response_deserializer=users__pb2.User.FromString,
)
self.Update = channel.unary_unary(
'/UserService/Update',
request_serializer=users__pb2.User.SerializeToString,
response_deserializer=users__pb2.User.FromString,
)
self.Remove = channel.unary_unary(
'/UserService/Remove',
request_serializer=users__pb2.UserRequestId.SerializeToString,
response_deserializer=users__pb2.Empty.FromString,
)
class UserServiceServicer(object):
"""Missing associated documentation comment in .proto file."""
def GetAll(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def Get(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def Insert(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def Update(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def Remove(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def add_UserServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'GetAll': grpc.unary_unary_rpc_method_handler(
servicer.GetAll,
request_deserializer=users__pb2.Empty.FromString,
response_serializer=users__pb2.UserList.SerializeToString,
),
'Get': grpc.unary_unary_rpc_method_handler(
servicer.Get,
request_deserializer=users__pb2.UserRequestId.FromString,
response_serializer=users__pb2.User.SerializeToString,
),
'Insert': grpc.unary_unary_rpc_method_handler(
servicer.Insert,
request_deserializer=users__pb2.User.FromString,
response_serializer=users__pb2.User.SerializeToString,
),
'Update': grpc.unary_unary_rpc_method_handler(
servicer.Update,
request_deserializer=users__pb2.User.FromString,
response_serializer=users__pb2.User.SerializeToString,
),
'Remove': grpc.unary_unary_rpc_method_handler(
servicer.Remove,
request_deserializer=users__pb2.UserRequestId.FromString,
response_serializer=users__pb2.Empty.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
'UserService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
# This class is part of an EXPERIMENTAL API.
class UserService(object):
"""Missing associated documentation comment in .proto file."""
@staticmethod
def GetAll(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/UserService/GetAll',
users__pb2.Empty.SerializeToString,
users__pb2.UserList.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def Get(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/UserService/Get',
users__pb2.UserRequestId.SerializeToString,
users__pb2.User.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def Insert(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/UserService/Insert',
users__pb2.User.SerializeToString,
users__pb2.User.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def Update(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/UserService/Update',
users__pb2.User.SerializeToString,
users__pb2.User.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@staticmethod
def Remove(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/UserService/Remove',
users__pb2.UserRequestId.SerializeToString,
users__pb2.Empty.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

344
package-lock.json generated 100644
View File

@ -0,0 +1,344 @@
{
"name": "nodetest",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@grpc/grpc-js": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.2.8.tgz",
"integrity": "sha512-9C1xiCbnYe/3OFpSuRqz2JgFSOxv6+SlqFhXgRC1nHfXYbLnXvtmsI/NpaMs6k9ZNyV4gyaOOh5Z4McfegQGew==",
"requires": {
"@types/node": ">=12.12.47",
"google-auth-library": "^6.1.1",
"semver": "^6.2.0"
}
},
"@grpc/proto-loader": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.6.tgz",
"integrity": "sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ==",
"requires": {
"lodash.camelcase": "^4.3.0",
"protobufjs": "^6.8.6"
}
},
"@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
},
"@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
},
"@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
},
"@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
},
"@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
"requires": {
"@protobufjs/aspromise": "^1.1.1",
"@protobufjs/inquire": "^1.1.0"
}
},
"@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
},
"@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
},
"@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
},
"@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
},
"@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
},
"@types/long": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
"integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
},
"@types/node": {
"version": "14.14.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz",
"integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g=="
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"requires": {
"event-target-shim": "^5.0.0"
}
},
"agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"requires": {
"debug": "4"
}
},
"arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
},
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"bignumber.js": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
"integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA=="
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"fast-text-encoding": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz",
"integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig=="
},
"gaxios": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.1.0.tgz",
"integrity": "sha512-vb0to8xzGnA2qcgywAjtshOKKVDf2eQhJoiL6fHhgW5tVN7wNk7egnYIO9zotfn3lQ3De1VPdf7V5/BWfCtCmg==",
"requires": {
"abort-controller": "^3.0.0",
"extend": "^3.0.2",
"https-proxy-agent": "^5.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.3.0"
}
},
"gcp-metadata": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz",
"integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==",
"requires": {
"gaxios": "^4.0.0",
"json-bigint": "^1.0.0"
}
},
"google-auth-library": {
"version": "6.1.6",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz",
"integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==",
"requires": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
"fast-text-encoding": "^1.0.0",
"gaxios": "^4.0.0",
"gcp-metadata": "^4.2.0",
"gtoken": "^5.0.4",
"jws": "^4.0.0",
"lru-cache": "^6.0.0"
}
},
"google-p12-pem": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz",
"integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==",
"requires": {
"node-forge": "^0.10.0"
}
},
"google-protobuf": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.1.tgz",
"integrity": "sha512-Ss2fADC0TpZXn6bqGgPJMUWoD1y9J7BTtJRVvf+quNxXRtQnrpubiFCdgoown+OetNsU4H3YbJgnpxYY/3kH6g=="
},
"gtoken": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz",
"integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==",
"requires": {
"gaxios": "^4.0.0",
"google-p12-pem": "^3.0.3",
"jws": "^4.0.0"
}
},
"https-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
"integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"requires": {
"agent-base": "6",
"debug": "4"
}
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
},
"json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
"requires": {
"bignumber.js": "^9.0.0"
}
},
"jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"requires": {
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
},
"long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
},
"protobufjs": {
"version": "6.10.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz",
"integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==",
"requires": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/long": "^4.0.1",
"@types/node": "^13.7.0",
"long": "^4.0.0"
},
"dependencies": {
"@types/node": {
"version": "13.13.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.45.tgz",
"integrity": "sha512-703YTEp8AwQeapI0PTXDOj+Bs/mtdV/k9VcTP7z/de+lx6XjFMKdB+JhKnK+6PZ5za7omgZ3V6qm/dNkMj/Zow=="
}
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

19
package.json 100644
View File

@ -0,0 +1,19 @@
{
"name": "nodetest",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"dependencies": {
"@grpc/grpc-js": "^1.1.0",
"@grpc/proto-loader": "^0.5.0",
"async": "^1.5.2",
"google-protobuf": "^3.0.0",
"minimist": "^1.2.5"
},
"author": "",
"license": "ISC"
}

2
requirement.txt 100644
View File

@ -0,0 +1,2 @@
grpcio==1.35.0
grpcio-tools==1.35.0

93
server/server.js 100644
View File

@ -0,0 +1,93 @@
var PROTO_PATH = __dirname + "/../users.proto";
var grpc = require("@grpc/grpc-js");
var protoLoader = require("@grpc/proto-loader");
var packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
arrays: true,
});
var users_proto = grpc.loadPackageDefinition(packageDefinition);
const { v4: uuidv4 } = require("uuid");
const server = new grpc.Server();
const users = [
{
id: "a68b823c-7ca6-44bc-b721-fb4d5312cafc",
name: "John Brad",
age: 23,
address: "Address 1",
},
{
id: "34415c7c-f82d-4e44-88ca-ae2a1aaa92b7",
name: "Mary Anne",
age: 45,
address: "Address 2",
},
];
server.addService(users_proto.UserService.service, {
getAll: (_, callback) => {
callback(null, { users });
},
get: (call, callback) => {
let user = users.find((n) => n.id == call.request.id);
if (user) {
callback(null, user);
} else {
callback({
code: grpc.status.NOT_FOUND,
details: "Not found",
});
}
},
insert: (call, callback) => {
let user = call.request;
user.id = uuidv4();
users.push(user);
callback(null, user);
},
update: (call, callback) => {
let existinguser = users.find((n) => n.id == call.request.id);
if (existinguser) {
existinguser.name = call.request.name;
existinguser.age = call.request.age;
existinguser.address = call.request.address;
callback(null, existinguser);
} else {
callback({
code: grpc.status.NOT_FOUND,
details: "Not found",
});
}
},
remove: (call, callback) => {
let existinguserIndex = users.findIndex((n) => n.id == call.request.id);
if (existinguserIndex != -1) {
users.splice(existinguserIndex, 1);
callback(null, {});
} else {
callback({
code: grpc.status.NOT_FOUND,
details: "Not found",
});
}
},
});
server.bindAsync(
"127.0.0.1:50051",
grpc.ServerCredentials.createInsecure(),
() => {
console.log("Server running at http://127.0.0.1:50051");
server.start();
}
);

69
server/server.py 100644
View File

@ -0,0 +1,69 @@
from concurrent import futures
import logging
import uuid
import grpc
import sys
sys.path.append('C:/Users/user/Documents/Develop Land/grpc/NodeTest/lib/proto')
import users_pb2_grpc as pb2_grpc
import users_pb2 as pb2
users = [
{
"id": "a68b823c-7ca6-44bc-b721-fb4d5312cafc",
"name": "John Brad",
"age": 23,
"address": "Address 1",
},
{
"id": "34415c7c-f82d-4e44-88ca-ae2a1aaa92b7",
"name": "Mary Anne",
"age": 45,
"address": "Address 2",
},
]
class UserController(pb2_grpc.UserServiceServicer):
def GetAll(self,request,context):
return pb2.UserList(users=users)
def Get(self, request, context):
pass
# user.id = str(uuid.uuid4())
def Insert(self, request, context):
user = request
user.id = str(uuid.uuid4())
users.append(user)
return pb2.User(
id=user.id,
name=user.name,
age=user.age,
address=user.address
)
def Update(self, request, context):
user = [user for user in users if user['id'] == request.id][0]
user['id'] = request.id
user['name'] = request.name
user['address'] = request.address
user['age'] = request.age
return pb2.User(**user)
def Remove(self, request, context):
print(request)
index = next((i for i, user in enumerate(users) if user['id'] == request.id), -1)
del users[index]
return pb2.Empty()
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
pb2_grpc.add_UserServiceServicer_to_server(UserController(), server)
server.add_insecure_port('[::]:50051')
server.start()
print("Server running at http://127.0.0.1:50051")
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()

26
users.proto 100644
View File

@ -0,0 +1,26 @@
syntax = "proto3";
service UserService {
rpc GetAll (Empty) returns (UserList) {}
rpc Get (UserRequestId) returns (User) {}
rpc Insert (User) returns (User) {}
rpc Update (User) returns (User) {}
rpc Remove (UserRequestId) returns (Empty) {}
}
message Empty {}
message User {
string id = 1;
string name = 2;
int32 age = 3;
string address = 4;
}
message UserList {
repeated User users = 1;
}
message UserRequestId {
string id = 1;
}