1 /* Copyright 2012-present Facebook, Inc.
2  * Licensed under the Apache License, Version 2.0 */
3 #pragma once
4 #include <deque>
5 #include <unordered_map>
6 #include <unordered_set>
7 #include "Logging.h"
8 #include "watchman_synchronized.h"
9 
10 struct watchman_client_subscription;
11 
12 struct watchman_client_state_assertion {
13   std::shared_ptr<w_root_t> root; // Holds a ref on the root
14   w_string name;
15   long id;
16 
17   watchman_client_state_assertion(
18       const std::shared_ptr<w_root_t>& root,
19       const w_string& name);
20 };
21 
22 struct watchman_client : public std::enable_shared_from_this<watchman_client> {
23   std::unique_ptr<watchman_stream> stm;
24   std::unique_ptr<watchman_event> ping;
25   w_jbuffer_t reader, writer;
26   bool client_mode{false};
27   bool client_is_owner{false};
28   enum w_pdu_type pdu_type;
29   uint32_t capabilities;
30 
31   // The command currently being processed by dispatch_command
32   json_ref current_command;
33   w_perf_t* perf_sample{nullptr};
34 
35   // Queue of things to send to the client.
36   std::deque<json_ref> responses;
37 
38   // Logging Subscriptions
39   std::shared_ptr<watchman::Publisher::Subscriber> debugSub;
40   std::shared_ptr<watchman::Publisher::Subscriber> errorSub;
41 
42   watchman_client();
43   explicit watchman_client(std::unique_ptr<watchman_stream>&& stm);
44   virtual ~watchman_client();
45 
46   void enqueueResponse(json_ref&& resp, bool ping = true);
47 };
48 
49 struct watchman_user_client;
50 
51 struct watchman_client_subscription
52     : public std::enable_shared_from_this<watchman_client_subscription> {
53   std::shared_ptr<w_root_t> root;
54   w_string name;
55   /* whether this subscription is paused */
56   bool debug_paused = false;
57 
58   std::shared_ptr<w_query> query;
59   bool vcs_defer;
60   uint32_t last_sub_tick;
61   // map of statename => bool.  If true, policy is drop, else defer
62   std::unordered_map<w_string, bool> drop_or_defer;
63   std::weak_ptr<watchman_client> weakClient;
64 
65   explicit watchman_client_subscription(
66       const std::shared_ptr<w_root_t>& root,
67       std::weak_ptr<watchman_client> client);
68   ~watchman_client_subscription();
69   void processSubscription();
70 
71   std::shared_ptr<watchman_user_client> lockClient();
72   json_ref buildSubscriptionResults(
73       const std::shared_ptr<w_root_t>& root,
74       ClockSpec& position);
75 
76  private:
77   ClockSpec runSubscriptionRules(
78       watchman_user_client* client,
79       const std::shared_ptr<w_root_t>& root);
80   void updateSubscriptionTicks(w_query_res* res);
81 };
82 
83 // Represents the server side session maintained for a client of
84 // the watchman per-user process
85 struct watchman_user_client : public watchman_client {
86   /* map of subscription name => struct watchman_client_subscription */
87   std::unordered_map<w_string, std::shared_ptr<watchman_client_subscription>>
88       subscriptions;
89 
90   /* map of unique id => watchman_client_state_assertion.
91    * The values are owned by root::asserted_states */
92   std::unordered_map<long, std::weak_ptr<watchman_client_state_assertion>>
93       states;
94   long next_state_id{0};
95 
96   // Subscriber to root::unilateralResponses
97   std::unordered_map<
98       std::shared_ptr<watchman_client_subscription>,
99       std::shared_ptr<watchman::Publisher::Subscriber>>
100       unilateralSub;
101 
102   explicit watchman_user_client(std::unique_ptr<watchman_stream>&& stm);
103   ~watchman_user_client() override;
104 
105   bool unsubByName(const w_string& name);
106 };
107 
108 extern watchman::Synchronized<
109     std::unordered_set<std::shared_ptr<watchman_client>>>
110     clients;
111 
112 void w_client_vacate_states(struct watchman_user_client *client);
113