Dart DocumentationTeamSpeakClient

Client class

class Client {
 /// Host the client will try to connect to
 final String host;

 /// Port the client will try to connnect on
 final int port;

 /// TCP-Socket that is used to do the communication
 Socket _zSocket;

 /// Data written to this stream is directly sent to the server.
 /// A newline is added automatically.
 final StreamController<String> _send = new StreamController();

 /// Counts lines received on the stream
 int _received_lines = 0;

 /// Returns the amount of lines received on the stream
 int get received_lines => _received_lines;

 /// Queue of commands that should be send to the server.
 /// This is necessary because the TeamSpeak-protocol is sequential.
 final Queue<Command> _queue = new Queue();

 /// Last command sent to the server
 Command _lastcommand;

 /// Command which was previously sent to the server and whose answer
 /// is currently pending
 Command get lastcommand => _lastcommand;

 /// Broadcast-Stream that holds lines received from the server
 Stream<String> _receive;
 
 /// Sets whether the client should throttle requests. This can be used
 /// to avoid getting disconnected by the server because of flooding.
 /// Requests are limited to one per two seconds. If there are more incoming
 /// requests, they will be buffered using the queue and are sent afterwards.
 bool enableThrottling = false;

 /// Returns the time the last command was sent to the server.
 DateTime _lastcommandsent = new DateTime.now();
 
 /// Checks whether a command is pending at the moment and executes the next
 /// one if not.
 void _checkPendingQueue(){
   // Wenn gerade kein Kommando ausgeführt wird...
   if(_lastcommand == null && _queue.isNotEmpty){
     if(enableThrottling && _lastcommandsent.difference(new DateTime.now()).inSeconds.abs() < 2){
       new Future.delayed(new Duration(seconds: 1)).then((dynamic pDyn){
         _checkPendingQueue();
       });
       return;
     }
     if(enableThrottling){
       _lastcommandsent = new DateTime.now();
     }
     Command lCommand = _queue.removeFirst();
     _send.add(lCommand.toString());
     _lastcommand = lCommand;
     bool lErrReceived = false;
     List<Map<String, String>> lItems;
     _receive
       .takeWhile((String pLine) => !lErrReceived)
       .listen((String pLine){
         
         if(pLine.startsWith("notify")){ // Notifications gehen uns nichts an
           return;
         }
         if(pLine.startsWith("error")){
           lErrReceived = true;
           // ToDo: Error / Bestätigung ausparsen
           final Map<String, String> lErr = Packet.parseItem(pLine
               .substring(pLine.indexOf(" "))
               .trim());
           if(lErr["id"] == "0"){
             final Answer lAnswer = new Answer(lItems, lErr);
             _lastcommand.gotAnswer(lAnswer);
           } else {
             _lastcommand.gotAnswerError(lErr);
           }
           _lastcommand = null;
           _checkPendingQueue();
         } else {
            lItems = pLine
                .split("|")
                .map((String pItem) => Packet.parseItem(pItem))
                .toList(growable: false);
         }
       });
   }
 }

 /// Initializes a new TeamSpeak-Client that is bound to the given host and port.
 /// The client will connect as soon as [connect] is executed.
 Client(String this.host, int this.port);

 /// Sends a new command. To retrieve the result of this command,
 /// you may use the returned future which is fired as soon as
 /// a result is received.
 Future<Answer> send(Command pCommand){
   _queue.add(pCommand);
   _checkPendingQueue();
   return pCommand.answer;
 }

 /// Registers for one type of notifications that are sent by the server.
 /// The name of the notification is the name of the notification without
 /// the leading "notify", e. g. "cliententerview" or "clientleftview".
 /// Since every message sent by the server is now checked if it is a 
 /// notification, the stream should be closed as soon as it isn't needed 
 /// anymore. There may be multiple listeners for the same type of
 /// notifications.
 Stream<Notification> registerNotification(String pNotification){
   return _receive.transform(new StreamTransformer<String, Notification>(
       handleData: (String pInput, EventSink pSink){
         if(pInput.startsWith("notify" + pNotification)){
           final String lString = pInput
               .substring(pInput.indexOf(" "))
               .trim();
           final Map<String, String> lParameters = Packet.parseItem(lString);
           final Notification lNotification = new Notification(pNotification, lParameters);
           pSink.add(lNotification);
         }
       }));
 }
 
 /// Connects to the host given when the client was initialized.
 Future connect(){
   return Socket.connect(host, port).then((Socket pSocket){
     _zSocket = pSocket;
     _receive = _zSocket
         .transform(new StringDecoder())
         .transform(new LineTransformer())
         .transform(new StreamTransformer<String, String>(
           handleData: (String pInput, EventSink<String> pSink){
             if(pInput.trim() != "") pSink.add(pInput);
           }))
         .asBroadcastStream();
     // ToDo: Dummy-Listener weg
     _receive.listen((pData){});
     _send.stream
       .transform(new StreamTransformer<String, String>(
         handleData: (String pInput, EventSink<String> pSink){
           pSink.add(pInput + "\n");
         }))
       .transform(new StringEncoder())
       .pipe(_zSocket);
     return _receive
       .take(2)
       .toList()
       .then((List<String> pList){
         if(pList[0] != "TS3"){
           return new Future.error("Invalid first message sent by server.");
         }
       });
   });
 }
}

Constructors

new Client(String host, int port) #

Initializes a new TeamSpeak-Client that is bound to the given host and port. The client will connect as soon as connect is executed.

Client(String this.host, int this.port);

Properties

bool enableThrottling #

Sets whether the client should throttle requests. This can be used to avoid getting disconnected by the server because of flooding. Requests are limited to one per two seconds. If there are more incoming requests, they will be buffered using the queue and are sent afterwards.

bool enableThrottling = false

final String host #

Host the client will try to connect to

final String host

final Command lastcommand #

Command which was previously sent to the server and whose answer is currently pending

Command get lastcommand => _lastcommand;

final int port #

Port the client will try to connnect on

final int port

final int received_lines #

Returns the amount of lines received on the stream

int get received_lines => _received_lines;

Methods

Future connect() #

Connects to the host given when the client was initialized.

Future connect(){
 return Socket.connect(host, port).then((Socket pSocket){
   _zSocket = pSocket;
   _receive = _zSocket
       .transform(new StringDecoder())
       .transform(new LineTransformer())
       .transform(new StreamTransformer<String, String>(
         handleData: (String pInput, EventSink<String> pSink){
           if(pInput.trim() != "") pSink.add(pInput);
         }))
       .asBroadcastStream();
   // ToDo: Dummy-Listener weg
   _receive.listen((pData){});
   _send.stream
     .transform(new StreamTransformer<String, String>(
       handleData: (String pInput, EventSink<String> pSink){
         pSink.add(pInput + "\n");
       }))
     .transform(new StringEncoder())
     .pipe(_zSocket);
   return _receive
     .take(2)
     .toList()
     .then((List<String> pList){
       if(pList[0] != "TS3"){
         return new Future.error("Invalid first message sent by server.");
       }
     });
 });
}

Stream<Notification> registerNotification(String pNotification) #

Registers for one type of notifications that are sent by the server. The name of the notification is the name of the notification without the leading "notify", e. g. "cliententerview" or "clientleftview". Since every message sent by the server is now checked if it is a notification, the stream should be closed as soon as it isn't needed anymore. There may be multiple listeners for the same type of notifications.

Stream<Notification> registerNotification(String pNotification){
 return _receive.transform(new StreamTransformer<String, Notification>(
     handleData: (String pInput, EventSink pSink){
       if(pInput.startsWith("notify" + pNotification)){
         final String lString = pInput
             .substring(pInput.indexOf(" "))
             .trim();
         final Map<String, String> lParameters = Packet.parseItem(lString);
         final Notification lNotification = new Notification(pNotification, lParameters);
         pSink.add(lNotification);
       }
     }));
}

Future<Answer> send(Command pCommand) #

Sends a new command. To retrieve the result of this command, you may use the returned future which is fired as soon as a result is received.

Future<Answer> send(Command pCommand){
 _queue.add(pCommand);
 _checkPendingQueue();
 return pCommand.answer;
}