summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/reducers/threads.js
blob: 81810595a0648c789e1d22a4351e8b9620197260 (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
113
114
115
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

// @flow

/**
 * Threads reducer
 * @module reducers/threads
 */

import { sortBy } from "lodash";
import { createSelector } from "reselect";

import type { Selector, State } from "./types";
import type { Thread, ThreadList, Worker } from "../types";
import type { Action } from "../actions/types";

export type ThreadsState = {
  threads: ThreadList,
  traits: Object,
  isWebExtension: boolean,
};

export function initialThreadsState(): ThreadsState {
  return {
    threads: [],
    traits: {},
    isWebExtension: false,
  };
}

export default function update(
  state: ThreadsState = initialThreadsState(),
  action: Action
): ThreadsState {
  switch (action.type) {
    case "CONNECT":
      return {
        ...state,
        traits: action.traits,
        isWebExtension: action.isWebExtension,
      };
    case "INSERT_THREAD":
      return {
        ...state,
        threads: [...state.threads, action.newThread],
      };

    case "REMOVE_THREAD":
      const { oldThread } = action;
      return {
        ...state,
        threads: state.threads.filter(
          thread => oldThread.actor != thread.actor
        ),
      };
    case "UPDATE_SERVICE_WORKER_STATUS":
      const { thread, status } = action;
      return {
        ...state,
        threads: state.threads.map(t => {
          if (t.actor == thread) {
            return { ...t, serviceWorkerStatus: status };
          }
          return t;
        }),
      };

    default:
      return state;
  }
}

export const getWorkerCount = (state: State) => getThreads(state).length;

export function getWorkerByThread(state: State, thread: string): ?Worker {
  return getThreads(state).find(worker => worker.actor == thread);
}

function isMainThread(thread: Thread) {
  return thread.isTopLevel;
}

export function getMainThread(state: State): ?Thread {
  return state.threads.threads.find(isMainThread);
}

export function getDebuggeeUrl(state: State): string {
  return getMainThread(state)?.url || "";
}

export const getThreads: Selector<Thread[]> = createSelector(
  state => state.threads.threads,
  threads => threads.filter(thread => !isMainThread(thread))
);

export const getAllThreads: Selector<Thread[]> = createSelector(
  getMainThread,
  getThreads,
  (mainThread, threads) =>
    [mainThread, ...sortBy(threads, thread => thread.name)].filter(Boolean)
);

export function getThread(state: State, threadActor: string) {
  return getAllThreads(state).find(thread => thread.actor === threadActor);
}

// checks if a path begins with a thread actor
// e.g "server1.conn0.child1/workerTarget22/context1/dbg-workers.glitch.me"
export function startsWithThreadActor(state: State, path: string): ?string {
  const threadActors = getAllThreads(state).map(t => t.actor);
  const match = path.match(new RegExp(`(${threadActors.join("|")})\/(.*)`));
  return match?.[1];
}