20211013のGoに関する記事は5件です。

やっぱりzstdのほうがよかった GoでZIP内部のBZIP2を解凍

ご覧いただきありがとうございます。ソリトンシステムズのセキュリティ分析チームです。 Google Colaboratoryにアカウントをお持ちの方は、上の「Open in Colab」という青いボタンを押せば直接notebookをColabで開けます。ぜひ動かしてみてください。 過去の記事も含め、全てのコードをGithubで公開しています。 以前の記事で、zipの圧縮にbzip2を使ったものをGo言語で読み出す方法について記載しました。しかし、zstdのほうが高性能ということなので同じことをzstdでやってみます。 まずサンプルを用意します。 !man man > man.txt !wc man.txt 724 4977 38134 man.txt zstdでzipアーカイブを作るには、zipfile-zstdモジュールを使うので、インストールします。 !pip install zipfile-zstd Collecting zipfile-zstd Downloading zipfile_zstd-0.0.3-py3-none-any.whl (4.1 kB) Collecting zstandard>=0.15.0 Downloading zstandard-0.15.2-cp37-cp37m-manylinux2014_x86_64.whl (2.2 MB) [K |████████████████████████████████| 2.2 MB 7.9 MB/s [?25hInstalling collected packages: zstandard, zipfile-zstd Successfully installed zipfile-zstd-0.0.3 zstandard-0.15.2 これを使ってアーカイブを作るのは以下です。 import zipfile_zstd as zipfile with zipfile.ZipFile('man.zip', 'w', zipfile.ZIP_ZSTANDARD, compresslevel=19) as zfile: zfile.write('man.txt', 'man.txt') !zipinfo man.zip Archive: man.zip Zip file size: 12162 bytes, number of entries: 1 -rw-r--r-- 6.3 unx 38134 b- u093 21-Oct-06 08:54 man.txt 1 file, 38134 bytes uncompressed, 12050 bytes compressed: 68.4% bzip2では70.2%でしたので、少し良くなっています。さらにzstdの方が解凍速度がすごく速いらしい。 次にGo言語をインストールします。 !wget https://golang.org/dl/go1.17.1.linux-amd64.tar.gz !tar -C /usr/local -xzf go1.17.1.linux-amd64.tar.gz import os os.environ['PATH'] += ":/usr/local/go/bin" --2021-10-06 08:55:05-- https://golang.org/dl/go1.17.1.linux-amd64.tar.gz Resolving golang.org (golang.org)... 74.125.142.141, 2607:f8b0:400e:c01::8d Connecting to golang.org (golang.org)|74.125.142.141|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://dl.google.com/go/go1.17.1.linux-amd64.tar.gz [following] --2021-10-06 08:55:05-- https://dl.google.com/go/go1.17.1.linux-amd64.tar.gz Resolving dl.google.com (dl.google.com)... 74.125.195.93, 74.125.195.136, 74.125.195.91, ... Connecting to dl.google.com (dl.google.com)|74.125.195.93|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 134784143 (129M) [application/x-gzip] Saving to: ‘go1.17.1.linux-amd64.tar.gz’ go1.17.1.linux-amd6 100%[===================>] 128.54M 217MB/s in 0.6s 2021-10-06 08:55:06 (217 MB/s) - ‘go1.17.1.linux-amd64.tar.gz’ saved [134784143/134784143] !go version go version go1.17.1 linux/amd64 それではgo言語でzipの中身を覗いてみましょう。まずは以下でunzip.goファイルにプログラムを書き込みます。 %%writefile unzip.go package main import ( "archive/zip" "fmt" "log" ) func main() { zfile, _ := zip.OpenReader("man.zip") defer zfile.Close() for _, f := range zfile.File { _, err := f.Open() if err != nil { fmt.Println(f.Method) log.Fatal(err) } fmt.Println(f.FileInfo().Name()) } } Overwriting unzip.go 早速実行! !go run unzip.go 93 2021/10/06 08:55:46 zip: unsupported compression algorithm exit status 1 案の定、そんな圧縮方式知らぬと怒られました。しかし、メソッド番号が93であることが分かりました。実はよく調べたら、この番号はここに書いてありました。 そして、Go言語のzstdのモジュールはgithub.com/klauspost/compress/zstdにありました。 完成したプログラムがこちら %%writefile unzip_fixed.go package main import ( "archive/zip" "github.com/klauspost/compress/zstd" "fmt" "io" "log" ) func main() { zfile, _ := zip.OpenReader("man.zip") defer zfile.Close() zfile.RegisterDecompressor(93, func(in io.Reader) io.ReadCloser { dec, _ := zstd.NewReader(in) return io.NopCloser(dec) }) for _, f := range zfile.File { rc, err := f.Open() if err != nil { log.Fatal(err) } fmt.Println(f.FileInfo().Name()) if !f.FileInfo().IsDir() { buf := make([]byte, f.UncompressedSize) n, _ := io.ReadFull(rc, buf) fmt.Println(n) } } } Writing unzip_fixed.go さっそく実行と行きたいところですが、外部モジュールを使っているので、その準備をば。 !go mod init unzip go: creating new go.mod: module unzip go: to add module requirements and sums: go mod tidy !go mod tidy go: finding module for package github.com/klauspost/compress/zstd go: downloading github.com/klauspost/compress v1.13.6 go: found github.com/klauspost/compress/zstd in github.com/klauspost/compress v1.13.6 実行! !go run unzip_fixed.go man.txt 38134 ちゃんと解凍できました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

5分で学ぶ気になるプログラミング言語(Go編)

※前回の記事はこちらになります。あわせてご覧ください 5分で学ぶ気になるプログラミング言語(Rust編) 5分で学ぶGo それでは今回はGoを学んでいきます。5分しかないので急ぎましょうw Goの公式サイトのURLは https://golang.org/ です。 「Go」という単語はググラビリティ的に難がありますが、「Golang」という呼称も結構浸透しているかなと思います。 「ゴー」って、言いやすいので好きですねw 発音で悩まないというのは日本人的には重要かと思います。 Rustでは日本語サイトが提供されていましたが、Goは硬派に英語のみです。ひるまずいきましょうw Rustでもそうでしたが、Goもファーストビューで特徴が語られています。 それによると、Goは「シンプルで信頼性が高く、効率的なソフトウェアを簡単に構築できるオープンソースのプログラミング言語」とのことです。Rustと同じ様な特徴を持っていましたが「シンプル」というのはGoのイメージとして強い部分だと思います。 Goはファーストビューに「Try Go」というプレイグラウンドのコンテンツがあるので、ここにコードを書いて「Run」を押すとリモートサーバ側で実行されすぐに結果を見ることが出来ます。まぁここでプログラミングする人はそんなに居ないと思いますが、インストールせずにすぐに試せるのはよいですね! メニューを見渡すと「Documents」と「Play」というのが学習系コンテンツだと思われますが、まだ「Play」するだけの知識がないので「Documents」から見てみます。 最初に「Getting started」というカテゴリがあり、幾つかのコンテンツが用意されています。「Installing Go」については、前回に決めた通りインストールはパッケージマネージャを使用することとしていますのでスキップします。 「Tutorial: Getting started」とチュートリアルコンテンツが良さそうなので見てみます。このチュートリアルを行うと以下の様な体験が出来ると書かれています。この様に、学習の前段でどの様な結果が得られるかを先に説明することは非常に分かりやすいと思います。 「Hello, world」のコードを書く goコマンドを使ってコードを実行する Goパッケージのツールを使ってパッケージを探し自分のコードで使用する 外部モジュールの関数を使用する それではやっていきましょう。 「3.Enable dependency tracking for your code.」では、依存性の管理のための準備の方法が紹介されています。「dependency tracking」の詳細はまだ理解できていませんが、他の言語やフレームワークでも導入されている外部モジュールの管理機能と同じものだと思われます。ここではチュートリアルの指定通り下記のコマンドを実行しておきます。 $ go mod init example/hello go: creating new go.mod: module example/hello 次にHello, worldのコードを書きます。例が示されていますので写経します。 hello.go package main import "fmt" func main() { fmt.Println("Hello, World!") } 最初に「package」として「main」が宣言されていますが、こちらはいわゆる名前空間を表すものだと思います。「main」というワードに特別な意味があるのかはまだ分かりません。次に「import」が記述されていますが、これは外部モジュールをインポートする命令でしょう。「fmt」というのはいわゆる文字列のフォーマット等を扱うモジュールだと思われます。 そしてmain関数があり、中でHello, worldの文字列を出力しています。この辺りの流れはどの言語でもほぼ同じですね。Rustでは関数宣言は「fn」でしたがGoでは「func」ですね。個人的には後者の方が好みです。ブロックはRustと同じ波括弧となっていますが、行末のセミコロンは省略できる様です。コードを書く際にマルチステートメントを使用することは殆ど無くなってきているので、個人的には賛成です。 続いて「main」に関する説明があり、Goでは「main」パッケージの「main」関数がエントリポイントになっているとのことです。何かコードを書く時はまずはこのフォーマットのコードでスタートするということですね。 それでは書いたコードを実行します。 $ go run . Hello, World! 「go」コマンドに「run」というパラメータと「.」というパラメータを渡して実行しています。「run」は分かるとして「.」の方は普通に考えると実行するファイル名を指定することになると思いますが、カレントディレクトリを指定している様です。先程Goが「main」パッケージの「main」関数を実行することを学びましたが、カレントディレクトリを指定することでそれを含むコードを探して実行してくれるということでしょうか。この辺りはまた追々学んでいくことになるのかなと思います。 ここでチュートリアルの流れからは若干逸れますが、「go」コマンドでどんなことが出来るのか把握するためにパラメータ無しで実行してみます。 $ go Go is a tool for managing Go source code. Usage: go <command> [arguments] The commands are: bug start a bug report build compile packages and dependencies clean remove object files and cached files doc show documentation for package or symbol env print Go environment information fix update packages to use new APIs fmt gofmt (reformat) package sources generate generate Go files by processing source get add dependencies to current module and install them install compile and install packages and dependencies list list packages or modules mod module maintenance run compile and run Go program test test packages tool run specified go tool version print Go version vet report likely mistakes in packages Use "go help <command>" for more information about a command. Additional help topics: buildconstraint build constraints buildmode build modes c calling between Go and C cache build and test caching environment environment variables filetype file types go.mod the go.mod file gopath GOPATH environment variable gopath-get legacy GOPATH go get goproxy module proxy protocol importpath import path syntax modules modules, module versions, and more module-get module-aware go get module-auth module authentication using go.sum packages package lists and patterns private configuration for downloading non-public code testflag testing flags testfunc testing functions vcs controlling version control with GOVCS Use "go help <topic>" for more information about that topic. ズラっとコマンドリストが表示されました。先程使った「run」コマンドも一覧にありますがここで興味深いのは「build」コマンドです。どうやらGoもRustと同じくバイナリを生成する機能を持っている様です。先程実行した際には「run」コマンドで実行しましたが、バイナリを生成して直接実行することも可能となると、スクリプト(インタプリタ)言語の簡単さとコンパイラ言語の両方の特徴を兼ね備えた便利な言語であると言えると思います。 次のセクションでは「Call code in an external package」として、外部モジュールを使ったコードの実行を学びます。 まずは外部モジュールを探すために pkg.go.devにアクセスして、キーワードで検索する方法が提供されます。このサイトはGoの公式サイトの一部の様ですが、使用したいモジュールをキーワードで探す方法が公式として提供されていることは、迷いが生まれずに済みますので非常によいと思います。 チュートリアルでは「rsc.io/quote」という外部モジュールを使用することになっています。いわゆるfortuneコマンドと同じ動きをするものの様ですね。先程書いたHello, worldのコードを変更して、表示するメッセージを「rsc.io/quote」パッケージの「quote.Go()」関数に差し替えます。 package main import "fmt" import "rsc.io/quote" func main() { fmt.Println(quote.Go()) } 次に、「go mod tidy」コマンドを実行して、モジュールをダウンロードします。 $ go mod tidy go: finding module for package rsc.io/quote go: found rsc.io/quote in rsc.io/quote v1.5.2 「tidy」というのもどういう意味か確認しておきましょう。 $ go mod Go mod provides access to operations on modules. Note that support for modules is built into all the go commands, not just 'go mod'. For example, day-to-day adding, removing, upgrading, and downgrading of dependencies should be done using 'go get'. See 'go help modules' for an overview of module functionality. Usage: go mod <command> [arguments] The commands are: download download modules to local cache edit edit go.mod from tools or scripts graph print module requirement graph init initialize new module in current directory tidy add missing and remove unused modules vendor make vendored copy of dependencies verify verify dependencies have expected content why explain why packages or modules are needed Use "go help mod <command>" for more information about a command. 必要なモジュールを追加したり、使用されていないモジュールを削除してくれるコマンドの様ですね。 全体的に、必要なツールが過不足なく用意されていて、効率よく開発が行えそうだなという印象を受けます。 最後に変更後のコードを実行してみると、rsc.io/quote パッケージの戻り値を受け取った内容に変化していました。 $ go run . Don't communicate by sharing memory, share memory by communicating. 学べたこと 5分過ぎてないか?と言われそうですがw、今回Goについて下記のことが分かりました。 Goはコンパイラ型言語である Goは、ソースコードを記述してそれをgoコマンドで直接実行もできつつ、コンパイルして実行バイナリを生成することもできる、コンパイラ型言語であることが分かりました。Rustも同じ特徴を持っていましたが、コンパイラ型であることでポータビリティに優れていたり、パフォーマンス上の優位性があったり、適用できるシーンが増えることが期待できます。 Goはビルドシステムとパッケージマネージャを内包している Goは専用のビルドシステムとパッケージマネージャを言語として持っています。言語には含まれず、別途アプリケーションとして配布されるケースも多くありますが、更新頻度やプロジェクトの継続性等の観点でやや不安は残りますので、言語としての配布に内包されているというのは安心できる要素だと思います。 Goは公式の学習コンテンツが充実している 今回試してみたチュートリアルの他、「A Tour of Go」という学習コンテンツがあり、初期学習の大きな助けになります。このコンテンツはさすがに5分ではなくしっかり時間を取って学ぶことをおススメしますが、コードを書いてその結果を確認しながら学べる様になっていて、書籍等で説明やコードを「見る」だけで学ぶのに比較して、習得はこちらの方が早いと個人的には思います。 あれ…? なんと、学べたことはRustとほぼ同じですね…w ある意味、各言語とも同じ様な特徴を持っていてそれが現代のプログラミング言語ではスタンダードであると言えるかと思います。また、プログラミング言語はある程度時間をかけて学ばなければならない分スイッチングコストが大きいものとなりますが、それをサポートする様に学習コンテンツについても力が入れられているなということが分かりました。 次回 次回は3部作の最後、Nimを学びたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GAE+Go(2nd-Gen)API実装のサンプル

こんにちは。みなさんはGoogle App Engine(GAE)使っていますか? フルマネージドでオートスケールでお気に入りのプロダクトなのですが、やや情報が少ないような・・・ 実戦投入しようと思うと、環境変数の設定や、サービス間認証、はたまたcloud_build.yamlどう書くんだ、など結構詰まるポイントが多いかと思います。 そこで、基本的な部分を実装したGAE+goのAPI実装のサンプルを公開します! これからGAE+Goを始める方のご参考になればと。 サンプル GAE-Go-sample GAEスタンダード環境です GAEのruntimeはgo116です ユーザオブジェクトを登録/取得するだけの簡単なAPIのサンプルです Firebaseを使うので、Firebaseのセットアップと、GAEサービスアカウントへの「Firebase管理者」ロールの付与が必要です ポイントの紹介 工夫しているポイントをいくつかご紹介します。 環境変数が使えるようにしてあります 調べても意外とサンプルが出てこないように思います。envconfigを使い、ビルド時にapp_{ENV}.yamlから埋め込みます。 クリーンアーキテクチャを意識したレイヤリング  全体の構成は↓こんな感じです。 - /src - /handler - /input - request bodyをマッピングする構造体 - /output - response bodyをマッピングする構造体 - router.go - APIのルーティング - /domain - /model - ドメインモデル - /repository - infra層(DBやFirestoreなど)のinterface - /usecase - ビジネスロジックの実装 - /infra - repositoryの実装 - /registry - repositoryの実装を返す - /lib - logging、HTTPリクエストなど共通基盤 - /main - app_{ENV}.yaml(ビルド時にenvconfigで出し分けます) - main.go テスト時にRepository層をモックできるようにDIを実装してあります。 こちらの記事がとても参考になります。 ロギングの強化 GAEは1st-Genのロギングが素敵すぎるのですが、これはもう諦めるしかないですね。。。 こちらの記事を参考に、できるだけGAE-1st-Genに近い使い心地のログを出せるようにしています。 Identity Aware Proxy(IAP)のサンプル GAE-2nd-Genでは魔法のヘッダx-appengine-appidがつかないため、サービス間認証はIAPで実現することになります。 IAP有効状態で、他サービスにHTTPリクエストを投げる場合のサンプルコードを実装してあります。 Firebaseのサンプル 大体どこでも使うAuthenticationとFirestoreのサンプルを実装してあります。 cloudbuild.yaml Cloud Buildについても案外サンプルが少なく苦労したので。 Cloud Buildの代入変数で_APP_YAML_NAMEに指定したい環境のapp_{ENV}.yamlを指定してください。 終わりに 参考になれば幸いです。今後は工夫ポイントそれぞれの詳しい解説も投稿していく予定です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoとGORMを使った勉強(1) 

概要 ・GoとGORMを使ってDBに接続してテーブルの情報を画面に表示させます。 ・続きあります。 環境 ・DockerでGoの環境構築  docker run -itd -p 8080:80 golang:latest 準備 Docker #mysqlの用意 root@df86ed89dfdc:/go# apt update root@df86ed89dfdc:/go# apt install mariadb-server root@df86ed89dfdc:/go# service mariadb start #初期設定 root@df86ed89dfdc:~# mysql_secure_installation データの用意 #mysqlにログイン root@3ba225e11191:~# mysql -u root -p #DBを作る MariaDB [(none)]> create database hoge; #createしたDBに入る MariaDB [(none)]> use hoge Database changed #usersテーブルを作る MariaDB [hoge]> create table users(id int auto_increment,name varchar(255),index(id),created_at datetime,updated_at datetime,deleted_at datetime); #usersテーブルの状態を確認する MariaDB [hoge]> desc users; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | MUL | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | created_at | datetime | YES | | NULL | | | updated_at | datetime | YES | | NULL | | | deleted_at | datetime | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ #データを追加 MariaDB [hoge]> insert into users values(null,"sample_user",null,null,null); MariaDB [hoge]> select * from users; +----+-------------+------------+------------+------------+ | id | name | created_at | updated_at | deleted_at | +----+-------------+------------+------------+------------+ | 1 | sample_user | NULL | NULL | NULL | +----+-------------+------------+------------+------------+ DBにユーザーを追加して権限を与える rootユーザーではエラーが出る #登録されてるホストとユーザー名の確認 MariaDB [hoge]> select user, host from mysql.user; +-------------+-----------+ | User | Host | +-------------+-----------+ | mariadb.sys | localhost | | mysql | localhost | | root | localhost | +-------------+-----------+ #fugaというユーザーを追加する MariaDB [(none)]> create user 'fuga'@'localhost' identified by 'fugapass'; #fugaの権限を確認する MariaDB [hoge]> show grants for fuga@localhost; +-------------------------------------------------------------------------------------------------------------+ | Grants for fuga@localhost | +-------------------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO `fuga`@`localhost` IDENTIFIED BY PASSWORD '*7449FCB52B0D3D41243103FA7B23D545CD33F2A5' | +-------------------------------------------------------------------------------------------------------------+ #fugaにhogeDBの操作権限を与える  MariaDB [hoge]> grant all privileges on hoge.* to "fuga"@"localhost"; #fugaの権限を確認する MariaDB [hoge]> show grants for fuga@localhost; +-------------------------------------------------------------------------------------------------------------+ | Grants for fuga@localhost | +-------------------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO `fuga`@`localhost` IDENTIFIED BY PASSWORD '*7449FCB52B0D3D41243103FA7B23D545CD33F2A5' | | GRANT ALL PRIVILEGES ON `hoge`.* TO `fuga`@`localhost` | +-------------------------------------------------------------------------------------------------------------+ MariaDB [hoge]> exit コーディング main.go package main import ( "github.com/gin-gonic/gin" _ "github.com/joho/godotenv/autoload" "gorm.io/driver/mysql" "gorm.io/gorm" ) func main() { r := gin.Default() r.GET("/users", ListUsers) r.Run(":80") } func DB() *gorm.DB { dsn := "fuga:fugapass@tcp(127.0.0.1:3306)/hoge?charset=utf8mb4&parseTime=True&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") } return db } func ListUsers(c *gin.Context) { var users []User db := DB() db.Find(&users) // find product with integer primary key c.JSON(200, gin.H{ "user": users, }) } type User struct { gorm.Model Name string } Ginをダウンロードする Docker root@df86ed89dfdc:~# go get github.com/gin-gonic/gin root@df86ed89dfdc:~# go mod init example.com/m root@df86ed89dfdc:~# go mod vendor 確認 補足 ユーザーを追加した理由 rootユーザーを使ってDBに接続しようとしたらエラーになるので新たにユーザを追加しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ginでサーバーを立ち上げてJSONのメッセージを表示

概要 Ginでサーバーを立ち上げてJSONのメッセージを表示させる。 環境 ・Docker ・MacBook docker run でgolamgが入ったコンテナを作る。 ~/d/q/gin_server ❯❯❯ docker run -itd --name gin_server -p 8080:80 golang:latest #コンテナにはいる ~/d/q/gin_server ❯❯❯ docker attach gin_server Docker root@1cc8cba550f2:~# cd ../root #Vimをインストールする root@1cc8cba550f2:~# apt update root@1cc8cba550f2:~# apt install vim #Vimで空のmain.goを作る root@1cc8cba550f2:~# vim main.go #ginをダウンロードする root@1cc8cba550f2:~# go get github.com/gin-gonic/gin go: downloading github.com/gin-gonic/gin v1.7.4 root@1cc8cba550f2:~# go mod init example.com/m コーディング main.go package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run(":80") } go mod vendorする Docker root@1cc8cba550f2:~# go mod vendor go: finding module for package github.com/gin-gonic/gin go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.7.4 main.goを起動する root@1cc8cba550f2:~# go run main.go ブラウザからlocalhostにアクセスする 画面に下記のように表示されたら成功 { message: "pong" }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む