Add old articles, fix caddy

This commit is contained in:
Jeff 2023-08-24 02:48:56 -04:00
parent 17f8d0052d
commit 61a2e794be
9 changed files with 184 additions and 43 deletions

View File

@ -1,19 +1,7 @@
jeffa.io,
www.jeffa.io,
localhost:8080 { localhost:8080 {
redir http://www.{host}:{port}{uri}
}
jeffa.io {
redir https://www.{host}{uri}
}
www.localhost:8080,
www.jeffa.io {
root * /srv/ root * /srv/
file_server { file_server
index /srv/index.html try_files {path} {path}.html {path}/ 404
}
rewrite @not_html {path}.html
@not_html {
not path *.html
}
} }

View File

@ -1,13 +1,15 @@
FROM alpine as build FROM alpine as build
RUN apk update && apk add pandoc RUN apk update && apk add pandoc fish
WORKDIR /jeffa.io/ WORKDIR /www.jeffa.io/
COPY . . COPY . .
RUN fish build.fish
FROM caddy:2-alpine FROM caddy:2-alpine
COPY Caddyfile /etc/caddy/Caddyfile COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=build /jeffa.io/out /srv COPY --from=build /www.jeffa.io/out /srv

View File

@ -1,13 +1,19 @@
if ! test -d out/
mkdir out/
end
cp basic.css out/index.css
for file in src/**/*.md for file in src/**/*.md
set -l output (string replace .md .html $file) set -l output (string replace .md .html $file)
set -l output (string replace src/ out/ $output) set -l output (string replace src/ out/ $output)
pandoc \ pandoc \
--to html \ --to html \
--css basic.css \ --embed-resources \
--self-contained \ --standalone \
--template templates/page.html \
--email-obfuscation references \
$file \ $file \
> $output > $output
end end
podman build -t www.jeffa.io .
podman run -p 8080:8080 www.jeffa.io:latest

2
www/run.fish Normal file
View File

@ -0,0 +1,2 @@
podman build -t www.jeffa.io .
podman run -p 8080:8080 www.jeffa.io:latest

View File

@ -2,14 +2,14 @@ variant: fcos
version: 1.5.0 version: 1.5.0
systemd: systemd:
units: units:
- name: www_jeffa_io.service - name: hello.service
enabled: true enabled: true
contents: | contents: |
[Unit] [Unit]
Description=caddy run Description=Run jeffa.io
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=no
ExecStart=podman-compose up ExecStart=/usr/bin/podman run git.jeffa.io/jeff/www.jeffa.io
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -0,0 +1,84 @@
---
date: Jan 26th, 2021
---
# An Auto-Increment Crate for Rust
...now exists! [Check it out.][1]
## The Problem
I was recently working on a Rust program and needed a way to give instances a unique identifier. These IDs did not need to be *universally* unique. I wanted the simplest way to recognize two instances as unique even if they were identical aside from the ID. A serial (or auto-increment) ID seemed like an appropriate choice.
As a rule, I try to write my own code to avoid over-reliance on dependencies. But this case seemed to warrant a dependency. It would be a simple thing to implement. What I wanted was essentially a counter, after all. I expected to find a reliable crate with lots of downloads.
Surprisingly, no such crate existed. I tried searching for "serial", "increment", "auto increment", "serial id", etc. and found nothing. One [crate][2] had a promising name but no documentation and, from what I could tell from the code, did not quite do what I was looking for.
I decided to write and publish such a crate myself. It seemed like a good opportunity to contribute a small but useful crate with relatively simple code to the greater Rust ecosystem.
## The Solution
### Are Universally Unique IDs a Universal Solution?
Serial IDs are used as identifiers because they are simple. Universally unique identifiers (or UUIDs), on the other hand, are usually used when a program needs to create identifiers without access to information about IDs created elsewhere. This is why a distributed database would use them. Rust developers have access to the [rand] crate and the [uuid] crate, which uses rand internally but creates IDs in formats that conform to formal standards. The basic strategy is to create a pseudo-random value or to capture a value (such as a UTC timestamp) and hash it. The details of UUID generation are too extensive to get into here. The uuid crate is both well-documented and cleanly coded, and there are countless other descriptions of the standards it implements.
The important difference between serial IDs and UUIDs is the performance cost. Hashing and random number generation are more expensive than increasing the value of an integer by one. Even if threads have to wait to get exclusive access to an ID generator, each thread will only hold it for the number of nanoseconds that it takes to calculate "x + 1". Serial IDs are also free from the issue of collisions, allowing them to be smaller. A 32-bit serial ID can have 4,294,967,296 unique instances. There is no probability to consider.
*UUIDs are always good enough, but their cost is not always necessary.* Git, for example, creates an SHA-1 has of a commit's content to create a commit ID. The IDs need to be unique when commits from different machines are pushed to a single remote. But many IDs do not need a high probability of being universally unique. CLI applications or other client-side programs that only work with in-memory values or store data locally are such examples.
### How Has This Been Implemented Before?
Serial IDs are familiar to users of database systems. In SQL, auto-increment integers can be used by setting `GENERATE BY DEFAULT AS IDENTITY` as the default value for a column.
```sql
CREATE TABLE distributors (
did integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
name varchar(40) NOT NULL CHECK (name <> '')
);
```
[Source][Postgres: CREATE TABLE]
Postgres has its own `SERIAL` type that mimics this behavior.
```sql
CREATE TABLE tablename (
colname SERIAL
);
```
[Source][Postgres: SERIAL]
Postgres provides a reasonable standard to replicate: 32-bit integers by default with support for any other unsigned integer. By using a trait to define the types that can be generated, users can make their own types compatible with the API provided by the crate. My crate just needs to provide the generator, the trait and implementations for unsigned integers in the standard library.
## Goals
- Small: The crate should be tiny. This is just a counter.
- Safe: IDs should be unique to each generator. There should be no panics.
- Compatible: Prefer primitives as the output values instead of a new type.
- Usable: Use feature flags to offer serde implementations, atomic primitives and other features
that may be useful to some users.
## Takeaway
This process proved something about Rust that wasn't readily apparent to me before. Encouraging flexibility by defining behavior (through traits) makes it intuitive to implement new features. When you know what you want to do the code starts to seem obvious. If you need a single type that can output many types, define the common behavior of those types and make the single type operate based on that shared behavior.
Rust is often described as flexible, but many languages are flexible. With Rust, it feels like the API writes itself once you clearly define what it should do. The code is not just expressive, it's obvious.
I also realized that there are still plenty of opportunities to contribute Rust code. Both widely-applicable and more niche libraries have provided the tools that developers need to adopt the language. But while Rust has become mature enough to fit many use cases, the ecosystem is far from bloated. There is still plenty of space to do new or different things and make an impact.
The serial_int crate is on [crates.io][1] and [lib.rs][lib.rs]. Contributions and feedback on the API are welcome!
[1]: https://crates.io/crates/serial_int
[2]: https://crates.io/crates/increment
[lib.rs]: https://lib.rs/crates/serial_int
[Postgres: CREATE TABLE]: https://www.postgresql.org/docs/13/sql-createtable.html
[Postgres: SERIAL]: https://www.postgresql.org/docs/13/datatype-numeric.html#DATATYPE-SERIAL
[rand]: https://crates.io/crates/rand
[uuid]: https://crates.io/crates/uuid

View File

@ -1,13 +1,13 @@
# jeffa.io
I am a programmer in New York. This is my website. I am a programmer in New York. This is my website.
<!--toc:start--> <!--toc:start-->
- Sites - Sites
- [jeffa.io](https://jeffa.io) - [jeffa.io](https://www.jeffa.io)
- [git.jeffa.io](https://git.jeffa.io) - [git.jeffa.io](https://git.jeffa.io)
- [Sourcehut](https://sr.ht/~jeffa) - [Sourcehut](https://sr.ht/~jeffa)
- [Github](https://github.com/solaeus) - [Github](https://github.com/solaeus)
- Articles - Articles
- [It's Time to Rethink the Command Line Shell](its_time_to_rethink_the_command_line_shell.html) - [It's Time to Rethink the Command Line Shell](its_time_to_rethink_the_command_line_shell)
- [An Auto-Increment Crate for Rust](an_auto_increment_crate_for_rust)
- [Rust Packages vs Crates](rust_packages_vs_crates)
<!--toc:end--> <!--toc:end-->

View File

@ -0,0 +1,57 @@
---
date: Nov 18th, 2021
---
# Rust Packages vs Crates
It is a common misconception that packages are crates and visa versa. I will
admit that this is a pet peeve. But for Rust coders, it is important to know the
difference because otherwise you are denied an understanding of how Rust code is
organized, shared and consumed.
## Crate
A **crate**, like a **module** inside of a crate, is a means of organizing code.
A **crate** is either a binary or a library.
A **crate** is not published independently, but rather as a member of its
**package**.
The compiler knows what a **crate** is and uses **crates** as namespaces for
items. If `std::hash::Hash` is not in scope, you can define your own trait
called `Hash`.
## Package
A **package** is a wrapper for at least one crate.
A **package** is publishable.
A **package** can contain one or zero library **crates**.
A **package** can contain any number of binary **crates**.
When you add a **package** to your dependencies, you consume the one library
**crate** inside of that **package**.
When you use **cargo run** or **cargo install** without specificying a
**crate**, you consume the one binary **crate** in that **package**.
When you use **cargo run --bin** or **cargo install --bin** followed by a
**crate** name, you consume the specified binary **crate** in that **package**.
## Why Is There Confusion About This?
I think the reason people get mixed up is because [crates.io] is actually a
repository for packages. If you find a library on [crates.io], you add the
*package* to the dependencies in your Cargo.toml file. You don't have to
specificy the crate because a package can only have one library crate. If the
default repository were called "packages.io", this may be less of an issue.
As always, The Book is there as an easy-to-read authority that clears up these
little confusions.
[The Rust Programming Language: Packages and Crates](https://doc.rust-lang.org/stable/book/ch07-01-packages-and-crates.html)
[crates.io]:https://crates.io

View File

@ -2,20 +2,22 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""> <html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
$if(title)$ <meta name="author" content="Jeff Anderson" />
<title>$title$</title>
$endif$
$if(author)$
<meta name="author" content=\"$author$\">
$endif$
$if(date)$ $if(date)$
<meta name="date" content=\"$date$\"> <meta name="date" content=\"$date$\" />
$endif$ $endif$
$styles()$ <link rel="stylesheet" href="index.css" />
<title>jeffa.io</title>
</head> </head>
<body> <body>
$body$ <h1><a href="https://www.jeffa.io">jeffa.io</a></h1>
$body$
<br />
<footer>
<p> Please contact me by <a href = "mailto: jeff@jeffa.io">email</a> with questions or corrections. You can view this website's <a href = "https://git.jeffa.io/jeff/jeffa.io">source</a>.
</p>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
</footer>
</body> </body>
</html> </html>