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?

More than 1 year has passed since last update.

NCMBとMonaca、Framework7を使ってチャットアプリを作る(その3:チャット処理)

Last updated at Posted at 2022-08-03

NCMBとMonacaを使ってチャットアプリを作ります。以前、PieSocketを使ったチャットアプリを公開したのですが、現在○○は無料での利用枠がなくなっています。そこで今回はgoofmint/ruby-websockets-chat-demoをベースにチャットアプリを作ります。これはごく単純なWebScoketサーバーで、Herokuにデプロイできるものです。Herokuの無料枠内での利用が可能です。

前回の記事では認証周りを解説しました。今回はチャット処理について解説します。

コードについて

今回のコードはNCMBMania/MonacaChatDemoにアップロードしてあります。実装時の参考にしてください。

WebSocketサーバーのデプロイ

チャットサーバーをデプロイします。Herokuに対応していますので、クリック1つでデプロイできます。

goofmint/ruby-websockets-chat-demo

デプロイした際のURLが https://CHAR-SERVER.herokuapp.com だとしたら、httpswss に変更して config.json にて websocketUrl キーで設定します。 wss はWebSocketのSSL/TLS版です。

{
	"applicationKey": "YOUR_APPLICATION_KEY",
	"clientKey": "YOUR_CLIENT_KEY",
	"websocketUrl": "wss://CHAR-SERVER.herokuapp.com"
}

WebSocket接続の設定

NCMBの初期化を行った js/app.js にて、同じくWebSocketの初期化を行います。その際、状態を把握するのに使える関数も指定しておきます(必須ではありません)。

const webSocket = new WebSocket(config.websocketUrl);
webSocket.onopen = onOpen;
webSocket.onclose = onClose;
webSocket.onerror = onError;
window.webSocket = webSocket;

// 接続した時に呼ばれるイベント
const onOpen = (e) => {
}

// エラーが出た際に呼ばれるイベント
const onError  = (e) => {
  console.log(e);
};

// 接続を閉じた時に呼ばれるイベント
const onClose = (e) => {
}

チャット画面について

チャット画面はFramework7のメッセージ機能を使うので、HTMLはとてもシンプルです。

<div class="page" data-name="chat">
	<div class="navbar">
		<div class="navbar-bg"></div>
		<div class="navbar-inner sliding">
			<div class="title">チャット</div>
		</div>
	</div>
	<div class="toolbar messagebar">
		<form id="chat">
			<div class="toolbar-inner">
				<div class="messagebar-area">
					<textarea name="text" class="resizable" placeholder="Message"></textarea>
				</div>
				<a class="link send-link" href="#" @click=${sendMessage}>Send</a>
			</div>
		</form>
	</div>
	<div class="page-content">
		<div class="messages">
		</div>
	</div>
</div>

FireShot Capture 485 - Monaca × Framework7 × NCMB - localhost 20220803154354 - 485.jpg

変数の準備

画面を構築するのに必要な変数、NCMBのデータストアに保存する際に使う変数を準備します。

export default (props, { $on, $update, $tick, $onMounted }) => {
	// データストアに保存する用のクラス名(DBで言うテーブル名相当)
	const Message = ncmb.DataStore('Message');
	// ログインユーザー
	const user = ncmb.User.getCurrentUser();
	// データ保存する際のACL(アクセス権限)
	const acl = new ncmb.Acl;
	acl
		.setPublicReadAccess(true)        // 誰でも閲覧可能
		.setUserWriteAccess(user, true);  // ユーザのみ編集・削除可能
	
	let messagebar;           // メッセージ入力欄用
	let messages = [];        // チャットメッセージ(描画用)
	let messageObjects = [];  // チャットメッセージ(データストアから取得)

チャットメッセージを受け取った際の処理を用意

チャットメッセージをWebSocketサーバー経由で受け取った際の処理を記述します。これはWebSocketサーバーが送信する内容を解析し、後述する addMessage 関数にデータを送ります。 unescapeHtml 関数は○○より拝借しています。

// マウントされた際に実行
$onMounted(() => {
	// WebSocketでメッセージを受け取った際に呼び出される関数
	window.webSocket.onmessage = (e) => {
		// 文字列のメッセージをJSONとしてパース
		const message = JSON.parse(e.data);
		// ユーザー情報はHTMLをアンエスケープした上でパース
		message.user = JSON.parse(unescapeHtml(message.user));
		// チャットメッセージを追加
		addMessage(message);
	};
});

// HTMLをアンエスケープする関数
const unescapeHtml = (target) => {
	if (typeof target !== 'string') return target;
	const patterns = {
		'&lt;': '<',
		'&gt;': '>',
		'&amp;': '&',
		'&quot;': '"',
		'&#x27;':  '\'',
		'&#x60;': '`'
	};
	return target.replace(/&(lt|gt|amp|quot|#x27|#x60);/g, match => {
		return patterns[match];
	});
};

画面の初期化処理

画面が初期化された際には page:init イベントが呼ばれます。ここでFramework7のメッセージ機能を利用します。処理がちょっと長いですが、コメントを参照してください。

// ページが初期化される際に呼ばれる関数
$on('page:init', async () => {
	// チャットメッセージの作成
	messages = app.messages.create({
		el: '.messages',
		scrollMessagesOnEdge: true,
		// 最後のメッセージか判定する関数
		lastMessageRule: function (message, previousMessage, nextMessage) {
			if (message.isTitle) return false;
			if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
			return false;
		},
		// メッセージに吹き出しを付けるか判定する関数
		tailMessageRule: function (message, previousMessage, nextMessage) {
			if (message.isTitle) return false;
			if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
			return false;
		}
	});
	// データストアからメッセージを取得
	messageObjects = await getMessages();
	// チャットメッセージに追加
	messageObjects.forEach(addMessage);
	// メッセージ入力欄を作成
	messagebar = app.messagebar.create({
		el: '.messagebar'
	});
});

メッセージの取得

getMessages 関数はNCMBのデータストアから既存メッセージを取得する処理です。

// NCMBにあるチャットメッセージを取得する関数
const getMessages = () => {
	return Message
		.include('user') // ユーザー情報も取得
		.limit(100)      // 100件まで
		.fetchAll();
}

メッセージの追加処理

取得したメッセージは addMessage 関数にて messages に追加していきます。この関数はWebSocketサーバーからメッセージを受け取った際にも利用されます。

// チャット表示用のメッセージを追加する関数
const addMessage = (message) => {
	// 詳細は以下を参照
	// https://framework7.io/docs/messages#single-message-parameters
	messages.addMessage({
		text: message.message,
		type: message.user.objectId === user.objectId ? 'sent' : 'received',
		name: message.displayName,
		avatar: '/assets/icons/person.png',
	});
};

メッセージの送信

メッセージを送信すると sendMessage 関数が呼ばれます。ここではNCMBのMessageクラスにデータを保存した上で、メッセージをWebSocketサーバーに送信しています。WebSocketでは文字列のみ扱えますので、JSON.stringifyを使って文字列化しています。

// メッセージ送信処理
const sendMessage = async () => {
	// 入力内容を取得
	const params = app.form.convertToData($('#chat'));
	// Messageクラスのインスタンス(DBでいう行相当)を作成
	const message = new Message;
	// データを適用して保存
	await message
		.set('user', user)
		.set('acl', acl)
		.set('message', params.text)
		.save();
	// WebSocketで通知
	window.webSocket.send(JSON.stringify(message));
}

FireShot Capture 486 - Monaca × Framework7 × NCMB - localhost 20220803154430 - 486.jpg

これでチャットアプリの完成です。

まとめ

今回はチャット画面周りを解説しました。WebSocketサーバーを自分で立てれば、簡単なチャットアプリを作成できます。WebSocketサーバーだけではメッセージが保存されませんが、NCMBのデータストアを組み合わせることで、チャットメッセージを残しておけます。

Framework7のメッセージ機能は画像を投稿、表示できるなど多機能なものになっています。今回のチャットアプリをカスタマイズして実装してみてください。

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?