|
| 1 | +// backupd.c |
| 2 | + |
| 3 | +#include <ansi.h> |
| 4 | +#include <localtime.h> |
| 5 | +#include <command.h> |
| 6 | + |
| 7 | +inherit F_DBASE; |
| 8 | + |
| 9 | +#define BACKUP_DATE 7 // the oldest's backup (days) |
| 10 | + |
| 11 | +static int state; |
| 12 | + |
| 13 | +#define SLEEPING 0 |
| 14 | +#define GET_READY 1 |
| 15 | +#define GET_READY_2 2 |
| 16 | +#define BACKUPING 3 |
| 17 | + |
| 18 | +#define CMD_RM "/cmds/wiz/rm" |
| 19 | +#define CMD_CP "/cmds/wiz/cp" |
| 20 | + |
| 21 | +static int *tlist = ({ 0, 550, 559, 600 }); |
| 22 | +static int *hlist = ({ 45, 1, 1, 1 }); |
| 23 | + |
| 24 | +// 通知一次准备的时间:凌晨5:50分 |
| 25 | +// 通知再次准备的时间:凌晨5:59分 |
| 26 | +// 开始进行备份的时间:凌晨6:00分 |
| 27 | +// 凌晨六点以后到第二天凌晨5:50分之前属于休眠状态 |
| 28 | + |
| 29 | +// 提供给外面的接口函数 |
| 30 | +void backup_data(); |
| 31 | + |
| 32 | +// 内部使用的函数 |
| 33 | +private void remove_backup(mixed lt); |
| 34 | +private void check_all_player(); |
| 35 | +private void change_state(int new_state); |
| 36 | +private void sys_info(string msg); |
| 37 | +private int assure_not_exist(string bkdir); |
| 38 | +private int is_recent_time(int y, int m, int d, int cy, int cm, int cd); |
| 39 | + |
| 40 | +// return the time of prompt |
| 41 | +int is_backuping() { return state != SLEEPING; } |
| 42 | + |
| 43 | +// return the time of backup |
| 44 | +int query_backup_time() { return tlist[BACKUPING]; } |
| 45 | + |
| 46 | +void create() |
| 47 | +{ |
| 48 | + seteuid(ROOT_UID); |
| 49 | + set("channel_id", "备份精灵"); |
| 50 | + sys_info("备份系统已经启动。"); |
| 51 | + state = SLEEPING; |
| 52 | + set_heart_beat(hlist[state]); |
| 53 | +} |
| 54 | + |
| 55 | +int clean_up() |
| 56 | +{ |
| 57 | + return 1; |
| 58 | +} |
| 59 | + |
| 60 | +void heart_beat() |
| 61 | +{ |
| 62 | + mixed lt; |
| 63 | + int ti; |
| 64 | + |
| 65 | + seteuid(ROOT_UID); |
| 66 | + lt = localtime(time()); |
| 67 | + ti = lt[LT_HOUR] * 100 + lt[LT_MIN]; |
| 68 | + |
| 69 | + switch(state) |
| 70 | + { |
| 71 | + case SLEEPING: |
| 72 | + if (ti < tlist[GET_READY] || ti > tlist[GET_READY_2]) |
| 73 | + // not change state |
| 74 | + break; |
| 75 | + // chanage state to "GET_READY"; |
| 76 | + change_state(GET_READY); |
| 77 | + break; |
| 78 | + |
| 79 | + case GET_READY: |
| 80 | + if (ti < tlist[GET_READY_2]) |
| 81 | + break; |
| 82 | + |
| 83 | + // change state to "GET_READY_2"; |
| 84 | + change_state(GET_READY_2); |
| 85 | + break; |
| 86 | + |
| 87 | + case GET_READY_2: |
| 88 | + if (ti < tlist[BACKUPING]) |
| 89 | + break; |
| 90 | + |
| 91 | + // change state to "GET_READY_2"; |
| 92 | + change_state(BACKUPING); |
| 93 | + |
| 94 | + // the last function will change to "SLEEPING" state |
| 95 | + // after backing |
| 96 | + break; |
| 97 | + |
| 98 | + default: |
| 99 | + change_state(SLEEPING); |
| 100 | + break; |
| 101 | + } |
| 102 | + |
| 103 | + // reset heart beat |
| 104 | + set_heart_beat(hlist[state]); |
| 105 | +} |
| 106 | + |
| 107 | +private void change_state(int new_state) |
| 108 | +{ |
| 109 | + mixed lt; |
| 110 | + |
| 111 | + lt = localtime(time()); |
| 112 | + switch (new_state) |
| 113 | + { |
| 114 | + case GET_READY: |
| 115 | + case GET_READY_2: |
| 116 | + if (lt[LT_HOUR] * 100 + lt[LT_MIN] != tlist[BACKUPING]) |
| 117 | + { |
| 118 | + message_system(sprintf("现在是 %d 点 %d 分,系统将在 %d 点 %d 分" |
| 119 | + "自动备份所有玩家的数据,期间游戏会有停滞。", |
| 120 | + lt[LT_HOUR], lt[LT_MIN], |
| 121 | + (tlist[BACKUPING] / 100) % 100, |
| 122 | + tlist[BACKUPING] % 100)); |
| 123 | + break; |
| 124 | + } else |
| 125 | + new_state = BACKUPING; |
| 126 | + |
| 127 | + case BACKUPING: |
| 128 | + state = new_state; |
| 129 | + message_system(sprintf(HIY "现在是 %d 点 %d 分,系统开始" |
| 130 | + "自动备份所有玩家数据,请稍候..." NOR, |
| 131 | + lt[LT_HOUR], lt[LT_MIN])); |
| 132 | + |
| 133 | + backup_data(); |
| 134 | + |
| 135 | + message_system(sprintf(HIC "系统已经处理完备份工作。" NOR, |
| 136 | + lt[LT_HOUR], lt[LT_MIN])); |
| 137 | + |
| 138 | + // after backup, change state to SLEEPING |
| 139 | + new_state = SLEEPING; |
| 140 | + break; |
| 141 | + |
| 142 | + case SLEEPING: |
| 143 | + break; |
| 144 | + } |
| 145 | + |
| 146 | + // change to new state |
| 147 | + state = new_state; |
| 148 | + return; |
| 149 | +} |
| 150 | + |
| 151 | +// backup |
| 152 | +// copy current /DATA to /BACKUP_DIR/yyyy.mm.dd, if the directory |
| 153 | +// has been existed, then remove the directory first. |
| 154 | +// after that, I will check wether the other directory in backup |
| 155 | +// directiry was the backup of recently(BACKUP_DATE days), if not, |
| 156 | +// I will remove it. |
| 157 | +void backup_data() |
| 158 | +{ |
| 159 | + string bkdir; |
| 160 | + mixed lt; |
| 161 | + int count; |
| 162 | + |
| 163 | + if (! is_root(previous_object())) |
| 164 | + { |
| 165 | + write(HIR "YOU HAVE NO ACCESS TO BACKUP\n" NOR); |
| 166 | + return; |
| 167 | + } |
| 168 | + |
| 169 | + seteuid(getuid()); |
| 170 | + |
| 171 | + sys_info("备份工作开始。"); |
| 172 | + lt = localtime(time()); |
| 173 | + |
| 174 | + // because LT_MON is from 0..11, so I must add 1 |
| 175 | + lt[LT_MON]++; |
| 176 | + bkdir = sprintf("%s%d-%d-%d", BACKUP_DIR, |
| 177 | + lt[LT_YEAR], lt[LT_MON], lt[LT_MDAY]); |
| 178 | + if (! assure_not_exist(bkdir)) |
| 179 | + { |
| 180 | + sys_info(sprintf("备份失败:无法删除(%s)。", bkdir)); |
| 181 | + return; |
| 182 | + } |
| 183 | + |
| 184 | + // backup data |
| 185 | + count = CMD_CP->copy_dir(DATA_DIR, bkdir); |
| 186 | + if (count) |
| 187 | + sys_info(sprintf("总共有%d个文件被保存到(%s)中。", count, bkdir)); |
| 188 | + |
| 189 | + call_out("remove_backup", 1, lt); |
| 190 | +} |
| 191 | + |
| 192 | +// 删除以前的备份 |
| 193 | +void remove_backup(mixed lt) |
| 194 | +{ |
| 195 | + object *obs; |
| 196 | + mixed *file; |
| 197 | + int i; |
| 198 | + |
| 199 | + // clear the older backup data |
| 200 | + file = get_dir(BACKUP_DIR, -1); |
| 201 | + for (i = 0; i < sizeof(file); i++) |
| 202 | + { |
| 203 | + int y, m, d; |
| 204 | + |
| 205 | + reset_eval_cost(); |
| 206 | + if (file[i][1] != -2) |
| 207 | + // not directory |
| 208 | + continue; |
| 209 | + |
| 210 | + if (sscanf(file[i][0], "%d-%d-%d", y, m, d) != 3) |
| 211 | + // not backup directory |
| 212 | + continue; |
| 213 | + |
| 214 | + if (is_recent_time(y, m, d, lt[LT_YEAR], lt[LT_MON], lt[LT_MDAY])) |
| 215 | + // is the receant backup, won't delete |
| 216 | + continue; |
| 217 | + |
| 218 | + CMD_RM->rm_dir(BACKUP_DIR + file[i][0]); |
| 219 | + sys_info(sprintf("备份(%s)已经被自动删除。", file[i][0])); |
| 220 | + } |
| 221 | + |
| 222 | + // update all loging object |
| 223 | + obs = users(); |
| 224 | + for (i = 0; i < sizeof(obs); i++) |
| 225 | + if (obs[i]->is_loging_now()) |
| 226 | + { |
| 227 | + obs[i]->end_log(); |
| 228 | + obs[i]->start_log(); |
| 229 | + } |
| 230 | + |
| 231 | + // 为了显示正确的时间,所以使用 call_out 呼叫。 |
| 232 | + call_out("sys_info", 0, "备份工作完毕。"); |
| 233 | + |
| 234 | +} |
| 235 | +/* |
| 236 | + // 10s以后检查所有的玩家 |
| 237 | + call_out("check_all_player", 1); |
| 238 | +} |
| 239 | +
|
| 240 | +// 检查所有玩家 |
| 241 | +private void check_all_player() |
| 242 | +{ |
| 243 | + message_system("系统开始核查所有玩家,并清除长时间不上线的使用者..."); |
| 244 | + sys_info("系统开始检查所有玩家。"); |
| 245 | +
|
| 246 | + EXAMINE_CMD->search_dir(0, 1); |
| 247 | +
|
| 248 | + // 为了显示正确的时间,所以使用 call_out 呼叫。 |
| 249 | + call_out("sys_info", 0, "系统检查所有玩家完毕。"); |
| 250 | +} |
| 251 | +*/ |
| 252 | + |
| 253 | +// check that y/m/d wether or not close cy/cm/cd(current time) |
| 254 | +private int is_recent_time(int y, int m, int d, int cy, int cm, int cd) |
| 255 | +{ |
| 256 | + if (y > cy) return 1; // future backup? laugh |
| 257 | + if (y == cy) |
| 258 | + { |
| 259 | + // the same year |
| 260 | + if (m > cm) return 1; // maybe future backup |
| 261 | + if (m == cm) |
| 262 | + { |
| 263 | + // the same month |
| 264 | + if (d <= cd - BACKUP_DATE) return 0; |
| 265 | + return 1; |
| 266 | + } |
| 267 | + if (m != cm - 1) return 0; |
| 268 | + switch (m) |
| 269 | + { |
| 270 | + case 1: case 3: case 5: case 7: case 8: case 10: case 12: |
| 271 | + cd += 31; |
| 272 | + break; |
| 273 | + case 2: |
| 274 | + cd += 28; |
| 275 | + if ((y % 4) == 0 && (y % 100) != 0) cd++; |
| 276 | + break; |
| 277 | + default: |
| 278 | + cd += 30; |
| 279 | + break; |
| 280 | + } |
| 281 | + if (d <= cd - BACKUP_DATE) return 0; |
| 282 | + return 1; |
| 283 | + } |
| 284 | + if (y != cy - 1) return 0; |
| 285 | + if (m != 12 || cm != 1) return 0; |
| 286 | + cd += 31; |
| 287 | + if (d <= cd - BACKUP_DATE) return 0; |
| 288 | + return 1; |
| 289 | +} |
| 290 | + |
| 291 | +private int assure_not_exist(string bkdir) |
| 292 | +{ |
| 293 | + switch (file_size(bkdir)) |
| 294 | + { |
| 295 | + case -1: |
| 296 | + return 1; |
| 297 | + |
| 298 | + case -2: |
| 299 | + CMD_RM->rm_dir(bkdir); |
| 300 | + return (file_size(bkdir) == -1); |
| 301 | + |
| 302 | + default: |
| 303 | + return rm(bkdir); |
| 304 | + } |
| 305 | +} |
| 306 | + |
| 307 | +private void sys_info(string msg) |
| 308 | +{ |
| 309 | + CHANNEL_D->do_channel(this_object(), "sys", msg); |
| 310 | + log_file("backup", log_time() + ": " + msg + "\n"); |
| 311 | +} |
| 312 | + |
0 commit comments