Go言語、SendGridでメール送信機能

はじめに

SendGridはメール送信に特化したサービスです。
今までの現場でも使われているようでしたが触ったことはなかったので、
配信関係の流れで試してみました。
ユーザ登録してAPI呼ぶだけで使えるのがお手軽ですね。
SDKも豊富そうなので、困らなそう。
後、ドキュメントの説明が丁寧な印象です。

コード

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "os"

    "github.com/sendgrid/sendgrid-go"
    "github.com/sendgrid/sendgrid-go/helpers/mail"
)

func main() {
    // クライアント作成
    client := sendgrid.NewSendClient(os.Getenv("SENDGRID_API_KEY"))

    // メッセージ作成
    from := mail.NewEmail("Example User", "test@example.com")
    subject := "お知らせサンプル Sendgrid"
    to := mail.NewEmail("Example User", os.Getenv("EMAIL")) // 環境変数より取得
    plainTextContent := "テキストメッセージの送信"
    htmlContent := "<strong>HTMLメッセージの送信</strong>"
    message := mail.NewSingleEmail(from, subject, to, plainTextContent, htmlContent)

    // メール送信
    response, err := client.Send(message)
    if err != nil {
        log.Println(err)
    } else {
        fmt.Println(response.StatusCode)
        fmt.Println(response.Body)
        fmt.Println(response.Headers)
    }
}

レスポンス

202

map[Access-Control-Allow-Headers:[Authorization, Content-Type, On-behalf-of, x-sg-elas-acl] Access-Control-Allow-Methods:[POST] Access-Control-Allow-Origin:[https://sendgrid.api-docs.io] Access-Control-Max-Age:[600] Connection:[keep-alive] Content-Length:[0] Date:[Wed, 29 Sep 2021 05:09:54 GMT] Server:[nginx] Strict-Transport-Security:[max-age=600; includeSubDomains] X-Message-Id:[CnapdViTR0KjGH2JUc6wYA] X-No-Cors-Reason:[https://sendgrid.com/docs/Classroom/Basics/API/cors.html]]

おわりに

Twilioを使ったSMS配信もあり、一緒に乗せたかったのですが、検証間に合わずでした。
Go用のSDKはなさそうなのでAPI呼び出しでの実装になりそうです。
というかTwilioがSendGridの親会社だったんですね。

Go言語、VonageでSMS送信機能

はじめに

AWSサービスとの比較でSMS送信を試してみました。

Vonage

https://www.vonagebusiness.jp/

APIベースでSMS配信、音声メッセージ配信、ビデオ配信などが可能

登録すると2ユーロ分無料で使えるのである程度試せます。
文字数にもよるかもしれませんが、SMSの1回配信で0.07ユーロだったので数十回は試せます。

音声配信もWebから簡単に試せて、
実際に電話がかかってくるのは面白いですね。

コード

   // パラメータの作成
    value := url.Values{}
    value.Set("from", SenderId)
    value.Add("text", "サンプルメッセージ By Vonage API")
    value.Add("to", PHONE)
    value.Add("api_key", VONAGE_API_KEY)
    value.Add("api_secret", VONAGE_API_SECRET)
    value.Add("type", "unicode")

    // APIリクエスト
    resp, err := http.PostForm("https://rest.nexmo.com/sms/json", value)
    if err != nil {
        log.Fatal(err)
    }
    buffer := make([]byte, 1024)

    respLen, _ := resp.Body.Read(buffer)
    body := string(buffer[:respLen])
    log.Println(body)
    log.Println(resp.Status)
    defer resp.Body.Close()

レスポンス

{
    "message-count": "1",
    "messages": [{
        "to": "819012345678",
        "message-id": "1C00000003DCB8FD",
        "status": "0",
        "remaining-balance": "1.19200000",
        "message-price": "0.07000000",
        "network": "44020"
    }]
}

Go言語、Amazon PinpointでSMS送信機能を試してみる

はじめに

Pinpoint は、PUSH 通知だけでなくメール、SMS などに対応しています。 LINE などのカスタムチャネル対応もしているため、Pinpoint を起点に様々なサービス連携が可能なため、Amazon SNSより拡張性が高いと考えられます。

  • メール、SMS、プッシュ通知、音声
  • 通知系の全てを備えているのはPinpointのみ
  • 音声送信は東京リージョンでは不可
     バージニア北部にて設定可能なことを確認

特徴としては下記
* 対象者のセグメント分け
* メッセージングキャンペーン
* ユーザージャーニー
* テンプレートを用いた一貫性のあるメッセージング
* パーソナライズされたコンテンツ配信
* ユーザー行動の分析
* テストメッセージの送信

E メールの開封とクリックイベントの追跡 https://docs.aws.amazon.com/ja_jp/pinpoint/latest/userguide/channels-email-open-click-tracking.html

Amazon Pinpoint は、送信する各 E メールの最後に、ごく小さな、透明なイメージを追加します。このイメージは AWS サーバーでホストされています。このイメージのファイル名は、各受取人に固有です。受取人が E メールを開封すると、E メールクライアントがこのファイルを当社のサーバーからダウンロードします。E メールクライアントが当社のサーバーから追跡イメージをダウンロードすると、開封イベントとしてカウントします。

無料枠

Amazon Pinpoint では、毎月 5,000 エンドポイントのターゲット、毎月 100 万回のプッシュ通知の送信、毎月 1 億回のイベントの追跡を無料で行えます。

Amazon Pinpoint のクォータ(制限値)

Amazon Pinpoint のクォータ - Amazon Pinpoint


CLI

aws pinpoint send-messages \
--application-id 80fb90a6c****************** \
--cli-input-json file://pinpoint.json --region ap-northeast-1

pinpoint.json

{
    "ApplicationId": "80fb90a6c******************",
    "MessageRequest": {
        "Addresses": {
            "+819012345678": {
                "ChannelType": "SMS"
            }
        },
        "MessageConfiguration": {
            "SMSMessage": {
                "Body": "てすと",
                "MessageType": "PROMOTIONAL",
        "SenderId": "testsend"
            }
        }
    }
}

戻り(パラメータエラー)

{
    "MessageResponse": {
        "ApplicationId": "80fb90a6c******************",
        "RequestId": "a28ada49-****-****-****-********",
        "Result": {
            "08012345678": {
                "DeliveryStatus": "PERMANENT_FAILURE",
                "MessageId": "9q633b6gts******************",
                "StatusCode": 400,
                "StatusMessage": "Invalid PhoneNumber"
            }
        }
    }
}

指定した電話番号が誤っていたので修正し再度実行
電話番号の指定は+で始まる国コード付きの電話番号にしないと無効になります。

直した版

{
    "MessageResponse": {
        "ApplicationId": "80fb90a6c******************",
        "RequestId": "5bf917c8-****-****-****-********",
        "Result": {
            "+819012345678": {
                "DeliveryStatus": "SUCCESSFUL",
                "MessageId": "75i5gmnsar******************",
                "StatusCode": 200,
                "StatusMessage": "MessageId: 75i5gmnsar******************"
            }
        }
    }
}

コード

SMSとメール送信を同時に実行

package main

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/pinpoint"
)

const (
    AwsAccessKey       = "アクセスキー"
    AwsSecretAccessKey = "シークレットキー"
    AwsRegion          = "us-east-1"
    AppId              = "PinpointのプロジェクトID"
    SenderId           = "testsend" // 送信ID SMSの送信者名
)

func main() {
    // クライアントの生成
    creds := credentials.NewStaticCredentials(AwsAccessKey, AwsSecretAccessKey, "")
    sess, _ := session.NewSession(&aws.Config{
        Credentials: creds,
        Region:      aws.String(AwsRegion),
    })

    client := pinpoint.New(sess)

    // メッセージ作成
    text := "Pinpoint サンプルメッセージ"

    // サブスクリプションのプロトコルごとにメッセージを指定
    messageJson := map[string]string{
        "default": text,
        "sms":     "SMSのメッセージ\n" + text,
        "email":   "E メールのメッセージ\n" + text,
    }
    // メッセージ構造体はJSON文字列にする
    bytes, err := json.Marshal(messageJson)
    if err != nil {
        fmt.Println("JSON marshal Error: ", err)
    }
    message := string(bytes)

    // Pinpoint送信
    pin := &pinpoint.SendMessagesInput{
        ApplicationId: aws.String(AppId),
        MessageRequest: &pinpoint.MessageRequest{
            Addresses: map[string]*pinpoint.AddressConfiguration{
                "+819012345678": &pinpoint.AddressConfiguration{ // 電話番号を指定
                    ChannelType: aws.String(pinpoint.ChannelTypeSms),
                },
                "your-mail@mail.com": &pinpoint.AddressConfiguration{ // メールアドレスを指定
                    ChannelType: aws.String(pinpoint.ChannelTypeEmail),
                },
            },
            MessageConfiguration: &pinpoint.DirectMessageConfiguration{
                SMSMessage: &pinpoint.SMSMessage{
                    Body:        aws.String(text),     // 本文
                    SenderId:    aws.String(SenderId), // 送信ID SMSの送信者名
                    MessageType: aws.String(pinpoint.MessageTypePromotional),
                },
                EmailMessage: &pinpoint.EmailMessage{
                    FromAddress: aws.String("sender@mail.com"), // 送信者アドレス
                    SimpleEmail: &pinpoint.SimpleEmail{
                        Subject: &pinpoint.SimpleEmailPart{ // 件名
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("subject"),
                        },
                        HtmlPart: &pinpoint.SimpleEmailPart{
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("<HTML>html message</html>"),
                        },
                        TextPart: &pinpoint.SimpleEmailPart{
                            Charset: aws.String("utf-8"),
                            Data:    aws.String("text message"),
                        },
                    },
                },
            },
        },
    }


    result, _ := client.SendMessages(pin)
    log.Println(result.MessageResponse.Result)
}


解説

SendMessagesInputの構造体が結構複雑です。
感覚的には以下
* Addressesのmapで送信対象を指定(mapのキーが電話番号だったり、メールアドレスだったりなのが) * MessageConfigurationにてプロトコル毎に送信内容を設定

あまり情報がないので、実装見ながら必要なtypeを掘り下げて、
値を設定していく感じで実装できます。
ポイントとしてはstringの値などがポインタなため、直接文字列を設定してもエラーになってしまう点です。
回避策としては別途変数を宣言した上で代入時にポインタを渡すか、
上記の実装のように、awsが提供しているポインタに変換する関数を噛ませることでポインタ渡しができます。

値の設定がやり辛いのですが、案件で使っているgo-swaggerが生成するコードもポインタで定義しているので、
きっとライブラリ的には良い実装なんだろうと納得させています。
おそらくメモリ効率が良いのではと思いますが。


Amazon SNSAmazon Pinpointの差異

公式より

https://aws.amazon.com/jp/pinpoint/faqs/

Q: 現在、Amazon SNSAmazon Simple Email Service (SES) を使用している場合、Amazon Pinpoint に切り替えることによってどんなメリットがありますか? Amazon SNSAmazon SES の一般的なユースケースでは、それぞれのメッセージの対象者、コンテンツ、配信スケジュールを管理するためにアプリケーションをセットアップする必要があります。Amazon Pinpoint を使用すると、メッセージテンプレート、配信スケジュール、対象を絞ったセグメント、全面的なキャンペーンを作成できます。

https://docs.aws.amazon.com/pinpoint/latest/apireference/welcome.html

AmazonPinpointとAmazonSimple Email Service(SES)のどちらを選択するか 購入確認やパスワードリセットメッセージなど、大量のトランザクションメールを送信する場合は、AmazonSESの使用を検討してください。Amazon SESにはAPISMTPインターフェースがあり、どちらもアプリケーションやサービスからメールを送信するのに適しています。また、電子メールの受信機能、構成セット、送信認証機能など、追加の電子メール機能も提供します。 Amazon SESには、Salesforceなどの顧客関係管理(CRM)サービスなど、既存のサードパーティアプリケーションと統合できるSMTPインターフェイスも含まれています。アマゾンSESを使用して電子メールを送信する方法の詳細については、以下を参照してくださいアマゾンSESのAPI v2の 詳細については、を。


送信の制限

初期状態では1ドル分以上のSMSが送れないようになっています。
1ドルの制限はコンソールから変更可能です。


参考情報

SendMessage(CLIhttps://docs.aws.amazon.com/cli/latest/reference/pinpoint/send-messages.html

SDK Example https://docs.aws.amazon.com/pinpoint/latest/developerguide/send-messages-sms.html

SDK Document Go https://docs.aws.amazon.com/sdk-for-go/api/service/pinpoint/#Pinpoint.SendMessages

REST API Document https://docs.aws.amazon.com/pinpoint/latest/apireference/apps-application-id-messages.html

Go言語、Amazon SNSでSMS・メール配信機能を試してみる

Amazon SNSとは

正式名称:Amazon Simple Notification Service
https://aws.amazon.com/jp/sns/

フルマネージド型 pub/sub メッセージングサービス
AWSのサービス間の連携に使われたり、
電子メール、SMS、およびモバイルプッシュ通知へのメッセージ配信も可能

連携できるAWSサービスは以下

※ 音声配信はAmazon SNSでは扱っていません。
Amazon PinpointやAmazon Connectなどで実現できそうです。


コード

SMSの発信(番号指定)

package main

import (
    "encoding/json"
    "fmt"
    "log"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sns"
)

const (
    AwsAccessKey       = "AWSアクセスキー"
    AwsSecretAccessKey = "AWSシークレットキー"
    AwsRegion          = "us-east-1"
)

func main() {
    // クライアントの生成
    creds := credentials.NewStaticCredentials(AwsAccessKey, AwsSecretAccessKey, "")
    sess, err := session.NewSession(&aws.Config{
        Credentials: creds,
        Region:      aws.String(AwsRegion),
    })

    if err != nil {
        log.Fatal(err)
    }

    client := sns.New(sess)

    // メッセージの作成
    pin := &sns.PublishInput{}
    pin.SetMessage("SMS エンドポイントのサンプルメッセージ")
    // E.164 形式の電話番号(国コードを指定します。今回は日本の場合は、[+81]を指定。090や080の最初の0は取り除く)
    pin.SetPhoneNumber("+81xxxxxxxxxx")

    // SMS送信
    result, err := client.Publish(pin)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: %s", result.String())
}


解説

PublishInput構造体にメッセージをセットし、Publishするのが基本動作
SetMessage:メッセージ本文
SetPhoneNumber:電話番号

PublishInputには、TopicArnかTargetArn、またはPhoneNumberのいずれかを設定する必要があります。
メールの場合はPhoneNumber以外のいずれかを指定

AWSセッションの作成の際に、リージョンの指定をしています。
こちらは「us-east-1」固定とします。
詳細は下記「サンドボックス内でのSMS送信における注意点」に記載していますが、
サンドボックスのためus-east-1以外での確認が出来なくなっています。
他のリージョンを指定しても一見成功しますが、メッセージが送られてきません。


サンドボックス内でのSMS送信における注意点

SMSの場合、サブスクリプション登録していなくても送ることができます。
初回のサービス利用時はサンドボックス環境と言って事前に検証済みの番号にしか配信できません。
配信の設定はAWSのコンソールより設定します。

https://console.aws.amazon.com/sns/v3/home?region=us-east-1#/mobile/text-messaging

注意すべきはリージョンはバージニア北部でしか設定できないのでリージョンを確認してください。
Amazon SNSのテキストメッセージング (SMS)のページを開きます。
「電話番号を追加」をクリックし、電話番号を追加します。 f:id:katutoki:20210926181300p:plain

電話番号はE.164 形式で記述します。
+2桁の国コード + 電話番号
日本の場合は、[+81]を指定。090や080の最初の0は取り除く)
例)090-1234-5678 の場合 +81 80 1234 5678 となります。
f:id:katutoki:20210926181452p:plain

番号入力後、検証コードを入力することになるので、
スマホの通知を確認し、検証コードを入力することで検証完了となります。 f:id:katutoki:20210926182217p:plain

スマホでの検証コードの表示。表示はワンタイムパスワードとなっています。 f:id:katutoki:20210926182429p:plain:w200:h300

テキストメッセージング (SMS)のページにて検証ステータスが検証済みとなっていれば成功です。


SMSの発信(トピック指定)

   // ~ 中略(メッセージの作成より前は上と同様) ~

    // メッセージの作成
    text := "共通のサンプルメッセージです。"

    // サブスクリプションのプロトコルごとにメッセージを指定
    messageJson := map[string]string{
        "default": text,
        "sms":     "SMSへのサンプルメッセージ\n" + text,
        "email":   "Eメールへのサンプルメッセージ\n" + text,
    }

    // メッセージ構造体はJSON文字列にする
    bytes, err := json.Marshal(messageJson)
    if err != nil {
        fmt.Println("JSON marshal Error: ", err)
    }
    message := string(bytes)

    pin := &sns.PublishInput{
        MessageStructure: aws.String("json"), // MessageStructureにjsonを指定
        TopicArn:         aws.String(TopicARN),
    }

    // 配信
    result, err := client.Publish(pin)
    if err != nil {
        fmt.Println("Publish Error: ", err)
    }

    log.Println(result.GoString())
}

※この場合、同じトピックに指定したサブスクリプションにまとめて配信できるので実用的な気がします。
 ここではSMS送信とメール送信用のテキストを指定しています。


解説

PublishInput構造体にメッセージをセットし、Publishするのが基本動作なのは変わらず
Message:メッセージ本文(json形式)
MessageStructure:メッセージ本文がjson形式であることを指定
TopicArn: SNSトピックのARN

トピックを指定した送信の場合、トピックとサブスクリプションの作成が必要です。

SMS送信したい場合、サブスクリプションプロトコルにSMSを指定し、エンドポイントとして送りたい電話番号を指定します。
先ほど検証済みにした電話番号を指定します。別な番号で確認したい場合は検証済みの電話番号に追加が必要です。


メール送信したい場合、サブスクリプションプロトコルにEメールを指定し、エンドポイントとして送りたいemailアドレスを設定します。

また、トピックの種類にはスタンダードとFIFOの2種類あります。
SMSやメール送信するためにはスタンダードを選択します。


SMS送信における注意点

1送信単位は160文字。

160文字を超えてもメッセージとしては1度に配信されますが、内部的には送りたい文字数÷160回数分配信したとみなされるようです。
無料枠として月100万回配信可能ですが、SMSは無料枠ではないので注意

1送信当たり、$0.07451

GCPで別なプロジェクトのリソースにアクセスする

はじめに

サービスの立て付け上、プロジェクトを分ける必要性があるが、
システム上同期をとって他方のサービスに対して処理を実行したい。
アクセスはセキュアにしたいので、認証されたアカウントでのいアクセスさせたい。
APIで通信すれば実現可能だが、クラウド的な実装で解決したい。

構成

f:id:katutoki:20210830234228p:plain

プロジェクトAからPub/Subをパブリッシュし、
プロジェクトBのCloud Runにメッセージ送信
Pub/Subのトリガーは簡単なのでSchedulerにしました。
実際はCloud Functionだったり、Cloud Runからキックする実装になるかと思います。


解決法

先に答えを行ってしまうと、

  1. 呼び出し元でサービスアカウントを作成
  2. サービスアカウントで認証しつつPub/Subメッセージ送信
  3. 呼び出される側のCloud Runの権限にメンバーとして上記のサービスアカウントを追加


詳細

1.Cloud Runアプリケーション作成(プロジェクトA

サービス名やリージョンは任意 f:id:katutoki:20210831000212p:plain

コンテナイメージも任意(今回はアクセスできれば良いのでデモコンテナを指定) f:id:katutoki:20210831001425p:plain

トリガーはこんな感じ
「認証が必要」を選ぶことで外から許可されたメンバー以外アクセスできなくなります。 f:id:katutoki:20210831001748p:plain

作成が完了するとURLが生成されます。 f:id:katutoki:20210831003732p:plain 後でPub/Subに設定するのに使います。


2.Pub/Subトピック作成(プロジェクトB)

トピックの作成
一緒にデフォルトのサブスクリプションも作成します。 f:id:katutoki:20210831005008p:plain

後ほどサブスクリプションの設定を変更しますが、
その前に変更する設定に必要なサービスアカウントを作成します。


3.サービスアカウント作成(プロジェクトB)

f:id:katutoki:20210831005749p:plain

f:id:katutoki:20210831005907p:plain サービス名は任意で、他は未設定でもOK

作成されたサービスアカウント f:id:katutoki:20210831010039p:plain ※サービスアカウントのメールアドレスをこの後使います。


4.Pub/Subサブスクリプション作成(プロジェクトB)

サブスクリプションの編集 f:id:katutoki:20210831005225p:plain f:id:katutoki:20210831005252p:plain

サブスクリプションの設定を変更します。
配信タイプ:Push
エンドポイント:1で作成したClourd Run URL
認証を有効:3で作成したサービスアカウントを設定
f:id:katutoki:20210831010424p:plain トークン作成の権限が必要とのことなので付与ボタンをクリックしておきます。
付与すると一度入力がリセットされてしまうのでもう一度入力しなおしてください。

残りの項目はデフォルトでOKです。


5.スケジューラの作成(プロジェクトB)

初回だけリージョンの選択をします。東京で f:id:katutoki:20210831003422p:plain

ジョブの設定。今回はコンソールから手動で起動するつもりなので適当に f:id:katutoki:20210831004812p:plain

ターゲットタイプにPub/Sub、トピックは作成したトピックを選択します。 f:id:katutoki:20210831010916p:plain


6.Cloud Runの権限追加(プロジェクトA

Cloud Runの権限にてメンバーを追加 f:id:katutoki:20210831011226p:plain

メンバー:3で作成したサービスアカウントのメールアドレスを指定 ロール:Cloud Run 起動元 f:id:katutoki:20210831011352p:plain

メンバーにメールアドレスを入力すると下記のようにテキスト入力欄の下に候補が出るので、それをクリックする。 f:id:katutoki:20210831011458p:plain

確認

スケジューラを手動実行します。 「今すぐ実行」をクリック f:id:katutoki:20210831011715p:plain

Cloud Runのログを確認します。 f:id:katutoki:20210831012736p:plain

無事届きました。

上手くいかない場合は経路のどこかの設定が間違えていたり抜けていたりします。
設定したつもりがされていなかったり、更新したつもりが変わってなかったり。

【AWS Cloud9 の使い方】最初に覚えておくべき機能まとめ

はじめに

Cloud9でよく使う操作方法についてピックアップしてご紹介いたします。
どれも開発環境のツールとして使われるIDEでは基本的なものではありますが、
初めて開発環境ツールとしてCloud9を選択された方向けの内容となっています。

Cloud9って

ブラウザ上で操作可能なIDE統合開発環境
ブラウザのみでコードを記述、実行、デバッグができるクラウドのサービスです。


画面の構成

まずは全体 f:id:katutoki:20210826233425p:plain


メニューバー(画面上部)

f:id:katutoki:20210827071158p:plain

メニューバーが表示されていない場合 f:id:katutoki:20210827071532p:plain メニューバーが表示される画面上部の真ん中に「▼」(上記画像の黄色枠)がありますので、こちらをクリックすると表示されます。1
メニューバーを表示したくない場合 f:id:katutoki:20210827072356p:plain メニューバーの左側、画面の一番左上にある「▲」をクリックすれば表示されない状態になります。


環境ウィンドウ(画面左側)

f:id:katutoki:20210827082210p:plain ディレクトリ(フォルダ)やファイルの一覧が表示されます。
私はツリーという事が多いです。

Windowsで言うところのナビゲーションウィンドウ
Macで言うところのFinderのリスト表示が近いでしょうか。

ここに表示されているファイルをダブルクリックするとエディタ部分にファイルの内容が表示されます。2

エディタ(画面中央)

f:id:katutoki:20210827084811p:plain ファイルの内容が表示されます。
ファイルの編集を行うことができます。

OSで使えるような便利なショートカットを備えているので、
下記のようなよく使うショートカットも使えます。

  • Ctrl + S:保存
  • Ctrl + C:コピー
  • Ctrl + V:貼り付け
  • Ctrl + Z:前に戻る


タブ

f:id:katutoki:20210827084200p:plain エディタの上部にあります。開いたファイルが並んでいて、
それぞれのタブをクリックすることでエディタの表示を切り替えられます。
各タブの右端の「×」でタブを閉じることができます。

「×」部分が「●」になっている場合
そのファイルは変更されていて、まだ保存されていないことを表します。
f:id:katutoki:20210827090215p:plain カーソルを合わせてクリックすると「×」同様閉じることができますが、
下記のようなダイアログが表示されます。 f:id:katutoki:20210827090421p:plain 左から、「保存して閉じる」、「保存しないで閉じる」、「閉じるのを止める」です。

ターミナル(画面下部)

f:id:katutoki:20210827092037p:plain サーバ上でコマンドを入力し、実行する場所です。
エディタ同様こちらもタブがあり、複数のタブの切り替えが可能です。

ターミナル上での移動はLinuxのコマンドが使えます。

コマンドの操作がどうにも苦手、という方はツリーからも移動が可能です。
移動したいディレクトリやファイルを右クリックし、
表示されたメニューの「Open Terminal Here」をクリックすることで、
ターミナル上で移動された状態のターミナルが表示されます。 f:id:katutoki:20210827094055p:plain この場合、画面の下部ではなくエディタの部分にターミナルが表示されます。
下部に表示したい場合、タブの部分をドラッグするとタブを動かすことが出来ます。


カラーテーマを切り替える

メニューバー>View>Themes で変更できます。 f:id:katutoki:20210827095220p:plain Themesで表示されているリストから好きなテーマを選ぶことができます。
大きくは黒ベースのダークテーマと白ベースのライトテーマに分かれます。
ダークテーマからライトテーマに切り替える際に下記のような警告が出ますが、
そのままYesをクリックすれば適用されます。

f:id:katutoki:20210827095337p:plain


ファイルの作成

1.メニューから作成

メニューのFileをクリックしNew Fileをクリックして新規にファイルを作成します。
ショートカットキーとしてAlt+Nでも作れます。 f:id:katutoki:20210830002446p:plain

空のエディタが開くので、内容を入力し保存しようとすると、保存先を聞かれるので好きなファイル名と保存場所を選択して保存します。
保存場所は「/」から始まる絶対パスを指定します。

f:id:katutoki:20210830002705p:plain

2.ツリーから作成

ツリー上でファイルを作成したいディレクトリにカーソルを置き、右クリックし、
New Fileを選択します。 f:id:katutoki:20210830003855p:plain

「Untitled」というファイル名でファイルが作成されるので、
好きなの名前に変更しましょう。
変更できずにそのままの名前で確定してしまった場合は、
ツリーから作成したファイルを右クリックし、「Rename」を選べば名前を変更できます。


フォルダの作成

上記のツリーからファイルを作成すると同様の操作で進め、
「New File」をクリックする際に「New File」の下に「New Folder」があるのでそちらをクリックします。


コードのフォーマット

書いたHtmlやPHPなどのプログラムを見やすい形に整えてくれます。

メニューのEdit > Code Formatting > Apply Code Formatting
とメニューの中から選択するとフォーマットされます。 f:id:katutoki:20210906091615p:plain


その他できること

  • 画像の編集
  • リアルタイムに共同でコーディング
  • ターミナルからAWS のサービスに直接アクセス
  • CodeStarとの連携によるCI/CD
  • ファイル改訂履歴
  • コード補完とコードヒント候補
  • ・・・etc

他にもまだまだたくさんありますので、興味が沸いてきたら公式のドキュメントも見てみてください。 https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/welcome.html


  1. 正確には「▼」含め、画面上部に薄いバーがあり、バーのどの位置でもクリックすれば開きます。

  2. 正確にはペインという表示領域。画面下部のターミナルが表示される部分もペイン。

横浜市長選挙候補者比較してみました。

はじめに

横浜市民になり初の市長選挙です。
普段はそこまで積極的に情報取りにいかないのですが、
先日YouTubeを見ていたら候補者の方の広告が流れて来て、
ついに選挙もここまで来たなと感じたので情報収集し始めました。

情報サイト

横浜市長選挙

投票日

8/22(日) 7時~20時

候補者

※届け出受理番号順

候補者名 年齢 ウェブサイト
太田 正孝(おおた まさたか) 75 http://www.ota-masataka.com/
田中 康夫(たなか やすお) 65 https://yokohama2021.me/
おこのぎ 八郎(おこのぎ はちろう) 56 https://hachirou.com/
坪倉 良和(つぼくら よしかず) 70 https://www.tsubokura-yoshikazu.com/
福田 峰之(ふくだ みねゆき) 57 https://fukudamineyuki.yokohama/
山中 竹春(やまなか たけはる) 48 https://takeharu-yamanaka.yokohama/
林 文子(はやし ふみこ) 75 http://hayashifumiko.com/
松沢 しげふみ(まつざわ しげふみ) 63 https://www.matsuzawa.com/

太田さんと林さんがhttpだったのが衝撃的です。 個人サイトなのかしらと不安になります。

SNS状況

今時なのでtwitter facebook instagram YouTubeと一通りアカウントはありそうですね。
やっぱりフォロワー数が気になるので比較してみます。
そういえば、ちょっと前に選挙カーがスピーカー鳴らしながら通りすぎていきましたが、
いまだにこれをやっている候補者は正直投票したくないですね。
名前覚えてないので誰だったかわからないのが残念。。

※以降は簡略化のため候補者は苗字のみにします。

twitter

順位 候補者名 フォロワー
1 田中   67,593
2 松沢   5,494
3 福田   5,155
4 山中   4,167
5 おこのぎ 1,755
6 林    812
7 坪倉   781
8 太田   716

田中さん圧勝ですね。現職の林さんが意外と少ない。

facebook

順位 候補者名 フォロワー
1 松沢   8,922
2 福田   3,116
3 おこのぎ 1,235
4 坪倉   1,043
5 田中   903
6 山中   634
7 林    88
8 太田   0

松沢さんが抜けてますね。 太田さんはリンクがなかったので未集計

Instagram

順位 候補者名 フォロワー
1 坪倉   1,850
2 田中   903
3 福田   765
4 山中   369
5 おこのぎ 316
6 林    179
7 松沢   0
8 太田   12(応援団)

インスタはあまり活発ではない様子です。若年層寄りだからでしょうか?
そんな中でも坪倉さんが頭1つ抜けているのが印象的です。
普段インスタ見ないのでよくわからないですがフォロワー多い方なのかしら?

YouTube

順位 候補者名 チャンネル登録 再生数
1 田中   8,600 5,188,902
2 松沢   - 196,679
3 坪倉   163 170,809
4 福田   211 17,515
5 山中   247 11,531
6 おこのぎ 93 5,679
7 林    146 4,765
8 太田   91 1,691

情報が見られているかという事で再生数でのランク付けにしてみました。
田中さんが圧倒的です。

松沢さんは登録者数がわかりませんでしたが、再生数的に200人弱はいらっしゃるんじゃないかなと思われます。
ちなみに冒頭でお伝えしたYouTubeで見た選挙広告?は松沢さんのものでした。

総合

ランキングの合計
合計値が少ない方が上位、同点の場合はいずれかで高い順位を獲得している方を上位としました。

候補者名 twitter Facebook Instagram YouTube 合計
田中   1 5 2 1 9
松沢   2 1 7 2 12
福田   3 2 3 4 12
坪倉   7 4 1 3 15
おこのぎ 5 3 5 6 19
山中   4 6 4 5 19
林    6 7 6 7 26
太田   8 8 8 8 32

フォロワー数の合計

候補者名 フォロワー計
田中 69,399
松沢 14,416
福田 9,036
山中 5,170
坪倉 3,674
おこのぎ 3,306
1,079
太田 716

フォロワー数の合計だけ見ると上位4人はランキングが大きく変わることはなさそうですね。

さいごに

自分自身の世代にとってよいかも気になりますし、
子供らの将来も考えるとそちらも重視したいですし、
40過ぎて親世代のことも気になる年頃でもあります。

政策の動画など見ていますが、誰に投票しようか迷いますね。
個人的には文字ベースより動画ベースで発信されていると受け取りやすいですね。