1313#ifndef  LLDB_HOST_JSONTRANSPORT_H
1414#define  LLDB_HOST_JSONTRANSPORT_H 
1515
16+ #include  " lldb/Host/MainLoopBase.h" 
17+ #include  " lldb/Utility/IOObject.h" 
18+ #include  " lldb/Utility/Status.h" 
1619#include  " lldb/lldb-forward.h" 
1720#include  " llvm/ADT/StringRef.h" 
1821#include  " llvm/Support/Error.h" 
1922#include  " llvm/Support/FormatVariadic.h" 
2023#include  " llvm/Support/JSON.h" 
21- #include  < chrono > 
24+ #include  < string > 
2225#include  < system_error> 
26+ #include  < vector> 
2327
2428namespace  lldb_private  {
2529
@@ -28,27 +32,26 @@ class TransportEOFError : public llvm::ErrorInfo<TransportEOFError> {
2832  static  char  ID;
2933
3034  TransportEOFError () = default ;
31- 
32-   void  log (llvm::raw_ostream &OS) const  override  {
33-     OS << " transport end of file reached"  ;
34-   }
35-   std::error_code convertToErrorCode () const  override  {
36-     return  llvm::inconvertibleErrorCode ();
37-   }
35+   void  log (llvm::raw_ostream &OS) const  override ;
36+   std::error_code convertToErrorCode () const  override ;
3837};
3938
40- class  TransportTimeoutError  : public  llvm ::ErrorInfo<TransportTimeoutError> {
39+ class  TransportUnhandledContentsError 
40+     : public llvm::ErrorInfo<TransportUnhandledContentsError> {
4141public: 
4242  static  char  ID;
4343
44-   TransportTimeoutError () =  default ;
44+   explicit   TransportUnhandledContentsError (std::string unhandled_contents) ;
4545
46-   void  log (llvm::raw_ostream &OS) const  override  { 
47-     OS <<  " transport operation timed out "  ;
48-   } 
49-   std::error_code  convertToErrorCode () const   override  {
50-     return  std::make_error_code (std::errc::timed_out) ;
46+   void  log (llvm::raw_ostream &OS) const  override ; 
47+   std::error_code  convertToErrorCode ()  const   override ;
48+ 
49+   const   std::string & getUnhandledContents () const  {
50+     return  m_unhandled_contents ;
5151  }
52+ 
53+ private: 
54+   std::string m_unhandled_contents;
5255};
5356
5457class  TransportInvalidError  : public  llvm ::ErrorInfo<TransportInvalidError> {
@@ -57,17 +60,17 @@ class TransportInvalidError : public llvm::ErrorInfo<TransportInvalidError> {
5760
5861  TransportInvalidError () = default ;
5962
60-   void  log (llvm::raw_ostream &OS) const  override  {
61-     OS << " transport IO object invalid"  ;
62-   }
63-   std::error_code convertToErrorCode () const  override  {
64-     return  std::make_error_code (std::errc::not_connected);
65-   }
63+   void  log (llvm::raw_ostream &OS) const  override ;
64+   std::error_code convertToErrorCode () const  override ;
6665};
6766
6867// / A transport class that uses JSON for communication.
6968class  JSONTransport  {
7069public: 
70+   using  ReadHandleUP = MainLoopBase::ReadHandleUP;
71+   template  <typename  T>
72+   using  Callback = std::function<void (MainLoopBase &, const  llvm::Expected<T>)>;
73+ 
7174  JSONTransport (lldb::IOObjectSP input, lldb::IOObjectSP output);
7275  virtual  ~JSONTransport () = default ;
7376
@@ -83,24 +86,68 @@ class JSONTransport {
8386    return  WriteImpl (message);
8487  }
8588
86-   // / Reads  the next message from  the input stream .
89+   // / Registers  the transport with  the MainLoop .
8790  template  <typename  T>
88-   llvm::Expected<T> Read (const  std::chrono::microseconds &timeout) {
89-     llvm::Expected<std::string> message = ReadImpl (timeout);
90-     if  (!message)
91-       return  message.takeError ();
92-     return  llvm::json::parse<T>(/* JSON=*/  *message);
91+   llvm::Expected<ReadHandleUP> RegisterReadObject (MainLoopBase &loop,
92+                                                   Callback<T> read_cb) {
93+     Status error;
94+     ReadHandleUP handle = loop.RegisterReadObject (
95+         m_input,
96+         [read_cb, this ](MainLoopBase &loop) {
97+           char  buf[kReadBufferSize ];
98+           size_t  num_bytes = sizeof (buf);
99+           if  (llvm::Error error = m_input->Read (buf, num_bytes).takeError ()) {
100+             read_cb (loop, std::move (error));
101+             return ;
102+           }
103+           if  (num_bytes)
104+             m_buffer.append (std::string (buf, num_bytes));
105+ 
106+           //  If the buffer has contents, try parsing any pending messages.
107+           if  (!m_buffer.empty ()) {
108+             llvm::Expected<std::vector<std::string>> messages = Parse ();
109+             if  (llvm::Error error = messages.takeError ()) {
110+               read_cb (loop, std::move (error));
111+               return ;
112+             }
113+ 
114+             for  (const  auto  &message : *messages)
115+               if  constexpr  (std::is_same<T, std::string>::value)
116+                 read_cb (loop, message);
117+               else 
118+                 read_cb (loop, llvm::json::parse<T>(message));
119+           }
120+ 
121+           //  On EOF, notify the callback after the remaining messages were
122+           //  handled.
123+           if  (num_bytes == 0 ) {
124+             if  (m_buffer.empty ())
125+               read_cb (loop, llvm::make_error<TransportEOFError>());
126+             else 
127+               read_cb (loop, llvm::make_error<TransportUnhandledContentsError>(
128+                                 std::string (m_buffer)));
129+           }
130+         },
131+         error);
132+     if  (error.Fail ())
133+       return  error.takeError ();
134+     return  handle;
93135  }
94136
95137protected: 
138+   template  <typename ... Ts> inline  auto  Logv (const  char  *Fmt, Ts &&...Vals) {
139+     Log (llvm::formatv (Fmt, std::forward<Ts>(Vals)...).str ());
140+   }
96141  virtual  void  Log (llvm::StringRef message);
97142
98143  virtual  llvm::Error WriteImpl (const  std::string &message) = 0;
99-   virtual  llvm::Expected<std::string>
100-   ReadImpl (const  std::chrono::microseconds &timeout) = 0 ;
144+   virtual  llvm::Expected<std::vector<std::string>> Parse () = 0;
145+ 
146+   static  constexpr  size_t  kReadBufferSize  = 1024 ;
101147
102148  lldb::IOObjectSP m_input;
103149  lldb::IOObjectSP m_output;
150+   llvm::SmallString<kReadBufferSize > m_buffer;
104151};
105152
106153// / A transport class for JSON with a HTTP header.
@@ -111,14 +158,13 @@ class HTTPDelimitedJSONTransport : public JSONTransport {
111158  virtual  ~HTTPDelimitedJSONTransport () = default ;
112159
113160protected: 
114-   virtual  llvm::Error WriteImpl (const  std::string &message) override ;
115-   virtual  llvm::Expected<std::string>
116-   ReadImpl (const  std::chrono::microseconds &timeout) override ;
117- 
118-   //  FIXME: Support any header.
119-   static  constexpr  llvm::StringLiteral kHeaderContentLength  =
120-       " Content-Length: "  ;
121-   static  constexpr  llvm::StringLiteral kHeaderSeparator  = " \r\n\r\n "  ;
161+   llvm::Error WriteImpl (const  std::string &message) override ;
162+   llvm::Expected<std::vector<std::string>> Parse () override ;
163+ 
164+   static  constexpr  llvm::StringLiteral kHeaderContentLength  = " Content-Length"  ;
165+   static  constexpr  llvm::StringLiteral kHeaderFieldSeparator  = " :"  ;
166+   static  constexpr  llvm::StringLiteral kHeaderSeparator  = " \r\n "  ;
167+   static  constexpr  llvm::StringLiteral kEndOfHeader  = " \r\n\r\n "  ;
122168};
123169
124170// / A transport class for JSON RPC.
@@ -129,9 +175,8 @@ class JSONRPCTransport : public JSONTransport {
129175  virtual  ~JSONRPCTransport () = default ;
130176
131177protected: 
132-   virtual  llvm::Error WriteImpl (const  std::string &message) override ;
133-   virtual  llvm::Expected<std::string>
134-   ReadImpl (const  std::chrono::microseconds &timeout) override ;
178+   llvm::Error WriteImpl (const  std::string &message) override ;
179+   llvm::Expected<std::vector<std::string>> Parse () override ;
135180
136181  static  constexpr  llvm::StringLiteral kMessageSeparator  = " \n "  ;
137182};
0 commit comments