Explorar o código

Initial gRPC setup for RPC project

Sajjad hai 3 semanas
achega
543172c4be

+ 6 - 0
.vscode/settings.json

@@ -0,0 +1,6 @@
+{
+    "python.defaultInterpreterPath": "C:/Users/Asus/AppData/Local/Programs/Python/Python313/python.exe",
+    "python.analysis.extraPaths": [
+        "C:/Users/Asus/AppData/Local/Programs/Python/Python313/Lib/site-packages"
+    ]
+}

BIN=BIN
__pycache__/grpc.cpython-313.pyc


BIN=BIN
__pycache__/grpc_server.cpython-313.pyc


BIN=BIN
__pycache__/hr_pb2.cpython-313.pyc


BIN=BIN
__pycache__/hr_pb2_grpc.cpython-313.pyc


+ 234 - 0
grpc_server.py

@@ -0,0 +1,234 @@
+import grpc
+
+from concurrent import futures
+import time
+import threading
+import hr_pb2
+import hr_pb2_grpc
+
+# ========== IAM Service ==========
+class IAMService(hr_pb2_grpc.IAMServiceServicer):
+    def GetUser(self, request, context):
+        print(f"[IAM] GetUser called with id={request.id}")
+        return hr_pb2.UserResponse(id=request.id, name="Alice", role="Engineer")
+
+    def Login(self, request, context):
+        print(f"[IAM] Login attempt: {request.username}")
+        if request.username == "admin" and request.password == "1234":
+            return hr_pb2.LoginResponse(success=True, message="Login successful")
+        else:
+            return hr_pb2.LoginResponse(success=False, message="Invalid credentials")
+
+# ========== Personality Test Service ==========
+class PersonalityTestService(hr_pb2_grpc.PersonalityTestServiceServicer):
+    def __init__(self, channel):
+        self.iam_stub = hr_pb2_grpc.IAMServiceStub(channel)
+    
+    def GetTestResult(self, request, context):
+        print(f"[PersonalityTest] GetTestResult for user {request.user_id}")
+        
+        # Call IAM service to verify user exists
+        try:
+            user = self.iam_stub.GetUser(hr_pb2.UserRequest(id=request.user_id))
+            print(f"[PersonalityTest] User verified: {user.name}")
+        except grpc.RpcError as e:
+            print(f"[PersonalityTest] Failed to verify user: {e}")
+        
+        return hr_pb2.TestResponse(user_id=request.user_id, result="INTJ - The Architect")
+
+
+# ========== Interview Service ==========
+class InterviewService(hr_pb2_grpc.InterviewServiceServicer):
+    def __init__(self, channel):
+        self.data = {}
+        self.iam_stub = hr_pb2_grpc.IAMServiceStub(channel)
+        self.workspace_stub = hr_pb2_grpc.WorkspaceServiceStub(channel)
+
+    def ScheduleInterview(self, request, context):
+        print(f"[Interview] Scheduling interview for user {request.user_id} on {request.date}")
+        
+        # Call IAM to get user info
+        try:
+            user = self.iam_stub.GetUser(hr_pb2.UserRequest(id=request.user_id))
+            print(f"[Interview] Scheduling for: {user.name} ({user.role})")
+        except grpc.RpcError as e:
+            print(f"[Interview] Could not get user info: {e}")
+        
+        # Call Workspace to get user profile
+        try:
+            profile = self.workspace_stub.GetProfile(hr_pb2.GetProfileRequest(user_id=request.user_id))
+            if profile.success:
+                print(f"[Interview] Candidate skills: {profile.skills}")
+        except grpc.RpcError as e:
+            print(f"[Interview] Could not get profile: {e}")
+        
+        self.data.setdefault(request.user_id, []).append(request.date)
+        return hr_pb2.InterviewResponse(success=True, message="Interview scheduled")
+
+    def GetInterviews(self, request, context):
+        print(f"[Interview] Getting interviews for user {request.user_id}")
+        interviews = self.data.get(request.user_id, [])
+        return hr_pb2.InterviewListResponse(interviews=interviews)
+
+
+# ========== Workspace Service ==========
+class WorkspaceService(hr_pb2_grpc.WorkspaceServiceServicer):
+    def __init__(self, channel):
+        self.profiles = {}
+        self.job_descriptions = {}
+        self.iam_stub = hr_pb2_grpc.IAMServiceStub(channel)
+        self.test_stub = hr_pb2_grpc.PersonalityTestServiceStub(channel)
+
+    def CreateProfile(self, request, context):
+        print(f"[Workspace] Creating profile for user {request.user_id}")
+        
+        # Call IAM to verify user
+        try:
+            user = self.iam_stub.GetUser(hr_pb2.UserRequest(id=request.user_id))
+            print(f"[Workspace] Creating profile for verified user: {user.name}")
+        except grpc.RpcError as e:
+            print(f"[Workspace] Could not verify user: {e}")
+        
+        # Get personality test result
+        try:
+            test_result = self.test_stub.GetTestResult(hr_pb2.TestRequest(user_id=request.user_id))
+            print(f"[Workspace] User personality: {test_result.result}")
+        except grpc.RpcError as e:
+            print(f"[Workspace] Could not get personality test: {e}")
+        
+        self.profiles[request.user_id] = {
+            'name': request.name,
+            'skills': request.skills,
+            'experience': request.experience
+        }
+        return hr_pb2.ProfileResponse(
+            user_id=request.user_id,
+            name=request.name,
+            skills=request.skills,
+            experience=request.experience,
+            success=True,
+            message="Profile created successfully"
+        )
+
+    def GetProfile(self, request, context):
+        print(f"[Workspace] Getting profile for user {request.user_id}")
+        profile = self.profiles.get(request.user_id)
+        if profile:
+            return hr_pb2.ProfileResponse(
+                user_id=request.user_id,
+                name=profile['name'],
+                skills=profile['skills'],
+                experience=profile['experience'],
+                success=True,
+                message="Profile retrieved"
+            )
+        else:
+            return hr_pb2.ProfileResponse(
+                user_id=request.user_id,
+                success=False,
+                message="Profile not found"
+            )
+
+    def CreateJobDescription(self, request, context):
+        print(f"[Workspace] Creating job description {request.job_id}")
+        self.job_descriptions[request.job_id] = {
+            'title': request.title,
+            'description': request.description,
+            'requirements': request.requirements
+        }
+        return hr_pb2.JobDescriptionResponse(
+            job_id=request.job_id,
+            title=request.title,
+            description=request.description,
+            requirements=request.requirements,
+            success=True,
+            message="Job description created successfully"
+        )
+
+    def GetJobDescription(self, request, context):
+        print(f"[Workspace] Getting job description {request.job_id}")
+        job = self.job_descriptions.get(request.job_id)
+        if job:
+            return hr_pb2.JobDescriptionResponse(
+                job_id=request.job_id,
+                title=job['title'],
+                description=job['description'],
+                requirements=job['requirements'],
+                success=True,
+                message="Job description retrieved"
+            )
+        else:
+            return hr_pb2.JobDescriptionResponse(
+                job_id=request.job_id,
+                success=False,
+                message="Job description not found"
+            )
+
+
+# ========== Server Function ==========
+def serve():
+    # Create internal channel for inter-service communication
+    internal_channel = grpc.insecure_channel('localhost:50051')
+    
+    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    hr_pb2_grpc.add_IAMServiceServicer_to_server(IAMService(), server)
+    hr_pb2_grpc.add_PersonalityTestServiceServicer_to_server(PersonalityTestService(internal_channel), server)
+    hr_pb2_grpc.add_InterviewServiceServicer_to_server(InterviewService(internal_channel), server)
+    hr_pb2_grpc.add_WorkspaceServiceServicer_to_server(WorkspaceService(internal_channel), server)
+    server.add_insecure_port('[::]:50051')
+    server.start()
+    print("🚀 gRPC server running on port 50051 with inter-service communication enabled")
+    server.wait_for_termination()
+
+
+# ========== Client Function ==========
+def run_client():
+    time.sleep(2)  # Wait for server to fully start
+    with grpc.insecure_channel('localhost:50051') as channel:
+        iam = hr_pb2_grpc.IAMServiceStub(channel)
+        test = hr_pb2_grpc.PersonalityTestServiceStub(channel)
+        interview = hr_pb2_grpc.InterviewServiceStub(channel)
+        workspace = hr_pb2_grpc.WorkspaceServiceStub(channel)
+
+        print("\n=== Testing IAM ===")
+        user = iam.GetUser(hr_pb2.UserRequest(id=1))
+        print(f"✅ User: {user.name}, Role: {user.role}")
+
+        login = iam.Login(hr_pb2.LoginRequest(username="admin", password="1234"))
+        print(f"✅ Login: {login.message}")
+
+        print("\n=== Testing Personality Test (calls IAM) ===")
+        result = test.GetTestResult(hr_pb2.TestRequest(user_id=1))
+        print(f"✅ Personality result: {result.result}")
+
+        print("\n=== Testing Workspace - Profile (calls IAM & PersonalityTest) ===")
+        profile = workspace.CreateProfile(hr_pb2.ProfileRequest(
+            user_id=1,
+            name="Alice Johnson",
+            skills="Python, gRPC, Microservices",
+            experience="5 years"
+        ))
+        print(f"✅ Profile created: {profile.message}")
+
+        print("\n=== Testing Interview Scheduling (calls IAM & Workspace) ===")
+        interview.ScheduleInterview(hr_pb2.InterviewRequest(user_id=1, date="2025-10-25"))
+        interview.ScheduleInterview(hr_pb2.InterviewRequest(user_id=1, date="2025-10-30"))
+
+        interviews = interview.GetInterviews(hr_pb2.InterviewListRequest(user_id=1))
+        print(f"✅ Interview dates: {list(interviews.interviews)}")
+
+        print("\n=== Testing Workspace - Job Description ===")
+        job = workspace.CreateJobDescription(hr_pb2.JobDescriptionRequest(
+            job_id=101,
+            title="Senior Backend Engineer",
+            description="Build scalable microservices",
+            requirements="5+ years Python, gRPC experience"
+        ))
+        print(f"✅ Job description created: {job.message}")
+
+
+# ========== Run Both ==========
+if __name__ == "__main__":
+    t = threading.Thread(target=serve, daemon=True)
+    t.start()
+    run_client()

+ 118 - 0
hr.proto

@@ -0,0 +1,118 @@
+syntax = "proto3";
+
+package hr;
+
+// ===== IAM Service =====
+service IAMService {
+  rpc GetUser (UserRequest) returns (UserResponse);
+  rpc Login (LoginRequest) returns (LoginResponse);
+}
+
+message UserRequest {
+  int32 id = 1;
+}
+
+message UserResponse {
+  int32 id = 1;
+  string name = 2;
+  string role = 3;
+}
+
+message LoginRequest {
+  string username = 1;
+  string password = 2;
+}
+
+message LoginResponse {
+  bool success = 1;
+  string message = 2;
+}
+
+
+// ===== Personality Test Service =====
+service PersonalityTestService {
+  rpc GetTestResult (TestRequest) returns (TestResponse);
+}
+
+message TestRequest {
+  int32 user_id = 1;
+}
+
+message TestResponse {
+  int32 user_id = 1;
+  string result = 2;
+}
+
+
+// ===== Interview Service =====
+service InterviewService {
+  rpc ScheduleInterview (InterviewRequest) returns (InterviewResponse);
+  rpc GetInterviews (InterviewListRequest) returns (InterviewListResponse);
+}
+
+message InterviewRequest {
+  int32 user_id = 1;
+  string date = 2;
+}
+
+message InterviewResponse {
+  bool success = 1;
+  string message = 2;
+}
+
+message InterviewListRequest {
+  int32 user_id = 1;
+}
+
+message InterviewListResponse {
+  repeated string interviews = 1;
+}
+
+
+// ===== Workspace Service =====
+service WorkspaceService {
+  rpc CreateProfile (ProfileRequest) returns (ProfileResponse);
+  rpc GetProfile (GetProfileRequest) returns (ProfileResponse);
+  rpc CreateJobDescription (JobDescriptionRequest) returns (JobDescriptionResponse);
+  rpc GetJobDescription (GetJobDescriptionRequest) returns (JobDescriptionResponse);
+}
+
+message ProfileRequest {
+  int32 user_id = 1;
+  string name = 2;
+  string skills = 3;
+  string experience = 4;
+}
+
+message GetProfileRequest {
+  int32 user_id = 1;
+}
+
+message ProfileResponse {
+  int32 user_id = 1;
+  string name = 2;
+  string skills = 3;
+  string experience = 4;
+  bool success = 5;
+  string message = 6;
+}
+
+message JobDescriptionRequest {
+  int32 job_id = 1;
+  string title = 2;
+  string description = 3;
+  string requirements = 4;
+}
+
+message GetJobDescriptionRequest {
+  int32 job_id = 1;
+}
+
+message JobDescriptionResponse {
+  int32 job_id = 1;
+  string title = 2;
+  string description = 3;
+  string requirements = 4;
+  bool success = 5;
+  string message = 6;
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 26 - 0
hr_pb2.py


+ 540 - 0
hr_pb2_grpc.py

@@ -0,0 +1,540 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+import warnings
+
+import hr_pb2 as hr__pb2
+
+GRPC_GENERATED_VERSION = '1.75.1'
+GRPC_VERSION = grpc.__version__
+_version_not_supported = False
+
+try:
+    from grpc._utilities import first_version_is_lower
+    _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
+except ImportError:
+    _version_not_supported = True
+
+if _version_not_supported:
+    raise RuntimeError(
+        f'The grpc package installed is at version {GRPC_VERSION},'
+        + f' but the generated code in hr_pb2_grpc.py depends on'
+        + f' grpcio>={GRPC_GENERATED_VERSION}.'
+        + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+        + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
+    )
+
+
+class IAMServiceStub(object):
+    """===== IAM Service =====
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.GetUser = channel.unary_unary(
+                '/hr.IAMService/GetUser',
+                request_serializer=hr__pb2.UserRequest.SerializeToString,
+                response_deserializer=hr__pb2.UserResponse.FromString,
+                _registered_method=True)
+        self.Login = channel.unary_unary(
+                '/hr.IAMService/Login',
+                request_serializer=hr__pb2.LoginRequest.SerializeToString,
+                response_deserializer=hr__pb2.LoginResponse.FromString,
+                _registered_method=True)
+
+
+class IAMServiceServicer(object):
+    """===== IAM Service =====
+    """
+
+    def GetUser(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 Login(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_IAMServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'GetUser': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetUser,
+                    request_deserializer=hr__pb2.UserRequest.FromString,
+                    response_serializer=hr__pb2.UserResponse.SerializeToString,
+            ),
+            'Login': grpc.unary_unary_rpc_method_handler(
+                    servicer.Login,
+                    request_deserializer=hr__pb2.LoginRequest.FromString,
+                    response_serializer=hr__pb2.LoginResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'hr.IAMService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+    server.add_registered_method_handlers('hr.IAMService', rpc_method_handlers)
+
+
+ # This class is part of an EXPERIMENTAL API.
+class IAMService(object):
+    """===== IAM Service =====
+    """
+
+    @staticmethod
+    def GetUser(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,
+            '/hr.IAMService/GetUser',
+            hr__pb2.UserRequest.SerializeToString,
+            hr__pb2.UserResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+    @staticmethod
+    def Login(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,
+            '/hr.IAMService/Login',
+            hr__pb2.LoginRequest.SerializeToString,
+            hr__pb2.LoginResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+
+class PersonalityTestServiceStub(object):
+    """===== Personality Test Service =====
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.GetTestResult = channel.unary_unary(
+                '/hr.PersonalityTestService/GetTestResult',
+                request_serializer=hr__pb2.TestRequest.SerializeToString,
+                response_deserializer=hr__pb2.TestResponse.FromString,
+                _registered_method=True)
+
+
+class PersonalityTestServiceServicer(object):
+    """===== Personality Test Service =====
+    """
+
+    def GetTestResult(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_PersonalityTestServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'GetTestResult': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetTestResult,
+                    request_deserializer=hr__pb2.TestRequest.FromString,
+                    response_serializer=hr__pb2.TestResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'hr.PersonalityTestService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+    server.add_registered_method_handlers('hr.PersonalityTestService', rpc_method_handlers)
+
+
+ # This class is part of an EXPERIMENTAL API.
+class PersonalityTestService(object):
+    """===== Personality Test Service =====
+    """
+
+    @staticmethod
+    def GetTestResult(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,
+            '/hr.PersonalityTestService/GetTestResult',
+            hr__pb2.TestRequest.SerializeToString,
+            hr__pb2.TestResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+
+class InterviewServiceStub(object):
+    """===== Interview Service =====
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.ScheduleInterview = channel.unary_unary(
+                '/hr.InterviewService/ScheduleInterview',
+                request_serializer=hr__pb2.InterviewRequest.SerializeToString,
+                response_deserializer=hr__pb2.InterviewResponse.FromString,
+                _registered_method=True)
+        self.GetInterviews = channel.unary_unary(
+                '/hr.InterviewService/GetInterviews',
+                request_serializer=hr__pb2.InterviewListRequest.SerializeToString,
+                response_deserializer=hr__pb2.InterviewListResponse.FromString,
+                _registered_method=True)
+
+
+class InterviewServiceServicer(object):
+    """===== Interview Service =====
+    """
+
+    def ScheduleInterview(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 GetInterviews(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_InterviewServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'ScheduleInterview': grpc.unary_unary_rpc_method_handler(
+                    servicer.ScheduleInterview,
+                    request_deserializer=hr__pb2.InterviewRequest.FromString,
+                    response_serializer=hr__pb2.InterviewResponse.SerializeToString,
+            ),
+            'GetInterviews': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetInterviews,
+                    request_deserializer=hr__pb2.InterviewListRequest.FromString,
+                    response_serializer=hr__pb2.InterviewListResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'hr.InterviewService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+    server.add_registered_method_handlers('hr.InterviewService', rpc_method_handlers)
+
+
+ # This class is part of an EXPERIMENTAL API.
+class InterviewService(object):
+    """===== Interview Service =====
+    """
+
+    @staticmethod
+    def ScheduleInterview(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,
+            '/hr.InterviewService/ScheduleInterview',
+            hr__pb2.InterviewRequest.SerializeToString,
+            hr__pb2.InterviewResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+    @staticmethod
+    def GetInterviews(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,
+            '/hr.InterviewService/GetInterviews',
+            hr__pb2.InterviewListRequest.SerializeToString,
+            hr__pb2.InterviewListResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+
+class WorkspaceServiceStub(object):
+    """===== Workspace Service =====
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.CreateProfile = channel.unary_unary(
+                '/hr.WorkspaceService/CreateProfile',
+                request_serializer=hr__pb2.ProfileRequest.SerializeToString,
+                response_deserializer=hr__pb2.ProfileResponse.FromString,
+                _registered_method=True)
+        self.GetProfile = channel.unary_unary(
+                '/hr.WorkspaceService/GetProfile',
+                request_serializer=hr__pb2.GetProfileRequest.SerializeToString,
+                response_deserializer=hr__pb2.ProfileResponse.FromString,
+                _registered_method=True)
+        self.CreateJobDescription = channel.unary_unary(
+                '/hr.WorkspaceService/CreateJobDescription',
+                request_serializer=hr__pb2.JobDescriptionRequest.SerializeToString,
+                response_deserializer=hr__pb2.JobDescriptionResponse.FromString,
+                _registered_method=True)
+        self.GetJobDescription = channel.unary_unary(
+                '/hr.WorkspaceService/GetJobDescription',
+                request_serializer=hr__pb2.GetJobDescriptionRequest.SerializeToString,
+                response_deserializer=hr__pb2.JobDescriptionResponse.FromString,
+                _registered_method=True)
+
+
+class WorkspaceServiceServicer(object):
+    """===== Workspace Service =====
+    """
+
+    def CreateProfile(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 GetProfile(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 CreateJobDescription(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 GetJobDescription(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_WorkspaceServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'CreateProfile': grpc.unary_unary_rpc_method_handler(
+                    servicer.CreateProfile,
+                    request_deserializer=hr__pb2.ProfileRequest.FromString,
+                    response_serializer=hr__pb2.ProfileResponse.SerializeToString,
+            ),
+            'GetProfile': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetProfile,
+                    request_deserializer=hr__pb2.GetProfileRequest.FromString,
+                    response_serializer=hr__pb2.ProfileResponse.SerializeToString,
+            ),
+            'CreateJobDescription': grpc.unary_unary_rpc_method_handler(
+                    servicer.CreateJobDescription,
+                    request_deserializer=hr__pb2.JobDescriptionRequest.FromString,
+                    response_serializer=hr__pb2.JobDescriptionResponse.SerializeToString,
+            ),
+            'GetJobDescription': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetJobDescription,
+                    request_deserializer=hr__pb2.GetJobDescriptionRequest.FromString,
+                    response_serializer=hr__pb2.JobDescriptionResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'hr.WorkspaceService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+    server.add_registered_method_handlers('hr.WorkspaceService', rpc_method_handlers)
+
+
+ # This class is part of an EXPERIMENTAL API.
+class WorkspaceService(object):
+    """===== Workspace Service =====
+    """
+
+    @staticmethod
+    def CreateProfile(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,
+            '/hr.WorkspaceService/CreateProfile',
+            hr__pb2.ProfileRequest.SerializeToString,
+            hr__pb2.ProfileResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+    @staticmethod
+    def GetProfile(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,
+            '/hr.WorkspaceService/GetProfile',
+            hr__pb2.GetProfileRequest.SerializeToString,
+            hr__pb2.ProfileResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+    @staticmethod
+    def CreateJobDescription(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,
+            '/hr.WorkspaceService/CreateJobDescription',
+            hr__pb2.JobDescriptionRequest.SerializeToString,
+            hr__pb2.JobDescriptionResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)
+
+    @staticmethod
+    def GetJobDescription(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,
+            '/hr.WorkspaceService/GetJobDescription',
+            hr__pb2.GetJobDescriptionRequest.SerializeToString,
+            hr__pb2.JobDescriptionResponse.FromString,
+            options,
+            channel_credentials,
+            insecure,
+            call_credentials,
+            compression,
+            wait_for_ready,
+            timeout,
+            metadata,
+            _registered_method=True)

+ 94 - 0
http_gateway.py

@@ -0,0 +1,94 @@
+from flask import Flask, jsonify, request
+import grpc
+import hr_pb2
+import hr_pb2_grpc
+
+app = Flask(__name__)
+
+# gRPC channel setup
+channel = grpc.insecure_channel('localhost:50051')
+iam_stub = hr_pb2_grpc.IAMServiceStub(channel)
+test_stub = hr_pb2_grpc.PersonalityTestServiceStub(channel)
+interview_stub = hr_pb2_grpc.InterviewServiceStub(channel)
+
+@app.route('/')
+def home():
+    return '''
+    <h1>HR gRPC Gateway</h1>
+    <h2>Available Endpoints:</h2>
+    <ul>
+        <li><a href="/user/1">GET /user/&lt;id&gt;</a> - Get user info</li>
+        <li>POST /login - Login (send JSON: {"username": "admin", "password": "1234"})</li>
+        <li><a href="/test/1">GET /test/&lt;user_id&gt;</a> - Get personality test result</li>
+        <li>POST /interview - Schedule interview (send JSON: {"user_id": 1, "date": "2025-10-25"})</li>
+        <li><a href="/interviews/1">GET /interviews/&lt;user_id&gt;</a> - Get user interviews</li>
+    </ul>
+    '''
+
+@app.route('/user/<int:user_id>')
+def get_user(user_id):
+    try:
+        response = iam_stub.GetUser(hr_pb2.UserRequest(id=user_id))
+        return jsonify({
+            'id': response.id,
+            'name': response.name,
+            'role': response.role
+        })
+    except grpc.RpcError as e:
+        return jsonify({'error': str(e)}), 500
+
+@app.route('/login', methods=['POST'])
+def login():
+    try:
+        data = request.json
+        response = iam_stub.Login(hr_pb2.LoginRequest(
+            username=data['username'],
+            password=data['password']
+        ))
+        return jsonify({
+            'success': response.success,
+            'message': response.message
+        })
+    except grpc.RpcError as e:
+        return jsonify({'error': str(e)}), 500
+
+@app.route('/test/<int:user_id>')
+def get_test(user_id):
+    try:
+        response = test_stub.GetTestResult(hr_pb2.TestRequest(user_id=user_id))
+        return jsonify({
+            'user_id': response.user_id,
+            'result': response.result
+        })
+    except grpc.RpcError as e:
+        return jsonify({'error': str(e)}), 500
+
+@app.route('/interview', methods=['POST'])
+def schedule_interview():
+    try:
+        data = request.json
+        response = interview_stub.ScheduleInterview(hr_pb2.InterviewRequest(
+            user_id=data['user_id'],
+            date=data['date']
+        ))
+        return jsonify({
+            'success': response.success,
+            'message': response.message
+        })
+    except grpc.RpcError as e:
+        return jsonify({'error': str(e)}), 500
+
+@app.route('/interviews/<int:user_id>')
+def get_interviews(user_id):
+    try:
+        response = interview_stub.GetInterviews(hr_pb2.InterviewListRequest(user_id=user_id))
+        return jsonify({
+            'user_id': user_id,
+            'interviews': list(response.interviews)
+        })
+    except grpc.RpcError as e:
+        return jsonify({'error': str(e)}), 500
+
+if __name__ == '__main__':
+    print("🌐 HTTP Gateway running on http://localhost:5000")
+    app.run(debug=True, port=5000)

+ 3 - 0
requirements.txt

@@ -0,0 +1,3 @@
+grpcio>=1.75.1
+grpcio-tools>=1.75.1
+protobuf>=6.31.1

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio