add post, fix profile err
This commit is contained in:
181
my-blog/content/posts/2025-08-08-arch.md
Normal file
181
my-blog/content/posts/2025-08-08-arch.md
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
---
|
||||||
|
title: "archlinuxのinstall"
|
||||||
|
slug: "arch"
|
||||||
|
date: "2025-08-08"
|
||||||
|
tags: ["arch"]
|
||||||
|
draft: false
|
||||||
|
---
|
||||||
|
|
||||||
|
## 最小構成
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# cgdisk /dev/sda
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ mkfs.vfat /dev/sda1
|
||||||
|
$ mkfs.ext4 /dev/sda2
|
||||||
|
|
||||||
|
$ mount /dev/sda2 /mnt
|
||||||
|
$ mount --mkdir /dev/sda1 /mnt/boot
|
||||||
|
|
||||||
|
$ pacstrap /mnt base base-devel linux linux-firmware linux-headers
|
||||||
|
|
||||||
|
$ arch-chroot /mnt
|
||||||
|
$ pacman -S dhcpcd grub os-prober efibootmgr
|
||||||
|
$ grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=grub
|
||||||
|
$ grub-mkconfig -o /boot/grub/grub.cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
これだけで`exit;reboot`すると起動できます。
|
||||||
|
|
||||||
|
## networkの設定
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ pacman -S git vim tmux zsh openssh
|
||||||
|
```
|
||||||
|
|
||||||
|
次にnetworkです。ここでは`systemd-networkd`を使用します。`dhcpcd`を使ったほうが簡単ではあります。もし安定しないようなら`dhcpcd`を使用。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# systemctl enable dhcpcd
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ systemctl enable systemd-networkd
|
||||||
|
```
|
||||||
|
|
||||||
|
network deviceをeth0にします。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ip link
|
||||||
|
$ ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh:/etc/systemd/network/eth.network
|
||||||
|
[Match]
|
||||||
|
Name=eth0
|
||||||
|
[Network]
|
||||||
|
Address=192.168.1.2/24
|
||||||
|
Gateway=192.168.1.1
|
||||||
|
DNS=192.168.1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ systemctl enable systemd-resolved
|
||||||
|
```
|
||||||
|
|
||||||
|
## auto-login
|
||||||
|
|
||||||
|
次にauto-loginを設定していきます。ここでは`getty`を使用。`${USER}`のところを自分のusernameにしてください。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ mkdir -p /etc/systemd/system/getty@tty1.service.d/
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh:/etc/systemd/system/getty@tty1.service.d/override.conf
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=-/usr/bin/agetty --autologin ${USER} --noclear %I $TERM
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ systemctl daemon-reload
|
||||||
|
$ systemctl restart getty@tty1
|
||||||
|
```
|
||||||
|
|
||||||
|
## window-manager
|
||||||
|
|
||||||
|
`xorg`でdesktop(window-manager)を作ります。`i3`を使うことにしましょう。`xorg`は`wayland`に切り替えたほうがいいかも。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ pacman -S xorg xorg-xinit i3 xterm
|
||||||
|
|
||||||
|
# 確認
|
||||||
|
$ startx
|
||||||
|
$ i3
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh:~/.xinitrc
|
||||||
|
exec i3
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh:~/.bash_profile
|
||||||
|
if [[ ! $DISPLAY && $XDG_VTNR -eq 1 ]]; then
|
||||||
|
exec startx
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
## sshの使い方
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ systemctl enable sshd
|
||||||
|
$ cat /etc/ssh/sshd_config
|
||||||
|
Port 22119
|
||||||
|
PasswordAuthentication no
|
||||||
|
|
||||||
|
$ systemctl restart sshd
|
||||||
|
```
|
||||||
|
|
||||||
|
基本的にlanで使う場合はdefaultで問題ありませんが、wanで使う場合は変更します。とはいえ、lanでもport, passwordは変えておいたほうがいいでしょう。
|
||||||
|
|
||||||
|
次に接続側でkeyを作ってserverに登録します。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ssh-keygen -f ~/.ssh/archlinux
|
||||||
|
$ ssh-copy-id -i ~/.ssh/archlinux ${USER}@192.168.1.2 -p 22119
|
||||||
|
```
|
||||||
|
|
||||||
|
`ssh-copy-id`がない場合は以下のようにしましょう。
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ cat ~/.ssh/archlinux.pub | ssh -p 22119 ${USER}@192.168.1.2 'cat >> ~/.ssh/authorized_keys'
|
||||||
|
```
|
||||||
|
|
||||||
|
この設定で`ssh archlinux`コマンドで接続できます。
|
||||||
|
|
||||||
|
```sh:~/.ssh/config
|
||||||
|
Host archlinux
|
||||||
|
User syui
|
||||||
|
Hostname 192.168.1.2
|
||||||
|
Port 22119
|
||||||
|
IdentityFile ~/.ssh/archlinux
|
||||||
|
```
|
||||||
|
|
||||||
|
おそらく、これがarchlinuxを普通に使っていくうえでの最小構成かと思います。
|
||||||
|
|
||||||
|
serverだけならxorgなどは必要ありません。
|
||||||
|
|
||||||
|
## zshの使い方
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ sudo pacman -S git-zsh-completion powerline zsh-autocomplete zsh-autosuggestions zsh-completions zsh-history-substring-search zsh-syntax-highlighting
|
||||||
|
```
|
||||||
|
|
||||||
|
例えば、`ls -`と入力すると補完され、`C-n`, `C-p`で選択。
|
||||||
|
|
||||||
|
```sh:~/.zshrc
|
||||||
|
alias u="sudo pacman -Syu --noconfirm"
|
||||||
|
alias zs="vim ~/.zshrc"
|
||||||
|
alias zr="exec $SHELL && source ~/.zshrc"
|
||||||
|
|
||||||
|
source /usr/share/zsh/plugins/zsh-autocomplete/zsh-autocomplete.plugin.zsh
|
||||||
|
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||||
|
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
||||||
|
source /usr/share/zsh/plugins/zsh-history-substring-search/zsh-history-substring-search.zsh
|
||||||
|
# source /usr/share/powerline/bindings/zsh/powerline.zsh
|
||||||
|
|
||||||
|
autoload -Uz compinit
|
||||||
|
compinit
|
||||||
|
fpath=(/usr/share/zsh/site-functions $fpath)
|
||||||
|
|
||||||
|
HISTSIZE=10000
|
||||||
|
SAVEHIST=10000
|
||||||
|
HISTFILE=~/.zsh_history
|
||||||
|
setopt SHARE_HISTORY
|
||||||
|
setopt HIST_IGNORE_DUPS
|
||||||
|
bindkey '^[[A' history-substring-search-up
|
||||||
|
bindkey '^[[B' history-substring-search-down
|
||||||
|
```
|
||||||
|
|
||||||
|
`powerline`は重いのでコメントしています。
|
1675
my-blog/content/posts/2025-08-09-9935c5b5.md
Normal file
1675
my-blog/content/posts/2025-08-09-9935c5b5.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -83,11 +83,14 @@ export const atproto = {
|
|||||||
return await request(`${apiEndpoint}/xrpc/${ENDPOINTS.getProfile}?actor=${actor}`)
|
return await request(`${apiEndpoint}/xrpc/${ENDPOINTS.getProfile}?actor=${actor}`)
|
||||||
},
|
},
|
||||||
|
|
||||||
async getRecords(pds, repo, collection, limit = 10, cursor = null) {
|
async getRecords(pds, repo, collection, limit = 10, cursor = null, reverse = false) {
|
||||||
let url = `${pds}/xrpc/${ENDPOINTS.listRecords}?repo=${repo}&collection=${collection}&limit=${limit}`
|
let url = `${pds}/xrpc/${ENDPOINTS.listRecords}?repo=${repo}&collection=${collection}&limit=${limit}`
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
url += `&cursor=${cursor}`
|
url += `&cursor=${cursor}`
|
||||||
}
|
}
|
||||||
|
if (reverse) {
|
||||||
|
url += `&reverse=true`
|
||||||
|
}
|
||||||
const res = await request(url)
|
const res = await request(url)
|
||||||
return {
|
return {
|
||||||
records: res.records || [],
|
records: res.records || [],
|
||||||
@@ -151,7 +154,7 @@ export const collections = {
|
|||||||
const cached = dataCache.get(cacheKey)
|
const cached = dataCache.get(cacheKey)
|
||||||
if (cached) return cached
|
if (cached) return cached
|
||||||
|
|
||||||
const data = await atproto.getRecords(pds, repo, `${collection}.chat.comment`, limit)
|
const data = await atproto.getRecords(pds, repo, `${collection}.chat.comment`, limit, null, true) // reverse=true for chronological order
|
||||||
// Extract records array for backward compatibility
|
// Extract records array for backward compatibility
|
||||||
const records = data.records || data
|
const records = data.records || data
|
||||||
dataCache.set(cacheKey, records)
|
dataCache.set(cacheKey, records)
|
||||||
@@ -161,7 +164,7 @@ export const collections = {
|
|||||||
async getChat(pds, repo, collection, limit = 10, cursor = null) {
|
async getChat(pds, repo, collection, limit = 10, cursor = null) {
|
||||||
// Don't use cache for pagination requests
|
// Don't use cache for pagination requests
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
const result = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, cursor)
|
const result = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, cursor, true) // reverse=true for chronological order
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +175,7 @@ export const collections = {
|
|||||||
return Array.isArray(cached) ? { records: cached, cursor: null } : cached
|
return Array.isArray(cached) ? { records: cached, cursor: null } : cached
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await atproto.getRecords(pds, repo, `${collection}.chat`, limit)
|
const data = await atproto.getRecords(pds, repo, `${collection}.chat`, limit, null, true) // reverse=true for chronological order
|
||||||
// Cache only the records array for backward compatibility
|
// Cache only the records array for backward compatibility
|
||||||
dataCache.set(cacheKey, data.records || data)
|
dataCache.set(cacheKey, data.records || data)
|
||||||
return data
|
return data
|
||||||
|
@@ -45,7 +45,10 @@ pub struct ProfileFetcher {
|
|||||||
impl ProfileFetcher {
|
impl ProfileFetcher {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
client: reqwest::Client::new(),
|
client: reqwest::Client::builder()
|
||||||
|
.timeout(std::time::Duration::from_secs(30))
|
||||||
|
.build()
|
||||||
|
.unwrap_or_else(|_| reqwest::Client::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,11 +87,15 @@ impl ProfileFetcher {
|
|||||||
let response = self.client
|
let response = self.client
|
||||||
.get(&url)
|
.get(&url)
|
||||||
.query(&[("repo", handle)])
|
.query(&[("repo", handle)])
|
||||||
|
.timeout(std::time::Duration::from_secs(10))
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| anyhow::anyhow!("Request failed: {}", e))?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(anyhow::anyhow!("Failed to describe repo: {}", response.status()));
|
let status = response.status();
|
||||||
|
let error_text = response.text().await.unwrap_or_default();
|
||||||
|
return Err(anyhow::anyhow!("Failed to describe repo: {} - {}", status, error_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
let repo_desc: RepoDescription = response.json().await?;
|
let repo_desc: RepoDescription = response.json().await?;
|
||||||
@@ -117,11 +124,15 @@ impl ProfileFetcher {
|
|||||||
let response = self.client
|
let response = self.client
|
||||||
.get(&url)
|
.get(&url)
|
||||||
.query(&[("actor", did)])
|
.query(&[("actor", did)])
|
||||||
|
.timeout(std::time::Duration::from_secs(10))
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await
|
||||||
|
.map_err(|e| anyhow::anyhow!("Request failed: {}", e))?;
|
||||||
|
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
return Err(anyhow::anyhow!("Failed to get profile: {}", response.status()));
|
let status = response.status();
|
||||||
|
let error_text = response.text().await.unwrap_or_default();
|
||||||
|
return Err(anyhow::anyhow!("Failed to get profile: {} - {}", status, error_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
let profile_data: Value = response.json().await?;
|
let profile_data: Value = response.json().await?;
|
||||||
|
@@ -1875,7 +1875,7 @@ async fn check_and_process_new_posts(
|
|||||||
|
|
||||||
async fn get_existing_records(config: &AuthConfig, collection: &str) -> Result<Vec<serde_json::Value>> {
|
async fn get_existing_records(config: &AuthConfig, collection: &str) -> Result<Vec<serde_json::Value>> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let url = format!("{}/xrpc/com.atproto.repo.listRecords?repo={}&collection={}&limit=100",
|
let url = format!("{}/xrpc/com.atproto.repo.listRecords?repo={}&collection={}&limit=100&reverse=true",
|
||||||
config.admin.pds,
|
config.admin.pds,
|
||||||
urlencoding::encode(&config.admin.did),
|
urlencoding::encode(&config.admin.did),
|
||||||
urlencoding::encode(collection));
|
urlencoding::encode(collection));
|
||||||
|
Reference in New Issue
Block a user