package com.jetbrains.lang.dart.pubServer; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.*; import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.lang.dart.sdk.DartSdk; import com.jetbrains.lang.dart.util.PubspecYamlUtil; import io.netty.channel.Channel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import org.jetbrains.annotations.NotNull; import org.jetbrains.builtInWebServer.ConsoleManager; import java.util.Collection; import java.util.concurrent.ExecutionException; public class PubServerManager implements Disposable { private static final Logger LOG = Logger.getInstance(PubServerManager.class); private final Project project; private final ConsoleManager consoleManager = new ConsoleManager(); private String myServedSdkVersion; private final LoadingCache<VirtualFile, PubServerService> myServedDirToPubService = CacheBuilder.newBuilder().build(new CacheLoader<VirtualFile, PubServerService>() { @Override public PubServerService load(@NotNull VirtualFile key) throws Exception { return new PubServerService(project, consoleManager); } }); @NotNull public static PubServerManager getInstance(@NotNull Project project) { return ServiceManager.getService(project, PubServerManager.class); } public PubServerManager(@NotNull Project project) { this.project = project; VirtualFileManager.getInstance() .addVirtualFileListener(new VirtualFileListener() { @Override public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) { if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) { contentsChanged(event); } } @Override public void beforeFileMovement(@NotNull final VirtualFileMoveEvent event) { contentsChanged(event); } @Override public void fileDeleted(@NotNull final VirtualFileEvent event) { contentsChanged(event); } @Override public void contentsChanged(@NotNull final VirtualFileEvent event) { final VirtualFile file = event.getFile(); if (PubspecYamlUtil.PUBSPEC_YAML.equals(file.getName()) && file.getFileSystem() == LocalFileSystem.getInstance()) { pubspecYamlChanged(file); } } }, project); } private void pubspecYamlChanged(@NotNull final VirtualFile file) { final VirtualFile mainDir = file.getParent(); if (mainDir == null) return; for (VirtualFile subdir : mainDir.getChildren()) { if (!subdir.isDirectory()) continue; final PubServerService service = myServedDirToPubService.getIfPresent(subdir); if (service != null) { Disposer.dispose(service); } } } public void send(@NotNull Channel clientChannel, @NotNull FullHttpRequest clientRequest, @NotNull HttpHeaders extraHeaders, @NotNull VirtualFile servedDir, @NotNull String pathForPubServer) { final DartSdk sdk = DartSdk.getDartSdk(project); if (sdk != null && !sdk.getVersion().equals(myServedSdkVersion)) { stopAllPubServerProcesses(); myServedSdkVersion = sdk.getVersion(); } try { // servedDir - web or test, direct child of directory containing pubspec.yaml myServedDirToPubService.get(servedDir).sendToPubServer(clientChannel, clientRequest, extraHeaders, servedDir, pathForPubServer); } catch (ExecutionException e) { LOG.error(e); } } public boolean hasAlivePubServerProcesses() { for (PubServerService service : myServedDirToPubService.asMap().values()) { if (service.isPubServerProcessAlive()) return true; } return false; } @Override public void dispose() { stopAllPubServerProcesses(); } public void stopAllPubServerProcesses() { for (PubServerService service : myServedDirToPubService.asMap().values()) { try { Disposer.dispose(service); } catch (Exception e) { LOG.error(e); } } } @NotNull public Collection<String> getAlivePubServerAuthorities(@NotNull final VirtualFile dartProjectRoot) { final Collection<String> result = new SmartList<>(); for (VirtualFile subdir : dartProjectRoot.getChildren()) { if (!subdir.isDirectory()) continue; final PubServerService service = myServedDirToPubService.getIfPresent(subdir); if (service == null) continue; ContainerUtil.addIfNotNull(result, service.getPubServeAuthority(subdir)); } return result; } }