implement chunk paging, moved some functions out of xrxs.c into user.c
PGP Signature
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmD3vlwACgkQO3+8IhRO Y5g3nQ/+PXvkjZSELKbbSTHVpDFJbLTN6H9HWzcAvKVoHYznCTnA3nmks9G8ZIeq yR8bncrEzZm12EoO5MDynPLsLleK7flSMXmsilawwO+F/1eVSa1jAazDjOruJUhi bQqEHoYktek8y742inB9Hv/1LvA5qA050mqLHX+XesekoeG58WTXTL1V9F0Klpod pRqfDTa9i23taQ2ORqFmkl/NvCgZNj8/Wpdr+d0+evD2/h9kancZ/z9cwynPkqJY 0VQI4tYuZuBmzcHCeex+Gtbz7wkLEDf9D5vPHN+KK29XvoGMBCgiHEKixM6D3z7A ag41Nzi0HZXpVAK/93CI0X7ruv4MEP2r2a2OlZibrzJqpiSkYKX8+Qhtf5eRFPoh XotTL2Bwes7v1LfjPEqpeVyz6gKG18xacNGHGiCDUREqg94INXA1x9GBE3/8eAF/ zW6872TlZfBrFog66sHfE/QeTtSiRdY1ZTm9EWRHy5HVF+GSBpaZ36ByHi7L03+p XMFRsW/r1UJzUyE1dXMaAKpAgv/JZQsiPNsvY2OSISd+/8BRluVILgRHucASEd0g /0uoTL8SJn/nMquaj3uov9ijob8NfKhT9vjql8iI3l95UEll4diWDLPcc8HGjSLR 7tfiSSSumBIYOB9NUJBmoDxNRWzXzRgLeL/Ka9HHku8s4l0qW84= =dRwL -----END PGP SIGNATURE-----
@@ -25,7 +25,7 @@ * `/carts`: Available game/app cartridges for this server, read only; Carts are listed per line upon reading the file. It is backed by files on the server in a directory structure like `carts/CART_NAME/{CART_NAME.rom, data/, realms/}`.
* `/slot`: After loading the cartridge, its ROM is read from here; Read-only. -* `/data/`: Any supporting data that comes with the cartridge will be found here; They are in three parts: `sprite`, `audio`, and `text`. Because `uxn` is limited to 64-128kb input files, the filesizes of these data blobs should be 64kb max, and the `chunk` command should be used to page different files into the service when needed. The files on the server should be like `TYPE_dataN` where `TYPE` is one of `sprite`, `audio`, and `text`, and `N` is a nonnegative integer. `data0` is the default loaded if no specific chunk has been requested. Inputting a command `chunk sprite 2` will make `sprite_data2` available under `data/sprite`, and so on. +* `/data/`: Any supporting data that comes with the cartridge will be found here; They are in three parts: `sprite`, `audio`, and `text`. Because `uxn` is limited to 64-128kb input files, the filesizes of these data blobs should be 64kb max, and the `chunk` command should be used to page different files into the service when needed. The files on the server should be like `TYPEN` where `TYPE` is one of `sprite`, `audio`, and `text`, and `N` is any sequence of characters (canonically a nonnegative integer). When first loading the cartridge, `N == 0`. Issuing the command `chunk TYPE XXX` will attempt to load data from file `carts/CART_NAME/data/TYPEXXX` into the correct data file. If `TYPE` is not one of `sprite`, `audio`, or `text`, or the ifle `TYPEXXX` doesn't exist in the data directory, the `chunk` command does nothing. * `/realms`: Open/saved realms, read-only. Realms and their associated universe are backed by real files on the server so that they can be preserved across service instantiations, in a directory structure like: `carts/CART_NAME/realms/REALM_NAME/{realm, universe}`. Realms can either be solo, open, or protected; Open or protected realms can have limited member numbers. Depending on the cartridge, these settings can be user-managed or managed by the cartridge itself. Realms are listed per line upon reading the file like: `REALM_NAME 1 4 1`. First would obviously be the name of the realm. The first number is number of members, second is member limit, third is 1 if protected, 0 if not. `0 1 1` represents a protected solo realm that is empty (saved game with password). `0 1 0` represents an unprotected solo realm that is empty (saved game with no password).
@@ -24,13 +24,13 @@ scpy(name, cart->name, 32);
cart->rom = cart_data; scpy(path, file, 64); - scat(file, "/data/sprites"); + scat(file, "/data/sprites0"); cart->sprite_data = read_bytes(file); scpy(path, file, 64); - scat(file, "/data/text"); + scat(file, "/data/text0"); cart->txt_data = read_bytes(file); scpy(path, file, 64); - scat(file, "/data/audio"); + scat(file, "/data/audio0"); cart->audio_data = read_bytes(file); return cart;@@ -47,6 +47,44 @@ return u->cart;
u++; } return nil; +} + +int get_chunk(UserInfo* table, char* uname, char* chunk) { + UserInfo* u = find_user(table, uname); + char type[8] = {0}; + char chunk_id[64] = {0}; + char* c = chunk; + char* data; + + if (u == nil || u->cart == nil) + return 0; + + while (*c && *c != ' ') { + ccat(type, *c++); + } + if (*c == ' ') + c++; + + scat(chunk_id, "carts/"); + scat(chunk_id, u->cart->name); + ccat(chunk_id, '/'); + scat(chunk_id, type); + scat(chunk_id, c); + + data = read_bytes(chunk_id); + if (data == nil) { + return 0; + } + + if (scmp(type, "sprite")) { + u->cart->sprite_data = data; + } else if (scmp(type, "audio")) { + u->cart->audio_data = data; + } else { + u->cart->txt_data = data; + } + + return 1; } uint count_carts(UserInfo* table, char* name) {
@@ -69,7 +69,12 @@ f = fopen(file, "r");
if (f != nil) { if (fgets(buf, 256, f)) { self = malloc(sizeof(Realm)); - sscanf(buf, "%hu %32s %llu", &(self->max), self->master, &(self->password)); + sscanf( + buf, + "%hu %32s %llu", + &(self->max), + self->master, + &(self->password)); fclose(f); } else { return nil;
@@ -19,24 +19,74 @@ }
return nil; } -int load_cart(UserInfo* table, char* uname, char* cart_name) { - Cart* c = find_cart(table, cart_name); +int login(UserInfo* table, char* uname, char* password) { UserInfo* u = find_user(table, uname); if (u == nil) return 0; - if (c != nil) { - u->cart = c; + u->password = hash(password, 0); + return 1; +} + +int logout(UserInfo* table, char* uname) { + UserInfo* u = table; + + if (u == nil) + return 0; + + *(u->name) = 0; + u->password = 0; + + if (u->scope != nil) { + free(u->scope); + u->scope = nil; + } + + u->random = 0; + + if (u->realm != nil) + leave_realm(table, uname); + + if (u->cart != nil) + unload_cart(table, uname); + + return 1; +} + +int protect_realm(UserInfo* table, char* uname, char* password) { + UserInfo* u = find_user(table, uname); + + if (u != nil && u->realm != nil && scmp(uname, u->realm->master)) { + u->realm->password = hash(password, 0); return 1; + } + return 0; +} + +int transfer_realm(UserInfo* table, char* from, char* to) { + UserInfo* old_user = find_user(table, from); + UserInfo* new_user = find_user(table, to); + + if (old_user == nil || new_user == nil || old_user->realm == nil) + return 0; + + scpy(to, old_user->realm->master, 32); + return 1; +} + +int load_cart(UserInfo* table, char* uname, char* cart_name) { + UserInfo* u = find_user(table, uname); + + if (u == nil) + return 0; + + u->cart = create_cart(cart_name); + if (u->cart == nil) { + fprintf(stderr, "failed creating cart\n"); + return 0; } else { - u->cart = create_cart(cart_name); - if (u->cart == nil) { - fprintf(stderr, "failed creating cart\n"); - return 0; - } else { - return 1; - } + return 1; } }@@ -105,17 +155,11 @@ }
int unload_cart(UserInfo* table, char* uname) { UserInfo* u = find_user(table, uname); - Cart* c; - if (u == nil) - return 0; - - c = u->cart; - if (c == nil) + if (u == nil || u->cart == nil) return 0; + destroy_cart(u->cart); u->cart = nil; - if (find_cart(table, c->name) == nil) - destroy_cart(c); return 1; }
@@ -10,6 +10,10 @@ int random;
} UserInfo; UserInfo* find_user(UserInfo* table, char* uname); +int login(UserInfo* table, char* uname, char* password); +int logout(UserInfo* table, char* uname); +int protect_realm(UserInfo* table, char* uname, char* password); +int transfer_realm(UserInfo* table, char* from, char* to); int load_cart(UserInfo* table, char* uname, char* cart_name); int enter_realm(UserInfo* table, char* uname, char* realm_name); int leave_realm(UserInfo* table, char* uname);
@@ -32,15 +32,10 @@ * to detect a detach to remove them... You can't delay respond()
* or the attach will never complete. We have logout() for now... */ int i = 0; - int l = 0; int vacancy = 0; char* usr; char* username = r->ifcall.uname; - usr = username; - while (*usr) { - l++; - usr++; - } + for (i = 0; i < 64; i++) { usr = users_table[i].name; if (scmp(usr, username)) {@@ -48,7 +43,7 @@ respond(r, EUNAME);
return; } if (*usr == 0) { - scpy(username, usr, l + 1); + scpy(username, usr, 32); vacancy = 1; break; }@@ -60,47 +55,6 @@ respond(r, EUFULL);
} } -void login(char* uname, char* password) { - int i; - for (i = 0; i < 64; i++) { - if (scmp(uname, users_table[i].name)) { - users_table[i].password = hash(password, 0); - } - } -} - -int logout(char* uname) { - int i; - UserInfo* u = users_table; - - for (i = 0; i < 64; i++) { - if (scmp(uname, u->name)) { - *(u->name) = 0; - u->password = 0; - if (u->scope != nil) { - free(u->scope); - u->scope = nil; - } - u->random = 0; - if (u->realm != nil) - leave_realm(users_table, uname); - if (u->cart != nil) - unload_cart(users_table, uname); - return 1; - } - u++; - } - return 0; -} - -void protect(char* uname, char* password) { - UserInfo* u = find_user(users_table, uname); - - if (u != nil && u->realm != nil && scmp(uname, u->realm->master)) { - u->realm->password = hash(password, 0); - } -} - void write_ctl(Req* r) { char cmd[16] = {0}; char* c = r->ifcall.data;@@ -117,22 +71,23 @@ fprintf(stderr, "%s(%s)\n", cmd, c);
uvlong const cmd_hashv = hash(cmd, 0); switch (cmd_hashv) { case LOGIN: - login(r->fid->uid, c); + login(users_table, r->fid->uid, c); break; case LOAD: load_cart(users_table, r->fid->uid, c); break; case CHUNK: - // get_chunk(users_table, r->fid->uid, c); + get_chunk(users_table, r->fid->uid, c); break; case CREATE: create_realm(users_table, r->fid->uid, c); break; case PROTECT: - protect(r->fid->uid, c); + protect_realm(users_table, r->fid->uid, c); break; case TRANSFER: - // transfer(r->fid->uid, c); + transfer_realm(users_table, r->fid->uid, c); + break; case ENTER: enter_realm(users_table, r->fid->uid, c); break;@@ -140,7 +95,7 @@ case LEAVE:
leave_realm(users_table, r->fid->uid); break; case LOGOUT: - logout(r->fid->uid); + logout(users_table, r->fid->uid); break; case SAVE: // save(r->fid->uid);@@ -242,7 +197,7 @@ if ((dir = opendir(path)) != NULL) {
while ((ent = readdir(dir)) != NULL) { if (i = size) { size *= 2; - self = reallloc(self, size * sizeof(String*)); + self = realloc(self, size * sizeof(String*)); } c = ent->d_name; if (scmp(c, ".") || scmp(c, "..")) {@@ -272,19 +227,12 @@ }
free(ss); } -String* s_putmanyc(String* s, char* c) { - String* tmp = s_copy(c); - s_append(s, tmp); - s_free(tmp); - return s; -} - void read_carts(Req* r) { String** carts = list_dir(CARTSPATH); String** c = carts; - string* data = s_new(); + String* data = s_new(); while (*c != nil) { - s_append(data, *c); + s_append(data, (*c)->base); s_putc(data, '\n'); c++; }@@ -352,7 +300,7 @@ realms = list_dir(realm_path);
rr = realms; while (*rr != nil) { - s_append(data, *rr); + s_append(data, (*rr)->base); s_putc(data, ' '); realm = parse_realm(user->cart->name, (*rr)->base);@@ -366,13 +314,13 @@ scmp(users_table[i].realm->name, realm->name))
u++; } itoa(u, ubuf, 10); - s_putmanyc(data, ubuf); + s_append(data, ubuf); s_putc(data, ' '); itoa(m, mbuf, 10); - s_putmanyc(data, mbuf); + s_append(data, mbuf); s_putc(data, ' '); itoa(p, pbuf, 10); - s_putmanyc(data, pbuf); + s_append(data, pbuf); s_putc(data, '\n'); rr++; }@@ -390,19 +338,19 @@ String* data = s_new();
Universe* universe; Atom* a; int i; - + if (u == nil || u->realm == nil) { respond(r, nil); return; } - + universe = u->realm->universe; for (i = 0; i < 256; i++) { - a = universe[i]; + a = universe->atoms[i]; while (a != nil) { - s_putmanyc(data, a->name); - s_putmanyc(data, " = "); - s_putmanyc(data, a->value); + s_append(data, a->name); + s_append(data, " = "); + s_append(data, a->value); s_putc(data, '\n'); a = a->next; }