Skip to content

Commit

Permalink
Feat: updateStorageArray method for simultaneous array updates
Browse files Browse the repository at this point in the history
  • Loading branch information
therealPaulPlay committed Jan 25, 2025
1 parent f92c45e commit 52097e1
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 9 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ const hostId = await peer.createRoom({
// Or, join room
await peer.joinRoom('host-peer-id'); // Rejects if connection fails or times out
const currentState = peer.getStorage;
peer.updateStorage('players', [...(currentState.players || []), newPlayer]);
peer.updateStorageArray('players', 'add', { username: 'PeerEnjoyer4', level: 2 }); // Special method to enable simultaneous storage updates for arrays
peer.updateStorage('latestPlayer', 'PeerEnjoyer4'); // Regular synced storage update

// To leave the room, destroy the instance
peer.destroy();
Expand Down Expand Up @@ -80,6 +81,7 @@ Creates a new PlayPeer instance with a specified peer ID and [PeerJS options](ht
#### State Management

- `updateStorage(key: string, value: any)`: Update a value in the synchronized storage
- `updateStorageArray(key: string, operation: 'add' | 'remove-matching' | 'update-matching', value: any, updateValue?: any)`: Safely update arrays in storage by adding, removing, or updating items. This is necessary for when array updates might be happening simultanously to ensure changes are being applied and not overwritten.
- `onEvent(event: string, callback: Function)`: Register an event callback

##### Event types
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "playpeerjs",
"version": "1.0.9",
"version": "1.1.0",
"description": "WebRTC-based wrapper for creating robust peer-2-peer multiplayer systems with ease.",
"type": "module",
"main": "dist/playpeer.js",
Expand Down
9 changes: 2 additions & 7 deletions src/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,10 @@
const currentStorage = peer.getStorage;
const newMessage = {
sender: peer.id,
text: text,
time: Date.now()
text: text
};

peer.updateStorage('messages', [
...(currentStorage.messages || []),
newMessage
]);

peer.updateStorageArray('messages', 'add', newMessage);
input.value = '';
}

Expand Down
86 changes: 86 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ export default class PlayPeer {
}
break;
}
case 'array_update': {
// Perform array updates on host to avoid race conditions
this.#handleArrayUpdate(data.key, data.operation, data.value, data.updateValue);
this.#broadcastMessage("storage_sync", { storage: this.#storage });
break;
}
}
});

Expand Down Expand Up @@ -403,6 +409,86 @@ export default class PlayPeer {
this.#triggerEvent("storageUpdate", this.#storage);
}

/**
* Handle dynamic array update
* @private
* @param {string} key
* @param {string} operation
* @param {*} value
* @param {*} updateValue
*/
#handleArrayUpdate(key, operation, value, updateValue) {
const updatedArray = this.#storage?.[key] || [];
if (!Array.isArray(this.#storage?.[key])) {
this.#storage[key] = []; // Ensure it's an array if it wasn't already
}

switch (operation) {
case 'add':
this.#storage[key].push(value);
break;

case 'remove-matching':
// Remove matching value (deep comparison for objects)
this.#storage[key] = updatedArray.filter(item => {
if (typeof value === 'object' && value !== null) {
return JSON.stringify(item) !== JSON.stringify(value);
}
return item !== value; // Strict equality for primitives
});
break;

case 'update-matching':
// Find and update the matching value (deep comparison for objects)
const updateIndex = updatedArray.findIndex(item => {
if (typeof value === 'object' && value !== null) {
return JSON.stringify(item) === JSON.stringify(value);
}
return item === value; // Strict equality for primitives
});

if (updateIndex > -1) {
this.#storage[key][updateIndex] = updateValue; // Perform the update
}
break;

default:
console.error(ERROR_PREFIX + `Unknown array operation: ${operation}`);
this.#triggerEvent("error", `Unknown array operation: ${operation}`);
}

this.#setStorageLocally(key, this.#storage[key]); // Update storage locally
}

/**
* Safely update an array from a storage key
* @param {string} key
* @param {string} operation
* @param {*} value
* @param {* | undefined} updateValue
*/
updateStorageArray(key, operation, value, updateValue) {
if (this.#isHost) {
this.#handleArrayUpdate(key, operation, value, updateValue);
this.#broadcastMessage("storage_sync", { storage: this.#storage });
} else {
try {
// Request the host to perform the operation
this.#outgoingConnection?.send({
type: 'array_update',
key,
operation,
value,
updateValue
});
this.#handleArrayUpdate(key, operation, value, updateValue); // Optimistc update
} catch (error) {
console.error(ERROR_PREFIX + `Failed to send array update to host:`, error);
this.#triggerEvent("error", `Failed to send array update to host: ${error}`);
}
}
}

/**
* Broadcast a message of a specific type to all peers. Used by host only
* @private
Expand Down

0 comments on commit 52097e1

Please sign in to comment.