Repository: incubator-wave Updated Branches: refs/heads/master e650c2d86 -> b15695b9e
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/b15695b9/wave/src/proto/proto/org/waveprotocol/wave/concurrencycontrol/clientserver.proto ---------------------------------------------------------------------- diff --git a/wave/src/proto/proto/org/waveprotocol/wave/concurrencycontrol/clientserver.proto b/wave/src/proto/proto/org/waveprotocol/wave/concurrencycontrol/clientserver.proto new file mode 100644 index 0000000..17c20a7 --- /dev/null +++ b/wave/src/proto/proto/org/waveprotocol/wave/concurrencycontrol/clientserver.proto @@ -0,0 +1,268 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// The wave client-server protocol. +// See http://www.waveprotocol.org/protocol/design-proposals/clientserver-protocol +// +// Author: ano...@google.com (Alex North) + +syntax = "proto2"; + +import "org/waveprotocol/box/server/rpc/rpc.proto"; +import "org/waveprotocol/wave/federation/federation.protodevel"; + +package concurrencycontrol; + +option java_package = "org.waveprotocol.wave.concurrencycontrol"; +option java_outer_classname = "ClientServer"; + + +/* + *** Fetch service. *** + * Provides snapshots describing a client's view of a wave. + * As a bandwidth optimization, the client may specify that it already has + * snapshots of some wavelets at some version (such as from a previous fetch). + * If the server's current version matches the version the client provides + * then the snapshot is omitted from the response. + */ +service FetchService { + rpc Fetch(FetchWaveViewRequest) returns (FetchWaveViewResponse); +} + +message FetchWaveViewRequest { + // Wave to open, URI path format. + required string waveId = 1; + // Wavelet versions the client already knows. + // At most one version per wavelet. + repeated WaveletVersion knownWavelet = 2; +} + +message FetchWaveViewResponse { + required ResponseStatus status = 1; + + message Wavelet { + // The wavelet in view, URI path format. + required string waveletId = 1; + // Snapshot of the wavelet; omitted if the client already knew it. + optional WaveletSnapshot snapshot = 2; + } + repeated Wavelet wavelet = 2; +} + +/* A wavelet with a known hashed version of that wavelet. */ +message WaveletVersion { + // Known wavelet, URI path format. + required string waveletId = 1; + // Known hashed version of the wavelet. + required federation.ProtocolHashedVersion version = 2; +} + +/* A wavelet and associated metadata. */ +message WaveletSnapshot { + // Wavelet's id, URI path format. + required string waveletId = 1; + // Participants of this wavelet. + repeated string participant = 2; + // Snapshots of all the documents in the wavelet. + repeated DocumentSnapshot document = 3; + + //// Metadata //// + // Current version and modification timestamp of the wavelet. + required federation.ProtocolHashedVersion version = 4; + required int64 lastModifiedTime = 5; + // Participant and time of creation for the wavelet. + required string creator = 6; + required int64 creationTime = 7; +} + +/* A document and associated metadata. */ +message DocumentSnapshot { + // Id of the document. + required string documentId = 1; + // Operation that transforms an empty document the document state. + required federation.ProtocolDocumentOperation documentOperation = 2; + + //// Metadata //// + // Participant who submitted the first operation to the document. + required string author = 3; + // All participants who have submitted operations to the document. + repeated string contributor = 4; + // Wavelet version and timestamp when the document was last modified. + required int64 lastModifiedVersion = 5; + required int64 lastModifiedTime = 6; +} + +/* + *** Wavelet channel service. *** + * Provides a uni-directional stream of deltas for a single wavelet, + * beginning at the delta applying at a client-specified version. + * The stream continues until either the client requests the channel + * be closed or a terminating message is received. Deltas submitted + * with this channel's id are excluded from the stream. There is no + * ordering guarantee between this service and responses from the + * delta submission service. + */ +service WaveletChannelService { + rpc Open(OpenWaveletChannelRequest) returns (OpenWaveletChannelStream) { + option (rpc.is_streaming_rpc) = true; + }; + rpc Close(CloseWaveletChannelRequest) returns (EmptyResponse); +} + +message OpenWaveletChannelRequest { + // Wave id, URI path format. + required string waveId = 1; + // Wavelet id, URI path format. + required string waveletId = 2; + // Application version of first delta to return. + required federation.ProtocolHashedVersion beginVersion = 3; +} + +/** Repeated message for a wavelet channel. */ +message OpenWaveletChannelStream { + // Identifies the channel, provided only in the first message. + optional string channelId = 1; + + // Second and subsequent messages contain either or both a delta + // and commitVersion. + optional WaveletUpdate delta = 2; + optional federation.ProtocolHashedVersion commitVersion = 3; + + // Last message contains only a terminator. + optional WaveletChannelTerminator terminator = 4; +} + +message CloseWaveletChannelRequest { + // Channel to close. + required string channelId = 1; +} + +/** A delta applied to a wavelet. */ +message WaveletUpdate { + // Transformed delta. + required federation.ProtocolWaveletDelta delta = 1; + // Wavelet hashed version after the delta. + required federation.ProtocolHashedVersion resultingVersion = 2; + // Timestamp of delta application. + required int64 applicationTimpstamp = 3; +} + +/** Terminates a wavelet stream. */ +message WaveletChannelTerminator { + required ResponseStatus status = 1; +} + + +/* + *** Delta submission service. *** + * Receives deltas submitted against wavelets. + * Deltas are submitted in association with a wavelet channel (see + * WaveletChannelService). + */ +service DeltaSubmissionService { + rpc Submit(SubmitDeltaRequest) returns (SubmitDeltaResponse); +} + +message SubmitDeltaRequest { + // Wave to submit to, URI path format. + required string waveId = 1; + // Wavelet to submit to, URI path format. + required string waveletId = 2; + // Delta to submit. + required federation.ProtocolWaveletDelta delta = 3; + // Wavelet channel associated with submission. + required string channelId = 4; +} + +message SubmitDeltaResponse { + required ResponseStatus status = 1; + + // Number of ops applied from the delta. + required int32 operationsApplied = 2; + // Wavelet hashed version after the delta. + optional federation.ProtocolHashedVersion hashedVersionAfterApplication = 3; + // Timestamp of delta application. + optional int64 timestampAfterApplication = 4; +} + + +/* + *** Transport authentication service. *** + * Authenticates the underlying transport. + * This service is required only to work around a bug in some browsers' + * websocket implementations that fail to set cookies containing authentication + * tokens. + * If the client's authentication is invalid the server should close the + * transport. + * See: http://code.google.com/p/wave-protocol/issues/detail?id=119 + */ +service TransportAuthenticationService { + rpc Authenticate (TransportAuthenticationRequest) returns (EmptyResponse); +} + +message TransportAuthenticationRequest { + // Authentication token. + required string token = 1; +} + + +/*** An empty message for services which have no application-level result. ***/ +message EmptyResponse { +} + +/*** Response status for all services ***/ +message ResponseStatus { + enum ResponseCode { + // All good. + OK = 0; + + // Request was ill-formed. + BAD_REQUEST = 1; + + // An unspecified internal error occurred. + INTERNAL_ERROR = 2; + + // The request was not authorized. + NOT_AUTHORIZED = 3; + + // Hashed version didn't match a point in history. + VERSION_ERROR = 4; + + // A delta contained an invalid operation (before or after transformation). + INVALID_OPERATION = 5; + + // An operation didn't preserve a document schema. + SCHEMA_VIOLATION = 6; + + // A delta is too big or the resulting document count or size is too large. + SIZE_LIMIT_EXCEEDED = 7; + + // An operation was rejected by a server policy. + POLICY_VIOLATION = 8; + + // An object is unavailable because it has been quarantined. + QUARANTINED = 9; + + // A request was made against a version older than the server was willing + // to satisfy. Transform and retry. + TOO_OLD = 10; + } + + required ResponseCode status = 1; + // Reason must be provided if status != OK. + optional string failureReason = 2; +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/b15695b9/wave/src/proto/proto/org/waveprotocol/wave/diff/build.xml ---------------------------------------------------------------------- diff --git a/wave/src/proto/proto/org/waveprotocol/wave/diff/build.xml b/wave/src/proto/proto/org/waveprotocol/wave/diff/build.xml new file mode 100644 index 0000000..0b2ffc0 --- /dev/null +++ b/wave/src/proto/proto/org/waveprotocol/wave/diff/build.xml @@ -0,0 +1,28 @@ +<?xml version='1.0'?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +--> +<project name="diff"> + <import file="${build.common.path}"/> + <property name="libname" value="diff"/> + <patternset id="srcs"> + <include name="org/waveprotocol/wave/diff/**"/> + </patternset> +</project> http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/b15695b9/wave/src/proto/proto/org/waveprotocol/wave/diff/diff.proto ---------------------------------------------------------------------- diff --git a/wave/src/proto/proto/org/waveprotocol/wave/diff/diff.proto b/wave/src/proto/proto/org/waveprotocol/wave/diff/diff.proto new file mode 100644 index 0000000..d75d27a --- /dev/null +++ b/wave/src/proto/proto/org/waveprotocol/wave/diff/diff.proto @@ -0,0 +1,114 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// The wave diff-on-open fetch service. +// +// Author: hearn...@google.com (David Hearnden) +// ano...@google.com (Alex North) + +syntax = "proto2"; + +import "org/waveprotocol/box/server/rpc/rpc.proto"; +import "org/waveprotocol/wave/concurrencycontrol/clientserver.proto"; +import "org/waveprotocol/wave/federation/federation.protodevel"; +import "org/apache/wave/pst/protobuf/extensions.proto"; + +package diff; + +option java_package = "org.waveprotocol.wave.diff"; +option java_outer_classname = "Diff"; + + +/* + *** Fetch service. *** + * Provides snapshots describing a client's view of a wave, in diff format. + * As a bandwidth optimization, the client may specify that it already has + * snapshots of some wavelets at some version (such as from a previous fetch). + * If the server's current version matches the version the client provides + * then the snapshot is omitted from the response. + */ +service FetchDiffService { + rpc Fetch(FetchDiffRequest) returns (FetchDiffResponse); +} + +message FetchDiffRequest { + // Wave to open, URI path format. + required string waveId = 1; + // Wavelet versions the client already knows. + // At most one version per wavelet. + repeated concurrencycontrol.WaveletVersion knownWavelet = 2; +} + +message FetchDiffResponse { + required concurrencycontrol.ResponseStatus status = 1; + + message WaveletDiff { + // The wavelet in view, URI path format. + required string waveletId = 1; + // Snapshot of the wavelet; omitted if the client already knew it. + optional WaveletDiffSnapshot snapshot = 2; + } + repeated WaveletDiff wavelet = 2; +} + +/* A wavelet and associated metadata. */ +message WaveletDiffSnapshot { + // Wavelet's id, URI path format. + required string waveletId = 1; + + // Participants of this wavelet. + repeated string participant = 2; + // Added participants of this wavelet; + repeated string addedParticipant = 21; + // Removed participants of this wavelet; + repeated string removedParticipant = 22; + + // Snapshots of all the documents in the wavelet. + repeated DocumentDiffSnapshot document = 3; + + //// Metadata //// + // Current version and modification timestamp of the wavelet. + required federation.ProtocolHashedVersion version = 4; + required int64 lastModifiedTime = 5 [(int52) = true]; + // Participant and time of creation for the wavelet. + required string creator = 6; + required int64 creationTime = 7 [(int52) = true]; +} + +/* A document and associated metadata. */ +message DocumentDiffSnapshot { + // Id of the document. + required string documentId = 1; + // Operation that transforms an empty document the last-read document state. + optional federation.ProtocolDocumentOperation state = 2; + + // Operation that transforms the last-read document state to the current state. + optional federation.ProtocolDocumentOperation diff = 21; + + //// Metadata //// + // Participant who submitted the first operation to the document. + required string author = 3; + // All participants who have submitted operations to the document. + repeated string contributor = 4; + // Added participants who have submitted operations to the document. + repeated string addedContributor = 22; + // Removed participants who have submitted operations to the document. + repeated string removedContributor = 23; + // Wavelet version and timestamp when the document was last modified. + required int64 lastModifiedVersion = 5 [(int52) = true]; + required int64 lastModifiedTime = 6 [(int52) = true]; +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/b15695b9/wave/src/proto/proto/org/waveprotocol/wave/federation/federation.protodevel ---------------------------------------------------------------------- diff --git a/wave/src/proto/proto/org/waveprotocol/wave/federation/federation.protodevel b/wave/src/proto/proto/org/waveprotocol/wave/federation/federation.protodevel new file mode 100644 index 0000000..4163a4d --- /dev/null +++ b/wave/src/proto/proto/org/waveprotocol/wave/federation/federation.protodevel @@ -0,0 +1,247 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Google Wave Federation Protocol data structures. +// +// They are intended to be equivalent to the data structures in the +// draft "Google Wave Federation Protocol Over XMPP" at +// http://code.google.com/p/wave-protocol/source +// +// Author: thorog...@google.com (Sam Thorogood), so...@google.com (Soren Lassen) + +syntax = "proto2"; + +package federation; + +import "org/apache/wave/pst/protobuf/extensions.proto"; + +option java_package = "org.waveprotocol.wave.federation"; +option java_outer_classname = "Proto"; + +/** + * An immutable list of operations for contribution to a wavelet. + * Specifies the contributor and the wavelet version that the + * operations are intended to be applied to. The host wave server + * may apply the operations to the wavelet at the specified wavelet version + * or it may accept them at a later version after operational transformation + * against the operations at the intermediate wavelet versions. + */ +message ProtocolWaveletDelta { + // Wavelet version that the delta is intended to be applied to. + required ProtocolHashedVersion hashed_version = 1; + + // Wave address of the contributor. Must be an explicit wavelet participant, + // and may be different from the originator of this delta. + required string author = 2; + + // Operations included in this delta. + repeated ProtocolWaveletOperation operation = 3; + + /* + * The nodes on the "overt" path from the originator through the address + * access graph leading up to (but excluding) the author. The path excludes + * any initial segments of the complete path which come before a WRITE edge + * in the graph. This field is empty if the author is either the originator's + * entry point into the address graph or is accessed by a WRITE edge. + * + * For example, "wave-disc...@acmewave.com" may be the explicit participant of + * a wavelet, and is set as the author of a delta. However, this group is + * being asked to act on behalf of "pe...@initech-corp.com", who is a member + * of "wave-authors", which is in turn a member of "wave-discuss". In this + * example, the delta would be configured as such: + * delta.author = "wave-disc...@acmewave.com" + * delta.addressPath = ["pe...@initech-corp.com", "wave-auth...@acmewave.com"] + */ + repeated string address_path = 4; +} + +/** + * Describes a wavelet version and the wavelet's history hash at that version. + */ +message ProtocolHashedVersion { + required int64 version = 1 [(int52) = true]; + required bytes history_hash = 2; +} + +/** + * An operation within a delta. Exactly one of the following seven fields must be set + * for this operation to be valid. + */ +message ProtocolWaveletOperation { + + // A document operation. Mutates the contents of the specified document. + message MutateDocument { + required string document_id = 1; + required ProtocolDocumentOperation document_operation = 2; + } + + // Adds a new participant (canonicalized wave address) to the wavelet. + optional string add_participant = 1; + + // Removes an existing participant (canonicalized wave address) from the wavelet. + optional string remove_participant = 2; + + // Mutates a document. + optional MutateDocument mutate_document = 3; + + // Does nothing. True if set. + optional bool no_op = 4; +} + +/** + * A list of mutation components. + */ +message ProtocolDocumentOperation { + + /** + * A component of a document operation. One (and only one) of the component + * types must be set. + */ + message Component { + + message KeyValuePair { + required string key = 1; + required string value = 2; + } + + message KeyValueUpdate { + required string key = 1; + // Absent field means that the attribute was absent/the annotation + // was null. + optional string old_value = 2; + // Absent field means that the attribute should be removed/the annotation + // should be set to null. + optional string new_value = 3; + } + + message ElementStart { + required string type = 1; + // MUST NOT have two pairs with the same key. + repeated KeyValuePair attribute = 2; + } + + message ReplaceAttributes { + // This field is set to true if and only if both oldAttributes and + // newAttributes are empty. It is needed to ensure that the optional + // replaceAttributes component field is not dropped during serialization. + optional bool empty = 1; + // MUST NOT have two pairs with the same key. + repeated KeyValuePair old_attribute = 2; + // MUST NOT have two pairs with the same key. + repeated KeyValuePair new_attribute = 3; + } + + message UpdateAttributes { + // This field is set to true if and only if attributeUpdates are empty. + // It is needed to ensure that the optional updateAttributes + // component field is not dropped during serialization. + optional bool empty = 1; + // MUST NOT have two updates with the same key. + repeated KeyValueUpdate attribute_update = 2; + } + + message AnnotationBoundary { + // This field is set to true if and only if both ends and changes are + // empty. It is needed to ensure that the optional annotationBoundary + // component field is not dropped during serialization. + optional bool empty = 1; + // MUST NOT have the same string twice. + repeated string end = 2; + // MUST NOT have two updates with the same key. MUST NOT + // contain any of the strings listed in the 'end' field. + repeated KeyValueUpdate change = 3; + } + + optional AnnotationBoundary annotation_boundary = 1; + optional string characters = 2; + optional ElementStart element_start = 3; + optional bool element_end = 4; + optional int32 retain_item_count = 5; + optional string delete_characters = 6; + optional ElementStart delete_element_start = 7; + optional bool delete_element_end = 8; + optional ReplaceAttributes replace_attributes = 9; + optional UpdateAttributes update_attributes = 10; + } + + repeated Component component = 1; +} + +/** + * Information generated about this delta post-applicaton. Used in + * ProtocolUpdate and ProtocolHistoryResponse. + */ +message ProtocolAppliedWaveletDelta { + required ProtocolSignedDelta signed_original_delta = 1; + optional ProtocolHashedVersion hashed_version_applied_at = 2; + required int32 operations_applied = 3; + required int64 application_timestamp = 4 [(int52) = true]; +} + +/** + * A canonicalised delta signed with a number of domain signatures. + */ +message ProtocolSignedDelta { + required bytes delta = 1; + repeated ProtocolSignature signature = 2; +} + +/** + * A signature for a delta. It contains the actual bytes of the signature, + * an identifier of the signer (usually the hash of a certificate chain), + * and an enum identifying the signature algorithm used. + */ +message ProtocolSignature { + + enum SignatureAlgorithm { + SHA1_RSA = 1; + } + + required bytes signature_bytes = 1; + required bytes signer_id = 2; + required SignatureAlgorithm signature_algorithm = 3; +} + +/** + * A certificate chain that a sender will refer to in subsequent signatures. + * + * The signer_id field in a ProtocolSignature refers to a ProtocolSignerInfo + * as follows: The certificates present in a ProtocolSignerInfo are encoded + * in PkiPath format, and then hashed using the hash algorithm indicated in the + * ProtocolSignerInfo. + */ +message ProtocolSignerInfo { + + enum HashAlgorithm { + SHA256 = 1; + SHA512 = 2; + } + + // The hash algorithm senders will use to generate an id that will refer to + // this certificate chain in the future + required HashAlgorithm hash_algorithm = 1; + + // The domain that this certificate chain was issued to. Receivers of this + // ProtocolSignerInfo SHOULD reject the ProtocolSignerInfo if the target + // certificate (the first one in the list) is not issued to this domain. + required string domain = 2; + + // The certificate chain. The target certificate (i.e., the certificate issued + // to the signer) is first, and the CA certificate (or one issued directly + // by the CA) is last. + repeated bytes certificate = 3; +} http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/b15695b9/wave/src/proto/proto/org/waveprotocol/wave/federation/federation_error.protodevel ---------------------------------------------------------------------- diff --git a/wave/src/proto/proto/org/waveprotocol/wave/federation/federation_error.protodevel b/wave/src/proto/proto/org/waveprotocol/wave/federation/federation_error.protodevel new file mode 100644 index 0000000..f6fbcb7 --- /dev/null +++ b/wave/src/proto/proto/org/waveprotocol/wave/federation/federation_error.protodevel @@ -0,0 +1,81 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Google Wave Federation Protocol error codes. +// +// Author: kal...@google.com (Benjamin Kalman) + +syntax = "proto2"; + +option java_package = "org.waveprotocol.wave.federation"; +option java_outer_classname = "FederationErrorProto"; + +package federation; + +/** + * Container for a Federation error, containing the error code (as per the + * specification) and an optional description for debugging etc. + * + * The internal enum has codes which must map directly to XMPP error stanzas, + * as defined in RFC 3920 (9.3.3). + * + * TODO(arb): Once the error codes have been audited and standardised, merge into federation.proto. + */ +message FederationError { + enum Code { + // Should only be used for internal success. + OK = 0; + + // Response for a completely broken request. + BAD_REQUEST = 1; + + // Either the wavelet does not exist, or the request is not authorised and + // thus should not reveal the existence of the target wavelet. + ITEM_NOT_FOUND = 2; + + // Revealable error conditions; including, but not limited to: + // + submit failed due to invalid delta + // + invalid signer info post + NOT_ACCEPTABLE = 3; + + // Signer info not available for delta submit. + NOT_AUTHORIZED = 4; + + // Generic 'back-off' message. + RESOURCE_CONSTRAINT = 5; + + // Undefined condition. This error will be generated if an error condition + // not otherwise contained within this protobuf is received over-the-wire. + UNDEFINED_CONDITION = 6; + + // Timeout error condition. Note that this may be generated internally + // as well as being valid on-the-wire. + REMOTE_SERVER_TIMEOUT = 7; + + // Request unexpected, wait requested. Note that this may be generated + // internally, notably if an in-flight ID is re-used. + UNEXPECTED_REQUEST = 8; + + // Internal server error, wait requested. + INTERNAL_SERVER_ERROR = 9; + } + + required Code error_code = 1; + optional string error_message = 2; + + // TODO(thorogood): Optional source of message field (i.e. wire/internal) for internal use? +}