UNPKG

cheetah-framework

Version:

Cheetah Framework JS used in all our applications

199 lines (176 loc) 5.77 kB
import LaravelModel from '@cheetah/models/LaravelModel' import config from '@cheetah/config' import LockListener from '@cheetah/utils/locks/LocksListener' class LockResource extends LockListener { /** * @param {LaravelModel|String} model model on which to lock or name of the resource * @param {Number|String} [modelId] the model id, if the model is not a LaravelModel * @param {Object} [Echo] */ constructor (model, modelId) { if (model instanceof LaravelModel) { super(model.constructor) this.resourceId = model[model.constructor.idKey] } else { super(model) this.resourceId = modelId } this.isLocked = true this.users = null this.lockingUserId = null } get channelName () { return 'locks.' + this.resourceName + '.' + this.resourceId } get channel () { return this._channel || (this._channel = window.Echo?.join(this.channelName)) } startListening () { return super.startListening()?.here(users => { this.users = users }).joining(user => { this.users.push(user) }).leaving(user => { const index = this.users.indexOf(user) if (index > -1) { this.users.splice(index, 1) } }).listen('.Locks.RequestLock', message => { if (message.lock.user_id === config.locks.getUserId(config.locks.getCurrentUser())) { typeof this.lockRequested === 'function' && this.lockRequested(message) } }).listen('.Locks.ModelLocked', message => { this.isLocked = message.lock.user_id !== config.locks.getUserId(config.locks.getCurrentUser()) this.lockingUserId = message.lock.user_id }).listen('.Locks.ModelUnlocked', message => { if (this.isLocked) { const firstUser = this.users.filter(user => config.locks.getUserId(user.user) !== message.lock.user_id).sort((a, b) => a.timestamp - b.timestamp)[0] if (firstUser && config.locks.getUserId(firstUser.user) === config.locks.getUserId(config.locks.getCurrentUser())) { typeof this.joinIsPossible === 'function' && this.joinIsPossible(message) } } }) } getUser (userId) { return this.users?.find(user => config.locks.getUserId(user.user) === userId) } get lockingUser () { return this.getUser(this.lockingUserId)?.user } async forceKick () { const { data } = await axios.get(route('model.lock.requestKick', { modelType: this.resourceName, modelId: this.resourceId }), { params: { force: true }}) return data.user_id === config.locks.getUserId(config.locks.getCurrentUser()) } async askForKick (accepted, refused) { const stopListeningForKick = () => { this.channel?.stopListening('.client-AcceptKick') this.channel?.stopListening('.client-CancelKick') } this.channel?.listenForWhisper('AcceptKick', message => { stopListeningForKick() if (message.user_id === config.locks.getUserId(config.locks.getCurrentUser())) { accepted(message) } else { refused(message) } }).listenForWhisper('CancelKick', () => { stopListeningForKick() refused() }) try { const { data } = await axios.get(route('model.lock.requestKick', { modelType: this.resourceName, modelId: this.resourceId })) // If you get the lock, unlock the resource if (data.user_id === config.locks.getUserId(config.locks.getCurrentUser())) { stopListeningForKick() this.isLocked = false return true } } catch (e) { stopListeningForKick() refused() RemoteErrors(e) } } async unlock () { return await axios.delete(route('model.lock.destroy', { modelType: this.resourceName, modelId: this.resourceId })) } async acceptKick (userId, force = false) { force ? this.unlock() : await this.unlock() this.lockingUserId = userId this.channel.whisper('AcceptKick', { user_id: userId }) this.refreshResource() } cancelKick () { this.channel.whisper('CancelKick', { user_id: this.userId }) } async tryLocking () { try { if (!this._listening) { this.startListening() } const response = await axios.post(route('model.lock.store', { modelType: this.resourceName, modelId: this.resourceId })) this.isLocked = false return response } catch (error) { if (error.response?.status === 423) { this.isLocked = true this.lockingUserId = error.response.data.lock?.user_id return false } RemoteErrors(error) } return !this.isLocked } refreshResource () { if (typeof this.refresh === 'function') { this.refresh() return } setTimeout(window.location.reload, 2000) } /** * @typedef Message * @type {Object} * @property {number|String} id the model id * @property {String} type the model type */ /** * @callback lockMessageCallback * @param {Message} message * @returns {LockResource} */ /** * @param {lockMessageCallback} callback * @returns {LockResource} */ setOnLockRequest (callback) { /** @private */ this.lockRequested = callback return this } /** * @param {lockMessageCallback} callback * @returns {LockResource} */ setOnJoinPossible (callback) { /** @private */ this.joinIsPossible = callback return this } /** * Sets the function to call when we need to refresh the resource. * By default, we refresh the page 2 seconds after notifying the user. * @param {Function} callback The function to call for a refresh * @returns {LockResource} this */ setRefreshResourceFunction (callback) { /** @private */ this.refresh = callback return this } } export default LockResource