20210128のGoに関する記事は3件です。

MySQL に ssl 認証で接続

次のファイルがあるフォルダーで実行します。

client-cert.pem
client-key.pem
server-ca.pem

コマンド

ssl_connect.sh
host="example.com"
user="scott"
pass="secret"
#
mysql --ssl-ca=server-ca.pem --ssl-cert=client-cert.pem \
        --ssl-key=client-key.pem \
        --host=${host} --user=${user} --password=${pass}

Python3

show_tables.py
#! /usr/bin/python
#
#   show_tables.py
#
#                       Jan/28/2021
import pymysql.cursors
#
host_aa='example.com' 
user_aa='scott'
pass_aa='secret'
db_aa='dbfirst'
#
connection = pymysql.connect(host=host_aa,
    user=user_aa,
    password=pass_aa,
    db=db_aa,
    charset='utf8',
    cursorclass=pymysql.cursors.DictCursor,
    ssl={'key': './client-key.pem', 'cert': './client-cert.pem', 'ca': './server-ca.pem','check_hostname': False})
cursor = connection.cursor()
cursor.execute("show tables")
result = cursor.fetchall()
# print(result)
for rr in result:
    print(rr)
cursor.close()
connection.close()

Node.js

show_tables.js
#! /usr/bin/node
// ---------------------------------------------------------------
//  show_tables.js
//
//                  Jan/28/2021
//
// ---------------------------------------------------------------
'use strict'

var fs = require("fs")
// ---------------------------------------------------------------
console.error ("*** 開始 ***")

var mysql = require('mysql')

var connection = mysql.createConnection ({
    host: 'example.com',
    user: 'scott',
    password: 'secret',
    database : 'dbfirst',
ssl      : {
        ca   : fs.readFileSync('./server-ca.pem'),
        key  : fs.readFileSync('./client-key.pem'),
        cert : fs.readFileSync('./client-cert.pem'),
  }
    })

connection.query("show tables", function (err, rows)
    {
    if (err) throw err
    console.log (rows.length)

    rows.forEach(function(row)
        {
        console.log(row)
        })


    connection.end()
    console.error ("*** 終了 ***")
    })

// ---------------------------------------------------------------

Go

show_tables.go
// ----------------------------------------------------------------
//
//  show_tables.go
//
//                  Jan/29/2021
//
// ----------------------------------------------------------------
package main

import (
    "crypto/tls"
    "database/sql"
    "fmt"
    "log"
    "os"

    "github.com/go-sql-driver/mysql"
)

func main() {
    fmt.Fprintf (os.Stderr,"*** 開始 ***\n")
    cert, err := tls.LoadX509KeyPair("./client-cert.pem", "./client-key.pem")
    if err != nil {
        log.Fatal(err)
    }
    clientCert := []tls.Certificate{cert}

    mysql.RegisterTLSConfig("custom", &tls.Config{
        Certificates:       clientCert,
        InsecureSkipVerify: true,
    })

    db, err := sql.Open("mysql", "scott:secret@tcp(example.com:3306)/dbfirst?tls=custom")
    if err != nil {
        log.Fatal(err)
    }

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

sql_str := "show tables"
rows, err := db.Query(sql_str)
if err != nil {
        fmt.Println(err)
}
defer rows.Close()

for rows.Next() {
        var name string
    if err := rows.Scan(&name); err != nil {
                fmt.Println(err)
        }
        fmt.Printf ("%s\n",name)
}

if err := rows.Err(); err != nil {
        fmt.Println(err)
        }

    fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ----------------------------------------------------------------

参考ページ
MySQLでクライアント証明書を使う

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【自己学習用】はじめてのGo3

type

Goではtypeを用いて既存の型を拡張した独自の型を定義できる。
呼び出す際に,型が適合していないとコンパイルエラー。

type ID int
type Priority int

func ProcessTask(id ID, priority Priority) {
}

var id ID = 3
var priority Priority = 5
ProcessTask(priority, id) // コンパイルエラー

構造体(struct)

GOの構造体はメソッドを持つことができ,RubyやJavaでのクラスに近い。
構造体もtypeを用いて宣言し,構造体名のあとにそのフィールドを記述する。
各フィールドの可視性は名前で決まり,大文字で始まる場合はパブリック,小文字はプライベート。

type Task struct {
    ID int         // public
    Detail string  // public
    done bool      // private
}

func main() {
    var task Task = Task{
        ID: 1,
        Detail: "buy the milk",
        done: true,
    }
    fmt.Println(task.ID) // 1
    fmt.Println(task.Detail) // "buy the milk"
    fmt.Println(task.done) // true

    task := Task{} //構造体の生成時に値を明示的に指定しなかった場合は,ゼロ値で初期化
}

コンストラクタ

Goにはコンストラクタがない。
代わりにNewで始まる関数を定義し,その内部で構造体を生成するのが通例。

func NewTask(id int, detail string) *Task {
    task := &Task{
        ID: id,
        Detail: detail,
        done: false,
    }
    return task
}

func main() {
    task := NewTask(1, "buy the milk")
    // &{ID:1 Detail:buy the milk done:false}
    fmt.Printf("%+v", task)
}

メソッド

型にはメソッドを定義できます。メソッドは,そのメソッドを実行した対象の型をレシーバとして受>け取り,メソッドの内部で使用できます。
つまりいわゆる拡張メソッドのこと。
func (メソッドを定義する型名の変数名, メソッドを定義する型名) メソッド名 戻り値 {
}

package main

import (
    "fmt"
)

type Task struct {
    ID     int
    Detail string
    done   bool
}

func NewTask(id int, detail string) *Task {
    task := &Task{
        ID:     id,
        Detail: detail,
        done:   false,
    }
    return task
}

func (task Task) String() string {
    str := fmt.Sprintf("%d) %s", task.ID, task.Detail)
    return str
}

func main() {
    task := NewTask(1, "buy the milk")
    fmt.Printf("%s", task.String()) // 1) buy the milk
}

インタフェース

インタフェースの名前は,実装すべき関数名が単純な場合は,その関数名にerを加えた名前を付ける慣習がある。
Goは,型がインタフェースに定義されたメソッドを実装していれば,インタフェースを満たしているとみなす。
↑のTaskにはString()メソッドを実装しているため,Stringerを引数に取る次のような関数に渡すことができる。

type Stringer interface {
    String() string
}

~省略~

func main() {
    task := NewTask(1, "buy the milk")
    fmt.Printf("%s", task.String()) // 1) buy the milk

    Print(task) // TaskにはStringメソッドを定義しているためエラーにならない
}

func Print(stringer Stringer) {
    fmt.Println(stringer.String())
}

次のような何も指定していないインタフェースを定義すると、どんな型も受け取ることができる関数を定義できる。
定義しなくてもinterface{}と記述すると同じ意味になる。

func Do(e Any) {
  // do something
}

Do("a") // どのような型も渡すことができる

func Do(e interface{}) {
  // do something
}

Do("a") // どのような型も渡すことができる

型の埋め込み

Goでは,継承はサポートされていない代わりに、ほかの型を「埋め込む」(⁠Embed)という方式で,構造体やインタフェースの振る舞いを拡張できる。

package main

import (
    "fmt"
)

type User struct {
    FirstName string
    LastName  string
}

func (u *User) FullName() string {
    fullname := fmt.Sprintf("%s %s",
        u.FirstName, u.LastName)
    return fullname
}

func NewUser(firstName, lastName string) *User {
    return &User{
        FirstName: firstName,
        LastName:  lastName,
    }
}

type Task struct {
    ID     int
    Detail string
    done   bool
    *User  // Userを埋め込む
}

func NewTask(id int, detail,
    firstName, lastName string) *Task {
    task := &Task{
        ID:     id,
        Detail: detail,
        done:   false,
        User:   NewUser(firstName, lastName),
    }
    return task
}

func main() {
    task := NewTask(1, "buy the milk", "Jxck", "Daniel")
    // TaskにUserのフィールドが埋め込まれている
    fmt.Println(task.FirstName)
    fmt.Println(task.LastName)
    // TaskにUserのメソッドが埋め込まれている
    fmt.Println(task.FullName())
    // Taskから埋め込まれたUser自体にもアクセス可能
    fmt.Println(task.User)
    fmt.Println(task.User.FirstName) //Userからもメンバにアクセス可能
    /*
    type Task struct {
        ID     int
        Detail string
        FirstName string
        done   bool
        *User  // Userを埋め込む
    }
    もしTaskにUser配下のメンバと同名のメンバがいたらどうなるか?
    →エラーとはならず共存する
    fmt.Println(task.FirstName)
    fmt.Println(task.User.FirstName)
    */
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Redis の WebAPI (Gin)

こちらで定めた仕様を満たすサーバーサイドのプログラムです。
Redis の WebAPI を作成

次のプログラムを改造しました。
Gin の使い方

redis_api.go
// ---------------------------------------------------------------
//
//  redis_api.go
//
//                  Jan/28/2021
// ---------------------------------------------------------------
package main

import "github.com/gin-gonic/gin"
import "net/http"
import (
    "os"
    "fmt"
    "net"
    "strings"
    "encoding/json"
)

// ---------------------------------------------------------------
func main() {
    router := gin.Default()

    router.GET("/user/:name", func(c *gin.Context) {
        name := c.Param("name")
        c.String(http.StatusOK, "Hello %s", name)
    })

    router.POST("/redis_read", func(c *gin.Context) {
        key := c.PostForm("key")
        message := read_proc(key)
        c.String(http.StatusOK, message)
    })

    router.POST("/redis_insert", func(c *gin.Context) {
        key := c.PostForm("key")
        value := c.PostForm("value")
        message := insert_proc(key,value)
        c.String(http.StatusOK, message)
    })

    router.POST("/redis_list", func(c *gin.Context) {
        message := list_proc()
        c.String(http.StatusOK, message)
    })
    router.Run(":8080")
}

// ---------------------------------------------------------------
// [4]:
func read_proc(key string) string {
    fmt.Fprintf (os.Stderr,"*** read_proc ***\n")
    hostname := "localhost"
    port := "6379"

    conn, err := net.Dial ("tcp", hostname + ":" + port)
    if err != nil {
        fmt.Println(err)
        return "err"
        }

    json_str := mcached_socket_read_proc (conn,key)
    conn.Close ()

    return json_str
}

// ---------------------------------------------------------------
// [4-6]:
func mcached_socket_read_proc (conn net.Conn,key_in string) string {
    json_str := ""
    str_received := socket_read_proc (conn,key_in)

    lines := strings.Split(str_received,"\n")

    if (! strings.Contains(lines[0],"END")) {
        json_str = lines[1]
        }

    return  json_str
}

// ---------------------------------------------------------------
// [4-6-8]:
func socket_read_proc (conn net.Conn,key_in string) string {
    str_received := ""
    _, err := conn.Write([]byte("get " + key_in + "\r\n"))
    if err != nil {
        fmt.Println(err)
        return str_received
        }

    buf := make([]byte, 1024)
    nn, err := conn.Read(buf[:])
    if err != nil {
        fmt.Println(err)
        return str_received
        }

    str_received = string(buf[0:nn])

    return  str_received
}

// ---------------------------------------------------------------
// [6]:
func insert_proc(key string, value string) string {
    fmt.Fprintf (os.Stderr,"*** insert_proc ***\n")
    hostname := "localhost"
    port := "6379"

    conn, err := net.Dial ("tcp", hostname + ":" + port)
    if err != nil {
        fmt.Println(err)
        return "err"
        }

    redis_socket_write_proc (conn,key,value)

    conn.Close ()

    return "ok"
}

// ----------------------------------------------------------------
func redis_socket_write_proc (conn net.Conn,key_in string,json_str string) {
    fmt.Println (key_in)
    fmt.Println (json_str)

    comm_aa := "set " + key_in + " '" + json_str + "'\r\n"
    conn.Write([]byte(comm_aa))

    buf := make ([]byte,1024)
    conn.Read (buf[:])

    fmt.Println (string(buf[0:10]))
}

// ----------------------------------------------------------------
// [8]:
func list_proc() string {
    fmt.Fprintf (os.Stderr,"*** list_proc ***\n")
    hostname := "localhost"
    port := "6379"

    conn, err := net.Dial ("tcp", hostname + ":" + port)
    if err != nil {
        fmt.Println(err)
        return "err"
        }


    keys := key_get_proc(conn)

    conn.Close ()

    output, _ := json.Marshal(keys)

    return string(output)
}

// ---------------------------------------------------------------
// [8-4]:
func key_get_proc (conn net.Conn) []string {
    var keys []string

    string_received := string_get_proc (conn)

    if 0 < len (string_received) {
        datax := strings.Split (string_received,"\n")
        for _, pp := range datax {
            if (0 < len (pp)) && (pp[:1] == "t") {
                pp = strings.TrimRight(pp, "\r")
                keys = append(keys, pp)
                }
            }
        }

    return keys
}

// ----------------------------------------------------------------
// [8-4-4]:
func string_get_proc (conn net.Conn) string{
    str_received := ""

    comm_aa := "keys *" + "\r\n"

    _, err := conn.Write([]byte(comm_aa))
    if err != nil {
        fmt.Println(err)
        return str_received
        }

    buf := make([]byte, 1024)
    nn, err := conn.Read(buf[:])
    if err != nil {
        fmt.Println(err)
        return str_received
        }

    str_received = string(buf[0:nn])

    return str_received
}

// ---------------------------------------------------------------

サーバーの実行

go run redis_api.go

テストスクリプト

read

curl -X POST http://localhost:8080/redis_read -d key=t1851

insert

curl -X POST http://localhost:8080/redis_insert -d key=t1855 \
    -d value='{"name": "宇都宮","population": 8751206,"date_mod": "2021-1-16"}'

list

curl -X POST http://localhost:8080/redis_list
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む