mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUAC-609: Migrate outbound clipboard integration to new streams.
This commit is contained in:
		| @@ -42,6 +42,7 @@ import org.glyptodon.guacamole.net.event.TunnelCloseEvent; | ||||
| import org.glyptodon.guacamole.net.event.TunnelConnectEvent; | ||||
| import org.glyptodon.guacamole.net.event.listener.TunnelCloseListener; | ||||
| import org.glyptodon.guacamole.net.event.listener.TunnelConnectListener; | ||||
| import org.glyptodon.guacamole.properties.GuacamoleProperties; | ||||
| import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| @@ -329,8 +330,19 @@ public class BasicTunnelRequestUtility { | ||||
|  | ||||
|             @Override | ||||
|             public GuacamoleReader acquireReader() { | ||||
|                 // Monitor instructions which pertain to server-side events | ||||
|                 return new MonitoringGuacamoleReader(clipboard, super.acquireReader()); | ||||
|  | ||||
|                 // Monitor instructions which pertain to server-side events, if necessary | ||||
|                 try { | ||||
|                     if (GuacamoleProperties.getProperty(CaptureClipboard.INTEGRATION_ENABLED, false)) | ||||
|                         return new MonitoringGuacamoleReader(clipboard, super.acquireReader()); | ||||
|                 } | ||||
|                 catch (GuacamoleException e) { | ||||
|                     logger.warn("Clipboard integration disabled due to error.", e); | ||||
|                 } | ||||
|  | ||||
|                 // Pass through by default. | ||||
|                 return super.acquireReader(); | ||||
|                  | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|   | ||||
| @@ -71,8 +71,11 @@ public class CaptureClipboard extends AuthenticatingHttpServlet { | ||||
|  | ||||
|             // Send clipboard contents | ||||
|             try { | ||||
|                 response.setContentType("text/plain"); | ||||
|                 response.getWriter().print(clipboard.waitForContents(CLIPBOARD_TIMEOUT)); | ||||
|                 synchronized (clipboard) { | ||||
|                     clipboard.waitForContents(CLIPBOARD_TIMEOUT); | ||||
|                     response.setContentType(clipboard.getMimetype()); | ||||
|                     response.getOutputStream().write(clipboard.getContents()); | ||||
|                 } | ||||
|             } | ||||
|             catch (IOException e) { | ||||
|                 throw new GuacamoleServerException("Unable to send clipboard contents", e); | ||||
|   | ||||
| @@ -31,11 +31,36 @@ package org.glyptodon.guacamole.net.basic; | ||||
|  */ | ||||
| public class ClipboardState { | ||||
|  | ||||
|     /** | ||||
|      * The maximum number of bytes to track. | ||||
|      */ | ||||
|     private static final int MAXIMUM_LENGTH = 262144; | ||||
|  | ||||
|      /** | ||||
|      * The mimetype of the current contents. | ||||
|      */ | ||||
|     private String mimetype = "text/plain"; | ||||
|  | ||||
|     /** | ||||
|      * The mimetype of the pending contents. | ||||
|      */ | ||||
|     private String pending_mimetype = "text/plain"; | ||||
|      | ||||
|     /** | ||||
|      * The current contents. | ||||
|      */ | ||||
|     private String contents = ""; | ||||
|     private byte[] contents = new byte[0]; | ||||
|  | ||||
|     /** | ||||
|      * The pending clipboard contents. | ||||
|      */ | ||||
|     private final byte[] pending = new byte[MAXIMUM_LENGTH]; | ||||
|  | ||||
|     /** | ||||
|      * The length of the pending data, in bytes. | ||||
|      */ | ||||
|     private int pending_length = 0; | ||||
|      | ||||
|     /** | ||||
|      * The timestamp of the last contents update. | ||||
|      */ | ||||
| @@ -45,38 +70,84 @@ public class ClipboardState { | ||||
|      * Returns the current clipboard contents. | ||||
|      * @return The current clipboard contents | ||||
|      */ | ||||
|     public synchronized String getContents() { | ||||
|     public synchronized byte[] getContents() { | ||||
|         return contents; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the current clipboard contents. | ||||
|      * @param contents The contents to assign to the clipboard. | ||||
|      * Returns the mimetype of the current clipboard contents. | ||||
|      * @return The mimetype of the current clipboard contents. | ||||
|      */ | ||||
|     public synchronized void setContents(String contents) { | ||||
|         this.contents = contents; | ||||
|         last_update = System.currentTimeMillis(); | ||||
|         this.notifyAll(); | ||||
|     public synchronized String getMimetype() { | ||||
|         return mimetype; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Wait up to the given timeout for new clipboard data. If data more recent | ||||
|      * than the timeout period is available, return that. | ||||
|      * Begins a new update of the clipboard contents. The actual contents will | ||||
|      * not be saved until commit() is called. | ||||
|      *  | ||||
|      * @param mimetype The mimetype of the contents being added. | ||||
|      */ | ||||
|     public synchronized void begin(String mimetype) { | ||||
|         pending_length = 0; | ||||
|         this.pending_mimetype = mimetype; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Appends the given data to the clipboard contents. | ||||
|      *  | ||||
|      * @param data The raw data to append. | ||||
|      */ | ||||
|     public synchronized void append(byte[] data) { | ||||
|  | ||||
|         // Calculate size of copy | ||||
|         int length = data.length; | ||||
|         int remaining = pending.length - pending_length; | ||||
|         if (remaining < length) | ||||
|             length = remaining; | ||||
|      | ||||
|         // Append data | ||||
|         System.arraycopy(data, 0, pending, pending_length, length); | ||||
|         pending_length += length; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Commits the pending contents to the clipboard, notifying any threads | ||||
|      * waiting for clipboard updates. | ||||
|      */ | ||||
|     public synchronized void commit() { | ||||
|  | ||||
|         // Commit contents | ||||
|         mimetype = pending_mimetype; | ||||
|         contents = new byte[pending_length]; | ||||
|         System.arraycopy(pending, 0, contents, 0, pending_length); | ||||
|  | ||||
|         // Notify of update | ||||
|         last_update = System.currentTimeMillis(); | ||||
|         this.notifyAll(); | ||||
|  | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Wait up to the given timeout for new clipboard data. | ||||
|      *  | ||||
|      * @param timeout The amount of time to wait, in milliseconds. | ||||
|      * @return The current clipboard contents. | ||||
|      * @return true if the contents were updated within the timeframe given, | ||||
|      *         false otherwise. | ||||
|      */ | ||||
|     public synchronized String waitForContents(int timeout) { | ||||
|     public synchronized boolean waitForContents(int timeout) { | ||||
|  | ||||
|         // Wait for new contents if it's been a while | ||||
|         if (System.currentTimeMillis() - last_update > timeout) { | ||||
|             try { | ||||
|                 this.wait(timeout); | ||||
|                 return true; | ||||
|             } | ||||
|             catch (InterruptedException e) { /* ignore */ } | ||||
|         } | ||||
|  | ||||
|         return getContents(); | ||||
|         return false; | ||||
|  | ||||
|     } | ||||
|      | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| package org.glyptodon.guacamole.net.basic; | ||||
|  | ||||
| import java.util.List; | ||||
| import javax.xml.bind.DatatypeConverter; | ||||
| import org.glyptodon.guacamole.GuacamoleException; | ||||
| import org.glyptodon.guacamole.io.GuacamoleReader; | ||||
| import org.glyptodon.guacamole.protocol.GuacamoleInstruction; | ||||
| @@ -45,6 +46,11 @@ public class MonitoringGuacamoleReader implements GuacamoleReader { | ||||
|      */ | ||||
|     private final ClipboardState clipboard; | ||||
|  | ||||
|     /** | ||||
|      * The index of the clipboard stream, if any. | ||||
|      */ | ||||
|     private String clipboard_stream_index = null; | ||||
|      | ||||
|     /** | ||||
|      * Creates a new MonitoringGuacamoleReader which watches the instructions | ||||
|      * read by the given GuacamoleReader, firing events when specific | ||||
| @@ -84,11 +90,31 @@ public class MonitoringGuacamoleReader implements GuacamoleReader { | ||||
|         if (instruction == null) | ||||
|             return null; | ||||
|  | ||||
|         // If clipboard changed, notify listeners | ||||
|         // If clipboard changing, reset clipboard state | ||||
|         if (instruction.getOpcode().equals("clipboard")) { | ||||
|             List<String> args = instruction.getArgs(); | ||||
|             if (args.size() >= 1) | ||||
|                 clipboard.setContents(args.get(0)); | ||||
|             if (args.size() >= 2) { | ||||
|                 clipboard_stream_index = args.get(0); | ||||
|                 clipboard.begin(args.get(1)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Add clipboard blobs to existing streams | ||||
|         else if (instruction.getOpcode().equals("blob")) { | ||||
|             List<String> args = instruction.getArgs(); | ||||
|             if (args.size() >= 2 && args.get(0).equals(clipboard_stream_index)) { | ||||
|                 String base64 = args.get(1); | ||||
|                 clipboard.append(DatatypeConverter.parseBase64Binary(base64)); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Terminate and update clipboard at end of stream | ||||
|         else if (instruction.getOpcode().equals("end")) { | ||||
|             List<String> args = instruction.getArgs(); | ||||
|             if (args.size() >= 1 && args.get(0).equals(clipboard_stream_index)) { | ||||
|                 clipboard.commit(); | ||||
|                 clipboard_stream_index = null; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         return instruction; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user