1 //===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ProgressEvent.h"
10 
11 #include "JSONUtils.h"
12 
13 using namespace lldb_vscode;
14 using namespace llvm;
15 
16 ProgressEvent::ProgressEvent(uint64_t progress_id, const char *message,
17                              uint64_t completed, uint64_t total)
18     : m_progress_id(progress_id), m_message(message) {
19   if (completed == total)
20     m_event_type = progressEnd;
21   else if (completed == 0)
22     m_event_type = progressStart;
23   else if (completed < total)
24     m_event_type = progressUpdate;
25   else
26     m_event_type = progressInvalid;
27 
28   if (0 < total && total < UINT64_MAX)
29     m_percentage = (uint32_t)(((float)completed / (float)total) * 100.0);
30 }
31 
32 bool ProgressEvent::operator==(const ProgressEvent &other) const {
33   return m_progress_id == other.m_progress_id &&
34          m_event_type == other.m_event_type &&
35          m_percentage == other.m_percentage;
36 }
37 
38 const char *ProgressEvent::GetEventName() const {
39   if (m_event_type == progressStart)
40     return "progressStart";
41   else if (m_event_type == progressEnd)
42     return "progressEnd";
43   else if (m_event_type == progressUpdate)
44     return "progressUpdate";
45   else
46     return "progressInvalid";
47 }
48 
49 bool ProgressEvent::IsValid() const { return m_event_type != progressInvalid; }
50 
51 uint64_t ProgressEvent::GetID() const { return m_progress_id; }
52 
53 json::Value ProgressEvent::ToJSON() const {
54   llvm::json::Object event(CreateEventObject(GetEventName()));
55   llvm::json::Object body;
56 
57   std::string progress_id_str;
58   llvm::raw_string_ostream progress_id_strm(progress_id_str);
59   progress_id_strm << m_progress_id;
60   progress_id_strm.flush();
61   body.try_emplace("progressId", progress_id_str);
62 
63   if (m_event_type == progressStart) {
64     EmplaceSafeString(body, "title", m_message);
65     body.try_emplace("cancellable", false);
66   }
67 
68   auto now = std::chrono::duration<double>(
69       std::chrono::system_clock::now().time_since_epoch());
70   std::string timestamp(llvm::formatv("{0:f9}", now.count()));
71   EmplaceSafeString(body, "timestamp", timestamp);
72 
73   if (m_percentage)
74     body.try_emplace("percentage", *m_percentage);
75 
76   event.try_emplace("body", std::move(body));
77   return json::Value(std::move(event));
78 }
79 
80 ProgressEventFilterQueue::ProgressEventFilterQueue(
81     std::function<void(ProgressEvent)> callback)
82     : m_callback(callback) {}
83 
84 void ProgressEventFilterQueue::Push(const ProgressEvent &event) {
85   if (!event.IsValid())
86     return;
87 
88   auto it = m_last_events.find(event.GetID());
89   if (it == m_last_events.end() || !(it->second == event)) {
90     m_last_events[event.GetID()] = event;
91     m_callback(event);
92   }
93 }
94