66#include <stdlib.h>
77#include <string.h>
88#include <ctype.h>
9+ #include <pthread.h>
910
1011static char latest_version [64 ] = {0 };
11- static int checked = 0 ;
12+ static int check_state = 0 ; /* 0=idle, 1=checking, 2=checked */
13+ static pthread_mutex_t check_mutex = PTHREAD_MUTEX_INITIALIZER ;
1214
1315static int parse_version (const char * s , int * major , int * minor , int * patch ) {
1416 if (!s ) return -1 ;
@@ -29,16 +31,13 @@ int updater_compare_versions(const char *a, const char *b) {
2931 return a_pat - b_pat ;
3032}
3133
32- int updater_check (void ) {
34+ /* Blocking implementation (runs in background thread) */
35+ static int do_check (void ) {
3336 FILE * fp ;
3437 char buf [4096 ];
3538 const char * tag ;
3639 size_t len ;
3740
38- /*
39- * Query GitHub Releases API. curl is available on Raspberry Pi OS
40- * by default; the -s flag suppresses progress, -m limits timeout.
41- */
4241 fp = popen ("curl -s -m 10 "
4342 "https://api.github.com/repos/kmatzen/millennium/releases/latest"
4443 " 2>/dev/null" , "r" );
@@ -55,20 +54,15 @@ int updater_check(void) {
5554 }
5655 buf [len ] = '\0' ;
5756
58- /*
59- * Minimal JSON extraction: find "tag_name" : "vX.Y.Z"
60- * Full JSON parsing is overkill for a single field.
61- */
6257 tag = strstr (buf , "\"tag_name\"" );
6358 if (!tag ) {
6459 logger_debug_with_category ("Updater" , "No tag_name in GitHub response (may have no releases)" );
6560 return -1 ;
6661 }
6762
68- /* Advance past the key and colon to the value */
6963 tag = strchr (tag + 10 , '"' );
7064 if (!tag ) return -1 ;
71- tag ++ ; /* skip opening quote */
65+ tag ++ ;
7266
7367 {
7468 const char * end = strchr (tag , '"' );
@@ -77,7 +71,6 @@ int updater_check(void) {
7771 latest_version [end - tag ] = '\0' ;
7872 }
7973
80- checked = 1 ;
8174 {
8275 char log_msg [128 ];
8376 snprintf (log_msg , sizeof (log_msg ),
@@ -88,13 +81,70 @@ int updater_check(void) {
8881 return 0 ;
8982}
9083
84+ static void * check_thread_func (void * arg ) {
85+ (void )arg ;
86+ int rc = do_check ();
87+ pthread_mutex_lock (& check_mutex );
88+ check_state = 2 ; /* checked */
89+ if (rc != 0 ) latest_version [0 ] = '\0' ;
90+ pthread_mutex_unlock (& check_mutex );
91+ return NULL ;
92+ }
93+
94+ /* #119: Non-blocking. Starts background check if idle; returns immediately. */
95+ void updater_check_async (void ) {
96+ pthread_t th ;
97+ pthread_mutex_lock (& check_mutex );
98+ if (check_state == 0 ) {
99+ check_state = 1 ;
100+ pthread_mutex_unlock (& check_mutex );
101+ if (pthread_create (& th , NULL , check_thread_func , NULL ) == 0 ) {
102+ pthread_detach (th );
103+ } else {
104+ pthread_mutex_lock (& check_mutex );
105+ check_state = 0 ;
106+ pthread_mutex_unlock (& check_mutex );
107+ }
108+ } else {
109+ pthread_mutex_unlock (& check_mutex );
110+ }
111+ }
112+
113+ /* Returns 1 if a check is in progress (curl running in background). */
114+ int updater_is_checking (void ) {
115+ int s ;
116+ pthread_mutex_lock (& check_mutex );
117+ s = (check_state == 1 );
118+ pthread_mutex_unlock (& check_mutex );
119+ return s ;
120+ }
121+
122+ /* Legacy blocking API; prefer updater_check_async for HTTP handlers. */
123+ int updater_check (void ) {
124+ int rc = do_check ();
125+ pthread_mutex_lock (& check_mutex );
126+ check_state = 2 ;
127+ if (rc != 0 ) latest_version [0 ] = '\0' ;
128+ pthread_mutex_unlock (& check_mutex );
129+ return rc ;
130+ }
131+
91132const char * updater_get_latest_version (void ) {
92- return checked ? latest_version : NULL ;
133+ const char * v = NULL ;
134+ pthread_mutex_lock (& check_mutex );
135+ if (check_state == 2 && latest_version [0 ]) v = latest_version ;
136+ pthread_mutex_unlock (& check_mutex );
137+ return v ;
93138}
94139
95140int updater_is_update_available (void ) {
96- if (!checked ) return 0 ;
97- return updater_compare_versions (latest_version , version_get_string ()) > 0 ;
141+ const char * lv ;
142+ int avail = 0 ;
143+ pthread_mutex_lock (& check_mutex );
144+ lv = (check_state == 2 && latest_version [0 ]) ? latest_version : NULL ;
145+ pthread_mutex_unlock (& check_mutex );
146+ if (lv ) avail = updater_compare_versions (lv , version_get_string ()) > 0 ;
147+ return avail ;
98148}
99149
100150static char apply_status [256 ] = "No update attempted" ;
0 commit comments