// Copyright 2018 The Nakama Authors
//
// Licensed 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 realtime protocol for Nakama server.
 */
syntax = "proto3";

package nakama.realtime;

import "google/protobuf/wrappers.proto";
import "github.com/heroiclabs/nakama/api/api.proto";

option go_package = "rtapi";

option java_multiple_files = true;
option java_outer_classname = "NakamaRealtime";
option java_package = "com.heroiclabs.nakama";

option csharp_namespace = "Nakama";

option objc_class_prefix = "NKPB";

// An envelope for a realtime message.
message Envelope {
  string cid = 1;
  oneof message {
    // Describes an error which occurred on the server.
    Error error = 2;
    // Incoming information about a realtime match.
    Match match = 3;
    // A client to server request to create a realtime match.
    MatchCreate match_create = 4;
    // Incoming realtime match data delivered from the server.
    MatchData match_data = 5;
    // A client to server request to send data to a realtime match.
    MatchDataSend match_data_send = 6;
    // A client to server request to join a realtime match.
    MatchJoin match_join = 7;
    // A client to server request to leave a realtime match.
    MatchLeave match_leave = 8;
    // Presence update for a particular realtime match.
    MatchPresenceEvent match_presence_event = 9;
    // Notifications send by the server.
    Notifications notifications = 10;
    // RPC call or response.
    api.Rpc rpc = 11;
    // A data message delivered over a stream.
    StreamData stream_data = 12;
    // Presence update for a particular stream.
    StreamPresenceEvent stream_presence_event = 13;
  }
}

// A logical error which may occur on the server.
message Error {
  // The selection of possible error codes.
  enum Code {
    // An unexpected result from the server.
    RUNTIME_EXCEPTION = 0;
    // The server received a message which is not recognised.
    UNRECOGNIZED_PAYLOAD = 1;
    // A message was expected but contains no content.
    MISSING_PAYLOAD = 2;
    // Fields in the message have an invalid format.
    BAD_INPUT = 3;
    // The match id was not found.
    MATCH_NOT_FOUND = 4;
    // The match join was rejected.
    MATCH_JOIN_REJECTED = 5;
    // The runtime function does not exist on the server.
    RUNTIME_FUNCTION_NOT_FOUND = 6;
    // The runtime function executed with an error.
    RUNTIME_FUNCTION_EXCEPTION = 7;
  }

  // The error code which should be one of "Error.Code" enums.
  int32 code = 1;
  // A message in English to help developers debug the response.
  string message = 2;
  // Additional error details which may be different for each response.
  map<string, string> context = 3;
}

// A realtime match.
message Match {
  // The match unique ID.
  string match_id = 1;
  // True if it's an server-managed authoritative match, false otherwise.
  bool authoritative = 2;
  // Match label, if any.
  google.protobuf.StringValue label = 3;
  // The number of users currently in the match.
  int32 size = 4;
  // The users currently in the match.
  repeated StreamPresence presences = 5;
  // A reference to the current user's presence in the match.
  StreamPresence self = 6;
}

// Create a new realtime match.
message MatchCreate {}

// Realtime match data received from the server.
message MatchData {
  // The match unique ID.
  string match_id = 1;
  // A reference to the user presence that sent this data, if any.
  StreamPresence presence = 2;
  // Op code value.
  int64 op_code = 3;
  // Data payload, if any.
  bytes data = 4;
}

// Send realtime match data to the server.
message MatchDataSend {
  // The match unique ID.
  string match_id = 1;
  // Op code value.
  int64 op_code = 2;
  // Data payload, if any.
  bytes data = 3;
  // List of presences in the match to deliver to, if filtering is required. Otherwise deliver to everyone in the match.
  repeated StreamPresence presences = 4;
}

// Join an existing realtime match.
message MatchJoin {
  oneof id {
    // The match unique ID.
    string match_id = 1;
    // A matchmaking result token.
    string token = 2;
  }
}

// Leave a realtime match.
message MatchLeave {
  // The match unique ID.
  string match_id = 1;
}

// A set of joins and leaves on a particular realtime match.
message MatchPresenceEvent {
  // The match unique ID.
  string match_id = 1;
  // User presences that have just joined the match.
  repeated StreamPresence joins = 2;
  // User presences that have just left the match.
  repeated StreamPresence leaves = 3;
}

// A collection of zero or more notifications.
message Notifications {
  // Collection of notifications.
  repeated api.Notification notifications = 1;
}

// Represents identifying information for a stream.
message Stream {
  // Mode identifies the type of stream.
  int32 mode = 1;
  // Subject is the primary identifier, if any.
  string subject = 2;
  // Descriptor is a secondary identifier, if any.
  string descriptor = 3;
  // The label is an arbitrary identifying string, if the stream has one.
  string label = 4;
}

// A data message delivered over a stream.
message StreamData {
  // The stream this data message relates to.
  Stream stream = 1;
  // The sender, if any.
  StreamPresence sender = 2;
  // Arbitrary contents of the data message.
  string data = 3;
}

// A user session associated to a stream, usually through a list operation or a join/leave event.
message StreamPresence {
  // The user this presence belongs to.
  string user_id = 1;
  // A unique session ID identifying the particular connection, because the user may have many.
  string session_id = 2;
  // The username for display purposes.
  string username = 3;
  // Whether this presence generates persistent data/messages, if applicable for the stream type.
  bool persistence = 4;
  // A user-set status message for this stream, if applicable.
  string status = 5;
}

// A set of joins and leaves on a particular stream.
message StreamPresenceEvent {
  // The stream this event relates to.
  Stream stream = 1;
  // Presences joining the stream as part of this event, if any.
  repeated StreamPresence joins = 2;
  // Presences leaving the stream as part of this event, if any.
  repeated StreamPresence leaves = 3;
}
