syntax = "proto3";

package daemon;
option go_package = "github.com/sagernet/sing-box/daemon";

import "google/protobuf/empty.proto";

service StartedService {
  rpc StopService(google.protobuf.Empty) returns (google.protobuf.Empty);
  rpc ReloadService(google.protobuf.Empty) returns (google.protobuf.Empty);

  rpc SubscribeServiceStatus(google.protobuf.Empty) returns(stream ServiceStatus) {}
  rpc SubscribeLog(google.protobuf.Empty) returns(stream Log) {}
  rpc GetDefaultLogLevel(google.protobuf.Empty) returns(DefaultLogLevel) {}
  rpc ClearLogs(google.protobuf.Empty) returns(google.protobuf.Empty) {}
  rpc SubscribeStatus(SubscribeStatusRequest) returns(stream Status) {}
  rpc SubscribeGroups(google.protobuf.Empty) returns(stream Groups) {}

  rpc GetClashModeStatus(google.protobuf.Empty) returns(ClashModeStatus) {}
  rpc SubscribeClashMode(google.protobuf.Empty) returns(stream ClashMode) {}
  rpc SetClashMode(ClashMode) returns(google.protobuf.Empty) {}

  rpc URLTest(URLTestRequest) returns(google.protobuf.Empty) {}
  rpc SelectOutbound(SelectOutboundRequest) returns (google.protobuf.Empty) {}
  rpc SetGroupExpand(SetGroupExpandRequest) returns (google.protobuf.Empty) {}

  rpc GetSystemProxyStatus(google.protobuf.Empty) returns(SystemProxyStatus) {}
  rpc SetSystemProxyEnabled(SetSystemProxyEnabledRequest) returns(google.protobuf.Empty) {}
  rpc TriggerDebugCrash(DebugCrashRequest) returns(google.protobuf.Empty) {}
  rpc TriggerOOMReport(google.protobuf.Empty) returns(google.protobuf.Empty) {}

  rpc SubscribeConnections(SubscribeConnectionsRequest) returns(stream ConnectionEvents) {}
  rpc CloseConnection(CloseConnectionRequest) returns(google.protobuf.Empty) {}
  rpc CloseAllConnections(google.protobuf.Empty) returns(google.protobuf.Empty) {}
  rpc GetDeprecatedWarnings(google.protobuf.Empty) returns(DeprecatedWarnings) {}
  rpc GetStartedAt(google.protobuf.Empty) returns(StartedAt) {}

  rpc SubscribeOutbounds(google.protobuf.Empty) returns (stream OutboundList) {}
  rpc StartNetworkQualityTest(NetworkQualityTestRequest) returns (stream NetworkQualityTestProgress) {}
  rpc StartSTUNTest(STUNTestRequest) returns (stream STUNTestProgress) {}
  rpc SubscribeTailscaleStatus(google.protobuf.Empty) returns (stream TailscaleStatusUpdate) {}
  rpc StartTailscalePing(TailscalePingRequest) returns (stream TailscalePingResponse) {}
}

message ServiceStatus {
  enum Type {
    IDLE = 0;
    STARTING = 1;
    STARTED = 2;
    STOPPING = 3;
    FATAL = 4;
  }
  Type status = 1;
  string errorMessage = 2;
}

message ReloadServiceRequest {
  string newProfileContent = 1;
}

message SubscribeStatusRequest {
  int64 interval = 1;
}

enum LogLevel {
  PANIC = 0;
  FATAL = 1;
  ERROR = 2;
  WARN = 3;
  INFO = 4;
  DEBUG = 5;
  TRACE = 6;
}

message Log {
  repeated Message messages = 1;
  bool reset = 2;
  message Message {
    LogLevel level = 1;
    string message = 2;
  }
}

message DefaultLogLevel {
  LogLevel level = 1;
}

message Status {
  uint64 memory = 1;
  int32 goroutines = 2;
  int32 connectionsIn = 3;
  int32 connectionsOut = 4;
  bool trafficAvailable = 5;
  int64 uplink = 6;
  int64 downlink = 7;
  int64 uplinkTotal = 8;
  int64 downlinkTotal = 9;
}

message Groups {
  repeated Group group = 1;
}

message Group {
  string tag = 1;
  string type = 2;
  bool selectable = 3;
  string selected = 4;
  bool isExpand = 5;
  repeated GroupItem items = 6;
}

message GroupItem {
  string tag = 1;
  string type = 2;
  int64 urlTestTime = 3;
  int32 urlTestDelay = 4;
}

message URLTestRequest {
  string outboundTag = 1;
}

message SelectOutboundRequest {
  string groupTag = 1;
  string outboundTag = 2;
}

message SetGroupExpandRequest {
  string groupTag = 1;
  bool isExpand = 2;
}

message ClashMode {
  string mode = 3;
}

message ClashModeStatus {
  repeated string modeList = 1;
  string currentMode = 2;
}

message SystemProxyStatus {
  bool available = 1;
  bool enabled = 2;
}

message SetSystemProxyEnabledRequest {
  bool enabled = 1;
}

message DebugCrashRequest {
  enum Type {
    GO = 0;
    NATIVE = 1;
  }

  Type type = 1;
}

message SubscribeConnectionsRequest {
  int64 interval = 1;
}

enum ConnectionEventType {
  CONNECTION_EVENT_NEW = 0;
  CONNECTION_EVENT_UPDATE = 1;
  CONNECTION_EVENT_CLOSED = 2;
}

message ConnectionEvent {
  ConnectionEventType type = 1;
  string id = 2;
  Connection connection = 3;
  int64 uplinkDelta = 4;
  int64 downlinkDelta = 5;
  int64 closedAt = 6;
}

message ConnectionEvents {
  repeated ConnectionEvent events = 1;
  bool reset = 2;
}

message Connection {
  string id = 1;
  string inbound = 2;
  string inboundType = 3;
  int32 ipVersion = 4;
  string network = 5;
  string source = 6;
  string destination = 7;
  string domain = 8;
  string protocol = 9;
  string user = 10;
  string fromOutbound = 11;
  int64 createdAt = 12;
  int64 closedAt = 13;
  int64 uplink = 14;
  int64 downlink = 15;
  int64 uplinkTotal = 16;
  int64 downlinkTotal = 17;
  string rule = 18;
  string outbound = 19;
  string outboundType = 20;
  repeated string chainList = 21;
  ProcessInfo processInfo = 22;
}

message ProcessInfo {
  uint32 processId = 1;
  int32 userId = 2;
  string userName = 3;
  string processPath = 4;
  repeated string packageNames = 5;
}

message CloseConnectionRequest {
  string id = 1;
}

message DeprecatedWarnings {
  repeated DeprecatedWarning warnings = 1;
}

message DeprecatedWarning {
  string message = 1;
  bool impending = 2;
  string migrationLink = 3;
  string description = 4;
  string deprecatedVersion = 5;
  string scheduledVersion = 6;
}

message StartedAt {
  int64 startedAt = 1;
}

message OutboundList {
  repeated GroupItem outbounds = 1;
}

message NetworkQualityTestRequest {
  string configURL = 1;
  string outboundTag = 2;
  bool serial = 3;
  int32 maxRuntimeSeconds = 4;
  bool http3 = 5;
}

message NetworkQualityTestProgress {
  int32 phase = 1;
  int64 downloadCapacity = 2;
  int64 uploadCapacity = 3;
  int32 downloadRPM = 4;
  int32 uploadRPM = 5;
  int32 idleLatencyMs = 6;
  int64 elapsedMs = 7;
  bool isFinal = 8;
  string error = 9;
  int32 downloadCapacityAccuracy = 10;
  int32 uploadCapacityAccuracy = 11;
  int32 downloadRPMAccuracy = 12;
  int32 uploadRPMAccuracy = 13;
}

message STUNTestRequest {
  string server = 1;
  string outboundTag = 2;
}

message STUNTestProgress {
  int32 phase = 1;
  string externalAddr = 2;
  int32 latencyMs = 3;
  int32 natMapping = 4;
  int32 natFiltering = 5;
  bool isFinal = 6;
  string error = 7;
  bool natTypeSupported = 8;
}

message TailscaleStatusUpdate {
  repeated TailscaleEndpointStatus endpoints = 1;
}

message TailscaleEndpointStatus {
  string endpointTag = 1;
  string backendState = 2;
  string authURL = 3;
  string networkName = 4;
  string magicDNSSuffix = 5;
  TailscalePeer self = 6;
  repeated TailscaleUserGroup userGroups = 7;
}

message TailscaleUserGroup {
  int64 userID = 1;
  string loginName = 2;
  string displayName = 3;
  string profilePicURL = 4;
  repeated TailscalePeer peers = 5;
}

message TailscalePeer {
  string hostName = 1;
  string dnsName = 2;
  string os = 3;
  repeated string tailscaleIPs = 4;
  bool online = 5;
  bool exitNode = 6;
  bool exitNodeOption = 7;
  bool active = 8;
  int64 rxBytes = 9;
  int64 txBytes = 10;
  int64 keyExpiry = 11;
}

message TailscalePingRequest {
  string endpointTag = 1;
  string peerIP = 2;
}

message TailscalePingResponse {
  double latencyMs = 1;
  bool isDirect = 2;
  string endpoint = 3;
  int32 derpRegionID = 4;
  string derpRegionCode = 5;
  string error = 6;
}
