go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/store/services.ts (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import { PrpcClientOptions } from '@chopsui/prpc-client';
    16  import { computed, untracked } from 'mobx';
    17  import {
    18    addDisposer,
    19    Instance,
    20    isAlive,
    21    SnapshotIn,
    22    SnapshotOut,
    23    types,
    24  } from 'mobx-state-tree';
    25  import { keepAlive } from 'mobx-utils';
    26  
    27  import { MAY_REQUIRE_SIGNIN } from '@/common/common_tags';
    28  import { POTENTIAL_PERM_ERROR_CODES } from '@/common/constants/rpc';
    29  import { BuildsService } from '@/common/services/buildbucket';
    30  import {
    31    ClustersService,
    32    TestHistoryService,
    33  } from '@/common/services/luci_analysis';
    34  import { MiloInternal } from '@/common/services/milo_internal';
    35  import { ResultDb } from '@/common/services/resultdb';
    36  import { PrpcClientExt } from '@/generic_libs/tools/prpc_client_ext';
    37  import { attachTags } from '@/generic_libs/tools/tag';
    38  
    39  import { AuthStateStore, AuthStateStoreInstance } from './auth_state';
    40  
    41  export const ServicesStore = types
    42    .model('ServicesStore', {
    43      id: types.optional(types.identifierNumber, () => Math.random()),
    44      authState: types.safeReference(AuthStateStore),
    45    })
    46    .views((self) => {
    47      function makeClient(opts: PrpcClientOptions) {
    48        // Don't track the access token so services won't be refreshed when the
    49        // access token is updated.
    50        return new PrpcClientExt(
    51          opts,
    52          () =>
    53            untracked(
    54              () => (isAlive(self) && self.authState?.value?.accessToken) || '',
    55            ),
    56          (e) => {
    57            if (POTENTIAL_PERM_ERROR_CODES.includes(e.code)) {
    58              attachTags(e, MAY_REQUIRE_SIGNIN);
    59            }
    60            throw e;
    61          },
    62        );
    63      }
    64  
    65      return {
    66        get resultDb() {
    67          if (!self.authState?.identity) {
    68            return null;
    69          }
    70          return new ResultDb(makeClient({ host: SETTINGS.resultdb.host }));
    71        },
    72        get testHistory() {
    73          if (!self.authState?.identity) {
    74            return null;
    75          }
    76          return new TestHistoryService(
    77            makeClient({ host: SETTINGS.luciAnalysis.host }),
    78          );
    79        },
    80        get milo() {
    81          if (!self.authState?.identity) {
    82            return null;
    83          }
    84          return new MiloInternal(
    85            makeClient({ host: '', insecure: location.protocol === 'http:' }),
    86          );
    87        },
    88        get builds() {
    89          if (!self.authState?.identity) {
    90            return null;
    91          }
    92          return new BuildsService(
    93            makeClient({ host: SETTINGS.buildbucket.host }),
    94          );
    95        },
    96        get clusters() {
    97          if (!self.authState?.identity) {
    98            return null;
    99          }
   100          return new ClustersService(
   101            makeClient({ host: SETTINGS.luciAnalysis.host }),
   102          );
   103        },
   104      };
   105    })
   106    .actions((self) => ({
   107      setDependencies({ authState }: { authState: AuthStateStoreInstance }) {
   108        self.authState = authState;
   109      },
   110      afterCreate() {
   111        // These computed properties contains internal caches. Keep them alive.
   112        addDisposer(self, keepAlive(computed(() => self.resultDb)));
   113        addDisposer(self, keepAlive(computed(() => self.testHistory)));
   114        addDisposer(self, keepAlive(computed(() => self.milo)));
   115        addDisposer(self, keepAlive(computed(() => self.builds)));
   116        addDisposer(self, keepAlive(computed(() => self.clusters)));
   117      },
   118    }));
   119  
   120  export type ServicesStoreInstance = Instance<typeof ServicesStore>;
   121  export type ServicesStoreSnapshotIn = SnapshotIn<typeof ServicesStore>;
   122  export type ServicesStoreSnapshotOut = SnapshotOut<typeof ServicesStore>;