8 Commits

4 changed files with 117 additions and 9 deletions

View File

@@ -1,2 +1,24 @@
## 1.0.3
### Bugfixes
- `executeFor` functions will no longer fail with an exception if a function scheduled to be called by the local user throws.
## 1.0.2
### New API endpoints
- Added `executeForOthers` and `executeForOtherGMs` that execute for all users/all GMs except the local client.
### Bugfixes
- `executeAsUser` and `executeForUsers` didn't execute locally if the id of the current user was passed in as recipient.
- `executeForEveryone` and `executeForAllGMs` now execute locally as well, as they should
## 1.0.1
### New features
- Added support for game systems
### Compatibility
- Add support for Foundry 0.8.1
## 1.0.0 ## 1.0.0
### Initial release ### Initial release

View File

@@ -64,6 +64,17 @@ Call `registerModule` to make socketlib listen for sockets that come in for your
**Return value**: A socket instance is returned, that is used for all further interactions with socketlib. **Return value**: A socket instance is returned, that is used for all further interactions with socketlib.
#### socketlib.registerSystem
```javascript
registerSystem(systemId);
```
Call `registerSystem` to make socketlib listen for sockets that come in for your game system. This is the first function in socketlib that your game system should call.
- **systemId** the id of your game system as specified in your game system's manifest.
**Return value**: A socket instance is returned, that is used for all further interactions with socketlib.
#### socket.register #### socket.register
```javascript ```javascript
socket.register(name, func); socket.register(name, func);
@@ -106,7 +117,19 @@ Executes a function on the client of the specified user. This function will fail
async socket.executeForAllGMs(handler, parameters...); async socket.executeForAllGMs(handler, parameters...);
``` ```
Executes a function on the clients of all connected GMs. Executes a function on the clients of all connected GMs. If the current user is a GM the function will be executed locally as well.
- **handler** can either be the function that should be executed or the name given to that function during registration.
- **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call.
**Return value**: The promise returned by this function will resolve as soon as the request for execution has been sent to the connected GM clients and *will not* wait until those clients have finished processing that function. The promise will not yield any return value.
#### socket.executeForOtherGMs
```javascript
async socket.executeForOtherGMs(handler, parameters...);
```
Executes a function on the clients of all connected GMs, except for the current user. If the current user is not a GM this function has the same behavior as [`socket.executeForAllGMs`](#socketexecuteasgm).
- **handler** can either be the function that should be executed or the name given to that function during registration. - **handler** can either be the function that should be executed or the name given to that function during registration.
- **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call. - **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call.
@@ -118,7 +141,19 @@ Executes a function on the clients of all connected GMs.
async socket.executeForEveryone(handler, ...args); async socket.executeForEveryone(handler, ...args);
``` ```
Executes a function on all connected clients. Executes a function on all connected clients, including on the local client.
- **handler** can either be the function that should be executed or the name given to that function during registration.
- **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call.
**Return value**: The promise returned by this function will resolve as soon as the request for execution has been sent to the connected clients and *will not* wait until those clients have finished processing that function. The promise will not yield any return value.
#### socket.executeForOthers
```javascript
async socket.executeForOthers(handler, ...args);
```
Executes a function on all connected clients, but not locally.
- **handler** can either be the function that should be executed or the name given to that function during registration. - **handler** can either be the function that should be executed or the name given to that function during registration.
- **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call. - **parameters...** the parameters that should be passed to the called function. Pass the parameters in comma separated, as you would do for a regular function call.

View File

@@ -2,9 +2,9 @@
"name": "socketlib", "name": "socketlib",
"title": "socketlib", "title": "socketlib",
"description": "A library for easier handling of foundry sockets", "description": "A library for easier handling of foundry sockets",
"version": "1.0.0", "version": "1.0.3",
"minimumCoreVersion" : "0.7.9", "minimumCoreVersion" : "0.7.9",
"compatibleCoreVersion" : "0.7.9", "compatibleCoreVersion" : "0.8.1",
"library": true, "library": true,
"authors": [ "authors": [
{ {
@@ -17,7 +17,7 @@
"src/socketlib.js" "src/socketlib.js"
], ],
"url": "https://github.com/manuelVo/foundryvtt-socketlib", "url": "https://github.com/manuelVo/foundryvtt-socketlib",
"download": "https://github.com/manuelVo/foundryvtt-socketlib/archive/v1.0.0.zip", "download": "https://github.com/manuelVo/foundryvtt-socketlib/archive/v1.0.3.zip",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-socketlib/master/module.json", "manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-socketlib/master/module.json",
"readme": "https://github.com/manuelVo/foundryvtt-socketlib/blob/master/README.md", "readme": "https://github.com/manuelVo/foundryvtt-socketlib/blob/master/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-socketlib/blob/master/CHANGELOG.md", "changelog": "https://github.com/manuelVo/foundryvtt-socketlib/blob/master/CHANGELOG.md",

View File

@@ -39,17 +39,32 @@ class Socketlib {
console.error(`socketlib | Failed to register socket for module '${moduleName}'. Please set '"socket":true' in your manifset and restart foundry (you need to reload your world - simply reloading your browser won't do).`); console.error(`socketlib | Failed to register socket for module '${moduleName}'. Please set '"socket":true' in your manifset and restart foundry (you need to reload your world - simply reloading your browser won't do).`);
return undefined; return undefined;
} }
const newSocket = new SocketlibSocket(moduleName); const newSocket = new SocketlibSocket(moduleName, "module");
this.modules.set(moduleName, newSocket); this.modules.set(moduleName, newSocket);
return newSocket; return newSocket;
} }
registerSystem(systemId) {
if (game.system.id !== systemId) {
console.error(`socketlib | Someone tried to register system '${systemId}', but that system isn't active. As a result the registration request has been ignored.`);
return undefined;
}
const existingSocket = this.system;
if (existingSocket)
return existingSocket;
if (!game.system.data.socket) {
console.error(`socketlib | Failed to register socket for system '${systemId}'. Please set '"socket":true' in your manifest and restart foundry (you need to reload your world - simply reloading your browser won't do).`);
}
const newSocket = new SocketlibSocket(systemId, "system");
this.system = newSocket;
return newSocket;
}
} }
class SocketlibSocket { class SocketlibSocket {
constructor(moduleName) { constructor(moduleName, moduleType) {
this.moduleName = moduleName;
this.functions = new Map(); this.functions = new Map();
this.socketName = `module.${moduleName}`; this.socketName = `${moduleType}.${moduleName}`;
this.pendingRequests = new Map(); this.pendingRequests = new Map();
game.socket.on(this.socketName, this._onSocketReceived.bind(this)); game.socket.on(this.socketName, this._onSocketReceived.bind(this));
} }
@@ -81,6 +96,8 @@ class SocketlibSocket {
async executeAsUser(handler, userId, ...args) { async executeAsUser(handler, userId, ...args) {
const [name, func] = this._resolveFunction(handler); const [name, func] = this._resolveFunction(handler);
if (userId === game.userId)
return func(...args);
const user = game.users.get(userId); const user = game.users.get(userId);
if (!user) if (!user)
throw new SocketlibInvalidUserError(`No user with id '${userId}' exists.`); throw new SocketlibInvalidUserError(`No user with id '${userId}' exists.`);
@@ -92,18 +109,52 @@ class SocketlibSocket {
async executeForAllGMs(handler, ...args) { async executeForAllGMs(handler, ...args) {
const [name, func] = this._resolveFunction(handler); const [name, func] = this._resolveFunction(handler);
this._sendCommand(name, args, RECIPIENT_TYPES.ALL_GMS); this._sendCommand(name, args, RECIPIENT_TYPES.ALL_GMS);
if (game.user.isGM) {
try {
func(...args);
}
catch (e) {
console.error(e);
}
}
}
async executeForOtherGMs(handler, ...args) {
const [name, func] = this._resolveFunction(handler);
this._sendCommand(name, args, RECIPIENT_TYPES.ALL_GMS);
} }
async executeForEveryone(handler, ...args) { async executeForEveryone(handler, ...args) {
const [name, func] = this._resolveFunction(handler); const [name, func] = this._resolveFunction(handler);
this._sendCommand(name, args, RECIPIENT_TYPES.EVERYONE); this._sendCommand(name, args, RECIPIENT_TYPES.EVERYONE);
try {
func(...args);
} catch (e) {
console.error(e);
}
}
async executeForOthers(handler, ...args) {
const [name, func] = this._resolveFunction(handler);
this._sendCommand(name, args, RECIPIENT_TYPES.EVERYONE);
} }
async executeForUsers(handler, recipients, ...args) { async executeForUsers(handler, recipients, ...args) {
if (!(recipients instanceof Array)) if (!(recipients instanceof Array))
throw new TypeError("Recipients parameter must be an array of user ids."); throw new TypeError("Recipients parameter must be an array of user ids.");
const [name, func] = this._resolveFunction(handler); const [name, func] = this._resolveFunction(handler);
const currentUserIndex = recipients.indexOf(game.userId);
if (currentUserIndex >= 0)
recipients.splice(currentUserIndex, 1);
this._sendCommand(name, args, recipients); this._sendCommand(name, args, recipients);
if (currentUserIndex >= 0) {
try {
func(...args);
}
catch (e) {
console.error(e);
}
}
} }
_sendRequest(handlerName, args, recipient) { _sendRequest(handlerName, args, recipient) {