『Go言語によるWebアプリケーション開発』学習メモ(2日目)
『Go言語によるWebアプリケーション開発』という本での学習の中で、 学んだことを自分用に整理してメモしていきます。
前回から大分時間が空いてしまったのですが、進めていきます。
第2章 認証機能の追加
ログインしたユーザー名の表示
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { t.once.Do(func() { t.templ = template.Must(template.ParseFiles(filepath.Join("templates", t.filename))) }) data := map[string]interface{}{ "Host": r.Host, } if authCookie, err := r.Cookie("auth"); err == nil { data["UserData"] = objx.MustFromBase64(authCookie.Value) } t.templ.Execute(w, data) }
<form id="chatbox"> {{.UserData.name}}:<br/> <textarea></textarea> <input type="submit" value="送信" /> </form>
実行の流れ
http.Handlerのインターフェースを実装する。templateHandlerは、 HTTPリクエストを直接処理することが出来るようになる
t.onece.Doで、テンプレートファイルを一回だけロードして実行している
dataという、新しいマップを作成し、リクエストから取得したホスト名をHostキーに格納する
リクエストの中からauthという名のcookieを探し、エラーがない場合は、cookieの値をデコードする データは、UserDataというキーで、dataマップに格納される
t.templ.Execute(w, data)でHTMLを作成し、 HTTPレスポンスとして書き込む
JSON形式での送信
WriteJSONメソッドを使用することで、オブジェクトをJSON形式にして、WebSocket経由で
送信を行う。
第1章での実装
func (c *client) write() { for msg := range c.send { if err := c.socket.WriteMessage(websocket.TextMessage, msg); err != nil { break } } c.socket.Close() }
[]byte型のmsgをそのまま、websocket.TextMessageタイプで送信
第2章での実装
func (c *client) write() { for msg := range c.send { if err := c.socket.WriteJSON(msg); err != nil { break } } c.socket.Close() }
メッセージの受信者(クライアント型)は、メッセージを自動的に変換されたJSON形式で受け取る websocket.TextMessageのように、メッセージタイプを指定する必要がなくなる
msgとは?? message構造体のインスタンス chatでの、メッセージ内容などの情報をもつインスタンス type message struct { Name string Message string When time.Time }
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 本日はここまでで、また後日続きを行います
『Go言語によるWebアプリケーション開発』学習メモ(1日目)
『Go言語によるWebアプリケーション開発』という本での学習の中で、 学んだことを自分用に整理してメモしていきます。
第1章 WebSocketを使ったチャットアプリケーション
package main import ( "github.com/gorilla/websocket" ) type client struct { socket *websocket.Conn send chan []byte room *room }
Channelは、ゴルーチン間で、データの送受信を行うための機構を構築する Channelはバッファを持つことが出来る
バッファのあるChannelでは、指定された容量分、データを保持できる 送信ゴルーチンでは、容量がいっぱいになるまで、データを送信 受信ゴルーチンでは、バッファが空になるまでデータを受信できる
複数の送受信者が、同時に読み書きすることが出来る
バッファとは 一時的にデータを保存する領域のこと サーバーなどで複数のクライアントからリクエストが来た際に、 同時に処理することはできないため、一時的に保存したりする
c.room.forward <- msg
チャネル演算子で値を送受信することができる
並列処理と並行処理 並列処理:複数のタスクを同時に処理する 並行処理:複数のタスクを短時間で切り替える
チャットルームの作成
type room struct { forward chan []byte join chan *client leave chan *client clients map[*client]bool }
なぜmapを使うのか?
const ( socketBufferSize = 1024 messageBufferSize = 256 ) var upgrader = &websocket.Upgrader{ReadBufferSize: socketBufferSize, WriteBufferSize: socketBufferSize} func (r *room) ServeHTTP(w http.ResponseWriter, req *http.Request) { socket, err := upgrader.Upgrade(w, req, nil) if err != nil { log.Fatal("serveHTTP:", err) return } client := &client{ socket: socket, send: make(chan []byte, messageBufferSize), room: r, } r.join <- client defer func() { r.leave <- client }() go client.write() client.read() }
- ServeHTTP関数で、HTTPリクエストを受け取り、WebSocketの接続にアップグレード
- 成功後、Clientを作成し、チャットルームに追加
- ClientはWebSocketの接続、送信用のチャンネル、チャットルームを保持する
- Clientの終了時に退出
- goroutinueで、読み書きを行い、Clientはメッセージの送受信を同時に行う
websocket
クライアントとサーバー間でのリアルタイム通信を実現する通信プロトコル
ターミナルにログを出す
tracer.go type Tracer interface { Trace(...interface{}) } type tracer struct { out io.Writer } func (t *tracer) Trace(a ...interface{}) { t.out.Write([]byte(fmt.Sprint(a...))) t.out.Write([]byte("\n")) } func New(w io.Writer) Tracer { return &tracer{out: w} }
Tracerインターフェースを定義し、Traceメソッドを定義 New関数で、新しいTracerを作る
trace.go func (t *tracer) Trace(a ...interface{}) { t.out.Write([]byte(fmt.Sprint(a...))) t.out.Write([]byte("\n")) }
a ...interface{} 任意の長さの引数を受け取ることが出来る Writeメソッドは2回呼び出され、1回目は、文字列の出力 2回目は、改行を行っている
room.go type room struct { forward chan []byte join chan *client leave chan *client clients map[*client]bool tracer trace.Tracer }
roomは、Tracerインターフェースを持つ 構造体を定義し、フィールドを作る フィールド経由で、Traceメソッドを呼び出すことが出来る
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 本日はここまでで、また後日続きを行います
JavaScriptで順列を生成するライブラリをつくる
はじめに
JavaScriptで配列の要素をすべて並び替えて、順列を生成するライブラリを作成したので、 その過程を記事にしてみました。
既に多くの方が、npm packageとして公開されているのですが、 コードを書いたので、ライブラリとして公開してみました。
コード
function generatePermutations(arr, currentPermutation = []){ if (arr.length === 0) { return [currentPermutation]; } let permutations = []; for (let i = 0; i < arr.length; i++) { const remainingElements = arr.slice(0, i).concat(arr.slice(i + 1)); const newPermutation = currentPermutation.concat(arr[i]); permutations = permutations.concat(generatePermutations(remainingElements, newPermutation)); } return permutations; } module.exports = { generatePermutations };
解説
function generatePermutations(arr, currentPermutation = []){
generatePermutationsという関数を定義し、引数には以下を指定します
arr : 元の配列
currentPermutation : 順列を追跡していくための空の配列
if (arr.length === 0) { return [currentPermutation]; }
ここで、もし、arrの長さが0だった場合、currentPermutationを返します
再帰関数の終了条件です
let permutations = [];
生成された順列を保存する空配列
for (let i = 0; i < arr.length; i++) { const remainingElements = arr.slice(0, i).concat(arr.slice(i + 1)); const newPermutation = currentPermutation.concat(arr[i]); permutations = permutations.concat(generatePermutations(remainingElements, newPermutation)); }
arrの長さ文、ループを回します。
remainingElements : arrから、現在の要素を取り除いた新しい配列を生成している
arrの0番目の要素から、i - 1番目の要素までを取得
arr.slice(i + 1)で、i + 1番目の要素から、最後の要素を取得
concatメソッドで、その2つの部分配列を結合
現在のi番目の要素を除いた新しい配列が完成する
newPermutation : 現在の順列(currentPermutation)にarr[i]の要素を追加した新たな配列
permutations : 再帰的に順列生成の関数を呼び出し、その結果を順列リストに追加
それぞれの再帰のステップで、配列の1つの要素を指定し、その要素を固定し
その残りの要素ですべての順列を生成している
これをすべての要素で処理を実行している
テストコード
テストフレームワークのJestを使用し、テストのコードを書いてみました
const { generatePermutations } = require('../js/index.js'); describe('generatePermutations', () => { test('good permutations', () => { const input = [1, 2, 3]; const expected = [ [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1], ]; const result = generatePermutations(input); expect(result).toEqual(expect.arrayContaining(expected)); expect(result.length).toBe(expected.length); }); test('empty array', () => { const input = []; const expected = [[]]; const result = generatePermutations(input); expect(result).toEqual(expected); })
npm packageとして公開
最後に、npm packageとして公開し、どなたでもnpm installできる状態にします
npmでアカウントを作成し、npmにパッケージを公開します
公開の手順は、公式のドキュメントを参考にしました docs.npmjs.com
npm init -y
公開したいファイルのディレクトリに移動し、上記のコマンドを実行します
コマンドを実行すると、package.jsonが作成されます
npm login
その後、コマンドを実行しnpmにログインをします
npm publish
上記のコマンドを実行し、npm packagepackageをnpmレジストリに公開することが出来ます
おわりに
思っているよりも、簡単にnpm packegeを公開できることが分かりました
今後も、他にもライブラリを作成できるように頑張っていきたいです(^^)