1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""The base interface of RPC Framework. 15 16Implementations of this interface support the conduct of "operations": 17exchanges between two distinct ends of an arbitrary number of data payloads 18and metadata such as a name for the operation, initial and terminal metadata 19in each direction, and flow control. These operations may be used for transfers 20of data, remote procedure calls, status indication, or anything else 21applications choose. 22""" 23 24# threading is referenced from specification in this module. 25import abc 26import enum 27import threading # pylint: disable=unused-import 28 29import six 30 31# abandonment is referenced from specification in this module. 32from grpc.framework.foundation import abandonment # pylint: disable=unused-import 33 34# pylint: disable=too-many-arguments 35 36 37class NoSuchMethodError(Exception): 38 """Indicates that an unrecognized operation has been called. 39 40 Attributes: 41 code: A code value to communicate to the other side of the operation 42 along with indication of operation termination. May be None. 43 details: A details value to communicate to the other side of the 44 operation along with indication of operation termination. May be None. 45 """ 46 47 def __init__(self, code, details): 48 """Constructor. 49 50 Args: 51 code: A code value to communicate to the other side of the operation 52 along with indication of operation termination. May be None. 53 details: A details value to communicate to the other side of the 54 operation along with indication of operation termination. May be None. 55 """ 56 super(NoSuchMethodError, self).__init__() 57 self.code = code 58 self.details = details 59 60 61class Outcome(object): 62 """The outcome of an operation. 63 64 Attributes: 65 kind: A Kind value coarsely identifying how the operation terminated. 66 code: An application-specific code value or None if no such value was 67 provided. 68 details: An application-specific details value or None if no such value was 69 provided. 70 """ 71 72 @enum.unique 73 class Kind(enum.Enum): 74 """Ways in which an operation can terminate.""" 75 76 COMPLETED = 'completed' 77 CANCELLED = 'cancelled' 78 EXPIRED = 'expired' 79 LOCAL_SHUTDOWN = 'local shutdown' 80 REMOTE_SHUTDOWN = 'remote shutdown' 81 RECEPTION_FAILURE = 'reception failure' 82 TRANSMISSION_FAILURE = 'transmission failure' 83 LOCAL_FAILURE = 'local failure' 84 REMOTE_FAILURE = 'remote failure' 85 86 87class Completion(six.with_metaclass(abc.ABCMeta)): 88 """An aggregate of the values exchanged upon operation completion. 89 90 Attributes: 91 terminal_metadata: A terminal metadata value for the operaton. 92 code: A code value for the operation. 93 message: A message value for the operation. 94 """ 95 96 97class OperationContext(six.with_metaclass(abc.ABCMeta)): 98 """Provides operation-related information and action.""" 99 100 @abc.abstractmethod 101 def outcome(self): 102 """Indicates the operation's outcome (or that the operation is ongoing). 103 104 Returns: 105 None if the operation is still active or the Outcome value for the 106 operation if it has terminated. 107 """ 108 raise NotImplementedError() 109 110 @abc.abstractmethod 111 def add_termination_callback(self, callback): 112 """Adds a function to be called upon operation termination. 113 114 Args: 115 callback: A callable to be passed an Outcome value on operation 116 termination. 117 118 Returns: 119 None if the operation has not yet terminated and the passed callback will 120 later be called when it does terminate, or if the operation has already 121 terminated an Outcome value describing the operation termination and the 122 passed callback will not be called as a result of this method call. 123 """ 124 raise NotImplementedError() 125 126 @abc.abstractmethod 127 def time_remaining(self): 128 """Describes the length of allowed time remaining for the operation. 129 130 Returns: 131 A nonnegative float indicating the length of allowed time in seconds 132 remaining for the operation to complete before it is considered to have 133 timed out. Zero is returned if the operation has terminated. 134 """ 135 raise NotImplementedError() 136 137 @abc.abstractmethod 138 def cancel(self): 139 """Cancels the operation if the operation has not yet terminated.""" 140 raise NotImplementedError() 141 142 @abc.abstractmethod 143 def fail(self, exception): 144 """Indicates that the operation has failed. 145 146 Args: 147 exception: An exception germane to the operation failure. May be None. 148 """ 149 raise NotImplementedError() 150 151 152class Operator(six.with_metaclass(abc.ABCMeta)): 153 """An interface through which to participate in an operation.""" 154 155 @abc.abstractmethod 156 def advance(self, 157 initial_metadata=None, 158 payload=None, 159 completion=None, 160 allowance=None): 161 """Progresses the operation. 162 163 Args: 164 initial_metadata: An initial metadata value. Only one may ever be 165 communicated in each direction for an operation, and they must be 166 communicated no later than either the first payload or the completion. 167 payload: A payload value. 168 completion: A Completion value. May only ever be non-None once in either 169 direction, and no payloads may be passed after it has been communicated. 170 allowance: A positive integer communicating the number of additional 171 payloads allowed to be passed by the remote side of the operation. 172 """ 173 raise NotImplementedError() 174 175 176class ProtocolReceiver(six.with_metaclass(abc.ABCMeta)): 177 """A means of receiving protocol values during an operation.""" 178 179 @abc.abstractmethod 180 def context(self, protocol_context): 181 """Accepts the protocol context object for the operation. 182 183 Args: 184 protocol_context: The protocol context object for the operation. 185 """ 186 raise NotImplementedError() 187 188 189class Subscription(six.with_metaclass(abc.ABCMeta)): 190 """Describes customer code's interest in values from the other side. 191 192 Attributes: 193 kind: A Kind value describing the overall kind of this value. 194 termination_callback: A callable to be passed the Outcome associated with 195 the operation after it has terminated. Must be non-None if kind is 196 Kind.TERMINATION_ONLY. Must be None otherwise. 197 allowance: A callable behavior that accepts positive integers representing 198 the number of additional payloads allowed to be passed to the other side 199 of the operation. Must be None if kind is Kind.FULL. Must not be None 200 otherwise. 201 operator: An Operator to be passed values from the other side of the 202 operation. Must be non-None if kind is Kind.FULL. Must be None otherwise. 203 protocol_receiver: A ProtocolReceiver to be passed protocol objects as they 204 become available during the operation. Must be non-None if kind is 205 Kind.FULL. 206 """ 207 208 @enum.unique 209 class Kind(enum.Enum): 210 211 NONE = 'none' 212 TERMINATION_ONLY = 'termination only' 213 FULL = 'full' 214 215 216class Servicer(six.with_metaclass(abc.ABCMeta)): 217 """Interface for service implementations.""" 218 219 @abc.abstractmethod 220 def service(self, group, method, context, output_operator): 221 """Services an operation. 222 223 Args: 224 group: The group identifier of the operation to be serviced. 225 method: The method identifier of the operation to be serviced. 226 context: An OperationContext object affording contextual information and 227 actions. 228 output_operator: An Operator that will accept output values of the 229 operation. 230 231 Returns: 232 A Subscription via which this object may or may not accept more values of 233 the operation. 234 235 Raises: 236 NoSuchMethodError: If this Servicer does not handle operations with the 237 given group and method. 238 abandonment.Abandoned: If the operation has been aborted and there no 239 longer is any reason to service the operation. 240 """ 241 raise NotImplementedError() 242 243 244class End(six.with_metaclass(abc.ABCMeta)): 245 """Common type for entry-point objects on both sides of an operation.""" 246 247 @abc.abstractmethod 248 def start(self): 249 """Starts this object's service of operations.""" 250 raise NotImplementedError() 251 252 @abc.abstractmethod 253 def stop(self, grace): 254 """Stops this object's service of operations. 255 256 This object will refuse service of new operations as soon as this method is 257 called but operations under way at the time of the call may be given a 258 grace period during which they are allowed to finish. 259 260 Args: 261 grace: A duration of time in seconds to allow ongoing operations to 262 terminate before being forcefully terminated by the stopping of this 263 End. May be zero to terminate all ongoing operations and immediately 264 stop. 265 266 Returns: 267 A threading.Event that will be set to indicate all operations having 268 terminated and this End having completely stopped. The returned event 269 may not be set until after the full grace period (if some ongoing 270 operation continues for the full length of the period) or it may be set 271 much sooner (if for example this End had no operations in progress at 272 the time its stop method was called). 273 """ 274 raise NotImplementedError() 275 276 @abc.abstractmethod 277 def operate(self, 278 group, 279 method, 280 subscription, 281 timeout, 282 initial_metadata=None, 283 payload=None, 284 completion=None, 285 protocol_options=None): 286 """Commences an operation. 287 288 Args: 289 group: The group identifier of the invoked operation. 290 method: The method identifier of the invoked operation. 291 subscription: A Subscription to which the results of the operation will be 292 passed. 293 timeout: A length of time in seconds to allow for the operation. 294 initial_metadata: An initial metadata value to be sent to the other side 295 of the operation. May be None if the initial metadata will be later 296 passed via the returned operator or if there will be no initial metadata 297 passed at all. 298 payload: An initial payload for the operation. 299 completion: A Completion value indicating the end of transmission to the 300 other side of the operation. 301 protocol_options: A value specified by the provider of a Base interface 302 implementation affording custom state and behavior. 303 304 Returns: 305 A pair of objects affording information about the operation and action 306 continuing the operation. The first element of the returned pair is an 307 OperationContext for the operation and the second element of the 308 returned pair is an Operator to which operation values not passed in 309 this call should later be passed. 310 """ 311 raise NotImplementedError() 312 313 @abc.abstractmethod 314 def operation_stats(self): 315 """Reports the number of terminated operations broken down by outcome. 316 317 Returns: 318 A dictionary from Outcome.Kind value to an integer identifying the number 319 of operations that terminated with that outcome kind. 320 """ 321 raise NotImplementedError() 322 323 @abc.abstractmethod 324 def add_idle_action(self, action): 325 """Adds an action to be called when this End has no ongoing operations. 326 327 Args: 328 action: A callable that accepts no arguments. 329 """ 330 raise NotImplementedError() 331