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.
|
* `/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).
|
* `/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;
|
cart->rom = cart_data;
|
||||||
|
|
||||||
scpy(path, file, 64);
|
scpy(path, file, 64);
|
||||||
scat(file, "/data/sprites");
|
scat(file, "/data/sprites0");
|
||||||
cart->sprite_data = read_bytes(file);
|
cart->sprite_data = read_bytes(file);
|
||||||
scpy(path, file, 64);
|
scpy(path, file, 64);
|
||||||
scat(file, "/data/text");
|
scat(file, "/data/text0");
|
||||||
cart->txt_data = read_bytes(file);
|
cart->txt_data = read_bytes(file);
|
||||||
scpy(path, file, 64);
|
scpy(path, file, 64);
|
||||||
scat(file, "/data/audio");
|
scat(file, "/data/audio0");
|
||||||
cart->audio_data = read_bytes(file);
|
cart->audio_data = read_bytes(file);
|
||||||
|
|
||||||
return cart;
|
return cart;
|
||||||
|
@ -49,6 +49,44 @@ Cart* find_cart(UserInfo* table, char* name) {
|
||||||
return nil;
|
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) {
|
uint count_carts(UserInfo* table, char* name) {
|
||||||
UserInfo* u = table;
|
UserInfo* u = table;
|
||||||
uint i, j;
|
uint i, j;
|
||||||
|
|
1
cart.h
1
cart.h
|
@ -11,5 +11,6 @@ typedef struct Cart {
|
||||||
|
|
||||||
Cart* create_cart(char* name);
|
Cart* create_cart(char* name);
|
||||||
Cart* find_cart(UserInfo* table, 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);
|
uint count_carts(UserInfo* table, char* name);
|
||||||
void destroy_cart(Cart* self);
|
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 (f != nil) {
|
||||||
if (fgets(buf, 256, f)) {
|
if (fgets(buf, 256, f)) {
|
||||||
self = malloc(sizeof(Realm));
|
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);
|
fclose(f);
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
|
|
82
user.c
82
user.c
|
@ -19,24 +19,74 @@ UserInfo* find_user(UserInfo* table, char* uname) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_cart(UserInfo* table, char* uname, char* cart_name) {
|
int login(UserInfo* table, char* uname, char* password) {
|
||||||
Cart* c = find_cart(table, cart_name);
|
|
||||||
UserInfo* u = find_user(table, uname);
|
UserInfo* u = find_user(table, uname);
|
||||||
|
|
||||||
if (u == nil)
|
if (u == nil)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (c != nil) {
|
u->password = hash(password, 0);
|
||||||
u->cart = c;
|
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 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 {
|
} else {
|
||||||
u->cart = create_cart(cart_name);
|
return 1;
|
||||||
if (u->cart == nil) {
|
|
||||||
fprintf(stderr, "failed creating cart\n");
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,17 +155,11 @@ int leave_realm(UserInfo* table, char* uname) {
|
||||||
|
|
||||||
int unload_cart(UserInfo* table, char* uname) {
|
int unload_cart(UserInfo* table, char* uname) {
|
||||||
UserInfo* u = find_user(table, uname);
|
UserInfo* u = find_user(table, uname);
|
||||||
Cart* c;
|
|
||||||
|
|
||||||
if (u == nil)
|
if (u == nil || u->cart == nil)
|
||||||
return 0;
|
|
||||||
|
|
||||||
c = u->cart;
|
|
||||||
if (c == nil)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
destroy_cart(u->cart);
|
||||||
u->cart = nil;
|
u->cart = nil;
|
||||||
if (find_cart(table, c->name) == nil)
|
|
||||||
destroy_cart(c);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
4
user.h
4
user.h
|
@ -10,6 +10,10 @@ typedef struct UserInfo {
|
||||||
} UserInfo;
|
} UserInfo;
|
||||||
|
|
||||||
UserInfo* find_user(UserInfo* table, char* uname);
|
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 load_cart(UserInfo* table, char* uname, char* cart_name);
|
||||||
int enter_realm(UserInfo* table, char* uname, char* realm_name);
|
int enter_realm(UserInfo* table, char* uname, char* realm_name);
|
||||||
int leave_realm(UserInfo* table, char* uname);
|
int leave_realm(UserInfo* table, char* uname);
|
||||||
|
|
94
xrxs.c
94
xrxs.c
|
@ -32,15 +32,10 @@ void xrxs_attach(Req* r) {
|
||||||
* or the attach will never complete. We have logout() for now...
|
* or the attach will never complete. We have logout() for now...
|
||||||
*/
|
*/
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int l = 0;
|
|
||||||
int vacancy = 0;
|
int vacancy = 0;
|
||||||
char* usr;
|
char* usr;
|
||||||
char* username = r->ifcall.uname;
|
char* username = r->ifcall.uname;
|
||||||
usr = username;
|
|
||||||
while (*usr) {
|
|
||||||
l++;
|
|
||||||
usr++;
|
|
||||||
}
|
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
usr = users_table[i].name;
|
usr = users_table[i].name;
|
||||||
if (scmp(usr, username)) {
|
if (scmp(usr, username)) {
|
||||||
|
@ -48,7 +43,7 @@ void xrxs_attach(Req* r) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (*usr == 0) {
|
if (*usr == 0) {
|
||||||
scpy(username, usr, l + 1);
|
scpy(username, usr, 32);
|
||||||
vacancy = 1;
|
vacancy = 1;
|
||||||
break;
|
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) {
|
void write_ctl(Req* r) {
|
||||||
char cmd[16] = {0};
|
char cmd[16] = {0};
|
||||||
char* c = r->ifcall.data;
|
char* c = r->ifcall.data;
|
||||||
|
@ -117,22 +71,23 @@ void write_ctl(Req* r) {
|
||||||
uvlong const cmd_hashv = hash(cmd, 0);
|
uvlong const cmd_hashv = hash(cmd, 0);
|
||||||
switch (cmd_hashv) {
|
switch (cmd_hashv) {
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
login(r->fid->uid, c);
|
login(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
case LOAD:
|
case LOAD:
|
||||||
load_cart(users_table, r->fid->uid, c);
|
load_cart(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
case CHUNK:
|
case CHUNK:
|
||||||
// get_chunk(users_table, r->fid->uid, c);
|
get_chunk(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
case CREATE:
|
case CREATE:
|
||||||
create_realm(users_table, r->fid->uid, c);
|
create_realm(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
case PROTECT:
|
case PROTECT:
|
||||||
protect(r->fid->uid, c);
|
protect_realm(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
case TRANSFER:
|
case TRANSFER:
|
||||||
// transfer(r->fid->uid, c);
|
transfer_realm(users_table, r->fid->uid, c);
|
||||||
|
break;
|
||||||
case ENTER:
|
case ENTER:
|
||||||
enter_realm(users_table, r->fid->uid, c);
|
enter_realm(users_table, r->fid->uid, c);
|
||||||
break;
|
break;
|
||||||
|
@ -140,7 +95,7 @@ void write_ctl(Req* r) {
|
||||||
leave_realm(users_table, r->fid->uid);
|
leave_realm(users_table, r->fid->uid);
|
||||||
break;
|
break;
|
||||||
case LOGOUT:
|
case LOGOUT:
|
||||||
logout(r->fid->uid);
|
logout(users_table, r->fid->uid);
|
||||||
break;
|
break;
|
||||||
case SAVE:
|
case SAVE:
|
||||||
// save(r->fid->uid);
|
// save(r->fid->uid);
|
||||||
|
@ -242,7 +197,7 @@ String** list_dir(char* path) {
|
||||||
while ((ent = readdir(dir)) != NULL) {
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
if (i = size) {
|
if (i = size) {
|
||||||
size *= 2;
|
size *= 2;
|
||||||
self = reallloc(self, size * sizeof(String*));
|
self = realloc(self, size * sizeof(String*));
|
||||||
}
|
}
|
||||||
c = ent->d_name;
|
c = ent->d_name;
|
||||||
if (scmp(c, ".") || scmp(c, "..")) {
|
if (scmp(c, ".") || scmp(c, "..")) {
|
||||||
|
@ -272,19 +227,12 @@ void s_freemany(String** ss) {
|
||||||
free(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) {
|
void read_carts(Req* r) {
|
||||||
String** carts = list_dir(CARTSPATH);
|
String** carts = list_dir(CARTSPATH);
|
||||||
String** c = carts;
|
String** c = carts;
|
||||||
string* data = s_new();
|
String* data = s_new();
|
||||||
while (*c != nil) {
|
while (*c != nil) {
|
||||||
s_append(data, *c);
|
s_append(data, (*c)->base);
|
||||||
s_putc(data, '\n');
|
s_putc(data, '\n');
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
@ -352,7 +300,7 @@ void read_realms(Req* r) {
|
||||||
rr = realms;
|
rr = realms;
|
||||||
|
|
||||||
while (*rr != nil) {
|
while (*rr != nil) {
|
||||||
s_append(data, *rr);
|
s_append(data, (*rr)->base);
|
||||||
s_putc(data, ' ');
|
s_putc(data, ' ');
|
||||||
|
|
||||||
realm = parse_realm(user->cart->name, (*rr)->base);
|
realm = parse_realm(user->cart->name, (*rr)->base);
|
||||||
|
@ -366,13 +314,13 @@ void read_realms(Req* r) {
|
||||||
u++;
|
u++;
|
||||||
}
|
}
|
||||||
itoa(u, ubuf, 10);
|
itoa(u, ubuf, 10);
|
||||||
s_putmanyc(data, ubuf);
|
s_append(data, ubuf);
|
||||||
s_putc(data, ' ');
|
s_putc(data, ' ');
|
||||||
itoa(m, mbuf, 10);
|
itoa(m, mbuf, 10);
|
||||||
s_putmanyc(data, mbuf);
|
s_append(data, mbuf);
|
||||||
s_putc(data, ' ');
|
s_putc(data, ' ');
|
||||||
itoa(p, pbuf, 10);
|
itoa(p, pbuf, 10);
|
||||||
s_putmanyc(data, pbuf);
|
s_append(data, pbuf);
|
||||||
s_putc(data, '\n');
|
s_putc(data, '\n');
|
||||||
rr++;
|
rr++;
|
||||||
}
|
}
|
||||||
|
@ -390,19 +338,19 @@ void read_universe(Req* r) {
|
||||||
Universe* universe;
|
Universe* universe;
|
||||||
Atom* a;
|
Atom* a;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (u == nil || u->realm == nil) {
|
if (u == nil || u->realm == nil) {
|
||||||
respond(r, nil);
|
respond(r, nil);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
universe = u->realm->universe;
|
universe = u->realm->universe;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
a = universe[i];
|
a = universe->atoms[i];
|
||||||
while (a != nil) {
|
while (a != nil) {
|
||||||
s_putmanyc(data, a->name);
|
s_append(data, a->name);
|
||||||
s_putmanyc(data, " = ");
|
s_append(data, " = ");
|
||||||
s_putmanyc(data, a->value);
|
s_append(data, a->value);
|
||||||
s_putc(data, '\n');
|
s_putc(data, '\n');
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue