Package tk.baumi.jaraco

Source Code of tk.baumi.jaraco.NetworkController$CloseSocket

package tk.baumi.jaraco;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;

import tk.baumi.jaraco.JaracoPlayer.PlayingChangeNetworkListener;
import tk.baumi.jaraco.JaracoPlayer.PlaylistChange;

/**
* <p>
* The class NetworkController is responsible for all networking operations.
* It registers observers to the Player and sends these informations to the client
* </p>
* <ul>
* <li>Playlist changes (whole playlist on each change)</li>
* <li>The current song (Artist + Title)</li>
* <li>Listing the files in the given folder</li>
* </ul>
*
* @author Manuel Baumgartner
*
*/
public class NetworkController {
  private ServerSocket server;
  private boolean serverRunning = true;
  private Thread thAcceptRun, thBroadcastRun;
  private JaracoPlayer playerInstance;
  private JaracoGUI guiInstance;
  private PlaylistChange playlistChange;
  private PlayingChangeNetworkListener playChangeNetwork;
  private ArrayList<Socket> clients;
  private CloseSocket socketClose;
 
  public interface CloseSocket{
    public void closeSocket();
  }
  /**
   * A broadcast sends a byte-stream to all connected clients.<br/>
   * This could be the playlist or the currently played song.
   * @param message The message as byte-array (MTU 1024)
   */
  public void sendBroadcast(byte[] message) {
    for(int i = 0; i < clients.size(); i++) {
      Socket client = clients.get(i);
      if(client != null && client.isConnected()) {
        try {
          client.getOutputStream().write(message);
        } catch (IOException e) {
          try {
            client.close();
          } catch (IOException e1) {
            e1.printStackTrace();
          }
        }
      } else {
        try {
          client.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  }
  /**
   * The Broadcast-run is responsible for receiving broadcast messages
   * from the network <br/>
   * It shows the availability to the non-yet-connected users.
   */
  Runnable broadcastRun = new Runnable() {

    @Override
    public void run() {
      try {
        DatagramSocket udp = new DatagramSocket(8802);
        byte[] buf = new byte[8];
        DatagramPacket udpreceive = new DatagramPacket(buf, 8);
        DatagramPacket udpsend;
        udp.setBroadcast(true);
        udp.setSoTimeout(1000);
       
        while(serverRunning) {
          try{
            udp.receive(udpreceive);
            byte[] addr = InetAddress.getLocalHost().getHostName().getBytes();
            SocketAddress socketSender = udpreceive.getSocketAddress();
            udpsend = new DatagramPacket(addr, addr.length, socketSender);
            udp.send(udpsend);
          } catch (Exception ex) {
            //An exception will be thrown thrown
            //if there it no packet to receive.
          }
        }
        udp.close();
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
   
  };
  /**
   * The acceptRun is the actual listener of the server.
   * It provides client
   */
  Runnable acceptRun = new Runnable() {
   
    @Override
    public void run() {
      while(serverRunning) {
        try {
          Socket client = server.accept();
          clients.add(client);
          final String name = client.getInetAddress().getHostName();
          javax.swing.SwingUtilities.invokeLater(new Runnable() {
           
            @Override
            public void run() {
              guiInstance.addUser(name);
            }
          });
          Thread thClient = new Thread(new DeserveClientThread(client, name));
          thClient.start();
        } catch (Exception e) {
        }
      }
    }
  };
  /**
   * <p>This Runnable deserves each client with waiting for a request.</p>
   * <p>It provides functions for operations:
   * <ul>
   * <li>Play/Pause</li>
   * <li>Stop</li>
   * <li>Play the previous file</li>
   * <li>Play the next file</li>
   * <li>List a folder</li>
   * <li>Add a song to the playlist</li>
   * <li>Upload a file
   * `  <ul>
   *     <li>Opens the upload-mode</li>
   *     <li>Closes the upload mode, when file-transmission is finished</li>
   *     </ul>
   * </li>
   * @author Manuel Baumgartner
   *
   */
  class DeserveClientThread implements Runnable{
    private Socket client;
    private String name;
    //private byte[] key;
   
    public DeserveClientThread(Socket client, String name) {
      this.client = client;
      this.name = name;
      try {
        client.setSoTimeout(1000);
      } catch (SocketException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    /**
     * Lists all elements of a folder.
     * Each element has it's own first character. <br/>
     *     If the first character is d --> folder<br/>
     *     If the first character is f --> file<br/>
     * @param folder The path of the folder.
     * @return The elements of the folder
     */
    public String[] getFolder(String folder) {
      folder = folder.replace('\\', File.separatorChar);
      File f = null;
      if(folder.contains(JaracoGUI.userMusic)) {
        f = new File(folder);
      } else {
        f = new File(JaracoGUI.userMusic + File.separator + folder);
      }
      File[] files = f.listFiles();
      Arrays.sort(files);
      String[] sf = new String[files.length];
      for(int i=0;i<files.length;i++) {
        if(files[i].isDirectory()) {
          sf[i] = "d" + files[i].getAbsolutePath();
        } else {
          sf[i] = "f" + files[i].getAbsolutePath();
        }
      }
      return sf;
    }
    @Override
    public void run() {
      byte[] buf;
      OutputStream osDl = null;
      boolean operation = false;
      //key = client.getInetAddress().getAddress();
      //SEND playlist
     
      File fDl = null;
     
     
      /*try {
        buf = out.getBytes("UTF-8");
        buf[0] = Jaraco.TYPE_PLAYLIST;
        client.getOutputStream().write(buf);
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }*/
     
      try {
        //client.setTcpNoDelay(true);
        client.setSendBufferSize(Jaraco.MTU);
      } catch (SocketException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      sendPlaylist(playerInstance.playListToString(), client);
     
      playChangeNetwork = new PlayingChangeNetworkListener() {
        /**
         * The changeplay here sends the information for the current played
         * file to all users.
         */
        @Override
        public void changePlay(int currFile, String filename, boolean playing, int currPos, int max) {
          try {
            String[] idtags = Jaraco.getIDTags(filename);
            byte[] str = (currFile + "\n" + idtags[0]+"\n" + idtags[2]+"\n"+"F\n"+"0\n0").getBytes("UTF-8");
            byte[] buf = new byte[Jaraco.MTU];
            buf[0] = Jaraco.TYPE_SONGNAME;
            for(int i = 0; i < str.length && (i+1) < buf.length; i++) {
              buf[i + 1] = str[i];
            }
            sendBroadcast(buf);
          } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      };
      try {
        client.setSendBufferSize(1);
      } catch (SocketException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
      }
      String[] playing = playerInstance.getCurrentFile();
        if(playing != null) {
        String[] idtags = Jaraco.getIDTags(playing[1]);
        try {
          byte[] str = (playing[0] + "\n" + idtags[0]+"\n" + idtags[2]+"\n"+"F\n"+"0\n0").getBytes("UTF-8");
          buf = new byte[Jaraco.MTU];
          buf[0] = Jaraco.TYPE_SONGNAME;
          for(int i = 0; i < str.length && (i+1) < buf.length; i++) {
            buf[i + 1] = str[i];
          }
          client.getOutputStream().write(buf);
          client.getOutputStream().flush();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
        try {
          client.setSendBufferSize(Jaraco.MTU);
        } catch (SocketException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
     
     
      while(serverRunning && client != null && client.isConnected()
          && !client.isClosed()) {
        try {
          if(operation) {
            buf = new byte[Jaraco.MTU];
          } else {
            buf = new byte[255];
          }
         
          int length = 0;
         
          length = client.getInputStream().read(buf);
         
          //buf = ipEn.decrypt(buf, key);
          try {
            if(length >= 0) {
              if(!operation) {
                if(buf[0] == 1) {
                  playerInstance.play();
                } else if(buf[0] == 2) {
                  playerInstance.stop();
                } else if(buf[0] == 3) {
                  playerInstance.playBefore();
                } else if(buf[0] == 4) {
                  playerInstance.playNext();
                } else if(buf[0] == Jaraco.TYPE_FOLDER) {
                  String folder = new String(buf, 1, length - 1, "UTF-8");
                  int index0 = folder.indexOf(0);
                  folder = folder.substring(0, index0);
                  System.out.println(folder);
                  String[] files = getFolder(folder);
                  byte[] b = new byte[Jaraco.MTU];
                  b[0] = Jaraco.TYPE_FOLDER;
                  client.setSendBufferSize(Jaraco.MTU);
                  int offset = 1;
                  for(int i = 0; i < files.length; i++) {
                    byte[] file = (files[i] + "\n").getBytes("UTF-8");
                    if(offset + file.length < Jaraco.MTU) {
                      for(int j = 0; j < file.length; j++) {
                        b[offset] = file[j];
                        offset++;
                      }
                    } else {
                      client.getOutputStream().write(b);
                      client.getOutputStream().flush();
                      b = new byte[Jaraco.MTU];
                      b[0] = Jaraco.TYPE_FOLDER_ADD;
                      offset = 1;
                      for(int j = 0; j < file.length; j++) {
                        b[offset] = file[j];
                        offset++;
                      }
                    }
                  }
                  client.getOutputStream().write(b);
                  client.getOutputStream().flush();
                  //Thread.sleep(10);
                } else if(buf[0] == Jaraco.TYPE_ADDSONG) {
                  String folder = new String(buf, 1, length - 1, "UTF-8");
                  System.out.println(folder);
                  int index0 = folder.indexOf(0);
                  final String mfolder = folder.substring(0, index0);
                  javax.swing.SwingUtilities.invokeLater(new Runnable() {
                   
                    @Override
                    public void run() {
                      playerInstance.addFile(mfolder);
                    }
                  });
                } else if(buf[0] == Jaraco.TYPE_ULSONG) {
                  String folder = new String(buf, 1, length - 1, "UTF-8");
                  File fJaraco = new File(JaracoGUI.userMusic + File.separator + "jaraco");
                  if(!fJaraco.exists()) {
                    fJaraco.mkdir();
                  }
                  fDl = new File(fJaraco, folder.substring(folder.lastIndexOf("/") + 1));
                  fDl.createNewFile();
                  operation = true;
                  System.out.println("uploading " + folder);
                  osDl = new FileOutputStream(fDl);
                } else if(buf[0] == Jaraco.TYPE_PHONE_STOP) {
                  if(guiInstance.getPhoneStop()) {
                    if(playerInstance.isPlaying()) {
                      playerInstance.play();
                    }
                  }
                } else if(buf[0] == Jaraco.TYPE_VOTE) {
                  byte[] b = new byte[4];
                  b[0] = buf[1];
                  b[1] = buf[2];
                  b[2] = buf[3];
                  b[3] = buf[4];
                  int v = IPEncryption.byteArrayToInt(b);
                  System.out.println("Vote for " + v);
                  playerInstance.voteSong(v, client.getInetAddress());
                } else {
                  System.err.println("Invalid operation\n:"+new String(buf, 0, length, "UTF-8"));
                  clients.remove(client);
                  client.close();
                  client = null;
                }
              } else {
                if(osDl != null) {
                  String mEnd = new String(buf, "UTF-8");
                  //System.out.println(mEnd);
                  if(mEnd.startsWith("ENDOFMUSICFILE") || length <= 0) {
                    System.out.println("ENDING UPLOAD");
                    osDl.close();
                    operation = false;
                    osDl = null;
                    playerInstance.addFile(fDl.getAbsolutePath());
                    fDl = null;
                  } else if(mEnd.startsWith("ABORTTRANSMISS")) {
                    System.out.println("Aborted upload");
                    osDl.close();
                    fDl.delete();
                    operation = false;
                    osDl = null;
                    fDl = null;
                  } else {
                    osDl.write(buf, 0, length);
                  }
                }
              }
            } else {
              clients.remove(client);
              client.close();
              client = null;
            }
          } catch (Exception ex) {
            ex.printStackTrace();
          }
        } catch (SocketTimeoutException ex) {
         
        } catch (IOException ex) {
         
        }
      }
      clients.remove(client);
      javax.swing.SwingUtilities.invokeLater(new Runnable() {
       
        @Override
        public void run() {
          guiInstance.removeUser(name);
        }
      });
    }
   
  }
  /**
   * Sends the whole given ArrayList<String> to all or the given socket.
   * @param playlist The given playlist as ArrayList
   * @param socket If null the playlist will be sent to all clients
   *       otherwise it will be sent to the given client.
   */
  public void sendPlaylist(ArrayList<String> playlist, Socket socket) {
    byte[] buf = new byte[Jaraco.MTU];
    int offset = 1;
   
    buf[0] = Jaraco.TYPE_PLAYLIST;
    try {
      for(int i = 0; i < playlist.size(); i++) {
        byte[] elem = (playlist.get(i) + "\n").getBytes("UTF-8");
        if(offset + elem.length >= buf.length) {
          if(socket != null) {
            socket.getOutputStream().write(buf);
            socket.getOutputStream().flush();
          } else {
            sendBroadcast(buf);
          }
          buf = new byte[Jaraco.MTU];
          buf[0] = Jaraco.TYPE_PLAYLIST_ADD;
          offset = 1;
          for(int j = 0; j < elem.length; j++) {
            buf[offset + j] = elem[j];
          }
          offset += elem.length;
        } else {
          int j = 0;
          for(; j < elem.length; j++) {
            buf[offset + j] = elem[j];
          }
          offset += elem.length;
        }
       
      }
      if(offset > 0) {
        if(socket != null) {
          socket.getOutputStream().write(buf);
          socket.getOutputStream().flush();
        } else {
          sendBroadcast(buf);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**
   * Initializes a new Network-TCP-Socket with the given port
   * For operations and listeners it needs the instance of the player and the GUI.
   * @param port The specified port (8800 should be the default port)
   * @param playerInstance The JaracoPlayer-object
   * @param guiInstance The JaracoGUI-object
   */
  public NetworkController(int port, JaracoPlayer playerInstance, JaracoGUI guiInstance) {
    try {
      serverRunning = true;
      this.playerInstance = playerInstance;
      this.guiInstance = guiInstance;
      clients = new ArrayList<Socket>();
      //ipEn = new IPEncryption();
      server = new ServerSocket(port);
      server.setSoTimeout(1000);
     
      thAcceptRun = new Thread(acceptRun);
      thAcceptRun.start();
     
      thBroadcastRun = new Thread(broadcastRun);
      thBroadcastRun.start();
     
      playChangeNetwork = new PlayingChangeNetworkListener() {
       
        @Override
        public void changePlay(int currFile, String filename, boolean playing, int curr, int max) {
          try {
            String[] idtags = Jaraco.getIDTags(filename);
            byte[] str = (currFile + "\n"
                  + idtags[0]+"\n"
                  + idtags[2]+"\n"
                  + (playing ? "T" : "F") + "\n"
                  + curr+"\n"
                  + max).getBytes("UTF-8");
            byte[] buf = new byte[Jaraco.MTU];
            buf[0] = Jaraco.TYPE_SONGNAME;
            for(int i = 0; i < str.length && (i+1) < buf.length; i++) {
              buf[i + 1] = str[i];
            }
            sendBroadcast(buf);
          } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      };
      /**
       * The playlist-change sends the current playlist without
       * a specified client.
       */
      playlistChange = new PlaylistChange() {
       
        @Override
        public void getPlaylist(ArrayList<String> playlist) {
          sendPlaylist(playlist, null);
        }
      };
     
      playerInstance.setPlaylistchange(playlistChange);
      playerInstance.setPlayingChangeNetworkListener(playChangeNetwork);
     
      socketClose = new CloseSocket() {
       
        @Override
        public void closeSocket() {
          serverRunning = false;
          thAcceptRun.interrupt();
          thAcceptRun = null;
        }
      };
     
      guiInstance.setCloseSocket(socketClose);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}
TOP

Related Classes of tk.baumi.jaraco.NetworkController$CloseSocket

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.