//------------------------------------------------------------------------------
// Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
//
// 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.
//------------------------------------------------------------------------------

syntax = "proto3";

option csharp_namespace = "Emqx.Exhook.V1";
option go_package = "emqx.io/grpc/exhook";
option java_multiple_files = true;
option java_package = "io.emqx.exhook";
option java_outer_classname = "EmqxExHookProto";

package emqx.exhook.v1;

service HookProvider {

  rpc OnProviderLoaded(ProviderLoadedRequest) returns (LoadedResponse) {};

  rpc OnProviderUnloaded(ProviderUnloadedRequest) returns (EmptySuccess) {};

  rpc OnClientConnect(ClientConnectRequest) returns (EmptySuccess) {};

  rpc OnClientConnack(ClientConnackRequest) returns (EmptySuccess) {};

  rpc OnClientConnected(ClientConnectedRequest) returns (EmptySuccess) {};

  rpc OnClientDisconnected(ClientDisconnectedRequest) returns (EmptySuccess) {};

  rpc OnClientAuthenticate(ClientAuthenticateRequest) returns (ValuedResponse) {};

  rpc OnClientCheckAcl(ClientCheckAclRequest) returns (ValuedResponse) {};

  rpc OnClientSubscribe(ClientSubscribeRequest) returns (EmptySuccess) {};

  rpc OnClientUnsubscribe(ClientUnsubscribeRequest) returns (EmptySuccess) {};

  rpc OnSessionCreated(SessionCreatedRequest) returns (EmptySuccess) {};

  rpc OnSessionSubscribed(SessionSubscribedRequest) returns (EmptySuccess) {};

  rpc OnSessionUnsubscribed(SessionUnsubscribedRequest) returns (EmptySuccess) {};

  rpc OnSessionResumed(SessionResumedRequest) returns (EmptySuccess) {};

  rpc OnSessionDiscarded(SessionDiscardedRequest) returns (EmptySuccess) {};

  rpc OnSessionTakeovered(SessionTakeoveredRequest) returns (EmptySuccess) {};

  rpc OnSessionTerminated(SessionTerminatedRequest) returns (EmptySuccess) {};

  rpc OnMessagePublish(MessagePublishRequest) returns (ValuedResponse) {};

  rpc OnMessageDelivered(MessageDeliveredRequest) returns (EmptySuccess) {};

  rpc OnMessageDropped(MessageDroppedRequest) returns (EmptySuccess) {};

  rpc OnMessageAcked(MessageAckedRequest) returns (EmptySuccess) {};
}

//------------------------------------------------------------------------------
// Request & Response
//------------------------------------------------------------------------------

message ProviderLoadedRequest {

  BrokerInfo broker = 1;
}

message LoadedResponse {

  repeated HookSpec hooks = 1;
}

message ProviderUnloadedRequest { }

message ClientConnectRequest {

  ConnInfo conninfo = 1;

  // MQTT CONNECT packet's properties (MQTT v5.0)
  //
  // It should be empty on MQTT v3.1.1/v3.1 or others protocol
  repeated Property props = 2;
}

message ClientConnackRequest {

  ConnInfo conninfo = 1;

  string result_code = 2;

  repeated Property props = 3;
}

message ClientConnectedRequest {

  ClientInfo clientinfo = 1;
}

message ClientDisconnectedRequest {

  ClientInfo clientinfo = 1;

  string reason = 2;
}

message ClientAuthenticateRequest {

  ClientInfo clientinfo = 1;

  bool result = 2;
}

message ClientCheckAclRequest {

  ClientInfo clientinfo = 1;

  enum AclReqType {

    PUBLISH = 0;

    SUBSCRIBE = 1;
  }

  AclReqType type = 2;

  string topic = 3;

  bool result = 4;
}

message ClientSubscribeRequest {

  ClientInfo clientinfo = 1;

  repeated Property props = 2;

  repeated TopicFilter topic_filters = 3;
}

message ClientUnsubscribeRequest {

  ClientInfo clientinfo = 1;

  repeated Property props = 2;

  repeated TopicFilter topic_filters = 3;
}

message SessionCreatedRequest {

  ClientInfo clientinfo = 1;
}

message SessionSubscribedRequest {

  ClientInfo clientinfo = 1;

  string topic = 2;

  SubOpts subopts = 3;
}

message SessionUnsubscribedRequest {

  ClientInfo clientinfo = 1;

  string topic = 2;
}

message SessionResumedRequest {

  ClientInfo clientinfo = 1;
}

message SessionDiscardedRequest {

  ClientInfo clientinfo = 1;
}

message SessionTakeoveredRequest {

  ClientInfo clientinfo = 1;
}

message SessionTerminatedRequest {

  ClientInfo clientinfo = 1;

  string reason = 2;
}

message MessagePublishRequest {

  Message message = 1;
}

message MessageDeliveredRequest {

  ClientInfo clientinfo = 1;

  Message message = 2;
}

message MessageDroppedRequest {

  Message message = 1;

  string reason = 2;
}

message MessageAckedRequest {

  ClientInfo clientinfo = 1;

  Message message = 2;
}

//------------------------------------------------------------------------------
// Basic data types
//------------------------------------------------------------------------------

message EmptySuccess { }

message ValuedResponse {

  // The responsed value type
  //  - contiune: Use the responsed value and execute the next hook
  //  - ignore: Ignore the responsed value
  //  - stop_and_return: Use the responsed value and stop the chain executing
  enum ResponsedType {

    CONTINUE = 0;

    IGNORE = 1;

    STOP_AND_RETURN = 2;
  }

  ResponsedType type = 1;

  oneof value {

    // Boolean result, used on the 'client.authenticate', 'client.check_acl' hooks
    bool bool_result = 3;

    // Message result, used on the 'message.*' hooks
    Message message = 4;
  }
}

message BrokerInfo {

  string version = 1;

  string sysdescr = 2;

  string uptime = 3;

  string datetime = 4;
}

message HookSpec {

  // The registered hooks name
  //
  // Available value:
  //   "client.connect",      "client.connack"
  //   "client.connected",    "client.disconnected"
  //   "client.authenticate", "client.check_acl"
  //   "client.subscribe",    "client.unsubscribe"
  //
  //   "session.created",      "session.subscribed"
  //   "session.unsubscribed", "session.resumed"
  //   "session.discarded",    "session.takeovered"
  //   "session.terminated"
  //
  //   "message.publish", "message.delivered"
  //   "message.acked",   "message.dropped"
  string name = 1;

  // The topic filters for message hooks
  repeated string topics = 2;
}

message ConnInfo {

  string node = 1;

  string clientid = 2;

  string username = 3;

  string peerhost = 4;

  uint32 sockport = 5;

  string proto_name = 6;

  string proto_ver = 7;

  uint32 keepalive = 8;
}

message ClientInfo {

  string node = 1;

  string clientid = 2;

  string username = 3;

  string password = 4;

  string peerhost = 5;

  uint32 sockport = 6;

  string protocol = 7;

  string mountpoint = 8;

  bool  is_superuser = 9;

  bool  anonymous = 10;

  // common name of client TLS cert
  string cn = 11;

  // subject of client TLS cert
  string dn = 12;
}

message Message {

  string node = 1;

  string id = 2;

  uint32 qos = 3;

  string from = 4;

  string topic = 5;

  bytes  payload = 6;

  uint64 timestamp = 7;
}

message Property {

  string name = 1;

  string value = 2;
}

message TopicFilter {

  string name = 1;

  uint32 qos = 2;
}

message SubOpts {

  // The QoS level
  uint32 qos = 1;

  // The group name for shared subscription
  string share = 2;

  // The Retain Handling option (MQTT v5.0)
  //
  //  0 = Send retained messages at the time of the subscribe
  //  1 = Send retained messages at subscribe only if the subscription does
  //       not currently exist
  //  2 = Do not send retained messages at the time of the subscribe
  uint32 rh = 3;

  // The Retain as Published option (MQTT v5.0)
  //
  //  If 1, Application Messages forwarded using this subscription keep the
  //        RETAIN flag they were published with.
  //  If 0, Application Messages forwarded using this subscription have the
  //        RETAIN flag set to 0.
  // Retained messages sent when the subscription is established have the RETAIN flag set to 1.
  uint32 rap = 4;

  // The No Local option (MQTT v5.0)
  //
  // If the value is 1, Application Messages MUST NOT be forwarded to a
  // connection with a ClientID equal to the ClientID of the publishing
  uint32 nl = 5;
}
