generated from theripper93/FoundryVTT-Module-Template
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3c8de70
commit 6d7220c
Showing
11 changed files
with
353 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
MANIFEST-000333 | ||
MANIFEST-000353 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
2024/06/08-19:50:40.390 3f58 Recovering log #331 | ||
2024/06/08-19:50:40.394 3f58 Delete type=0 #331 | ||
2024/06/08-19:50:40.395 3f58 Delete type=3 #329 | ||
2024/06/27-22:45:40.343 4928 Recovering log #352 | ||
2024/06/27-22:45:40.346 4928 Delete type=0 #352 | ||
2024/06/27-22:45:40.346 4928 Delete type=3 #351 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,3 @@ | ||
2024/05/30-14:14:05.946 4760 Recovering log #328 | ||
2024/05/30-14:14:05.949 4760 Delete type=0 #328 | ||
2024/05/30-14:14:05.949 4760 Delete type=3 #327 | ||
2024/05/30-14:24:29.343 6724 Level-0 table #332: started | ||
2024/05/30-14:24:29.343 6724 Level-0 table #332: 0 bytes OK | ||
2024/05/30-14:24:29.345 6724 Delete type=0 #330 | ||
2024/05/30-14:24:29.345 6724 Manual compaction at level-0 from '!macros!LD5Wc6K0vLQw0att' @ 72057594037927935 : 1 .. '!macros!iWwnlmoMWqNGJ54U' @ 0 : 0; will stop at (end) | ||
2024/05/30-14:24:29.345 6724 Manual compaction at level-1 from '!macros!LD5Wc6K0vLQw0att' @ 72057594037927935 : 1 .. '!macros!iWwnlmoMWqNGJ54U' @ 0 : 0; will stop at (end) | ||
2024/06/27-22:41:50.291 68d4 Recovering log #349 | ||
2024/06/27-22:41:50.295 68d4 Delete type=0 #349 | ||
2024/06/27-22:41:50.295 68d4 Delete type=3 #347 |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
import { MODULE_ID } from "../main.js"; | ||
|
||
export class Socket { | ||
static __$callbacks = {}; | ||
|
||
static __$stores = {}; | ||
|
||
static __$promises = {}; | ||
|
||
static USERS = { | ||
GMS: "gms", | ||
PLAYERS: "players", | ||
ALL: "all", | ||
OTHERS: "others", | ||
FIRSTGM: "firstGM", | ||
SELF: "self", | ||
}; | ||
|
||
static __$reserved = ["__$eventName", "__$response", "__$onMessage", "__$parseUsers", "register", "USERS"]; | ||
|
||
static async __$onMessage(data) { | ||
const options = data.__$socketOptions; | ||
|
||
if (options.__$storeName) { | ||
if (options.__$request) { | ||
const store = this.__$stores[options.__$storeName]; | ||
const _isLive = store._isLive; | ||
if (!_isLive) return; | ||
game.socket.emit(`module.${MODULE_ID}`, { __$socketOptions: { __$storeName: options.__$storeName, user: game.user.id }, data: store.getData() }); | ||
} else { | ||
this.__$stores[options.__$storeName].synchronize(data.data, game.users.get(options.user)); | ||
} | ||
return; | ||
} | ||
|
||
if (options.__$eventName === "__$response") { | ||
const key = options.__$responseKey; | ||
if (this.__$promises[key]) { | ||
this.__$promises[key].resolve({ user: game.users.get(options.__$userId), response: data.result }); | ||
delete this.__$promises[key]; | ||
} | ||
return; | ||
} | ||
if (!options.users.includes(game.user.id)) return; | ||
const callback = this.__$callbacks[options.__$eventName]; | ||
delete data.__$socketOptions; | ||
const result = await callback(data); | ||
if (options.response) { | ||
const key = `${options.__$eventId}.${game.user.id}`; | ||
const data = { __$socketOptions: { __$eventName: "__$response", __$responseKey: key, __$userId: game.user.id }, result }; | ||
this.__$socket.emit(`module.${MODULE_ID}`, data); | ||
} | ||
} | ||
|
||
static __$parseUsers(options) { | ||
if (Array.isArray(options?.users)) return options; | ||
if (typeof options === "string") options = { users: options }; | ||
if (Array.isArray(options)) options = { users: options }; | ||
options.users = options.users || this.USERS.ALL; | ||
const active = game.users.filter((u) => u.active); | ||
const users = options.users; | ||
if (users === this.USERS.ALL) { | ||
options.users = active.map((u) => u.id); | ||
} else if (users === this.USERS.GMS) { | ||
options.users = active.filter((u) => u.isGM).map((u) => u.id); | ||
} else if (users === this.USERS.PLAYERS) { | ||
options.users = active.filter((u) => !u.isGM).map((u) => u.id); | ||
} else if (users === this.USERS.OTHERS) { | ||
options.users = active.filter((u) => u.id !== game.user.id).map((u) => u.id); | ||
} else if (users === this.USERS.FIRSTGM) { | ||
options.users = game.users.activeGM.id; | ||
} else if (users === this.USERS.SELF) { | ||
options.users = [game.user.id]; | ||
} | ||
return options; | ||
} | ||
|
||
static register(eventName, callback, defaultOptions = {}) { | ||
if (!this.__$socket) { | ||
this.__$socket = game.socket; | ||
game.socket.on(`module.${MODULE_ID}`, this.__$onMessage.bind(this)); | ||
} | ||
|
||
if (this.__$reserved.includes(eventName)) { | ||
throw new Error(`Socket event name ${eventName} is reserved`); | ||
} | ||
|
||
this.__$callbacks[eventName] = callback; | ||
|
||
const wrappedCallback = async (data = {}, options = {}) => { | ||
options = this.__$parseUsers(options); | ||
options = { ...defaultOptions, ...options }; | ||
const eventId = foundry.utils.randomID(); | ||
options.__$eventId = eventId; | ||
options.__$eventName = eventName; | ||
const promises = []; | ||
const local = options.users.includes(game.user.id); | ||
options.users = options.users.filter((u) => u !== game.user.id); | ||
if (options.response) { | ||
for (const user of options.users) { | ||
promises.push( | ||
new Promise((resolve, reject) => { | ||
const key = `${eventId}.${user}`; | ||
this.__$promises[key] = { resolve, reject }; | ||
}), | ||
); | ||
} | ||
|
||
setTimeout(() => { | ||
for (const user of options.users) { | ||
const key = `${eventId}.${user}`; | ||
if (this.__$promises[key]) { | ||
this.__$promises[key].reject({ user: game.users.get(user), response: "timeout" }); | ||
delete this.__$promises[key]; | ||
} | ||
} | ||
}, options.timeout || 30000); | ||
} | ||
|
||
data.__$socketOptions = options; | ||
this.__$socket.emit(`module.${MODULE_ID}`, data); | ||
|
||
const results = []; | ||
|
||
if (local) { | ||
const localWrapper = async () => { | ||
return { user: game.user, response: await callback(data) }; | ||
}; | ||
promises.push(localWrapper()); | ||
} | ||
|
||
const allPromises = await Promise.all(promises); | ||
for (const promise of allPromises) { | ||
results.push(promise); | ||
} | ||
|
||
return results; | ||
}; | ||
|
||
this[eventName] = wrappedCallback.bind(this); | ||
} | ||
|
||
static registerStore(storeName, initialValue = {}, callback = null) { | ||
if (this.__$reserved.includes(storeName)) { | ||
throw new Error(`Store name ${storeName} is reserved`); | ||
} | ||
|
||
if (typeof initialValue !== "object") { | ||
throw new Error("Initial value for store must be an object"); | ||
} | ||
|
||
this.__$stores[storeName] = new SynchronizedStore(storeName, initialValue, callback); | ||
|
||
Object.defineProperty(this, storeName, { | ||
get: () => { | ||
return this.__$stores[storeName].getData(); | ||
}, | ||
set: (value) => { | ||
this.__$stores[storeName].setData(value); | ||
}, | ||
}); | ||
|
||
return this.__$stores[storeName]; | ||
} | ||
} | ||
|
||
class SynchronizedStore { | ||
constructor(storeName, initialValue, callback) { | ||
this._storeName = storeName; | ||
|
||
this._onChange = callback; | ||
|
||
this._data = initialValue; | ||
|
||
this._timestamp = Date.now(); | ||
|
||
this._isLive = false; | ||
|
||
//request value from other users | ||
game.socket.emit(`module.${MODULE_ID}`, { __$socketOptions: { __$storeName: this._storeName, __$request: true, user: game.user.id } }); | ||
} | ||
|
||
synchronize(data) { | ||
this._data = data; | ||
this._timestamp = Date.now(); | ||
this._isLive = true; | ||
this._onChange?.(this.data); | ||
} | ||
|
||
getData() { | ||
return this._data; | ||
} | ||
|
||
setData(value) { | ||
this.synchronize(value); | ||
game.socket.emit(`module.${MODULE_ID}`, { __$socketOptions: { __$storeName: this._storeName, user: game.user.id }, data: value }); | ||
} | ||
} |
Oops, something went wrong.