 			}
 		}
 	}
-	
-	func send<T: Encodable>(object: T) throws {
-		let data = try settings.encode(object)
-		sockets.forEach { $0.send(data: data) { () in } }
-	}
+}
 
+// MARK: - SessionSocketDelegate
+extension Session: SessionSocketDelegate {
+	/// Called when a socket was remotely closed
+	///
+	/// - Parameter socket: the socket that closed
 	func closed(socket: SessionSocket) {
 		remove(socket: socket)
 	}
 	
+	/// Handle a command from a client
+	///
+	/// - Parameters:
+	///   - command: the command to handle
+	///   - socket: the client that sent the command
 	func handle(command: SessionCommand, socket: SessionSocket) {
 		Log.logger.info(message: "got command: \(command)", true)
+		switch command {
+		case .help(let topic):
+			handleHelp(topic: topic, socket: socket)
+		case .execute(let params):
+			handleExecute(params: params)
+		case .executeFile(let params):
+			handleExecuteFile(params: params)
+		case .fileOperation(let params):
+			handleFileOperation(params: params)
+		case .getVariable(let name):
+			handleGetVariable(name: name, socket: socket)
+		case .watchVariables(let enable):
+			handleWatchVaraibles(enable: enable, socket: socket)
+		case .save(let params):
+			handleSave(params: params, socket: socket)
+		}
+	}
+}
+
+// MARK: - Command Handling
+extension Session {
+	private func handleExecute(params: SessionCommand.ExecuteParams) {
+		
+	}
+	
+	private func handleExecuteFile(params: SessionCommand.ExecuteFileParams) {
+		
 	}
 
-	var hashValue: Int { return ObjectIdentifier(self).hashValue }
+	private func handleFileOperation(params: SessionCommand.FileOperationParams) {
+		
+	}
 	
-	static func == (lhs: Session, rhs: Session) -> Bool {
-		return lhs.workspace.id == rhs.workspace.id
+	private func handleGetVariable(name: String, socket: SessionSocket) {
+		
+	}
+	
+	private func handleWatchVaraibles(enable: Bool, socket: SessionSocket) {
+		
+	}
+	
+	private func handleSave(params: SessionCommand.SaveParams, socket: SessionSocket) {
+		
+	}
+	
+	private func handleHelp(topic: String, socket: SessionSocket) {
+		
 	}
 }

			lastClientDisconnectTime = nil
		}
		do {
			try send(object: try settings.dao.getUserInfo(user: socket.user))
		} catch {
			Log.logger.error(message: "failed to send BulkUserInfo \(error)", true)
		}
	}
	
	func remove(socket: SessionSocket) {
		lockQueue.sync {
			sockets.remove(socket)

		self.lockQueue = DispatchQueue(label: "workspace \(workspace.id)")
	}
	
	/// Hashable implementation
	var hashValue: Int { return ObjectIdentifier(self).hashValue }
	
	/// Equatable implementation
	static func == (lhs: Session, rhs: Session) -> Bool {
		return lhs.workspace.id == rhs.workspace.id
	}
}

// MARK: - client communications
extension Session {
	/// Send a message to all clients
	///
	/// - Parameter object: the message to send
	/// - Throws: any encoding errors
	func broadcastToAllClients<T: Encodable>(object: T) throws {
		let data = try settings.encode(object)
		sockets.forEach { $0.send(data: data) { () in } }
	}
}

// MARK: - Socket Management
extension Session {
	/// Add a socket/client to this session
	///
	/// - Parameter socket: the socket representing a new client
	func add(socket: SessionSocket) {
		lockQueue.sync {
			sockets.insert(socket)
