Kirk Haines
wyhaines@gmail.com
@wyhaines
Hack a POC product and pitch it.
The company might back it with resources to build it.
Build the tool that he always wanted when doing professional services and devops work
. . . . . . . . . . . . . .
I don't have any images of the original mockup.
(but it was pretty....)
Practical use case to keep in mind -- COVID-19 testing appliances that need monitoring of custom hardware, that require data gathering to be durable to intermittent internet connection failures, and that can facilitate remote management without providing full remote shell access.
Stable, with capacity for a phenomenal concurrent connection and messages/second rate. It's core capabilities had a lot of overlap with core capabilities needed by Minion.
Maybe it could be repurposed?
I started using it in April. I loved it. TL;DR:
I decided to translate Analogger, as that would give a huge head start to the project.
Austin was going to write the Agent, and he wanted to use Go, since he was learning it.
StreamServer worked, written in Crystal.
Agent lagged behind; writing it from scratch in Go just bogged down.
I had written an Agent skeleton in Crystal to use to test the StreamServer anyway.
So let's just use that!
No plan of operations reaches with any certainty beyond the first encounter with the enemy's main force. -- Helmuth von Multke
Everything Else was in Crystal, so Why Not?
But...how to implement it?
@blacksmoke16 was talking about Athena on the Crystal Gitter
I checked it out
Things I liked:
module MinionAPI
class AuthController < ART::Controller
@[ART::Get("/api/v1/auth/")]
def index : String
"TODO: Return appropriate top level response."
end
@[ART::QueryParam("email")]
@[ART::QueryParam("password")]
@[ART::Get("/api/v1/auth/signin")]
def signin(email : String = "", password : String = "") : ART::Response
signin_impl(email, password)
end
@[ART::Post("/api/v1/auth/signin")]
def signin(request : HTTP::Request) : ART::Response
raise ART::Exceptions::BadRequest.new "Missing request body." unless body = request.body
data = JSON.parse(body.gets_to_end)
handle_invalid_auth_credentials unless email = data["email"]?
handle_invalid_auth_credentials unless password = data["password"]?
signin_impl(email.not_nil!.as_s, password.not_nil!.as_s)
end
# REDACTED
end
end
(Athena Controller Snippet)
WITH RECURSIVE t AS ( (
SELECT data_key
FROM telemetries
WHERE server_id IN($1, $2, $3)
ORDER BY data_key
LIMIT 1
) UNION ALL
SELECT (
SELECT data_key
FROM telemetries
WHERE
data_key > t.data_key AND
server_id IN($1, $2, $3)
ORDER BY data_key
LIMIT 1
)
FROM t
WHERE t.data_key IS NOT NULL
)
SELECT data_key
FROM t
WHERE data_key IS NOT NULL;
https://github.com/wyhaines/splay_tree_map.cr
A Splay Tree is a binary search tree that balances in a way such that the most accessed nodes tend to be closer to the root. It can be useful in caches because this optimizes for the most accessed items being the fastest to access.
My version implements leaf pruning, which tends to remove the less commonly accessed data from the tree.
If you are interested, there are a lot of places where I could use help.