Created
September 23, 2018 13:42
-
-
Save luciusmagn/fa8a5673d9eaa872fd570fa14094cb6c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# --- This file was borrowed from Picheta's nimble package manager | |
# --- Modifications: now it is kinda thread-safe, removal of testing output | |
# Copyright (C) Dominik Picheta. All rights reserved. | |
# BSD License. Look at license.txt for more info. | |
# | |
# Rough rules/philosophy for the messages that Nimble displays are the following: | |
# - Green is only shown when the requested operation is successful. | |
# - Blue can be used to emphasise certain keywords, for example actions such | |
# as "Downloading" or "Reading". | |
# - Red is used when the requested operation fails with an error. | |
# - Yellow is used for warnings. | |
# | |
# - Dim for LowPriority. | |
# - Bright for HighPriority. | |
# - Normal for MediumPriority. | |
import logging, terminal, sets, strutils | |
type | |
CLI* = ref object | |
level: Priority | |
warnings: HashSet[(string, string)] | |
suppressionCount: int ## Amount of messages which were not shown. | |
showColor: bool ## Whether messages should be colored. | |
suppressMessages: bool ## Whether Warning, Message and Success messages | |
## should be suppressed, useful for | |
## commands like `dump` whose output should be | |
## machine readable. | |
Priority* = enum | |
DebugPriority, LowPriority, MediumPriority, HighPriority | |
DisplayType* = enum | |
Error, Warning, Message, Success | |
ForcePrompt* = enum | |
dontForcePrompt, forcePromptYes, forcePromptNo | |
const | |
longestCategory = len("Downloading") | |
foregrounds: array[Error .. Success, ForegroundColor] = | |
[fgRed, fgYellow, fgCyan, fgGreen] | |
styles: array[DebugPriority .. HighPriority, set[Style]] = | |
[{styleDim}, {styleDim}, {}, {styleBright}] | |
proc newCLI(): CLI = | |
result = CLI( | |
level: LowPriority, | |
suppressionCount: 0, | |
showColor: true, | |
suppressMessages: false | |
) | |
var threadCLI {.threadvar.}: CLI | |
proc maybe_init_cli() = | |
if threadCLI == nil: | |
threadCLI = newCLI(); | |
proc calculateCategoryOffset(category: string): int = | |
assert category.len <= longestCategory | |
return longestCategory - category.len | |
proc displayCategory(category: string, displayType: DisplayType, | |
priority: Priority) = | |
maybe_init_cli() | |
# Calculate how much the `category` must be offset to align along a center | |
# line. | |
let offset = calculateCategoryOffset(category) | |
# Display the category. | |
let text = "$1$2 " % [spaces(offset), category] | |
if threadCLI.showColor: | |
if priority != DebugPriority: | |
setForegroundColor(stdout, foregrounds[displayType]) | |
writeStyled(text, styles[priority]) | |
resetAttributes() | |
else: | |
stdout.write(text) | |
proc displayLine(category, line: string, displayType: DisplayType, | |
priority: Priority) = | |
displayCategory(category, displayType, priority) | |
# Display the message. | |
writeStyled(line & "\n", styles[priority]) | |
proc display*(category, msg: string, displayType = Message, | |
priority = MediumPriority) {.gcsafe.} = | |
maybe_init_cli() | |
# Don't print any Warning, Message or Success messages when suppression of | |
# warnings is enabled. That is, unless the user asked for --verbose output. | |
if threadCLI.suppressMessages and displayType >= Warning and | |
threadCLI.level == HighPriority: | |
return | |
# Suppress this message if its priority isn't high enough. | |
if priority < threadCLI.level: | |
if priority != DebugPriority: | |
threadCLI.suppressionCount.inc | |
return | |
# Display each line in the message. | |
var i = 0 | |
for line in msg.splitLines(): | |
if len(line) == 0: continue | |
displayLine(if i == 0: category else: "...", line, displayType, priority) | |
i.inc | |
proc displayDebug*(category, msg: string) = | |
## Convenience for displaying debug messages. | |
display(category, msg, priority = DebugPriority) | |
proc displayDebug*(msg: string) = | |
## Convenience for displaying debug messages with a default category. | |
displayDebug("Debug:", msg) | |
proc displayTip*() = | |
maybe_init_cli() | |
## Called just before Nimble exits. Shows some tips for the user, for example | |
## the amount of messages that were suppressed and how to show them. | |
if threadCLI.suppressionCount > 0: | |
let msg = "$1 messages have been suppressed, use --verbose to show them." % | |
$threadCLI.suppressionCount | |
display("Tip:", msg, Warning, HighPriority) | |
proc prompt*(forcePrompts: ForcePrompt, question: string): bool = | |
case forcePrompts | |
of forcePromptYes: | |
display("Prompt:", question & " -> [forced yes]", Warning, HighPriority) | |
return true | |
of forcePromptNo: | |
display("Prompt:", question & " -> [forced no]", Warning, HighPriority) | |
return false | |
of dontForcePrompt: | |
display("Prompt:", question & " [y/N]", Warning, HighPriority) | |
displayCategory("Answer:", Warning, HighPriority) | |
let yn = stdin.readLine() | |
case yn.normalize | |
of "y", "yes": | |
return true | |
of "n", "no": | |
return false | |
else: | |
return false | |
proc promptCustom*(forcePrompts: ForcePrompt, question, default: string): string = | |
case forcePrompts: | |
of forcePromptYes: | |
display("Prompt:", question & " -> [forced " & default & "]", Warning, | |
HighPriority) | |
return default | |
else: | |
if default == "": | |
display("Prompt:", question, Warning, HighPriority) | |
displayCategory("Answer:", Warning, HighPriority) | |
let user = stdin.readLine() | |
if user.len == 0: return promptCustom(forcePrompts, question, default) | |
else: return user | |
else: | |
display("Prompt:", question & " [" & default & "]", Warning, HighPriority) | |
displayCategory("Answer:", Warning, HighPriority) | |
let user = stdin.readLine() | |
if user == "": return default | |
else: return user | |
proc promptCustom*(question, default: string): string = | |
return promptCustom(dontForcePrompt, question, default) | |
proc promptList*(forcePrompts: ForcePrompt, question: string, args: openarray[string]): string = | |
case forcePrompts: | |
of forcePromptYes: | |
result = args[0] | |
display("Prompt:", question & " -> [forced " & result & "]", Warning, | |
HighPriority) | |
else: | |
display("Prompt:", question & " [" & join(args, "/") & "]", Warning, HighPriority) | |
displayCategory("Answer:", Warning, HighPriority) | |
result = stdin.readLine() | |
for arg in args: | |
if arg.cmpIgnoreCase(result) == 0: | |
return arg | |
return promptList(forcePrompts, question, args) | |
proc setVerbosity*(level: Priority) = | |
threadCLI.level = level | |
proc setShowColor*(val: bool) = | |
threadCLI.showColor = val | |
proc setSuppressMessages*(val: bool) = | |
threadCLI.suppressMessages = val |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import | |
asyncdispatch, | |
asyncfile, | |
db_postgres, | |
times, | |
strutils, | |
sequtils, | |
threadpool, | |
posix, | |
cli, | |
os | |
let file = open("remedias.log"); | |
proc to_priority(s: string): Priority = | |
case s | |
of "LOW": LowPriority | |
of "MED": MediumPriority | |
of "HGH": HighPriority | |
else: LowPriority | |
proc eliminate_tokens() {.async.} = | |
while true: | |
if now().hour == 4 and now().hour == 0 and now().second == 0 and not file_exists(".db-lock"): | |
discard open(".db-lock", fmWrite) | |
echo "eliminating" | |
let | |
db = open("localhost", "db", "test", "Meedias") | |
rows = db.get_all_rows(sql"SELECT id, valid_tokens FROM users"); | |
for row in rows: | |
let id = row[0]; | |
let tokens = row[1] | |
.replace("{", "") | |
.replace("}", "") | |
.split(','); | |
let res = | |
if tokens.len() > 1: | |
'{' & tokens[1..<tokens.len()].foldl(a & ',' & b) & '}' | |
else: | |
"{}" | |
db.exec(sql"UPDATE users SET valid_tokens=? WHERE id=?", res, id); | |
display("daemon", "eliminated tokens") | |
db.close(); | |
sleep 1000 | |
discard unlink(".db-lock") | |
sleep 23 * 3600 * 1000; | |
proc logger() {.async.} = | |
while true: | |
try: | |
echo "reading"; | |
let line = file.read_line(); | |
let words = line.split(' '); | |
case words[0] | |
of "REQ": | |
display("Request", words[1..<words.len()].join(" "), Success, HighPriority) | |
of "INF": | |
display("Info", words[2..<words.len()].join(" "), Message, words[1].to_priority()) | |
of "ERR": | |
display("Error", words[2..<words.len()].join(" "), Error, words[1].to_priority()) | |
of "WRN": | |
display("Warning", words[2..<words.len()].join(" "), Warning, words[1].to_priority()) | |
of "FTL": | |
display("Fatal", words[2..<words.len()].join(" "), Error, words[1].to_priority()) | |
except: | |
sleep 300 | |
if prompt(dont_force_prompt, "start daemon?"): | |
display("daemon", "eliminating tokens at 4 AM", Success, HighPriority); | |
discard spawn eliminate_tokens(); | |
waitfor logger(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment