text: /*
   *
   * Copyright 2016 gRPC authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  
  #ifndef GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
  #define GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
  
  #include <stddef.h>
  
  #include <map>
  #include <memory>
  #include <string>
  
  #include "absl/base/thread_annotations.h"
  
  #include <grpcpp/grpcpp.h>
  #include <grpcpp/health_check_service_interface.h>
  #include <grpcpp/impl/codegen/sync.h>
  #include <grpcpp/impl/service_type.h>
  #include <grpcpp/support/byte_buffer.h>
  #include <grpcpp/support/config.h>
  #include <grpcpp/support/server_callback.h>
  #include <grpcpp/support/status.h>
  
  #include "src/core/lib/gprpp/ref_counted.h"
  #include "src/core/lib/gprpp/ref_counted_ptr.h"
  
  namespace grpc {
  
  // Default implementation of HealthCheckServiceInterface. Server will create and
  // own it.
  class DefaultHealthCheckService final : public HealthCheckServiceInterface {
   public:
    enum ServingStatus { NOT_FOUND, SERVING, NOT_SERVING };
  
    // The service impl to register with the server.
    class HealthCheckServiceImpl : public Service {
     public:
      // Reactor for handling Watch streams.
      class WatchReactor : public ServerWriteReactor<ByteBuffer>,
                           public grpc_core::RefCounted<WatchReactor> {
       public:
        WatchReactor(HealthCheckServiceImpl* service, const ByteBuffer* request);
  
        void SendHealth(ServingStatus status);
  
        void OnWriteDone(bool ok) override;
        void OnCancel() override;
        void OnDone() override;
  
       private:
        void SendHealthLocked(ServingStatus status)
            ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
  
        void MaybeFinishLocked(Status status) ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
  
        HealthCheckServiceImpl* service_;
        std::string service_name_;
        ByteBuffer response_;
  
        grpc::internal::Mutex mu_;
        bool write_pending_ ABSL_GUARDED_BY(mu_) = false;
        ServingStatus pending_status_ ABSL_GUARDED_BY(mu_) = NOT_FOUND;
        bool finish_called_ ABSL_GUARDED_BY(mu_) = false;
      };
  
      explicit HealthCheckServiceImpl(DefaultHealthCheckService* database);
  
      ~HealthCheckServiceImpl() override;
  
     private:
      // Request handler for Check method.
      static ServerUnaryReactor* HandleCheckRequest(
          DefaultHealthCheckService* database, CallbackServerContext* context,
          const ByteBuffer* request, ByteBuffer* response);
  
      // Returns true on success.
      static bool DecodeRequest(const ByteBuffer& request,
                                std::string* service_name);
      static bool EncodeResponse(ServingStatus status, ByteBuffer* response);
  
      DefaultHealthCheckService* database_;
  
      grpc::internal::Mutex mu_;
      grpc::internal::CondVar shutdown_condition_;
      bool shutdown_ ABSL_GUARDED_BY(mu_) = false;
      size_t num_watches_ ABSL_GUARDED_BY(mu_) = 0;
    };
  
    DefaultHealthCheckService();
  
    void SetServingStatus(const std::string& service_name, bool serving) override;
    void SetServingStatus(bool serving) override;
  
    void Shutdown() override;
  
    ServingStatus GetServingStatus(const std::string& service_name) const;
  
    HealthCheckServiceImpl* GetHealthCheckService();
  
   private:
    // Stores the current serving status of a service and any call
    // handlers registered for updates when the service's status changes.
    class ServiceData {
     public:
      void SetServingStatus(ServingStatus status);
      ServingStatus GetServingStatus() const { return status_; }
      void AddWatch(
          grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher);
      void RemoveWatch(HealthCheckServiceImpl::WatchReactor* watcher);
      bool Unused() const { return watchers_.empty() && status_ == NOT_FOUND; }
  
     private:
      ServingStatus status_ = NOT_FOUND;
      std::map<HealthCheckServiceImpl::WatchReactor*,
               grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor>>
          watchers_;
    };
  
    void RegisterWatch(
        const std::string& service_name,
        grpc_core::RefCountedPtr<HealthCheckServiceImpl::WatchReactor> watcher);
  
    void UnregisterWatch(const std::string& service_name,
                         HealthCheckServiceImpl::WatchReactor* watcher);
  
    mutable grpc::internal::Mutex mu_;
    bool shutdown_ ABSL_GUARDED_BY(&mu_) = false;
    std::map<std::string, ServiceData> services_map_ ABSL_GUARDED_BY(&mu_);
    std::unique_ptr<HealthCheckServiceImpl> impl_;
  };
  
  }  // namespace grpc
  
  #endif  // GRPC_INTERNAL_CPP_SERVER_DEFAULT_HEALTH_CHECK_SERVICE_H
  