implement chunk paging, moved some functions out of xrxs.c into user.c

This commit is contained in:
Iris Lightshard 2021-07-21 00:27:40 -06:00
parent c8ba412121
commit 940791631c
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
7 changed files with 137 additions and 97 deletions

View file

@ -25,7 +25,7 @@ This is the working structure of the 9p filesystem:
* `/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).

44
cart.c
View file

@ -24,13 +24,13 @@ Cart* create_cart(char* name) {
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;
@ -49,6 +49,44 @@ Cart* find_cart(UserInfo* table, char* name) {
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) {
UserInfo* u = table;
uint i, j;

1
cart.h
View file

@ -11,5 +11,6 @@ typedef struct Cart {
Cart* create_cart(char* name);
Cart* find_cart(UserInfo* table, char* name);
int get_chunk(UserInfo* table, char* uname, char* chunk);
uint count_carts(UserInfo* table, char* name);
void destroy_cart(Cart* self);

View file

@ -69,7 +69,12 @@ Realm* parse_realm(char* cart, char* name) {
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;

82
user.c
View file

@ -19,24 +19,74 @@ UserInfo* find_user(UserInfo* table, char* uname) {
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 leave_realm(UserInfo* table, char* uname) {
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;
}

4
user.h
View file

@ -10,6 +10,10 @@ typedef struct UserInfo {
} 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);

90
xrxs.c
View file

@ -32,15 +32,10 @@ void xrxs_attach(Req* r) {
* 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 @@ void xrxs_attach(Req* r) {
return;
}
if (*usr == 0) {
scpy(username, usr, l + 1);
scpy(username, usr, 32);
vacancy = 1;
break;
}
@ -60,47 +55,6 @@ void xrxs_attach(Req* r) {
}
}
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 @@ void write_ctl(Req* r) {
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 @@ void write_ctl(Req* r) {
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 @@ String** list_dir(char* path) {
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 @@ void s_freemany(String** ss) {
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 @@ void read_realms(Req* r) {
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 @@ void read_realms(Req* r) {
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++;
}
@ -398,11 +346,11 @@ void read_universe(Req* r) {
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;
}