Ejemplo n.º 1
0
    def leave_create(self, data, sesh):
        """Leave

		Disconnects a session from an account or contact so that messages are
		no longer collected for it

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['service', 'key'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Update the sync cache
        Sync.leave(sesh.id(), data['service'], data['key'])

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 2
0
    def clear_update(self, data, sesh):
        """Clear

		Clears the given number of messages from the sync cache

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['service', 'key', 'count'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Clear the messages from the sync cache
        Sync.clear(sesh.id(), data['service'], data['key'], data['count'])

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 3
0
    def join_create(self, data, sesh):
        """Join

		Connects a session to an account or contact so that any messages
		associated with either are stored for later polling

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['service', 'key'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Update the sync cache
        Sync.join(sesh.id(), data['service'], data['key'])

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 4
0
    def pull_read(self, data, sesh):
        """Pull

		A client is requesting an update on anything they might be looking at

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['service', 'key'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # If we have messages to delete
        if 'messages' in data and data['messages']:
            Sync.clear(sesh.id(), data['service'], data['key'],
                       data['messages'])

        # Get as many messages as possible
        lRet = Sync.pull(sesh.id(), data['service'], data['key'])

        # Return whatever was found
        return Services.Effect(lRet)
Ejemplo n.º 5
0
    def matchRequest_create(self, data, sesh):
        """Match Request (Create)

		Creates a new match request and notifies the opponent

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['opponent', 'org'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Find opponent
        dOpponent = Thrower.get(data['opponent'], raw=['alias'])
        if not dOpponent:
            return Services.Effect(error=(1104,
                                          'thrower:%s' % data['opponent']))

        # Create a new request
        try:
            oRequest = MatchRequest({
                "_created": int(time()),
                "initiator": sesh['thrower']['_id'],
                "opponent": data['opponent'],
                "org": data['org']
            })
        except ValueError as e:
            return Services.Effect(error=(1001, e.args[0]))

        # Store the instance
        if not oRequest.create():
            return Services.Effect(error=1100)

        # Sync the data for anyone listening
        Sync.push(
            'auth', 'requests-%s' % data['opponent'], {
                "type": 'match_request',
                "_id": oRequest['_id'],
                "initiator": sesh['thrower']['_id'],
                "alias": sesh['thrower']['alias'],
                "org": data['org']
            })

        # Return the ID of the new request
        return Services.Effect(oRequest['_id'])
Ejemplo n.º 6
0
    def matchRequest_update(self, data, sesh):
        """Match Request (Update)

		Accepts a match request and creates the match with the proper service,
		then notifies both throwers of the ID of the new match

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Find the request
        oRequest = MatchRequest.get(data['id'])
        if not oRequest:
            return Services.Effect(error=(1104,
                                          'match_request:%s' % data['id']))

        # If the accepter is not the opponent
        if sesh['thrower']['_id'] != oRequest['opponent']:
            return Services.Effect(error=1000)

        # Create a new match in the proper service
        oEffect = Services.create(
            oRequest['org'].lower(), 'match', {
                "_internal_": Services.internalKey(),
                "initiator": oRequest['initiator'],
                "opponent": oRequest['opponent']
            }, sesh)
        if oEffect.errorExists():
            return oEffect

        # Delete the request
        oRequest.delete()

        # Notify the initiator of the new match
        Sync.push('auth', 'request-%s' % data['id'], {
            "type": "accepted",
            "match": oEffect.data
        })

        # Return the ID of the new match
        return Services.Effect(oEffect.data)
Ejemplo n.º 7
0
    def matchRequest_delete(self, data, sesh):
        """Match Request (Delete)

		Refuses a match request and deletes it

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Find the request
        oRequest = MatchRequest.get(data['id'])
        if not oRequest:
            return Services.Effect(error=(1104,
                                          'match_request:%s' % data['id']))

        # If the deleter is not the initiator or opponent
        if sesh['thrower']['_id'] != oRequest['initiator'] and \
         sesh['thrower']['_id'] != oRequest['opponent']:
            return Services.Effect(error=1000)

        # Delete it
        if not oRequest.delete():
            return Services.Effect(error=1102)

        # If the initiator retracted their request
        if sesh['thrower']['_id'] == oRequest['initiator']:

            # Let the opponent know
            Sync.push('auth', 'requests-%s' % oRequest['opponent'], {
                "type": "match_request_delete",
                "id": data['id']
            })

        # Else the opponent rejected the request
        else:

            # Let the initiator know
            Sync.push('auth', 'request-%s' % data['id'], {"type": "rejected"})

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 8
0
    def initialise(self):
        """Initialise

		Initialises the instance and returns itself for chaining

		Returns:
			Auth
		"""

        # Init the sync module
        Sync.init(
            Conf.get(('redis', 'sync'), {
                "host": "localhost",
                "port": 6379,
                "db": 1
            }))
Ejemplo n.º 9
0
    def match_delete(self, data, sesh):
        """Match (Delete)

		Deletes an existing match, can only be done if it's not finished

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Get the match
        dMatch = Match.get(data['id'],
                           raw=['finished', 'initiator', 'opponent'])
        if not dMatch:
            return Services.Effect(error=(1104, 'watl_match:%s' % data['id']))

        # If the thrower is neither the initiator or opponent, or the match is
        #	already marked finished
        if (dMatch['initiator'] != sesh['thrower']['_id'] and \
         dMatch['opponent'] != sesh['thrower']['_id']) or \
         dMatch['finished']:
            return Services.Effect(error=1000)

        # Else, attempt to delete the record
        Match.deleteGet(data['id'])

        # Notify anyone watching the match
        Sync.push('watl', 'match-%s' % data['id'], {"type": "deleted"})

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 10
0
    def websocket_read(self, data, sesh):
        """WebSocket

		Generates a unique key for the client that it can use to authorize a
		websocket connection

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- The session associated with the request

		Returns:
			Services.Effect
		"""

        # Generate a random key
        sKey = StrHelper.random(32, ['aZ', '10', '!'])

        # Store the key in the sync cache
        Sync.socket(sKey, {"session": sesh.id()})

        # Return the key
        return Services.Effect(sKey)
Ejemplo n.º 11
0
    def matchGame_update(self, data, sesh):
        """Match Game Update

		Takes a new throw value and stores it, then notifies the opponent

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id', 'throw', 'value'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Get the match
        dMatch = Match.get(
            data['id'],
            raw=['finished', 'game_finished', 'initiator', 'opponent'])
        if not dMatch:
            return Services.Effect(error=(1104, 'natf_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the match as finished
        if dMatch['game_finished'][sIs]:
            return Services.Effect(error=1002)

        # If the throw is not a valid value
        if data['throw'] not in [
                '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'
        ]:
            return Services.Effect(error=(1001, [('throw', 'invalid')]))

        # Validate the value
        dStruct = Match.struct()
        if not dStruct['tree']['game'][sIs][data['throw']].valid(
                data['value']):
            return Services.Effect(error=(1001, [('value',
                                                  'invalid data.value')]))

        # If it's throw 5, and clutch is set, but we didn't get 'd', 0, or 7
        if data['throw'] in ['5', '10']:
            if data['value']['killshot'] != '0':
                if data['value']['value'] not in ['d', 0, 8]:
                    return Services.Effect(
                        error=(1001, [('value', 'invalid data.value.value')]))

        # Update the throw
        Match.updateThrow(data['id'], sIs, data['throw'], data['value'])

        # Notify anyone listening
        Sync.push(
            'watl', 'match-%s' % data['id'], {
                "type": "throw",
                "thrower": sIs,
                "throw": data['throw'],
                "value": data['value']
            })

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 12
0
    def matchFinishGame_update(self, data, sesh):
        """Match Finish Game

		Marks the game as finished. If both throwers are finished, calculates
		if there's a winner or it's a tie

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Get the match
        dMatch = Match.get(
            data['id'],
            raw=['finished', 'game_finished', 'initiator', 'opponent'])
        if not dMatch:
            return Services.Effect(error=(1104, 'natf_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the match as finished
        if dMatch['game_finished'][sIs]:
            return Services.Effect(True)

        # Update the finished state
        Match.finishGame(data['id'], sIs)

        # Fetch the updated data
        dMatch = Match.get(data['id'], raw=['game', 'game_finished'])

        # If both sides are done
        if dMatch['game_finished']['i'] and dMatch['game_finished']['o']:

            # Calculate the stats
            dPoints = {"i": 0, "o": 0}
            for w in ["i", "o"]:
                for t in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]:
                    if t in ['5', '10']:
                        if dMatch['game'][w][t]['value'] != 'd':
                            dPoints[w] += dMatch['game'][w][t]['value']
                    else:
                        if dMatch['game'][w][t] != 'd':
                            dPoints[w] += dMatch['game'][w][t]

            # If we don't have a winner
            if dPoints['i'] == dPoints['o']:

                # Add the overtime section
                Match.addOvertime(data['id'])

                # Start overtime mode
                Sync.push('watl', 'match-%s' % data['id'], {
                    "type": "overtime",
                    "subtype": "start"
                })

            # Else, send back the winner
            else:

                # Mark as finished
                Match.finished(data['id'])

                # Notify the throwers
                Sync.push(
                    'watl', 'match-%s' % data['id'], {
                        "type": "winner",
                        "is": dPoints['i'] > dPoints['o'] and 'i' or 'o'
                    })

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 13
0
    def matchFinishOvertime_update(self, data, sesh):
        """Match Finish Overtime

		Marks the overtime part as finished. If both throwers are finished,
		verifies and notifies if the game is over

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Get the match
        dMatch = Match.get(
            data['id'], raw=['finished', 'initiator', 'opponent', 'overtime'])
        if not dMatch:
            return Services.Effect(error=(1104, 'watl_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the match as finished
        if dMatch['overtime']['finished'][sIs]:
            return Services.Effect(True)

        # Update the finished state
        Match.finishOvertime(data['id'], sIs)

        # Fetch the updated data
        dMatch = Match.get(data['id'], raw=['overtime'])

        # If both sides are done
        if dMatch['overtime']['finished'] == {'i': True, 'o': True}:

            # If the lengths don't match
            if len(dMatch['overtime']['i']) != len(dMatch['overtime']['o']):

                # Reset finished
                Match.finishOvertimeReset(data['id'])

                # Notify throwers we aren't finished
                Sync.push('watl', 'match-%s' % data['id'], {
                    "type": "overtime",
                    "subtype": "notfinished"
                })

                # Return failure
                return Services.Effect(False)

            # Init the consecutive successes
            iCons = 0

            # Count up until we have a clear winner or loser
            for i in range(len(dMatch['overtime']['i'])):

                # If we got a drop, consider it a zero
                if dMatch['overtime']['i'][i] == 'd':
                    dMatch['overtime']['i'][i] = 0
                if dMatch['overtime']['o'][i] == 'd':
                    dMatch['overtime']['o'][i] = 0

                # If they aren't the same
                if dMatch['overtime']['i'][i] != dMatch['overtime']['o'][i]:

                    # Mark as finished
                    Match.finished(data['id'])

                    # Notify throwers
                    Sync.push(
                        'watl', 'match-%s' % data['id'], {
                            "type":
                            "winner",
                            "is":
                            dMatch['overtime']['i'][i] >
                            dMatch['overtime']['o'][i] and 'i' or 'o'
                        })

                    # Break out of the loop
                    break

            # If we didn't get a winner, something is wrong
            else:

                # Reset finished
                Match.finishOvertimeReset(data['id'])

                # Notify throwers we aren't finished
                Sync.push('watl', 'match-%s' % data['id'], {
                    "type": "overtime",
                    "subtype": "notfinished"
                })

                # Return failure
                return Services.Effect(False)

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 14
0
    def matchOvertime_update(self, data, sesh):
        """Match Overtime

		Takes a new throw for overtime and records it, then notifies the opponent

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id', 'throw', 'value'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # If the throw is not an int
        if not isinstance(data['throw'], int):
            return Services.Effect(error=(1001, [('throw', 'not an int')]))

        # If the value is anything other than 'd', 0, or 1
        if data['value'] not in ['d', 0, 1]:
            return Services.Effect(error=(1001, [('value', 'invalid')]))

        # Get the match
        dMatch = Match.get(
            data['id'], raw=['finished', 'initiator', 'opponent', 'overtime'])
        if not dMatch:
            return Services.Effect(error=(1104, 'watl_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the section as finished
        if dMatch['overtime']['finished'][sIs]:
            return Services.Effect(error=1002)

        # If the value doesn't exist
        if len(dMatch['overtime'][sIs]) == data['throw']:
            dMatch['overtime'][sIs].append(data['value'])

        # Else, overwrite it
        else:
            dMatch['overtime'][sIs][data['throw']] = data['value']

        # Store the changes
        Match.updateOvertime(data['id'], sIs, dMatch['overtime'])

        # Notify anyone listening
        Sync.push(
            'watl', 'match-%s' % data['id'], {
                "type": "overtime",
                "subtype": "throw",
                "thrower": sIs,
                "throw": data['throw'],
                "value": data['value']
            })

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 15
0
    def matchFinishBigaxeTarget_update(self, data, sesh):
        """Match Finish Big Axe Target

		Marks the target part of big axe as finished. If both throwers are
		finished, verifies and notifies if the game is over or points should
		start

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # Get the match
        dMatch = Match.get(data['id'],
                           raw=['finished', 'initiator', 'opponent', 'bigaxe'])
        if not dMatch:
            return Services.Effect(error=(1104, 'natf_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the match as finished
        if dMatch['bigaxe']['target']['finished'][sIs]:
            return Services.Effect(True)

        # Update the finished state
        Match.finishBigAxe('target', data['id'], sIs)

        # Fetch the updated data
        dMatch = Match.get(data['id'], raw=['bigaxe'])

        # If both sides are done
        if dMatch['bigaxe']['target']['finished'] == {'i': True, 'o': True}:

            # If the lengths don't match
            if len(dMatch['bigaxe']['target']['i']) != len(
                    dMatch['bigaxe']['target']['o']):

                # Reset finished
                Match.finishBigAxeReset('target', data['id'])

                # Notify throwers we aren't finished
                Sync.push('natf', 'match-%s' % data['id'], {
                    "type": "bigaxe_target",
                    "subtype": "notfinished"
                })

                # Return failure
                return Services.Effect(False)

            # Init the consecutive successes
            iCons = 0

            # Count up until we have a clear winner or loser
            for i in range(len(dMatch['bigaxe']['target']['i'])):

                # If both are 0 or drops
                if (dMatch['bigaxe']['target']['i'][i] == 0 or \
                 dMatch['bigaxe']['target']['i'][i] == 'd') and \
                 (dMatch['bigaxe']['target']['o'][i] == 0 or \
                 dMatch['bigaxe']['target']['o'][i] == 'd'):

                    # Reset the consecutive and continue
                    iCons = 0

                # If they're both 1
                elif dMatch['bigaxe']['target']['i'][i] == 1 and \
                 dMatch['bigaxe']['target']['o'][i] == 1:

                    # Increase the consecutive successes
                    iCons += 1

                    # If it's hit 3
                    if iCons == 3:

                        # Add the section
                        Match.addBigAxe("points", data['id'])

                        # Notify that we're going to points
                        Sync.push('natf', 'match-%s' % data['id'], {
                            "type": "bigaxe_points",
                            "subtype": "start"
                        })

                        # Break out of the loop
                        break

                # Else we have a winner
                else:

                    # Mark as finished
                    Match.finished(data['id'])

                    # Notify throwers
                    Sync.push(
                        'natf', 'match-%s' % data['id'], {
                            "type":
                            "winner",
                            "is":
                            dMatch['bigaxe']['target']['i'][i] == 1 and 'i'
                            or 'o'
                        })

                    # Break out of the loop
                    break

            # If we didn't get a winner or a jump to points, something is wrong
            else:

                # Reset finished
                Match.finishBigAxeReset('target', data['id'])

                # Notify throwers we aren't finished
                Sync.push('natf', 'match-%s' % data['id'], {
                    "type": "bigaxe_target",
                    "subtype": "notfinished"
                })

                # Return failure
                return Services.Effect(False)

        # Return OK
        return Services.Effect(True)
Ejemplo n.º 16
0
    def matchBigaxePoints_update(self, data, sesh):
        """Match Big Axe Points

		Takes a new throw for points and records it, then notifies the opponent

		Arguments:
			data {dict} -- Data sent with the request
			sesh {Sesh._Session} -- Session associated with the request

		Returns:
			Services.Effect
		"""

        # Verify fields
        try:
            DictHelper.eval(data, ['id', 'throw', 'clutch', 'value'])
        except ValueError as e:
            return Services.Effect(error=(1001, [(f, "missing")
                                                 for f in e.args]))

        # If the throw is not an int
        if not isinstance(data['throw'], int):
            return Services.Effect(error=(1001, [('throw', 'not an int')]))

        # If the clutch is not a bool
        if not isinstance(data['clutch'], bool):
            return Services.Effect(error=(1001, [('clutch', 'not a bool')]))

        # If clutch is true but we didn't get 'd', 0, or 7
        if data['clutch']:
            if data['value'] not in ['d', 0, 7]:
                return Services.Effect(error=(1001, [('value', 'invalid')]))

        # Get the match
        dMatch = Match.get(data['id'],
                           raw=['finished', 'initiator', 'opponent', 'bigaxe'])
        if not dMatch:
            return Services.Effect(error=(1104, 'natf_match:%s' % data['id']))

        # If the match is already finished
        if dMatch['finished']:
            return Services.Effect(error=1002)

        # Is the thrower the initiator or the opponent?
        if sesh['thrower']['_id'] == dMatch['initiator']:
            sIs = 'i'
        elif sesh['thrower']['_id'] == dMatch['opponent']:
            sIs = 'o'
        else:
            return Services.Effect(error=1000)

        # If the thrower already marked the section as finished
        if dMatch['bigaxe']['points']['finished'][sIs]:
            return Services.Effect(error=1002)

        # If the value doesn't exist
        if len(dMatch['bigaxe']['points'][sIs]) == data['throw']:
            dMatch['bigaxe']['points'][sIs].append({
                "clutch": data['clutch'],
                "value": data['value']
            })

        # Else, overwrite it
        else:
            dMatch['bigaxe']['points'][sIs][data['throw']] = {
                "clutch": data['clutch'],
                "value": data['value']
            }

        # Store the changes
        Match.updateBigAxe(
            'points',
            data['id'],
            sIs,
            dMatch['bigaxe']['points'],
        )

        # Notify anyone listening
        Sync.push(
            'natf', 'match-%s' % data['id'], {
                "type": "bigaxe_points",
                "subtype": "throw",
                "thrower": sIs,
                "throw": data['throw'],
                "clutch": data['clutch'],
                "value": data['value']
            })

        # Return OK
        return Services.Effect(True)