/[LeafOK_CVS]/lbbs/src/user_list.c
ViewVC logotype

Diff of /lbbs/src/user_list.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.9 by sysadm, Wed Oct 22 07:39:02 2025 UTC Revision 1.29 by sysadm, Wed Nov 5 04:19:21 2025 UTC
# Line 1  Line 1 
1  /***************************************************************************  /* SPDX-License-Identifier: GPL-3.0-or-later */
2                                                   user_list.c  -  description  /*
3                                                           -------------------   * user_list
4          Copyright            : (C) 2004-2025 by Leaflet   *   - data model and basic operations of (online) user list
5          Email                : leaflet@leafok.com   *
6   ***************************************************************************/   * Copyright (C) 2004-2025  Leaflet <leaflet@leafok.com>
7     */
 /***************************************************************************  
  *                                                                         *  
  *   This program is free software; you can redistribute it and/or modify  *  
  *   it under the terms of the GNU General Public License as published by  *  
  *   the Free Software Foundation; either version 3 of the License, or     *  
  *   (at your option) any later version.                                   *  
  *                                                                         *  
  ***************************************************************************/  
8    
9  #include "common.h"  #include "common.h"
10  #include "database.h"  #include "database.h"
11  #include "log.h"  #include "log.h"
12  #include "trie_dict.h"  #include "trie_dict.h"
13  #include "user_list.h"  #include "user_list.h"
14    #include "user_stat.h"
15  #include <errno.h>  #include <errno.h>
16  #include <stdlib.h>  #include <stdlib.h>
17  #include <string.h>  #include <string.h>
# Line 40  union semun Line 33  union semun
33  };  };
34  #endif // #ifdef _SEM_SEMUN_UNDEFINED  #endif // #ifdef _SEM_SEMUN_UNDEFINED
35    
36  #define USER_LIST_TRY_LOCK_WAIT_TIME 1 // second  enum _user_list_constant_t
37  #define USER_LIST_TRY_LOCK_TIMES 10  {
38            USER_LIST_TRY_LOCK_WAIT_TIME = 1, // second
39            USER_LIST_TRY_LOCK_TIMES = 10,
40    };
41    
42  struct user_list_pool_t  struct user_list_pool_t
43  {  {
# Line 53  struct user_list_pool_t Line 49  struct user_list_pool_t
49          USER_ONLINE_LIST user_online_list[2];          USER_ONLINE_LIST user_online_list[2];
50          USER_ONLINE_LIST *p_online_current;          USER_ONLINE_LIST *p_online_current;
51          USER_ONLINE_LIST *p_online_new;          USER_ONLINE_LIST *p_online_new;
52            USER_STAT_MAP user_stat_map;
53            int user_login_count;
54  };  };
55  typedef struct user_list_pool_t USER_LIST_POOL;  typedef struct user_list_pool_t USER_LIST_POOL;
56    
# Line 91  static int user_list_rd_lock(int semid); Line 89  static int user_list_rd_lock(int semid);
89  static int user_list_rw_lock(int semid);  static int user_list_rw_lock(int semid);
90    
91  static int user_list_load(MYSQL *db, USER_LIST *p_list);  static int user_list_load(MYSQL *db, USER_LIST *p_list);
92  static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list);  static int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list);
93    static int user_login_count_load(MYSQL *db);
94    
95  static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)  static int user_info_index_uid_comp(const void *ptr1, const void *ptr2)
96  {  {
# Line 106  static int user_info_index_uid_comp(cons Line 105  static int user_info_index_uid_comp(cons
105          {          {
106                  return 1;                  return 1;
107          }          }
108            else if (p1->id < p2->id)
109            {
110                    return -1;
111            }
112            else if (p1->id > p2->id)
113            {
114                    return 1;
115            }
116          return 0;          return 0;
117  }  }
118    
# Line 116  int user_list_load(MYSQL *db, USER_LIST Line 123  int user_list_load(MYSQL *db, USER_LIST
123          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
124          int ret = 0;          int ret = 0;
125          int i;          int i;
126            int j;
127            int32_t last_uid;
128            size_t intro_buf_offset;
129            size_t intro_len;
130    
131          if (db == NULL || p_list == NULL)          if (db == NULL || p_list == NULL)
132          {          {
# Line 123  int user_list_load(MYSQL *db, USER_LIST Line 134  int user_list_load(MYSQL *db, USER_LIST
134                  return -1;                  return -1;
135          }          }
136    
137            if (p_list->user_count > 0)
138            {
139                    last_uid = p_list->users[p_list->user_count - 1].uid;
140            }
141            else
142            {
143                    last_uid = -1;
144            }
145    
146          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
147                           "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, "                           "SELECT user_list.UID AS UID, username, nickname, gender, gender_pub, life, exp, visit_count, "
148                           "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(birthday) "                           "UNIX_TIMESTAMP(signup_dt), UNIX_TIMESTAMP(last_login_dt), UNIX_TIMESTAMP(last_logout_dt), "
149                             "UNIX_TIMESTAMP(birthday), `introduction` "
150                           "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "                           "FROM user_list INNER JOIN user_pubinfo ON user_list.UID = user_pubinfo.UID "
151                           "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "                           "INNER JOIN user_reginfo ON user_list.UID = user_reginfo.UID "
152                           "WHERE enable ORDER BY username");                           "WHERE enable ORDER BY username");
# Line 144  int user_list_load(MYSQL *db, USER_LIST Line 165  int user_list_load(MYSQL *db, USER_LIST
165                  goto cleanup;                  goto cleanup;
166          }          }
167    
168            intro_buf_offset = 0;
169          i = 0;          i = 0;
170          while ((row = mysql_fetch_row(rs)))          while ((row = mysql_fetch_row(rs)))
171          {          {
# Line 158  int user_list_load(MYSQL *db, USER_LIST Line 180  int user_list_load(MYSQL *db, USER_LIST
180                  p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));                  p_list->users[i].gender_pub = (int8_t)(row[4] == NULL ? 0 : atoi(row[4]));
181                  p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));                  p_list->users[i].life = (row[5] == NULL ? 0 : atoi(row[5]));
182                  p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));                  p_list->users[i].exp = (row[6] == NULL ? 0 : atoi(row[6]));
183                  p_list->users[i].signup_dt = (row[7] == NULL ? 0 : atol(row[7]));                  p_list->users[i].visit_count = (row[7] == NULL ? 0 : atoi(row[7]));
184                  p_list->users[i].last_login_dt = (row[8] == NULL ? 0 : atol(row[8]));                  p_list->users[i].signup_dt = (row[8] == NULL ? 0 : atol(row[8]));
185                  p_list->users[i].birthday = (row[9] == NULL ? 0 : atol(row[9]));                  p_list->users[i].last_login_dt = (row[9] == NULL ? 0 : atol(row[9]));
186                    p_list->users[i].last_logout_dt = (row[10] == NULL ? 0 : atol(row[10]));
187                  // index                  p_list->users[i].birthday = (row[10] == NULL ? 0 : atol(row[11]));
188                  p_list->index_uid[i].uid = p_list->users[i].uid;                  intro_len = strlen((row[12] == NULL ? "" : row[12]));
189                  p_list->index_uid[i].id = i;                  if (intro_len >= sizeof(p_list->user_intro_buf) - 1 - intro_buf_offset)
190                    {
191                            log_error("OOM for user introduction: len=%d, i=%d\n", intro_len, i);
192                            break;
193                    }
194                    memcpy(p_list->user_intro_buf + intro_buf_offset,
195                               (row[12] == NULL ? "" : row[12]),
196                               intro_len + 1);
197                    p_list->users[i].intro = p_list->user_intro_buf + intro_buf_offset;
198                    intro_buf_offset += (intro_len + 1);
199    
200                  i++;                  i++;
201                  if (i >= BBS_max_user_count)                  if (i >= BBS_max_user_count)
# Line 176  int user_list_load(MYSQL *db, USER_LIST Line 207  int user_list_load(MYSQL *db, USER_LIST
207          mysql_free_result(rs);          mysql_free_result(rs);
208          rs = NULL;          rs = NULL;
209    
210          p_list->user_count = i;          if (i != p_list->user_count || p_list->users[i - 1].uid != last_uid) // Count of users changed
211            {
212                    // Rebuild index
213                    for (j = 0; j < i; j++)
214                    {
215                            p_list->index_uid[j].uid = p_list->users[j].uid;
216                            p_list->index_uid[j].id = j;
217                    }
218    
219          // Sort index                  qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
220          qsort(p_list->index_uid, (size_t)i, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);  
221    #ifdef _DEBUG
222                    log_error("Rebuild index of %d users, last_uid=%d\n", i, p_list->users[i - 1].uid);
223    #endif
224            }
225    
226            p_list->user_count = i;
227    
228  #ifdef _DEBUG  #ifdef _DEBUG
229          log_error("Loaded %d users\n", p_list->user_count);          log_error("Loaded %d users\n", p_list->user_count);
# Line 191  cleanup: Line 235  cleanup:
235          return ret;          return ret;
236  }  }
237    
238  int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_list)  int user_online_list_load(MYSQL *db, USER_ONLINE_LIST *p_online_list)
239  {  {
240          MYSQL_RES *rs = NULL;          MYSQL_RES *rs = NULL;
241          MYSQL_ROW row;          MYSQL_ROW row;
242          char sql[SQL_BUFFER_LEN];          char sql[SQL_BUFFER_LEN];
243          int ret = 0;          int ret = 0;
244          int i;          int i;
245            int j;
246            int user_cnt;
247            int guest_cnt;
248    
249          if (db == NULL || p_list == NULL)          if (db == NULL || p_online_list == NULL)
250          {          {
251                  log_error("NULL pointer error\n");                  log_error("NULL pointer error\n");
252                  return -1;                  return -1;
# Line 208  int user_online_list_load(MYSQL *db, USE Line 255  int user_online_list_load(MYSQL *db, USE
255          snprintf(sql, sizeof(sql),          snprintf(sql, sizeof(sql),
256                           "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "                           "SELECT SID, UID, ip, current_action, UNIX_TIMESTAMP(login_tm), "
257                           "UNIX_TIMESTAMP(last_tm) FROM user_online "                           "UNIX_TIMESTAMP(last_tm) FROM user_online "
258                           "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) AND UID <> 0 "                           "WHERE last_tm >= SUBDATE(NOW(), INTERVAL %d SECOND) "
259                           "ORDER BY last_tm DESC",                           "ORDER BY last_tm DESC",
260                           BBS_user_off_line);                           BBS_user_off_line);
261    
# Line 227  int user_online_list_load(MYSQL *db, USE Line 274  int user_online_list_load(MYSQL *db, USE
274          }          }
275    
276          i = 0;          i = 0;
277            user_cnt = 0;
278            guest_cnt = 0;
279          while ((row = mysql_fetch_row(rs)))          while ((row = mysql_fetch_row(rs)))
280          {          {
281                  p_list->users[i].id = i;                  if (atoi(row[1]) == 0) // guest
                 strncpy(p_list->users[i].session_id, row[0], sizeof(p_list->users[i].session_id) - 1);  
                 p_list->users[i].session_id[sizeof(p_list->users[i].session_id) - 1] = '\0';  
   
                 if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_list->users[i].user_info))) < 0)  
282                  {                  {
283                          log_error("query_user_info(%d) error\n", atoi(row[1]));                          guest_cnt++;
284                          continue;                          continue;
285                  }                  }
286                  else if (ret == 0) // skip Guest                  else
287                    {
288                            user_cnt++;
289                    }
290    
291                    p_online_list->users[i].id = i;
292                    strncpy(p_online_list->users[i].session_id, row[0], sizeof(p_online_list->users[i].session_id) - 1);
293                    p_online_list->users[i].session_id[sizeof(p_online_list->users[i].session_id) - 1] = '\0';
294    
295                    if ((ret = query_user_info_by_uid(atoi(row[1]), &(p_online_list->users[i].user_info), NULL, 0)) <= 0)
296                  {                  {
297                            log_error("query_user_info_by_uid(%d) error\n", atoi(row[1]));
298                          continue;                          continue;
299                  }                  }
300    
301                  strncpy(p_list->users[i].ip, row[2], sizeof(p_list->users[i].ip) - 1);                  strncpy(p_online_list->users[i].ip, row[2], sizeof(p_online_list->users[i].ip) - 1);
302                  p_list->users[i].ip[sizeof(p_list->users[i].ip) - 1] = '\0';                  p_online_list->users[i].ip[sizeof(p_online_list->users[i].ip) - 1] = '\0';
303    
304                  strncpy(p_list->users[i].current_action, row[3], sizeof(p_list->users[i].current_action) - 1);                  strncpy(p_online_list->users[i].current_action, row[3], sizeof(p_online_list->users[i].current_action) - 1);
305                  p_list->users[i].current_action[sizeof(p_list->users[i].current_action) - 1] = '\0';                  p_online_list->users[i].current_action[sizeof(p_online_list->users[i].current_action) - 1] = '\0';
306                  p_list->users[i].current_action_title = NULL;                  p_online_list->users[i].current_action_title = NULL;
307                  if (p_list->users[i].current_action[0] == '\0')                  if (p_online_list->users[i].current_action[0] == '\0')
308                  {                  {
309                          p_list->users[i].current_action_title = "";                          p_online_list->users[i].current_action_title = "";
310                  }                  }
311                  else if (trie_dict_get(p_trie_action_dict, p_list->users[i].current_action, (int64_t *)(&(p_list->users[i].current_action_title))) < 0)                  else if (trie_dict_get(p_trie_action_dict, p_online_list->users[i].current_action, (int64_t *)(&(p_online_list->users[i].current_action_title))) < 0)
312                  {                  {
313                          log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",                          log_error("trie_dict_get(p_trie_action_dict, %s) error on session_id=%s\n",
314                                            p_list->users[i].current_action, p_list->users[i].session_id);                                            p_online_list->users[i].current_action, p_online_list->users[i].session_id);
315                          continue;                          continue;
316                  }                  }
317    
318                  p_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));                  p_online_list->users[i].login_tm = (row[4] == NULL ? 0 : atol(row[4]));
319                  p_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));                  p_online_list->users[i].last_tm = (row[5] == NULL ? 0 : atol(row[5]));
320    
321                  i++;                  i++;
322                  if (i >= BBS_max_user_online_count)                  if (i >= BBS_max_user_online_count)
# Line 273  int user_online_list_load(MYSQL *db, USE Line 328  int user_online_list_load(MYSQL *db, USE
328          mysql_free_result(rs);          mysql_free_result(rs);
329          rs = NULL;          rs = NULL;
330    
331          p_list->user_count = i;          if (user_cnt > 0)
332            {
333                    // Rebuild index
334                    for (j = 0; j < user_cnt; j++)
335                    {
336                            p_online_list->index_uid[j].uid = p_online_list->users[j].user_info.uid;
337                            p_online_list->index_uid[j].id = j;
338                    }
339    
340                    qsort(p_online_list->index_uid, (size_t)user_cnt, sizeof(USER_INFO_INDEX_UID), user_info_index_uid_comp);
341    
342  #ifdef _DEBUG  #ifdef _DEBUG
343          log_error("Loaded %d users\n", p_list->user_count);                  log_error("Rebuild index of %d online users\n", user_cnt);
344    #endif
345            }
346    
347            p_online_list->user_count = user_cnt;
348            p_online_list->guest_count = guest_cnt;
349    
350    #ifdef _DEBUG
351            log_error("Loaded %d online users and %d guest users\n", p_list->user_count, p_list->guest_count);
352  #endif  #endif
353    
354  cleanup:  cleanup:
# Line 285  cleanup: Line 357  cleanup:
357          return ret;          return ret;
358  }  }
359    
360  int user_list_pool_init(void)  int user_login_count_load(MYSQL *db)
361    {
362            MYSQL_RES *rs = NULL;
363            MYSQL_ROW row;
364            char sql[SQL_BUFFER_LEN];
365    
366            if (db == NULL)
367            {
368                    log_error("NULL pointer error\n");
369                    return -1;
370            }
371    
372            snprintf(sql, sizeof(sql),
373                             "SELECT ID FROM user_login_log ORDER BY ID DESC LIMIT 1");
374            if (mysql_query(db, sql) != 0)
375            {
376                    log_error("Query user_login_log error: %s\n", mysql_error(db));
377                    return -2;
378            }
379            if ((rs = mysql_store_result(db)) == NULL)
380            {
381                    log_error("Get user_login_log data failed\n");
382                    return -2;
383            }
384            if ((row = mysql_fetch_row(rs)))
385            {
386                    p_user_list_pool->user_login_count = atoi(row[0]);
387            }
388            mysql_free_result(rs);
389    
390            return 0;
391    }
392    
393    int user_list_pool_init(const char *filename)
394  {  {
395          int shmid;          int shmid;
396          int semid;          int semid;
# Line 319  int user_list_pool_init(void) Line 424  int user_list_pool_init(void)
424    
425          // Allocate shared memory          // Allocate shared memory
426          proj_id = (int)(time(NULL) % getpid());          proj_id = (int)(time(NULL) % getpid());
427          key = ftok(VAR_USER_LIST_SHM, proj_id);          key = ftok(filename, proj_id);
428          if (key == -1)          if (key == -1)
429          {          {
430                  log_error("ftok(%s %d) error (%d)\n", VAR_USER_LIST_SHM, proj_id, errno);                  log_error("ftok(%s %d) error (%d)\n", filename, proj_id, errno);
431                  return -2;                  return -2;
432          }          }
433    
# Line 375  int user_list_pool_init(void) Line 480  int user_list_pool_init(void)
480          p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);          p_user_list_pool->p_online_current = &(p_user_list_pool->user_online_list[0]);
481          p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);          p_user_list_pool->p_online_new = &(p_user_list_pool->user_online_list[1]);
482    
483            user_stat_map_init(&(p_user_list_pool->user_stat_map));
484    
485          return 0;          return 0;
486  }  }
487    
# Line 399  void user_list_pool_cleanup(void) Line 506  void user_list_pool_cleanup(void)
506                  log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);                  log_error("shmdt(shmid = %d) error (%d)\n", shmid, errno);
507          }          }
508    
509          if (shmctl(shmid, IPC_RMID, NULL) == -1)          if (shmid != 0 && shmctl(shmid, IPC_RMID, NULL) == -1)
510          {          {
511                  log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);                  log_error("shmctl(shmid = %d, IPC_RMID) error (%d)\n", shmid, errno);
512          }          }
# Line 458  int user_list_pool_reload(int online_use Line 565  int user_list_pool_reload(int online_use
565          MYSQL *db = NULL;          MYSQL *db = NULL;
566          USER_LIST *p_tmp;          USER_LIST *p_tmp;
567          USER_ONLINE_LIST *p_online_tmp;          USER_ONLINE_LIST *p_online_tmp;
568            int ret = 0;
569    
570          if (p_user_list_pool == NULL)          if (p_user_list_pool == NULL)
571          {          {
# Line 477  int user_list_pool_reload(int online_use Line 585  int user_list_pool_reload(int online_use
585                  if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)                  if (user_online_list_load(db, p_user_list_pool->p_online_new) < 0)
586                  {                  {
587                          log_error("user_online_list_load() error\n");                          log_error("user_online_list_load() error\n");
588                          return -2;                          ret = -2;
589                            goto cleanup;
590                    }
591    
592                    if (user_login_count_load(db) < 0)
593                    {
594                            log_error("user_login_count_load() error\n");
595                            ret = -2;
596                            goto cleanup;
597                  }                  }
598          }          }
599          else          else
# Line 485  int user_list_pool_reload(int online_use Line 601  int user_list_pool_reload(int online_use
601                  if (user_list_load(db, p_user_list_pool->p_new) < 0)                  if (user_list_load(db, p_user_list_pool->p_new) < 0)
602                  {                  {
603                          log_error("user_list_load() error\n");                          log_error("user_list_load() error\n");
604                          return -2;                          ret = -2;
605                            goto cleanup;
606                  }                  }
607          }          }
608    
609          mysql_close(db);          mysql_close(db);
610            db = NULL;
611    
612          if (user_list_rw_lock(p_user_list_pool->semid) < 0)          if (user_list_rw_lock(p_user_list_pool->semid) < 0)
613          {          {
614                  log_error("user_list_rw_lock() error\n");                  log_error("user_list_rw_lock() error\n");
615                  return -3;                  ret = -3;
616                    goto cleanup;
617          }          }
618    
619          if (online_user)          if (online_user)
# Line 515  int user_list_pool_reload(int online_use Line 634  int user_list_pool_reload(int online_use
634          if (user_list_rw_unlock(p_user_list_pool->semid) < 0)          if (user_list_rw_unlock(p_user_list_pool->semid) < 0)
635          {          {
636                  log_error("user_list_rw_unlock() error\n");                  log_error("user_list_rw_unlock() error\n");
637                  return -3;                  ret = -3;
638                    goto cleanup;
639          }          }
640    
641          return 0;  cleanup:
642            mysql_close(db);
643    
644            return ret;
645  }  }
646    
647  int user_list_try_rd_lock(int semid, int wait_sec)  int user_list_try_rd_lock(int semid, int wait_sec)
# Line 683  int query_user_list(int page_id, USER_IN Line 806  int query_user_list(int page_id, USER_IN
806                  return -1;                  return -1;
807          }          }
808    
809            *p_user_count = 0;
810            *p_page_count = 0;
811    
812          // acquire lock of user list          // acquire lock of user list
813          if (user_list_rd_lock(p_user_list_pool->semid) < 0)          if (user_list_rd_lock(p_user_list_pool->semid) < 0)
814          {          {
# Line 736  int query_user_online_list(int page_id, Line 862  int query_user_online_list(int page_id,
862                  return -1;                  return -1;
863          }          }
864    
865            *p_user_count = 0;
866            *p_page_count = 0;
867    
868          // acquire lock of user list          // acquire lock of user list
869          if (user_list_rd_lock(p_user_list_pool->semid) < 0)          if (user_list_rd_lock(p_user_list_pool->semid) < 0)
870          {          {
# Line 779  cleanup: Line 908  cleanup:
908          return ret;          return ret;
909  }  }
910    
911    int get_user_list_count(int *p_user_cnt)
912    {
913            if (p_user_cnt == NULL)
914            {
915                    log_error("NULL pointer error\n");
916                    return -1;
917            }
918    
919            // acquire lock of user list
920            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
921            {
922                    log_error("user_list_rd_lock() error\n");
923                    return -2;
924            }
925    
926            *p_user_cnt = p_user_list_pool->p_current->user_count;
927    
928            // release lock of user list
929            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
930            {
931                    log_error("user_list_rd_unlock() error\n");
932                    return -2;
933            }
934    
935            return 0;
936    }
937    
938    int get_user_online_list_count(int *p_user_cnt, int *p_guest_cnt)
939    {
940            if (p_user_cnt == NULL || p_guest_cnt == NULL)
941            {
942                    log_error("NULL pointer error\n");
943                    return -1;
944            }
945    
946            // acquire lock of user list
947            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
948            {
949                    log_error("user_list_rd_lock() error\n");
950                    return -2;
951            }
952    
953            *p_user_cnt = p_user_list_pool->p_online_current->user_count;
954            *p_guest_cnt = p_user_list_pool->p_online_current->guest_count;
955    
956            // release lock of user list
957            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
958            {
959                    log_error("user_list_rd_unlock() error\n");
960                    return -2;
961            }
962    
963            return 0;
964    }
965    
966    int get_user_login_count(int *p_login_cnt)
967    {
968            if (p_login_cnt == NULL)
969            {
970                    log_error("NULL pointer error\n");
971                    return -1;
972            }
973    
974            *p_login_cnt = p_user_list_pool->user_login_count;
975    
976            return 0;
977    }
978    
979  int query_user_info(int32_t id, USER_INFO *p_user)  int query_user_info(int32_t id, USER_INFO *p_user)
980  {  {
981          int ret = 0;          int ret = 0;
# Line 812  int query_user_info(int32_t id, USER_INF Line 1009  int query_user_info(int32_t id, USER_INF
1009          return ret;          return ret;
1010  }  }
1011    
1012  int query_user_info_by_uid(int32_t uid, USER_INFO *p_user)  int query_user_info_by_uid(int32_t uid, USER_INFO *p_user, char *p_intro_buf, size_t intro_buf_len)
1013  {  {
1014          int left;          int left;
1015          int right;          int right;
# Line 841  int query_user_info_by_uid(int32_t uid, Line 1038  int query_user_info_by_uid(int32_t uid,
1038                  mid = (left + right) / 2;                  mid = (left + right) / 2;
1039                  if (uid < p_user_list_pool->p_current->index_uid[mid].uid)                  if (uid < p_user_list_pool->p_current->index_uid[mid].uid)
1040                  {                  {
1041                          right = mid;                          right = mid - 1;
1042                  }                  }
1043                  else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)                  else if (uid > p_user_list_pool->p_current->index_uid[mid].uid)
1044                  {                  {
# Line 857  int query_user_info_by_uid(int32_t uid, Line 1054  int query_user_info_by_uid(int32_t uid,
1054          if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found          if (uid == p_user_list_pool->p_current->index_uid[left].uid) // Found
1055          {          {
1056                  id = p_user_list_pool->p_current->index_uid[left].id;                  id = p_user_list_pool->p_current->index_uid[left].id;
1057                  if ((ret = query_user_info(id, p_user)) <= 0)                  *p_user = p_user_list_pool->p_current->users[id];
1058                    ret = 1;
1059    
1060                    if (p_intro_buf != NULL)
1061                  {                  {
1062                          log_error("query_user_info(id=%d) error: %d\n", id, ret);                          strncpy(p_intro_buf, p_user_list_pool->p_current->users[id].intro, intro_buf_len - 1);
1063                            p_intro_buf[intro_buf_len - 1] = '\0';
1064                            p_user->intro = p_intro_buf;
1065                  }                  }
1066                  else          }
1067    
1068            // release lock of user list
1069            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1070            {
1071                    log_error("user_list_rd_unlock() error\n");
1072                    ret = -1;
1073            }
1074    
1075            return ret;
1076    }
1077    
1078    int query_user_info_by_username(const char *username_prefix, int max_user_cnt,
1079                                                                    int32_t uid_list[], char username_list[][BBS_username_max_len + 1])
1080    {
1081            int left;
1082            int right;
1083            int mid;
1084            int left_save;
1085            int ret = 0;
1086            size_t prefix_len;
1087            int comp;
1088            int i;
1089    
1090            if (username_prefix == NULL || uid_list == NULL || username_list == NULL)
1091            {
1092                    log_error("NULL pointer error\n");
1093                    return -1;
1094            }
1095    
1096            prefix_len = strlen(username_prefix);
1097    
1098            // acquire lock of user list
1099            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1100            {
1101                    log_error("user_list_rd_lock() error\n");
1102                    return -2;
1103            }
1104    
1105            left = 0;
1106            right = p_user_list_pool->p_current->user_count - 1;
1107    
1108            while (left < right)
1109            {
1110                    mid = (left + right) / 2;
1111                    comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1112                    if (comp < 0)
1113                  {                  {
1114                          ret = 1;                          right = mid - 1;
1115                    }
1116                    else if (comp > 0)
1117                    {
1118                            left = mid + 1;
1119                    }
1120                    else // if (comp == 0)
1121                    {
1122                            left = mid;
1123                            break;
1124                    }
1125            }
1126    
1127            if (strncasecmp(username_prefix, p_user_list_pool->p_current->users[left].username, prefix_len) == 0) // Found
1128            {
1129    #ifdef _DEBUG
1130                    log_error("Debug: match found, pos=%d\n", left);
1131    #endif
1132    
1133                    left_save = left;
1134                    right = left;
1135                    left = 0;
1136    
1137                    while (left < right)
1138                    {
1139                            mid = (left + right) / 2;
1140                            comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1141                            if (comp > 0)
1142                            {
1143                                    left = mid + 1;
1144                            }
1145                            else if (comp == 0)
1146                            {
1147                                    right = mid;
1148                            }
1149                            else // if (comp < 0)
1150                            {
1151                                    log_error("Bug: left=%d right=%d mid=%d");
1152                                    ret = -2;
1153                                    goto cleanup;
1154                            }
1155                    }
1156    
1157    #ifdef _DEBUG
1158                    log_error("Debug: first match found, pos=%d\n", right);
1159    #endif
1160    
1161                    left = left_save;
1162                    left_save = right;
1163                    right = p_user_list_pool->p_current->user_count - 1;
1164    
1165                    while (left < right)
1166                    {
1167                            mid = (left + right) / 2 + (left + right) % 2;
1168                            comp = strncasecmp(username_prefix, p_user_list_pool->p_current->users[mid].username, prefix_len);
1169                            if (comp < 0)
1170                            {
1171                                    right = mid - 1;
1172                            }
1173                            else if (comp == 0)
1174                            {
1175                                    left = mid;
1176                            }
1177                            else // if (comp > 0)
1178                            {
1179                                    log_error("Bug: left=%d right=%d mid=%d");
1180                                    ret = -2;
1181                                    goto cleanup;
1182                            }
1183                    }
1184    
1185    #ifdef _DEBUG
1186                    log_error("Debug: last match found, pos=%d\n", left);
1187    #endif
1188    
1189                    right = left;
1190                    left = left_save;
1191    
1192                    for (i = 0; i < max_user_cnt && left + i <= right; i++)
1193                    {
1194                            uid_list[i] = p_user_list_pool->p_current->users[left + i].uid;
1195                            strncpy(username_list[i], p_user_list_pool->p_current->users[left + i].username, sizeof(username_list[i]) - 1);
1196                            username_list[i][sizeof(username_list[i]) - 1] = '\0';
1197                  }                  }
1198                    ret = i;
1199          }          }
1200    
1201    cleanup:
1202          // release lock of user list          // release lock of user list
1203          if (user_list_rd_unlock(p_user_list_pool->semid) < 0)          if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1204          {          {
# Line 909  int query_user_online_info(int32_t id, U Line 1241  int query_user_online_info(int32_t id, U
1241    
1242          return ret;          return ret;
1243  }  }
1244    
1245    int query_user_online_info_by_uid(int32_t uid, USER_ONLINE_INFO *p_users, int *p_user_cnt, int start_id)
1246    {
1247            int left;
1248            int right;
1249            int mid;
1250            int32_t id;
1251            int ret = 0;
1252            int i;
1253            int user_cnt;
1254    
1255            if (p_users == NULL || p_user_cnt == NULL)
1256            {
1257                    log_error("NULL pointer error\n");
1258                    return -1;
1259            }
1260    
1261            user_cnt = *p_user_cnt;
1262            *p_user_cnt = 0;
1263    
1264            // acquire lock of user list
1265            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1266            {
1267                    log_error("user_list_rd_lock() error\n");
1268                    return -2;
1269            }
1270    
1271            left = start_id;
1272            right = p_user_list_pool->p_online_current->user_count - 1;
1273    
1274            while (left < right)
1275            {
1276                    mid = (left + right) / 2;
1277                    if (uid < p_user_list_pool->p_online_current->index_uid[mid].uid)
1278                    {
1279                            right = mid - 1;
1280                    }
1281                    else if (uid > p_user_list_pool->p_online_current->index_uid[mid].uid)
1282                    {
1283                            left = mid + 1;
1284                    }
1285                    else // if (uid == p_user_list_pool->p_online_current->index_uid[mid].uid)
1286                    {
1287                            left = mid;
1288                            break;
1289                    }
1290            }
1291    
1292            if (uid == p_user_list_pool->p_online_current->index_uid[left].uid)
1293            {
1294                    right = left;
1295                    left = start_id;
1296    
1297                    while (left < right)
1298                    {
1299                            mid = (left + right) / 2;
1300                            if (uid - 1 < p_user_list_pool->p_online_current->index_uid[mid].uid)
1301                            {
1302                                    right = mid;
1303                            }
1304                            else // if (uid - 1 >= p_user_list_pool->p_online_current->index_uid[mid].uid)
1305                            {
1306                                    left = mid + 1;
1307                            }
1308                    }
1309    
1310                    for (i = 0;
1311                             left < p_user_list_pool->p_online_current->user_count && i < user_cnt &&
1312                             uid == p_user_list_pool->p_online_current->index_uid[left].uid;
1313                             left++, i++)
1314                    {
1315                            id = p_user_list_pool->p_online_current->index_uid[left].id;
1316                            p_users[i] = p_user_list_pool->p_online_current->users[id];
1317                    }
1318    
1319                    if (i > 0)
1320                    {
1321                            *p_user_cnt = i;
1322                            ret = 1;
1323                    }
1324            }
1325    
1326            // release lock of user list
1327            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1328            {
1329                    log_error("user_list_rd_unlock() error\n");
1330                    ret = -1;
1331            }
1332    
1333            return ret;
1334    }
1335    
1336    int get_user_id_list(int32_t *p_uid_list, int *p_user_cnt, int start_uid)
1337    {
1338            int left;
1339            int right;
1340            int mid;
1341            int ret = 0;
1342            int i;
1343    
1344            if (p_uid_list == NULL || p_user_cnt == NULL)
1345            {
1346                    log_error("NULL pointer error\n");
1347                    return -1;
1348            }
1349    
1350            // acquire lock of user list
1351            if (user_list_rd_lock(p_user_list_pool->semid) < 0)
1352            {
1353                    log_error("user_list_rd_lock() error\n");
1354                    return -2;
1355            }
1356    
1357            left = 0;
1358            right = p_user_list_pool->p_current->user_count - 1;
1359    
1360            while (left < right)
1361            {
1362                    mid = (left + right) / 2;
1363                    if (start_uid < p_user_list_pool->p_current->index_uid[mid].uid)
1364                    {
1365                            right = mid - 1;
1366                    }
1367                    else if (start_uid > p_user_list_pool->p_current->index_uid[mid].uid)
1368                    {
1369                            left = mid + 1;
1370                    }
1371                    else // if (start_uid == p_user_list_pool->p_current->index_uid[mid].uid)
1372                    {
1373                            left = mid;
1374                            break;
1375                    }
1376            }
1377    
1378            for (i = 0; i < *p_user_cnt && left + i < p_user_list_pool->p_current->user_count; i++)
1379            {
1380                    p_uid_list[i] = p_user_list_pool->p_current->index_uid[left + i].uid;
1381            }
1382            *p_user_cnt = i;
1383    
1384            // release lock of user list
1385            if (user_list_rd_unlock(p_user_list_pool->semid) < 0)
1386            {
1387                    log_error("user_list_rd_unlock() error\n");
1388                    ret = -1;
1389            }
1390    
1391            return ret;
1392    }
1393    
1394    int user_stat_update(void)
1395    {
1396            return user_stat_map_update(&(p_user_list_pool->user_stat_map));
1397    }
1398    
1399    int user_article_cnt_inc(int32_t uid, int n)
1400    {
1401            return user_stat_article_cnt_inc(&(p_user_list_pool->user_stat_map), uid, n);
1402    }
1403    
1404    int get_user_article_cnt(int32_t uid)
1405    {
1406            const USER_STAT *p_stat;
1407            int ret;
1408    
1409            ret = user_stat_get(&(p_user_list_pool->user_stat_map), uid, &p_stat);
1410            if (ret < 0)
1411            {
1412                    log_error("user_stat_get(uid=%d) error: %d\n", uid, ret);
1413                    return -1;
1414            }
1415            else if (ret == 0) // user not found
1416            {
1417                    return -1;
1418            }
1419    
1420            return p_stat->article_count;
1421    }


Legend:
Removed lines/characters  
Changed lines/characters
  Added lines/characters

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1