0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【やってみた】AWS Amplify を使用して Amazon Chime SDK アプリケーションを起動

Posted at

はじめに

Amazon Chime SDKで会議アプリの試用・検証する機会があったので、メモ書きです。

前提

node.js v22.13.0がインストールされていること
AWS CLIが実行できる環境になっていること

手順参考(英語サイト)

ReactとChime SDK関連のインストール

npx create-react-app react-sample --template typescript

を実行して、「y」で基本的なアプリの設定を実施する。

image.png

npm を動かすのが久しぶりだったので、最新Verが存在するよ!と言われたのでバージョンアップを実施しました。
image.png

cd react-sample
npm install

image.png

脆弱体の問題に対する改修版があるというので、指示どおりに当てる。

npm audit fix --force
npm audit

image.png

次に、Amazon Chime SDK React コンポーネントライブラリとピア依存関係を React アプリケーションのルートディレクトリにインストールするのですが、、、公開されてから、結構期間が経ってるようでバージョンの依存関係が成立しなくなっているようです。

npm install --save amazon-chime-sdk-component-library-react amazon-chime-sdk-js styled-components styled-system aws-amplify && npm install --save-dev @types/styled-components

image.png

「--legacy-peer-deps」のオプションをつけて無視しつつインストールしてみます。
また公式サイトの方を見ると、Ver3まで上がっている「@3付き」ので、最新にしてインストールする。

npm install --save --legacy-peer-deps amazon-chime-sdk-component-library-react@3 amazon-chime-sdk-js@3 styled-components styled-system aws-amplify && npm install --save-dev --legacy-peer-deps @types/styled-components

image.png

Amplifyのセットアップ

npm install -g @aws-amplify/cli

image.png

「プロジェクトをAmplifyプロジェクトとして初期化」で問題発生。。。

実行環境では、AWS SSOでCLIを実行しているのだけど、IAMユーザを使って固定のアクセスキーを払い出さないとセットアップをさせてくれない模様。。。
仕方ないので一時的にIAMユーザとアクセスキーを払い出して対応する。

海外ブログの手順になった設問だけメモ書き

⚠️ For new projects, we recommend starting with AWS Amplify Gen 2, our new code-first developer experience. Get started at https://docs.amplify.aws/react/start/quickstart/

新しいバージョンのAmplify(Gen2)があるのにGen1を使いますか?ってことで、「Yes」
Amplify(Gen2)は初期化の手順や思想が異なり、海外ブログの手順が全く役に立たなくなるほどの乖離があるため、Gen1で続行する。

√ Why would you like to use Amplify Gen 1? · I am a current Gen 1 user

選択肢は複数の中から選択できましたが、Gen1の既存ユーザだから。と無難な選択をする。

React関連のソースを手順書に従って置き換えていく。

  • \public\index.html
  • \src\components\Meeting.tsx
  • \src\components\MeetingForm.tsx
  • \src\index.tsx
  • \src\aws-exports.js (ファイルを残すだけ)

Amplifyのバックグラウンドの登録

  • Lambdaの追加の手順は、手順通りに、、、
  • GraphQLの追加で、問題発生。。。

どうもスキーマ定義がV1で書かれているが、現状はV2に書き直さないとダメな模様。

手順書のGraphQLのスキーマ定義

type Meeting @model(mutations: {create: "createMeetingGraphQL", delete: "deleteMeetingGraphQL"}, subscriptions: null) @key(fields: ["title"]){
  meetingId: String!
  title: String!
  data: String!
}

type Attendee @model(mutations: {create: "createAttendeeGraphQL", delete: "deleteAttendeeGraphQL"}, subscriptions: null) @key(fields: ["attendeeId"]){
  attendeeId: String!
  name: String!
}

type Query {
  createChimeMeeting(title: String, name: String, region: String): Response @function(name: "reactSampleLambda-${env}")
  joinChimeMeeting(meetingId: String, name: String): Response @function(name: "reactSampleLambda-${env}")
  endChimeMeeting(meetingId: String): Response  @function(name: "reactSampleLambda-${env}")
}

type Response {
  statusCode: String!
  headers: String
  body: String
  isBase64Encoded: String
}

V1→V2へのマイグレーション方法

@key の廃止と、@authの追加に対応しないといけないと。。。

type Meeting @model(mutations: {create: "createMeetingGraphQL", delete: "deleteMeetingGraphQL"}, subscriptions: null) 
@auth(rules: [{allow: owner}, {allow: private, operations:[read, create, update, delete]}])
{
  meetingId: String!
  title: String! @primaryKey
  data: String!
}

type Attendee @model(mutations: {create: "createAttendeeGraphQL", delete: "deleteAttendeeGraphQL"}, subscriptions: null) 
@auth(rules: [{allow: owner}, {allow: private, operations:[read, create, update, delete]}])
{
  attendeeId: String!  @primaryKey
  name: String!
}

type Query {
  createChimeMeeting(title: String, name: String, region: String): Response @function(name: "reactSampleLambda-${env}")
  joinChimeMeeting(meetingId: String, name: String): Response @function(name: "reactSampleLambda-${env}")
  endChimeMeeting(meetingId: String): Response  @function(name: "reactSampleLambda-${env}")
}

type Response {
  statusCode: String!
  headers: String
  body: String
  isBase64Encoded: String
}

上記のような形に書き直して、

amplify push

を実行した所、デプロイできた模様。

手順通りに、起動しようとしたところ、まだ依存関係問題が発生した。

npm install && npm run build && npm run start

ので、「 --legacy-peer-deps」のオプションを付けて実行する。

npm install && npm run build && npm run start

image.png

と、

'react-scripts' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。

'react-scripts'が一緒に入らなかった模様なので追加でインストールする。

npm install --legacy-peer-deps react-scripts

で、「--legacy-peer-deps」を忘れずに。。。

ここまできて、どうにも起動が、上手くいかないのでバージョン依存関係の解消に、本腰を入れて手を付ける。

npmのバージョンが新しすぎてダメなようなので10まで落とす。

npm install npm@10.0.0 -g

Reactのバージョンが新しすぎるので、こちらもバージョンダウンする。

npm install --save react@18.0.0 react-dom@18.0.0

どうも

npm audit fix --force
npm audit

を実施すると、'react-scripts' の実行バイナリが消えてしまう。

結果

'react-scripts' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。

が発生してしまう模様。。。

package.json
に、

    "react-scripts": "^5.0.1",

を記載して、

npm install  react-scripts --save

をし直す事で、コマンドを認識するようになった。

次は、

image.png

npm run build 

が成功しない。。。

の事象が発生している模様。

  • \src\index.tsx
    のimport分を変更する。
import { Amplify } from 'aws-amplify';
  • \amplify\backend\api\amplifydemo\schema.graphql

サンプルはV1で、最新だとV2で動作しようとするのでマイグレーションが必要だった

type Meeting @model(mutations: {create: "createMeetingGraphQL", delete: "deleteMeetingGraphQL"}, subscriptions: null) 
@auth(rules: [{allow: owner}, {allow: private, operations:[read, create, update, delete]}])
{
  meetingId: String!
  title: String! @primaryKey
  data: String!
}

type Attendee @model(mutations: {create: "createAttendeeGraphQL", delete: "deleteAttendeeGraphQL"}, subscriptions: null) 
@auth(rules: [{allow: owner}, {allow: private, operations:[read, create, update, delete]}])
{
  attendeeId: String!  @primaryKey
  name: String!
}

type Query {
  createChimeMeeting(title: String, name: String, region: String): Response @function(name: "reactSampleLambda-${env}")
  joinChimeMeeting(meetingId: String, name: String): Response @function(name: "reactSampleLambda-${env}")
  endChimeMeeting(meetingId: String): Response  @function(name: "reactSampleLambda-${env}")
}

type Response {
  statusCode: String!
  headers: String
  body: String
  isBase64Encoded: String
}
  • \src\uril\api.ts

amplify V5のサンプル例となっており、現行はV6で動作しようとする。

上記のサイトを参考に、V6用に書き換える。

import { generateClient } from 'aws-amplify/api';
import { createAttendeeGraphQL, createMeetingGraphQL, deleteMeetingGraphQL } from '../graphql/mutations';
import { createChimeMeeting, getAttendee, endChimeMeeting, getMeeting, joinChimeMeeting } from '../graphql/queries';


export async function createMeeting(title: string, attendeeName: string, region: string) {
  const client = generateClient();
  const joinInfo: any = await client.graphql({query: createChimeMeeting, variables:{title: title, name: attendeeName, region: region }});
  const joinInfoJson = joinInfo.data.createChimeMeeting;
  const joinInfoJsonParse = JSON.parse(joinInfoJson.body);
  return joinInfoJsonParse;
}

export async function joinMeeting(meetingId: string, name: string) {
  const client = generateClient();
  const joinInfo: any = await client.graphql({query: joinChimeMeeting, variables:{meetingId: meetingId, name: name}});
  const joinInfoJson = joinInfo.data.joinChimeMeeting;
  const joinInfoJsonParse = JSON.parse(joinInfoJson.body);
  return joinInfoJsonParse;
}

export async function endMeeting(meetingId: string) {
  const client = generateClient();
  const endInfo: any = await client.graphql({query: endChimeMeeting, variables:{meetingId: meetingId}});
  const endInfoJson = endInfo.data.endChimeMeeting;
  await client.graphql({query: deleteMeetingGraphQL, variables:{title: meetingId}});
  return endInfoJson;
}

export async function addMeetingToDB(title: string, meetingId: string, meetingData: string) {
  const client = generateClient();
  await client.graphql({query:createMeetingGraphQL , variables:{input: {title: title, meetingId: meetingId, data: meetingData, }}});
}

export async function addAttendeeToDB(attendeeID: string, attendeeName: string) {
  const client = generateClient();
  await client.graphql({query:createAttendeeGraphQL , variables:{input: {attendeeId: attendeeID, name: attendeeName }}});
}

export async function getMeetingFromDB(title: string) {
  const client = generateClient();
  const meetingInfo = await client.graphql({query:getMeeting , variables:{title: title } });
  return meetingInfo;
}

export async function getAttendeeFromDB(attendeeId: string) {
  const client = generateClient();
  const attendeeInfo =  await client.graphql({ query:getAttendee , variables:{attendeeId: attendeeId } });
  return attendeeInfo;
}

サンプルは、V1で書かれているので、V3に対応する必要がある。(メモ書き)

import React, { ChangeEvent, FC, FormEvent, useState } from 'react';

import {
  Flex,
  FormField,
  Input,
  PrimaryButton,
  useMeetingManager,
} from 'amazon-chime-sdk-component-library-react';

import { MeetingSessionConfiguration } from 'amazon-chime-sdk-js';

import { addAttendeeToDB, addMeetingToDB, createMeeting, getAttendeeFromDB, getMeetingFromDB, joinMeeting } from '../utils/api';

const MeetingForm: FC = () => {

  const meetingManager = useMeetingManager();
  const [meetingTitle, setMeetingTitle] = useState('');
  const [attendeeName, setName] = useState('');

  function getAttendeeCallback() {
    return async (chimeAttendeeId: string, externalUserId?: string) => {
      const attendeeInfo: any = await getAttendeeFromDB(chimeAttendeeId);
      const attendeeData = attendeeInfo.data.getAttendee;
      return {
        name: attendeeData.name
      };
    }
  }

  const clickedJoinMeeting = async (event: FormEvent) => {
    event.preventDefault();
  
    meetingManager.getAttendee = getAttendeeCallback();
    const title = meetingTitle.trim().toLocaleLowerCase();
    const name = attendeeName.trim();
  
  // Fetch the Meeting via AWS AppSync - if it exists, then the meeting has already
  // been created, and you just need to join it - you don't need to create a new meeting
    const meetingResponse: any = await getMeetingFromDB(title);
    const meetingJson = meetingResponse.data.getMeeting;
    try {
      if (meetingJson) {
        const meetingData = JSON.parse(meetingJson.data);
        const joinInfo = await joinMeeting(meetingData.MeetingId, name);
        await addAttendeeToDB(joinInfo.Attendee.AttendeeId, name);
        
        const meetingSessionConfiguration = new MeetingSessionConfiguration(
            meetingData,
            joinInfo.Attendee
        );
        
        await meetingManager.join(meetingSessionConfiguration);
      } else {
        const joinInfo = await createMeeting(title, name, 'us-east-1');
        await addMeetingToDB(title, joinInfo.Meeting.MeetingId, JSON.stringify(joinInfo.Meeting));       await addAttendeeToDB(joinInfo.Attendee.AttendeeId, name);
        
        const meetingSessionConfiguration = new MeetingSessionConfiguration(
            joinInfo.Meeting,
            joinInfo.Attendee
        );
        
        
        await meetingManager.join(meetingSessionConfiguration);
      }
    } catch (error) {
      console.log(error);
    }
    
    // At this point you can let users setup their devices, or start the session immediately
    await meetingManager.start();
  };
  
  return (
    <form>
      <FormField
        field={Input}     
        label='Meeting Id'
        value={meetingTitle}
        fieldProps={{
          name: 'Meeting Id',
          placeholder: 'Enter a Meeting ID',
        }}
        onChange={(e: ChangeEvent<HTMLInputElement>) => {
          setMeetingTitle(e.target.value);
        }}
      />
      <FormField
        field={Input}
        label="Name"
        value={attendeeName}
        fieldProps={{
          name: 'Name',
          placeholder: 'Enter your Attendee Name'
        }}
        onChange={(e: ChangeEvent<HTMLInputElement>) => {
          setName(e.target.value);
        }}
      />
      <Flex
        container
        layout="fill-space-centered"
        style={{ marginTop: '2.5rem' }}
      >
          <PrimaryButton label="Join Meeting" onClick={clickedJoinMeeting} />
      </Flex>
    </form>
  );
};

export default MeetingForm;

MeetingSessionConfiguration 関連の取り扱いが変わったらしく、V3対応に書き換える。

これでも、まだビルドが通らない。。。

index.tsx
Reactの最新版では、react-domからrenderが無くなってると。。。

そしてtypescriptのチェックが強固にかかりすぎてるので、

で、Nullチェックを回避する。

import { createRoot } from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import {
  MeetingProvider,
  lightTheme
} from 'amazon-chime-sdk-component-library-react';
import Meeting from './components/Meeting';
import MeetingForm from './components/MeetingForm';

import { Amplify } from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

const container = document.getElementById('root')!;
const root = createRoot(container);

window.addEventListener('load', () => {
  root.render(
  <ThemeProvider theme={lightTheme}>
    <MeetingProvider>
      <MeetingForm />
      <Meeting/>
    </MeetingProvider>
  </ThemeProvider>
  );
});

と、ここまでやって、最新版に対応したソースは、

配下にあった。諸々、手修正したものの、上記から最新版を適用することで、無事に動いた。
リージョン情報はハードコードされているソースが何個かあるので、動作させるリージョンに修正した。(メモ書き)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?