@@ -10,7 +10,64 @@ use crate::constants;
1010/// the string passed to said printer will consist of one or more lines of text.
1111pub fn tail_scriptslog < P > ( printer : P , refresh_time_millis : u64 , cancel_token : Receiver < ( ) > , custom_path : Option < String > ) -> Option < String >
1212where P : Fn ( & String ) -> ( ) {
13- match scriptslog_file ( custom_path) {
13+ if let Some ( p) = custom_path {
14+ tail_scriptslog_loop ( Path :: new ( & p) . to_path_buf ( ) , printer, refresh_time_millis, cancel_token)
15+ } else {
16+ match scriptslog_file_path ( ) {
17+ Ok ( p) => {
18+ tail_scriptslog_loop ( p, printer, refresh_time_millis, cancel_token)
19+ }
20+ Err ( e) => {
21+ Some ( e)
22+ }
23+ }
24+ }
25+ }
26+
27+ fn scriptslog_file_path ( ) -> Result < PathBuf , String > {
28+ let mut docs = None ;
29+ if let Some ( ud) = UserDirs :: new ( ) {
30+ if cfg ! ( windows) {
31+ if let Some ( path) = ud. document_dir ( ) {
32+ docs = Some ( path. to_owned ( ) ) ;
33+ }
34+ }
35+ else if cfg ! ( unix) {
36+ if let Some ( path) = Some ( ud. home_dir ( ) ) {
37+ docs = Some ( path. join ( constants:: LINUX_STEAM_PFX_PATH ) . to_owned ( ) ) ;
38+ }
39+ }
40+ else {
41+ unimplemented ! ( ) ;
42+ }
43+ }
44+
45+ if let Some ( docs) = docs {
46+ return Ok ( docs. join ( Path :: new ( "The Witcher 3" ) . join ( constants:: SCRIPTSLOG_FILE_NAME ) ) ) ;
47+ } else {
48+ return Err ( "Documents directory could not be found." . to_owned ( ) ) ;
49+ }
50+ }
51+
52+ fn open_scriptslog ( path : & PathBuf ) -> Result < File , String > {
53+ let file = OpenOptions :: new ( )
54+ . read ( true )
55+ . write ( true ) // so that it can be created if doesn't exist
56+ . create ( true )
57+ . open ( path) ;
58+
59+ if let Err ( e) = file {
60+ println ! ( "{:?}" , e. kind( ) ) ;
61+ return Err ( "File open error: " . to_owned ( ) + & e. to_string ( ) ) ;
62+ } else {
63+ return Ok ( file. unwrap ( ) ) ;
64+ }
65+ }
66+
67+ #[ cfg( target_os = "windows" ) ]
68+ fn tail_scriptslog_loop < P > ( scriptslog_path : PathBuf , printer : P , refresh_time_millis : u64 , cancel_token : Receiver < ( ) > ) -> Option < String >
69+ where P : Fn ( & String ) -> ( ) {
70+ match open_scriptslog ( & scriptslog_path) {
1471 Ok ( file) => {
1572 let mut reader = BufReader :: new ( & file) ;
1673 // start from the end of the file
@@ -53,50 +110,61 @@ where P: Fn(&String) -> () {
53110 Err ( e) => {
54111 Some ( e)
55112 }
56- }
113+ }
57114}
58115
59- fn scriptslog_file ( custon_path : Option < String > ) -> Result < File , String > {
60- let scriptslog_path: PathBuf ;
61-
62- if let Some ( custom_path) = custon_path {
63- scriptslog_path = Path :: new ( & custom_path) . to_owned ( ) ;
64- } else if let Some ( ud) = UserDirs :: new ( ) {
65- let mut docs = None ;
66- if cfg ! ( windows) {
67- if let Some ( path) = ud. document_dir ( ) {
68- docs = Some ( path. to_owned ( ) ) ;
69- }
70- }
71- else if cfg ! ( unix) {
72- if let Some ( path) = Some ( ud. home_dir ( ) ) {
73- docs = Some ( path. join ( constants:: LINUX_STEAM_PFX_PATH ) . to_owned ( ) ) ;
116+ #[ cfg( target_os = "linux" ) ]
117+ fn tail_scriptslog_loop < P > ( scriptslog_path : PathBuf , printer : P , refresh_time_millis : u64 , cancel_token : Receiver < ( ) > ) -> Option < String >
118+ where P : Fn ( & String ) -> ( ) {
119+ let mut last_pos: u64 ;
120+ match open_scriptslog ( & scriptslog_path) {
121+ Ok ( file) => last_pos = file. metadata ( ) . unwrap ( ) . len ( ) ,
122+ Err ( e) => {
123+ return Some ( e)
124+ }
125+ }
126+
127+ let mut text = String :: new ( ) ;
128+ loop {
129+ match cancel_token. try_recv ( ) {
130+ Ok ( _) | Err ( TryRecvError :: Disconnected ) => {
131+ break ;
74132 }
75- }
76- else {
77- unimplemented ! ( ) ;
133+ Err ( _) => { }
78134 }
135+
136+ // on linux file system is different in a sense that we have to reopen the file to see the changes made to it
137+ match open_scriptslog ( & scriptslog_path) {
138+ Ok ( file) => {
139+ let mut reader = BufReader :: new ( & file) ;
140+ let filesize = file. metadata ( ) . unwrap ( ) . len ( ) ;
79141
80- if let Some ( docs ) = docs {
81- scriptslog_path = docs . join ( Path :: new ( "The Witcher 3" ) . join ( constants :: SCRIPTSLOG_FILE_NAME ) ) ;
82- } else {
83- return Err ( "Documents directory could not be found." . to_owned ( ) ) ;
84- }
142+ if last_pos > filesize {
143+ last_pos = reader . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
144+ } else {
145+ reader . seek ( SeekFrom :: Start ( last_pos ) ) . unwrap ( ) ;
146+ }
85147
86- } else {
87- return Err ( "Scriptslog path could not be resolved" . to_owned ( ) ) ;
148+ text. clear ( ) ;
149+ match reader. read_to_string ( & mut text) {
150+ Ok ( size) => {
151+ if size > 0 {
152+ last_pos += size as u64 ;
153+ printer ( & text) ;
154+ }
155+ }
156+ Err ( e) => {
157+ return Some ( "File read error: " . to_owned ( ) + & e. to_string ( ) )
158+ }
159+ }
160+ }
161+ Err ( e) => {
162+ return Some ( e)
163+ }
164+ }
165+
166+ std:: thread:: sleep ( Duration :: from_millis ( refresh_time_millis ) ) ;
88167 }
89168
90- let file = OpenOptions :: new ( )
91- . read ( true )
92- . write ( true ) // so that it can be created if doesn't exist
93- . create ( true )
94- . open ( scriptslog_path) ;
95-
96- if let Err ( e) = file {
97- println ! ( "{:?}" , e. kind( ) ) ;
98- return Err ( "File open error: " . to_owned ( ) + & e. to_string ( ) ) ;
99- } else {
100- return Ok ( file. unwrap ( ) ) ;
101- }
169+ None
102170}
0 commit comments