forked from Telodendria/Telodendria
[MOD] Revamping the state a bit
Some checks are pending
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run
Some checks are pending
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run
This commit is contained in:
parent
15f4de2a25
commit
b719a16d9f
5 changed files with 261 additions and 178 deletions
39
src/Room.c
39
src/Room.c
|
@ -35,6 +35,7 @@
|
|||
#include <Cytoplasm/Base64.h>
|
||||
#include <Cytoplasm/Util.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <Cytoplasm/Log.h>
|
||||
#include <Cytoplasm/Db.h>
|
||||
|
||||
#include <Schema/RoomCreateRequest.h>
|
||||
|
@ -430,7 +431,7 @@ RoomVersionGet(Room * room)
|
|||
return room ? room->version : 0;
|
||||
}
|
||||
|
||||
HashMap *
|
||||
State *
|
||||
RoomStateGet(Room * room)
|
||||
{
|
||||
HashMap *database_state;
|
||||
|
@ -446,10 +447,11 @@ RoomStateGet(Room * room)
|
|||
database_state = DbJson(room->state_ref);
|
||||
return StateDeserialise(database_state);
|
||||
}
|
||||
HashMap *
|
||||
State *
|
||||
RoomStateGetID(Room * room, char *event_id)
|
||||
{
|
||||
HashMap *event, *state;
|
||||
HashMap *event;
|
||||
State *state;
|
||||
if (!room || !event_id)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -490,7 +492,7 @@ RoomStateGetID(Room * room, char *event_id)
|
|||
} \
|
||||
return ret
|
||||
static bool
|
||||
RoomIsJoinRule(Room * room, HashMap *state, char *jr)
|
||||
RoomIsJoinRule(Room * room, State *state, char *jr)
|
||||
{
|
||||
HashMap *joinrule = NULL;
|
||||
char *id_joinrule = NULL;
|
||||
|
@ -510,7 +512,7 @@ finish:
|
|||
}
|
||||
/* Verifies if user has a specific membership before [e_id] in the room. */
|
||||
static bool
|
||||
RoomUserHasMembership(Room * room, HashMap *state, char *user, char *mbr)
|
||||
RoomUserHasMembership(Room * room, State *state, char *user, char *mbr)
|
||||
{
|
||||
HashMap *membership = NULL;
|
||||
char *id_membership = NULL;
|
||||
|
@ -559,7 +561,7 @@ ParsePL(JsonValue *v, int64_t def)
|
|||
}
|
||||
/* Computes the smallest PL needed to do something somewhere */
|
||||
static int64_t
|
||||
RoomMinPL(Room * room, HashMap *state, char *type, char *act)
|
||||
RoomMinPL(Room * room, State *state, char *type, char *act)
|
||||
{
|
||||
HashMap *pl = NULL;
|
||||
JsonValue *val;
|
||||
|
@ -599,7 +601,7 @@ finish:
|
|||
/* Finds the power level of an user before [e_id] was sent. */
|
||||
/* TODO: The creator should have PL100 by default. */
|
||||
static int64_t
|
||||
RoomUserPL(Room * room, HashMap *state, char *user)
|
||||
RoomUserPL(Room * room, State *state, char *user)
|
||||
{
|
||||
HashMap *pl = NULL;
|
||||
char *id_pl;
|
||||
|
@ -919,7 +921,7 @@ AuthoriseAliasV1(PduV1 pdu)
|
|||
return true;
|
||||
}
|
||||
static bool
|
||||
AuthorizeInviteMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthorizeInviteMembershipV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
int64_t invite_level;
|
||||
int64_t pdu_level;
|
||||
|
@ -1018,7 +1020,7 @@ AuthorizeInviteMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
return false;
|
||||
}
|
||||
static bool
|
||||
AuthorizeLeaveMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthorizeLeaveMembershipV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
int64_t ban_level = RoomMinPL(room, state, NULL, "ban");
|
||||
int64_t kick_level = RoomMinPL(room, state, NULL, "kick");
|
||||
|
@ -1061,7 +1063,7 @@ AuthorizeLeaveMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
return false;
|
||||
}
|
||||
static bool
|
||||
AuthorizeBanMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthorizeBanMembershipV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
int64_t ban_pl, pdu_pl, target_pl;
|
||||
|
||||
|
@ -1086,7 +1088,7 @@ AuthorizeBanMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
return false;
|
||||
}
|
||||
static bool
|
||||
AuthorizeJoinMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthorizeJoinMembershipV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
/* Step 5.2.1: If the only previous event is an m.room.create and the
|
||||
* state_key is the creator, allow. */
|
||||
|
@ -1144,7 +1146,7 @@ AuthorizeJoinMembershipV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
return false;
|
||||
}
|
||||
static bool
|
||||
AuthoriseMemberV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthoriseMemberV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
JsonValue *membership;
|
||||
char *membership_str;
|
||||
|
@ -1186,7 +1188,7 @@ AuthoriseMemberV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
#undef JumpIfMembership
|
||||
}
|
||||
static bool
|
||||
AuthorisePowerLevelsV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
AuthorisePowerLevelsV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
/* Step 10.1: If the users property in content is not an object with
|
||||
* keys that are valid user IDs with values that are integers
|
||||
|
@ -1362,7 +1364,7 @@ AuthorisePowerLevelsV1(Room * room, PduV1 pdu, HashMap *state)
|
|||
return true;
|
||||
}
|
||||
bool
|
||||
RoomAuthoriseEventV1(Room * room, PduV1 pdu, HashMap *state)
|
||||
RoomAuthoriseEventV1(Room * room, PduV1 pdu, State *state)
|
||||
{
|
||||
HashMap *create_event;
|
||||
char *create_event_id;
|
||||
|
@ -1563,12 +1565,13 @@ RoomEventSendV1(Room * room, HashMap * event)
|
|||
PduV1 pdu = { 0 };
|
||||
HashMap *pdu_object = NULL;
|
||||
bool client_event, valid = false;
|
||||
HashMap *state = NULL;
|
||||
State *state = NULL;
|
||||
|
||||
client_event = !PopulateEventV1(room, event, &pdu, RoomGetCreator(room));
|
||||
pdu_object = PduV1ToJson(&pdu);
|
||||
|
||||
state = StateResolve(room, pdu_object);
|
||||
|
||||
if (client_event)
|
||||
{
|
||||
char *ev_id;
|
||||
|
@ -1851,7 +1854,7 @@ RoomAddEventV1(Room *room, PduV1 pdu)
|
|||
}
|
||||
|
||||
{
|
||||
HashMap *state;
|
||||
State *state;
|
||||
char *type, *state_key, *event_id;
|
||||
|
||||
pdu_json = PduV1ToJson(&pdu);
|
||||
|
@ -2133,7 +2136,7 @@ RoomGetDB(Room *room)
|
|||
bool
|
||||
RoomContainsUser(Room *room, char *user)
|
||||
{
|
||||
HashMap *state;
|
||||
State *state;
|
||||
bool ret;
|
||||
if (!room || !user)
|
||||
{
|
||||
|
@ -2151,7 +2154,7 @@ RoomContainsUser(Room *room, char *user)
|
|||
bool
|
||||
RoomCanJoin(Room *room, char *user)
|
||||
{
|
||||
HashMap *state;
|
||||
State *state;
|
||||
HashMap *joinRule = NULL;
|
||||
char *joinRuleV;
|
||||
bool ret;
|
||||
|
|
|
@ -184,7 +184,7 @@ ROUTE_IMPL(RouteSync, path, argp)
|
|||
char *firstEvent = NULL;
|
||||
char *type, *key, *id;
|
||||
HashMap *joinedObj;
|
||||
HashMap *state;
|
||||
State *state;
|
||||
Array *el;
|
||||
size_t j;
|
||||
Room *r;
|
||||
|
|
369
src/State.c
369
src/State.c
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Base64.h>
|
||||
#include <Cytoplasm/Array.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <Cytoplasm/Sha.h>
|
||||
|
@ -36,6 +37,21 @@
|
|||
#include <Event.h>
|
||||
#include <Room.h>
|
||||
|
||||
struct State {
|
||||
/* A hashmap of event IDs for a state */
|
||||
HashMap *table;
|
||||
};
|
||||
|
||||
|
||||
static State *
|
||||
InitialiseState(void)
|
||||
{
|
||||
State *ret = Malloc(sizeof(*ret));
|
||||
|
||||
ret->table = HashMapCreate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
V1Cmp(void *a, void *b)
|
||||
{
|
||||
|
@ -76,30 +92,60 @@ V1Cmp(void *a, void *b)
|
|||
return ret;
|
||||
}
|
||||
}
|
||||
static HashMap *
|
||||
StateResolveV1(Room * room, Array * states)
|
||||
|
||||
static char *
|
||||
EncodeStateTuple(char *type, char *stateKey)
|
||||
{
|
||||
size_t typeLen = type ? strlen(type) : 0;
|
||||
size_t stateKeyLen = stateKey ? strlen(stateKey) : 0;
|
||||
size_t length = typeLen + 1 + stateKeyLen + 1;
|
||||
char *tuple = Malloc(length);
|
||||
char *base64;
|
||||
|
||||
memset(tuple, '\0', length);
|
||||
memcpy(tuple, type, typeLen);
|
||||
memcpy(tuple + typeLen + 1, stateKey, stateKeyLen);
|
||||
|
||||
base64 = Base64Encode((const char *) tuple, length);
|
||||
Free(tuple);
|
||||
return base64;
|
||||
}
|
||||
static void
|
||||
DecodeStateTuple(char *base64, char **key, char **val)
|
||||
{
|
||||
size_t base64Size = base64 ? strlen(base64) : 0;
|
||||
char *decodeBuffer = NULL;
|
||||
if (!base64 || !key || !val)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
decodeBuffer = Base64Decode((const char *) base64, base64Size);
|
||||
*key = StrDuplicate(decodeBuffer);
|
||||
*val = StrDuplicate(decodeBuffer + strlen(decodeBuffer) + 1);
|
||||
|
||||
Free(decodeBuffer);
|
||||
}
|
||||
|
||||
static void
|
||||
BuildBaseAndConflictV1(Room *room, Array *states, State *R, HashMap *conflicts)
|
||||
{
|
||||
HashMap *R = HashMapCreate();
|
||||
HashMap *conflicts = HashMapCreate();
|
||||
Array *events = NULL, *types = NULL, *conflicting = NULL;
|
||||
size_t i;
|
||||
ssize_t j;
|
||||
|
||||
char *type, *key, *event_id;
|
||||
|
||||
char *type = NULL, *key = NULL;
|
||||
for (i = 0; i < ArraySize(states); i++)
|
||||
{
|
||||
HashMap *state = ArrayGet(states, i);
|
||||
char *tuple;
|
||||
while (HashMapIterate(state, &tuple, (void **) &event_id))
|
||||
char *event_id;
|
||||
State *state = ArrayGet(states, i);
|
||||
while (StateIterate(state, &type, &key, (void **) &event_id))
|
||||
{
|
||||
if (HashMapGet(R, tuple))
|
||||
char *tuple = EncodeStateTuple(type, key);
|
||||
if (StateGet(R, type, key) || HashMapGet(conflicts, tuple))
|
||||
{
|
||||
Array *arr;
|
||||
HashMap *hm;
|
||||
|
||||
/* Conflicts! */
|
||||
HashMapDelete(R, tuple);
|
||||
StateSet(R, type, key, NULL);
|
||||
arr = HashMapGet(conflicts, tuple);
|
||||
if (!arr)
|
||||
{
|
||||
|
@ -112,98 +158,136 @@ StateResolveV1(Room * room, Array * states)
|
|||
else
|
||||
{
|
||||
/* Add to R */
|
||||
HashMapSet(R, tuple, StrDuplicate(event_id));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* R and conflicts are now configured */
|
||||
types = ArrayCreate();
|
||||
ArrayAdd(types, "m.room.power_levels");
|
||||
ArrayAdd(types, "m.room.join_rules");
|
||||
ArrayAdd(types, "m.room.member");
|
||||
for (i = 0; i < ArraySize(types); i++)
|
||||
{
|
||||
char *t = ArrayGet(types, i);
|
||||
HashMap *first;
|
||||
Array *state_keys;
|
||||
|
||||
events = ArrayCreate();
|
||||
while (StateIterate(conflicts, &type, &key, (void **) &conflicting))
|
||||
{
|
||||
if (StrEquals(type, t))
|
||||
{
|
||||
for (j = 0; j < (ssize_t) ArraySize(conflicting); j++)
|
||||
{
|
||||
HashMap *event = ArrayGet(conflicting, j);
|
||||
ArrayAdd(events, event);
|
||||
}
|
||||
StateSet(R, type, key, event_id);
|
||||
}
|
||||
Free(tuple);
|
||||
Free(type);
|
||||
Free(key);
|
||||
}
|
||||
ArraySort(events, V1Cmp);
|
||||
/* Add first event. */
|
||||
first = ArrayDelete(events, 0);
|
||||
StateSet(
|
||||
R,
|
||||
JsonValueAsString(JsonGet(first, 1, "type")),
|
||||
JsonValueAsString(JsonGet(first, 1, "state_key")),
|
||||
JsonValueAsString(JsonGet(first, 1, "event_id")));
|
||||
JsonFree(first);
|
||||
|
||||
for (j = 0; j < (ssize_t) ArraySize(events); j++)
|
||||
{
|
||||
HashMap *event = ArrayGet(events, j);
|
||||
PduV1 pdu;
|
||||
char *msg;
|
||||
}
|
||||
}
|
||||
static void
|
||||
FixoutConflictV1(char *t, Room *room, State *R, HashMap *conflicts)
|
||||
{
|
||||
HashMap *first;
|
||||
Array *state_keys, *conflicting, *events;
|
||||
char *tuple;
|
||||
size_t i;
|
||||
|
||||
PduV1FromJson(event, &pdu, &msg);
|
||||
if (RoomAuthoriseEventV1(room, pdu, R))
|
||||
events = ArrayCreate();
|
||||
while (HashMapIterate(conflicts, &tuple, (void **) &conflicting))
|
||||
{
|
||||
char *type, *key;
|
||||
DecodeStateTuple(tuple, &type, &key);
|
||||
|
||||
if (StrEquals(type, t))
|
||||
{
|
||||
for (i = 0; i < ArraySize(conflicting); i++)
|
||||
{
|
||||
StateSet(R, pdu.type, pdu.state_key, pdu.event_id);
|
||||
HashMap *event = ArrayGet(conflicting, i);
|
||||
ArrayAdd(events, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
PduV1Free(&pdu);
|
||||
JsonFree(event);
|
||||
break;
|
||||
}
|
||||
(void) msg;
|
||||
}
|
||||
Free(type);
|
||||
Free(key);
|
||||
}
|
||||
ArraySort(events, V1Cmp);
|
||||
/* Add first event. */
|
||||
first = ArrayDelete(events, 0);
|
||||
StateSet(
|
||||
R,
|
||||
JsonValueAsString(JsonGet(first, 1, "type")),
|
||||
JsonValueAsString(JsonGet(first, 1, "state_key")),
|
||||
JsonValueAsString(JsonGet(first, 1, "event_id"))
|
||||
);
|
||||
JsonFree(first);
|
||||
|
||||
for (i = 0; i < ArraySize(events); i++)
|
||||
{
|
||||
HashMap *event = ArrayGet(events, i);
|
||||
PduV1 pdu;
|
||||
char *msg;
|
||||
|
||||
PduV1FromJson(event, &pdu, &msg);
|
||||
if (RoomAuthoriseEventV1(room, pdu, R))
|
||||
{
|
||||
StateSet(R, pdu.type, pdu.state_key, pdu.event_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
PduV1Free(&pdu);
|
||||
JsonFree(event);
|
||||
break;
|
||||
}
|
||||
ArrayFree(events);
|
||||
/* Delete all elements within a key. */
|
||||
state_keys = ArrayCreate();
|
||||
while (StateIterate(conflicts, &type, &key, (void **) &event_id))
|
||||
{
|
||||
if (StrEquals(type, t))
|
||||
{
|
||||
ArrayAdd(state_keys, key);
|
||||
}
|
||||
Free(type);
|
||||
}
|
||||
for (j = 0; j < (ssize_t) ArraySize(state_keys); j++)
|
||||
{
|
||||
char *state_key = ArrayGet(state_keys, j);
|
||||
StateSet(conflicts, t, state_key, NULL);
|
||||
Free(state_key);
|
||||
}
|
||||
ArrayFree(state_keys);
|
||||
(void) msg;
|
||||
PduV1Free(&pdu);
|
||||
JsonFree(event);
|
||||
}
|
||||
ArrayFree(types);
|
||||
ArrayFree(events);
|
||||
|
||||
while (StateIterate(conflicts, &type, &key, (void **) &conflicting))
|
||||
state_keys = ArrayCreate();
|
||||
while (HashMapIterate(conflicts, &tuple, (void **) &conflicting))
|
||||
{
|
||||
ArraySort(conflicting, V1Cmp);
|
||||
for (j = ArraySize(conflicting) - 1; j >= 0; j--)
|
||||
char *type, *key;
|
||||
DecodeStateTuple(tuple, &type, &key);
|
||||
|
||||
if (StrEquals(type, t))
|
||||
{
|
||||
HashMap *event = ArrayGet(events, j);
|
||||
PduV1 pdu;
|
||||
ArrayAdd(state_keys, key);
|
||||
}
|
||||
else
|
||||
{
|
||||
Free(key);
|
||||
}
|
||||
Free(type);
|
||||
}
|
||||
for (i = 0; i < ArraySize(state_keys); i++)
|
||||
{
|
||||
char *state_key = ArrayGet(state_keys, i);
|
||||
char *tuple = EncodeStateTuple(t, state_key);
|
||||
Array *conflict = HashMapDelete(conflicts, tuple);
|
||||
|
||||
/* All of the other values are already freed */
|
||||
ArrayFree(conflict);
|
||||
|
||||
Free(state_key);
|
||||
Free(tuple);
|
||||
}
|
||||
ArrayFree(state_keys);
|
||||
}
|
||||
|
||||
|
||||
static State *
|
||||
StateResolveV1(Room * room, Array * states)
|
||||
{
|
||||
State *R = InitialiseState();
|
||||
HashMap *conflicts = HashMapCreate();
|
||||
Array *events = NULL, *conflicting = NULL;
|
||||
char *type, *key, *tuple;
|
||||
|
||||
BuildBaseAndConflictV1(room, states, R, conflicts);
|
||||
|
||||
/* R and conflicts are now configured */
|
||||
FixoutConflictV1("m.room.power_levels", room, R, conflicts);
|
||||
FixoutConflictV1("m.room.join_rules", room, R, conflicts);
|
||||
FixoutConflictV1("m.room.member", room, R, conflicts);
|
||||
|
||||
while (HashMapIterate(conflicts, &tuple, (void **) &conflicting))
|
||||
{
|
||||
ssize_t i;
|
||||
DecodeStateTuple(tuple, &type, &key);
|
||||
|
||||
ArraySort(conflicting, V1Cmp);
|
||||
for (i = ArraySize(conflicting) - 1; i >= 0; i--)
|
||||
{
|
||||
HashMap *event = ArrayGet(events, i);
|
||||
PduV1 pdu = { 0 };
|
||||
char *msg;
|
||||
|
||||
PduV1FromJson(event, &pdu, &msg);
|
||||
if (!PduV1FromJson(event, &pdu, &msg))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RoomAuthoriseEventV1(room, pdu, R))
|
||||
{
|
||||
|
@ -217,8 +301,10 @@ StateResolveV1(Room * room, Array * states)
|
|||
Free(type);
|
||||
Free(key);
|
||||
}
|
||||
while (HashMapIterate(conflicts, &type, (void **) &conflicting))
|
||||
|
||||
while (HashMapIterate(conflicts, &tuple, (void **) &conflicting))
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ArraySize(conflicting); i++)
|
||||
{
|
||||
JsonFree(ArrayGet(conflicting, i));
|
||||
|
@ -230,14 +316,14 @@ StateResolveV1(Room * room, Array * states)
|
|||
return R;
|
||||
}
|
||||
|
||||
static HashMap *
|
||||
static State *
|
||||
StateResolveV2(Array * states)
|
||||
{
|
||||
(void) states;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HashMap *
|
||||
static State *
|
||||
StateFromPrevs(Room *room, Array *states)
|
||||
{
|
||||
switch (RoomVersionGet(room))
|
||||
|
@ -249,7 +335,7 @@ StateFromPrevs(Room *room, Array *states)
|
|||
}
|
||||
}
|
||||
|
||||
HashMap *
|
||||
State *
|
||||
StateResolve(Room * room, HashMap * event)
|
||||
{
|
||||
Array *states;
|
||||
|
@ -257,7 +343,7 @@ StateResolve(Room * room, HashMap * event)
|
|||
|
||||
Array *prevEvents;
|
||||
|
||||
HashMap *ret_state;
|
||||
State *ret_state;
|
||||
|
||||
char *room_id, *event_id;
|
||||
|
||||
|
@ -300,7 +386,7 @@ StateResolve(Room * room, HashMap * event)
|
|||
{
|
||||
HashMap *prevEvent =
|
||||
RoomEventFetch(room, JsonValueAsString(ArrayGet(prevEvents, i)));
|
||||
HashMap *state = StateResolve(room, prevEvent);
|
||||
State *state = StateResolve(room, prevEvent);
|
||||
|
||||
if (HashMapGet(prevEvent, "state_key"))
|
||||
{
|
||||
|
@ -308,7 +394,8 @@ StateResolve(Room * room, HashMap * event)
|
|||
state,
|
||||
JsonValueAsString(HashMapGet(prevEvent, "type")),
|
||||
JsonValueAsString(HashMapGet(prevEvent, "state_key")),
|
||||
JsonValueAsString(HashMapGet(prevEvent, "event_id")));
|
||||
JsonValueAsString(HashMapGet(prevEvent, "event_id"))
|
||||
);
|
||||
}
|
||||
|
||||
ArrayAdd(states, state);
|
||||
|
@ -319,7 +406,7 @@ StateResolve(Room * room, HashMap * event)
|
|||
|
||||
for (i = 0; i < ArraySize(states); i++)
|
||||
{
|
||||
HashMap *state = ArrayGet(states, i);
|
||||
State *state = ArrayGet(states, i);
|
||||
StateFree(state);
|
||||
}
|
||||
ArrayFree(states);
|
||||
|
@ -335,13 +422,13 @@ StateResolve(Room * room, HashMap * event)
|
|||
|
||||
return ret_state;
|
||||
}
|
||||
HashMap *
|
||||
State *
|
||||
StateCurrent(Room *room)
|
||||
{
|
||||
Array *prevEvents;
|
||||
Array *states;
|
||||
size_t i;
|
||||
HashMap *ret;
|
||||
State *ret;
|
||||
if (!room)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -353,8 +440,7 @@ StateCurrent(Room *room)
|
|||
{
|
||||
HashMap *event =
|
||||
JsonValueAsObject(ArrayGet(prevEvents, i));
|
||||
HashMap *state = StateResolve(room, event);
|
||||
|
||||
State *state = StateResolve(room, event);
|
||||
|
||||
if (HashMapGet(event, "state_key"))
|
||||
{
|
||||
|
@ -362,7 +448,8 @@ StateCurrent(Room *room)
|
|||
state,
|
||||
JsonValueAsString(HashMapGet(event, "type")),
|
||||
JsonValueAsString(HashMapGet(event, "state_key")),
|
||||
JsonValueAsString(HashMapGet(event, "event_id")));
|
||||
JsonValueAsString(HashMapGet(event, "event_id"))
|
||||
);
|
||||
}
|
||||
|
||||
ArrayAdd(states, state);
|
||||
|
@ -372,7 +459,7 @@ StateCurrent(Room *room)
|
|||
|
||||
for (i = 0; i < ArraySize(states); i++)
|
||||
{
|
||||
HashMap *state = ArrayGet(states, i);
|
||||
State *state = ArrayGet(states, i);
|
||||
StateFree(state);
|
||||
}
|
||||
ArrayFree(states);
|
||||
|
@ -380,90 +467,79 @@ StateCurrent(Room *room)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: USING A ',' DELIMITED HASHMAP IS A _BAD_ IDEA!
|
||||
* I'll need to change these functions, and some things in the room
|
||||
* implementation, thankfully _that_ was abstracted away, so I don't have
|
||||
* to think about it too much... */
|
||||
bool
|
||||
StateIterate(HashMap *state, char **type, char **key, void **event)
|
||||
StateIterate(State *state, char **type, char **key, void **event)
|
||||
{
|
||||
char *tuple;
|
||||
bool ret;
|
||||
char *tuple;
|
||||
if (!state || !type || !key || !event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = HashMapIterate(state, &tuple, event);
|
||||
|
||||
ret = HashMapIterate(state->table, &tuple, event);
|
||||
if (ret)
|
||||
{
|
||||
tuple = StrDuplicate(tuple);
|
||||
*(strchr(tuple, ',')) = '\0';
|
||||
|
||||
*type = tuple;
|
||||
*key = StrDuplicate(tuple + strlen(tuple) + 1);
|
||||
DecodeStateTuple(tuple, type, key);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
StateGet(HashMap *state, char *type, char *key)
|
||||
StateGet(State *state, char *type, char *key)
|
||||
{
|
||||
char *full_string;
|
||||
char *tableKey;
|
||||
char *ret;
|
||||
if (!state || !type || !key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
full_string = StrConcat(3, type, ",", key);
|
||||
ret = HashMapGet(state, full_string);
|
||||
Free(full_string);
|
||||
tableKey = EncodeStateTuple(type, key);
|
||||
ret = HashMapGet(state->table, tableKey);
|
||||
|
||||
Free(tableKey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
StateSet(HashMap *state, char *type, char *key, char *event)
|
||||
StateSet(State *state, char *type, char *key, char *event)
|
||||
{
|
||||
char *full_string, *old;
|
||||
char *tableKey;
|
||||
if (!state || !type || !key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
full_string = StrConcat(3, type, ",", key);
|
||||
old = HashMapDelete(state, full_string);
|
||||
if (old)
|
||||
{
|
||||
Free(old);
|
||||
}
|
||||
tableKey = EncodeStateTuple(type, key);
|
||||
Free(HashMapDelete(state->table, tableKey));
|
||||
if (event)
|
||||
{
|
||||
HashMapSet(state, full_string, StrDuplicate(event));
|
||||
HashMapSet(state->table, tableKey, StrDuplicate(event));
|
||||
}
|
||||
Free(full_string);
|
||||
Free(tableKey);
|
||||
}
|
||||
void
|
||||
StateFree(HashMap *state)
|
||||
StateFree(State *state)
|
||||
{
|
||||
char *full;
|
||||
char *event_id;
|
||||
char *tuple;
|
||||
char *eventID;
|
||||
|
||||
if (!state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (HashMapIterate(state, &full, (void **) &event_id))
|
||||
|
||||
while (HashMapIterate(state->table, &tuple, (void **) &eventID))
|
||||
{
|
||||
Free(event_id);
|
||||
Free(eventID);
|
||||
}
|
||||
HashMapFree(state);
|
||||
HashMapFree(state->table);
|
||||
Free(state);
|
||||
}
|
||||
HashMap *
|
||||
State *
|
||||
StateDeserialise(HashMap *json_state)
|
||||
{
|
||||
HashMap *raw_state;
|
||||
State *raw_state;
|
||||
|
||||
char *state_type;
|
||||
JsonValue *state_keys;
|
||||
|
@ -473,7 +549,7 @@ StateDeserialise(HashMap *json_state)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
raw_state = HashMapCreate();
|
||||
raw_state = InitialiseState();
|
||||
|
||||
while (HashMapIterate(json_state, &state_type, (void **) &state_keys))
|
||||
{
|
||||
|
@ -484,18 +560,15 @@ StateDeserialise(HashMap *json_state)
|
|||
while (HashMapIterate(state_keys_obj, &state_key, (void **) &event_id))
|
||||
{
|
||||
char *eid_string = JsonValueAsString(event_id);
|
||||
char *key_name = StrConcat(3, state_type, ",", state_key);
|
||||
|
||||
HashMapSet(raw_state, key_name, StrDuplicate(eid_string));
|
||||
|
||||
Free(key_name);
|
||||
StateSet(raw_state, state_type, state_key, eid_string);
|
||||
}
|
||||
}
|
||||
|
||||
return raw_state;
|
||||
}
|
||||
HashMap *
|
||||
StateSerialise(HashMap *rawState)
|
||||
StateSerialise(State *rawState)
|
||||
{
|
||||
HashMap *returned;
|
||||
char *type, *key, *event;
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
*/
|
||||
typedef struct Room Room;
|
||||
|
||||
#include <State.h>
|
||||
|
||||
/**
|
||||
* Create a new room in the given database using the given
|
||||
* RoomCreateRequest.
|
||||
|
@ -104,14 +106,14 @@ extern int RoomVersionGet(Room *);
|
|||
* which is used to select auth events on incoming
|
||||
* client events.
|
||||
*/
|
||||
extern HashMap * RoomStateGet(Room *);
|
||||
extern State * RoomStateGet(Room *);
|
||||
/**
|
||||
* Resolves the room's state before a specific point,
|
||||
* (with the event hashmap taking priority),
|
||||
* like
|
||||
* .Fn RoomStateGet .
|
||||
*/
|
||||
extern HashMap * RoomStateGetID(Room *, char *);
|
||||
extern State * RoomStateGetID(Room *, char *);
|
||||
|
||||
/**
|
||||
* Get a list of the most recent events in the
|
||||
|
@ -168,7 +170,7 @@ extern HashMap * RoomEventClientify(HashMap *);
|
|||
* Verifies whenever an event(as a PDUv1) is
|
||||
* authorised by a room.
|
||||
*/
|
||||
extern bool RoomAuthoriseEventV1(Room *, PduV1, HashMap *);
|
||||
extern bool RoomAuthoriseEventV1(Room *, PduV1, State *);
|
||||
|
||||
/**
|
||||
* Gets the room's creator as a ServerPart. This value should
|
||||
|
|
|
@ -37,17 +37,22 @@
|
|||
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
|
||||
/**
|
||||
* An opaque structure to hold information about the state.
|
||||
*/
|
||||
typedef struct State State;
|
||||
|
||||
#include <Room.h>
|
||||
|
||||
/**
|
||||
* Retrieve the value of a state tuple.
|
||||
*/
|
||||
extern char *StateGet(HashMap *, char *, char *);
|
||||
extern char *StateGet(State *, char *, char *);
|
||||
|
||||
/**
|
||||
* Set a state tuple to a value.
|
||||
*/
|
||||
extern void StateSet(HashMap *, char *, char *, char *);
|
||||
extern void StateSet(State *, char *, char *, char *);
|
||||
|
||||
/**
|
||||
* Iterates through a statemap, with (type, key) -> event.
|
||||
|
@ -56,22 +61,22 @@ extern void StateSet(HashMap *, char *, char *, char *);
|
|||
* This function behaves like
|
||||
* .Fn HashMapIterate .
|
||||
*/
|
||||
extern bool StateIterate(HashMap *, char **, char **, void **);
|
||||
extern bool StateIterate(State *, char **, char **, void **);
|
||||
|
||||
/**
|
||||
* Compute the room state before the specified event was sent.
|
||||
*/
|
||||
extern HashMap * StateResolve(Room *, HashMap *);
|
||||
extern State * StateResolve(Room *, HashMap *);
|
||||
|
||||
/**
|
||||
* Computes the current state from the room's leaves.
|
||||
*/
|
||||
extern HashMap * StateCurrent(Room *);
|
||||
extern State * StateCurrent(Room *);
|
||||
|
||||
/**
|
||||
* Frees an entire state table from the heap.
|
||||
*/
|
||||
extern void StateFree(HashMap *);
|
||||
extern void StateFree(State *);
|
||||
|
||||
/**
|
||||
* Deserialises a state map from JSON to the internal format
|
||||
|
@ -81,11 +86,11 @@ extern void StateFree(HashMap *);
|
|||
* and should be freed with
|
||||
* .Fn StateFree .
|
||||
*/
|
||||
extern HashMap * StateDeserialise(HashMap *);
|
||||
extern State * StateDeserialise(HashMap *);
|
||||
/**
|
||||
* Serialises a state map from the internal format to JSON
|
||||
* used for the database, for example
|
||||
*/
|
||||
extern HashMap * StateSerialise(HashMap *);
|
||||
extern HashMap * StateSerialise(State *);
|
||||
|
||||
#endif /* TELODENDRIA_STATE_H */
|
||||
|
|
Loading…
Reference in a new issue