[100] | 1 | from abc import ABC
|
---|
| 2 | from typing import List, Any
|
---|
| 3 |
|
---|
| 4 | from pyson.JsonSubTypes import JsonSubTypes
|
---|
| 5 | from pyson.JsonTypeInfo import JsonTypeInfo, Id, As
|
---|
| 6 |
|
---|
| 7 | from geniusweb.actions.Action import Action
|
---|
| 8 | from geniusweb.actions.PartyId import PartyId
|
---|
| 9 | from geniusweb.inform.Inform import Inform
|
---|
| 10 | from geniusweb.protocol.ProtocolException import ProtocolException
|
---|
| 11 | from geniusweb.protocol.session.mopac.PartyStates import PartyStates
|
---|
| 12 | from geniusweb.voting.VotingEvaluator import VotingEvaluator
|
---|
| 13 |
|
---|
| 14 |
|
---|
| 15 | PHASE_MAXTIME = 30000 # 30sec
|
---|
| 16 | PHASE_MINTIME = 100 # 100 millisec
|
---|
| 17 |
|
---|
| 18 |
|
---|
| 19 | @JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
|
---|
| 20 | @JsonSubTypes(["geniusweb.protocol.session.mopac.phase.OfferPhase.OfferPhase",
|
---|
| 21 | "geniusweb.protocol.session.mopac.phase.OptInPhase.OptInPhase",
|
---|
| 22 | "geniusweb.protocol.session.mopac.phase.VotingPhase.VotingPhase"])
|
---|
| 23 | class Phase(ABC):
|
---|
| 24 | '''
|
---|
| 25 | A Phase is a part of the round structure. In each round parties have to take
|
---|
| 26 | multiple actions. Each action is part of a phase.
|
---|
| 27 |
|
---|
| 28 | Invariant: A phase object handles negotiation events, ensuring that the
|
---|
| 29 | events are handled according to the possible actions in this phase. A phase
|
---|
| 30 | object must always remain in a consistent state. It does so by modifying the
|
---|
| 31 | contained {@link PartyStates} as needed.
|
---|
| 32 | <p>
|
---|
| 33 | The standard exception handling is assumed: unchecked exceptions are thrown
|
---|
| 34 | only if there is a bug in the protocol. Because none of the functions in this
|
---|
| 35 | interface throws, any error must be either ignored or the party must be
|
---|
| 36 | kicked.
|
---|
| 37 | '''
|
---|
| 38 |
|
---|
| 39 | def With(self, actor:PartyId ,action: Action ,now:int)->"Phase" :
|
---|
| 40 | '''
|
---|
| 41 | Handle an actor's action. If a {@link ProtocolException} occurs, this is
|
---|
| 42 | handled by updating the PartyStates
|
---|
| 43 |
|
---|
| 44 | @param actor the real actor (may differ from the actor contained in the
|
---|
| 45 | action)
|
---|
| 46 | @param action the action submitted by actor, which this phase can really
|
---|
| 47 | handle.
|
---|
| 48 | @param now the current time
|
---|
| 49 | @return new VotingPhase
|
---|
| 50 | '''
|
---|
| 51 |
|
---|
| 52 | def WithException(self, e:ProtocolException)->"Phase" :
|
---|
| 53 | '''
|
---|
| 54 | @param e a {@link ProtocolException}
|
---|
| 55 | @return new Phase with a party disabled because it violated a protocol eg
|
---|
| 56 | breaking a websocket link.
|
---|
| 57 | '''
|
---|
| 58 |
|
---|
| 59 | def getInform(self)->Inform :
|
---|
| 60 | '''
|
---|
| 61 | @return the inform object to send to all parties at start of phase.
|
---|
| 62 | '''
|
---|
| 63 |
|
---|
| 64 | def isFinal(self, now:int) -> bool:
|
---|
| 65 | '''
|
---|
| 66 | @param now the current time
|
---|
| 67 | @return true iff past deadline or no more actions are allowed anyway.
|
---|
| 68 | (which usually means, all parties have done exactly one act).
|
---|
| 69 | Notice, this is the main reason that it is desirable to require
|
---|
| 70 | all parties to act exactly once in each phase. Without such a
|
---|
| 71 | rule, the protocol will always have to wait till the deadline.
|
---|
| 72 | '''
|
---|
| 73 |
|
---|
| 74 | def finish(self)->"Phase" :
|
---|
| 75 | '''
|
---|
| 76 | @return finished state. That means, all parties that did not act have
|
---|
| 77 | been kicked, new agreements have been computed, etc.
|
---|
| 78 | '''
|
---|
| 79 |
|
---|
| 80 | def next(self, now:int, duration:int) -> "Phase" :
|
---|
| 81 | '''
|
---|
| 82 | Determines the next phase. Resets the actions field. Can only be called
|
---|
| 83 | after {@link #finish()}
|
---|
| 84 |
|
---|
| 85 | @param now the current time
|
---|
| 86 | @param duration the max duration (ms) of the next phase. Must be between
|
---|
| 87 | {@link #PHASE_MINTIME} and {@link #PHASE_MAXTIME}. Also
|
---|
| 88 | make sure that now+duration is at most at the total
|
---|
| 89 | negotiation deadline.
|
---|
| 90 | @return the next phase, or null if negotiation is complete.
|
---|
| 91 | '''
|
---|
| 92 |
|
---|
| 93 | def getEvaluator(self)->VotingEvaluator :
|
---|
| 94 | '''
|
---|
| 95 | @return the voting evaluator
|
---|
| 96 | '''
|
---|
| 97 |
|
---|
| 98 | def getDeadline(self)->int:
|
---|
| 99 | '''
|
---|
| 100 | @return time (ms since 1970) at which phase ends. The phase may end
|
---|
| 101 | before, but never after this.
|
---|
| 102 | '''
|
---|
| 103 |
|
---|
| 104 | def getPartyStates(self)->PartyStates :
|
---|
| 105 | '''
|
---|
| 106 | @return the party states. Notice that someone must call
|
---|
| 107 | {@link PartyStates#finish()} if passed the deadline.
|
---|
| 108 | '''
|
---|
| 109 |
|
---|
| 110 | def getAllowedActions(self) -> List[Any]: # Class<? extends Action>...
|
---|
| 111 | '''
|
---|
| 112 | @return the allowed actinos in this phase
|
---|
| 113 | '''
|
---|