X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=submit%2Fcommands.c;h=432e2deb2dd0dd3fbbfacb77c0570d76d9b47f62;hb=3043ffa0cb666e509d5b07e479ead4792fbf722d;hp=e583d66a518ec97d477cc8afd6b1ce348372f129;hpb=b451c5db7c24116c306eb1ce207641350ef98d8f;p=eval.git diff --git a/submit/commands.c b/submit/commands.c index e583d66..432e2de 100644 --- a/submit/commands.c +++ b/submit/commands.c @@ -6,9 +6,13 @@ #include "lib/lib.h" #include "lib/mempool.h" +#include "lib/simple-lists.h" +#include "lib/stkstring.h" #include "sherlock/object.h" #include "sherlock/objread.h" +#include + #include "submitd.h" /*** REQUESTS AND REPLIES ***/ @@ -72,8 +76,7 @@ write_reply(struct conn *c) else log(L_DEBUG, ">> ???"); } - put_attr_set_type(BUCKET_TYPE_PLAIN); - bput_object(&c->tx_fb, c->reply); + obj_write(&c->tx_fb, c->reply, BUCKET_TYPE_PLAIN); bputc(&c->tx_fb, '\n'); bflush(&c->tx_fb); } @@ -84,8 +87,81 @@ err(struct conn *c, byte *msg) obj_set_attr(c->reply, '-', msg); } +/*** STATUS ***/ + +static void +copy_attrs(struct odes *dest, struct odes *src) +{ + for (struct oattr *a = src->attrs ; a; a=a->next) + if (a->attr < OBJ_ATTR_SON) + for (struct oattr *aa = a; aa; aa=aa->same) + obj_add_attr(dest, aa->attr, aa->val); +} + +static void +cmd_status(struct conn *c) +{ + uns verbose = obj_find_anum(c->request, 'V', 0); + task_load_status(c); + + CLIST_FOR_EACH(struct task *, t, task_list) + { + struct odes *to = task_status_find_task(c, t, 1); + struct odes *tr = obj_add_son(c->reply, 'T' + OBJ_ATTR_SON); + copy_attrs(tr, to); + CLIST_FOR_EACH(simp_node *, x, *t->extensions) + obj_add_attr(tr, 'A', x->s); + CLIST_FOR_EACH(simp_node *, p, t->parts) + { + struct odes *po = task_status_find_part(to, p->s, 1); + struct odes *pr = obj_add_son(tr, 'P' + OBJ_ATTR_SON); + copy_attrs(pr, po); + uns current_ver = obj_find_anum(po, 'V', 0); + for (struct oattr *v = obj_find_attr(po, 'V' + OBJ_ATTR_SON); v; v=v->same) + { + struct odes *vo = v->son; + uns ver = obj_find_anum(vo, 'V', 0); + if (ver == current_ver || verbose) + obj_add_son_ref(pr, 'V' + OBJ_ATTR_SON, vo); + } + } + } +} + /*** SUBMIT ***/ +static struct fastbuf * +read_attachment(struct conn *c) +{ + uns size = obj_find_anum(c->request, 'S', 0); + if (size > max_attachment_size) + { + err(c, "Submission too large"); + return NULL; + } + obj_set_attr(c->reply, '+', "Go on"); + write_reply(c); + obj_set_attr(c->reply, '+', NULL); + + // This is less efficient than bbcopy(), but we want our own error handling. + struct fastbuf *fb = bopen_tmp(4096); + byte buf[4096]; + uns remains = size; + while (remains) + { + uns cnt = bread(&c->rx_fb, buf, MIN(remains, (uns)sizeof(buf))); + if (!cnt) + { + bclose(fb); + client_error("Truncated attachment"); + } + bwrite(fb, buf, cnt); + remains -= cnt; + } + brewind(fb); + return fb; +} + static void cmd_submit(struct conn *c) { @@ -101,6 +177,70 @@ cmd_submit(struct conn *c) err(c, "No such task"); return; } + + byte *pname = obj_find_aval(c->request, 'P'); + if (!pname) + { + simp_node *s = clist_head(&task->parts); + ASSERT(s); + pname = s->s; + } + else if (!part_exists_p(task, pname)) + { + err(c, "No such task part"); + return; + } + + byte *ext = obj_find_aval(c->request, 'X'); + if (!ext || !ext_exists_p(task, ext)) + { + err(c, "Missing or invalid extension"); + return; + } + + struct fastbuf *fb = read_attachment(c); + if (!fb) + return; + + // FIXME: Check contest time + // FIXME: Keep history of submitted tasks + + task_lock_status(c); + struct odes *tasko = task_status_find_task(c, task, 1); + struct odes *parto = task_status_find_part(tasko, pname, 1); + uns current_ver = obj_find_anum(parto, 'V', 0); + uns last_ver = 0; + uns replaced_ver = 0; + for (struct oattr *a = obj_find_attr(parto, 'V' + OBJ_ATTR_SON); a; a=a->same) + { + uns ver = obj_find_anum(a->son, 'V', 0); + byte *ext = obj_find_aval(a->son, 'X'); + ASSERT(ver && ext); + last_ver = MAX(last_ver, ver); + if (ver == current_ver) + { + task_delete_part(c->user, tname, pname, ext, ver); + obj_set_attr(a->son, 'S', "replaced"); + replaced_ver = current_ver; + } + } + struct odes *vero = obj_add_son(parto, 'V' + OBJ_ATTR_SON); + obj_set_attr_num(vero, 'V', ++last_ver); + obj_set_attr_num(vero, 'T', time(NULL)); + obj_set_attr_num(vero, 'L', obj_find_anum(c->request, 'S', 0)); + obj_set_attr(vero, 'S', "submitted"); + obj_set_attr(vero, 'X', ext); + // FIXME: hash + // FIXME: remove old versions from the status file? + task_submit_part(c->user, tname, pname, ext, last_ver, fb); + obj_set_attr_num(parto, 'V', last_ver); + task_unlock_status(c, 1); + + log(L_INFO, "User %s submitted task %s%s (version %d%s)", + c->user, tname, + (strcmp(tname, pname) ? stk_printf("/%s", pname) : ""), + last_ver, + (replaced_ver ? stk_printf(", replaced %d", replaced_ver) : "")); } /*** COMMAND MUX ***/ @@ -118,6 +258,8 @@ execute_command(struct conn *c) log(L_DEBUG, "<< %s", cmd); if (!strcasecmp(cmd, "SUBMIT")) cmd_submit(c); + else if (!strcasecmp(cmd, "STATUS")) + cmd_status(c); else err(c, "Unknown command"); }