Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
Cadey Ratio | 858949745e | |
Cadey Ratio | 398cd96934 | |
Cadey Ratio | 8501c8b61d | |
Cadey Ratio | 50d62d1283 | |
Cadey Ratio | ae305313eb | |
Cadey Ratio | 6095468e76 | |
Cadey Ratio | e92842da33 | |
Cadey Ratio | 364efb280c | |
Cadey Ratio | 6e3d49beb2 | |
Cadey Ratio | 3cb50f1c35 | |
Cadey Ratio | 19dd028c07 | |
Cadey Ratio | c78fb3dcb5 | |
Cadey Ratio | 310c018d0c | |
Cadey Ratio | 3de2d10f90 | |
Cadey Ratio | 722a99c8d9 | |
Cadey Ratio | b4d3cfe960 |
|
@ -2,6 +2,6 @@ kind: pipeline
|
|||
name: zbasu
|
||||
steps:
|
||||
- commands:
|
||||
- "nix-build ./cabytcini.nix"
|
||||
- "nix-build"
|
||||
image: "monacoremo/nix:2020-04-05-05f09348-circleci"
|
||||
name: zbasu le sampla
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# Changelog
|
||||
|
||||
## 0.3.0
|
||||
|
||||
- Rewrite using async rust
|
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "cabytcini"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Christine Dodrill <me@christine.website>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
|
@ -8,18 +8,12 @@ license = "MIT"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
chrono = "0.4"
|
||||
log = "0.4"
|
||||
env_logger = "0.7"
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
log = "0.4"
|
||||
serde_json = "1"
|
||||
serde = { version = "1", features = [ "derive" ] }
|
||||
toml = "0.5"
|
||||
xdg = "2.2"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.10"
|
||||
features = [ "blocking", "json" ]
|
||||
|
||||
[dependencies.x11]
|
||||
features = ["xlib"]
|
||||
version = "2.18.2"
|
||||
ureq = { version = "2", features = ["json", "charset"] }
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
"homepage": "",
|
||||
"owner": "nmattia",
|
||||
"repo": "naersk",
|
||||
"rev": "1dd63230066a93c61ab7a66934eb0aae3f1a3613",
|
||||
"sha256": "1xn8m62ypg13jh4zf101qmfa6gy8cl923fgwvk9c33m573h3k154",
|
||||
"rev": "e8061169e1495871b56be97c5c51d310fae01374",
|
||||
"sha256": "0683bdn7nvd63ziy09vm43iwpis4fdsj2hyk14hksz7igwrsy2g3",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/nmattia/naersk/archive/1dd63230066a93c61ab7a66934eb0aae3f1a3613.tar.gz",
|
||||
"url": "https://github.com/nmattia/naersk/archive/e8061169e1495871b56be97c5c51d310fae01374.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"niv": {
|
||||
|
@ -17,22 +17,22 @@
|
|||
"homepage": "https://github.com/nmattia/niv",
|
||||
"owner": "nmattia",
|
||||
"repo": "niv",
|
||||
"rev": "f73bf8d584148677b01859677a63191c31911eae",
|
||||
"sha256": "0jlmrx633jvqrqlyhlzpvdrnim128gc81q5psz2lpp2af8p8q9qs",
|
||||
"rev": "527494090f7075ed5e3aa15ef7093846e5e25d52",
|
||||
"sha256": "1hahf0i0iix1iyzaaq5a7rbgyfm3xjcfl69lm1b5mas1p8vdimih",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/nmattia/niv/archive/f73bf8d584148677b01859677a63191c31911eae.tar.gz",
|
||||
"url": "https://github.com/nmattia/niv/archive/527494090f7075ed5e3aa15ef7093846e5e25d52.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
},
|
||||
"nixpkgs": {
|
||||
"branch": "nixos-20.03",
|
||||
"branch": "nixpkgs-unstable",
|
||||
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
|
||||
"homepage": "https://github.com/NixOS/nixpkgs",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs-channels",
|
||||
"rev": "0bb35152be895abfd1fc743b42f1c4e56ae71906",
|
||||
"sha256": "0mydmhr1fm5l0p668wx5wlk3six7k3n56sz41fv0h9zms0lqszf9",
|
||||
"rev": "502845c3e31ef3de0e424f3fcb09217df2ce6df6",
|
||||
"sha256": "0fcqpsy6y7dgn0y0wgpa56gsg0b0p8avlpjrd79fp4mp9bl18nda",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs-channels/archive/0bb35152be895abfd1fc743b42f1c4e56ae71906.tar.gz",
|
||||
"url": "https://github.com/NixOS/nixpkgs-channels/archive/502845c3e31ef3de0e424f3fcb09217df2ce6df6.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
}
|
||||
}
|
||||
|
|
132
nix/sources.nix
132
nix/sources.nix
|
@ -6,52 +6,63 @@ let
|
|||
# The fetchers. fetch_<type> fetches specs of type <type>.
|
||||
#
|
||||
|
||||
fetch_file = pkgs: spec:
|
||||
if spec.builtin or true then
|
||||
builtins_fetchurl { inherit (spec) url sha256; }
|
||||
else
|
||||
pkgs.fetchurl { inherit (spec) url sha256; };
|
||||
fetch_file = pkgs: name: spec:
|
||||
let
|
||||
name' = sanitizeName name + "-src";
|
||||
in
|
||||
if spec.builtin or true then
|
||||
builtins_fetchurl { inherit (spec) url sha256; name = name'; }
|
||||
else
|
||||
pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
|
||||
|
||||
fetch_tarball = pkgs: spec:
|
||||
if spec.builtin or true then
|
||||
builtins_fetchTarball { inherit (spec) url sha256; }
|
||||
else
|
||||
pkgs.fetchzip { inherit (spec) url sha256; };
|
||||
fetch_tarball = pkgs: name: spec:
|
||||
let
|
||||
name' = sanitizeName name + "-src";
|
||||
in
|
||||
if spec.builtin or true then
|
||||
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
|
||||
else
|
||||
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
|
||||
|
||||
fetch_git = spec:
|
||||
builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
|
||||
fetch_git = name: spec:
|
||||
let
|
||||
ref =
|
||||
if spec ? ref then spec.ref else
|
||||
if spec ? branch then "refs/heads/${spec.branch}" else
|
||||
if spec ? tag then "refs/tags/${spec.tag}" else
|
||||
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
|
||||
in
|
||||
builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
|
||||
|
||||
fetch_builtin-tarball = spec:
|
||||
builtins.trace
|
||||
''
|
||||
WARNING:
|
||||
The niv type "builtin-tarball" will soon be deprecated. You should
|
||||
instead use `builtin = true`.
|
||||
fetch_local = spec: spec.path;
|
||||
|
||||
$ niv modify <package> -a type=tarball -a builtin=true
|
||||
''
|
||||
builtins_fetchTarball { inherit (spec) url sha256; };
|
||||
fetch_builtin-tarball = name: throw
|
||||
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
|
||||
$ niv modify ${name} -a type=tarball -a builtin=true'';
|
||||
|
||||
fetch_builtin-url = spec:
|
||||
builtins.trace
|
||||
''
|
||||
WARNING:
|
||||
The niv type "builtin-url" will soon be deprecated. You should
|
||||
instead use `builtin = true`.
|
||||
|
||||
$ niv modify <package> -a type=file -a builtin=true
|
||||
''
|
||||
(builtins_fetchurl { inherit (spec) url sha256; });
|
||||
fetch_builtin-url = name: throw
|
||||
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
|
||||
$ niv modify ${name} -a type=file -a builtin=true'';
|
||||
|
||||
#
|
||||
# Various helpers
|
||||
#
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
|
||||
sanitizeName = name:
|
||||
(
|
||||
concatMapStrings (s: if builtins.isList s then "-" else s)
|
||||
(
|
||||
builtins.split "[^[:alnum:]+._?=-]+"
|
||||
((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
|
||||
)
|
||||
);
|
||||
|
||||
# The set of packages used when specs are fetched using non-builtins.
|
||||
mkPkgs = sources:
|
||||
mkPkgs = sources: system:
|
||||
let
|
||||
sourcesNixpkgs =
|
||||
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
|
||||
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
|
||||
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
|
||||
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
|
||||
in
|
||||
|
@ -71,14 +82,27 @@ let
|
|||
|
||||
if ! builtins.hasAttr "type" spec then
|
||||
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
|
||||
else if spec.type == "file" then fetch_file pkgs spec
|
||||
else if spec.type == "tarball" then fetch_tarball pkgs spec
|
||||
else if spec.type == "git" then fetch_git spec
|
||||
else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
|
||||
else if spec.type == "builtin-url" then fetch_builtin-url spec
|
||||
else if spec.type == "file" then fetch_file pkgs name spec
|
||||
else if spec.type == "tarball" then fetch_tarball pkgs name spec
|
||||
else if spec.type == "git" then fetch_git name spec
|
||||
else if spec.type == "local" then fetch_local spec
|
||||
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
|
||||
else if spec.type == "builtin-url" then fetch_builtin-url name
|
||||
else
|
||||
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
|
||||
|
||||
# If the environment variable NIV_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
replace = name: drv:
|
||||
let
|
||||
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
|
||||
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
|
||||
in
|
||||
if ersatz == "" then drv else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}";
|
||||
|
||||
# Ports of functions for older nix versions
|
||||
|
||||
# a Nix version of mapAttrs if the built-in doesn't exist
|
||||
|
@ -87,23 +111,37 @@ let
|
|||
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
|
||||
);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatMapStrings = f: list: concatStrings (map f list);
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
|
||||
optionalAttrs = cond: as: if cond then as else {};
|
||||
|
||||
# fetchTarball version that is compatible between all the versions of Nix
|
||||
builtins_fetchTarball = { url, sha256 }@attrs:
|
||||
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
|
||||
let
|
||||
inherit (builtins) lessThan nixVersion fetchTarball;
|
||||
in
|
||||
if lessThan nixVersion "1.12" then
|
||||
fetchTarball { inherit url; }
|
||||
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||
else
|
||||
fetchTarball attrs;
|
||||
|
||||
# fetchurl version that is compatible between all the versions of Nix
|
||||
builtins_fetchurl = { url, sha256 }@attrs:
|
||||
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
|
||||
let
|
||||
inherit (builtins) lessThan nixVersion fetchurl;
|
||||
in
|
||||
if lessThan nixVersion "1.12" then
|
||||
fetchurl { inherit url; }
|
||||
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||
else
|
||||
fetchurl attrs;
|
||||
|
||||
|
@ -115,14 +153,15 @@ let
|
|||
then abort
|
||||
"The values in sources.json should not have an 'outPath' attribute"
|
||||
else
|
||||
spec // { outPath = fetch config.pkgs name spec; }
|
||||
spec // { outPath = replace name (fetch config.pkgs name spec); }
|
||||
) config.sources;
|
||||
|
||||
# The "config" used by the fetchers
|
||||
mkConfig =
|
||||
{ sourcesFile ? ./sources.json
|
||||
, sources ? builtins.fromJSON (builtins.readFile sourcesFile)
|
||||
, pkgs ? mkPkgs sources
|
||||
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
|
||||
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
|
||||
, system ? builtins.currentSystem
|
||||
, pkgs ? mkPkgs sources system
|
||||
}: rec {
|
||||
# The sources, i.e. the attribute set of spec name to spec
|
||||
inherit sources;
|
||||
|
@ -130,5 +169,6 @@ let
|
|||
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
|
||||
inherit pkgs;
|
||||
};
|
||||
|
||||
in
|
||||
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
use anyhow::Result;
|
||||
use cabytcini::*;
|
||||
use chrono::prelude::*;
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread, time,
|
||||
};
|
||||
|
||||
const UPDATE_FREQUENCY: u64 = 15000;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
println!(r#"{{ "version": 1 }}"#);
|
||||
println!("[[]");
|
||||
|
||||
let st: State = State::init();
|
||||
let mtst = Arc::new(Mutex::new(st));
|
||||
let cfg = config::load()?;
|
||||
|
||||
// start front thread
|
||||
{
|
||||
let mtst = mtst.clone();
|
||||
let cfg = cfg.clone();
|
||||
thread::spawn(move || front::update(mtst, cfg));
|
||||
}
|
||||
|
||||
// start weather thread
|
||||
{
|
||||
let mtst = mtst.clone();
|
||||
let cfg = cfg.clone();
|
||||
thread::spawn(move || weather::update(mtst, cfg));
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(750));
|
||||
|
||||
loop {
|
||||
{
|
||||
let data = mtst.lock().unwrap();
|
||||
let mut blocks: Vec<Block> = vec![Block {
|
||||
full_text: data.front.clone(),
|
||||
color: match data.front.as_str() {
|
||||
"Cadey" => Some("#F86AF3".to_string()),
|
||||
"Nicole" => Some("#C79DD7".to_string()),
|
||||
"Jessie" => Some("#97871A".to_string()),
|
||||
"Ashe" => Some("#458588".to_string()),
|
||||
"Sephie" => Some("#D79921".to_string()),
|
||||
"Mai" => Some("#D65D0E".to_string()),
|
||||
_ => None,
|
||||
},
|
||||
}];
|
||||
|
||||
if let Some(datni) = &data.weather {
|
||||
blocks.push(Block {
|
||||
full_text: format!(
|
||||
"{} {} / {} {}",
|
||||
datni.currently.temperature,
|
||||
datni.currently.summary,
|
||||
datni.daily.data[0].temperature_high,
|
||||
datni.daily.data[0].temperature_low
|
||||
),
|
||||
color: None,
|
||||
})
|
||||
}
|
||||
|
||||
blocks.push(Block {
|
||||
full_text: Local::now().format("%H:%M M%m %-d %a").to_string(),
|
||||
color: None,
|
||||
});
|
||||
|
||||
println!(",{}", serde_json::to_string(&blocks)?);
|
||||
}
|
||||
|
||||
let so_often = time::Duration::from_millis(UPDATE_FREQUENCY);
|
||||
thread::sleep(so_often);
|
||||
}
|
||||
}
|
|
@ -1,29 +1,26 @@
|
|||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Result, Write},
|
||||
io::{Read, Write},
|
||||
};
|
||||
use xdg::*;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub(crate) struct Config {
|
||||
pub struct Config {
|
||||
pub(crate) front_url: String,
|
||||
pub(crate) weather_url: String,
|
||||
}
|
||||
|
||||
pub(crate) fn load() -> Result<Config> {
|
||||
pub fn load() -> Result<Config> {
|
||||
let xdg_dirs =
|
||||
BaseDirectories::with_prefix("cabytcini").expect("pu djica lo nu finti lei datnyveiste");
|
||||
let config_path = xdg_dirs
|
||||
.place_config_file("gaftercu'a.toml")
|
||||
.expect("pu djica lo nu le datnyveiste be lo gaftercu'a zvati");
|
||||
let config_path = xdg_dirs.place_config_file("gaftercu'a.toml")?;
|
||||
match File::open(&config_path) {
|
||||
Ok(mut fin) => {
|
||||
let mut datni = String::new();
|
||||
fin.read_to_string(&mut datni)
|
||||
.expect("pu djica lo nu tcidu le sfaile");
|
||||
let cfg: Config =
|
||||
toml::from_str(datni.as_str()).expect("pu djica lo nu jimpe lo sfaile");
|
||||
fin.read_to_string(&mut datni)?;
|
||||
let cfg: Config = toml::from_str(datni.as_str())?;
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,15 @@ use std::{thread, time};
|
|||
|
||||
const FIVE_MINUTES: u64 = 60 * 5;
|
||||
|
||||
pub(crate) fn update(st: MTState, cfg: Config) {
|
||||
pub fn update(st: MTState, cfg: Config) {
|
||||
loop {
|
||||
match reqwest::blocking::get(&cfg.front_url) {
|
||||
match ureq::get(&cfg.front_url)
|
||||
.set("User-Agent", crate::APP_USER_AGENT)
|
||||
.call()
|
||||
{
|
||||
Ok(who) => {
|
||||
let mut data = st.lock().unwrap();
|
||||
let who = who.text().unwrap().trim().to_string();
|
||||
let who = who.into_string().unwrap().trim().to_string();
|
||||
if who != data.front {
|
||||
data.front = who;
|
||||
info!("new front: {}", data.front);
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
fmt,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use xsetroot::XSetRoot;
|
||||
|
||||
pub mod config;
|
||||
pub mod front;
|
||||
pub mod weather;
|
||||
pub mod xsetroot;
|
||||
|
||||
pub static APP_USER_AGENT: &str = concat!(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
" +https://tulpa.dev/cadey/cabytcini",
|
||||
);
|
||||
|
||||
pub type MTState = Arc<Mutex<State>>;
|
||||
|
||||
pub struct State {
|
||||
pub msg: String,
|
||||
pub front: String,
|
||||
pub weather: Option<weather::Root>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Default)]
|
||||
pub struct Block {
|
||||
pub full_text: String,
|
||||
pub color: Option<String>,
|
||||
}
|
||||
|
||||
impl fmt::Display for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn init() -> State {
|
||||
State {
|
||||
msg: "".to_string(),
|
||||
front: "".to_string(),
|
||||
weather: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
let now = Local::now().format("%H:%M M%m %-d %a");
|
||||
let mut msg = String::new();
|
||||
|
||||
if self.msg != "" {
|
||||
msg.push_str(format!("{} | ", self.msg).as_str());
|
||||
}
|
||||
|
||||
if self.front != "" {
|
||||
msg.push_str(format!("{} | ", self.front).as_str());
|
||||
}
|
||||
|
||||
match &self.weather {
|
||||
Some(datni) => msg.push_str(
|
||||
format!(
|
||||
"{} {} / {} {} | ",
|
||||
datni.currently.temperature,
|
||||
datni.currently.summary,
|
||||
datni.daily.data[0].temperature_high,
|
||||
datni.daily.data[0].temperature_low
|
||||
)
|
||||
.as_str(),
|
||||
),
|
||||
None => {}
|
||||
};
|
||||
|
||||
msg.push_str(format!("{}", now).as_str());
|
||||
msg
|
||||
}
|
||||
|
||||
pub fn xsetroot(&self) {
|
||||
let xsr = XSetRoot::init().expect("xsetroot to initialize");
|
||||
|
||||
if let Err(why) = xsr.render(self.to_string()) {
|
||||
error!("error setting root window title: {:?}", why);
|
||||
}
|
||||
}
|
||||
}
|
82
src/main.rs
82
src/main.rs
|
@ -1,29 +1,16 @@
|
|||
mod config;
|
||||
mod front;
|
||||
mod weather;
|
||||
mod xsetroot;
|
||||
|
||||
use chrono::prelude::*;
|
||||
use anyhow::Result;
|
||||
use log::*;
|
||||
use std::{
|
||||
fmt,
|
||||
io::{prelude::*, BufReader},
|
||||
net::Shutdown,
|
||||
os::unix::net::{UnixListener, UnixStream},
|
||||
sync::{Arc, Mutex},
|
||||
thread, time,
|
||||
};
|
||||
use xsetroot::XSetRoot;
|
||||
|
||||
// Name your user agent after your app?
|
||||
pub static APP_USER_AGENT: &str = concat!(
|
||||
env!("CARGO_PKG_NAME"),
|
||||
"/",
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
" +https://tulpa.dev/cadey/cabytcini",
|
||||
);
|
||||
use cabytcini::*;
|
||||
|
||||
pub(crate) type MTState = Arc<Mutex<State>>;
|
||||
pub type MTState = Arc<Mutex<State>>;
|
||||
|
||||
fn handle_client(stream: UnixStream, st: MTState) {
|
||||
let mut rdr = BufReader::new(&stream);
|
||||
|
@ -37,7 +24,7 @@ fn handle_client(stream: UnixStream, st: MTState) {
|
|||
stream.shutdown(Shutdown::Both).expect("socket to close");
|
||||
}
|
||||
|
||||
const UPDATE_FREQUENCY: u64 = 250;
|
||||
const UPDATE_FREQUENCY: u64 = 15000;
|
||||
|
||||
fn update_every_so_often(st: MTState) {
|
||||
loop {
|
||||
|
@ -46,14 +33,14 @@ fn update_every_so_often(st: MTState) {
|
|||
|
||||
{
|
||||
let data = st.lock().unwrap();
|
||||
data.show();
|
||||
data.xsetroot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
fn main() -> Result<()> {
|
||||
let st: State = State::init();
|
||||
st.show();
|
||||
st.xsetroot();
|
||||
let mtst = Arc::new(Mutex::new(st));
|
||||
env_logger::init();
|
||||
let cfg = config::load()?;
|
||||
|
@ -87,63 +74,10 @@ fn main() -> std::io::Result<()> {
|
|||
thread::spawn(move || handle_client(stream, mtst));
|
||||
}
|
||||
Err(err) => {
|
||||
error!("unix listener error: {:?}", err);
|
||||
break;
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) struct State {
|
||||
msg: String,
|
||||
front: String,
|
||||
weather: Option<weather::Root>,
|
||||
}
|
||||
|
||||
impl fmt::Display for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn init() -> State {
|
||||
State {
|
||||
msg: "".to_string(),
|
||||
front: "".to_string(),
|
||||
weather: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn show(&self) {
|
||||
let now = Local::now().format("%H:%M M%m %-d %a");
|
||||
let xsr = XSetRoot::init();
|
||||
|
||||
let mut msg = String::new();
|
||||
|
||||
if self.msg != "" {
|
||||
msg.push_str(format!("{} | ", self.msg).as_str());
|
||||
}
|
||||
|
||||
if self.front != "" {
|
||||
msg.push_str(format!("{} | ", self.front).as_str());
|
||||
}
|
||||
|
||||
match &self.weather {
|
||||
Some(datni) => msg.push_str(format!(
|
||||
"{} {} / {} {} | ",
|
||||
datni.currently.temperature,
|
||||
datni.currently.summary,
|
||||
datni.daily.data[0].temperature_high,
|
||||
datni.daily.data[0].temperature_low
|
||||
).as_str()),
|
||||
None => {}
|
||||
};
|
||||
|
||||
msg.push_str(format!("{}", now).as_str());
|
||||
|
||||
xsr.render(msg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{config::Config, MTState};
|
||||
use reqwest::blocking::*;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{thread, time};
|
||||
|
||||
|
@ -40,14 +40,16 @@ pub struct Daum {
|
|||
|
||||
const UPDATE_FREQUENCY: u64 = 15 * 60; // 15 minutes
|
||||
|
||||
fn get(cfg: &Config) -> reqwest::Result<Root> {
|
||||
let client = Client::builder().user_agent(crate::APP_USER_AGENT).build()?;
|
||||
let now: Root = client.get(&cfg.weather_url).send()?.json()?;
|
||||
fn get(cfg: &Config) -> Result<Root> {
|
||||
let now: Root = ureq::get(&cfg.weather_url)
|
||||
.set("User-Agent", crate::APP_USER_AGENT)
|
||||
.call()?
|
||||
.into_json()?;
|
||||
|
||||
Ok(now)
|
||||
}
|
||||
|
||||
pub(crate) fn update(st: MTState, cfg: Config) {
|
||||
pub fn update(st: MTState, cfg: Config) {
|
||||
loop {
|
||||
match get(&cfg) {
|
||||
Ok(datni) => {
|
||||
|
|
|
@ -1,53 +1,17 @@
|
|||
#![allow(unsafe_code)]
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr;
|
||||
use x11::xlib;
|
||||
use anyhow::Result;
|
||||
use std::process::Command;
|
||||
|
||||
pub(crate) struct XSetRoot {
|
||||
display: *mut xlib::Display,
|
||||
root_window: xlib::Window,
|
||||
}
|
||||
pub struct XSetRoot;
|
||||
|
||||
impl XSetRoot {
|
||||
pub(crate) fn init() -> Self {
|
||||
unsafe {
|
||||
let display = xlib::XOpenDisplay(ptr::null());
|
||||
|
||||
if display.is_null() {
|
||||
panic!("cannot open display");
|
||||
}
|
||||
|
||||
let screen = xlib::XDefaultScreen(display);
|
||||
let root_window = xlib::XRootWindow(display, screen);
|
||||
|
||||
Self {
|
||||
display,
|
||||
root_window,
|
||||
}
|
||||
}
|
||||
pub fn init() -> Result<Self> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
pub(crate) fn render(&self, text: String) {
|
||||
let status_c = CString::new(text).expect("status text could not be converted to CString");
|
||||
|
||||
unsafe {
|
||||
xlib::XStoreName(
|
||||
self.display,
|
||||
self.root_window,
|
||||
status_c.as_ptr() as *mut c_char,
|
||||
);
|
||||
|
||||
xlib::XFlush(self.display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XSetRoot {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
xlib::XCloseDisplay(self.display);
|
||||
}
|
||||
pub fn render(&self, text: String) -> Result<()> {
|
||||
Command::new("xsetroot").arg("-name").arg(text).output()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue