implement chunk paging, moved some functions out of xrxs.c into user.c
This commit is contained in:
parent
c8ba412121
commit
940791631c
7 changed files with 137 additions and 97 deletions
|
@ -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
44
cart.c
|
@ -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
1
cart.h
|
@ -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);
|
7
realm.c
7
realm.c
|
@ -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;
|
||||
|
|
72
user.c
72
user.c
|
@ -19,17 +19,68 @@ 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;
|
||||
} else {
|
||||
}
|
||||
|
||||
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");
|
||||
|
@ -37,7 +88,6 @@ int load_cart(UserInfo* table, char* uname, char* cart_name) {
|
|||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int enter_realm(UserInfo* table, char* uname, char* realm_name) {
|
||||
|
@ -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
4
user.h
|
@ -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
90
xrxs.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue