Compare commits
	
		
			25 Commits
		
	
	
		
			main
			...
			rust_rewri
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 50520bb1b8 | |||
| 1edaf643c9 | |||
| 026a68364b | |||
| 9f53240807 | |||
| 6dd22fe0c3 | |||
| 5b3b89ec4c | |||
| 50782cd512 | |||
| bd40dfe44a | |||
| 8349316169 | |||
| 7f6920507c | |||
| 19aee664c2 | |||
| 43a07debde | |||
| 8693e10979 | |||
| 7f22334f0e | |||
| 3b107f09cd | |||
| 08eca1a2d0 | |||
| 208eed348b | |||
| 85891abba0 | |||
| 793ed4d730 | |||
| c816c1025e | |||
| 213fbe31e2 | |||
| ca71830262 | |||
| f55279b7ef | |||
| 407faab33a | |||
| 35cb20545c | 
							
								
								
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
modules/*
 | 
			
		||||
.cache/
 | 
			
		||||
dim
 | 
			
		||||
/target
 | 
			
		||||
/plugins
 | 
			
		||||
/.cache
 | 
			
		||||
/config/*
 | 
			
		||||
!/config/main.template.toml
 | 
			
		||||
compile_commands.json
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										787
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										787
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,787 @@
 | 
			
		|||
# This file is automatically @generated by Cargo.
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
version = 3
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aho-corasick"
 | 
			
		||||
version = "1.1.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "android-tzdata"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "android_system_properties"
 | 
			
		||||
version = "0.1.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anstream"
 | 
			
		||||
version = "0.6.14"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstyle",
 | 
			
		||||
 "anstyle-parse",
 | 
			
		||||
 "anstyle-query",
 | 
			
		||||
 "anstyle-wincon",
 | 
			
		||||
 "colorchoice",
 | 
			
		||||
 "is_terminal_polyfill",
 | 
			
		||||
 "utf8parse",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anstyle"
 | 
			
		||||
version = "1.0.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anstyle-parse"
 | 
			
		||||
version = "0.2.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "utf8parse",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anstyle-query"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anstyle-wincon"
 | 
			
		||||
version = "3.0.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstyle",
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "anyhow"
 | 
			
		||||
version = "1.0.86"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "autocfg"
 | 
			
		||||
version = "1.3.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "battery"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "dim_sdk",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bumpalo"
 | 
			
		||||
version = "3.16.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bytes"
 | 
			
		||||
version = "1.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "camino"
 | 
			
		||||
version = "1.1.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cc"
 | 
			
		||||
version = "1.0.99"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "cfg-if"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "chrono"
 | 
			
		||||
version = "0.4.38"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "android-tzdata",
 | 
			
		||||
 "iana-time-zone",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap"
 | 
			
		||||
version = "4.5.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap_builder",
 | 
			
		||||
 "clap_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_builder"
 | 
			
		||||
version = "4.5.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstream",
 | 
			
		||||
 "anstyle",
 | 
			
		||||
 "clap_lex",
 | 
			
		||||
 "strsim",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_derive"
 | 
			
		||||
version = "4.5.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "heck",
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "syn 2.0.66",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_lex"
 | 
			
		||||
version = "0.7.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clock"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "dim_sdk",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "colorchoice"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "core-foundation-sys"
 | 
			
		||||
version = "0.8.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "counter"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "dim_sdk",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dim"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "camino",
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "clap",
 | 
			
		||||
 "dlopen",
 | 
			
		||||
 "dlopen_derive",
 | 
			
		||||
 "env_logger",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "log",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "toml",
 | 
			
		||||
 "x11",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dim_sdk"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dlopen"
 | 
			
		||||
version = "0.1.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "dlopen_derive",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dlopen_derive"
 | 
			
		||||
version = "0.1.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
 "quote 0.6.13",
 | 
			
		||||
 "syn 0.15.44",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "env_filter"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "log",
 | 
			
		||||
 "regex",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "env_logger"
 | 
			
		||||
version = "0.11.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstream",
 | 
			
		||||
 "anstyle",
 | 
			
		||||
 "env_filter",
 | 
			
		||||
 "humantime",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "equivalent"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "example_rust"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "dim_sdk",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hashbrown"
 | 
			
		||||
version = "0.14.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "heck"
 | 
			
		||||
version = "0.5.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "humantime"
 | 
			
		||||
version = "2.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "iana-time-zone"
 | 
			
		||||
version = "0.1.60"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "android_system_properties",
 | 
			
		||||
 "core-foundation-sys",
 | 
			
		||||
 "iana-time-zone-haiku",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "windows-core",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "iana-time-zone-haiku"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "indexmap"
 | 
			
		||||
version = "2.2.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "equivalent",
 | 
			
		||||
 "hashbrown",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "is_terminal_polyfill"
 | 
			
		||||
version = "1.70.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "js-sys"
 | 
			
		||||
version = "0.3.69"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "lazy_static"
 | 
			
		||||
version = "1.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "spin",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "libc"
 | 
			
		||||
version = "0.2.155"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "log"
 | 
			
		||||
version = "0.4.21"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memchr"
 | 
			
		||||
version = "2.7.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-traits"
 | 
			
		||||
version = "0.2.19"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "once_cell"
 | 
			
		||||
version = "1.19.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pkg-config"
 | 
			
		||||
version = "0.3.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "proc-macro2"
 | 
			
		||||
version = "0.4.30"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-xid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "proc-macro2"
 | 
			
		||||
version = "1.0.85"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "unicode-ident",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quote"
 | 
			
		||||
version = "0.6.13"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 0.4.30",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "quote"
 | 
			
		||||
version = "1.0.36"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex"
 | 
			
		||||
version = "1.10.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "regex-automata",
 | 
			
		||||
 "regex-syntax",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex-automata"
 | 
			
		||||
version = "0.4.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "regex-syntax",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "regex-syntax"
 | 
			
		||||
version = "0.8.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.203"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.203"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "syn 2.0.66",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_spanned"
 | 
			
		||||
version = "0.6.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "spin"
 | 
			
		||||
version = "0.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "strsim"
 | 
			
		||||
version = "0.11.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "syn"
 | 
			
		||||
version = "0.15.44"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 0.4.30",
 | 
			
		||||
 "quote 0.6.13",
 | 
			
		||||
 "unicode-xid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "syn"
 | 
			
		||||
version = "2.0.66"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "unicode-ident",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "toml"
 | 
			
		||||
version = "0.8.14"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_spanned",
 | 
			
		||||
 "toml_datetime",
 | 
			
		||||
 "toml_edit",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "toml_datetime"
 | 
			
		||||
version = "0.6.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "toml_edit"
 | 
			
		||||
version = "0.22.14"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "indexmap",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_spanned",
 | 
			
		||||
 "toml_datetime",
 | 
			
		||||
 "winnow",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-ident"
 | 
			
		||||
version = "1.0.12"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-xid"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "utf8parse"
 | 
			
		||||
version = "0.2.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "volume"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "dim_sdk",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "log",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "toml",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "wasm-bindgen-macro",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen-backend"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bumpalo",
 | 
			
		||||
 "log",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "syn 2.0.66",
 | 
			
		||||
 "wasm-bindgen-shared",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen-macro"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "wasm-bindgen-macro-support",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen-macro-support"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2 1.0.85",
 | 
			
		||||
 "quote 1.0.36",
 | 
			
		||||
 "syn 2.0.66",
 | 
			
		||||
 "wasm-bindgen-backend",
 | 
			
		||||
 "wasm-bindgen-shared",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen-shared"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi"
 | 
			
		||||
version = "0.3.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi-i686-pc-windows-gnu",
 | 
			
		||||
 "winapi-x86_64-pc-windows-gnu",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-i686-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-x86_64-pc-windows-gnu"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-core"
 | 
			
		||||
version = "0.52.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-sys"
 | 
			
		||||
version = "0.52.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-targets"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows_aarch64_gnullvm",
 | 
			
		||||
 "windows_aarch64_msvc",
 | 
			
		||||
 "windows_i686_gnu",
 | 
			
		||||
 "windows_i686_gnullvm",
 | 
			
		||||
 "windows_i686_msvc",
 | 
			
		||||
 "windows_x86_64_gnu",
 | 
			
		||||
 "windows_x86_64_gnullvm",
 | 
			
		||||
 "windows_x86_64_msvc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_aarch64_gnullvm"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_aarch64_msvc"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_i686_gnu"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_i686_gnullvm"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_i686_msvc"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_x86_64_gnu"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_x86_64_gnullvm"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows_x86_64_msvc"
 | 
			
		||||
version = "0.52.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winnow"
 | 
			
		||||
version = "0.6.13"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "x11"
 | 
			
		||||
version = "2.21.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
 "pkg-config",
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										30
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
[workspace]
 | 
			
		||||
members = [ 
 | 
			
		||||
    "sdk/rust/dim_sdk",
 | 
			
		||||
    "dim_plugins/example_rust", 
 | 
			
		||||
    "dim_plugins/clock", 
 | 
			
		||||
    "dim_plugins/counter", 
 | 
			
		||||
    "dim_plugins/battery", 
 | 
			
		||||
    "dim_plugins/volume", 
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[package]
 | 
			
		||||
name = "dim"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
camino = "1.1.7"
 | 
			
		||||
chrono = "0.4.38"
 | 
			
		||||
clap = { version = "4.5.7", features = ["derive"] }
 | 
			
		||||
dlopen = "0.1.8"
 | 
			
		||||
dlopen_derive = "0.1.4"
 | 
			
		||||
env_logger = "0.11.3"
 | 
			
		||||
libc = "0.2.155"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
serde = { version = "1.0.203", features = ["derive"] }
 | 
			
		||||
toml = "0.8.14"
 | 
			
		||||
x11 = { version = "2.21.0", features = ["xlib"] }
 | 
			
		||||
							
								
								
									
										38
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								Makefile
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,21 +1,33 @@
 | 
			
		|||
BIN=./dim
 | 
			
		||||
CC=gcc
 | 
			
		||||
CCARGS=-Isrc/include -Wall -pedantic
 | 
			
		||||
 | 
			
		||||
MODULES= \
 | 
			
		||||
		modules/clock.dim   \
 | 
			
		||||
		modules/battery.dim \
 | 
			
		||||
		modules/timesince.dim
 | 
			
		||||
CWD := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
all: $(BIN) $(MODULES) compile_commands.json
 | 
			
		||||
PLUGIN_DIR   = ${CWD}plugins
 | 
			
		||||
OBJECT_DIR   = $(CWD)target/objects
 | 
			
		||||
BUILD_DIR    = $(CWD)target
 | 
			
		||||
DIM_CC_FLAGS = -I$(CWD)sdk/c_cxx 
 | 
			
		||||
DIM_CC       = gcc
 | 
			
		||||
 | 
			
		||||
$(BIN): src/main.c src/plug.c src/socket.c src/util.c
 | 
			
		||||
	$(CC) -o $@ $^ $(CCARGS) -lX11 -ldl
 | 
			
		||||
BIN=$(BUILD_DIR)/dim
 | 
			
		||||
 | 
			
		||||
PLUGINS=$(wildcard dim_plugins/**/Makefile)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
modules/%.dim: src/modules/%.c
 | 
			
		||||
	$(CC) -o $@ $^ -rdynamic -shared -fPIC $(CCARGS)
 | 
			
		||||
all: $(BIN) $(PLUGINS) compile_commands.json
 | 
			
		||||
 | 
			
		||||
$(BIN): target/release/dim
 | 
			
		||||
	cp $< $@
 | 
			
		||||
 | 
			
		||||
target/release/dim:
 | 
			
		||||
	cargo build --release
 | 
			
		||||
 | 
			
		||||
dim_plugins/%/Makefile:
 | 
			
		||||
	@$(MAKE) -C $(dir $@) \
 | 
			
		||||
		-E "PLUGIN_DIR=$(PLUGIN_DIR)"     \
 | 
			
		||||
		-E "OBJECT_DIR=$(OBJECT_DIR)"     \
 | 
			
		||||
		-E "BUILD_DIR=$(BUILD_DIR)"       \
 | 
			
		||||
		-E "DIM_CC_FLAGS=$(DIM_CC_FLAGS)" \
 | 
			
		||||
		-E "DIM_CC=$(DIM_CC)"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
compile_commands.json:
 | 
			
		||||
	compiledb -n make
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								compile_commands.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								compile_commands.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
[
 | 
			
		||||
 {
 | 
			
		||||
  "directory": "/home/mcorange/.dwm/sources/dim/dim_plugins/example_c",
 | 
			
		||||
  "arguments": [
 | 
			
		||||
   "gcc",
 | 
			
		||||
   "-c",
 | 
			
		||||
   "-o",
 | 
			
		||||
   "/home/mcorange/.dwm/sources/dim/target/objects/example_c/main.o",
 | 
			
		||||
   "src/main.c",
 | 
			
		||||
   "-pie",
 | 
			
		||||
   "-I/home/mcorange/.dwm/sources/dim/sdk/c_cxx",
 | 
			
		||||
   "-fPIC"
 | 
			
		||||
  ],
 | 
			
		||||
  "file": "src/main.c"
 | 
			
		||||
 }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										9
									
								
								config/main.template.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config/main.template.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
refresh_ms=100
 | 
			
		||||
sock_path="~/dim.sock" # must be full path
 | 
			
		||||
seperator=" | "
 | 
			
		||||
 | 
			
		||||
[plugins]
 | 
			
		||||
path="./plugins"
 | 
			
		||||
blacklist=["example_c", "example_rust"]
 | 
			
		||||
as_whitelist=false
 | 
			
		||||
template=["counter", "battery", "clock"]
 | 
			
		||||
							
								
								
									
										9
									
								
								config/main.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config/main.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
refresh_ms=100
 | 
			
		||||
sock_path="~/dim.sock" # must be full path
 | 
			
		||||
seperator=" | "
 | 
			
		||||
 | 
			
		||||
[plugins]
 | 
			
		||||
path="./plugins"
 | 
			
		||||
blacklist=["example_c", "example_rust"]
 | 
			
		||||
as_whitelist=false
 | 
			
		||||
template=["counter", "battery", "clock"]
 | 
			
		||||
							
								
								
									
										13
									
								
								dim_plugins/battery/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								dim_plugins/battery/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "battery"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
crate-type=["cdylib"]
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
							
								
								
									
										17
									
								
								dim_plugins/battery/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								dim_plugins/battery/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# Must match package name in Cargo.toml
 | 
			
		||||
PLUGIN_NAME=battery
 | 
			
		||||
# `release` or `debug`
 | 
			
		||||
TYPE=release
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so:
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								dim_plugins/battery/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								dim_plugins/battery/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
use std::{fmt::Write, path::PathBuf};
 | 
			
		||||
use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
			
		||||
use std::fs::read_to_string;
 | 
			
		||||
 | 
			
		||||
plugin_info!(
 | 
			
		||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
			
		||||
    "battery",               // Plugin name
 | 
			
		||||
    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
			
		||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Plug {
 | 
			
		||||
    ctx: Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const BATT0: &'static str = "/sys/class/power_supply/BAT0/capacity";
 | 
			
		||||
const BATT1: &'static str = "/sys/class/power_supply/BAT1/capacity";
 | 
			
		||||
 | 
			
		||||
impl DimPlugin for Plug {
 | 
			
		||||
    fn init(ctx: Context) -> Result<Self> {
 | 
			
		||||
        dim_sdk::DimLogger::new(&ctx).init();
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            ctx
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
			
		||||
        self.ctx.buf.reset();
 | 
			
		||||
        match msg.name.as_str() {
 | 
			
		||||
            "poll" => {
 | 
			
		||||
                //TODO: Quick fix, make this better, more portable
 | 
			
		||||
                let path = if PathBuf::from(BATT0).exists() { BATT0 } else { BATT1 };
 | 
			
		||||
 | 
			
		||||
                let contents = read_to_string(path)?;
 | 
			
		||||
                let cleaned_contents: String = contents.chars().filter(|c| c.is_digit(10)).collect();
 | 
			
		||||
 | 
			
		||||
                write!(self.ctx, "Battery: {}%", cleaned_contents)?;
 | 
			
		||||
            }
 | 
			
		||||
            _ => ()
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn free(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								dim_plugins/clock/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dim_plugins/clock/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "clock"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
crate-type=["cdylib"]
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
chrono = "0.4.38"
 | 
			
		||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
							
								
								
									
										14
									
								
								dim_plugins/clock/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dim_plugins/clock/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
# Must match package name in Cargo.toml
 | 
			
		||||
PLUGIN_NAME=clock
 | 
			
		||||
# `release` or `debug`
 | 
			
		||||
TYPE=release
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so:
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) 
 | 
			
		||||
							
								
								
									
										43
									
								
								dim_plugins/clock/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								dim_plugins/clock/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
use std::fmt::Write;
 | 
			
		||||
use chrono::prelude::*;
 | 
			
		||||
use dim_sdk::{plugin_info, Context, DimPlugin, Result};
 | 
			
		||||
 | 
			
		||||
plugin_info!(
 | 
			
		||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
			
		||||
    "clock",                 // Plugin name
 | 
			
		||||
    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
			
		||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Plug {
 | 
			
		||||
    ctx: Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl DimPlugin for Plug {
 | 
			
		||||
    fn init(ctx: Context) -> Result<Self> {
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            ctx
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn on_message(&mut self, msg: dim_sdk::Message) -> Result<()> {
 | 
			
		||||
        self.ctx.buf.reset();
 | 
			
		||||
        match msg.name.as_str() {
 | 
			
		||||
            "poll" => {
 | 
			
		||||
                let local: DateTime<Local> = Local::now();
 | 
			
		||||
                let formatted_time = local.format("%H:%M (%Y-%m-%d)").to_string();
 | 
			
		||||
                write!(self.ctx, "Time: {}", formatted_time)?;
 | 
			
		||||
            }
 | 
			
		||||
            _ => ()
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn free(&mut self) -> Result<()> { Ok(()) } 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								dim_plugins/counter/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dim_plugins/counter/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "counter"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
crate-type=["cdylib"]
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
chrono = "0.4.38"
 | 
			
		||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
							
								
								
									
										14
									
								
								dim_plugins/counter/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dim_plugins/counter/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
# Must match package name in Cargo.toml
 | 
			
		||||
PLUGIN_NAME=counter
 | 
			
		||||
# `release` or `debug`
 | 
			
		||||
TYPE=release
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so:
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) 
 | 
			
		||||
							
								
								
									
										44
									
								
								dim_plugins/counter/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								dim_plugins/counter/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
use std::fmt::Write;
 | 
			
		||||
use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
			
		||||
use chrono::{NaiveDate, Local};
 | 
			
		||||
 | 
			
		||||
plugin_info!(
 | 
			
		||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
			
		||||
    "counter",               // Plugin name
 | 
			
		||||
    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
			
		||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Plug {
 | 
			
		||||
    ctx: Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DimPlugin for Plug {
 | 
			
		||||
    fn init(ctx: Context) -> Result<Self> {
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            ctx
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
			
		||||
        self.ctx.buf.reset();
 | 
			
		||||
        match msg.name.as_str() {
 | 
			
		||||
            "poll" => {
 | 
			
		||||
                let start_date = NaiveDate::from_ymd_opt(2024, 3, 8).expect("Invalid date");
 | 
			
		||||
                let current_date = Local::now().date_naive();
 | 
			
		||||
                let duration = current_date.signed_duration_since(start_date);
 | 
			
		||||
 | 
			
		||||
                write!(self.ctx, "{} days <3", duration.num_days())?;
 | 
			
		||||
            }
 | 
			
		||||
            _ => ()
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
    fn free(&mut self) -> Result<()> { Ok(()) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								dim_plugins/example_c/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								dim_plugins/example_c/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
PLUGIN_NAME=example_c
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CC_FLAGS = $(DIM_CC_FLAGS) -fPIC
 | 
			
		||||
 | 
			
		||||
SOURCES=$(wildcard src/*.c)
 | 
			
		||||
OBJECTS=$(patsubst src/%.c,$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o,$(SOURCES))
 | 
			
		||||
 | 
			
		||||
$(info $(SOURCES))
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECTS)
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	$(DIM_CC) -o $@ $^ -rdynamic -shared $(CC_FLAGS)
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o: src/%.c
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	$(DIM_CC) -c -o $@ $< -pie $(CC_FLAGS)
 | 
			
		||||
							
								
								
									
										51
									
								
								dim_plugins/example_c/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								dim_plugins/example_c/src/main.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
// Only use this define once, cause it defines funcitons
 | 
			
		||||
#define PLUG_IMPL
 | 
			
		||||
#include "dim_sdk.h"
 | 
			
		||||
 | 
			
		||||
PLUG_INFO("example_c", "0.0.1", "GPLv3")
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* some_data;
 | 
			
		||||
    int count;
 | 
			
		||||
    plug_ctx_t ctx;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
// If any function returns not 0 the plugin will be disabled
 | 
			
		||||
// Except for `pre_reload`, the plugin will be disabled if it is NULL
 | 
			
		||||
int plug_init(plug_ctx_t* ctx) {
 | 
			
		||||
    setup_ctx(ctx);
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p != NULL && "Buy more ram KEKW");
 | 
			
		||||
    p->count = 0;
 | 
			
		||||
    p->ctx = *ctx;
 | 
			
		||||
 | 
			
		||||
    // log(INFO, "Hewo fwom C :3");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload() {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int plug_post_reload(void *state) {
 | 
			
		||||
    p = state;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int plug_on_msg(plug_msg_t* msg) {
 | 
			
		||||
    if (strcmp(msg->name, "poll") == 0) {
 | 
			
		||||
        snprintf(p->ctx.buf, BUF_SZ, "Hello from C! (%d)", p->count++);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int plug_free() {
 | 
			
		||||
    free(p);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								dim_plugins/example_rust/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								dim_plugins/example_rust/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "example_rust"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
crate-type=["cdylib"]
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
							
								
								
									
										14
									
								
								dim_plugins/example_rust/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dim_plugins/example_rust/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
# Must match package name in Cargo.toml
 | 
			
		||||
PLUGIN_NAME=example_rust
 | 
			
		||||
# `release` or `debug`
 | 
			
		||||
TYPE=release
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so:
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) 
 | 
			
		||||
							
								
								
									
										57
									
								
								dim_plugins/example_rust/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								dim_plugins/example_rust/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
use std::fmt::Write;
 | 
			
		||||
use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
			
		||||
 | 
			
		||||
plugin_info!(
 | 
			
		||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
			
		||||
    "example_rust",          // Plugin name
 | 
			
		||||
    "0.0.0",                 // Plugin Version (leave empty for none)
 | 
			
		||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Plug {
 | 
			
		||||
    ctx: Context,
 | 
			
		||||
    counter: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DimPlugin for Plug {
 | 
			
		||||
    fn init(ctx: Context) -> dim_sdk::Result<Self> {
 | 
			
		||||
        // Initialise data, this will run once, it will not run again after reload
 | 
			
		||||
        // log::info!("hewo from rust :3");
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            ctx,
 | 
			
		||||
            counter: 0
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn on_message(&mut self, msg: Message) -> dim_sdk::Result<()> {
 | 
			
		||||
        self.ctx.buf.reset();
 | 
			
		||||
        match msg.name.as_str() {
 | 
			
		||||
            "poll" => {
 | 
			
		||||
                // Write to buffer the text you want to display, keep this short
 | 
			
		||||
                write!(self.ctx, "Hello from rust! ({})", self.counter)?;
 | 
			
		||||
                self.counter += 1;
 | 
			
		||||
            }
 | 
			
		||||
            _ => ()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()> {
 | 
			
		||||
        // Do stuff before reload, probably save important things because theres a good chance
 | 
			
		||||
        // (especially on rust) that if you change the data layout it will die
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()>{
 | 
			
		||||
        // Do stuff after reloading plugin, state a.k.a this struct has the same data, will crash
 | 
			
		||||
        // if the data layout changed
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn free(&mut self) -> Result<()> {
 | 
			
		||||
        // Yout probably dont need this but its for freeing things before the plugin gets unloaded
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								dim_plugins/volume/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								dim_plugins/volume/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "volume"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
crate-type=["cdylib"]
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
log = "0.4.21"
 | 
			
		||||
regex = "1.10.5"
 | 
			
		||||
serde = { version = "1.0.203", features = ["derive"] }
 | 
			
		||||
toml = "0.8.14"
 | 
			
		||||
							
								
								
									
										17
									
								
								dim_plugins/volume/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								dim_plugins/volume/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# Must match package name in Cargo.toml
 | 
			
		||||
PLUGIN_NAME=volume
 | 
			
		||||
# `release` or `debug`
 | 
			
		||||
TYPE=release
 | 
			
		||||
 | 
			
		||||
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
 | 
			
		||||
 | 
			
		||||
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(OBJECT_DIR)/$(PLUGIN_NAME)/$(TYPE)/lib$(PLUGIN_NAME).so:
 | 
			
		||||
	@mkdir -p $(dir $@)
 | 
			
		||||
	cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								dim_plugins/volume/config.template.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								dim_plugins/volume/config.template.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
[commands]
 | 
			
		||||
get_volume="pactl get-sink-volume @DEFAULT_SINK@"
 | 
			
		||||
get_volume_regex=".* (?<vol>[0-9]{1,3})%.*"
 | 
			
		||||
							
								
								
									
										37
									
								
								dim_plugins/volume/src/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								dim_plugins/volume/src/config.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
use std::path::Path;
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use serde::Deserialize;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_CFG: &'static str = include_str!("../config.template.toml");
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone)]
 | 
			
		||||
pub struct Config {
 | 
			
		||||
    pub commands: ConfigCommands,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone)]
 | 
			
		||||
pub struct ConfigCommands {
 | 
			
		||||
    pub get_volume: String,
 | 
			
		||||
    pub get_volume_regex: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Config {
 | 
			
		||||
    pub fn parse(p: &Path) -> Result<Self> {
 | 
			
		||||
        if !p.exists() {
 | 
			
		||||
            std::fs::write(p, DEFAULT_CFG)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let c = std::fs::read_to_string(p)?;
 | 
			
		||||
        Ok(toml::from_str(c.as_str())?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            commands: ConfigCommands { 
 | 
			
		||||
                get_volume: String::new(),
 | 
			
		||||
                get_volume_regex: String::new()
 | 
			
		||||
            } 
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								dim_plugins/volume/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								dim_plugins/volume/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
use std::{fmt::Write, process::Stdio};
 | 
			
		||||
use anyhow::bail;
 | 
			
		||||
use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
			
		||||
 | 
			
		||||
mod config;
 | 
			
		||||
 | 
			
		||||
plugin_info!(
 | 
			
		||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
			
		||||
    "volume",                // Plugin name
 | 
			
		||||
    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
			
		||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct Plug {
 | 
			
		||||
    cfg: config::Config,
 | 
			
		||||
    ctx: Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DimPlugin for Plug {
 | 
			
		||||
    fn init(ctx: Context) -> Result<Self> {
 | 
			
		||||
        let cfg;
 | 
			
		||||
        match config::Config::parse(&ctx.config_dir.join("config.toml").clone()) {
 | 
			
		||||
            Ok(c) => cfg = c,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to open config file: {e}");
 | 
			
		||||
                // TODO: Add function to disable the plugin
 | 
			
		||||
                bail!("")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(Self { ctx, cfg })
 | 
			
		||||
    }
 | 
			
		||||
    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
			
		||||
        self.ctx.buf.reset();
 | 
			
		||||
        match msg.name.as_str() {
 | 
			
		||||
            "poll" => {
 | 
			
		||||
                let mut proc = {
 | 
			
		||||
                        let mut p = std::process::Command::new("sh");
 | 
			
		||||
                        p.arg("-c");
 | 
			
		||||
                        p.arg(&self.cfg.commands.get_volume);
 | 
			
		||||
                        p.stdout(Stdio::piped());
 | 
			
		||||
                        p
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                let output = String::from_utf8(proc.output()?.stdout)?;
 | 
			
		||||
                let re = regex::Regex::new(&self.cfg.commands.get_volume_regex)?;
 | 
			
		||||
            
 | 
			
		||||
                if let Some(caps) = re.captures(&output) {
 | 
			
		||||
                    let volume = &caps["vol"];
 | 
			
		||||
                    write!(self.ctx, "Vol: {volume}%")?;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            _ => ()
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn free(&mut self) -> Result<()> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								rust-toolchain
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								rust-toolchain
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
nightly
 | 
			
		||||
							
								
								
									
										86
									
								
								sdk/c_cxx/dim_sdk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								sdk/c_cxx/dim_sdk.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_PLUG
 | 
			
		||||
#define _H_PLUG
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#define BUF_SZ 2048
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define PATH_SEP "\\"
 | 
			
		||||
#else
 | 
			
		||||
#define PATH_SEP "/"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef enum log_level_t {
 | 
			
		||||
    ERROR=1,
 | 
			
		||||
    WARN=2,
 | 
			
		||||
    INFO=3,
 | 
			
		||||
    DEBUG=4,
 | 
			
		||||
} log_level_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_info_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    char* license;
 | 
			
		||||
} plug_info_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_funcs_ctx_t {
 | 
			
		||||
    void (*log)(char* module, log_level_t level, char* s);
 | 
			
		||||
} plug_funcs_ctx_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_ctx_t {
 | 
			
		||||
    char* config_dir;
 | 
			
		||||
    plug_funcs_ctx_t funcs;
 | 
			
		||||
    char* buf;
 | 
			
		||||
} plug_ctx_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_msg_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* value;
 | 
			
		||||
} plug_msg_t;
 | 
			
		||||
 | 
			
		||||
// Functions defs
 | 
			
		||||
// User defined funcs
 | 
			
		||||
int  plug_init(plug_ctx_t*);             // Loads when DIM initialises
 | 
			
		||||
void* plug_pre_reload();                  // Return a pointer to save state
 | 
			
		||||
int  plug_post_reload(void*);            // returns the same pointer after reload
 | 
			
		||||
int  plug_on_msg(plug_msg_t*);           // Write the message to `buf` with max `size` characters 
 | 
			
		||||
int  plug_free();                        // Free everything before being killed
 | 
			
		||||
 | 
			
		||||
// Lib funcs
 | 
			
		||||
void setup_ctx(plug_ctx_t* ctx);
 | 
			
		||||
void _log(char* module, log_level_t level, char* s);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Macros
 | 
			
		||||
#define PLUG_INFO(_name, _version, _license)                                                   \
 | 
			
		||||
static plug_info_t PLUG_INFO_VAR = { .name=(_name), .version=(_version), .license=(_license)}; \
 | 
			
		||||
void* plug_get_info() {                                                                        \
 | 
			
		||||
    return &PLUG_INFO_VAR;                                                                     \
 | 
			
		||||
}                                      
 | 
			
		||||
 | 
			
		||||
#define log(level, ...) do { \
 | 
			
		||||
    char* buf = (char*)malloc(BUF_SZ*sizeof(char));         \
 | 
			
		||||
    char* mod = (char*)malloc(BUF_SZ*sizeof(char));         \
 | 
			
		||||
    snprintf(mod, BUF_SZ*sizeof(char),                      \
 | 
			
		||||
            "(plug) %s/%s", PLUG_INFO_VAR.name, __FILE__); \
 | 
			
		||||
    snprintf(buf, BUF_SZ*sizeof(char), __VA_ARGS__);        \
 | 
			
		||||
    _log(mod, level, buf);                                  \
 | 
			
		||||
    free(buf);                                              \
 | 
			
		||||
    free(mod);                                              \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#ifdef PLUG_IMPL
 | 
			
		||||
static plug_ctx_t CTX = {0};
 | 
			
		||||
 | 
			
		||||
void setup_ctx(plug_ctx_t* ctx) {
 | 
			
		||||
    CTX = *ctx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _log(char* module, log_level_t level, char* s) {
 | 
			
		||||
    (CTX.funcs.log)(module, level, s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										14
									
								
								sdk/rust/dim_sdk/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								sdk/rust/dim_sdk/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "dim_sdk"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[lib]
 | 
			
		||||
name="dim_sdk"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = "1.0.86"
 | 
			
		||||
bytes = "1.6.0"
 | 
			
		||||
lazy_static = { version = "1.4.0", features = ["spin"] }
 | 
			
		||||
libc = "0.2.155"
 | 
			
		||||
log = { version = "0.4.21", features = ["std"] }
 | 
			
		||||
							
								
								
									
										43
									
								
								sdk/rust/dim_sdk/src/c_buffer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								sdk/rust/dim_sdk/src/c_buffer.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct CBuffer {
 | 
			
		||||
    inner: Vec<u8>,
 | 
			
		||||
    count: usize,
 | 
			
		||||
    capacity: usize 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic
 | 
			
		||||
                    // i hate that macro as much as you do
 | 
			
		||||
impl CBuffer {
 | 
			
		||||
    pub fn from_raw_parts_mut(buf: *mut u8, capacity: usize) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: unsafe {
 | 
			
		||||
                Vec::from_raw_parts(buf, capacity, capacity)
 | 
			
		||||
            },
 | 
			
		||||
            capacity,
 | 
			
		||||
            count: 0,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn reset(&mut self) {
 | 
			
		||||
        for i in 0..self.capacity {
 | 
			
		||||
            self.inner[i] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        self.count = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl std::fmt::Write for CBuffer {
 | 
			
		||||
    fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> { 
 | 
			
		||||
        for c in buf.as_bytes() {
 | 
			
		||||
            if self.count >= self.capacity - 1 {
 | 
			
		||||
                return Ok(());
 | 
			
		||||
            }
 | 
			
		||||
            self.inner[self.count] = *c;
 | 
			
		||||
            self.count += 1;
 | 
			
		||||
        }
 | 
			
		||||
        self.inner[self.count] = 0;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								sdk/rust/dim_sdk/src/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								sdk/rust/dim_sdk/src/context.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
use std::{ffi::{c_char, CStr}, path::PathBuf};
 | 
			
		||||
 | 
			
		||||
use crate::CBuffer;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct ContextRaw {
 | 
			
		||||
    pub config_dir: *const c_char,
 | 
			
		||||
    pub funcs: PluginContextFuncs,
 | 
			
		||||
    pub buf: *mut u8,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct Context {
 | 
			
		||||
    pub config_dir: PathBuf,
 | 
			
		||||
    pub funcs: PluginContextFuncs,
 | 
			
		||||
    pub buf: CBuffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct PluginContextFuncs {
 | 
			
		||||
    pub log: unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Context {
 | 
			
		||||
    pub fn new(cr: ContextRaw) -> Self {
 | 
			
		||||
        let config_dir = unsafe {
 | 
			
		||||
            let v = CStr::from_ptr(cr.config_dir);
 | 
			
		||||
            PathBuf::from(v.to_string_lossy().to_string().clone())
 | 
			
		||||
        };
 | 
			
		||||
        Self {
 | 
			
		||||
            config_dir,
 | 
			
		||||
            funcs: cr.funcs.clone(),
 | 
			
		||||
            buf: CBuffer::from_raw_parts_mut(cr.buf, crate::BUF_SZ)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl std::fmt::Write for Context {
 | 
			
		||||
    fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> { 
 | 
			
		||||
        self.buf.write_str(buf)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								sdk/rust/dim_sdk/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								sdk/rust/dim_sdk/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
 | 
			
		||||
#[macro_use]
 | 
			
		||||
mod magic;
 | 
			
		||||
mod c_buffer;
 | 
			
		||||
mod plugin_info;
 | 
			
		||||
mod context;
 | 
			
		||||
mod logger;
 | 
			
		||||
 | 
			
		||||
use std::ffi::{c_char, CStr};
 | 
			
		||||
 | 
			
		||||
pub use c_buffer::*;
 | 
			
		||||
pub use plugin_info::*;
 | 
			
		||||
pub use anyhow::Result;
 | 
			
		||||
pub use context::*;
 | 
			
		||||
pub use logger::*;
 | 
			
		||||
 | 
			
		||||
pub const BUF_SZ: usize = 2048;
 | 
			
		||||
 | 
			
		||||
pub trait DimPlugin: Clone{
 | 
			
		||||
    fn init(ctx: Context) -> Result<Self>;
 | 
			
		||||
    fn pre_reload(&mut self) -> Result<()>;
 | 
			
		||||
    fn post_reload(&mut self) -> Result<()>;
 | 
			
		||||
    fn on_message(&mut self, msg: Message) -> Result<()>;
 | 
			
		||||
    fn free(&mut self) -> Result<()>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Message {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub value: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct MessageRaw {
 | 
			
		||||
    pub name: *const c_char,
 | 
			
		||||
    pub value: *const c_char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl Message {
 | 
			
		||||
    pub fn new(msg: MessageRaw) -> Self {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            Self { 
 | 
			
		||||
                name: CStr::from_ptr(msg.name.clone())
 | 
			
		||||
                        .to_string_lossy().to_string(), 
 | 
			
		||||
                value: CStr::from_ptr(msg.value.clone())
 | 
			
		||||
                        .to_string_lossy().to_string()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								sdk/rust/dim_sdk/src/logger.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								sdk/rust/dim_sdk/src/logger.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
use std::ffi::{c_char, CString};
 | 
			
		||||
 | 
			
		||||
use crate::Context;
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct DimLogger {
 | 
			
		||||
    log_fn:  unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl log::Log for DimLogger {
 | 
			
		||||
    fn enabled(&self, _: &log::Metadata) -> bool {true}
 | 
			
		||||
 | 
			
		||||
    fn log(&self, record: &log::Record) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let module = format!("(plug) {}", record.module_path().unwrap_or("UNKNOWN"));
 | 
			
		||||
            let module = CString::new(module).unwrap();
 | 
			
		||||
            let s = CString::new(format!("{}", record.args())).unwrap();
 | 
			
		||||
            (self.log_fn)(module.as_ptr(), record.level(), s.as_ptr());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn flush(&self) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DimLogger {
 | 
			
		||||
    pub fn new(ctx: &Context) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            log_fn: ctx.funcs.log,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn init(&self) {
 | 
			
		||||
        let _ = log::set_boxed_logger(Box::new(self.clone()))
 | 
			
		||||
            .map(|()| log::set_max_level(log::LevelFilter::Debug));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								sdk/rust/dim_sdk/src/magic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								sdk/rust/dim_sdk/src/magic.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,101 @@
 | 
			
		|||
// Lord have mercy on me
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! plugin_info {
 | 
			
		||||
    ($typ:ty, $name:literal, $version:literal, $license:literal) => {
 | 
			
		||||
         
 | 
			
		||||
        lazy_static::lazy_static!(
 | 
			
		||||
            static ref PLUGIN_INFO: $crate::PluginInfo = $crate::PluginInfo::new($name, $version, $license);
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        static mut PLUG: Option<$typ> = None as Option<$typ>;
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_get_info() -> *const std::ffi::c_void {
 | 
			
		||||
            PLUGIN_INFO.get_raw_ptr()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl $typ {
 | 
			
		||||
            pub fn get_plugin_info(&self) -> $crate::PluginInfo {
 | 
			
		||||
                $crate::PluginInfo::new(
 | 
			
		||||
                    PLUGIN_INFO.name().as_str(),
 | 
			
		||||
                    PLUGIN_INFO.version().as_str(),
 | 
			
		||||
                    PLUGIN_INFO.license().as_str()
 | 
			
		||||
                    )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_init(ctx: *const $crate::ContextRaw) -> i32 {
 | 
			
		||||
            let ctx = $crate::Context::new((*ctx).clone());
 | 
			
		||||
            $crate::DimLogger::new(&ctx).init();
 | 
			
		||||
            match <$typ>::init(ctx) {
 | 
			
		||||
                Ok(v) => {
 | 
			
		||||
                    PLUG = Some(v);
 | 
			
		||||
                    return 0;
 | 
			
		||||
                }
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    log::error!("Had an error while initialising: {e}");
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_pre_reload() -> *mut $typ {
 | 
			
		||||
            //TODO: Untested 
 | 
			
		||||
            if let Some(p) = &mut PLUG {
 | 
			
		||||
                if let Err(e) = p.pre_reload() {
 | 
			
		||||
                    log::error!("Had an error on pre reload: {e}");
 | 
			
		||||
                    return std::ptr::null_mut();
 | 
			
		||||
                }
 | 
			
		||||
                return p as *mut $typ;
 | 
			
		||||
            }
 | 
			
		||||
            unreachable!();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_post_reload(state: *mut $typ) -> i32 {
 | 
			
		||||
            PLUG = Some((*state).clone());
 | 
			
		||||
 | 
			
		||||
            if let Some(p) = &mut PLUG {
 | 
			
		||||
                if let Err(e) = p.post_reload() {
 | 
			
		||||
                    log::error!("Had an error on pre reload: {e}");
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                unreachable!();
 | 
			
		||||
            }
 | 
			
		||||
            //TODO: Untested
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_on_msg(msg: *const $crate::MessageRaw) -> i32 {
 | 
			
		||||
            let msg = $crate::Message::new((*msg).clone());
 | 
			
		||||
            if let Some(p) = &mut PLUG {
 | 
			
		||||
                if let Err(e) = p.on_message(msg) {
 | 
			
		||||
                    log::error!("Had error on `on_msg`: {e}");
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                unreachable!();
 | 
			
		||||
            }
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #[no_mangle]
 | 
			
		||||
        unsafe extern "C" fn plug_free() -> i32 {
 | 
			
		||||
            if let Some(p) = &mut PLUG {
 | 
			
		||||
                // std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>());
 | 
			
		||||
                if let Err(e) = p.free() {
 | 
			
		||||
                    log::error!("Had error on `free`: {e}");
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                unreachable!();
 | 
			
		||||
            }
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								sdk/rust/dim_sdk/src/plugin_info.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								sdk/rust/dim_sdk/src/plugin_info.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
use std::ffi::{c_char, c_void, CString};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct PluginInfo {
 | 
			
		||||
    ptrs: PluginInfoPtrs,
 | 
			
		||||
    _name: CString,
 | 
			
		||||
    _version: CString,
 | 
			
		||||
    _license: CString
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct PluginInfoPtrs {
 | 
			
		||||
    name: *const c_char,
 | 
			
		||||
    version: *const c_char,
 | 
			
		||||
    license: *const c_char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PluginInfo {
 | 
			
		||||
    pub fn new(name: &str, version: &str, license: &str) -> Self {
 | 
			
		||||
 | 
			
		||||
        let _name = CString::new(name).unwrap();
 | 
			
		||||
        let _version = CString::new(version).unwrap();
 | 
			
		||||
        let _license = CString::new(license).unwrap();
 | 
			
		||||
        let name = _name.as_ptr();
 | 
			
		||||
        let version = if _version.is_empty() {
 | 
			
		||||
            std::ptr::null()
 | 
			
		||||
        } else {_version.as_ptr()};
 | 
			
		||||
        let license = if _license.is_empty() {
 | 
			
		||||
            std::ptr::null()
 | 
			
		||||
        } else {_license.as_ptr()};
 | 
			
		||||
 | 
			
		||||
        Self { ptrs: PluginInfoPtrs{ name, version, license }, _name, _version, _license }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_raw_ptr(&self) -> *const c_void {
 | 
			
		||||
        &self.ptrs as *const _ as *const c_void
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn name(&self) -> String {
 | 
			
		||||
        self._name.to_string_lossy().to_string()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn version(&self) -> String {
 | 
			
		||||
        self._version.to_string_lossy().to_string()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn license(&self) -> String {
 | 
			
		||||
        self._license.to_string_lossy().to_string()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
unsafe impl Sync for PluginInfo {}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										46
									
								
								src/cli.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/cli.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
use clap::{Parser, Subcommand};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Parser)]
 | 
			
		||||
pub struct CliArgs {
 | 
			
		||||
    /// Directory where all *.dim plugin files are stored
 | 
			
		||||
    #[arg(long, short, default_value="./plugins")]
 | 
			
		||||
    pub plugin_dir: camino::Utf8PathBuf,
 | 
			
		||||
    
 | 
			
		||||
    /// Directory where all configurations are stored
 | 
			
		||||
    #[arg(long, short, default_value="./config")]
 | 
			
		||||
    pub config_dir: camino::Utf8PathBuf,
 | 
			
		||||
    
 | 
			
		||||
    /// Print more debug info
 | 
			
		||||
    #[arg(long, short)]
 | 
			
		||||
    pub debug: bool,
 | 
			
		||||
    
 | 
			
		||||
    /// Socket path
 | 
			
		||||
    #[arg(long, short)]
 | 
			
		||||
    pub sock_path: Option<camino::Utf8PathBuf>,
 | 
			
		||||
 | 
			
		||||
    #[command(subcommand)]
 | 
			
		||||
    pub subcommand: Option<CliSubcommand>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Subcommand)]
 | 
			
		||||
pub enum CliSubcommand {
 | 
			
		||||
    /// Send a message through ipc to the running DIM instance
 | 
			
		||||
    Send {
 | 
			
		||||
        /// Command name, eg. `clock:reset`, 
 | 
			
		||||
        /// `clock:` will be stripped and the command will be sent
 | 
			
		||||
        /// only to plugin `clock`, dont include it to send it to all plugins
 | 
			
		||||
        #[arg(long, short)]
 | 
			
		||||
        name: String,
 | 
			
		||||
        
 | 
			
		||||
        /// Value to send
 | 
			
		||||
        #[arg(long, short, default_value="")]
 | 
			
		||||
        value: String,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /// Reload one or all plugins
 | 
			
		||||
    Reload {
 | 
			
		||||
        /// (Optional) Which plugin to Reload
 | 
			
		||||
        name: Option<String>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								src/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/config.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
use std::path::{Path, PathBuf};
 | 
			
		||||
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::cli::CliArgs;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Default)]
 | 
			
		||||
pub struct Config {
 | 
			
		||||
    pub seperator: String,
 | 
			
		||||
    pub refresh_ms: usize,
 | 
			
		||||
    pub sock_path: String,
 | 
			
		||||
    pub plugins: ConfigPlugins,
 | 
			
		||||
 | 
			
		||||
    #[serde(skip)]
 | 
			
		||||
    pub config_dir: PathBuf,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Serialize, Deserialize, Default)]
 | 
			
		||||
pub struct ConfigPlugins {
 | 
			
		||||
    pub path: PathBuf,
 | 
			
		||||
    pub blacklist: Vec<String>,
 | 
			
		||||
    pub as_whitelist: bool,
 | 
			
		||||
    pub template: Vec<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Config {
 | 
			
		||||
    pub fn new(cli: CliArgs) -> Result<Self, ConfigError> {
 | 
			
		||||
        let cfg_path = cli.config_dir.join("main.toml");
 | 
			
		||||
        
 | 
			
		||||
        if !cfg_path.exists() {
 | 
			
		||||
            println!("ERROR: {:?} doesnt exist", cli.config_dir);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut cfg: Self = toml::from_str(
 | 
			
		||||
                &std::fs::read_to_string(&cfg_path)?
 | 
			
		||||
            )?;
 | 
			
		||||
    
 | 
			
		||||
        cfg.config_dir = cli.config_dir.as_std_path().to_path_buf();
 | 
			
		||||
        cfg.plugins.path = cli.plugin_dir.as_std_path().to_path_buf();
 | 
			
		||||
        Ok(cfg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum ConfigError {
 | 
			
		||||
    IoError(std::io::Error),
 | 
			
		||||
    TomlDeserialiseError(toml::de::Error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<std::io::Error> for ConfigError {
 | 
			
		||||
    fn from(e: std::io::Error) -> Self {
 | 
			
		||||
        Self::IoError(e)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl From<toml::de::Error> for ConfigError {
 | 
			
		||||
    fn from(e: toml::de::Error) -> Self {
 | 
			
		||||
        Self::TomlDeserialiseError(e)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								src/display.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/display.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,105 @@
 | 
			
		|||
use std::{collections::HashMap, ffi::{CString, NulError}};
 | 
			
		||||
 | 
			
		||||
use x11::xlib;
 | 
			
		||||
 | 
			
		||||
use crate::{config::Config, plugman::PolledText};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct Display {
 | 
			
		||||
    window: u64,
 | 
			
		||||
    display: *mut xlib::Display
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display {
 | 
			
		||||
    pub fn new() -> Result<Self, ()> {
 | 
			
		||||
        let (window, display) = unsafe { 
 | 
			
		||||
            let display = xlib::XOpenDisplay(std::ptr::null());
 | 
			
		||||
            
 | 
			
		||||
            if display.is_null() {
 | 
			
		||||
                log::error!("Could not open x11 display");
 | 
			
		||||
                return Err(());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            (
 | 
			
		||||
                xlib::XDefaultRootWindow(display),
 | 
			
		||||
                display
 | 
			
		||||
            )
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            window,
 | 
			
		||||
            display
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    pub fn write_display_name(&mut self, name: &str) -> Result<(), NulError> {
 | 
			
		||||
        let cstr = CString::new(name)?;
 | 
			
		||||
        unsafe {
 | 
			
		||||
            xlib::XStoreName(self.display, self.window, cstr.as_ptr() as *const i8);
 | 
			
		||||
            xlib::XFlush(self.display);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn write_with_vec(&mut self, cfg: &Config, v: HashMap<String, PolledText>) -> Result<(), NulError> {
 | 
			
		||||
        let mut buf = Vec::new();
 | 
			
		||||
        
 | 
			
		||||
        let mut v = if cfg.plugins.as_whitelist {
 | 
			
		||||
            let mut vv = HashMap::new();
 | 
			
		||||
            for (n, pt) in v {
 | 
			
		||||
                if cfg.plugins.blacklist.contains(&n) {
 | 
			
		||||
                    vv.insert(n, pt);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            vv
 | 
			
		||||
        } else {
 | 
			
		||||
            let mut vv = HashMap::new();
 | 
			
		||||
            for (n, pt) in v {
 | 
			
		||||
                if !cfg.plugins.blacklist.contains(&n) {
 | 
			
		||||
                    vv.insert(n, pt);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            vv
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut used_values = Vec::new();
 | 
			
		||||
        for tv in &cfg.plugins.template {
 | 
			
		||||
            let mut found = false;
 | 
			
		||||
            for (pname, pt) in &v {
 | 
			
		||||
                if *pname == *tv {
 | 
			
		||||
                    if !pt.disabled() {
 | 
			
		||||
                        buf.push(pt.text().clone());
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    used_values.push(pname.clone());
 | 
			
		||||
                    found = true;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if !found {
 | 
			
		||||
                // log::warn!("Plugin '{}' was not found even though it was included in the template", tv);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for val in used_values {
 | 
			
		||||
            v.remove(&val);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        let mut kv: Vec<(&String, &PolledText)> = v.iter().collect();
 | 
			
		||||
        kv.sort_by(|a, b| a.0.cmp(b.0));
 | 
			
		||||
 | 
			
		||||
        for (_, pt) in &kv {
 | 
			
		||||
            buf.push(pt.text().clone());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let text = buf.join(&cfg.seperator);
 | 
			
		||||
 | 
			
		||||
        self.write_display_name(&text)?;
 | 
			
		||||
 | 
			
		||||
        Ok(()) 
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,35 +0,0 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_PLUG
 | 
			
		||||
#define _H_PLUG
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef void* (*plug_init_f)        (void);
 | 
			
		||||
typedef void* (*plug_pre_reload_f)  (void);
 | 
			
		||||
typedef void  (*plug_post_reload_f) (void*);
 | 
			
		||||
typedef void  (*plug_poll_f)        (char*, size_t);
 | 
			
		||||
typedef void  (*plug_free_f)        (void);
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_int_t {
 | 
			
		||||
    char* path;
 | 
			
		||||
    plug_init_f f_init; 
 | 
			
		||||
    plug_pre_reload_f f_pre_reload;
 | 
			
		||||
    plug_post_reload_f f_post_reload;
 | 
			
		||||
    plug_poll_f f_poll;
 | 
			
		||||
    plug_free_f f_free;
 | 
			
		||||
    plug_t* state;
 | 
			
		||||
} plug_int_t;
 | 
			
		||||
 | 
			
		||||
void setup_plugins(char* plugin_path);
 | 
			
		||||
char* poll_plugins(char* sep);
 | 
			
		||||
void free_plugins(void);
 | 
			
		||||
void reload_plugins(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_SOCKET
 | 
			
		||||
#define _H_SOCKET
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
 | 
			
		||||
typedef enum sock_msg_t{
 | 
			
		||||
    SM_NONE   = 0,
 | 
			
		||||
    SM_RELOAD = 1,
 | 
			
		||||
} sock_msg_t;
 | 
			
		||||
 | 
			
		||||
int socket_init(void);
 | 
			
		||||
sock_msg_t socket_poll(void);
 | 
			
		||||
void socket_close(void);
 | 
			
		||||
void socket_send(char*);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_UTIL
 | 
			
		||||
#define _H_UTIL
 | 
			
		||||
 | 
			
		||||
void to_lowercase(char* str);
 | 
			
		||||
void to_uppercase(char* str);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										0
									
								
								src/ipc/client/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/ipc/client/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										63
									
								
								src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
use std::ffi::{c_char, CString};
 | 
			
		||||
 | 
			
		||||
pub mod client;
 | 
			
		||||
pub mod server;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Message {
 | 
			
		||||
    pub plugin: Option<String>,
 | 
			
		||||
    pub name: CString,
 | 
			
		||||
    pub value: CString,
 | 
			
		||||
    pub ffi: MessageFFI
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct MessageFFI {
 | 
			
		||||
    pub name: *const c_char,
 | 
			
		||||
    pub value: *const c_char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Message {
 | 
			
		||||
    pub fn from_string_kv<S: ToString>(name: S, value: S) -> Self {
 | 
			
		||||
        let mut name = name.to_string();
 | 
			
		||||
        let value = value.to_string();
 | 
			
		||||
        let plugin;
 | 
			
		||||
        if name.contains(':') {
 | 
			
		||||
            let ns: Vec<&str> = name.split(':').collect();
 | 
			
		||||
            plugin = Some(ns[0].to_string());
 | 
			
		||||
            name = ns[1..].join(":");
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            plugin = None;
 | 
			
		||||
        }
 | 
			
		||||
           
 | 
			
		||||
        let name = CString::new(name).unwrap();
 | 
			
		||||
        let value = CString::new(value).unwrap();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Self {
 | 
			
		||||
            ffi: MessageFFI {
 | 
			
		||||
                name: name.as_ptr(),
 | 
			
		||||
                value: value.as_ptr()
 | 
			
		||||
            },
 | 
			
		||||
            plugin, 
 | 
			
		||||
            name, 
 | 
			
		||||
            value,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_string<S: ToString>(k: S) -> Self {
 | 
			
		||||
        let k = k.to_string();
 | 
			
		||||
        let mut v = String::new();
 | 
			
		||||
        let mut name = k.clone();
 | 
			
		||||
        if k.contains('=') {
 | 
			
		||||
            let kv: Vec<&str> = k.split('=').collect();
 | 
			
		||||
            name = kv[0].to_string();
 | 
			
		||||
            v = kv[1..].join("=");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Self::from_string_kv(name, v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								src/ipc/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ipc/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
use std::{io::Read, os::unix::net::UnixStream};
 | 
			
		||||
 | 
			
		||||
use crate::config::Config;
 | 
			
		||||
 | 
			
		||||
use super::Message;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
pub struct IpcServer{
 | 
			
		||||
    sock: UnixStream
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IpcServer {
 | 
			
		||||
    pub fn start(cfg: &Config) -> std::io::Result<Self> {
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            sock: UnixStream::connect(&cfg.sock_path)?,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn poll(&mut self) -> Option<Message> {
 | 
			
		||||
        let mut buf = String::new();
 | 
			
		||||
        let _ = self.sock.read_to_string(&mut buf);
 | 
			
		||||
        if buf.is_empty() {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
        Some(Message::from_string(buf))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/logger.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/logger.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
pub use crate::cli::CliArgs;
 | 
			
		||||
 | 
			
		||||
pub fn init(ca: &CliArgs) {
 | 
			
		||||
    if ca.debug {
 | 
			
		||||
        env_logger::builder()
 | 
			
		||||
            .filter(None, log::LevelFilter::Debug)
 | 
			
		||||
            .init();
 | 
			
		||||
    } else {
 | 
			
		||||
        env_logger::builder()
 | 
			
		||||
            .filter(None, log::LevelFilter::Info)
 | 
			
		||||
            .init();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										79
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								src/main.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,79 +0,0 @@
 | 
			
		|||
#include <X11/Xlib.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "plug.h"
 | 
			
		||||
#include "socket.h"
 | 
			
		||||
 | 
			
		||||
void interrupt_handler(int);
 | 
			
		||||
void print_help(void);
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
    signal(SIGINT, interrupt_handler);
 | 
			
		||||
 | 
			
		||||
    if (argc > 1) {
 | 
			
		||||
        if (strcmp(argv[1], "send") == 0) {
 | 
			
		||||
            if (argc == 3) {
 | 
			
		||||
                socket_send(argv[2]);
 | 
			
		||||
                return 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                print_help();
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            print_help();
 | 
			
		||||
            printf("ERROR: Unknown subcommand\n");
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (socket_init() != 0) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setup_plugins("./modules");
 | 
			
		||||
    char* buffer;
 | 
			
		||||
 | 
			
		||||
    Display *display = XOpenDisplay(NULL);
 | 
			
		||||
    Window window = DefaultRootWindow(display);
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        sock_msg_t msg = socket_poll();
 | 
			
		||||
 | 
			
		||||
        switch (msg) {
 | 
			
		||||
            case SM_RELOAD: {
 | 
			
		||||
                reload_plugins();
 | 
			
		||||
            } break;
 | 
			
		||||
            case SM_NONE: break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        buffer = poll_plugins("|");
 | 
			
		||||
        XStoreName(display, window, buffer);
 | 
			
		||||
        XFlush(display);
 | 
			
		||||
        sleep(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  XCloseDisplay(display);
 | 
			
		||||
  free_plugins();
 | 
			
		||||
  return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void interrupt_handler(int sig) {
 | 
			
		||||
    (void) sig;
 | 
			
		||||
    printf("\nCaught SIGINT, exiting\n");
 | 
			
		||||
    free_plugins();
 | 
			
		||||
    socket_close();
 | 
			
		||||
    exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_help(void) {
 | 
			
		||||
    printf("Usage: dim [command]\n");
 | 
			
		||||
    printf("Commands:\n");
 | 
			
		||||
    printf("    send [MESSAGE] - Sends a message, available messages: [reload]\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
#![allow(internal_features)]
 | 
			
		||||
#![feature(core_intrinsics)]
 | 
			
		||||
 | 
			
		||||
use std::{process::ExitCode, time::Duration};
 | 
			
		||||
use clap::Parser;
 | 
			
		||||
 | 
			
		||||
mod display;
 | 
			
		||||
mod plugman;
 | 
			
		||||
mod config;
 | 
			
		||||
mod util;
 | 
			
		||||
mod cli;
 | 
			
		||||
mod logger;
 | 
			
		||||
mod ipc;
 | 
			
		||||
 | 
			
		||||
// TODO: Make function available in ctx that disables the plugin
 | 
			
		||||
// TODO: Set up ipc with unix sockets
 | 
			
		||||
// TODO: Allow sending messages command -> running DIM instance -> plugin with ipc
 | 
			
		||||
// TODO: Clickable bar: https://dwm.suckless.org/patches/statuscmd/
 | 
			
		||||
// TODO: Run code through clippy
 | 
			
		||||
fn main() -> ExitCode {
 | 
			
		||||
    let ca = cli::CliArgs::parse();
 | 
			
		||||
    
 | 
			
		||||
    logger::init(&ca);
 | 
			
		||||
 | 
			
		||||
    let config;
 | 
			
		||||
    match config::Config::new(ca) {
 | 
			
		||||
        Ok(v) => config = v,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to parse config: {e:?}");
 | 
			
		||||
            return ExitCode::from(2);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    let Ok(mut disp) = display::Display::new() else {
 | 
			
		||||
        return ExitCode::from(1);
 | 
			
		||||
    }; 
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    let mut pm = plugman::PlugMan::new(1024); // idk tbh
 | 
			
		||||
    if let Err(e) = pm.load(&config.plugins.path){
 | 
			
		||||
        log::error!("Failed to load plugins: {e:?}");
 | 
			
		||||
        return ExitCode::from(3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pm.init_plugins(&config);
 | 
			
		||||
    
 | 
			
		||||
    loop {
 | 
			
		||||
        let vals = pm.poll_plugins();
 | 
			
		||||
 | 
			
		||||
        log::debug!("vals: {vals:?}");
 | 
			
		||||
        if let Err(e) = disp.write_with_vec(&config, vals) {
 | 
			
		||||
            log::warn!("Failed to write too bar: {e}");
 | 
			
		||||
        }
 | 
			
		||||
        std::thread::sleep(Duration::from_millis(250));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,62 +0,0 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    FILE* fp;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char* batt_files[] = {
 | 
			
		||||
    "/sys/class/power_supply/BAT0/capacity",
 | 
			
		||||
    "/sys/class/power_supply/BAT1/capacity"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p);
 | 
			
		||||
    p->name = "Battery";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < sizeof(batt_files)/sizeof(batt_files[0]); i++) {
 | 
			
		||||
        if (access(batt_files[i], F_OK) == 0) {
 | 
			
		||||
            p->fp = fopen(batt_files[i], "r");
 | 
			
		||||
            if (p->fp) {
 | 
			
		||||
                printf("Opened %s\n", batt_files[i]);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!p->fp) {
 | 
			
		||||
        printf("MODULE: ERROR: Unable to find battery\n");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    if (!p->fp) return;
 | 
			
		||||
    int perc = 0;
 | 
			
		||||
    fseek(p->fp, 0, SEEK_SET);
 | 
			
		||||
    fscanf(p->fp, "%d", &perc);
 | 
			
		||||
    snprintf(buf, len, "Batt: %d%%", perc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_free(void) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,42 +0,0 @@
 | 
			
		|||
#include <time.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    int i;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    p->name = "time";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
    p->i = 0;
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp;
 | 
			
		||||
    p->i += 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    time_t rawtime;
 | 
			
		||||
    struct tm *timeinfo;
 | 
			
		||||
    
 | 
			
		||||
    time(&rawtime);
 | 
			
		||||
    timeinfo = localtime(&rawtime);
 | 
			
		||||
    
 | 
			
		||||
    strftime(buf, len, "Time: %H:%M (%Y-%m-%d)", timeinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_free(void) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name; // Always keep these on top
 | 
			
		||||
    char* version;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p);
 | 
			
		||||
    p->name = "example";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
    // Return NULL if error
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p; // send state to dim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp; // get back state
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    // print text to `buf` with max len `len`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_free(void) {
 | 
			
		||||
    free(p); // free state
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,44 +0,0 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name; // Always keep these on top
 | 
			
		||||
    char* version;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p);
 | 
			
		||||
    p->name = "time-since";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p; // send state to dim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp; // get back state
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    struct tm t = {0};
 | 
			
		||||
    t.tm_year = 2024 - 1900;
 | 
			
		||||
    t.tm_mon = 2;
 | 
			
		||||
    t.tm_mday = 8;
 | 
			
		||||
 | 
			
		||||
    time_t diff = difftime(time(0), mktime(&t)) / (60 * 60 * 24);
 | 
			
		||||
 | 
			
		||||
    snprintf(buf, len, " %ld days <3", diff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_free(void) {
 | 
			
		||||
    free(p); // free state
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										214
									
								
								src/plug.c
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								src/plug.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,214 +0,0 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <dirent.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
#include "plug.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define PLUG_PATH_MAX 255
 | 
			
		||||
#define PLUG_MAX_COUNT (PLUG_PATH_MAX+255)
 | 
			
		||||
#define PLUG_POLL_BUF_SZ 1024
 | 
			
		||||
 | 
			
		||||
typedef struct PlugMan {
 | 
			
		||||
    plug_int_t* plugs[PLUG_MAX_COUNT];
 | 
			
		||||
    size_t plug_count;
 | 
			
		||||
    void* plug_objs[PLUG_MAX_COUNT];
 | 
			
		||||
    size_t plug_obj_count;
 | 
			
		||||
} plugman_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plugman_t PLUGMAN = {0};
 | 
			
		||||
 | 
			
		||||
void* load_plug_sym(void* plug_f, char* fn_name);
 | 
			
		||||
plug_int_t* load_plugin(char* path, bool);
 | 
			
		||||
 | 
			
		||||
void load_plugins(const char* mod_dir_p) {
 | 
			
		||||
    DIR* dir = {0};
 | 
			
		||||
 | 
			
		||||
    dir = opendir(mod_dir_p);
 | 
			
		||||
 | 
			
		||||
    if (!dir) {
 | 
			
		||||
        printf("ERROR: Failed to open dir %s\n", mod_dir_p);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct dirent* dir_entry;
 | 
			
		||||
 | 
			
		||||
    while ((dir_entry = readdir(dir)) != NULL) {
 | 
			
		||||
        if (!(dir_entry->d_type == DT_REG ||
 | 
			
		||||
                dir_entry->d_type == DT_LNK)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (strcmp(dir_entry->d_name, ".") == 0 ||
 | 
			
		||||
                strcmp(dir_entry->d_name, "..") == 0) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        char* dot = strchr(dir_entry->d_name, '.');
 | 
			
		||||
        
 | 
			
		||||
        if (!dot || dot == dir_entry->d_name) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        char* ext = dot+1;
 | 
			
		||||
        if (strcmp(ext, "dim") != 0) continue;
 | 
			
		||||
        
 | 
			
		||||
        printf("INFO: Found plugin: %s/%s\n", mod_dir_p, dir_entry->d_name);
 | 
			
		||||
 | 
			
		||||
        char* full_path = (char*)malloc(sizeof(char)*1028);
 | 
			
		||||
        snprintf(full_path, PLUG_MAX_COUNT, "%s/%s", mod_dir_p, dir_entry->d_name);
 | 
			
		||||
        plug_int_t* plug = load_plugin(full_path, true);
 | 
			
		||||
 | 
			
		||||
        if (!plug) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        PLUGMAN.plugs[PLUGMAN.plug_count++] = plug;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plug_int_t* load_plugin(char* path, bool check_duplicates) {
 | 
			
		||||
    if (check_duplicates) {
 | 
			
		||||
        for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
            plug_int_t* plug = PLUGMAN.plugs[i];
 | 
			
		||||
            if (strcmp(plug->path, path) == 0) {
 | 
			
		||||
                return NULL; // plugin exists
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    plug_int_t* plug = malloc(sizeof(plug_int_t));
 | 
			
		||||
    plug->path = path;
 | 
			
		||||
 | 
			
		||||
    void* plug_f = dlopen(path, RTLD_NOW);
 | 
			
		||||
    
 | 
			
		||||
    if (!plug_f) {
 | 
			
		||||
        printf("ERROR: Failed to load plugin %s\n", path);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // "technically" couldnt run on very niche platforms but idc
 | 
			
		||||
    #pragma GCC diagnostic push
 | 
			
		||||
    #pragma GCC diagnostic ignored "-Wpedantic"
 | 
			
		||||
    
 | 
			
		||||
    plug->f_init        = (plug_init_f)        load_plug_sym(plug_f, "plug_init");
 | 
			
		||||
    plug->f_pre_reload  = (plug_pre_reload_f)  load_plug_sym(plug_f, "plug_pre_reload");
 | 
			
		||||
    plug->f_post_reload = (plug_post_reload_f) load_plug_sym(plug_f, "plug_post_reload");
 | 
			
		||||
    plug->f_poll        = (plug_poll_f)        load_plug_sym(plug_f, "plug_poll");
 | 
			
		||||
    plug->f_free        = (plug_free_f)        load_plug_sym(plug_f, "plug_free");
 | 
			
		||||
 | 
			
		||||
    #pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
    if (!plug->f_init || !plug->f_pre_reload ||
 | 
			
		||||
            !plug->f_poll || !plug->f_free ||
 | 
			
		||||
            !plug->f_post_reload) {
 | 
			
		||||
        dlclose(plug_f);
 | 
			
		||||
        printf("ERROR: Failed to find all functions in plugin");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PLUGMAN.plug_objs[PLUGMAN.plug_obj_count++] = plug_f;
 | 
			
		||||
    return plug;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void* load_plug_sym(void* plug_f, char* fn_name) {
 | 
			
		||||
    void* f = dlsym(plug_f, fn_name);
 | 
			
		||||
    char* err = dlerror();
 | 
			
		||||
 | 
			
		||||
    if (err){
 | 
			
		||||
       printf("ERROR: Could not load plug symbol '%s': %s\n", fn_name, err);
 | 
			
		||||
       return NULL;
 | 
			
		||||
    } 
 | 
			
		||||
    return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup_plugins(char* plugin_path) {
 | 
			
		||||
    load_plugins(plugin_path);
 | 
			
		||||
    printf("INFO: Loaded %zu plugins:\n", PLUGMAN.plug_count);
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
 | 
			
		||||
        plug->state = (plug->f_init)();
 | 
			
		||||
        
 | 
			
		||||
        if (!plug->state) {
 | 
			
		||||
            printf("Plugin '%s' did not initialise, skipping\n", plug->path);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        printf(" - %s (%s)\n", plug->state->name, plug->state->version);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_plugins(void) {
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i];
 | 
			
		||||
        (plug->f_free)();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_obj_count; i++) {
 | 
			
		||||
        dlclose(PLUGMAN.plug_objs[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
char* poll_plugins(char* sep) {
 | 
			
		||||
    char* buf = malloc(PLUG_POLL_BUF_SZ * sizeof(char));
 | 
			
		||||
 | 
			
		||||
    if (!buf) {
 | 
			
		||||
        printf("Unable to allocate buffer for polling\n");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        if (!plug->state) continue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // printf("Polling plug id %zu\n", i);
 | 
			
		||||
        size_t len = strlen(buf);
 | 
			
		||||
        (plug->f_poll)(buf + len, PLUG_POLL_BUF_SZ - len);
 | 
			
		||||
        
 | 
			
		||||
        if (i < PLUGMAN.plug_count - 1) {
 | 
			
		||||
            size_t len_post = strlen(buf);
 | 
			
		||||
            snprintf(buf + len_post, PLUG_POLL_BUF_SZ - len_post, " %s ", sep);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // printf("Setting title: '%s'\n", buf);
 | 
			
		||||
 | 
			
		||||
    return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void reload_plugins(void) {
 | 
			
		||||
    void* plug_states[PLUG_MAX_COUNT];
 | 
			
		||||
    size_t plug_count = 0;
 | 
			
		||||
    
 | 
			
		||||
    printf("INFO: Reloading plugins\n");
 | 
			
		||||
    // save states
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        void* state = (plug->f_pre_reload)();
 | 
			
		||||
        plug_states[plug_count++] = state;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // unload plugins
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_obj_count; i++) {
 | 
			
		||||
        dlclose(PLUGMAN.plug_objs[i]);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    PLUGMAN.plug_obj_count = 0;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        plug = load_plugin(plug->path, false);
 | 
			
		||||
        (plug->f_post_reload)(plug_states[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    load_plugins("./modules");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										148
									
								
								src/plugman/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/plugman/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,148 @@
 | 
			
		|||
use std::{collections::HashMap, path::{Path, PathBuf}};
 | 
			
		||||
 | 
			
		||||
use crate::ipc::Message;
 | 
			
		||||
 | 
			
		||||
use self::plugin::Plugin;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
mod plugin;
 | 
			
		||||
 | 
			
		||||
pub struct PlugMan {
 | 
			
		||||
    plugins: Vec<Plugin>,
 | 
			
		||||
    len_cap: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl PlugMan {
 | 
			
		||||
    pub fn new(len_cap: usize) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            plugins: Vec::new(),
 | 
			
		||||
            len_cap
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), PluginError>{
 | 
			
		||||
        let dir: &Path = dir.as_ref();
 | 
			
		||||
        log::debug!("Loading plugins from {:?}", dir);
 | 
			
		||||
 | 
			
		||||
        let files = std::fs::read_dir(dir)?;
 | 
			
		||||
 | 
			
		||||
        for file in files {
 | 
			
		||||
            let entry = file?;
 | 
			
		||||
            if entry.file_type()?.is_file() {
 | 
			
		||||
                let plugin = Plugin::load(entry.path().to_path_buf())?;
 | 
			
		||||
                log::info!("Loaded plugin '{}' ({}) licensed with {}", 
 | 
			
		||||
                    plugin.name().clone(),
 | 
			
		||||
                    plugin.version().clone().unwrap_or("None".to_string()),
 | 
			
		||||
                    plugin.license().clone().unwrap_or("None".to_string())
 | 
			
		||||
                );
 | 
			
		||||
                self.plugins.push(plugin);
 | 
			
		||||
            } else 
 | 
			
		||||
            if entry.file_type()?.is_dir() {
 | 
			
		||||
                self.load(entry.path().to_path_buf())?;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if self.plugins.len() == 0 {
 | 
			
		||||
            log::error!("No plugins found");
 | 
			
		||||
            return Err(PluginError::NoPlugins);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        log::info!("Loaded {} plugins", self.plugins.len());
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn init_plugins(&mut self, cfg: &crate::config::Config) {
 | 
			
		||||
        for plugin in &mut self.plugins {
 | 
			
		||||
            plugin.init(cfg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    pub fn reload_plugins(&mut self) {
 | 
			
		||||
        for plugin in &mut self.plugins {
 | 
			
		||||
            if let Err(e) = plugin.reload() {
 | 
			
		||||
                log::error!("Failed to reload plugin {:?}: {e}", plugin.name()); 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    pub fn unload_plugins(&mut self) {
 | 
			
		||||
        while let Some(plug) = self.plugins.pop() {
 | 
			
		||||
            plug.free();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn poll_plugins(&mut self) -> HashMap<String, PolledText> {
 | 
			
		||||
        let mut answers = HashMap::new();
 | 
			
		||||
        for plugin in &mut self.plugins {
 | 
			
		||||
            if !plugin.enabled() {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            match plugin.poll() {
 | 
			
		||||
                Ok(v) => {
 | 
			
		||||
                    let pth = (plugin.name().clone(), PolledText::new(v));
 | 
			
		||||
                    if !pth.1.text().is_empty() {
 | 
			
		||||
                        answers.insert(pth.0, pth.1);
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                Err(e) => log::error!("Failed to poll plugin: {e}"),
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        answers
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_msg(&mut self, msg: Message) {
 | 
			
		||||
        for plugin in &mut self.plugins {
 | 
			
		||||
            if let Some(pn) = &msg.plugin {
 | 
			
		||||
                if *pn != plugin.name() {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            plugin.send_msg(msg);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct PolledText {
 | 
			
		||||
    text: String,
 | 
			
		||||
    disabled: bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PolledText {
 | 
			
		||||
    pub fn new(text: String) -> Self {
 | 
			
		||||
        Self { text, disabled: false }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn text(&self) -> &String {
 | 
			
		||||
        &self.text
 | 
			
		||||
    }
 | 
			
		||||
    pub fn disabled(&self) -> bool {
 | 
			
		||||
        self.disabled
 | 
			
		||||
    } 
 | 
			
		||||
    pub fn disable(&mut self) {
 | 
			
		||||
        self.disabled = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum PluginError {
 | 
			
		||||
    DlOpenError,
 | 
			
		||||
    IoError,
 | 
			
		||||
    NoPlugins
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<dlopen::Error> for PluginError {
 | 
			
		||||
    fn from(_: dlopen::Error) -> Self {
 | 
			
		||||
        Self::DlOpenError
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<std::io::Error> for PluginError {
 | 
			
		||||
    fn from(_: std::io::Error) -> Self {
 | 
			
		||||
        Self::IoError
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								src/plugman/plugin/context.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/plugman/plugin/context.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
use std::ffi::{c_char, CStr, CString};
 | 
			
		||||
use super::Plugin;
 | 
			
		||||
 | 
			
		||||
pub struct PluginContextContainer {
 | 
			
		||||
    pub inner: PluginContext,
 | 
			
		||||
    _config_dir: CString
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct PluginContext {
 | 
			
		||||
    pub config_dir: *const c_char,
 | 
			
		||||
    funcs: PluginContextFuncs,
 | 
			
		||||
    buf: *mut u8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct PluginContextFuncs {
 | 
			
		||||
    log: unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PluginContext {
 | 
			
		||||
    pub fn new(plug: &Plugin, config_dir: &CString) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            config_dir: config_dir.as_ptr(),
 | 
			
		||||
            funcs: PluginContextFuncs {
 | 
			
		||||
                log: plug_log,
 | 
			
		||||
            },
 | 
			
		||||
            buf: plug.buf
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl PluginContextContainer {
 | 
			
		||||
    pub fn new(plug: &Plugin, config_dir: &String) -> Self {
 | 
			
		||||
        let _config_dir = CString::new(config_dir.clone()).unwrap();
 | 
			
		||||
        Self {
 | 
			
		||||
            inner: PluginContext::new(plug, &_config_dir),
 | 
			
		||||
            _config_dir,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub unsafe extern "C" fn plug_log(module: *const c_char, level: log::Level, s: *const c_char) {
 | 
			
		||||
    let module = CStr::from_ptr(module).to_string_lossy().to_string();
 | 
			
		||||
    let s = CStr::from_ptr(s).to_string_lossy().to_string();
 | 
			
		||||
 | 
			
		||||
    log::log!(target: &module, level, "{s}");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								src/plugman/plugin/loader.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/plugman/plugin/loader.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
use dlopen::raw::Library;
 | 
			
		||||
use crate::ipc::MessageFFI;
 | 
			
		||||
 | 
			
		||||
use super::{context::PluginContext, Plugin, PluginInfo};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub struct PluginSyms {
 | 
			
		||||
    pub(super) init:        unsafe extern "C" fn(ctx: *const PluginContext) -> i32,
 | 
			
		||||
    pub(super) pre_reload:  unsafe extern "C" fn() -> *const (),
 | 
			
		||||
    pub(super) post_reload: unsafe extern "C" fn(state: *const ()) -> i32,
 | 
			
		||||
    pub(super) on_msg:      unsafe extern "C" fn(msg: *const MessageFFI) -> i32,
 | 
			
		||||
    pub(super) free:        unsafe extern "C" fn() -> i32,
 | 
			
		||||
    pub(super) get_info:    unsafe extern "C" fn() -> *const PluginInfo,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Plugin {
 | 
			
		||||
    pub fn reload_symbols(&mut self) -> Result<(), dlopen::Error> {
 | 
			
		||||
        log::debug!("Loading {:?}", self.path);
 | 
			
		||||
        let lib = Library::open(&self.path)?;
 | 
			
		||||
        let symbols = PluginSyms { 
 | 
			
		||||
            init: unsafe { lib.symbol("plug_init")? },
 | 
			
		||||
            pre_reload: unsafe { lib.symbol("plug_pre_reload")? },
 | 
			
		||||
            post_reload: unsafe { lib.symbol("plug_post_reload")? },
 | 
			
		||||
            on_msg: unsafe { lib.symbol("plug_on_msg")? },
 | 
			
		||||
            free: unsafe { lib.symbol("plug_free")? },
 | 
			
		||||
 | 
			
		||||
            get_info: unsafe { lib.symbol("plug_get_info")? },
 | 
			
		||||
        };
 | 
			
		||||
        unsafe {
 | 
			
		||||
            if (symbols.get_info)().is_null() {
 | 
			
		||||
                log::error!("Info fields for plugin {:?} are null", self.path);
 | 
			
		||||
                self.disable();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.syms = Some(symbols);
 | 
			
		||||
        self.lib = Some(lib);
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										159
									
								
								src/plugman/plugin/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/plugman/plugin/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,159 @@
 | 
			
		|||
use std::{alloc::Layout, ffi::{c_char, CStr}, path::PathBuf};
 | 
			
		||||
 | 
			
		||||
use dlopen::raw::Library;
 | 
			
		||||
 | 
			
		||||
use crate::{config::Config, ipc::{Message, MessageFFI}};
 | 
			
		||||
 | 
			
		||||
use self::context::{PluginContext, PluginContextContainer};
 | 
			
		||||
 | 
			
		||||
pub mod loader;
 | 
			
		||||
pub mod context;
 | 
			
		||||
 | 
			
		||||
const MEM_LAYOUT: Result<Layout, std::alloc::LayoutError> = Layout::from_size_align(2048, 1);
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
pub struct PluginInfo {
 | 
			
		||||
    name: *const c_char,
 | 
			
		||||
    version: *const c_char,
 | 
			
		||||
    license: *const c_char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Plugin {
 | 
			
		||||
    syms: Option<loader::PluginSyms>,
 | 
			
		||||
    path: PathBuf,
 | 
			
		||||
    lib: Option<Library>,
 | 
			
		||||
    enabled: bool,
 | 
			
		||||
    buf: *mut u8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
impl Plugin {
 | 
			
		||||
    pub fn load(path: PathBuf) -> Result<Self, dlopen::Error> {
 | 
			
		||||
        let buf = unsafe {
 | 
			
		||||
            std::alloc::alloc_zeroed(MEM_LAYOUT.unwrap())
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut s = Self {
 | 
			
		||||
            enabled: true,
 | 
			
		||||
            path,
 | 
			
		||||
            syms: None,
 | 
			
		||||
            lib: None,
 | 
			
		||||
            buf
 | 
			
		||||
        };
 | 
			
		||||
        s.reload_symbols()?;
 | 
			
		||||
        Ok(s)
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    pub fn syms(&self) -> loader::PluginSyms {
 | 
			
		||||
        self.syms.unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn init(&mut self, cfg: &Config) {
 | 
			
		||||
        let conf_dir = &cfg.config_dir.join(self.name()).to_string_lossy().to_string();
 | 
			
		||||
        let _ = std::fs::create_dir(&conf_dir); // dont care 
 | 
			
		||||
        let ctx = PluginContextContainer::new(self, conf_dir);
 | 
			
		||||
        
 | 
			
		||||
        unsafe {
 | 
			
		||||
            if (self.syms().init)(&ctx.inner as *const PluginContext) != 0 {
 | 
			
		||||
                log::warn!("`init` had an error, disabling");
 | 
			
		||||
                self.disable();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn reload(&mut self) -> Result<(), dlopen::Error> { 
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let state = (self.syms().pre_reload)();
 | 
			
		||||
            
 | 
			
		||||
            if state.is_null() {
 | 
			
		||||
                log::warn!("`pre_reload` had an error, disabling");
 | 
			
		||||
                self.disable();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if let Err(e) = self.reload_symbols() {
 | 
			
		||||
                self.disable();
 | 
			
		||||
                return Err(e);
 | 
			
		||||
            }
 | 
			
		||||
            if (self.syms().post_reload)(state) != 0 {
 | 
			
		||||
                log::warn!("`post_reload` had an error, disabling");
 | 
			
		||||
                self.disable();
 | 
			
		||||
            }
 | 
			
		||||
        
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_msg(&mut self, msg: Message) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            // log::debug!("Sending message to '{}': {:?}", self.name(), msg);
 | 
			
		||||
            if (self.syms().on_msg)(&msg.ffi  as *const MessageFFI) != 0 {
 | 
			
		||||
                log::warn!("`on_msg` had an error, disabling");
 | 
			
		||||
                self.disable();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn poll(&mut self) -> Result<String, std::string::FromUtf8Error> {
 | 
			
		||||
        self.send_msg(Message::from_string("poll"));
 | 
			
		||||
        let s = unsafe {
 | 
			
		||||
            CStr::from_ptr(self.buf as *const c_char).to_string_lossy().to_string()
 | 
			
		||||
        }; 
 | 
			
		||||
        
 | 
			
		||||
        if !s.is_empty() {
 | 
			
		||||
            // log::debug!("Polled: {}", s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(s)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    pub fn free(mut self) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            if (self.syms().free)() != 0 {
 | 
			
		||||
                log::warn!("`free` had an error, disabling");
 | 
			
		||||
                self.disable(); // Literaly useless but eh
 | 
			
		||||
            }
 | 
			
		||||
            std::alloc::dealloc(self.buf, MEM_LAYOUT.unwrap());
 | 
			
		||||
        }
 | 
			
		||||
        drop(self.lib.unwrap()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn enabled(&self) -> bool {
 | 
			
		||||
        self.enabled
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn disable(&mut self) {
 | 
			
		||||
        self.enabled = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn name(&self) -> String {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let info = (self.syms().get_info)();
 | 
			
		||||
            CStr::from_ptr((*info).name).to_string_lossy().to_string()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn version(&self) -> Option<String> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let info = (self.syms().get_info)();
 | 
			
		||||
            let v = (*info).version;
 | 
			
		||||
            if v.is_null() {
 | 
			
		||||
                return None;
 | 
			
		||||
            }
 | 
			
		||||
            Some(CStr::from_ptr(v).to_string_lossy().to_string())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn license(&self) -> Option<String> {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            let info = (self.syms().get_info)();
 | 
			
		||||
            let v = (*info).license;
 | 
			
		||||
            if v.is_null() {
 | 
			
		||||
                return None;
 | 
			
		||||
            }
 | 
			
		||||
            Some(CStr::from_ptr(v).to_string_lossy().to_string())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										189
									
								
								src/socket.c
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								src/socket.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,189 +0,0 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/select.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "socket.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#define SOCKET_PATH "/tmp/dim.sock"
 | 
			
		||||
#define BUFFER_SIZE 255
 | 
			
		||||
 | 
			
		||||
typedef struct sock_server_t {
 | 
			
		||||
    int s_fd;
 | 
			
		||||
    int c_fd;
 | 
			
		||||
    struct sockaddr_un s_addr;
 | 
			
		||||
    char buf[BUFFER_SIZE];
 | 
			
		||||
    int max_fd;
 | 
			
		||||
    fd_set read_fds;
 | 
			
		||||
} sock_server_t;
 | 
			
		||||
 | 
			
		||||
sock_server_t SOCK_SERVER = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int socket_init(void) {
 | 
			
		||||
    
 | 
			
		||||
    // Check if socket exists
 | 
			
		||||
    if (access(SOCKET_PATH, F_OK) == 0) {
 | 
			
		||||
        remove(SOCKET_PATH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Create the socket
 | 
			
		||||
    SOCK_SERVER.s_fd = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
    if (SOCK_SERVER.s_fd == -1) {
 | 
			
		||||
        perror("ERROR: Failed to create socket");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int flags = fcntl(SOCK_SERVER.s_fd, F_GETFL, 0);
 | 
			
		||||
    if (fcntl(SOCK_SERVER.s_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to set socket to non blocking");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set up the server address structure
 | 
			
		||||
    memset(&SOCK_SERVER.s_addr, 0, sizeof(struct sockaddr_un));
 | 
			
		||||
    SOCK_SERVER.s_addr.sun_family = AF_UNIX;
 | 
			
		||||
    strncpy(SOCK_SERVER.s_addr.sun_path, SOCKET_PATH, sizeof(SOCK_SERVER.s_addr.sun_path) - 1);
 | 
			
		||||
 | 
			
		||||
    // Bind the socket to the address
 | 
			
		||||
    int berr = bind(
 | 
			
		||||
                SOCK_SERVER.s_fd,
 | 
			
		||||
                (struct sockaddr *)&SOCK_SERVER.s_addr,
 | 
			
		||||
                sizeof(struct sockaddr_un));
 | 
			
		||||
 | 
			
		||||
    if (berr == -1) {
 | 
			
		||||
        perror("ERROR: Failed to bind to socket");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Listen for incoming connections
 | 
			
		||||
    if (listen(SOCK_SERVER.s_fd, 5) == -1) {
 | 
			
		||||
        perror("ERRROR: Failed to start listening for messages in the socket");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("INFO: Server is listening on %s\n", SOCKET_PATH);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct timeval timeout = {0};
 | 
			
		||||
 | 
			
		||||
sock_msg_t socket_poll(void) {
 | 
			
		||||
    FD_ZERO(&SOCK_SERVER.read_fds);
 | 
			
		||||
    FD_SET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds);
 | 
			
		||||
    SOCK_SERVER.max_fd = SOCK_SERVER.s_fd;
 | 
			
		||||
    
 | 
			
		||||
    // Add client sockets to the set
 | 
			
		||||
    if (SOCK_SERVER.c_fd > 0) {
 | 
			
		||||
        FD_SET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds);
 | 
			
		||||
        if (SOCK_SERVER.c_fd > SOCK_SERVER.max_fd) {
 | 
			
		||||
            SOCK_SERVER.max_fd = SOCK_SERVER.c_fd;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Wait for an activity on one of the sockets
 | 
			
		||||
    int activity = select(SOCK_SERVER.max_fd + 1, &SOCK_SERVER.read_fds, NULL, NULL, &timeout);
 | 
			
		||||
 | 
			
		||||
    if (activity < 0 && errno != EINTR) {
 | 
			
		||||
        perror("select error");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // If something happened on the server socket, it's an incoming connection
 | 
			
		||||
    if (FD_ISSET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds)) {
 | 
			
		||||
        if ((SOCK_SERVER.c_fd = accept(SOCK_SERVER.s_fd, NULL, NULL)) == -1) {
 | 
			
		||||
            if (errno != EWOULDBLOCK && errno != EAGAIN) {
 | 
			
		||||
                perror("accept error");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //printf("Accepted new connection\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // If something happened on the client socket, it's incoming data
 | 
			
		||||
    if (SOCK_SERVER.c_fd > 0 && FD_ISSET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds)) {
 | 
			
		||||
        int num_bytes = read(SOCK_SERVER.c_fd, SOCK_SERVER.buf, BUFFER_SIZE - 1);
 | 
			
		||||
        if (num_bytes > 0) {
 | 
			
		||||
            SOCK_SERVER.buf[num_bytes] = '\0'; // Null-terminate the buffer
 | 
			
		||||
            return (sock_msg_t)atoi(SOCK_SERVER.buf);
 | 
			
		||||
            //printf("Received message: %s\n", SOCK_SERVER.buf);
 | 
			
		||||
        } else if (num_bytes == 0) {
 | 
			
		||||
            // Client disconnected
 | 
			
		||||
            //printf("Client disconnected\n");
 | 
			
		||||
            close(SOCK_SERVER.c_fd);
 | 
			
		||||
            SOCK_SERVER.c_fd = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (errno != EWOULDBLOCK && errno != EAGAIN) {
 | 
			
		||||
                perror("read error");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return SM_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void socket_close(void) {
 | 
			
		||||
    close(SOCK_SERVER.s_fd);
 | 
			
		||||
    unlink(SOCKET_PATH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void socket_send(char* msg_str) {
 | 
			
		||||
    to_lowercase(msg_str);
 | 
			
		||||
    
 | 
			
		||||
    sock_msg_t msg_t = SM_NONE;
 | 
			
		||||
 | 
			
		||||
    if (strcmp(msg_str, "reload") == 0) {
 | 
			
		||||
        msg_t = SM_RELOAD;
 | 
			
		||||
    } else {
 | 
			
		||||
        printf("ERROR: Unknown message type '%s'\n", msg_str);
 | 
			
		||||
        printf("NOTE: Available messages:\n");
 | 
			
		||||
        printf(" - reload\n");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int client_fd;
 | 
			
		||||
    struct sockaddr_un server_addr;
 | 
			
		||||
 | 
			
		||||
    // Create the socket
 | 
			
		||||
    if ((client_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to create error");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set up the server address structure
 | 
			
		||||
    memset(&server_addr, 0, sizeof(struct sockaddr_un));
 | 
			
		||||
    server_addr.sun_family = AF_UNIX;
 | 
			
		||||
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
 | 
			
		||||
 | 
			
		||||
    // Connect to the server
 | 
			
		||||
    if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to connect to server");
 | 
			
		||||
        close(client_fd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    char msg[255];
 | 
			
		||||
 | 
			
		||||
    snprintf(msg, 255, "%d", msg_t);
 | 
			
		||||
 | 
			
		||||
    // Send a message to the server
 | 
			
		||||
    if (write(client_fd, msg, strlen(msg)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to write message to server");
 | 
			
		||||
        close(client_fd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clean up
 | 
			
		||||
    close(client_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/util.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/util.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
void to_lowercase(char* str) {
 | 
			
		||||
    for(int i = 0; str[i]; i++){
 | 
			
		||||
      str[i] = tolower(str[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void to_uppercase(char* str) {
 | 
			
		||||
    for(int i = 0; str[i]; i++){
 | 
			
		||||
      str[i] = tolower(str[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user