summaryrefslogtreecommitdiff
path: root/xml/impl/src/com/intellij/ide/browsers/BrowserStarter.java
blob: ca6726926d6f8c7917c9f550e7f5ba52e3bf9972 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.intellij.ide.browsers;

import com.google.common.net.HostAndPort;
import com.intellij.concurrency.JobScheduler;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Urls;
import com.intellij.util.net.NetUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * @author Sergey Simonchik
 */
public class BrowserStarter {
  private static final Logger LOG = Logger.getInstance(BrowserStarter.class);

  private final StartBrowserSettings mySettings;
  private final RunConfiguration myRunConfiguration;
  private final ProcessHandler myServerProcessHandler;

  public BrowserStarter(@NotNull RunConfiguration runConfiguration, @NotNull StartBrowserSettings settings, @NotNull ProcessHandler serverProcessHandler) {
    mySettings = settings;
    myRunConfiguration = runConfiguration;
    myServerProcessHandler = serverProcessHandler;
  }

  public void start() {
    if (!mySettings.isSelected() || mySettings.getUrl() == null) {
      return;
    }

    HostAndPort hostAndPort = getHostAndPort(mySettings.getUrl());
    if (hostAndPort != null) {
      checkAndOpenPageLater(hostAndPort, 1, 300);
    }
    else {
      // we can't check page availability gracefully, so we just open it after some delay
      openPageLater(1000);
    }
  }

  @Nullable
  private static HostAndPort getHostAndPort(@NotNull String rawUrl) {
    URI url = Urls.parseAsJavaUriWithoutParameters(rawUrl);
    if (url == null) {
      return null;
    }

    int port = url.getPort();
    if (port == -1) {
      port = "https".equals(url.getScheme()) ? 443 : 80;
    }
    return HostAndPort.fromParts(StringUtil.notNullize(url.getHost(), "127.0.0.1"), port);
  }

  private void checkAndOpenPageLater(@NotNull final HostAndPort hostAndPort, final int attemptNumber, int delayMillis) {
    JobScheduler.getScheduler().schedule(new Runnable() {
      @Override
      public void run() {
        checkAndOpenPage(hostAndPort, attemptNumber);
      }
    }, delayMillis, TimeUnit.MILLISECONDS);
  }

  private void checkAndOpenPage(@NotNull final HostAndPort hostAndPort, final int attemptNumber) {
    if (NetUtils.canConnectToRemoteSocket(hostAndPort.getHostText(), hostAndPort.getPort())) {
      openPageNow();
    }
    else {
      LOG.info("[attempt#" + attemptNumber + "] Checking " + hostAndPort + " failed");
      if (!isProcessTerminated()) {
        int delayMillis = getDelayMillis(attemptNumber);
        checkAndOpenPageLater(hostAndPort, attemptNumber + 1, delayMillis);
      }
    }
  }

  private static int getDelayMillis(int attemptNumber) {
    if (attemptNumber < 10) {
      return 400;
    }
    if (attemptNumber < 100) {
      return 1000;
    }
    return 2000;
  }

  private void openPageLater(int millis) {
    JobScheduler.getScheduler().schedule(new Runnable() {
      @Override
      public void run() {
        openPageNow();
      }
    }, millis, TimeUnit.MILLISECONDS);
  }

  private void openPageNow() {
    if (!isProcessTerminated()) {
      JavaScriptDebuggerStarter.Util.startDebugOrLaunchBrowser(myRunConfiguration, mySettings);
    }
  }

  private boolean isProcessTerminated() {
    return myServerProcessHandler.isProcessTerminating() || myServerProcessHandler.isProcessTerminated();
  }
}