
// adding a new message:
// within ClientMessage block, 
//     create a new field in the enum Type section (100s are meant to be normal messages; 1000s are meant to be errors).  It will have new field number X
//     create a optional message of the same name (but lower-case!  the json code requires this), and use the same field number X.
// then at bottom of the file (or wherever; just outside any existing blocks), add your message definition.

package jampb;

message ClientMessage {
    enum Type { 
        LOGIN                               = 100;
        LOGIN_ACK                           = 105;
        LOGOUT                              = 106;
        LOGOUT_ACK                          = 107;
        CONNECT_ACK                         = 108;
        LOGIN_MUSIC_SESSION                 = 110;
        LOGIN_MUSIC_SESSION_ACK             = 115;
        LEAVE_MUSIC_SESSION                 = 120;
        LEAVE_MUSIC_SESSION_ACK             = 125;
        HEARTBEAT                           = 130;
        HEARTBEAT_ACK                       = 135;
        SUBSCRIBE                           = 136;
        UNSUBSCRIBE                         = 137;
        SUBSCRIPTION_MESSAGE                = 138;
        SUBSCRIBE_BULK                      = 139;
        USER_STATUS                         = 141;
        DIAGNOSTIC                          = 142;

        // friend notifications
        FRIEND_UPDATE                       = 140;
        FRIEND_REQUEST                      = 145;
        FRIEND_REQUEST_ACCEPTED             = 150;
        FRIEND_SESSION_JOIN                 = 155;
        NEW_USER_FOLLOWER                   = 160;
        NEW_BAND_FOLLOWER                   = 161;

        // session invitations
        SESSION_INVITATION                      = 165;
        SESSION_ENDED                           = 166;
        JOIN_REQUEST                            = 167;
        JOIN_REQUEST_APPROVED                   = 168;
        JOIN_REQUEST_REJECTED                   = 169;
        SESSION_JOIN                            = 170;
        SESSION_DEPART                          = 171;
        MUSICIAN_SESSION_JOIN                   = 172;
        TRACKS_CHANGED                          = 173;
        SCHEDULED_SESSION_INVITATION            = 174;
        SCHEDULED_SESSION_RSVP                  = 175;
        SCHEDULED_SESSION_RSVP_APPROVED         = 176;
        SCHEDULED_SESSION_RSVP_CANCELLED        = 177;
        SCHEDULED_SESSION_RSVP_CANCELLED_ORG    = 178;
        SCHEDULED_SESSION_CANCELLED             = 179;
        SCHEDULED_SESSION_RESCHEDULED           = 180;
        SCHEDULED_SESSION_REMINDER              = 181;
        SCHEDULED_SESSION_COMMENT               = 182;
        SESSION_KICK                            = 183;

        // subscription-related
        SUBSCRIPTION_CHANGED                    = 195;

        // recording notifications
        MUSICIAN_RECORDING_SAVED            = 200;
        BAND_RECORDING_SAVED                = 205;
        RECORDING_STARTED                   = 210;
        RECORDING_ENDED                     = 215;
        RECORDING_MASTER_MIX_COMPLETE       = 220;
        DOWNLOAD_AVAILABLE                  = 221;
        RECORDING_STREAM_MIX_COMPLETE       = 222;

        // band notifications
        BAND_INVITATION                     = 225;
        BAND_INVITATION_ACCEPTED            = 230;
        BAND_SESSION_JOIN                   = 235;

        // text message
        TEXT_MESSAGE                        = 236;
        CHAT_MESSAGE                        = 237;
        SEND_CHAT_MESSAGE                   = 238;
        
        MUSICIAN_SESSION_FRESH              = 240;
        MUSICIAN_SESSION_STALE              = 245;


        // icecast notifications
        SOURCE_UP_REQUESTED                 = 250;
        SOURCE_DOWN_REQUESTED               = 251;
        SOURCE_UP                           = 252;
        SOURCE_DOWN                         = 253;

        // jamtracks notifications
        JAM_TRACK_SIGN_COMPLETE             = 260;
        JAM_TRACK_SIGN_FAILED               = 261;

        // jamtracks mixdown notifications
        MIXDOWN_SIGN_COMPLETE               = 270;
        MIXDOWN_SIGN_FAILED                 = 271;

        LESSON_MESSAGE                      = 280;
        SCHEDULED_JAMCLASS_INVITATION       = 281;

        TEST_SESSION_MESSAGE                = 295;

        PING_REQUEST                        = 300;
        PING_ACK                            = 305;
        PEER_MESSAGE                        = 310;
        TEST_CLIENT_MESSAGE                 = 315;

        // operational messages
        CLIENT_UPDATE                      = 400;
        GENERIC_MESSAGE                    = 401;
        RELOAD                             = 402;
        RESTART_APPLICATION                = 403;
        STOP_APPLICATION                   = 404;

        // jamblaster messages
        PAIR_ATTEMPT                       = 500;

        SERVER_BAD_STATE_RECOVERED          = 900;

        SERVER_GENERIC_ERROR                = 1000;
        SERVER_REJECTION_ERROR              = 1005;
        SERVER_PERMISSION_ERROR             = 1010;
        SERVER_BAD_STATE_ERROR              = 1015;
        SERVER_DUPLICATE_CLIENT_ERROR       = 1016;
    }

    // Identifies which inner message is filled in
    required Type type = 1;
    required string route_to = 2;
    optional string from = 3;
    optional string message_id = 4;
    optional string in_reply_to = 5;
    
    // One of the following messages can be populated:

    // Client-Server messages (to/from)
    optional Login                      login = 100; // to server
    optional LoginAck                   login_ack = 105; // from server
    optional Logout                     logout = 106; // to server
    optional LogoutAck                  logout_ack = 107; // from server
    optional ConnectAck                 connect_ack = 108; // from server
    optional LoginMusicSession          login_music_session = 110; // to server
    optional LoginMusicSessionAck       login_music_session_ack = 115; // from server
    optional LeaveMusicSession          leave_music_session = 120;
    optional LeaveMusicSessionAck       leave_music_session_ack = 125;
    optional Heartbeat                  heartbeat = 130;
    optional HeartbeatAck               heartbeat_ack = 135;
    optional Subscribe                  subscribe = 136;
    optional Unsubscribe                unsubscribe = 137;
    optional SubscriptionMessage        subscription_message = 138;
    optional SubscribeBulk              subscribe_bulk = 139;
    optional UserStatus                 user_status = 141;
    optional Diagnostic                 diagnostic = 142;

    // friend notifications
    optional FriendUpdate               friend_update = 140; // from server to all friends of user
    optional FriendRequest              friend_request = 145;
    optional FriendRequestAccepted      friend_request_accepted = 150;
    optional NewUserFollower            new_user_follower = 160;
    optional NewBandFollower            new_band_follower = 161;
    
    // session invitations
    optional SessionInvitation                  session_invitation = 165; // from server to user
    optional SessionEnded                       session_ended = 166;
    optional JoinRequest                        join_request = 167;
    optional JoinRequestApproved                join_request_approved = 168;
    optional JoinRequestRejected                join_request_rejected = 169;
    optional SessionJoin                        session_join = 170;
    optional SessionDepart                      session_depart = 171;
    optional MusicianSessionJoin                musician_session_join = 172;
    optional TracksChanged                      tracks_changed = 173;

    // scheduled sessions
    optional ScheduledSessionInvitation         scheduled_session_invitation = 174;
    optional ScheduledSessionRsvp               scheduled_session_rsvp = 175;
    optional ScheduledSessionRsvpApproved       scheduled_session_rsvp_approved = 176;
    optional ScheduledSessionRsvpCancelled      scheduled_session_rsvp_cancelled = 177;
    optional ScheduledSessionRsvpCancelledOrg   scheduled_session_rsvp_cancelled_org = 178;
    optional ScheduledSessionCancelled          scheduled_session_cancelled = 179;
    optional ScheduledSessionRescheduled        scheduled_session_rescheduled = 180;
    optional ScheduledSessionReminder           scheduled_session_reminder = 181;
    optional ScheduledSessionComment            scheduled_session_comment = 182;
    optional SessionKick                        session_kick = 183;

    // subscription-related
    optional SubscriptionChanged                subscription_changed = 195;

    // recording notifications
    optional MusicianRecordingSaved     musician_recording_saved = 200;
    optional BandRecordingSaved         band_recording_saved = 205;
    optional RecordingStarted           recording_started = 210;
    optional RecordingEnded             recording_ended = 215;
    optional RecordingMasterMixComplete recording_master_mix_complete = 220;
    optional DownloadAvailable          download_available = 221;
    optional RecordingStreamMixComplete recording_stream_mix_complete = 222;

    // band notifications
    optional BandInvitation             band_invitation = 225;
    optional BandInvitationAccepted     band_invitation_accepted = 230;
    optional BandSessionJoin            band_session_join = 235;

    // text message
    optional TextMessage                text_message = 236;
    optional ChatMessage                chat_message = 237;
    optional SendChatMessage            send_chat_message = 238;

    optional MusicianSessionFresh       musician_session_fresh = 240;
    optional MusicianSessionStale       musician_session_stale = 245;

    // icecast notifications
    optional SourceUpRequested          source_up_requested = 250;
    optional SourceDownRequested        source_down_requested = 251;
    optional SourceUp                   source_up = 252;
    optional SourceDown                 source_down = 253;

    // jamtracks notification
    optional JamTrackSignComplete       jam_track_sign_complete = 260;
    optional JamTrackSignFailed         jam_track_sign_failed = 261;

    // jamtrack mixdown notification
    optional MixdownSignComplete       mixdown_sign_complete = 270;
    optional MixdownSignFailed         mixdown_sign_failed = 271;

    // lesson notifications
    optional LessonMessage              lesson_message = 280;
    optional ScheduledJamclassInvitation scheduled_jamclass_invitation = 281;

    // Client-Session messages (to/from)  
    optional TestSessionMessage     test_session_message = 295;

    // Client-Client messages (to/from)
    optional PingRequest        ping_request = 300;
    optional PingAck            ping_ack = 305;
    optional PeerMessage        peer_message = 310;
    optional TestClientMessage  test_client_message = 315;

    // Server-to-All Client operational messages
    optional ClientUpdate client_update = 400;
    optional GenericMessage generic_message = 401;
    optional Reload reload = 402;
    optional RestartApplication restart_application = 403;
    optional StopApplication stop_application = 404;

    // JamBlaster messages
    optional PairAttempt pair_attempt = 500;

    // Server-to-Client special messages
    optional ServerBadStateRecovered server_bad_state_recovered = 900;

    // Server-to-Client errors 
    optional ServerGenericError server_generic_error = 1000;
    optional ServerRejectionError server_rejection_error = 1005;
    optional ServerPermissionError server_permission_error = 1010;
    optional ServerBadStateError server_bad_state_error = 1015;
    optional ServerDuplicateClientError server_duplicate_client_error = 1016;
}

// route_to: server
// sent from client to server to associate the connection with a user
// either supply a username/password, or just supply token
// if successful, a LoginAck is sent.
// if errored, a GenericServerError is sent and the connection is closed.
message Login {
    optional string username = 1; // username... could be email.  need to wait for prod requirements
    optional string password = 2; // a password
    optional string token = 3; // a token/cookie from previous successful login attempt or from 'token' field in .music file
    optional string client_id = 4; // if supplied, the server will accept this client_id as the unique Id of this client instance
    optional string reconnect_music_session_id = 5; // if supplied, the server will attempt to log the client into this session (designed for reconnect scenarios while in-session)
    optional string client_type = 6; // 'client', 'browser'
}

// route_to: client
// sent from server to client to let the client know the login was successful,
// and to also show the IP address of the client as seen by the server.
message LoginAck {
    optional string public_ip = 1;
    optional string client_id = 2; // a new client_id if none is supplied in Login, or just the original client_id echoed back
    optional string token = 3; // the remember me token.  This is useful if you logged in with username/password (otherwise it's just 'token' echoed back)
    optional int32  heartbeat_interval = 4; // set your heartbeat interval to this value
    optional string music_session_id = 5; // the music session that the user was in very recently (likely due to dropped connection)
    optional bool   reconnected = 6; // if reconnect_music_session_id is specified, and the server could log the user into that session, then true is returned. 
    optional string user_id = 7; // the database user id
    optional int32  connection_expire_time = 8; // this is how long the server gives you before killing your connection entirely after missing heartbeats
    optional ClientUpdate client_update = 9;
    optional string username = 10;
    optional int32  client_id_int = 11;
    repeated Ars arses = 12;
    optional SiteSubscription subscription = 13;
    optional string connection_policy = 14;
}

message ConnectAck {
    optional string public_ip = 1;
    optional string client_id = 2; // a new client_id if none is supplied in Login, or just the original client_id echoed back
    optional int32  heartbeat_interval = 3; // set your heartbeat interval to this value
    optional int32  connection_expire_time = 4; // this is how long the server gives you before killing your connection entirely after missing heartbeats
    optional ClientUpdate client_update = 5;
}

// route_to: server
// a logout ack is always sent
message Logout {

}

// route_to: client
// sent from server to client to let the client know the login was successful,
// and to also show the IP address of the client as seen by the server.
message LogoutAck {
    optional bool success = 1;
}


// route_to: server
// send from client to server to log in to a music session and be 'present'.
// if successful, a LoginMusicSessionAck is sent with error = false, and Client-Session messages will be passed 
// directly from client to all other client. Also, the server will generate a 'UserJoinedMusicSession' message
// and send it to all other users to let the others know the user is here.
// if errored, a LoginMusicSessionAck is sent with error = true.
message LoginMusicSession {
   optional string music_session = 1; 
}

// route_to: client
// error = true if the LoginMusicSession command failed.
message LoginMusicSessionAck {
    optional bool error = 1;
    optional string error_reason = 2;
}

// route_to: server
// send from client to server to leave a previously joined music session
message LeaveMusicSession {
    optional string music_session = 1;
}

// route_to: client
// error = true if the session didn't exist, but otherwise this is intended to always work barring server unrecoverable errors
message LeaveMusicSessionAck {
    optional bool error = 1;
    optional string error_reason = 2;
}

message FriendUpdate {
    optional string user_id = 1;
    optional string photo_url = 2;
    optional bool online = 3;
    optional string msg = 4;
}

message FriendRequest {
    optional string friend_request_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
}

message FriendRequestAccepted {
    optional string photo_url = 1;
    optional string msg = 2;
    optional string notification_id = 3;
    optional string created_at = 4;
}

message NewUserFollower {
    optional string photo_url = 1;
    optional string msg = 2;
    optional string notification_id = 3;
    optional string created_at = 4;
}

message NewBandFollower {
    optional string photo_url = 1;
    optional string msg = 2;
    optional string notification_id = 3;
    optional string created_at = 4;
}

message SessionInvitation {
    optional string session_id = 1;
    optional string msg = 2;
    optional string notification_id = 3;
    optional string created_at = 4;
}

message SessionEnded {
    optional string session_id = 1;
}

message JoinRequest {
    optional string join_request_id = 1;
    optional string session_id = 2;
    optional string photo_url = 3;
    optional string msg = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message JoinRequestApproved {
    optional string join_request_id = 1;
    optional string session_id = 2;
    optional string photo_url = 3;
    optional string msg = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message JoinRequestRejected {
    optional string join_request_id = 1;
    optional string session_id = 2;
    optional string photo_url = 3;
    optional string msg = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message SessionJoin {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional int32 track_changes_counter = 4;
    optional string source_user_id = 5;
    optional string client_id = 6;
}

message SessionDepart {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string recording_id = 4;
    optional int32 track_changes_counter = 5;
    optional string client_id = 6;
    optional string source_user_id = 7;
}

message TracksChanged {
    optional string session_id = 1;
    optional int32 track_changes_counter = 2;
}

message MusicianSessionJoin {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional bool fan_access = 3;
    optional bool musician_access = 4;
    optional bool approval_required = 5;
    optional string msg = 6;
    optional string notification_id = 7;
    optional string created_at = 8;
}

message ScheduledSessionInvitation {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string session_name = 4;
    optional string session_date = 5;
    optional string notification_id = 6;
    optional string created_at = 7;
}

message ScheduledSessionRsvp {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string user_id = 4;
    optional string instruments = 5;
    optional string session_name = 6;
    optional string session_date = 7;
    optional string notification_id = 8;
    optional string created_at = 9;
}

message ScheduledSessionRsvpApproved {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionRsvpCancelled {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionRsvpCancelledOrg {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionCancelled {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionRescheduled {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionReminder {
    optional string session_id = 1;
    optional string msg = 2;
    optional string session_name = 3;
    optional string session_date = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message ScheduledSessionComment {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string comment = 4;
    optional string session_name = 5;
    optional string session_date = 6;
    optional string notification_id = 7;
    optional string created_at = 8;
}

message SessionKick {
    optional string session_id = 1;
    optional string reason = 2;
}

message SubscriptionChanged {

}

message MusicianRecordingSaved {
    optional string recording_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
}

message BandRecordingSaved {
    optional string recording_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
}

message RecordingStarted {
    optional string photo_url = 1;
    optional string msg = 2;
}

message RecordingEnded {
    optional string photo_url = 1;
    optional string msg = 2;
}

message RecordingMasterMixComplete {
    optional string recording_id = 1;
    optional string band_id = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
    optional string claimed_recording_id = 6;
}

message RecordingStreamMixComplete {
    optional string recording_id = 1;
    optional string band_id = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
    optional string claimed_recording_id = 6;
}

message DownloadAvailable {

}

message BandInvitation {
    optional string band_invitation_id = 1;
    optional string band_id = 2;
    optional string photo_url = 3;
    optional string msg = 4;
    optional string notification_id = 5;
    optional string created_at = 6;
}

message BandInvitationAccepted {
    optional string band_invitation_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
}

message BandSessionJoin {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional bool fan_access = 3;
    optional bool musician_access = 4;
    optional bool approval_required = 5;
    optional string msg = 6;
    optional string notification_id = 7;
    optional string created_at = 8;
}

message TextMessage {
    optional string photo_url         = 1;
    optional string sender_name       = 2;
    optional string sender_id         = 3;
    optional string msg               = 4;
    optional string notification_id   = 5;
    optional string created_at        = 6;
    optional bool   clipped_msg       = 7;
}

message ChatMessage {
    optional string sender_name       = 1;
    optional string sender_id         = 2;
    optional string msg               = 3;
    optional string msg_id            = 4;
    optional string created_at        = 5;
    optional string channel           = 6;
    optional string lesson_session_id = 7;
    optional string purpose           = 8;
    optional string attachment_id     = 9;
    optional string attachment_type   = 10;
    optional string attachment_name   = 11;

}

message SendChatMessage {
    optional string msg               = 1;
    optional string channel           = 2;
}

// route_to: client:
// sent by server to let the rest of the participants know a client has become active again after going stale 
message MusicianSessionFresh {
    optional string session_id = 1; // the session ID
    optional string user_id = 2; // this is the user_id and can be used for user unicast messages
    optional string username = 3; // meant to be a display name
    optional string photo_url = 4;
}

// route_to: client:
// sent by server to let the rest of the participants know a user has gone stale (websocket connection dropped) 
message MusicianSessionStale {
    optional string session_id = 1; // the session ID
    optional string user_id = 2; // this is the user_id and can be used for user unicast messages
    optional string username = 3; // meant to be a display name
    optional string photo_url = 4;
}

message SourceUpRequested {
   optional string music_session = 1; // music session id
   optional string host = 2; // icecast server host
   optional int32 port = 3; // icecast server port
   optional string mount = 4; // mount name
   optional string source_user = 5; // source user
   optional string source_pass = 6; // source pass
   optional int32 bitrate = 7;
}

message SourceDownRequested {
   optional string music_session = 1; // music session id
   optional string mount = 2; // mount name
}

message SourceUp {
   optional string music_session = 1; // music session id
}

message SourceDown {
   optional string music_session = 1; // music session id
}


message JamTrackSignComplete {
    required int32 jam_track_right_id = 1; // jam track right id
}

message JamTrackSignFailed {
    required int32 jam_track_right_id = 1; // jam track right id
}

message MixdownSignComplete {
    required string mixdown_package_id = 1; // jam track mixdown package id
}

message MixdownSignFailed {
    required string mixdown_package_id = 1; // jam track mixdown package id
}

message LessonMessage {
    optional string music_session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string notification_id = 4;
    optional string created_at = 5;
    optional string sender_id = 6;
    optional string receiver_id = 7;
    optional bool student_directed = 8;
    optional string purpose = 9;
    optional string sender_name = 10;
    optional string lesson_session_id = 11;
}

message ScheduledJamclassInvitation {
    optional string session_id = 1;
    optional string photo_url = 2;
    optional string msg = 3;
    optional string session_name = 4;
    optional string session_date = 5;
    optional string notification_id = 6;
    optional string created_at = 7;
    optional string lesson_session_id = 8;
}


message SubscriptionMessage {
   optional string type = 1; // the type of the subscription
   optional string id = 2; // data about what to subscribe to, specifically
   optional string body = 3; // this is a JSON string; let the browser decode it
}

message Subscribe {
   optional string type = 1; // the type of the subscription
   optional string id = 2; // data about what to subscribe to, specifically
}

message Unsubscribe {
   optional string type = 1; // the type of the subscription
   optional string id = 2; // data about what to subscribe to, specifically
}

message Subscription {
    optional string type = 1; // the type of the subscription
    optional string id = 2; // data about what to subscribe to, specifically
}

message SubscribeBulk {
    repeated string types = 1;
    repeated string ids = 2;
   //repeated Subscription subscriptions = 1; # the ruby protocol buffer library chokes on this.  so we have to do the above
}

message UserStatus {
    optional bool active = 1; // same as heartbeat 'active'... does the user appear present
    optional string status = 2;
}


message Diagnostic {
    optional string message = 1;
}

// route_to: session
// a test message used by ruby-client currently.  just gives way to send out to rest of session
message TestSessionMessage {
    optional string msg = 1;
}

// route_to: client:[CLIENT_ID]
// asks a client to begin a ping session
message PingRequest {
    
}

// route_to: client:[CLIENT_ID]
// tells a client to begin pinging a session
message PingAck {

}

// route_to: client:[CLIENT_ID]
// generic message between clients
message PeerMessage {
    optional string message = 1;
}

// route_to: client:[CLIENT_ID]
// a test message used by ruby-client currently.  just gives a way to send directly to another client
message TestClientMessage {
    optional string msg = 1;
}

// route_to: server
// sent from client to server periodically to let server track if the client is truly alive and avoid TCP timeout scenarios
// the server will send a HeartbeatAck in response to this
message Heartbeat {
    optional string notification_seen = 1;
    optional string notification_seen_at = 2;
    optional bool   active = 3; // is the user active?
}

// target: client
// sent from server to client in response to a Heartbeat
message HeartbeatAck {
  optional int32 track_changes_counter = 1;
}

// target: client
// this needs to go to *every* client when it occurs
message ClientUpdate {
  optional string product = 1;
  optional string version = 2;
  optional string uri     = 3;
  optional int32  size    = 4;
}

message SiteSubscription {
  optional int32 play_time_per_month = 1;
  optional int32 play_time_per_session = 2;
  optional bool can_record_audio = 3;
  optional bool can_use_video = 4;
  optional bool can_record_video = 5;
  optional bool can_record_wave = 6;
  optional int32 audio_max_bitrate = 7;
  optional int32 video_resolution = 8;
  optional bool can_broadcast = 9;
  optional int32 broadcasting_type = 10;
  optional int32 max_players = 11;
  optional bool pro_audio = 12;
  optional string name = 13;
}

message Ars {
  optional int32 id = 1;
  optional string ip = 2;
  optional string name = 3;
  optional string username = 4;
  optional string password = 5;
  optional int32 port = 6;
  optional string country = 7;
  optional string continent = 8;
  optional string subdivision = 9;
  optional double latitude = 10;
  optional double longitude = 11;
  optional string city = 12;
}

// target: client
// this is meant to be a way to poke clients and do something meaningful that we didn't plan in advance
message GenericMessage {
  optional string purpose = 1;
  optional string message = 2;
}

// target: client
// this is meant to be a way to poke clients to reload frontend
message Reload {
}

// target: client
// this is meant to be a way to poke clients to restart themselves
message RestartApplication {

}

// target: client
// this is meant to be a way to poke clients to stop themselves
message StopApplication {

}

message PairAttempt {
    optional string scid = 1;
    optional string vtoken = 2;
}

// route_to: client
// this should follow a ServerBadStateError in the case that the 
// websocket gateway recovers from whatever ailed it
message ServerBadStateRecovered {
}

// route_to: client
// this indicates unhandled error on server
// if you receive this, your connection will close after.
// but gives the client a chance to know why.
message ServerGenericError {
    optional string error_msg = 1;
}

// route_to: client
// this indicates the client did something wrong, and the server is mad enough to close connection.
// if you receive this, your connection will close after.
// but gives the client a chance to know why.
message ServerRejectionError {
    optional string error_msg = 1;
    optional string error_code = 2;
}

// route_to: client
// this indicates that the client doesn't have permission to ask the command
// your connection is not closed if this message occurs
message ServerPermissionError {
    optional string error_msg = 1;
}

// route_to: client
// this indicates that the server is in a bad state, but could recover later, and is unable to process the request
// your connection is not closed if this message occurs
message ServerBadStateError {
    optional string error_msg = 1;
}

// route_to: client
// this indicates that we detected another client with the same client ID
message ServerDuplicateClientError {
}


