Merge branch 'dev' of https://git.4nkweb.com/4nk/ihm_client into dev
All checks were successful
Build and Push to Registry / build-and-push (push) Successful in 2m4s
All checks were successful
Build and Push to Registry / build-and-push (push) Successful in 2m4s
This commit is contained in:
commit
e4681f91e4
@ -208,12 +208,48 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async checkConnections(members: Member[]): Promise<void> {
|
// If we're updating a process, we must call that after update especially if roles are part of it
|
||||||
|
// We will take the roles from the last state, wheter it's commited or not
|
||||||
|
public async checkConnections(process: Process): Promise<void> {
|
||||||
|
if (process.states.length < 2) {
|
||||||
|
throw new Error('Process doesn\'t have any state yet');
|
||||||
|
}
|
||||||
|
let roles = process.states[process.states.length - 2].roles;
|
||||||
|
if (!roles) {
|
||||||
|
throw new Error('No roles found');
|
||||||
|
} else {
|
||||||
|
console.log('roles found', roles);
|
||||||
|
}
|
||||||
|
let members: Set<Member> = new Set();
|
||||||
|
for (const role of Object.values(roles!)) {
|
||||||
|
for (const member of role.members) {
|
||||||
|
// Check if we know the member that matches this id
|
||||||
|
const memberAddresses = this.getAddressesForMemberId(member);
|
||||||
|
if (memberAddresses && memberAddresses.length != 0) {
|
||||||
|
members.add({ sp_addresses: memberAddresses });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (members.size === 0) {
|
||||||
|
// This must be a pairing process
|
||||||
|
// Check if we have a pairedAddresses in the public data
|
||||||
|
const publicData = process.states[0]?.public_data;
|
||||||
|
if (!publicData || !publicData['pairedAddresses']) {
|
||||||
|
throw new Error('Not a pairing process');
|
||||||
|
}
|
||||||
|
const decodedAddresses = this.decodeValue(publicData['pairedAddresses']);
|
||||||
|
if (decodedAddresses.length === 0) {
|
||||||
|
throw new Error('Not a pairing process');
|
||||||
|
}
|
||||||
|
members.add({ sp_addresses: decodedAddresses });
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the amount is available before proceeding
|
// Ensure the amount is available before proceeding
|
||||||
await this.getTokensFromFaucet();
|
await this.getTokensFromFaucet();
|
||||||
let unconnectedAddresses: Set<string> = new Set();
|
let unconnectedAddresses = new Set<string>();
|
||||||
const myAddress = this.getDeviceAddress();
|
const myAddress = this.getDeviceAddress();
|
||||||
for (const member of members) {
|
for (const member of Array.from(members)) {
|
||||||
const sp_addresses = member.sp_addresses;
|
const sp_addresses = member.sp_addresses;
|
||||||
if (!sp_addresses || sp_addresses.length === 0) continue;
|
if (!sp_addresses || sp_addresses.length === 0) continue;
|
||||||
for (const address of sp_addresses) {
|
for (const address of sp_addresses) {
|
||||||
@ -226,7 +262,7 @@ export default class Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unconnectedAddresses && unconnectedAddresses.size != 0) {
|
if (unconnectedAddresses && unconnectedAddresses.size != 0) {
|
||||||
const apiResult = await this.connectAddresses([...unconnectedAddresses]);
|
const apiResult = await this.connectAddresses(Array.from(unconnectedAddresses));
|
||||||
await this.handleApiReturn(apiResult);
|
await this.handleApiReturn(apiResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,19 +410,6 @@ export default class Services {
|
|||||||
console.log('encoded data:', encodedPrivateData);
|
console.log('encoded data:', encodedPrivateData);
|
||||||
console.log('encoded data:', encodedPublicData);
|
console.log('encoded data:', encodedPublicData);
|
||||||
|
|
||||||
let members: Set<Member> = new Set();
|
|
||||||
for (const role of Object.values(roles!)) {
|
|
||||||
for (const member of role.members) {
|
|
||||||
// Check if we know the member that matches this id
|
|
||||||
const memberAddresses = this.getAddressesForMemberId(member);
|
|
||||||
if (memberAddresses && memberAddresses.length != 0) {
|
|
||||||
members.add({ sp_addresses: memberAddresses });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log('members:', members);
|
|
||||||
await this.checkConnections([...members]);
|
|
||||||
|
|
||||||
const result = this.sdkClient.create_new_process (
|
const result = this.sdkClient.create_new_process (
|
||||||
encodedPrivateData,
|
encodedPrivateData,
|
||||||
roles,
|
roles,
|
||||||
@ -396,7 +419,12 @@ export default class Services {
|
|||||||
this.getAllMembers()
|
this.getAllMembers()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (result.updated_process) {
|
||||||
|
await this.checkConnections(result.updated_process);
|
||||||
return(result);
|
return(result);
|
||||||
|
} else {
|
||||||
|
throw new Error('Empty updated_process in createProcessReturn');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProcess(process: Process, privateData: Record<string, any>, publicData: Record<string, any>, roles: Record<string, RoleDefinition> | null): Promise<ApiReturn> {
|
public async updateProcess(process: Process, privateData: Record<string, any>, publicData: Record<string, any>, roles: Record<string, RoleDefinition> | null): Promise<ApiReturn> {
|
||||||
@ -407,26 +435,6 @@ export default class Services {
|
|||||||
// We should check that we have the right to change the roles here, or maybe it's better leave it to the wasm
|
// We should check that we have the right to change the roles here, or maybe it's better leave it to the wasm
|
||||||
console.log('Provided new roles:', JSON.stringify(roles));
|
console.log('Provided new roles:', JSON.stringify(roles));
|
||||||
}
|
}
|
||||||
let members: Set<Member> = new Set();
|
|
||||||
for (const role of Object.values(roles!)) {
|
|
||||||
for (const member of role.members) {
|
|
||||||
members.add(member)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (members.size === 0) {
|
|
||||||
// This must be a pairing process
|
|
||||||
// Check if we have a pairedAddresses in the public data
|
|
||||||
const publicData = this.getPublicData(process);
|
|
||||||
if (!publicData || !publicData['pairedAddresses']) {
|
|
||||||
throw new Error('Not a pairing process');
|
|
||||||
}
|
|
||||||
const decodedAddresses = this.decodeValue(publicData['pairedAddresses']);
|
|
||||||
if (decodedAddresses.length === 0) {
|
|
||||||
throw new Error('Not a pairing process');
|
|
||||||
}
|
|
||||||
members.add({ sp_addresses: decodedAddresses });
|
|
||||||
}
|
|
||||||
await this.checkConnections([...members]);
|
|
||||||
const privateSplitData = this.splitData(privateData);
|
const privateSplitData = this.splitData(privateData);
|
||||||
const publicSplitData = this.splitData(publicData);
|
const publicSplitData = this.splitData(publicData);
|
||||||
const encodedPrivateData = {
|
const encodedPrivateData = {
|
||||||
@ -438,7 +446,13 @@ export default class Services {
|
|||||||
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
...this.sdkClient.encode_binary(publicSplitData.binaryData)
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.update_process(process, encodedPrivateData, roles, encodedPublicData, this.getAllMembers());
|
const result = this.sdkClient.update_process(process, encodedPrivateData, roles, encodedPublicData, this.getAllMembers());
|
||||||
|
if (result.updated_process) {
|
||||||
|
await this.checkConnections(result.updated_process);
|
||||||
|
return(result);
|
||||||
|
} else {
|
||||||
|
throw new Error('Empty updated_process in updateProcessReturn');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Failed to update process: ${e}`);
|
throw new Error(`Failed to update process: ${e}`);
|
||||||
}
|
}
|
||||||
@ -450,7 +464,13 @@ export default class Services {
|
|||||||
throw new Error('Unknown process');
|
throw new Error('Unknown process');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.create_update_message(process, stateId, this.getAllMembers());
|
const result = this.sdkClient.create_update_message(process, stateId, this.getAllMembers());
|
||||||
|
if (result.updated_process) {
|
||||||
|
await this.checkConnections(result.updated_process);
|
||||||
|
return(result);
|
||||||
|
} else {
|
||||||
|
throw new Error('Empty updated_process in createPrdUpdateReturn');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Failed to create prd update: ${e}`);
|
throw new Error(`Failed to create prd update: ${e}`);
|
||||||
}
|
}
|
||||||
@ -474,7 +494,13 @@ export default class Services {
|
|||||||
throw new Error('Failed to get process from db');
|
throw new Error('Failed to get process from db');
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return this.sdkClient.validate_state(process, stateId, this.getAllMembers());
|
const result = this.sdkClient.validate_state(process, stateId, this.getAllMembers());
|
||||||
|
if (result.updated_process) {
|
||||||
|
await this.checkConnections(result.updated_process);
|
||||||
|
return(result);
|
||||||
|
} else {
|
||||||
|
throw new Error('Empty updated_process in approveChangeReturn');
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Failed to create prd response: ${e}`);
|
throw new Error(`Failed to create prd response: ${e}`);
|
||||||
}
|
}
|
||||||
@ -1215,6 +1241,7 @@ export default class Services {
|
|||||||
|
|
||||||
if (!hasAccess) return null;
|
if (!hasAccess) return null;
|
||||||
|
|
||||||
|
await this.checkConnections((await this.getProcess(processId))!);
|
||||||
// We should have the key, so we're going to ask other members for it
|
// We should have the key, so we're going to ask other members for it
|
||||||
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
await this.requestDataFromPeers(processId, [state.state_id], [state.roles]);
|
||||||
|
|
||||||
@ -1378,8 +1405,8 @@ export default class Services {
|
|||||||
const existing = await this.getProcess(processId);
|
const existing = await this.getProcess(processId);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// Look for state id we don't know yet
|
// Look for state id we don't know yet
|
||||||
let new_states = [];
|
let newStates: string[] = [];
|
||||||
let roles = [];
|
let newRoles: Record<string, RoleDefinition>[] = [];
|
||||||
for (const state of process.states) {
|
for (const state of process.states) {
|
||||||
if (!state || !state.state_id) { continue; } // shouldn't happen
|
if (!state || !state.state_id) { continue; } // shouldn't happen
|
||||||
if (state.state_id === EMPTY32BYTES) {
|
if (state.state_id === EMPTY32BYTES) {
|
||||||
@ -1387,63 +1414,66 @@ export default class Services {
|
|||||||
const existingTip = existing.states[existing.states.length - 1].commited_in;
|
const existingTip = existing.states[existing.states.length - 1].commited_in;
|
||||||
if (existingTip !== state.commited_in) {
|
if (existingTip !== state.commited_in) {
|
||||||
console.log('Found new tip for process', processId);
|
console.log('Found new tip for process', processId);
|
||||||
// We update the process
|
existing.states.pop(); // We discard the last state
|
||||||
new_states.push(state.state_id);
|
existing.states.push(state);
|
||||||
roles.push(state.roles);
|
// We know that's the last state, so we just trigger the update
|
||||||
|
toSave[processId] = existing;
|
||||||
}
|
}
|
||||||
} else if (!this.lookForStateId(existing, state.state_id)) {
|
} else if (!this.lookForStateId(existing, state.state_id)) {
|
||||||
|
// We don't want to overwrite what we already have for existing processes
|
||||||
|
// We may end up overwriting the keys for example
|
||||||
|
// So the process we're going to save needs to merge new states with what we already have
|
||||||
|
const existingLastState = existing.states.pop();
|
||||||
|
if (!existingLastState) {
|
||||||
|
// This should never happen
|
||||||
|
console.error('Failed to get last state for process', processId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
existing.states.push(state);
|
||||||
|
existing.states.push(existingLastState);
|
||||||
|
toSave[processId] = existing; // We mark it for update
|
||||||
if (this.rolesContainsUs(state.roles)) {
|
if (this.rolesContainsUs(state.roles)) {
|
||||||
new_states.push(state.state_id);
|
newStates.push(state.state_id);
|
||||||
roles.push(state.roles);
|
newRoles.push(state.roles);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We already have the state, but we check if we have the keys
|
||||||
|
const existingState = this.getStateFromId(existing, state.state_id);
|
||||||
|
if (existingState!.keys && Object.keys(existingState!.keys).length != 0) {
|
||||||
|
// We have some keys, so we just assume everything ok and move on for now
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// We verify we are part of the roles
|
||||||
|
const roles = state.roles;
|
||||||
|
if (this.rolesContainsUs(roles)) {
|
||||||
|
// We don't have keys, but we are part of the roles, so we need to request the keys
|
||||||
|
// that may also be because we are part of a role that don't have any fields
|
||||||
|
// It's possible but let's request for nothing anyway
|
||||||
|
newStates.push(state.state_id);
|
||||||
|
newRoles.push(roles);
|
||||||
|
} else {
|
||||||
|
// We are simply not involved, move on
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_states.length != 0) {
|
if (newStates.length != 0) {
|
||||||
// We request the new states
|
await this.requestDataFromPeers(processId, newStates, newRoles);
|
||||||
// filter out the empty state, if any
|
|
||||||
// empty state will always be last, so that's easy
|
|
||||||
if (new_states.findLast(state => state === EMPTY32BYTES)) {
|
|
||||||
new_states.pop();
|
|
||||||
roles.pop();
|
|
||||||
}
|
}
|
||||||
await this.requestDataFromPeers(processId, new_states, roles);
|
|
||||||
toSave[processId] = process;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just to be sure check if that's a pairing process
|
|
||||||
const lastCommitedState = this.getLastCommitedState(process);
|
|
||||||
if (lastCommitedState && lastCommitedState.public_data && lastCommitedState.public_data['pairedAddresses']) {
|
|
||||||
// This is a pairing process
|
|
||||||
try {
|
|
||||||
const pairedAddresses = this.decodeValue(lastCommitedState.public_data['pairedAddresses']);
|
|
||||||
// Are we part of it?
|
|
||||||
if (pairedAddresses && pairedAddresses.length > 0 && pairedAddresses.includes(this.getDeviceAddress())) {
|
|
||||||
// We save the process to db
|
|
||||||
await this.saveProcessToDb(processId, process as Process);
|
|
||||||
// We update the device
|
|
||||||
await this.updateDevice();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to check for pairing process:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we're probably just in the initial loading at page initialization
|
// Otherwise we're probably just in the initial loading at page initialization
|
||||||
|
|
||||||
// We may learn an update for this process
|
|
||||||
// TODO maybe actually check if what the relay is sending us contains more information than what we have
|
|
||||||
// relay should always have more info than us, but we never know
|
|
||||||
// For now let's keep it simple and let the worker do the job
|
|
||||||
} else {
|
} else {
|
||||||
// We add it to db
|
// We add it to db
|
||||||
console.log(`Saving ${processId} to db`);
|
|
||||||
toSave[processId] = process;
|
toSave[processId] = process;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toSave && Object.keys(toSave).length > 0) {
|
||||||
|
console.log('batch saving processes to db', toSave);
|
||||||
await this.batchSaveProcessesToDb(toSave);
|
await this.batchSaveProcessesToDb(toSave);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to parse init message:', e);
|
console.error('Failed to parse init message:', e);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user