From a03e181601bca45620155ff5f52e8f517e2c497a Mon Sep 17 00:00:00 2001
From: IsolatedSushi <simen.vanherpt@gmail.com>
Date: Tue, 15 Dec 2020 15:47:07 +0100
Subject: [PATCH] Python server

---
 backend/gRPCProjector/{ => node}/Dockerfile   |   0
 .../{ => node}/package-lock.json              |   0
 backend/gRPCProjector/{ => node}/package.json |   0
 .../gRPCProjector/{ => node}/protos/README.md |   0
 .../{ => node}/protos/v3/projector.proto      |   0
 .../{ => node}/src/grpcServer.js              |   0
 .../__pycache__/projector_pb2.cpython-38.pyc  | Bin 0 -> 4044 bytes
 .../projector_pb2_grpc.cpython-38.pyc         | Bin 0 -> 4617 bytes
 backend/gRPCProjector/python/grpcServer.py    |  42 +++
 backend/gRPCProjector/python/projector_pb2.py | 239 ++++++++++++++++++
 .../python/projector_pb2_grpc.py              | 183 ++++++++++++++
 backend/gRPCProjector/python/protos/README.md |   3 +
 .../python/protos/v3/projector.proto          |  71 ++++++
 13 files changed, 538 insertions(+)
 rename backend/gRPCProjector/{ => node}/Dockerfile (100%)
 rename backend/gRPCProjector/{ => node}/package-lock.json (100%)
 rename backend/gRPCProjector/{ => node}/package.json (100%)
 rename backend/gRPCProjector/{ => node}/protos/README.md (100%)
 rename backend/gRPCProjector/{ => node}/protos/v3/projector.proto (100%)
 rename backend/gRPCProjector/{ => node}/src/grpcServer.js (100%)
 create mode 100644 backend/gRPCProjector/python/__pycache__/projector_pb2.cpython-38.pyc
 create mode 100644 backend/gRPCProjector/python/__pycache__/projector_pb2_grpc.cpython-38.pyc
 create mode 100644 backend/gRPCProjector/python/grpcServer.py
 create mode 100644 backend/gRPCProjector/python/projector_pb2.py
 create mode 100644 backend/gRPCProjector/python/projector_pb2_grpc.py
 create mode 100644 backend/gRPCProjector/python/protos/README.md
 create mode 100644 backend/gRPCProjector/python/protos/v3/projector.proto

diff --git a/backend/gRPCProjector/Dockerfile b/backend/gRPCProjector/node/Dockerfile
similarity index 100%
rename from backend/gRPCProjector/Dockerfile
rename to backend/gRPCProjector/node/Dockerfile
diff --git a/backend/gRPCProjector/package-lock.json b/backend/gRPCProjector/node/package-lock.json
similarity index 100%
rename from backend/gRPCProjector/package-lock.json
rename to backend/gRPCProjector/node/package-lock.json
diff --git a/backend/gRPCProjector/package.json b/backend/gRPCProjector/node/package.json
similarity index 100%
rename from backend/gRPCProjector/package.json
rename to backend/gRPCProjector/node/package.json
diff --git a/backend/gRPCProjector/protos/README.md b/backend/gRPCProjector/node/protos/README.md
similarity index 100%
rename from backend/gRPCProjector/protos/README.md
rename to backend/gRPCProjector/node/protos/README.md
diff --git a/backend/gRPCProjector/protos/v3/projector.proto b/backend/gRPCProjector/node/protos/v3/projector.proto
similarity index 100%
rename from backend/gRPCProjector/protos/v3/projector.proto
rename to backend/gRPCProjector/node/protos/v3/projector.proto
diff --git a/backend/gRPCProjector/src/grpcServer.js b/backend/gRPCProjector/node/src/grpcServer.js
similarity index 100%
rename from backend/gRPCProjector/src/grpcServer.js
rename to backend/gRPCProjector/node/src/grpcServer.js
diff --git a/backend/gRPCProjector/python/__pycache__/projector_pb2.cpython-38.pyc b/backend/gRPCProjector/python/__pycache__/projector_pb2.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0812ba7ac0dafc317f002a7f310df4c4bd25e7e5
GIT binary patch
literal 4044
zcmcgu&2QVt6(=c*l4wfQhpjkv5<8BQSZ$(soi>}MX}ar=q$!YCkewD41Q3*Fq|i%|
z#E|k@y7tnG|AQWqUWx_!xAfQrrq~6Fo^&jFXu5}@Z-$h_mDTNL4=aMhH}CWJX5PHf
zt87*k;FtXK=f<C|3&P*oB>uYslaJu_f0qyhBp}fidSXKo87%>wXvmyS0G(_ooR)!3
zHPWJh({D0wg@y{cN#HFsG~h`mS)`y8N}~+WIizCkMDL1d;XKvQfs;oX%Ay?B;RQLo
z1*D@q_$Z(vyaiMOI>(<98!@xWp~dq8*Ihzo(76Q9GSkIHB>YzV2K~!u1$0-xjea-L
z71#sbN+`{#E9fe^c3x<dAa)+Dq4gQ$*U<(?egoa$$T#0CqML8O3C}Hbo8#X?6+l(u
z(O9-Kxpt)sSbl(h$gwPOEO*e|87w-gz9*J@Xq#hUD?f|ngXy}@!Lozyb1Y?C#!Dxc
z(5=gYv5ZStKe>#w#{ypB)EZD_PTc`YeY1k~w<6St@@5rjSU$PZ5pfCq2>tl?(%VGi
zDrj88S0@^4k;c+QV~uO9O*HOA8s&+`I@efd8f<lp>oAr9-#x&09oB6FJwP8q?J+5<
zs)y(&@V$W^p`UV|cCrcex*16ypQpL>XXpv6Q;tdINPmt#g6e`ekW1)wZ1*wRg>?<>
zVzRD`_Rcenn}GEehH8Noxe2Ru8$EaoxQ>L%{)nB?ibz$2{Wh_@z$GwC^|0@oUCaao
zcWm4aEZ2dV?hkq`*EWzDm@U(13K`t<f`Q?+c80n~+!N4sNfoHTZ7A?L#h9{h;NJJQ
zA(*N=cD3I>wYp3Rq`So$`@#^~KCAE5YT_RxrB*-u)xm*ZkeCtZ#$6X9*DI@C*X`Q)
z9>@c?)$iQnaKiW-6*XCNEhi|ds$`*Mab4U>7Bi}Nwk!cDF><h+VC2TWx^PTP%dwp9
z5e|yFn(Da-+mThKxT(s-{nQ7;#MZ)2Il^9z+0@-nH+IzA*EzAsnc||FevMA~0&zd$
zu9O#d{w=DRN%F-H)ubPoBq)}vVP;_}kXiMBE%eI&;1?gLvLCqKd)w`*r7jL40I<t^
z!F+H7D+;?ali^Bs%;$O=!j`x#0%#R{yz-zdFf*NxeAaYZ+}(cPYG_5JR7p|UF?*P%
zJhS}?lqyyHffJZ#wCH1EnYJ~=$Z$PYw?0+d1OqhV6Fi{VnA~eo4Pg&E2s>>H`!p<<
zp%&%Nb9_mmc6e>G<>0KUg+?OO@+b+z(@KG);Y%}}zHJ*ERnh{NXH;?ey%r`^4h9~k
z>9*$?oJ!he3){5t+Vl;CJ7(Vwj8oI@W19W?RErK`XqLg?FC_K03)%8=4H=r{8~7~1
zjt?1AeL@<3+x0M6U;yQgWn-c-Qal^x;z?G|MsUo8k-~+88R1|Am$oo^$OaRJC}UD$
z+G*yMWlh#$O0Kej$51*Jwh^rU1dLBL2m1l+3|j^!87Jh22(#lXkl6yL>@Nk)Ps|Ns
zI$bbRTnD=ypXOs*$qx<9#W=95G=8Rs#fuf)7@zXt%0*!{>Hwn*!1yP;!Z6tnI(HvZ
z-U^17=9sV^F=C57V%SG*HvAC=I@1@1OBaoyfee@DvZ3A@lh!f3HeYAlT70&Vd2#d^
zi~Uy?I|~M3^JHzhB2jh!;ApS@ymow8r>bE<o_!k|2A%eyVLl2{8=H>41XtGQQ1&$J
zP{Z=9N|kRyCC!fmFAlQE;umAZ3LA84wJ}vK$Lj}S?Jl_eU_9Y<5Y`XxXOo4R0D&m3
zN9Q%I;pPQIb6OjX^{V0OJd3E2RWh+e)*%s|%@iPE*BSYMWe68$@Y+RwWsB-F&5y9{
zpbK!$#}_PNhl!?*=xh@?RG410gtZl#H)bwdn%WP01x+!Lfm(zg*Nrfuf!x4=boe#M
zC*jS^_MGOP!Xe$CK%k2TT#J}Erfp1nBYDE&sxdYFDLcY3MzUkOX3$WK+Trt;$5cVM
z4cBBtGmh&YKY#iB<+G!M<Axre)enD7b73biS_9r5$tsJp6z^^RSVqfr+_j)bkQu~R
zo?!<Q=;8<}A#mHS{UZF6a?E;bDw+_Txz@)%#@rp?l1EIGo?Hrrqp%cX+2vpGZH#dg
z<KRW@_%{vJfPW*uJlJC==JMG490yT(Pty5JAc)0g!&i9kQS%jO_)XvHVW)ZM;C*79
z;^w~F?gJz6o6oG^7yVWf^?SX+-P1n4+a+GR*@8O`+F7$(ukAth;aP5a1E@Kt30por
z+*NNt(~rXg{e+c~UxoV9ME)ew2`wRuQuF{NDesi*lp~3<1Tz7ia16gw4yWX=<kUqi
z<-2PAL%JkM5Rbj#!>GR~)&GYp{jDN`uW>$O^zWqnoQPj2x4-v@w=_`=A4y}m|0kVP
p=TQko)Y#5U9!|$NvdB2{J6WA-&Eth0X7v~scz=`rrQBDg{{qQrYK{N^

literal 0
HcmV?d00001

diff --git a/backend/gRPCProjector/python/__pycache__/projector_pb2_grpc.cpython-38.pyc b/backend/gRPCProjector/python/__pycache__/projector_pb2_grpc.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f95009adeb8c6035fbca843d5f5745e6c5051400
GIT binary patch
literal 4617
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
EzgH?=m;e9(

literal 0
HcmV?d00001

diff --git a/backend/gRPCProjector/python/grpcServer.py b/backend/gRPCProjector/python/grpcServer.py
new file mode 100644
index 0000000..78db1b0
--- /dev/null
+++ b/backend/gRPCProjector/python/grpcServer.py
@@ -0,0 +1,42 @@
+from concurrent import futures
+import grpc
+import projector_pb2_grpc as rpc
+
+import projector_pb2 as projector
+
+
+
+class ProjectorService(rpc.ProjectorServicer):
+
+    def __init__(self):
+        self.pointID = 0
+    
+    def getProjectionPoints(self, request_iterator, context):
+        print("Connected")
+        for message in request_iterator:
+            yield self.rowToPoint(message)
+
+    def rowToPoint(self, row):
+        hdvector = row.hdvector
+        returnPoint = projector.Point(id=self.pointID, x = float(hdvector[0]), y=float(hdvector[1]))
+        self.pointID += 1
+
+
+        if self.pointID % 1000 == 0:
+            print("Received {} points!".format(self.pointID))
+        return returnPoint
+    
+def serveServer():
+    port = '[::]:50051'
+    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    rpc.add_ProjectorServicer_to_server(ProjectorService(), server)
+    server.add_insecure_port(port)
+    server.start()
+    print("Listening on port: " + port)
+    server.wait_for_termination()
+
+def serveLocal():
+    return
+    
+if __name__ == '__main__':
+    serveServer()
diff --git a/backend/gRPCProjector/python/projector_pb2.py b/backend/gRPCProjector/python/projector_pb2.py
new file mode 100644
index 0000000..3f34f70
--- /dev/null
+++ b/backend/gRPCProjector/python/projector_pb2.py
@@ -0,0 +1,239 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: projector.proto
+
+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()
+
+
+from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='projector.proto',
+  package='provee',
+  syntax='proto3',
+  serialized_options=b'\n\017nl.uuvig.proveeB\022ProveProjectorGRCPP\001\242\002\006PROVEE',
+  create_key=_descriptor._internal_create_key,
+  serialized_pb=b'\n\x0fprojector.proto\x12\x06provee\x1a\x1bgoogle/protobuf/empty.proto\")\n\x05Point\x12\n\n\x02id\x18\x01 \x01(\x05\x12\t\n\x01x\x18\x02 \x01(\x02\x12\t\n\x01y\x18\x03 \x01(\x02\"D\n\x0bTrainingSet\x12\x0f\n\x07modelid\x18\x01 \x01(\t\x12$\n\x04rows\x18\x02 \x03(\x0b\x32\x16.provee.TrainingSetRow\"2\n\x0eTrainingSetRow\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x08hdvector\x18\x02 \x03(\x01\x42\x02\x10\x01\x32\xf9\x01\n\tProjector\x12\x37\n\x05start\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12\x36\n\x04stop\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12\x42\n\x13getProjectionPoints\x12\x16.provee.TrainingSetRow\x1a\r.provee.Point\"\x00(\x01\x30\x01\x12\x37\n\ngetUpdates\x12\x16.google.protobuf.Empty\x1a\r.provee.Point\"\x00\x30\x01\x42\x30\n\x0fnl.uuvig.proveeB\x12ProveProjectorGRCPP\x01\xa2\x02\x06PROVEEb\x06proto3'
+  ,
+  dependencies=[google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,])
+
+
+
+
+_POINT = _descriptor.Descriptor(
+  name='Point',
+  full_name='provee.Point',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='provee.Point.id', index=0,
+      number=1, 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='x', full_name='provee.Point.x', index=1,
+      number=2, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(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='y', full_name='provee.Point.y', index=2,
+      number=3, type=2, cpp_type=6, label=1,
+      has_default_value=False, default_value=float(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),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=56,
+  serialized_end=97,
+)
+
+
+_TRAININGSET = _descriptor.Descriptor(
+  name='TrainingSet',
+  full_name='provee.TrainingSet',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='modelid', full_name='provee.TrainingSet.modelid', 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='rows', full_name='provee.TrainingSet.rows', index=1,
+      number=2, 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=99,
+  serialized_end=167,
+)
+
+
+_TRAININGSETROW = _descriptor.Descriptor(
+  name='TrainingSetRow',
+  full_name='provee.TrainingSetRow',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='provee.TrainingSetRow.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='hdvector', full_name='provee.TrainingSetRow.hdvector', index=1,
+      number=2, type=1, cpp_type=5, 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=b'\020\001', 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=169,
+  serialized_end=219,
+)
+
+_TRAININGSET.fields_by_name['rows'].message_type = _TRAININGSETROW
+DESCRIPTOR.message_types_by_name['Point'] = _POINT
+DESCRIPTOR.message_types_by_name['TrainingSet'] = _TRAININGSET
+DESCRIPTOR.message_types_by_name['TrainingSetRow'] = _TRAININGSETROW
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+Point = _reflection.GeneratedProtocolMessageType('Point', (_message.Message,), {
+  'DESCRIPTOR' : _POINT,
+  '__module__' : 'projector_pb2'
+  # @@protoc_insertion_point(class_scope:provee.Point)
+  })
+_sym_db.RegisterMessage(Point)
+
+TrainingSet = _reflection.GeneratedProtocolMessageType('TrainingSet', (_message.Message,), {
+  'DESCRIPTOR' : _TRAININGSET,
+  '__module__' : 'projector_pb2'
+  # @@protoc_insertion_point(class_scope:provee.TrainingSet)
+  })
+_sym_db.RegisterMessage(TrainingSet)
+
+TrainingSetRow = _reflection.GeneratedProtocolMessageType('TrainingSetRow', (_message.Message,), {
+  'DESCRIPTOR' : _TRAININGSETROW,
+  '__module__' : 'projector_pb2'
+  # @@protoc_insertion_point(class_scope:provee.TrainingSetRow)
+  })
+_sym_db.RegisterMessage(TrainingSetRow)
+
+
+DESCRIPTOR._options = None
+_TRAININGSETROW.fields_by_name['hdvector']._options = None
+
+_PROJECTOR = _descriptor.ServiceDescriptor(
+  name='Projector',
+  full_name='provee.Projector',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  create_key=_descriptor._internal_create_key,
+  serialized_start=222,
+  serialized_end=471,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='start',
+    full_name='provee.Projector.start',
+    index=0,
+    containing_service=None,
+    input_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
+    output_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='stop',
+    full_name='provee.Projector.stop',
+    index=1,
+    containing_service=None,
+    input_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
+    output_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='getProjectionPoints',
+    full_name='provee.Projector.getProjectionPoints',
+    index=2,
+    containing_service=None,
+    input_type=_TRAININGSETROW,
+    output_type=_POINT,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+  _descriptor.MethodDescriptor(
+    name='getUpdates',
+    full_name='provee.Projector.getUpdates',
+    index=3,
+    containing_service=None,
+    input_type=google_dot_protobuf_dot_empty__pb2._EMPTY,
+    output_type=_POINT,
+    serialized_options=None,
+    create_key=_descriptor._internal_create_key,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_PROJECTOR)
+
+DESCRIPTOR.services_by_name['Projector'] = _PROJECTOR
+
+# @@protoc_insertion_point(module_scope)
diff --git a/backend/gRPCProjector/python/projector_pb2_grpc.py b/backend/gRPCProjector/python/projector_pb2_grpc.py
new file mode 100644
index 0000000..f36b3e0
--- /dev/null
+++ b/backend/gRPCProjector/python/projector_pb2_grpc.py
@@ -0,0 +1,183 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2
+import projector_pb2 as projector__pb2
+
+
+class ProjectorStub(object):
+    """Interface exported by the server.
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.start = channel.unary_unary(
+                '/provee.Projector/start',
+                request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                )
+        self.stop = channel.unary_unary(
+                '/provee.Projector/stop',
+                request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                )
+        self.getProjectionPoints = channel.stream_stream(
+                '/provee.Projector/getProjectionPoints',
+                request_serializer=projector__pb2.TrainingSetRow.SerializeToString,
+                response_deserializer=projector__pb2.Point.FromString,
+                )
+        self.getUpdates = channel.unary_stream(
+                '/provee.Projector/getUpdates',
+                request_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+                response_deserializer=projector__pb2.Point.FromString,
+                )
+
+
+class ProjectorServicer(object):
+    """Interface exported by the server.
+    """
+
+    def start(self, request, context):
+        """A simple RPC.
+
+        Start the Projector calculation
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def stop(self, request, context):
+        """Stop the Projector calculation
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def getProjectionPoints(self, request_iterator, context):
+        """A server-to-client streaming RPC.
+
+        Obtains the Projection Points in 2D given the trainings values stored in a row format.  Results are
+        streamed rather than returned at once (e.g. in a response message with a
+        repeated field).
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def getUpdates(self, request, context):
+        """A server-to-client streaming RPC.
+
+        Obtains the Projection Points in 2D given the trainings values stored in a row format.  Results are
+        streamed rather than returned at once (e.g. in a response message with a
+        repeated field).
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_ProjectorServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'start': grpc.unary_unary_rpc_method_handler(
+                    servicer.start,
+                    request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                    response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            ),
+            'stop': grpc.unary_unary_rpc_method_handler(
+                    servicer.stop,
+                    request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                    response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            ),
+            'getProjectionPoints': grpc.stream_stream_rpc_method_handler(
+                    servicer.getProjectionPoints,
+                    request_deserializer=projector__pb2.TrainingSetRow.FromString,
+                    response_serializer=projector__pb2.Point.SerializeToString,
+            ),
+            'getUpdates': grpc.unary_stream_rpc_method_handler(
+                    servicer.getUpdates,
+                    request_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+                    response_serializer=projector__pb2.Point.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'provee.Projector', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class Projector(object):
+    """Interface exported by the server.
+    """
+
+    @staticmethod
+    def start(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, '/provee.Projector/start',
+            google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def stop(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, '/provee.Projector/stop',
+            google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            google_dot_protobuf_dot_empty__pb2.Empty.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def getProjectionPoints(request_iterator,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.stream_stream(request_iterator, target, '/provee.Projector/getProjectionPoints',
+            projector__pb2.TrainingSetRow.SerializeToString,
+            projector__pb2.Point.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def getUpdates(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_stream(request, target, '/provee.Projector/getUpdates',
+            google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString,
+            projector__pb2.Point.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/backend/gRPCProjector/python/protos/README.md b/backend/gRPCProjector/python/protos/README.md
new file mode 100644
index 0000000..128e4b2
--- /dev/null
+++ b/backend/gRPCProjector/python/protos/README.md
@@ -0,0 +1,3 @@
+# protos
+
+Contains all Protos (gRCP) files that are used to communicate between services in Provee
\ No newline at end of file
diff --git a/backend/gRPCProjector/python/protos/v3/projector.proto b/backend/gRPCProjector/python/protos/v3/projector.proto
new file mode 100644
index 0000000..de425c0
--- /dev/null
+++ b/backend/gRPCProjector/python/protos/v3/projector.proto
@@ -0,0 +1,71 @@
+syntax = "proto3";
+
+package provee;
+
+import "google/protobuf/empty.proto";
+
+option java_multiple_files = true;
+option java_package = "nl.uuvig.provee";
+option java_outer_classname = "ProveProjectorGRCP";
+option objc_class_prefix = "PROVEE";
+
+
+// Interface exported by the server.
+service Projector {
+  // A simple RPC.
+  //
+  // Start the Projector calculation
+  rpc start(google.protobuf.Empty) returns (google.protobuf.Empty);
+
+  // Stop the Projector calculation
+  rpc stop(google.protobuf.Empty) returns (google.protobuf.Empty);
+
+  // A server-to-client streaming RPC.
+  //
+  // Obtains the Projection Points in 2D given the trainings values stored in a row format.  Results are
+  // streamed rather than returned at once (e.g. in a response message with a
+  // repeated field).
+  rpc getProjectionPoints(stream TrainingSetRow) returns (stream Point) {}
+
+  // A server-to-client streaming RPC.
+  //
+  // Obtains the Projection Points in 2D given the trainings values stored in a row format.  Results are
+  // streamed rather than returned at once (e.g. in a response message with a
+  // repeated field).
+  rpc getUpdates(google.protobuf.Empty) returns (stream Point) {}
+
+//   // A client-to-server streaming RPC.
+//   //
+//   // Accepts a stream of Points on a route being traversed, returning a
+//   // RouteSummary when traversal is completed.
+//   rpc RecordRoute(stream Point) returns (RouteSummary) {}
+
+//   // A Bidirectional streaming RPC.
+//   //
+//   // Accepts a stream of RouteNotes sent while a route is being traversed,
+//   // while receiving other RouteNotes (e.g. from other users).
+//   rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
+}
+
+// Points are represented as x-y pairs
+message Point {
+  int32 id = 1;
+  float x = 2;
+  float y = 3;
+}
+
+// Needs description
+message TrainingSet {
+  string modelid = 1;
+  repeated TrainingSetRow rows = 2;
+}
+
+// Needs documentation
+message TrainingSetRow {
+  // The id of the row, e.g., row index.
+  string id = 1;
+
+  // The hd vector of the item.
+  repeated double hdvector = 2 [packed=true];
+}
+
-- 
GitLab