@@ -23,16 +23,20 @@ use {
23
23
} ,
24
24
gefolge_websocket:: event:: Event ,
25
25
rand:: prelude:: * ,
26
+ tiny_skia:: Pixmap ,
26
27
tokio:: {
27
28
fs:: {
28
29
self ,
29
30
File ,
30
31
} ,
31
32
io:: AsyncReadExt as _,
32
- sync:: mpsc,
33
33
time:: sleep,
34
34
} ,
35
- crate :: Error ,
35
+ winit:: event_loop:: EventLoopProxy ,
36
+ crate :: {
37
+ Error ,
38
+ UserEvent ,
39
+ } ,
36
40
} ;
37
41
38
42
#[ derive( Clone , Copy , PartialEq , Eq , Hash , Sequence ) ]
@@ -50,7 +54,7 @@ impl Mode {
50
54
Self :: BinaryTime => {
51
55
let timezone = current_event?. timezone ;
52
56
let now = Utc :: now ( ) . with_timezone ( & timezone) ;
53
- let tomorrow = now. date ( ) . succ ( ) ;
57
+ let tomorrow = now. date_naive ( ) . succ_opt ( ) . expect ( "date overflow" ) ;
54
58
if tomorrow. month ( ) == 1 && tomorrow. day ( ) == 1 {
55
59
Some ( ( Priority :: Normal , State :: BinaryTime ( timezone) ) )
56
60
} else {
@@ -74,8 +78,8 @@ impl Mode {
74
78
if now. month ( ) == 1 && now. day ( ) == 1 && now. hour ( ) == 1 {
75
79
Some ( Priority :: Programm )
76
80
} else {
77
- let tomorrow = now. date ( ) . succ ( ) ;
78
- ( tomorrow. month ( ) == 1 && tomorrow. day ( ) == 1 ) . then ( || if tomorrow. and_hms ( 0 , 0 , 0 ) - now < Duration :: hours ( 1 ) . into ( ) {
81
+ let tomorrow = now. date_naive ( ) . succ_opt ( ) . expect ( "date overflow" ) ;
82
+ ( tomorrow. month ( ) == 1 && tomorrow. day ( ) == 1 ) . then ( || if timezone . from_local_datetime ( & tomorrow. and_hms_opt ( 0 , 0 , 0 ) . expect ( "tomorrow has no midnight" ) ) . single ( ) . expect ( "failed to determine tomorrow at midnight" ) - now < Duration :: hours ( 1 ) . into ( ) {
79
83
Priority :: Programm
80
84
} else {
81
85
Priority :: Normal
@@ -93,6 +97,7 @@ enum Priority {
93
97
Programm ,
94
98
}
95
99
100
+ #[ allow( unused) ] //TODO
96
101
#[ derive( Debug , Clone ) ]
97
102
pub ( crate ) enum State {
98
103
BinaryTime ( Tz ) ,
@@ -101,61 +106,44 @@ pub(crate) enum State {
101
106
HexagesimalTime ( Tz ) ,
102
107
Logo {
103
108
msg : & ' static str ,
104
- img : Option < Vec < u8 > > ,
105
109
} ,
106
110
NewYear ( Tz ) ,
107
111
}
108
112
109
- impl State {
110
- fn set ( & mut self , new_state : & State ) {
111
- if let ( State :: Logo { img : Some ( img) , .. } , State :: Logo { img : None , msg } ) = ( & self , new_state) {
112
- * self = State :: Logo { img : Some ( img. clone ( ) ) , msg : * msg } ;
113
- } else {
114
- * self = new_state. clone ( ) ;
115
- }
113
+ async fn load_images_inner ( state_tx : EventLoopProxy < UserEvent > ) -> Result < ( ) , Error > {
114
+ let dirs = stream:: iter ( xdg_basedir:: get_cache_home ( ) . into_iter ( ) ) ;
115
+ let files = dirs. filter_map ( |cfg_dir| async move { File :: open ( cfg_dir. join ( "fidera/gefolge.png" ) ) . await . ok ( ) } ) ;
116
+ pin_mut ! ( files) ;
117
+ if let Some ( mut file) = files. next ( ) . await {
118
+ let mut buf = Vec :: default ( ) ;
119
+ file. read_to_end ( & mut buf) . await ?;
120
+ tokio:: task:: block_in_place ( || Ok :: < _ , Error > ( state_tx. send_event ( UserEvent :: Logo ( Pixmap :: decode_png ( & buf) ?) ) ?) ) ?;
121
+ } else {
122
+ let cache_dir = xdg_basedir:: get_cache_home ( ) ?. join ( "fidera" ) ;
123
+ fs:: create_dir_all ( & cache_dir) . await ?;
124
+ let buf = reqwest:: get ( "https://gefolge.org/static/gefolge.png" ) . await ?
125
+ . error_for_status ( ) ?
126
+ . bytes ( ) . await ?
127
+ . to_vec ( ) ;
128
+ fs:: write ( cache_dir. join ( "gefolge.png" ) , & buf) . await ?;
129
+ tokio:: task:: block_in_place ( || Ok :: < _ , Error > ( state_tx. send_event ( UserEvent :: Logo ( Pixmap :: decode_png ( & buf) ?) ) ?) ) ?;
116
130
}
131
+ Ok ( ( ) )
132
+ }
117
133
118
- fn set_message ( & mut self , new_msg : & ' static str ) {
119
- match self {
120
- State :: Logo { msg, .. } => * msg = new_msg,
121
- _ => * self = State :: Logo { msg : new_msg, img : None } ,
122
- }
134
+ pub ( crate ) async fn load_images ( state_tx : EventLoopProxy < UserEvent > ) {
135
+ if let Err ( e) = load_images_inner ( state_tx) . await {
136
+ eprintln ! ( "error loading images: {e} (debug: {e:?})" ) ; //TODO send error to event loop?
123
137
}
124
138
}
125
139
126
- async fn maintain_inner ( mut rng : impl Rng , current_event : Option < Event > , states_tx : mpsc:: Sender < State > ) -> Result < Never , Error > {
127
- let mut state = State :: Logo {
128
- msg : "loading Gefolge logo" ,
129
- img : None ,
130
- } ;
131
- states_tx. send ( state. clone ( ) ) . await ?;
132
- if let State :: Logo { ref mut img, .. } = state {
133
- let dirs = stream:: iter ( xdg_basedir:: get_cache_home ( ) . into_iter ( ) ) ;
134
- let files = dirs. filter_map ( |cfg_dir| async move { File :: open ( cfg_dir. join ( "fidera/gefolge.png" ) ) . await . ok ( ) } ) ;
135
- pin_mut ! ( files) ;
136
- if let Some ( mut file) = files. next ( ) . await {
137
- let mut buf = Vec :: default ( ) ;
138
- file. read_to_end ( & mut buf) . await ?;
139
- * img = Some ( buf) ;
140
- } else {
141
- let cache_dir = xdg_basedir:: get_cache_home ( ) ?. join ( "fidera" ) ;
142
- fs:: create_dir_all ( & cache_dir) . await ?;
143
- let buf = reqwest:: get ( "https://gefolge.org/static/gefolge.png" ) . await ?
144
- . error_for_status ( ) ?
145
- . bytes ( ) . await ?
146
- . to_vec ( ) ;
147
- fs:: write ( cache_dir. join ( "gefolge.png" ) , & buf) . await ?;
148
- * img = Some ( buf) ;
149
- }
150
- states_tx. send ( state. clone ( ) ) . await ?;
151
- }
140
+ async fn maintain_inner ( mut rng : impl Rng + Send , current_event : Option < Event > , states_tx : EventLoopProxy < UserEvent > ) -> Result < Never , Error > {
141
+ tokio:: task:: block_in_place ( || states_tx. send_event ( UserEvent :: State ( State :: Logo { msg : "loading Gefolge logo" } ) ) ) ?;
152
142
if rng. gen_bool ( 0.1 ) {
153
- state. set_message ( "reticulating splines" ) ;
154
- states_tx. send ( state. clone ( ) ) . await ?;
143
+ tokio:: task:: block_in_place ( || states_tx. send_event ( UserEvent :: State ( State :: Logo { msg : "reticulating splines" } ) ) ) ?;
155
144
sleep ( StdDuration :: from_secs_f64 ( rng. gen_range ( 0.5 ..1.5 ) ) ) . await ;
156
145
}
157
- state. set_message ( "determining first mode" ) ;
158
- states_tx. send ( state. clone ( ) ) . await ?;
146
+ tokio:: task:: block_in_place ( || states_tx. send_event ( UserEvent :: State ( State :: Logo { msg : "determining first mode" } ) ) ) ?;
159
147
let mut seen_modes = HashSet :: new ( ) ;
160
148
loop { //TODO keep listening to WebSocket
161
149
let mut available_modes = all :: < Mode > ( ) . filter_map ( |mode| Some ( ( mode, mode. state ( current_event. as_ref ( ) ) ?) ) ) . collect :: < Vec < _ > > ( ) ;
@@ -168,18 +156,17 @@ async fn maintain_inner(mut rng: impl Rng, current_event: Option<Event>, states_
168
156
}
169
157
if let Some ( ( mode, ( _, new_state) ) ) = available_modes. choose ( & mut rng) {
170
158
seen_modes. insert ( * mode) ;
171
- state . set ( new_state) ; //TODO reload image if necessary
159
+ tokio :: task :: block_in_place ( || states_tx . send_event ( UserEvent :: State ( new_state. clone ( ) ) ) ) ? ;
172
160
} else {
173
- state . set_message ( "no modes available" ) ;
161
+ tokio :: task :: block_in_place ( || states_tx . send_event ( UserEvent :: State ( State :: Logo { msg : "no modes available" } ) ) ) ? ;
174
162
} ;
175
- states_tx. send ( state. clone ( ) ) . await ?;
176
163
sleep ( StdDuration :: from_secs ( 10 ) ) . await ;
177
164
}
178
165
}
179
166
180
- pub ( crate ) async fn maintain ( rng : impl Rng , current_event : Option < Event > , states_tx : mpsc :: Sender < State > ) {
167
+ pub ( crate ) async fn maintain ( rng : impl Rng + Send , current_event : Option < Event > , states_tx : EventLoopProxy < UserEvent > ) {
181
168
match maintain_inner ( rng, current_event, states_tx. clone ( ) ) . await {
182
169
Ok ( never) => match never { } ,
183
- Err ( e) => { let _ = states_tx. send ( State :: Error ( Arc :: new ( e) ) ) . await ; }
170
+ Err ( e) => { let _ = tokio :: task :: block_in_place ( || states_tx. send_event ( UserEvent :: State ( State :: Error ( Arc :: new ( e) ) ) ) ) ; }
184
171
}
185
172
}
0 commit comments