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
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- uses: cachix/install-nix-action@v6
|
- uses: cachix/install-nix-action@v12
|
||||||
- uses: cachix/cachix-action@v3
|
- uses: cachix/cachix-action@v7
|
||||||
with:
|
with:
|
||||||
name: xe
|
name: xe
|
||||||
|
- run: nix-build
|
||||||
- name: Log into GitHub Container Registry
|
- name: Log into GitHub Container Registry
|
||||||
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
|
run: echo "${{ secrets.CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
- name: Docker push
|
- 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.
|
|
@ -6,18 +6,24 @@ let Person =
|
||||||
|
|
||||||
let defaultPort = env:PORT ? 3030
|
let defaultPort = env:PORT ? 3030
|
||||||
|
|
||||||
|
let defaultWebMentionEndpoint =
|
||||||
|
env:WEBMENTION_ENDPOINT
|
||||||
|
? "https://mi.within.website/api/webmention/accept"
|
||||||
|
|
||||||
let Config =
|
let Config =
|
||||||
{ Type =
|
{ Type =
|
||||||
{ signalboost : List Person.Type
|
{ signalboost : List Person.Type
|
||||||
, port : Natural
|
, port : Natural
|
||||||
, clackSet : List Text
|
, clackSet : List Text
|
||||||
, resumeFname : Text
|
, resumeFname : Text
|
||||||
|
, webMentionEndpoint : Text
|
||||||
}
|
}
|
||||||
, default =
|
, default =
|
||||||
{ signalboost = [] : List Person.Type
|
{ signalboost = [] : List Person.Type
|
||||||
, port = defaultPort
|
, port = defaultPort
|
||||||
, clackSet = [ "Ashlynn" ]
|
, clackSet = [ "Ashlynn" ]
|
||||||
, resumeFname = "./static/resume/resume.md"
|
, resumeFname = "./static/resume/resume.md"
|
||||||
|
, webMentionEndpoint = defaultWebMentionEndpoint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,4 +7,4 @@ kubectl rollout status -n apps deployment/christinewebsite
|
||||||
kubectl apply -f ./k8s/job.yml
|
kubectl apply -f ./k8s/job.yml
|
||||||
sleep 10
|
sleep 10
|
||||||
kubectl delete -f ./k8s/job.yml
|
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 color_eyre::eyre::Result;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
use tracing::{instrument, error};
|
use tracing::{error, instrument};
|
||||||
|
|
||||||
pub mod markdown;
|
pub mod markdown;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[serde(rename = "clackSet")]
|
#[serde(rename = "clackSet")]
|
||||||
clack_set: Vec<String>,
|
pub(crate) clack_set: Vec<String>,
|
||||||
signalboost: Vec<Person>,
|
pub(crate) signalboost: Vec<Person>,
|
||||||
port: u16,
|
pub(crate) port: u16,
|
||||||
#[serde(rename = "resumeFname")]
|
#[serde(rename = "resumeFname")]
|
||||||
resume_fname: PathBuf,
|
pub(crate) resume_fname: PathBuf,
|
||||||
|
#[serde(rename = "webMentionEndpoint")]
|
||||||
|
pub(crate) webmention_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument]
|
#[instrument]
|
||||||
async fn patrons() -> Result<Option<patreon::Users>> {
|
async fn patrons() -> Result<Option<patreon::Users>> {
|
||||||
use patreon::*;
|
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);
|
let cli = Client::new(creds);
|
||||||
|
|
||||||
match cli.campaign().await {
|
match cli.campaign().await {
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -26,12 +26,15 @@ async fn main() -> Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
log::info!("starting up commit {}", env!("GITHUB_SHA"));
|
log::info!("starting up commit {}", env!("GITHUB_SHA"));
|
||||||
|
|
||||||
let state = Arc::new(app::init(
|
let state = Arc::new(
|
||||||
|
app::init(
|
||||||
std::env::var("CONFIG_FNAME")
|
std::env::var("CONFIG_FNAME")
|
||||||
.unwrap_or("./config.dhall".into())
|
.unwrap_or("./config.dhall".into())
|
||||||
.as_str()
|
.as_str()
|
||||||
.into(),
|
.into(),
|
||||||
).await?);
|
)
|
||||||
|
.await?,
|
||||||
|
);
|
||||||
|
|
||||||
let healthcheck = warp::get().and(warp::path(".within").and(warp::path("health")).map(|| "OK"));
|
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, "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))
|
.with(warp::log(APPLICATION_NAME))
|
||||||
.recover(handlers::rejection);
|
.recover(handlers::rejection);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
<meta name="msapplication-TileColor" content="#ffffff">
|
<meta name="msapplication-TileColor" content="#ffffff">
|
||||||
<meta name="msapplication-TileImage" content="/static/favicon/ms-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="/static/favicon/ms-icon-144x144.png">
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
<link href="https://mi.within.website/api/webmention/accept" rel="webmention" />
|
||||||
@if styles.is_some() {
|
@if styles.is_some() {
|
||||||
<style>
|
<style>
|
||||||
@styles.unwrap()
|
@styles.unwrap()
|
||||||
|
|
Loading…
Reference in New Issue