| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- package hostbridge
- import (
- "context"
- "log"
- "os"
- "github.com/atotto/clipboard"
- "github.com/cline/cli/pkg/cli/global"
- "github.com/cline/grpc-go/cline"
- "github.com/cline/grpc-go/host"
- "google.golang.org/protobuf/proto"
- )
- // Global shutdown channel - simple approach
- var globalShutdownCh chan struct{}
- func init() {
- globalShutdownCh = make(chan struct{})
- }
- // EnvService implements the host.EnvServiceServer interface
- type EnvService struct {
- host.UnimplementedEnvServiceServer
- verbose bool
- }
- // NewEnvService creates a new EnvService
- func NewEnvService(verbose bool) *EnvService {
- return &EnvService{
- verbose: verbose,
- }
- }
- // ClipboardWriteText writes text to the system clipboard
- func (s *EnvService) ClipboardWriteText(ctx context.Context, req *cline.StringRequest) (*cline.Empty, error) {
- if s.verbose {
- log.Printf("ClipboardWriteText called with text length: %d", len(req.GetValue()))
- }
- err := clipboard.WriteAll(req.GetValue())
- if err != nil {
- if s.verbose {
- log.Printf("Failed to write to clipboard: %v", err)
- }
- // Don't fail if clipboard is not available (e.g., headless environment)
- }
- return &cline.Empty{}, nil
- }
- // ClipboardReadText reads text from the system clipboard
- func (s *EnvService) ClipboardReadText(ctx context.Context, req *cline.EmptyRequest) (*cline.String, error) {
- if s.verbose {
- log.Printf("ClipboardReadText called")
- }
- text, err := clipboard.ReadAll()
- if err != nil {
- if s.verbose {
- log.Printf("Failed to read from clipboard: %v", err)
- }
- // Return empty string if clipboard is not available
- text = ""
- }
- return &cline.String{
- Value: text,
- }, nil
- }
- // GetHostVersion returns the host platform name and version
- func (s *EnvService) GetHostVersion(ctx context.Context, req *cline.EmptyRequest) (*host.GetHostVersionResponse, error) {
- if s.verbose {
- log.Printf("GetHostVersion called")
- }
- return &host.GetHostVersionResponse{
- Platform: proto.String("Cline CLI"),
- Version: proto.String(global.CliVersion),
- ClineType: proto.String("CLI"),
- ClineVersion: proto.String(global.CliVersion),
- }, nil
- }
- // Shutdown initiates a graceful shutdown of the host bridge service
- func (s *EnvService) Shutdown(ctx context.Context, req *cline.EmptyRequest) (*cline.Empty, error) {
- if s.verbose {
- log.Printf("Shutdown requested via RPC")
- }
- // Trigger global shutdown signal
- select {
- case globalShutdownCh <- struct{}{}:
- if s.verbose {
- log.Printf("Shutdown signal sent successfully")
- }
- default:
- if s.verbose {
- log.Printf("Shutdown signal already pending")
- }
- }
- return &cline.Empty{}, nil
- }
- // GetTelemetrySettings returns the telemetry settings for CLI mode
- func (s *EnvService) GetTelemetrySettings(ctx context.Context, req *cline.EmptyRequest) (*host.GetTelemetrySettingsResponse, error) {
- if s.verbose {
- log.Printf("GetTelemetrySettings called")
- }
- // In CLI mode, check the POSTHOG_TELEMETRY_ENABLED environment variable
- telemetryEnabled := os.Getenv("POSTHOG_TELEMETRY_ENABLED") == "true"
- var setting host.Setting
- if telemetryEnabled {
- setting = host.Setting_ENABLED
- } else {
- setting = host.Setting_DISABLED
- }
- return &host.GetTelemetrySettingsResponse{
- IsEnabled: setting,
- }, nil
- }
- // SubscribeToTelemetrySettings returns a stream of telemetry setting changes
- // In CLI mode, telemetry settings don't change at runtime, so we just send
- // the current state and keep the stream open
- func (s *EnvService) SubscribeToTelemetrySettings(req *cline.EmptyRequest, stream host.EnvService_SubscribeToTelemetrySettingsServer) error {
- if s.verbose {
- log.Printf("SubscribeToTelemetrySettings called")
- }
- // Send initial telemetry state
- telemetryEnabled := os.Getenv("POSTHOG_TELEMETRY_ENABLED") == "true"
- var setting host.Setting
- if telemetryEnabled {
- setting = host.Setting_ENABLED
- } else {
- setting = host.Setting_DISABLED
- }
- event := &host.TelemetrySettingsEvent{
- IsEnabled: setting,
- }
- if err := stream.Send(event); err != nil {
- if s.verbose {
- log.Printf("Failed to send telemetry settings event: %v", err)
- }
- return err
- }
- // Keep stream open until context is cancelled
- // (In CLI mode, settings don't change dynamically)
- <-stream.Context().Done()
- if s.verbose {
- log.Printf("SubscribeToTelemetrySettings stream closed")
- }
- return nil
- }
|