• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / PreCore / 550

29 Sep 2024 09:19AM UTC coverage: 53.22%. First build
550

push

github

PredatorCZ
implement NO_SIGNAL env and better signal report

0 of 18 new or added lines in 1 file covered. (0.0%)

4240 of 7967 relevant lines covered (53.22%)

10417.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

9.65
/src/cli/console.cpp
1
/*  Spike is universal dedicated module handler
2

3
    Copyright 2021-2023 Lukas Cone
4

5
    Licensed under the Apache License, Version 2.0 (the "License");
6
    you may not use this file except in compliance with the License.
7
    You may obtain a copy of the License at
8

9
        http://www.apache.org/licenses/LICENSE-2.0
10

11
    Unless required by applicable law or agreed to in writing, software
12
    distributed under the License is distributed on an "AS IS" BASIS,
13
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
    See the License for the specific language governing permissions and
15
    limitations under the License.
16
*/
17

18
#include "spike/app/console.hpp"
19
#include "spike/master_printer.hpp"
20
#include "spike/type/tchar.hpp"
21
#include <algorithm>
22
#include <csignal>
23
#include <mutex>
24
#include <thread>
25
#include <vector>
26

27
const size_t nextTickMS = 100;
28

29
const char8_t *loopchars[] = {
30
    u8"\u2807", u8"\u280B", u8"\u2819", u8"\u2838", u8"\u2834", u8"\u2826",
31
};
32

33
const char8_t *barchars[] = {
34
    u8"\u2801", u8"\u2803", u8"\u2807", u8"\u2847",
35
    u8"\u284F", u8"\u285F", u8"\u287F", u8"\u28FF",
36
};
37

38
void ProgressBar::PrintLine() {
×
39
  const size_t width = 50;
40
  const float normState = std::min(curitem * itemDelta, 1.f);
×
41
  const size_t state = normState * width;
×
42
  es::Print(label.data());
43
  es::Print("\033[38;2;168;204;140m");
44

45
  for (size_t i = 0; i < state; i++) {
×
46
#ifdef USEWIN
47
    es::Print("#");
48
#else
49
    es::Print(u8"\u25A0");
50
#endif
51
  }
52

53
  for (size_t i = state; i < width; i++) {
×
54
    es::Print(" ");
55
  }
56

57
  char percBuffer[16]{};
×
58
  snprintf(percBuffer, sizeof(percBuffer), "\033[0m %3u%% ",
×
59
           uint32(normState * 100));
×
60
  es::Print(percBuffer);
61
}
62

63
void DetailedProgressBar::PrintLine() {
×
64
  const size_t goal = curitem;
65
  const size_t width = 50;
66
  const size_t parts = 8;
67
  const float normStateGoal = std::min(goal * itemDelta, 1.f);
×
68
  float normState = normStateGoal;
69

70
  if (lastItem < normStateGoal) {
×
71
    lastItem += (normStateGoal - lastItem) / 5;
×
72
    normState = lastItem;
73
  } else {
74
    lastItem = normStateGoal;
×
75
  }
76

77
  const size_t stateMacro = normState * width;
×
78
  const size_t state = size_t(normState * width * parts) % parts;
×
79

80
  es::Print(label.data());
81
  es::Print("\033[38;2;168;204;140m");
82

83
  for (size_t i = 0; i < stateMacro; i++) {
×
84
    es::Print(barchars[7]);
×
85
  }
86

87
  if (state) {
×
88
    es::Print(barchars[state]);
×
89
  }
90

91
  for (size_t i = stateMacro + bool(state); i < width; i++) {
×
92
    es::Print(" ");
93
  }
94

95
  char percBuffer[16]{};
×
96
  snprintf(percBuffer, sizeof(percBuffer), "\033[0m %3u%% ",
×
97
           uint32(normState * 100));
×
98
  es::Print(percBuffer);
99
}
100

101
void LoadingBar::PrintLine() {
×
102
  if (!state) {
×
103
    const size_t loopTick = (innerTick / 100) % 6;
×
104
    es::Print(loopchars[loopTick]);
×
105
    es::Print(" ");
106
  } else if (state == 1) {
×
107
    es::Print(u8"\033[38;2;168;220;140m\u2714 \033[0m");
108
  } else {
109
    es::Print(u8"\u274C ");
110
  }
111

112
  es::Print(payload.data());
113
  innerTick += nextTickMS;
×
114
}
115

116
struct LineMsg {
3✔
117
  std::unique_ptr<LogLine> newLine;
118
  LogLine *line = nullptr;
119
  bool after = false;
120

121
  LineMsg(std::unique_ptr<LogLine> &&item) : newLine(std::move(item)) {}
1✔
122
  LineMsg(std::unique_ptr<LogLine> &&item, LogLine *point, bool after_)
123
      : newLine(std::move(item)), line(point), after(after_) {}
×
124
  LineMsg(LogLine *point) : line(point) {}
1✔
125
  LineMsg(LogLine *point, bool release) : line(point), after(release) {}
×
126
};
127

128
static std::vector<es::print::Queuer> messageQueues[2];
129
static std::vector<std::unique_ptr<LogLine>> lineStack;
130
static std::vector<LineMsg> lineQueue[2];
131
static std::atomic_bool currentlyUsedMessageQueue;
132
static std::atomic_bool currentlyUsedLineQueue;
133
static std::atomic_bool stopLogger;
134
static std::atomic_bool eraseAllLines;
135
static std::thread logger;
136
static std::atomic_uint8_t printDetail{0};
137
static std::atomic_uint64_t newPrintDetailSince{0};
138

139
void ReceiveQueue(const es::print::Queuer &que) {
×
140
  messageQueues[currentlyUsedMessageQueue].push_back(que);
×
141
}
142

143
void MakeLogger() {
×
144
  size_t innerTick = 0;
145
  currentlyUsedMessageQueue = false;
146
  currentlyUsedLineQueue = false;
147
  bool mustClear = false;
148

149
  while (!stopLogger) {
×
150
    if (mustClear) {
×
151
      es::Print("\033[J");
152
      mustClear = false;
153
    }
154

155
    if (bool mqo = currentlyUsedMessageQueue; !messageQueues[mqo].empty()) {
×
156
      currentlyUsedMessageQueue = !mqo;
×
157
      uint8 fullDetail = printDetail;
158
      uint64 newDetailSince = newPrintDetailSince.exchange(0);
159
      size_t curQue = 0;
160

161
      for (auto &l : messageQueues[mqo]) {
×
162
        uint8 detail = newDetailSince <= curQue ? fullDetail : fullDetail >> 4;
×
163
        bool colored = detail & 1;
164
        if (colored) {
×
165
          using es::print::MPType;
166
          switch (l.type) {
×
167
          case MPType::ERR:
168
            es::Print(u8"\033[38;2;255;50;50m\u26D4 ");
169
            break;
170
          case MPType::INF:
171
            es::Print(u8"\033[38;2;50;120;255m \u2139 ");
172
            break;
173
          case MPType::WRN:
174
            es::Print(u8"\033[38;2;255;255;50m\u26A0  ");
175
            break;
176
          default:
177
            es::Print(u8"\033[0m   ");
178
            colored = false;
179
            break;
180
          }
181
        }
182

183
        if (detail & 2) {
×
184
          char threadBuffer[16]{};
×
185
          snprintf(threadBuffer, sizeof(threadBuffer), "[0x%.8X] ", l.threadId);
×
186
          es::Print(threadBuffer);
187
        }
188

189
        es::Print(l.payload.data());
190

191
        if (colored) {
×
192
          es::Print(u8"\033[0m");
193
        }
194

195
        curQue++;
×
196
      }
197

198
      messageQueues[mqo].clear();
199
    }
200

201
    if (eraseAllLines) {
×
202
      lineQueue[0].clear();
203
      lineQueue[1].clear();
204
      lineStack.clear();
205
      eraseAllLines = false;
206
    }
207

208
    if (bool lqo = currentlyUsedLineQueue; !lineQueue[lqo].empty()) {
×
209
      currentlyUsedLineQueue = !lqo;
×
210

211
      for (auto &l : lineQueue[lqo]) {
×
212
        if (l.line) {
×
213
          if (l.newLine) {
×
214
            auto found = std::find_if(
×
215
                lineStack.begin(), lineStack.end(),
216
                [&](auto &item_) { return item_.get() == l.line; });
×
217
            lineStack.insert(std::next(found, l.after), std::move(l.newLine));
×
218
          } else {
219
            if (l.after) {
×
220
              l.line->PrintLine();
×
221
              es::Print("\n");
222
            }
223

224
            lineStack.erase(std::find_if(
×
225
                lineStack.begin(), lineStack.end(),
226
                [&](auto &item_) { return item_.get() == l.line; }));
×
227
          }
228
        } else {
229
          lineStack.emplace_back(std::move(l.newLine));
×
230
        }
231
      }
232

233
      lineQueue[lqo].clear();
234
    }
235

236
    for (auto &l : lineStack) {
×
237
      l->PrintLine();
×
238
      es::Print("\n");
239
    }
240

241
    for (size_t i = 0; i < lineStack.size(); i++) {
×
242
      es::Print("\033[A");
243
    }
244

245
    mustClear = true;
246

247
    std::this_thread::sleep_for(std::chrono::milliseconds(nextTickMS));
×
248
    innerTick += nextTickMS;
249
  }
250
}
251

252
void TerminateConsoleDontWait() {
×
253
  eraseAllLines = true;
254
  stopLogger = true;
255
  if (logger.joinable()) {
×
256
    logger.join();
×
257
  }
258

259
  es::Print("\033[?25h"); // Enable cursor
260
}
261

NEW
262
const char *SignalName(int sig) {
×
NEW
263
  switch (sig) {
×
264
  case SIGTERM:
265
    return "(SIGTERM)";
NEW
266
  case SIGABRT:
×
NEW
267
    return "(SIGABRT)";
×
NEW
268
  case SIGINT:
×
NEW
269
    return "(SIGINT) ";
×
NEW
270
  case SIGSEGV:
×
NEW
271
    return "(SIGSEGV)";
×
272
#ifdef SIGBUS
NEW
273
  case SIGBUS:
×
NEW
274
    return "(SIGBUS) ";
×
275
#endif
NEW
276
  default:
×
NEW
277
    return "         ";
×
278
  }
279
}
280

281
void InitConsole() {
×
282
  es::Print("\033[?25l"); // Disable cursor
283
  es::print::AddQueuer(ReceiveQueue);
×
284
  logger = std::thread{MakeLogger};
×
285
  pthread_setname_np(logger.native_handle(), "console_logger");
×
286
  auto terminate = [](int sig) {
×
287
    TerminateConsoleDontWait();
×
288
    printf("+----------------------------------------------------------+\n");
289
    printf("| APPLICATION HAVE CLOSED UNEXPECTEDLY, CODE: %.2i %s |\n", sig,
290
           SignalName(sig));
291
    printf("+----------------------------------------------------------+\n");
292
    std::exit(sig);
×
293
  };
294

NEW
295
  if (!getenv("NO_SIGNAL")) {
×
NEW
296
    std::signal(SIGTERM, terminate);
×
NEW
297
    std::signal(SIGABRT, terminate);
×
NEW
298
    std::signal(SIGINT, terminate);
×
NEW
299
    std::signal(SIGSEGV, terminate);
×
300
#ifdef SIGBUS
NEW
301
    std::signal(SIGBUS, terminate);
×
302
#endif
303
  }
304
}
305

306
void TerminateConsole() {
×
307
  while (!messageQueues[0].empty() && !messageQueues[1].empty()) {
308
  }
309

310
  TerminateConsoleDontWait();
×
311
}
312

313
void ConsolePrintDetail(uint8 detail) {
×
314
  newPrintDetailSince = messageQueues[currentlyUsedMessageQueue].size();
×
315
  uint8 oldDetail = printDetail;
316
  printDetail = detail | oldDetail << 4;
×
317
}
318

319
void ElementAPI::Append(std::unique_ptr<LogLine> &&item) {
1✔
320
  lineQueue[currentlyUsedLineQueue].emplace_back(std::move(item));
1✔
321
}
1✔
322

323
void ElementAPI::Remove(LogLine *item) {
1✔
324
  lineQueue[currentlyUsedLineQueue].emplace_back(item);
1✔
325
}
1✔
326

327
void ElementAPI::Release(LogLine *line) {
×
328
  lineQueue[currentlyUsedLineQueue].emplace_back(line, true);
×
329
}
330

331
void ElementAPI::Clean() { eraseAllLines = true; }
×
332

333
void ElementAPI::Insert(std::unique_ptr<LogLine> &&item, LogLine *where,
×
334
                        bool after) {
335
  lineQueue[currentlyUsedLineQueue].emplace_back(std::move(item), where, after);
×
336
}
337

338
void ModifyElements_(element_callback cb) {
2✔
339
  static std::mutex accessMutex;
340
  std::lock_guard lg(accessMutex);
341
  static ElementAPI EAPI;
342
  cb(EAPI);
343
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc