mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-11 23:09:22 +08:00
Compare commits
22 Commits
411a276d34
...
production
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e2114aaa3 | |||
| fe9bda0e7b | |||
| 16c84c3dca | |||
| 3336eeca78 | |||
| d22da25c2b | |||
| 40aa569024 | |||
| 5f36b073a7 | |||
| c707d8e168 | |||
| 758d86262c | |||
| 08e3440742 | |||
| 5e1c07931e | |||
| f1b762c959 | |||
| 2079a35e67 | |||
| 438c569c2f | |||
| 7a50f12129 | |||
| 0389536c9d | |||
| 163faa0db3 | |||
| 6d11d3232f | |||
| 48cd33e478 | |||
| 65bf14958b | |||
| 26371c3076 | |||
| f0cc24522e |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "nixpkgs"]
|
||||
path = nixpkgs
|
||||
url = https://github.com/CHN-beta/nixpkgs.git
|
||||
[submodule "packages/ufo"]
|
||||
path = packages/ufo
|
||||
url = https://git.chn.moe/chn/ufo.git
|
||||
@@ -7,6 +7,7 @@ let devices =
|
||||
"/dev/disk/by-partlabel/nas-root2".mapper = "root2";
|
||||
"/dev/disk/by-partlabel/nas-root3" = { mapper = "root3"; ssd = true; };
|
||||
"/dev/disk/by-partlabel/nas-root4" = { mapper = "root4"; ssd = true; };
|
||||
"/dev/disk/by-partlabel/nas-root5".mapper = "root5";
|
||||
"/dev/disk/by-partlabel/nas-swap" = { mapper = "swap"; ssd = true; };
|
||||
"/dev/disk/by-partlabel/nas-ssd1" = { mapper = "ssd1"; ssd = true; };
|
||||
"/dev/disk/by-partlabel/nas-ssd2" = { mapper = "ssd2"; ssd = true; };
|
||||
|
||||
18
devices/hwang/default.nix
Normal file
18
devices/hwang/default.nix
Normal file
@@ -0,0 +1,18 @@
|
||||
# sudo nix build --store 'local?store=/data/gpfs01/hwang/.nix/store&state=/data/gpfs01/hwang/.nix/state&log=/data/gpfs01/hwang/.nix/log' .#hwang
|
||||
# sudo nix-store --store 'local?store=/data/gpfs01/hwang/.nix/store&state=/data/gpfs01/hwang/.nix/state&log=/data/gpfs01/hwang/.nix/log' -qR ./result | grep -Fxv -f <(ssh hwang find .nix/store -maxdepth 1 -exec realpath '{}' '\;') | sudo xargs nix-store --store 'local?store=/data/gpfs01/hwang/.nix/store&state=/data/gpfs01/hwang/.nix/state&log=/data/gpfs01/hwang/.nix/log' --export | pv > hwang.nar
|
||||
# cat hwang.nar | nix-store --import
|
||||
{ inputs, localLib }:
|
||||
let
|
||||
pkgs = import inputs.nixpkgs (localLib.buildNixpkgsConfig
|
||||
{
|
||||
inputs = { inherit (inputs.nixpkgs) lib; topInputs = inputs; };
|
||||
nixpkgs = { march = "haswell"; nixRoot = "/data/gpfs01/hwang/.nix"; nixos = false; };
|
||||
});
|
||||
hwang = pkgs.symlinkJoin
|
||||
{
|
||||
name = "hwang";
|
||||
paths = with pkgs; [ pv localPackages.vasp.intel glibc ];
|
||||
postBuild = "echo ${inputs.self.rev or "dirty"} > $out/.version";
|
||||
passthru = { inherit pkgs; archive = pkgs.closureInfo { rootPaths = [ hwang.drvPath ]; }; };
|
||||
};
|
||||
in hwang
|
||||
@@ -21,7 +21,10 @@ inputs:
|
||||
swap = [ "/dev/mapper/swap" ];
|
||||
# TODO: snapshot should take place just before switching root
|
||||
rollingRootfs.waitDevices =
|
||||
[ "/dev/mapper/root2" "/dev/mapper/root3" "/dev/mapper/root4" "/dev/mapper/ssd1" "/dev/mapper/ssd2" ];
|
||||
[
|
||||
"/dev/mapper/root2" "/dev/mapper/root3" "/dev/mapper/root4" "/dev/mapper/root5"
|
||||
"/dev/mapper/ssd1" "/dev/mapper/ssd2"
|
||||
];
|
||||
};
|
||||
initrd.sshd = {};
|
||||
nixpkgs.march = "alderlake";
|
||||
|
||||
@@ -18,9 +18,10 @@ inputs:
|
||||
"/dev/mapper/tf1" =
|
||||
{
|
||||
"/" = "/nix/tf";
|
||||
"/nix/remote/jykang" = "/data/gpfs01/jykang/.nix";
|
||||
"/nix/remote/xmuhk" = "/public/home/xmuhk/.nix";
|
||||
"/nix/remote/jykang" = "/data/gpfs01/jykang/.nix";
|
||||
"/nix/remote/wlin" = "/data/gpfs01/wlin/.nix";
|
||||
"/nix/remote/hwang" = "/data/gpfs01/hwang/.nix";
|
||||
};
|
||||
};
|
||||
nfs."nas.ts.chn.moe:/" = { mountPoint = "/nix/remote/nas"; mountBeforeSwitch = false; };
|
||||
|
||||
36
flake.lock
generated
36
flake.lock
generated
@@ -1161,14 +1161,19 @@
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"path": "nixpkgs",
|
||||
"type": "path"
|
||||
"lastModified": 1767694262,
|
||||
"narHash": "sha256-xpFtS6JGpwaDVqXWEYDfoLb05oLEAL1VE2GF9x8smDk=",
|
||||
"owner": "CHN-beta",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ae0b0157cbfee59adb0d6211ea6e47299a173cd5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"path": "nixpkgs",
|
||||
"type": "path"
|
||||
},
|
||||
"parent": []
|
||||
"owner": "CHN-beta",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixvirt": {
|
||||
"inputs": {
|
||||
@@ -1491,6 +1496,7 @@
|
||||
"sticker": "sticker",
|
||||
"stickerpicker": "stickerpicker",
|
||||
"tgbot-cpp": "tgbot-cpp",
|
||||
"ufo": "ufo",
|
||||
"v-sim": "v-sim",
|
||||
"vaspberry": "vaspberry",
|
||||
"winapps": "winapps",
|
||||
@@ -1776,6 +1782,24 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"ufo": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1768114392,
|
||||
"lfs": true,
|
||||
"narHash": "sha256-H2vC6gA4oBBs4ZYSQAxI9VmviCcT9U9+xqNW0Q/N5Jw=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "b130375ff8c5e4c02febdf3821ddeb43b6cbd89c",
|
||||
"revCount": 89,
|
||||
"type": "git",
|
||||
"url": "https://git.chn.moe/chn/ufo.git"
|
||||
},
|
||||
"original": {
|
||||
"lfs": true,
|
||||
"type": "git",
|
||||
"url": "https://git.chn.moe/chn/ufo.git"
|
||||
}
|
||||
},
|
||||
"v-sim": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
inputs =
|
||||
{
|
||||
self = { submodules = true; lfs = true; };
|
||||
nixpkgs.url = ./nixpkgs;
|
||||
nixpkgs.url = "github:CHN-beta/nixpkgs/nixos-25.11";
|
||||
nixpkgs-2505.url = "github:CHN-beta/nixpkgs/nixos-25.05";
|
||||
nixpkgs-2411.url = "github:CHN-beta/nixpkgs/nixos-24.11";
|
||||
nixpkgs-2311.url = "github:CHN-beta/nixpkgs/nixos-23.11";
|
||||
@@ -66,6 +65,7 @@
|
||||
sqlgen = { url = "git+https://github.com/getml/sqlgen?submodules=1"; flake = false; };
|
||||
reflectcpp = { url = "git+https://github.com/getml/reflect-cpp?submodules=1"; flake = false; };
|
||||
linux-asus = { url = "github:CHN-beta/linux-g14/6.18"; flake = false; };
|
||||
ufo = { url = "git+https://git.chn.moe/chn/ufo.git?lfs=1"; flake = false; };
|
||||
};
|
||||
|
||||
outputs = inputs: let localLib = import ./flake/lib inputs.nixpkgs.lib; in
|
||||
|
||||
@@ -79,6 +79,7 @@ in platformConfig //
|
||||
buildInputs = prev.buildInputs or [] ++ [ final.localPackages.lsf final.libnsl ];
|
||||
});
|
||||
cpptrace = prev.cpptrace.overrideAttrs (prev: { doCheck = !final.stdenv.hostPlatform.isStatic; });
|
||||
typst = final.pkgs-2505.typst;
|
||||
}
|
||||
// (
|
||||
let
|
||||
@@ -104,6 +105,7 @@ in platformConfig //
|
||||
})
|
||||
];
|
||||
};
|
||||
pkgs-2505 = "nixpkgs-2505";
|
||||
};
|
||||
packages = name:
|
||||
let flakeSource = inputs.topInputs.${source.${name}.source or source.${name}};
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
jykang = import ../devices/jykang { inherit inputs localLib; };
|
||||
wlin = import ../devices/wlin { inherit inputs localLib; };
|
||||
xmuhk = import ../devices/xmuhk { inherit inputs localLib; };
|
||||
hwang = import ../devices/hwang { inherit inputs localLib; };
|
||||
src =
|
||||
let getDrv = x:
|
||||
if pkgs.lib.isDerivation x then [ x ]
|
||||
|
||||
@@ -15,7 +15,7 @@ inputs:
|
||||
[
|
||||
# system management
|
||||
# TODO: module should add yubikey-touch-detector into path
|
||||
gparted wayland-utils clinfo mesa-demos vulkan-tools dracut yubikey-touch-detector btrfs-assistant snapper-gui
|
||||
gparted wayland-utils clinfo mesa-demos vulkan-tools dracut yubikey-touch-detector btrfs-assistant
|
||||
cpu-x wl-mirror geekbench xpra
|
||||
(
|
||||
writeShellScriptBin "xclip"
|
||||
@@ -60,19 +60,15 @@ inputs:
|
||||
# matplot++ needs old gnuplot
|
||||
pkgs-2311.gnuplot
|
||||
# math, physics and chemistry
|
||||
octaveFull ovito localPackages.vesta localPackages.v-sim jmol mpi geogebra6 localPackages.ufo
|
||||
octaveFull ovito localPackages.vesta localPackages.v-sim mpi geogebra6 localPackages.ufo
|
||||
(quantum-espresso.override { stdenv = gcc14Stdenv; gfortran = gfortran14; })
|
||||
pkgs-2311.hdfview numbat qalculate-qt
|
||||
# virtualization
|
||||
virt-viewer bottles wineWowPackages.stagingFull genymotion playonlinux
|
||||
pkgs-2311.hdfview
|
||||
# media
|
||||
nur-xddxdd.svp
|
||||
# for kdenlive auto subtitle
|
||||
openai-whisper
|
||||
# daily management
|
||||
activitywatch super-productivity
|
||||
# game
|
||||
lutris
|
||||
super-productivity
|
||||
];
|
||||
_pythonPackages = [(pythonPackages: with pythonPackages;
|
||||
[
|
||||
|
||||
@@ -9,7 +9,7 @@ inputs:
|
||||
_packages = with inputs.pkgs;
|
||||
[
|
||||
# basic tools
|
||||
beep dos2unix gnugrep pv tmux screen parallel tldr cowsay jq yq ipfetch localPackages.pslist
|
||||
beep dos2unix gnugrep pv tmux screen parallel tldr cowsay jq yq-go ipfetch localPackages.pslist
|
||||
fastfetch reptyr duc ncdu progress libva-utils ksh neofetch dateutils glib cryptsetup
|
||||
# lsxx
|
||||
pciutils usbutils lshw util-linux lsof dmidecode lm_sensors hwloc acpica-tools ethtool
|
||||
|
||||
@@ -26,8 +26,7 @@ inputs:
|
||||
[
|
||||
"github.copilot" "github.copilot-chat" "github.github-vscode-theme"
|
||||
"intellsmi.comment-translate"
|
||||
"ms-vscode.cmake-tools" "ms-vscode.cpptools-extension-pack" "ms-vscode.hexeditor"
|
||||
"ms-vscode.remote-explorer"
|
||||
"ms-vscode.hexeditor" "ms-vscode.remote-explorer"
|
||||
"ms-vscode-remote.remote-ssh"
|
||||
"donjayamanne.githistory" "fabiospampinato.vscode-diff"
|
||||
"llvm-vs-code-extensions.vscode-clangd" "ms-ceintl.vscode-language-pack-zh-hans"
|
||||
@@ -65,6 +64,9 @@ inputs:
|
||||
"ms-toolsai.datawrangler"
|
||||
# nushell
|
||||
"TheNuProjectContributors.vscode-nushell-lang"
|
||||
# C/C++
|
||||
"ms-vscode.cmake-tools" "ms-vscode.cpptools-extension-pack" "ms-vscode.cpptools" "coolchyni.beyond-debug"
|
||||
"vadimcn.vscode-lldb"
|
||||
];
|
||||
keybindings =
|
||||
[
|
||||
@@ -335,6 +337,8 @@ inputs:
|
||||
"tinymist.preview.partialRendering" = false;
|
||||
"tinymist.preview.refresh" = "onSave";
|
||||
"workbench.secondarySideBar.defaultVisibility" = "hidden";
|
||||
# disable terminal suggestions
|
||||
"terminal.integrated.suggest.enabled" = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
inputs:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
config =
|
||||
{
|
||||
@@ -8,7 +8,12 @@ inputs:
|
||||
config.programs.yazi =
|
||||
{
|
||||
enable = true;
|
||||
keymap.mgr.append_keymap = [{ on = "T"; run = "shell --orphan ghostty"; }];
|
||||
keymap.mgr.append_keymap =
|
||||
[
|
||||
{ on = "T"; run = "shell --orphan ghostty"; }
|
||||
{ on = [ "c" "a" "a" ]; run = "plugin compress"; }
|
||||
];
|
||||
plugins = { inherit (pkgs.yaziPlugins) compress; };
|
||||
};
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -59,19 +59,22 @@ inputs:
|
||||
};
|
||||
# prevent AI web crawlers
|
||||
# https://her.esy.fun/posts/0031-how-i-protect-my-forgejo-instance-from-ai-web-crawlers/index.html
|
||||
nginx.virtualHosts."https:${gitea.hostname}".locations."/".extraConfigPre =
|
||||
''
|
||||
if ($http_user_agent ~* "git/|git-lfs/") {
|
||||
set $bypass_cookie 1;
|
||||
}
|
||||
if ($cookie_Yogsototh_opens_the_door = "1") {
|
||||
set $bypass_cookie 1;
|
||||
}
|
||||
if ($bypass_cookie != 1) {
|
||||
add_header Content-Type text/html always;
|
||||
return 418 '<script>document.cookie = "Yogsototh_opens_the_door=1; Path=/;"; window.location.reload();</script>';
|
||||
}
|
||||
'';
|
||||
# nginx.virtualHosts."https:${gitea.hostname}".locations."/".extraConfigPre =
|
||||
# ''
|
||||
# if ($http_user_agent ~* "git/|git-lfs/") {
|
||||
# set $bypass_cookie 1;
|
||||
# }
|
||||
# if ($cookie_Yogsototh_opens_the_door = "1") {
|
||||
# set $bypass_cookie 1;
|
||||
# }
|
||||
# if ($request_method != "GET") {
|
||||
# set $bypass_cookie 1;
|
||||
# }
|
||||
# if ($bypass_cookie != 1) {
|
||||
# add_header Content-Type text/html always;
|
||||
# return 418 '<script>document.cookie = "Yogsototh_opens_the_door=1; Path=/;"; window.location.reload();</script>';
|
||||
# }
|
||||
# '';
|
||||
};
|
||||
nixos =
|
||||
{
|
||||
|
||||
@@ -69,6 +69,8 @@ inputs:
|
||||
"bin" "Desktop" "Documents" "Downloads" "Music" "Pictures" "repo" "share" "Public" "Videos" ".config"
|
||||
".local" ".ecdata" { directory = ".mozilla/firefox/default"; mode = "0700"; } ".steam" ".zotero"
|
||||
"Zotero" ".thunderbird"
|
||||
# dms 将剪贴板历史数据和主题的一些设置存放在这里
|
||||
".cache/dms-clipboard" ".cache/DankMaterialShell"
|
||||
];
|
||||
})
|
||||
# 对于集群的工作节点,挂载一些本来由 home-manager 生成的文件,以及一些用来存放 home-manager 生成文件的目录
|
||||
|
||||
@@ -71,6 +71,10 @@ inputs:
|
||||
"Mod+WheelScrollUp" = { action.focus-column-left = {}; cooldown-ms = 50; };
|
||||
"Mod+Left".action.focus-column-left = {};
|
||||
"Mod+Right".action.focus-column-right = {};
|
||||
"Ctrl+Mod+Left".action.move-column-left = {};
|
||||
"Ctrl+Mod+Right".action.move-column-right = {};
|
||||
"Mod+Up".action.focus-workspace-up = {};
|
||||
"Mod+Down".action.focus-workspace-down = {};
|
||||
"Mod+MouseMiddle".action.close-window = {};
|
||||
"Mod+L".action.spawn = [ "dms" "ipc" "lock" "lock" ];
|
||||
"Mod+W".action.move-workspace-to-monitor-next = {};
|
||||
|
||||
1
nixpkgs
1
nixpkgs
Submodule nixpkgs deleted from d8ca282fc0
@@ -19,7 +19,7 @@ namespace biu
|
||||
namespace common
|
||||
{
|
||||
std::size_t hash(auto&&... objs);
|
||||
[[gnu::always_inline]] void unused(auto&&...);
|
||||
[[gnu::always_inline]] inline void unused(auto&&...);
|
||||
[[noreturn]] void block_forever();
|
||||
|
||||
bool is_interactive();
|
||||
|
||||
@@ -41,10 +41,10 @@ namespace biu
|
||||
protected: const std::chrono::time_point<std::chrono::steady_clock> CreateTime_;
|
||||
|
||||
// call log<Debug>("create {type} at {address}.");
|
||||
protected: [[gnu::always_inline]] ObjectMonitor();
|
||||
protected: [[gnu::noinline]] inline ObjectMonitor();
|
||||
|
||||
// call log<Debug>("destroy {type} at {address} after {duration} ms.");
|
||||
protected: [[gnu::always_inline]] virtual ~ObjectMonitor();
|
||||
protected: [[gnu::noinline]] inline virtual ~ObjectMonitor();
|
||||
};
|
||||
template <typename T> friend class ObjectMonitor;
|
||||
|
||||
@@ -65,24 +65,26 @@ namespace biu
|
||||
|
||||
// if sizeof...(Param) > 0, call log<Debug>("begin function with {arguments}.");
|
||||
// else call log<Debug>("begin function.");
|
||||
public: template <typename... Param> [[gnu::always_inline]] explicit Guard(Param&&... param);
|
||||
public: template <typename... Param> explicit Guard(Param&&... param);
|
||||
|
||||
// call log<Debug>("end function after {duration} ms.")
|
||||
public: [[gnu::always_inline]] inline virtual ~Guard();
|
||||
public: [[gnu::noinline]] inline virtual ~Guard();
|
||||
|
||||
// call log<Debug>("reached after {duration} ms.")
|
||||
public: [[gnu::always_inline]] inline void operator()() const;
|
||||
public: [[gnu::noinline]] inline void operator()() const;
|
||||
|
||||
// call log<Debug>("return {return} after {duration} ms.")
|
||||
public: template <typename T> [[gnu::always_inline]] T rtn(T&& value) const;
|
||||
public: template <typename T> [[gnu::noinline]] T rtn(T&& value) const;
|
||||
|
||||
// print the following message if LoggerConfig_ is set and the level is higher than the level of the
|
||||
// LoggerConfig_
|
||||
// [ {time} {thread} {indent} {filename}:{line} {function_name} ] {message}
|
||||
public: template <Level L> [[gnu::always_inline]] void log(const std::string& message) const;
|
||||
public: [[gnu::always_inline]] inline void error(const std::string& message) const;
|
||||
public: [[gnu::always_inline]] inline void info(const std::string& message) const;
|
||||
public: [[gnu::always_inline]] inline void debug(const std::string& message) const;
|
||||
// All directly called log functions should not be inlined to ensure correct stacktrace information
|
||||
// all not directly called log functions should be inlined to align stacktrace depth (always 1)
|
||||
protected: template <Level L> [[gnu::noinline]] void log_(const std::string& message) const;
|
||||
public: [[gnu::noinline]] inline void error(const std::string& message) const;
|
||||
public: [[gnu::noinline]] inline void info(const std::string& message) const;
|
||||
public: [[gnu::noinline]] inline void debug(const std::string& message) const;
|
||||
};
|
||||
friend class Guard;
|
||||
|
||||
|
||||
@@ -46,12 +46,12 @@ namespace biu
|
||||
{
|
||||
Guard guard;
|
||||
Objects_.lock()->emplace(this, nameof::nameof_full_type<T>());
|
||||
guard.debug("create {} at {}."_f(nameof::nameof_full_type<T>(), fmt::ptr(this)));
|
||||
guard.log_<Level::Debug>("create {} at {}."_f(nameof::nameof_full_type<T>(), fmt::ptr(this)));
|
||||
}
|
||||
template <typename T> Logger::ObjectMonitor<T>::~ObjectMonitor()
|
||||
{
|
||||
Guard guard;
|
||||
guard.log<Level::Debug>("destroy {} at {} after {} ms."_f
|
||||
guard.log_<Level::Debug>("destroy {} at {} after {} ms."_f
|
||||
(
|
||||
nameof::nameof_full_type<T>(), fmt::ptr(this),
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
@@ -102,13 +102,13 @@ namespace biu
|
||||
else return "({})"_f(nameof::nameof_full_type<T>());
|
||||
};
|
||||
if constexpr (sizeof...(Param) > 0)
|
||||
debug("begin function with {{{}}}."_f(fmt::join({try_format(std::forward<Param>(param))...}, ", ")));
|
||||
else debug("begin function.");
|
||||
log_<Level::Debug>("begin function with {{{}}}."_f(fmt::join({try_format(std::forward<Param>(param))...}, ", ")));
|
||||
else log_<Level::Debug>("begin function.");
|
||||
}
|
||||
|
||||
Logger::Guard::~Guard()
|
||||
{
|
||||
debug("end function after {} ms."_f(get_time_ms()));
|
||||
log_<Level::Debug>("end function after {} ms."_f(get_time_ms()));
|
||||
Indent_--;
|
||||
auto&& lock = Threads_.lock();
|
||||
if (auto thread_id = get_thread_id(); lock->contains(thread_id))
|
||||
@@ -116,14 +116,14 @@ namespace biu
|
||||
else [[unlikely]]
|
||||
error("{:08x} not found in Logger::Threads."_f(thread_id % std::numeric_limits<std::uint64_t>::max()));
|
||||
}
|
||||
void Logger::Guard::operator()() const { debug("reached after {} ms."_f(get_time_ms())); }
|
||||
template <Logger::Level L> void Logger::Guard::log(const std::string& message) const
|
||||
void Logger::Guard::operator()() const { log_<Level::Debug>("reached after {} ms."_f(get_time_ms())); }
|
||||
template <Logger::Level L> void Logger::Guard::log_(const std::string& message) const
|
||||
{
|
||||
if (auto&& lock = LoggerConfig_.lock(); lock->Level >= L)
|
||||
{
|
||||
static_assert(std::same_as<std::size_t, std::uint64_t>);
|
||||
auto time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
|
||||
auto frame = cpptrace::stacktrace::current(0, 1).frames[0];
|
||||
auto frame = cpptrace::stacktrace::current(2, 1).frames[0];
|
||||
# ifdef BIU_LOGGER_SOURCE_ROOT
|
||||
auto source_root = std::string_view(BIU_LOGGER_SOURCE_ROOT "/");
|
||||
auto source_file = frame.filename.starts_with(source_root) ?
|
||||
@@ -143,13 +143,13 @@ namespace biu
|
||||
) << std::flush;
|
||||
}
|
||||
}
|
||||
void Logger::Guard::error(const std::string& message) const { log<Level::Error>(message); }
|
||||
void Logger::Guard::info(const std::string& message) const { log<Level::Info>(message); }
|
||||
void Logger::Guard::debug(const std::string& message) const { log<Level::Debug>(message); }
|
||||
void Logger::Guard::error(const std::string& message) const { log_<Level::Error>(message); }
|
||||
void Logger::Guard::info(const std::string& message) const { log_<Level::Info>(message); }
|
||||
void Logger::Guard::debug(const std::string& message) const { log_<Level::Debug>(message); }
|
||||
|
||||
template <typename T> inline T Logger::Guard::rtn(T&& value) const
|
||||
template <typename T> T Logger::Guard::rtn(T&& value) const
|
||||
{
|
||||
debug("return {} after {} ms."_f(std::forward<T>(value), get_time_ms()));
|
||||
log_<Level::Debug>("return {} after {} ms."_f(std::forward<T>(value), get_time_ms()));
|
||||
return std::forward<T>(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,6 @@
|
||||
int main()
|
||||
{
|
||||
biu::Logger::Guard log("test", nullptr, std::ofstream());
|
||||
log.info("hello world");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ inputs: rec
|
||||
sqlite-orm = inputs.pkgs.callPackage ./sqlite-orm.nix { src = inputs.topInputs.sqlite-orm; };
|
||||
mkPnpmPackage = inputs.pkgs.callPackage ./mkPnpmPackage.nix {};
|
||||
sbatch-tui = inputs.pkgs.callPackage ./sbatch-tui { inherit biu; };
|
||||
ufo = inputs.pkgs.callPackage ./ufo { inherit biu matplotplusplus; tbb = inputs.pkgs.tbb_2022; };
|
||||
ufo = inputs.pkgs.callPackage inputs.topInputs.ufo { inherit biu matplotplusplus; tbb = inputs.pkgs.tbb_2022; };
|
||||
chn-bsub = inputs.pkgs.callPackage ./chn-bsub { inherit biu; };
|
||||
py4vasp = inputs.pkgs.python3Packages.callPackage ./py4vasp.nix { src = inputs.topInputs.py4vasp; };
|
||||
pocketfft = inputs.pkgs.callPackage ./pocketfft.nix { src = inputs.topInputs.pocketfft; };
|
||||
|
||||
@@ -12,10 +12,11 @@ endif()
|
||||
find_package(biu REQUIRED)
|
||||
find_package(httplib REQUIRED)
|
||||
find_package(sqlgen REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
|
||||
add_executable(missgram src/main.cpp src/db.cpp src/tg.cpp)
|
||||
target_include_directories(missgram PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||
target_link_libraries(missgram PRIVATE biu::biu httplib::httplib sqlgen::sqlgen)
|
||||
target_link_libraries(missgram PRIVATE biu::biu httplib::httplib sqlgen::sqlgen nlohmann_json::nlohmann_json)
|
||||
target_compile_features(missgram PRIVATE cxx_std_23)
|
||||
if(DEFINED MISSGRAM_CONFIG_FILE)
|
||||
target_compile_definitions(missgram PRIVATE MISSGRAM_CONFIG_FILE="${MISSGRAM_CONFIG_FILE}")
|
||||
@@ -23,6 +24,15 @@ endif()
|
||||
target_compile_definitions(missgram PRIVATE BIU_LOGGER_SOURCE_ROOT="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
install(TARGETS missgram RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
add_executable(tg-test EXCLUDE_FROM_ALL src/tg.cpp src/tg-test.cpp)
|
||||
target_include_directories(tg-test PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||
target_link_libraries(tg-test PRIVATE biu::biu httplib::httplib nlohmann_json::nlohmann_json)
|
||||
target_compile_features(tg-test PRIVATE cxx_std_23)
|
||||
if(DEFINED MISSGRAM_CONFIG_FILE)
|
||||
target_compile_definitions(tg-test PRIVATE MISSGRAM_CONFIG_FILE="${MISSGRAM_CONFIG_FILE}")
|
||||
endif()
|
||||
target_compile_definitions(tg-test PRIVATE BIU_LOGGER_SOURCE_ROOT="${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
||||
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{ lib, stdenv, cmake, pkg-config, biu, configFile ? null, httplib, sqlgen }: stdenv.mkDerivation
|
||||
{ lib, stdenv, cmake, pkg-config, biu, configFile ? null, httplib, sqlgen, nlohmann_json }: stdenv.mkDerivation
|
||||
{
|
||||
name = "missgram";
|
||||
src = ./.;
|
||||
buildInputs = [ biu httplib sqlgen ];
|
||||
buildInputs = [ biu httplib sqlgen nlohmann_json ];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
cmakeFlags = lib.optional (configFile != null) [ "-DMISSGRAM_CONFIG_FILE=${configFile}" ];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace missgram
|
||||
std::int16_t ServerPort;
|
||||
std::string dbPassword;
|
||||
} inline config;
|
||||
struct File { std::string url; bool is_photo; bool should_hidden; };
|
||||
struct File { std::string name, url, type; bool isSensitive; };
|
||||
|
||||
void db_write(std::string misskey_note, std::int32_t telegram_message_id);
|
||||
std::optional<std::int32_t> db_read(std::string misskey_note);
|
||||
|
||||
@@ -39,7 +39,6 @@ int main()
|
||||
struct Renote { std::string id; };
|
||||
std::optional<Renote> renote;
|
||||
bool localOnly;
|
||||
struct File { bool isSensitive; std::string url; std::string type; };
|
||||
std::vector<File> files;
|
||||
};
|
||||
std::optional<Note> note;
|
||||
@@ -66,7 +65,7 @@ int main()
|
||||
// 否则(引用或普通帖子)
|
||||
else
|
||||
{
|
||||
text = *content.body.note->text;
|
||||
text = content.body.note->text.value_or("");
|
||||
// 如果有引用,则需要查找被引用的帖子是否已经被转发过,若是则直接回复被转发的消息。
|
||||
// 如果没有被转发过,则在开头附上链接
|
||||
if (content.body.note->renote)
|
||||
@@ -82,21 +81,9 @@ int main()
|
||||
text += "\n[在联邦宇宙查看]({}/notes/{})"_f(content.server, content.body.note->id);
|
||||
}
|
||||
|
||||
// 接下来整理要转发的文件
|
||||
auto files = content.body.note->files | ranges::views::transform([](auto&& file) -> File
|
||||
{
|
||||
return File
|
||||
{
|
||||
.url = file.url,
|
||||
.is_photo = file.type.starts_with("image/"),
|
||||
.should_hidden = file.isSensitive
|
||||
};
|
||||
}) | ranges::to_vector;
|
||||
|
||||
log();
|
||||
|
||||
// 异步发送消息
|
||||
std::thread([text, note_id = content.body.note->id, reply_id, files]
|
||||
std::thread([text, note_id = content.body.note->id, reply_id,
|
||||
files = content.body.note->files]
|
||||
{
|
||||
auto message_id = tg_send(text, reply_id, files);
|
||||
if (message_id) db_write(note_id, *message_id);
|
||||
|
||||
25
packages/missgram/src/tg-test.cpp
Normal file
25
packages/missgram/src/tg-test.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
# include <missgram.hpp>
|
||||
|
||||
# ifndef MISSGRAM_CONFIG_FILE
|
||||
# define MISSGRAM_CONFIG_FILE "./config.yaml"
|
||||
# endif
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace biu::literals;
|
||||
using namespace missgram;
|
||||
biu::Logger::Guard log;
|
||||
|
||||
config = YAML::LoadFile(MISSGRAM_CONFIG_FILE).as<Config>();
|
||||
// tg_send("aaaa", std::nullopt, {});
|
||||
// tg_send("aaaa", std::nullopt, {{"IMG20241013173523.jpg", "https://xn--s8w913fdga.chn.moe/files/3dd41113-4df5-4f34-a825-e4137d146172", "image/jpeg", false}});
|
||||
tg_send("aaaa", std::nullopt,
|
||||
{
|
||||
{"2026-01-07 22-02-22 1.png", "https://xn--s8w913fdga.chn.moe/files/a23d13ea-de37-4907-9d54-66417d7e0e36", "image/png", false}
|
||||
});
|
||||
// tg_send("aaaa", std::nullopt,
|
||||
// {
|
||||
// {"IMG20241013173523.jpg", "https://xn--s8w913fdga.chn.moe/files/// 3dd41113-4df5-4f34-a825-e4137d146172", "image/jpeg", true},
|
||||
// {"2026-01-07 22-02-22 1.png", "https://xn--s8w913fdga.chn.moe/files/// a23d13ea-de37-4907-9d54-66417d7e0e36", "image/png", false}
|
||||
// });
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
# include <missgram.hpp>
|
||||
# include <tgbot/tgbot.h>
|
||||
# include <httplib.h>
|
||||
# include <nlohmann/json.hpp>
|
||||
|
||||
std::optional<std::int32_t> missgram::tg_send
|
||||
(std::string text, std::optional<std::int32_t> replyId, std::vector<File> files)
|
||||
@@ -7,84 +8,120 @@ std::optional<std::int32_t> missgram::tg_send
|
||||
using namespace biu::literals;
|
||||
biu::Logger::Guard log;
|
||||
|
||||
// 整理要发送的信息
|
||||
TgBot::Bot bot(config.TelegramBotToken);
|
||||
std::shared_ptr<TgBot::ReplyParameters> reply;
|
||||
if (replyId) reply = std::make_shared<TgBot::ReplyParameters>(*replyId, config.TelegramChatId);
|
||||
auto attachs = files
|
||||
| ranges::views::transform([&](auto&& file) -> TgBot::InputMedia::Ptr
|
||||
{
|
||||
if (file.is_photo)
|
||||
{
|
||||
auto pic = std::make_shared<TgBot::InputMediaPhoto>();
|
||||
pic->media = file.url;
|
||||
pic->hasSpoiler = file.should_hidden;
|
||||
return pic;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto doc = std::make_shared<TgBot::InputMediaDocument>();
|
||||
doc->media = file.url;
|
||||
return doc;
|
||||
}
|
||||
})
|
||||
| ranges::to_vector;
|
||||
|
||||
// 多次尝试运行函数,直到成功或达到最大尝试次数(5次)
|
||||
auto try_run = [&](auto&& func) -> std::optional<std::int32_t>
|
||||
auto try_run = [&](auto&& func) -> std::optional<decltype(func())>
|
||||
{
|
||||
auto retry_delay = 1s;
|
||||
int attempts = 0;
|
||||
while (attempts < 5)
|
||||
{
|
||||
TgBot::Message::Ptr message;
|
||||
biu::Logger::try_exec([&] { message = func(); });
|
||||
if (message) return message->messageId;
|
||||
std::optional<decltype(func())> result;
|
||||
biu::Logger::try_exec([&] { result = func(); });
|
||||
if (result) return result;
|
||||
std::this_thread::sleep_for(retry_delay);
|
||||
retry_delay *= 2;
|
||||
attempts++;
|
||||
}
|
||||
return std::nullopt;
|
||||
return {};
|
||||
};
|
||||
|
||||
// 如果没有附件,使用 sendMessage 发送文本消息
|
||||
if (attachs.empty()) return try_run([&] { return bot.getApi().sendMessage
|
||||
(
|
||||
config.TelegramChatId, text, nullptr, reply, nullptr,
|
||||
"MarkdownV2"
|
||||
);});
|
||||
// 如果只有一个附件并且是图片,使用 sendPhoto 发送
|
||||
else if (attachs.size() == 1 && files[0].is_photo) return try_run([&]
|
||||
// 下载一个 https 资源到内存
|
||||
auto download = [&](const std::string& url) -> std::string
|
||||
{
|
||||
return bot.getApi().sendPhoto
|
||||
(
|
||||
config.TelegramChatId, files[0].url, text, reply,
|
||||
nullptr, "MarkdownV2", false, {}, 0, false, files[0].should_hidden
|
||||
);
|
||||
});
|
||||
// 如果有多个附件,使用 sendMediaGroup 分两条消息发送,返回第一条的 id
|
||||
std::regex https_regex(R"(https://([^/]+)(/.+))");
|
||||
std::smatch match;
|
||||
if (!std::regex_match(url, match, https_regex))
|
||||
throw std::runtime_error("Only https URLs are supported");
|
||||
httplib::SSLClient cli(match[1].str());
|
||||
auto res = cli.Get(match[2].str());
|
||||
if (res && res->status == 200) return res->body;
|
||||
else throw std::runtime_error("Failed to download file from " + url);
|
||||
};
|
||||
|
||||
// 下载要发送的文件
|
||||
std::vector<std::string> file_contents;
|
||||
for (const auto& file : files)
|
||||
{
|
||||
auto content = try_run([&] { return download(file.url); });
|
||||
if (!content) throw std::runtime_error("Failed to download file from " + file.url);
|
||||
file_contents.push_back(std::move(*content));
|
||||
}
|
||||
|
||||
// 准备要发送的请求
|
||||
httplib::UploadFormDataItems items;
|
||||
std::string method;
|
||||
if (files.empty())
|
||||
{
|
||||
method = "sendMessage";
|
||||
items.push_back({"text", text});
|
||||
items.push_back({"parse_mode", "Markdown"});
|
||||
items.push_back({"link_preview_options",
|
||||
[]{ nlohmann::json j; j["is_disabled"] = true; return j.dump(); }()});
|
||||
}
|
||||
else if (files.size() == 1)
|
||||
{
|
||||
auto is_photo = files[0].type.starts_with("image/");
|
||||
method = is_photo ? "sendPhoto" : "sendDocument";
|
||||
items.push_back
|
||||
({
|
||||
is_photo ? "photo" : "document",
|
||||
file_contents[0], files[0].name, files[0].type
|
||||
});
|
||||
items.push_back({"caption", text});
|
||||
items.push_back({"parse_mode", "Markdown"});
|
||||
if (is_photo && files[0].isSensitive) items.push_back({"has_spoiler", "True"});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto message = try_run([&] { return bot.getApi().sendMessage
|
||||
(
|
||||
config.TelegramChatId, text, nullptr, reply, nullptr,
|
||||
"MarkdownV2"
|
||||
);});
|
||||
if (message)
|
||||
method = "sendMediaGroup";
|
||||
auto all_photo = ranges::all_of(files,
|
||||
[](auto&& file) { return file.type.starts_with("image/"); });
|
||||
nlohmann::json media_group = files | ranges::views::enumerate | ranges::views::transform([&](auto&& file)
|
||||
{
|
||||
auto message2 = try_run([&] -> TgBot::Message::Ptr
|
||||
nlohmann::json params;
|
||||
if (all_photo)
|
||||
{
|
||||
auto msg = bot.getApi().sendMediaGroup
|
||||
(
|
||||
config.TelegramChatId, attachs, false,
|
||||
std::make_shared<TgBot::ReplyParameters>(*message, config.TelegramChatId)
|
||||
);
|
||||
if (msg.empty() || !ranges::all_of(msg, [](auto&& m) { return bool(m); }))
|
||||
return nullptr;
|
||||
else return msg[0];
|
||||
});
|
||||
if (!message2) return {};
|
||||
params["type"] = "photo";
|
||||
if (file.second.isSensitive) params["has_spoiler"] = true;
|
||||
}
|
||||
else params["type"] = "document";
|
||||
params["media"] = "attach://media-{}"_f(file.first);
|
||||
log.debug("Prepared media {}: {}"_f(file.first, params.dump()));
|
||||
if (file.first == 0) { params["caption"] = text; params["parse_mode"] = "Markdown"; }
|
||||
return params;
|
||||
}) | ranges::to_vector;
|
||||
items.push_back({"media", media_group.dump()});
|
||||
for (int i = 0; i < files.size(); i++) items.push_back
|
||||
({"media-{}"_f(i), file_contents[i], files[i].name, files[i].type});
|
||||
}
|
||||
items.push_back({"chat_id", std::to_string(config.TelegramChatId)});
|
||||
if (replyId) items.push_back({"reply_parameters", [&]
|
||||
{
|
||||
nlohmann::json j;
|
||||
j["message_id"] = *replyId;
|
||||
j["chat_id"] = config.TelegramChatId;
|
||||
return j.dump();
|
||||
}()});
|
||||
|
||||
httplib::Client cli("https://api.telegram.org");
|
||||
auto result = cli.Post("/bot{}/{}"_f(config.TelegramBotToken, method), items);
|
||||
log.debug("{} {} {}"_f(result->status, result->body, result->headers));
|
||||
if (result && result->status == 200)
|
||||
{
|
||||
auto json = nlohmann::json::parse(result->body);
|
||||
// 测试 js["result"]["message_id"] 是否存在且为整数
|
||||
if (json.contains("result") && json["result"].contains("message_id")
|
||||
&& json["result"]["message_id"].is_number_integer())
|
||||
return json["result"]["message_id"].get<std::int32_t>();
|
||||
else
|
||||
{
|
||||
log.error("Telegram API error: {}"_f(json.dump()));
|
||||
return {};
|
||||
}
|
||||
return message;
|
||||
}
|
||||
else
|
||||
{
|
||||
log.error("HTTP error: {}"_f(result ? std::to_string(result->status) : "No response"));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Submodule packages/ufo deleted from 19736049c9
Reference in New Issue
Block a user