various updates (#263)
* various updates * fix glory shot * fix mi url for updating my blog * fix CI
This commit is contained in:
parent
089b14788d
commit
f643496416
|
@ -11,10 +11,11 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: cachix/install-nix-action@v6
|
||||
- uses: cachix/cachix-action@v3
|
||||
- uses: cachix/install-nix-action@v12
|
||||
- uses: cachix/cachix-action@v7
|
||||
with:
|
||||
name: xe
|
||||
- run: nix-build
|
||||
- name: Log into GitHub Container Registry
|
||||
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
- name: Docker push
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
---
|
||||
title: Various Updates
|
||||
date: 2020-11-18
|
||||
tags:
|
||||
- personal
|
||||
- consulting
|
||||
- docker
|
||||
- nixos
|
||||
---
|
||||
|
||||
# Various Updates
|
||||
|
||||
Immigration purgatory is an experience. It's got a lot of waiting and there is a
|
||||
lot of uncertainty that can make it feel stressful. Like I said
|
||||
[before](/blog/new-adventures-2020-10-24), I'm not concerned; however I have a
|
||||
lot of free time on my hands and I've been using it to make some plans for the
|
||||
blog (and a new offering for companies that need help dealing with the new
|
||||
[Docker Hub rate
|
||||
limits](https://docs.docker.com/docker-hub/download-rate-limit/)) in the future.
|
||||
I'm gonna outline them below in their own sections. This blogpost was originally
|
||||
about 4 separate blogposts that I started and abandoned because I had trouble
|
||||
focusing on finishing them. Stress sucks lol.
|
||||
|
||||
## WebMention Support
|
||||
|
||||
I recently deployed [mi v1.0.0](https://github.com/Xe/mi) to my home cluster. mi
|
||||
is a service that handles a lot of personal API tasks including the automatic
|
||||
post notifications to Twitter and Mastodon. The old implementation was in Go and
|
||||
stored its data in RethinkDB. I also have a snazzy frontend in Elm for mi. This
|
||||
new version is rewritten from scratch to use Rust, [Rocket](https://rocket.rs/)
|
||||
and SQLite. It is also fully
|
||||
[nixified](https://github.com/Xe/mi/blob/mara/default.nix) and is deployed to my
|
||||
home cluster via a [NixOS
|
||||
module](https://github.com/Xe/nixos-configs/blob/master/common/services/mi.nix).
|
||||
|
||||
One of the major new features I have in this rewrite is
|
||||
[WebMention](https://www.w3.org/TR/webmention/) support. WebMentions allow
|
||||
compatible websites to "mention" my articles or other pages on my main domains
|
||||
by sending a specially formatted HTTP request to mi. I am still in the early
|
||||
stages of integrating mi into my site code, but eventually I hope to have a list
|
||||
of places that articles are mentioned in each post. The WebMention endpoint for
|
||||
my site is `https://mi.within.website/api/webmention/accept`. I have added
|
||||
WebMention metadata into the HTML source of the blog pages as well as in the
|
||||
`Link` header as the W3 spec demands.
|
||||
|
||||
If you encounter any issues with this feature, please [let me know](/contact) so
|
||||
I can get it fixed as soon as possible.
|
||||
|
||||
### Thoughts on Elm as Used in mi
|
||||
|
||||
[Elm](https://elm-lang.org/) is an interesting language for making single page
|
||||
applications. The old version of mi was the first time I had really ever used
|
||||
Elm for anything serious and after some research I settled on using
|
||||
[elm-spa](https://www.elm-spa.dev/) as a framework to smooth over some of the
|
||||
weirder parts of the language. elm-spa worked great at first. All of the pages
|
||||
were separated out into their own components and the routing setup was really
|
||||
intuitive (if a bit weird because of the magic involved). It's worked great for
|
||||
a few years and has been very low maintenance.
|
||||
|
||||
However when I was starting to implement the backend of mi in Rust, I tried to
|
||||
nixify the elm-spa frontend I made. This was a disaster. The magic that elm-spa
|
||||
relied on fell apart and _at the time I attempted to do this_ it was very
|
||||
difficult to do this.
|
||||
|
||||
As a result I ended up rewriting the frontend in very very boring Elm using
|
||||
information from the [Elm Guide](https://guide.elm-lang.org/) and a lot of
|
||||
blogposts and help from the Elm slack. Overall this was a successful experiment
|
||||
and I can easily see this new frontend (which I have named sina as a compound
|
||||
[toki pona](https://tokipona.org/) pun) becoming a powerful tool for
|
||||
investigating and managing the data in mi.
|
||||
|
||||
[Special thanks to malinoff, wolfadex, chadtech and mfeineis on the Elm slack
|
||||
for helping with the weird issues involved in getting a split model approach
|
||||
working.](conversation://Mara/hacker)
|
||||
|
||||
Feel free to check out the code [here](https://github.com/Xe/mi/tree/mara/sina).
|
||||
I may try to make an Elm frontend to my site for people that use the Progressive
|
||||
Web App support.
|
||||
|
||||
### elm2nix
|
||||
|
||||
[elm2nix](https://github.com/cachix/elm2nix) is a very nice tool that lets you
|
||||
generate Nix definitions from Elm packages, however the
|
||||
template it uses is a bit out of date. To fix it you need to do the following:
|
||||
|
||||
```console
|
||||
$ elm2nix init > default.nix
|
||||
$ elm2nix convert > elm-srcs.nix
|
||||
$ elm2nix snapshot
|
||||
```
|
||||
|
||||
Then open `default.nix` in your favorite text editor and change this:
|
||||
|
||||
```nix
|
||||
buildInputs = [ elmPackages.elm ]
|
||||
++ lib.optional outputJavaScript nodePackages_10_x.uglify-js;
|
||||
```
|
||||
|
||||
to this:
|
||||
|
||||
```nix
|
||||
buildInputs = [ elmPackages.elm ]
|
||||
++ lib.optional outputJavaScript nodePackages.uglify-js;
|
||||
```
|
||||
|
||||
and this:
|
||||
|
||||
```nix
|
||||
uglifyjs $out/${module}.${extension} --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' \
|
||||
| uglifyjs --mangle --output=$out/${module}.min.${extension}
|
||||
```
|
||||
|
||||
to this:
|
||||
|
||||
```nix
|
||||
uglifyjs $out/${module}.${extension} --compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' \
|
||||
| uglifyjs --mangle --output $out/${module}.min.${extension}
|
||||
```
|
||||
|
||||
These issues should be fixed in the next release of elm2nix.
|
||||
|
||||
## New Character in the Blog Cutouts
|
||||
|
||||
As I mentioned [in the past](/blog/how-mara-works-2020-09-30), I am looking into
|
||||
developing out other characters for my blog. I am still in the early stages of
|
||||
designing this, but I think the next character in my blog is going to be an
|
||||
anthro snow leopard named Alicia. I want Alicia to be a beginner that is very
|
||||
new to computer programming and other topics, which would then make Mara into
|
||||
more of a teacher type. I may also introduce my own OC Cadey (the orca looking
|
||||
thing you can see [here](https://christine.website/static/img/avatar_large.png)
|
||||
or in the favicon of my site) into the mix to reply to these questions in
|
||||
something more close to the Socratic method.
|
||||
|
||||
Some people have joked that the introduction of Mara turned my blog into a shark
|
||||
visual novel that teaches you things. This sounds hilarious to me, and I am
|
||||
looking into what it would take to make an actual visual novel on a page on my
|
||||
blog using Rust and WebAssembly. I am in very early planning stages for this, so
|
||||
don't expect this to come out any time soon.
|
||||
|
||||
## Gergoplex Build
|
||||
|
||||
My [Gergoplex kit](https://www.gboards.ca/product/gergoplex) finally came in
|
||||
yesterday, and I got to work soldering it up with some switches and applying the
|
||||
keycaps.
|
||||
|
||||
![Me soldering the Gergoplex](https://cdn.christine.website/file/christine-static/img/keeb/gergoplex/EnEYNxvW4AEfWcH.jpg)
|
||||
|
||||
![A glory shot of the Gergoplex](https://cdn.christine.website/file/christine-static/img/keeb/gergoplex/Elm3dN8XUAAYHws.jpg)
|
||||
|
||||
I picked the Pro Red linear switches with a 35 gram spring in them (read: they
|
||||
need 35 grams of force to actuate, which is lighter than most switches) and
|
||||
typing on it is buttery smooth. The keycaps are a boring black, but they look
|
||||
nice on it.
|
||||
|
||||
Overall this kit (with the partial board, switches and keycaps) cost me about
|
||||
US$124 (not including shipping) with the costs looking something like this:
|
||||
|
||||
| Name | Count | Cost |
|
||||
| :------------------------- | :----- | :---- |
|
||||
| Gergoplex Partial Kit | 1 | $70 |
|
||||
| Choc Pro Red 35g switches | 4 | $10 |
|
||||
| Keycaps (15) | 3 | $30 |
|
||||
| Braided interconnect cable | 1 | $7 |
|
||||
| Mini-USB cable | 1 | $7 |
|
||||
|
||||
I'd say this was a worthwhile experience. I haven't really soldered anything
|
||||
since I was in high school and it was fun to pick up the iron again and make
|
||||
something useful. If you are looking for a beginner soldering project, I can't
|
||||
recommend the Gergoplex enough.
|
||||
|
||||
I also picked up some extra switches and keycaps (prices not listed here) for a
|
||||
future project involving an eInk display. More on that when it is time.
|
||||
|
||||
## Branch Conventions
|
||||
|
||||
You may have noticed that some of my projects have default branches named `main`
|
||||
and others have default branches named `mara`. This difference is very
|
||||
intentional. Repos with the default branch `main` generally contain code that is
|
||||
"stable" and contains robust and reusable code. Repos with the default branch
|
||||
`mara` are generally my experimental repos and the code in them may not be the
|
||||
most reusable across other projects. mi is a repo with a `mara` default branch
|
||||
because it is a very experimental thing. In the future I may promote it up to
|
||||
having a `main` branch, however for now it's less effort to keep things the way
|
||||
it is.
|
||||
|
||||
## Docker Consulting
|
||||
|
||||
The new [Docker Hub rate
|
||||
limits](https://docs.docker.com/docker-hub/download-rate-limit/) have thrown a
|
||||
wrench into many CI/CD setups as well as uncertainty in how CI services will
|
||||
handle this. Many build pipelines implictly trust the Docker Hub to be up and
|
||||
that it will serve the appropriate image so that your build can work. Many
|
||||
organizations use their own Docker registry (GHCR, AWS/Google Cloud image
|
||||
registries, Artifactory, etc.), however most image build definitions I've seen
|
||||
start out with something like this:
|
||||
|
||||
```Dockerfile
|
||||
FROM golang:alpine
|
||||
```
|
||||
|
||||
which will implicitly pull from the Docker Hub. This can lead to bad things.
|
||||
|
||||
If you would like to have a call with me for examining your process for building
|
||||
Docker images in CI and get a list of actionable suggestions for how to work
|
||||
around this, [contact me](/contact) so that we can discuss pricing and
|
||||
scheduling.
|
||||
|
||||
I have been using Docker for my entire professional career (way back since
|
||||
Docker required you to recompile your kernel to enable cgroup support in public
|
||||
beta) and I can also discuss methods to make your Docker images as small as they
|
||||
can possibly get. My record smallest Docker image is 5 MB.
|
||||
|
||||
If either of these prospects interest you, please contact me so we can work
|
||||
something out.
|
||||
|
||||
---
|
||||
|
||||
Here's hoping that the immigration purgatory ends soon. I'm lucky enough to have
|
||||
enough cash built up that I can weather this jobless month. I've been using this
|
||||
time to work on personal projects (like mi and
|
||||
[wasmcloud](https://wasmcloud.app)) and better myself. I've also done a little
|
||||
writing that I plan to release in the future after I clean it up.
|
||||
|
||||
In retrospect I probably should have done [NaNoWriMo](https://nanowrimo.org/)
|
||||
seeing that I basically will have the entire month of November jobless. I've had
|
||||
an idea for a while about someone that goes down the rabbit hole of mysticism
|
||||
and magick, but I may end up incorporating that into the visual novel project I
|
||||
mentioned in the Elm section.
|
||||
|
||||
Be well and stay safe out there. Wear a mask, stay at home.
|
18
config.dhall
18
config.dhall
|
@ -1,24 +1,30 @@
|
|||
let Person =
|
||||
{ Type = { name : Text, tags : List Text, gitLink : Text, twitter : Text }
|
||||
, default =
|
||||
{ name = "", tags = [] : List Text, gitLink = "", twitter = "" }
|
||||
{ name = "", tags = [] : List Text, gitLink = "", twitter = "" }
|
||||
}
|
||||
|
||||
let defaultPort = env:PORT ? 3030
|
||||
|
||||
let defaultWebMentionEndpoint =
|
||||
env:WEBMENTION_ENDPOINT
|
||||
? "https://mi.within.website/api/webmention/accept"
|
||||
|
||||
let Config =
|
||||
{ Type =
|
||||
{ signalboost : List Person.Type
|
||||
, port : Natural
|
||||
, clackSet : List Text
|
||||
, resumeFname : Text
|
||||
, webMentionEndpoint : Text
|
||||
}
|
||||
, default =
|
||||
{ signalboost = [] : List Person.Type
|
||||
, port = defaultPort
|
||||
, clackSet = [ "Ashlynn" ]
|
||||
, resumeFname = "./static/resume/resume.md"
|
||||
}
|
||||
{ signalboost = [] : List Person.Type
|
||||
, port = defaultPort
|
||||
, clackSet = [ "Ashlynn" ]
|
||||
, resumeFname = "./static/resume/resume.md"
|
||||
, webMentionEndpoint = defaultWebMentionEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
in Config::{
|
||||
|
|
|
@ -7,4 +7,4 @@ kubectl rollout status -n apps deployment/christinewebsite
|
|||
kubectl apply -f ./k8s/job.yml
|
||||
sleep 10
|
||||
kubectl delete -f ./k8s/job.yml
|
||||
curl --http1.1 -H "Authorization: $MI_TOKEN" --data "https://christine.website/blog.json" https://mi.within.website/blog/refresh
|
||||
curl --http1.1 -H "Authorization: $MI_TOKEN" https://mi.within.website/api/blog/refresh
|
||||
|
|
|
@ -2,24 +2,28 @@ use crate::{post::Post, signalboost::Person};
|
|||
use color_eyre::eyre::Result;
|
||||
use serde::Deserialize;
|
||||
use std::{fs, path::PathBuf};
|
||||
use tracing::{instrument, error};
|
||||
use tracing::{error, instrument};
|
||||
|
||||
pub mod markdown;
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(rename = "clackSet")]
|
||||
clack_set: Vec<String>,
|
||||
signalboost: Vec<Person>,
|
||||
port: u16,
|
||||
pub(crate) clack_set: Vec<String>,
|
||||
pub(crate) signalboost: Vec<Person>,
|
||||
pub(crate) port: u16,
|
||||
#[serde(rename = "resumeFname")]
|
||||
resume_fname: PathBuf,
|
||||
pub(crate) resume_fname: PathBuf,
|
||||
#[serde(rename = "webMentionEndpoint")]
|
||||
pub(crate) webmention_url: String,
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
async fn patrons() -> Result<Option<patreon::Users>> {
|
||||
use patreon::*;
|
||||
let creds: Credentials = envy::prefixed("PATREON_").from_env().unwrap_or(Credentials::default());
|
||||
let creds: Credentials = envy::prefixed("PATREON_")
|
||||
.from_env()
|
||||
.unwrap_or(Credentials::default());
|
||||
let cli = Client::new(creds);
|
||||
|
||||
match cli.campaign().await {
|
||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -26,12 +26,15 @@ async fn main() -> Result<()> {
|
|||
tracing_subscriber::fmt::init();
|
||||
log::info!("starting up commit {}", env!("GITHUB_SHA"));
|
||||
|
||||
let state = Arc::new(app::init(
|
||||
std::env::var("CONFIG_FNAME")
|
||||
.unwrap_or("./config.dhall".into())
|
||||
.as_str()
|
||||
.into(),
|
||||
).await?);
|
||||
let state = Arc::new(
|
||||
app::init(
|
||||
std::env::var("CONFIG_FNAME")
|
||||
.unwrap_or("./config.dhall".into())
|
||||
.as_str()
|
||||
.into(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));
|
||||
|
||||
|
@ -144,6 +147,17 @@ async fn main() -> Result<()> {
|
|||
)
|
||||
})
|
||||
.map(|reply| warp::reply::with_header(reply, "X-Clacks-Overhead", "GNU Ashlynn"))
|
||||
.map(|reply| {
|
||||
warp::reply::with_header(
|
||||
reply,
|
||||
"Link",
|
||||
format!(
|
||||
r#"<{}>; rel="webmention""#,
|
||||
std::env::var("WEBMENTION_URL")
|
||||
.unwrap_or("https://mi.within.website/api/webmention/accept".to_string())
|
||||
),
|
||||
)
|
||||
})
|
||||
.with(warp::log(APPLICATION_NAME))
|
||||
.recover(handlers::rejection);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<link rel="apple-touch-icon" sizes="144x144" href="/static/favicon/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/static/favicon/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/static/favicon/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/static/favicon/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/static/favicon/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/static/favicon/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon/favicon-16x16.png">
|
||||
|
@ -38,6 +38,7 @@
|
|||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="/static/favicon/ms-icon-144x144.png">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<link href="https://mi.within.website/api/webmention/accept" rel="webmention" />
|
||||
@if styles.is_some() {
|
||||
<style>
|
||||
@styles.unwrap()
|
||||
|
|
Loading…
Reference in New Issue