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
|
name: zbasu
|
||||||
steps:
|
steps:
|
||||||
- commands:
|
- commands:
|
||||||
- "nix-build ./cabytcini.nix"
|
- "nix-build"
|
||||||
image: "monacoremo/nix:2020-04-05-05f09348-circleci"
|
image: "monacoremo/nix:2020-04-05-05f09348-circleci"
|
||||||
name: zbasu le sampla
|
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]
|
[package]
|
||||||
name = "cabytcini"
|
name = "cabytcini"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
authors = ["Christine Dodrill <me@christine.website>"]
|
authors = ["Christine Dodrill <me@christine.website>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -8,18 +8,12 @@ license = "MIT"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
log = "0.4"
|
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
log = "0.4"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
xdg = "2.2"
|
xdg = "2.2"
|
||||||
|
ureq = { version = "2", features = ["json", "charset"] }
|
||||||
[dependencies.reqwest]
|
|
||||||
version = "0.10"
|
|
||||||
features = [ "blocking", "json" ]
|
|
||||||
|
|
||||||
[dependencies.x11]
|
|
||||||
features = ["xlib"]
|
|
||||||
version = "2.18.2"
|
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
"homepage": "",
|
"homepage": "",
|
||||||
"owner": "nmattia",
|
"owner": "nmattia",
|
||||||
"repo": "naersk",
|
"repo": "naersk",
|
||||||
"rev": "1dd63230066a93c61ab7a66934eb0aae3f1a3613",
|
"rev": "e8061169e1495871b56be97c5c51d310fae01374",
|
||||||
"sha256": "1xn8m62ypg13jh4zf101qmfa6gy8cl923fgwvk9c33m573h3k154",
|
"sha256": "0683bdn7nvd63ziy09vm43iwpis4fdsj2hyk14hksz7igwrsy2g3",
|
||||||
"type": "tarball",
|
"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"
|
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||||
},
|
},
|
||||||
"niv": {
|
"niv": {
|
||||||
|
@ -17,22 +17,22 @@
|
||||||
"homepage": "https://github.com/nmattia/niv",
|
"homepage": "https://github.com/nmattia/niv",
|
||||||
"owner": "nmattia",
|
"owner": "nmattia",
|
||||||
"repo": "niv",
|
"repo": "niv",
|
||||||
"rev": "f73bf8d584148677b01859677a63191c31911eae",
|
"rev": "527494090f7075ed5e3aa15ef7093846e5e25d52",
|
||||||
"sha256": "0jlmrx633jvqrqlyhlzpvdrnim128gc81q5psz2lpp2af8p8q9qs",
|
"sha256": "1hahf0i0iix1iyzaaq5a7rbgyfm3xjcfl69lm1b5mas1p8vdimih",
|
||||||
"type": "tarball",
|
"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"
|
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"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",
|
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
|
||||||
"homepage": "https://github.com/NixOS/nixpkgs",
|
"homepage": "https://github.com/NixOS/nixpkgs",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs-channels",
|
"repo": "nixpkgs-channels",
|
||||||
"rev": "0bb35152be895abfd1fc743b42f1c4e56ae71906",
|
"rev": "502845c3e31ef3de0e424f3fcb09217df2ce6df6",
|
||||||
"sha256": "0mydmhr1fm5l0p668wx5wlk3six7k3n56sz41fv0h9zms0lqszf9",
|
"sha256": "0fcqpsy6y7dgn0y0wgpa56gsg0b0p8avlpjrd79fp4mp9bl18nda",
|
||||||
"type": "tarball",
|
"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"
|
"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>.
|
# The fetchers. fetch_<type> fetches specs of type <type>.
|
||||||
#
|
#
|
||||||
|
|
||||||
fetch_file = pkgs: spec:
|
fetch_file = pkgs: name: spec:
|
||||||
if spec.builtin or true then
|
let
|
||||||
builtins_fetchurl { inherit (spec) url sha256; }
|
name' = sanitizeName name + "-src";
|
||||||
else
|
in
|
||||||
pkgs.fetchurl { inherit (spec) url sha256; };
|
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:
|
fetch_tarball = pkgs: name: spec:
|
||||||
if spec.builtin or true then
|
let
|
||||||
builtins_fetchTarball { inherit (spec) url sha256; }
|
name' = sanitizeName name + "-src";
|
||||||
else
|
in
|
||||||
pkgs.fetchzip { inherit (spec) url sha256; };
|
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:
|
fetch_git = name: spec:
|
||||||
builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
|
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:
|
fetch_local = spec: spec.path;
|
||||||
builtins.trace
|
|
||||||
''
|
|
||||||
WARNING:
|
|
||||||
The niv type "builtin-tarball" will soon be deprecated. You should
|
|
||||||
instead use `builtin = true`.
|
|
||||||
|
|
||||||
$ niv modify <package> -a type=tarball -a builtin=true
|
fetch_builtin-tarball = name: throw
|
||||||
''
|
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
|
||||||
builtins_fetchTarball { inherit (spec) url sha256; };
|
$ niv modify ${name} -a type=tarball -a builtin=true'';
|
||||||
|
|
||||||
fetch_builtin-url = spec:
|
fetch_builtin-url = name: throw
|
||||||
builtins.trace
|
''[${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'';
|
||||||
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; });
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Various helpers
|
# 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.
|
# The set of packages used when specs are fetched using non-builtins.
|
||||||
mkPkgs = sources:
|
mkPkgs = sources: system:
|
||||||
let
|
let
|
||||||
sourcesNixpkgs =
|
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;
|
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
|
||||||
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
|
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
|
||||||
in
|
in
|
||||||
|
@ -71,14 +82,27 @@ let
|
||||||
|
|
||||||
if ! builtins.hasAttr "type" spec then
|
if ! builtins.hasAttr "type" spec then
|
||||||
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
|
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 == "file" then fetch_file pkgs name spec
|
||||||
else if spec.type == "tarball" then fetch_tarball pkgs spec
|
else if spec.type == "tarball" then fetch_tarball pkgs name spec
|
||||||
else if spec.type == "git" then fetch_git spec
|
else if spec.type == "git" then fetch_git name spec
|
||||||
else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
|
else if spec.type == "local" then fetch_local spec
|
||||||
else if spec.type == "builtin-url" then fetch_builtin-url spec
|
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
|
||||||
|
else if spec.type == "builtin-url" then fetch_builtin-url name
|
||||||
else
|
else
|
||||||
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
|
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
|
# Ports of functions for older nix versions
|
||||||
|
|
||||||
# a Nix version of mapAttrs if the built-in doesn't exist
|
# 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))
|
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
|
# fetchTarball version that is compatible between all the versions of Nix
|
||||||
builtins_fetchTarball = { url, sha256 }@attrs:
|
builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
|
||||||
let
|
let
|
||||||
inherit (builtins) lessThan nixVersion fetchTarball;
|
inherit (builtins) lessThan nixVersion fetchTarball;
|
||||||
in
|
in
|
||||||
if lessThan nixVersion "1.12" then
|
if lessThan nixVersion "1.12" then
|
||||||
fetchTarball { inherit url; }
|
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||||
else
|
else
|
||||||
fetchTarball attrs;
|
fetchTarball attrs;
|
||||||
|
|
||||||
# fetchurl version that is compatible between all the versions of Nix
|
# fetchurl version that is compatible between all the versions of Nix
|
||||||
builtins_fetchurl = { url, sha256 }@attrs:
|
builtins_fetchurl = { url, name ? null, sha256 }@attrs:
|
||||||
let
|
let
|
||||||
inherit (builtins) lessThan nixVersion fetchurl;
|
inherit (builtins) lessThan nixVersion fetchurl;
|
||||||
in
|
in
|
||||||
if lessThan nixVersion "1.12" then
|
if lessThan nixVersion "1.12" then
|
||||||
fetchurl { inherit url; }
|
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
|
||||||
else
|
else
|
||||||
fetchurl attrs;
|
fetchurl attrs;
|
||||||
|
|
||||||
|
@ -115,14 +153,15 @@ let
|
||||||
then abort
|
then abort
|
||||||
"The values in sources.json should not have an 'outPath' attribute"
|
"The values in sources.json should not have an 'outPath' attribute"
|
||||||
else
|
else
|
||||||
spec // { outPath = fetch config.pkgs name spec; }
|
spec // { outPath = replace name (fetch config.pkgs name spec); }
|
||||||
) config.sources;
|
) config.sources;
|
||||||
|
|
||||||
# The "config" used by the fetchers
|
# The "config" used by the fetchers
|
||||||
mkConfig =
|
mkConfig =
|
||||||
{ sourcesFile ? ./sources.json
|
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
|
||||||
, sources ? builtins.fromJSON (builtins.readFile sourcesFile)
|
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
|
||||||
, pkgs ? mkPkgs sources
|
, system ? builtins.currentSystem
|
||||||
|
, pkgs ? mkPkgs sources system
|
||||||
}: rec {
|
}: rec {
|
||||||
# The sources, i.e. the attribute set of spec name to spec
|
# The sources, i.e. the attribute set of spec name to spec
|
||||||
inherit sources;
|
inherit sources;
|
||||||
|
@ -130,5 +169,6 @@ let
|
||||||
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
|
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
|
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 serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Result, Write},
|
io::{Read, Write},
|
||||||
};
|
};
|
||||||
use xdg::*;
|
use xdg::*;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub(crate) struct Config {
|
pub struct Config {
|
||||||
pub(crate) front_url: String,
|
pub(crate) front_url: String,
|
||||||
pub(crate) weather_url: String,
|
pub(crate) weather_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn load() -> Result<Config> {
|
pub fn load() -> Result<Config> {
|
||||||
let xdg_dirs =
|
let xdg_dirs =
|
||||||
BaseDirectories::with_prefix("cabytcini").expect("pu djica lo nu finti lei datnyveiste");
|
BaseDirectories::with_prefix("cabytcini").expect("pu djica lo nu finti lei datnyveiste");
|
||||||
let config_path = xdg_dirs
|
let config_path = xdg_dirs.place_config_file("gaftercu'a.toml")?;
|
||||||
.place_config_file("gaftercu'a.toml")
|
|
||||||
.expect("pu djica lo nu le datnyveiste be lo gaftercu'a zvati");
|
|
||||||
match File::open(&config_path) {
|
match File::open(&config_path) {
|
||||||
Ok(mut fin) => {
|
Ok(mut fin) => {
|
||||||
let mut datni = String::new();
|
let mut datni = String::new();
|
||||||
fin.read_to_string(&mut datni)
|
fin.read_to_string(&mut datni)?;
|
||||||
.expect("pu djica lo nu tcidu le sfaile");
|
let cfg: Config = toml::from_str(datni.as_str())?;
|
||||||
let cfg: Config =
|
|
||||||
toml::from_str(datni.as_str()).expect("pu djica lo nu jimpe lo sfaile");
|
|
||||||
Ok(cfg)
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,15 @@ use std::{thread, time};
|
||||||
|
|
||||||
const FIVE_MINUTES: u64 = 60 * 5;
|
const FIVE_MINUTES: u64 = 60 * 5;
|
||||||
|
|
||||||
pub(crate) fn update(st: MTState, cfg: Config) {
|
pub fn update(st: MTState, cfg: Config) {
|
||||||
loop {
|
loop {
|
||||||
match reqwest::blocking::get(&cfg.front_url) {
|
match ureq::get(&cfg.front_url)
|
||||||
|
.set("User-Agent", crate::APP_USER_AGENT)
|
||||||
|
.call()
|
||||||
|
{
|
||||||
Ok(who) => {
|
Ok(who) => {
|
||||||
let mut data = st.lock().unwrap();
|
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 {
|
if who != data.front {
|
||||||
data.front = who;
|
data.front = who;
|
||||||
info!("new front: {}", data.front);
|
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;
|
use anyhow::Result;
|
||||||
mod front;
|
|
||||||
mod weather;
|
|
||||||
mod xsetroot;
|
|
||||||
|
|
||||||
use chrono::prelude::*;
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
|
||||||
io::{prelude::*, BufReader},
|
io::{prelude::*, BufReader},
|
||||||
net::Shutdown,
|
net::Shutdown,
|
||||||
os::unix::net::{UnixListener, UnixStream},
|
os::unix::net::{UnixListener, UnixStream},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread, time,
|
thread, time,
|
||||||
};
|
};
|
||||||
use xsetroot::XSetRoot;
|
|
||||||
|
|
||||||
// Name your user agent after your app?
|
use cabytcini::*;
|
||||||
pub static APP_USER_AGENT: &str = concat!(
|
|
||||||
env!("CARGO_PKG_NAME"),
|
|
||||||
"/",
|
|
||||||
env!("CARGO_PKG_VERSION"),
|
|
||||||
" +https://tulpa.dev/cadey/cabytcini",
|
|
||||||
);
|
|
||||||
|
|
||||||
pub(crate) type MTState = Arc<Mutex<State>>;
|
pub type MTState = Arc<Mutex<State>>;
|
||||||
|
|
||||||
fn handle_client(stream: UnixStream, st: MTState) {
|
fn handle_client(stream: UnixStream, st: MTState) {
|
||||||
let mut rdr = BufReader::new(&stream);
|
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");
|
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) {
|
fn update_every_so_often(st: MTState) {
|
||||||
loop {
|
loop {
|
||||||
|
@ -46,14 +33,14 @@ fn update_every_so_often(st: MTState) {
|
||||||
|
|
||||||
{
|
{
|
||||||
let data = st.lock().unwrap();
|
let data = st.lock().unwrap();
|
||||||
data.show();
|
data.xsetroot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> Result<()> {
|
||||||
let st: State = State::init();
|
let st: State = State::init();
|
||||||
st.show();
|
st.xsetroot();
|
||||||
let mtst = Arc::new(Mutex::new(st));
|
let mtst = Arc::new(Mutex::new(st));
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let cfg = config::load()?;
|
let cfg = config::load()?;
|
||||||
|
@ -87,63 +74,10 @@ fn main() -> std::io::Result<()> {
|
||||||
thread::spawn(move || handle_client(stream, mtst));
|
thread::spawn(move || handle_client(stream, mtst));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("unix listener error: {:?}", err);
|
return Err(err.into());
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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 crate::{config::Config, MTState};
|
||||||
use reqwest::blocking::*;
|
use anyhow::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
|
|
||||||
|
@ -40,14 +40,16 @@ pub struct Daum {
|
||||||
|
|
||||||
const UPDATE_FREQUENCY: u64 = 15 * 60; // 15 minutes
|
const UPDATE_FREQUENCY: u64 = 15 * 60; // 15 minutes
|
||||||
|
|
||||||
fn get(cfg: &Config) -> reqwest::Result<Root> {
|
fn get(cfg: &Config) -> Result<Root> {
|
||||||
let client = Client::builder().user_agent(crate::APP_USER_AGENT).build()?;
|
let now: Root = ureq::get(&cfg.weather_url)
|
||||||
let now: Root = client.get(&cfg.weather_url).send()?.json()?;
|
.set("User-Agent", crate::APP_USER_AGENT)
|
||||||
|
.call()?
|
||||||
|
.into_json()?;
|
||||||
|
|
||||||
Ok(now)
|
Ok(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update(st: MTState, cfg: Config) {
|
pub fn update(st: MTState, cfg: Config) {
|
||||||
loop {
|
loop {
|
||||||
match get(&cfg) {
|
match get(&cfg) {
|
||||||
Ok(datni) => {
|
Ok(datni) => {
|
||||||
|
|
|
@ -1,53 +1,17 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use std::ffi::CString;
|
use anyhow::Result;
|
||||||
use std::os::raw::c_char;
|
use std::process::Command;
|
||||||
use std::ptr;
|
|
||||||
use x11::xlib;
|
|
||||||
|
|
||||||
pub(crate) struct XSetRoot {
|
pub struct XSetRoot;
|
||||||
display: *mut xlib::Display,
|
|
||||||
root_window: xlib::Window,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XSetRoot {
|
impl XSetRoot {
|
||||||
pub(crate) fn init() -> Self {
|
pub fn init() -> Result<Self> {
|
||||||
unsafe {
|
Ok(Self {})
|
||||||
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(crate) fn render(&self, text: String) {
|
pub fn render(&self, text: String) -> Result<()> {
|
||||||
let status_c = CString::new(text).expect("status text could not be converted to CString");
|
Command::new("xsetroot").arg("-name").arg(text).output()?;
|
||||||
|
Ok(())
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue