// db.go
package db

import (
	"database/sql"
	"encoding/json"
	"fmt"

	"log"
	"strings"

	"strconv"
	"time"

	"bytes"
	"crypto/tls"

	"io/ioutil"
	"net/http"

	"crypto/md5"
	"encoding/hex"

	"pool/internal/utility"

	_ "github.com/go-sql-driver/mysql"
	"go.uber.org/zap"
	"gopkg.in/natefinch/lumberjack.v2"
)

const DB_VERSION string = "v2.0a"

var dbconnstr string
var sharesdbconnstr string

type DbConfigInfo struct {
	Ip       string `json:"ip"`
	Port     int    `json:"port"`
	Username string `json:"username"`
	Password string `json:"password"`
	Dbname   string `json:"dbname"`
}

type DbConfig struct {
	Zaplog   zap.Config              `json:"zap"`
	Db       DbConfigInfo            `json:"db"`
	Shares   DbConfigInfo            `json:"shares"`
	Logrotae utility.LogRotateConfig `json:"logrotate"`
}

type Config_db_info struct {
	DbHostIp   string
	DbHostPort int
	DbUserName string
	DbPassWord string
	DbName     string
}

type PoolDb struct {
	*sql.DB
	Logg *zap.Logger
}

type DbContext struct {
	DbExit  bool
	AppExit chan bool

	Db_obj     *PoolDb
	Shares_obj *PoolDb

	DbCfg  DbConfig
	Coin   string
	Module string

	LastMinersTime      time.Time
	LastMinersStatsTime time.Time
	/*LastMinerTime         time.Time
	LastUsersTime         time.Time
	LastUsersStatsTime    time.Time
	LastUsersBlkStatsTime time.Time
	LastPoolTime          time.Time
	LastPoolStatsTime     time.Time*/
	LastPoolBlkStatsTime  time.Time
	LastBlockDetailHeight int64
	LastBlockNewTime      time.Time
	LastAddressTime       time.Time

	Miners_ch      chan Miners_db_msg
	MinersStats_ch chan MinersStats_db_msg
	/*Miner_ch         chan Miner_db_msg
	Users_ch         chan Users_db_msg
	UsersStats_ch    chan UsersStats_db_msg
	UsersBlkStats_ch chan UsersBlkStats_db_msg
	Pool_ch          chan Pool_db_msg
	PoolStats_ch     chan PoolStats_db_msg*/
	PoolBlkStats_ch chan PoolBlkStats_db_msg
	BlkDetail_ch    chan BlkDetail_db_msg
	BlkNew_ch       chan BlkNew_db_msg
	Address_ch      chan Address_db_msg

	LogR *lumberjack.Logger
}

type Miners_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	Fromip       string
	State        string
	Online       time.Time
	Offline      time.Time
	Retry        int
	Duration     float64
	Protocol     string
	User         string
	Miner        string
	Index        string
	Diff         float64
	Height       uint32
	Accepts      float64
	Rejects      float64
	Ratio        float64
	Staleds      float64
	Lows         float64
	Duplicates   float64
	Formats      float64
	Others       float64
	Disabled     bool
	Last_submit  time.Time
	Submits      int
	Blocks       int
	Orphans      int
	Orphan_ratio float64
}

type MinersStats_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	User  string
	Miner string
	Index string

	Shares5m  float64
	Shares15m float64
	Shares30m float64
	Shares1h  float64
	Shares3h  float64
	Shares6h  float64
	Shares12h float64
	Shares24h float64
	Shares48h float64

	Rejects5m  float64
	Rejects15m float64
	Rejects30m float64
	Rejects1h  float64
	Rejects3h  float64
	Rejects6h  float64
	Rejects12h float64
	Rejects24h float64
	Rejects48h float64

	Mhs5m  float64
	Mhs15m float64
	Mhs30m float64
	Mhs1h  float64
	Mhs3h  float64
	Mhs6h  float64
	Mhs12h float64
	Mhs24h float64
	Mhs48h float64

	Ratio5m  float64
	Ratio15m float64
	Ratio30m float64
	Ratio1h  float64
	Ratio3h  float64
	Ratio6h  float64
	Ratio12h float64
	Ratio24h float64
	Ratio48h float64
}

/*
type Miner_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	User  string
	Miner string
	Index string

	Target        string
	Submit_target string
	Height        int64
	Success       int
	Pow           string
	Net_target    string
	Submit        string
	Hash          string
	Header        string
	Accepts       float64
	Total_accepts float64
	Rejects       float64
	Total_rejects float64
	Reward        float64
	Fee           float64
	Nonce         string
	SubIdx        int64
}*/
/*
type Users_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	User     string
	Normal   int64
	Abnormal int64

	Offline     int64
	MhsZero     int64
	MhsLow      int64
	HighRejects int64
	Unstable    int64

	Submits      int64
	Blocks       int64
	Orphans      int64
	Orphan_ratio float64
	Reward       float64
	Fee          float64
}*/

/*type UsersStats_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	User string

	Shares5m  float64
	Shares15m float64
	Shares30m float64
	Shares1h  float64
	Shares3h  float64
	Shares6h  float64
	Shares12h float64
	Shares24h float64
	Shares48h float64

	Rejects5m  float64
	Rejects15m float64
	Rejects30m float64
	Rejects1h  float64
	Rejects3h  float64
	Rejects6h  float64
	Rejects12h float64
	Rejects24h float64
	Rejects48h float64

	Mhs5m  float64
	Mhs15m float64
	Mhs30m float64
	Mhs1h  float64
	Mhs3h  float64
	Mhs6h  float64
	Mhs12h float64
	Mhs24h float64
	Mhs48h float64

	Ratio5m  float64
	Ratio15m float64
	Ratio30m float64
	Ratio1h  float64
	Ratio3h  float64
	Ratio6h  float64
	Ratio12h float64
	Ratio24h float64
	Ratio48h float64
}*/

/*type UsersBlkStats_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	User  string
	Miner string
	Index string

	Height     int64
	Hash       string
	Pow        string
	Net_target string
	Submit     string
	Success    int
	Accepts    float64
	Rejects    float64
	Reward     float64
	Fee        float64
	Nonce      string
	SubIdx     int64
}*/

/*type Pool_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	Miners   int64
	Normal   int64
	Abnormal int64

	Offline     int64
	MhsZero     int64
	MhsLow      int64
	HighRejects int64
	Unstable    int64

	Net_target   string
	Height       uint64
	Submits      int64
	Blocks       int64
	Orphans      int64
	Orphan_ratio float64
	Reward       float64
	Fee          float64
}*/

/*type PoolStats_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	Shares5m  float64
	Shares15m float64
	Shares30m float64
	Shares1h  float64
	Shares3h  float64
	Shares6h  float64
	Shares12h float64
	Shares24h float64
	Shares48h float64

	Rejects5m  float64
	Rejects15m float64
	Rejects30m float64
	Rejects1h  float64
	Rejects3h  float64
	Rejects6h  float64
	Rejects12h float64
	Rejects24h float64
	Rejects48h float64

	Mhs5m  float64
	Mhs15m float64
	Mhs30m float64
	Mhs1h  float64
	Mhs3h  float64
	Mhs6h  float64
	Mhs12h float64
	Mhs24h float64
	Mhs48h float64

	Ratio5m  float64
	Ratio15m float64
	Ratio30m float64
	Ratio1h  float64
	Ratio3h  float64
	Ratio6h  float64
	Ratio12h float64
	Ratio24h float64
	Ratio48h float64
}*/

type PoolBlkStats_db_msg struct {
	Id         int
	Msg        string
	MinerType  string
	Date       time.Time
	FromGroup  uint32
	ToGroup    uint32
	Height     int64
	Hash       string
	Pow        string
	Net_target string
	Submit     string
	Success    int
	Accepts    float64
	Rejects    float64
	Reward     float64
	Fee        float64
	Nonce      string
	SubIdx     int64
}

type BlkHeightDetail_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	From int64
	To   int64
}

type BlkDetail_db_msg struct {
	Id         int
	Msg        string
	MinerType  string
	Date       time.Time
	FromGroup  uint32
	ToGroup    uint32
	Height     int64
	Hash       string
	User       string
	Miner      string
	Index      string
	Success    int
	Miner_diff float64
	Pool_diff  float64
	Nonce      string
	SubIdx     int64
}

type BlkNew_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time
	FromGroup uint32
	ToGroup   uint32
	Height    int64
	Hash      string
	Success   int
	Nonce     string
	SubIdx    int64
}

type Address_db_msg struct {
	Id        int
	Msg       string
	MinerType string
	Date      time.Time

	Addr  string
	Sum   string
	Valid bool
}

var DbCtx DbContext

func InitConfig(dbconfig *DbConfig) {
	data, err := ioutil.ReadFile("db.conf")
	if err != nil {
		panic(err.Error())
	}
	if err = json.Unmarshal(data, &dbconfig); err != nil {
		panic(err.Error())
	}
}

func OpenPoolDb(dbtype string, dbsql string) (*PoolDb, error) {
	db, err := sql.Open(dbtype, dbsql)
	if err != nil {
		return nil, err
	}
	pooldb := &PoolDb{DB: db}
	return pooldb, nil
}

func (this *PoolDb) ClosePoolDb() error {
	err := this.Close()
	if err != nil {
		return err
	}
	return err
}

func (this *PoolDb) QueryPoolDb(query string, args ...interface{}) (*sql.Rows, error) {
	result, err := this.DB.Query(query, args...)
	if err != nil {
		this.Logg.Error("[db]", zap.String("query db err", err.Error()))
		return nil, err
	}
	return result, nil
}

/*
func (this *PoolDb) InsertPoolDb2(table string, coinType string, table_name string, result interface{}) error {
	//log.Println(table_name)
	switch table {
	case "miner":
		var msg Miner_db_msg = result.(Miner_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,user,miner,`refindex`,target,submit_target,height,`success`,pow,net_target,submit,hash,header,accepts,total_accepts,rejects,total_rejects,reward,fee,nonce,subidx) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miner,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Miner, msg.Index, msg.Target, msg.Submit_target, msg.Height, msg.Success, msg.Pow, msg.Net_target, msg.Submit, msg.Hash, msg.Header, msg.Accepts, msg.Total_accepts, msg.Rejects, msg.Total_rejects, msg.Reward, msg.Fee, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miner,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert miner table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	default:
		this.Logg.Error("[db]", zap.String("inser table unkown table", table))
		break
	}
	return nil
}*/

func (this *PoolDb) InsertPoolDb(table string, coinType string, result interface{}) error {
	var table_name string = coinType + "_" + table
	switch table {
	case "miners":
		var msg Miners_db_msg = result.(Miners_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,fromip,state,online,offline,retry,duration,protocol,user,miner,`refindex`,diff,height,accepts,rejects,ratio,staleds,lows,duplicates,formats,others,is_disabled,last_submit,submits,blocks,orphans,orphan_ratio) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miners,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Fromip, msg.State, msg.Online, msg.Offline, msg.Retry, msg.Duration, msg.Protocol, msg.User, msg.Miner, msg.Index, msg.Diff, msg.Height, msg.Accepts, msg.Rejects, msg.Ratio, msg.Staleds, msg.Lows, msg.Duplicates, msg.Formats, msg.Others, msg.Disabled, msg.Last_submit, msg.Submits, msg.Blocks, msg.Orphans, msg.Orphan_ratio)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miners,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert miners table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "miners_stats":
		var msg MinersStats_db_msg = result.(MinersStats_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,user,miner,`refindex`,shares5m,shares15m,shares30m,shares1h,shares3h,shares6h,shares12h,shares24h,shares48h,rejects5m,rejects15m,rejects30m,rejects1h,rejects3h,rejects6h,rejects12h,rejects24h,rejects48h,mhs5m,mhs15m,mhs30m,mhs1h,mhs3h,mhs6h,mhs12h,mhs24h,mhs48h,ratio5m,ratio15m,ratio30m,ratio1h,ratio3h,ratio6h,ratio12h,ratio24h,ratio48h) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miners_stats,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Miner, msg.Index, msg.Shares5m, msg.Shares15m, msg.Shares30m, msg.Shares1h, msg.Shares3h, msg.Shares6h, msg.Shares12h, msg.Shares24h, msg.Shares48h, msg.Rejects5m, msg.Rejects15m, msg.Rejects30m, msg.Rejects1h, msg.Rejects3h, msg.Rejects6h, msg.Rejects12h, msg.Rejects24h, msg.Rejects48h, msg.Mhs5m, msg.Mhs15m, msg.Mhs30m, msg.Mhs1h, msg.Mhs3h, msg.Mhs6h, msg.Mhs12h, msg.Mhs24h, msg.Mhs48h, msg.Ratio5m, msg.Ratio15m, msg.Ratio30m, msg.Ratio1h, msg.Ratio3h, msg.Ratio6h, msg.Ratio12h, msg.Ratio24h, msg.Ratio48h)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miners_stats,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert miners stats table sucess,miner type", coinType), zap.String("sql", insert_sql))

		break
	/*case "miner":
		var msg Miner_db_msg = result.(Miner_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,user,miner,`refindex`,target,submit_target,height,`success`,pow,net_target,submit,hash,header,accepts,total_accepts,rejects,total_rejects,reward,fee,nonce,subidx) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miner,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Miner, msg.Index, msg.Target, msg.Submit_target, msg.Height, msg.Success, msg.Pow, msg.Net_target, msg.Submit, msg.Hash, msg.Header, msg.Accepts, msg.Total_accepts, msg.Rejects, msg.Total_rejects, msg.Reward, msg.Fee, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_miner,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert miner table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "users":
		var msg Users_db_msg = result.(Users_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,user,normal,abnormal,offline,mhszero,mhslow,highreject,unstable,submits,blocks,orphans,orphan_ratio,reward,fee) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Normal, msg.Abnormal, msg.Offline, msg.MhsZero, msg.MhsLow, msg.HighRejects, msg.Unstable, msg.Submits, msg.Blocks, msg.Orphans, msg.Orphan_ratio, msg.Reward, msg.Fee)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert users table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "users_stats":
		var msg UsersStats_db_msg = result.(UsersStats_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,user,shares5m,shares15m,shares30m,shares1h,shares3h,shares6h,shares12h,shares24h,shares48h,rejects5m,rejects15m,rejects30m,rejects1h,rejects3h,rejects6h,rejects12h,rejects24h,rejects48h,mhs5m,mhs15m,mhs30m,mhs1h,mhs3h,mhs6h,mhs12h,mhs24h,mhs48h,ratio5m,ratio15m,ratio30m,ratio1h,ratio3h,ratio6h,ratio12h,ratio24h,ratio48h) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users_stats,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Shares5m, msg.Shares15m, msg.Shares30m, msg.Shares1h, msg.Shares3h, msg.Shares6h, msg.Shares12h, msg.Shares24h, msg.Shares48h, msg.Rejects5m, msg.Rejects15m, msg.Rejects30m, msg.Rejects1h, msg.Rejects3h, msg.Rejects6h, msg.Rejects12h, msg.Rejects24h, msg.Rejects48h, msg.Mhs5m, msg.Mhs15m, msg.Mhs30m, msg.Mhs1h, msg.Mhs3h, msg.Mhs6h, msg.Mhs12h, msg.Mhs24h, msg.Mhs48h, msg.Ratio5m, msg.Ratio15m, msg.Ratio30m, msg.Ratio1h, msg.Ratio3h, msg.Ratio6h, msg.Ratio12h, msg.Ratio24h, msg.Ratio48h)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users_stats,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert users stats table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "users_blkstats":
		var msg UsersBlkStats_db_msg = result.(UsersBlkStats_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id, `date`, `user`, miner, `refindex`, height, `hash`, pow, net_target, submit, `success`, accepts, rejects, reward, fee, nonce, subidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users_blkstats,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.User, msg.Miner, msg.Index, msg.Height, msg.Hash, msg.Pow, msg.Net_target, msg.Submit, msg.Success, msg.Accepts, msg.Rejects, msg.Reward, msg.Fee, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_users_blkstats,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert users blkstats table sucess,miner type", coinType), zap.String("sql", insert_sql))

		break
	case "pool":
		var msg Pool_db_msg = result.(Pool_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,miners,normal,abnormal,offline,mhszero,mhslow,highreject,unstable,net_target,height,submits,blocks,orphans,orphan_ratio,reward,fee) VALUES  (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Miners, msg.Normal, msg.Abnormal, msg.Offline, msg.MhsZero, msg.MhsLow, msg.HighRejects, msg.Unstable, msg.Net_target, msg.Height, msg.Submits, msg.Blocks, msg.Orphans, msg.Orphan_ratio, msg.Reward, msg.Fee)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert pool table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "pool_stats":
		var msg PoolStats_db_msg = result.(PoolStats_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,shares5m,shares15m,shares30m,shares1h,shares3h,shares6h,shares12h,shares24h,shares48h,rejects5m,rejects15m,rejects30m,rejects1h,rejects3h,rejects6h,rejects12h,rejects24h,rejects48h,mhs5m,mhs15m,mhs30m,mhs1h,mhs3h,mhs6h,mhs12h,mhs24h,mhs48h,ratio5m,ratio15m,ratio30m,ratio1h,ratio3h,ratio6h,ratio12h,ratio24h,ratio48h) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool_stats,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Shares5m, msg.Shares15m, msg.Shares30m, msg.Shares1h, msg.Shares3h, msg.Shares6h, msg.Shares12h, msg.Shares24h, msg.Shares48h, msg.Rejects5m, msg.Rejects15m, msg.Rejects30m, msg.Rejects1h, msg.Rejects3h, msg.Rejects6h, msg.Rejects12h, msg.Rejects24h, msg.Rejects48h, msg.Mhs5m, msg.Mhs15m, msg.Mhs30m, msg.Mhs1h, msg.Mhs3h, msg.Mhs6h, msg.Mhs12h, msg.Mhs24h, msg.Mhs48h, msg.Ratio5m, msg.Ratio15m, msg.Ratio30m, msg.Ratio1h, msg.Ratio3h, msg.Ratio6h, msg.Ratio12h, msg.Ratio24h, msg.Ratio48h)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool_stats,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert pool stats table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break*/
	case "pool_blkstats":
		var msg PoolBlkStats_db_msg = result.(PoolBlkStats_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,height,hash,pow,net_target,submit,`success`,accepts,rejects,reward,fee,nonce,subidx) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool_blkstats,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Height, msg.Hash, msg.Pow, msg.Net_target, msg.Submit, msg.Success, msg.Accepts, msg.Rejects, msg.Reward, msg.Fee, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_pool_blkstats,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert pool blkstats table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "blk_detail":
		var msg BlkDetail_db_msg = result.(BlkDetail_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,height,hash,user,miner,`refindex`,`success`,miner_diff,pool_diff,nonce,subidx) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_detail,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Height, msg.Hash, msg.User, msg.Miner, msg.Index, msg.Success, msg.Miner_diff, msg.Pool_diff, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_detail,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert block detail table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "blk_height_detail":
		var msg BlkHeightDetail_db_msg = result.(BlkHeightDetail_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += " (id,date,`from`,`to`) VALUES (?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_height_detail,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.From, msg.To)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_height_detail,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert block height detail table sucess,miner type", coinType), zap.String("sql", insert_sql))
		break
	case "blk_new":
		var msg BlkNew_db_msg = result.(BlkNew_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,height,hash,`success`,nonce,subidx) VALUES (?,?,?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_new,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Height, msg.Hash, msg.Success, msg.Nonce, msg.SubIdx)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_block_new,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert block new table sucess,miner type", coinType), zap.String("sql", insert_sql))

		break
	case "address":
		var msg Address_db_msg = result.(Address_db_msg)
		var insert_sql string = "INSERT INTO " + table_name
		insert_sql += "(id,date,addr,alias,valid) VALUES (?,?,?,?,?)"
		stmt, err := this.Prepare(insert_sql)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_address,Prepare err", err.Error()))
			return err
		}
		defer stmt.Close()
		res, err := stmt.Exec(msg.Id, msg.Date.Format("2006-01-02 15:04:05"), msg.Addr, msg.Sum, msg.Valid)
		if err != nil {
			this.Logg.Error("[db]", zap.String("db_handle_address,Exec err", err.Error()), zap.Any("db_handle_miners,res", res))
			return err
		}
		this.Logg.Info("[db]", zap.String("insert address table sucess,miner type", coinType), zap.String("sql", insert_sql))

		break
	default:
		this.Logg.Error("[db]", zap.String("inser table unkown table", table))
		break
	}
	return nil
}

func (this *PoolDb) UpdatePoolDb(sql string, args ...interface{}) (int64, error) {

	result, err := this.Exec(sql, args...)
	if err != nil {
		return 0, err
	}
	var count int64
	count, err = result.RowsAffected()
	if err != nil {
		return 0, err
	}
	return count, nil
}

func (this *PoolDb) DeletePoolDb(sql string, args ...interface{}) (int64, error) {

	result, err := this.Exec(sql, args...)
	if err != nil {
		return 0, err
	}
	var count int64
	count, err = result.RowsAffected()
	if err != nil {
		return 0, err
	}
	return count, nil
}

func CheckHeightRangeFromTable(DbCtx *DbContext, TableName string, height int64) (int64, int64) {
	if DbCtx == nil {
		return -1, -1
	}

	query := fmt.Sprintf("SELECT `from`,`to` FROM %s WHERE `from` <= ? AND `to` > ?", TableName)
	rows, err := DbCtx.Shares_obj.Query(query, height, height)

	if err != nil {
		DbCtx.Shares_obj.Logg.Error("[db]", zap.String("failed to query %s", err.Error()))
		return -1, -1
	}
	defer rows.Close()

	for rows.Next() {
		var from int64 = -1
		var to int64 = -1
		if err := rows.Scan(&from, &to); err != nil {
			DbCtx.Shares_obj.Logg.Error("[db]", zap.String("failed to scan %s", err.Error()))
		}
		return from, to
	}
	return -1, -1
}

/*func CheckUserFromTable(DbCtx *DbContext, TableName string, User string) bool {
	if DbCtx == nil {
		return false
	}

	query := fmt.Sprintf("SELECT user FROM %s WHERE user = ?", TableName)
	rows, err := DbCtx.Db_obj.Query(query, User)

	if err != nil {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("failed to query %s", err.Error()))
		return false
	}
	defer rows.Close()

	for rows.Next() {
		var user string
		if err := rows.Scan(&user); err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("failed to scan %s", err.Error()))
		}
		return true
	}
	return false
}*/

func CheckUserMinerFromTable(DbCtx *DbContext, TableName string, User string, Miner string, Index string) bool {
	if DbCtx == nil {
		return false
	}

	query := fmt.Sprintf("SELECT user FROM %s WHERE user = ? AND miner = ? AND `refindex` = ?", TableName)
	rows, err := DbCtx.Db_obj.Query(query, User, Miner, Index)

	if err != nil {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("failed to query %s", err.Error()))
		return false
	}
	defer rows.Close()

	for rows.Next() {
		var user string
		if err := rows.Scan(&user); err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("failed to scan %s", err.Error()))
		}
		return true
	}
	return false
}

func CheckTableIsExist(DbCtx *DbContext, tableName string) bool {
	table_exist := true
	query := fmt.Sprintf("SHOW TABLES LIKE '%s'", tableName)
	var result string
	if strings.Contains(tableName, "blk_detail") || strings.Contains(tableName, "blk_new") || strings.Contains(tableName, "blk_height_detail") || strings.Contains(tableName, "block_detail") {
		err := DbCtx.Shares_obj.QueryRow(query).Scan(&result)
		if err != nil {
			if err == sql.ErrNoRows {
				table_exist = false
			}
			DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
			table_exist = false
		}
		return table_exist
	}
	err := DbCtx.Db_obj.QueryRow(query).Scan(&result)
	if err != nil {
		if err == sql.ErrNoRows {
			table_exist = false
		}
		DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
		table_exist = false
	}
	return table_exist
}

/*
func CreateTable2(DbCtx *DbContext, table string, coinType string, table_name string) error {
	var table_sql string
	if CheckTableIsExist(DbCtx, table_name) {
		return nil
	}
	switch table {
	case "miner":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`target` VARCHAR(128),"
		table_sql += "`submit_target` VARCHAR(128),"
		table_sql += "`height` INT(10),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`pow` VARCHAR(128),"
		table_sql += "`net_target` VARCHAR(128),"
		table_sql += "`submit` VARCHAR(64),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`header` VARCHAR(1024),"
		table_sql += "`accepts` DECIMAL(32,6),"
		table_sql += "`total_accepts` DECIMAL(32,6),"
		table_sql += "`rejects` DECIMAL(32,6),"
		table_sql += "`total_rejects` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	default:
		log.Println("[db],create table unkown table")
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("create table unkown table:", table))
		break
	}
	//log.Println(table, table_sql, table_name)
	_, err := DbCtx.Db_obj.QueryPoolDb(table_sql)
	if err != nil {
		//log.Println("[db],create table err: result:", err.Error())
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("create table err: result:", err.Error()))
	}
	return err
}*/

func CreateTable(DbCtx *DbContext, table string, coinType string) error {
	var table_sql string
	var table_name string
	table_name = coinType + "_" + table

	if CheckTableIsExist(DbCtx, table_name) {
		return nil
	}

	switch table {
	case "miners":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`fromip` VARCHAR(64),"
		table_sql += "`state` VARCHAR(64),"
		table_sql += "`online` DATETIME,"
		table_sql += "`offline` DATETIME,"
		table_sql += "`retry` INT(10),"
		table_sql += "`duration` DECIMAL(12,6),"
		table_sql += "`protocol` VARCHAR(64),"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`diff` DECIMAL(32,6),"
		table_sql += "`height` INT(10),"
		table_sql += "`accepts` DECIMAL(32,6),"
		table_sql += "`rejects` DECIMAL(32,6),"
		table_sql += "`ratio` DECIMAL(32,6),"
		table_sql += "`staleds` DECIMAL(32,6),"
		table_sql += "`lows` DECIMAL(32,6),"
		table_sql += "`duplicates` DECIMAL(32,6),"
		table_sql += "`formats` DECIMAL(32,6),"
		table_sql += "`others` DECIMAL(32,6),"
		table_sql += "`is_disabled` TINYINT(1),"
		table_sql += "`last_submit` DATETIME,"
		table_sql += "`submits` INT(10),"
		table_sql += "`blocks` INT(10),"
		table_sql += "`orphans` INT(10),"
		table_sql += "`orphan_ratio` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "miners_stats":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`shares5m` DECIMAL(32,6),"
		table_sql += "`shares15m` DECIMAL(32,6),"
		table_sql += "`shares30m` DECIMAL(32,6),"
		table_sql += "`shares1h` DECIMAL(32,6),"
		table_sql += "`shares3h` DECIMAL(32,6),"
		table_sql += "`shares6h` DECIMAL(32,6),"
		table_sql += "`shares12h` DECIMAL(32,6),"
		table_sql += "`shares24h` DECIMAL(32,6),"
		table_sql += "`shares48h` DECIMAL(32,6),"
		table_sql += "`rejects5m` DECIMAL(32,6),"
		table_sql += "`rejects15m` DECIMAL(32,6),"
		table_sql += "`rejects30m` DECIMAL(32,6),"
		table_sql += "`rejects1h` DECIMAL(32,6),"
		table_sql += "`rejects3h` DECIMAL(32,6),"
		table_sql += "`rejects6h` DECIMAL(32,6),"
		table_sql += "`rejects12h` DECIMAL(32,6),"
		table_sql += "`rejects24h` DECIMAL(32,6),"
		table_sql += "`rejects48h` DECIMAL(32,6),"
		table_sql += "`mhs5m` DECIMAL(32,6),"
		table_sql += "`mhs15m` DECIMAL(32,6),"
		table_sql += "`mhs30m` DECIMAL(32,6),"
		table_sql += "`mhs1h` DECIMAL(32,6),"
		table_sql += "`mhs3h` DECIMAL(32,6),"
		table_sql += "`mhs6h` DECIMAL(32,6),"
		table_sql += "`mhs12h` DECIMAL(32,6),"
		table_sql += "`mhs24h` DECIMAL(32,6),"
		table_sql += "`mhs48h` DECIMAL(32,6),"
		table_sql += "`ratio5m` DECIMAL(32,6),"
		table_sql += "`ratio15m` DECIMAL(32,6),"
		table_sql += "`ratio30m` DECIMAL(32,6),"
		table_sql += "`ratio1h` DECIMAL(32,6),"
		table_sql += "`ratio3h` DECIMAL(32,6),"
		table_sql += "`ratio6h` DECIMAL(32,6),"
		table_sql += "`ratio12h` DECIMAL(32,6),"
		table_sql += "`ratio24h` DECIMAL(32,6),"
		table_sql += "`ratio48h` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	/*case "miner":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`target` VARCHAR(128),"
		table_sql += "`submit_target` VARCHAR(128),"
		table_sql += "`height` INT(10),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`pow` VARCHAR(128),"
		table_sql += "`net_target` VARCHAR(128),"
		table_sql += "`submit` VARCHAR(64),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`header` VARCHAR(1024),"
		table_sql += "`accepts` DECIMAL(32,6),"
		table_sql += "`total_accepts` DECIMAL(32,6),"
		table_sql += "`rejects` DECIMAL(32,6),"
		table_sql += "`total_rejects` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "users":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`normal` INT(10),"
		table_sql += "`abnormal` INT(10),"
		table_sql += "`offline` INT(10),"
		table_sql += "`mhszero` INT(10),"
		table_sql += "`mhslow` INT(10),"
		table_sql += "`highreject` INT(10),"
		table_sql += "`unstable` INT(10),"
		table_sql += "`submits` INT(10),"
		table_sql += "`blocks` INT(10),"
		table_sql += "`orphans` INT(10),"
		table_sql += "`orphan_ratio` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "users_stats":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`shares5m` DECIMAL(32,6),"
		table_sql += "`shares15m` DECIMAL(32,6),"
		table_sql += "`shares30m` DECIMAL(32,6),"
		table_sql += "`shares1h` DECIMAL(32,6),"
		table_sql += "`shares3h` DECIMAL(32,6),"
		table_sql += "`shares6h` DECIMAL(32,6),"
		table_sql += "`shares12h` DECIMAL(32,6),"
		table_sql += "`shares24h` DECIMAL(32,6),"
		table_sql += "`shares48h` DECIMAL(32,6),"
		table_sql += "`rejects5m` DECIMAL(32,6),"
		table_sql += "`rejects15m` DECIMAL(32,6),"
		table_sql += "`rejects30m` DECIMAL(32,6),"
		table_sql += "`rejects1h` DECIMAL(32,6),"
		table_sql += "`rejects3h` DECIMAL(32,6),"
		table_sql += "`rejects6h` DECIMAL(32,6),"
		table_sql += "`rejects12h` DECIMAL(32,6),"
		table_sql += "`rejects24h` DECIMAL(32,6),"
		table_sql += "`rejects48h` DECIMAL(32,6),"
		table_sql += "`mhs5m` DECIMAL(32,6),"
		table_sql += "`mhs15m` DECIMAL(32,6),"
		table_sql += "`mhs30m` DECIMAL(32,6),"
		table_sql += "`mhs1h` DECIMAL(32,6),"
		table_sql += "`mhs3h` DECIMAL(32,6),"
		table_sql += "`mhs6h` DECIMAL(32,6),"
		table_sql += "`mhs12h` DECIMAL(32,6),"
		table_sql += "`mhs24h` DECIMAL(32,6),"
		table_sql += "`mhs48h` DECIMAL(32,6),"
		table_sql += "`ratio5m` DECIMAL(32,6),"
		table_sql += "`ratio15m` DECIMAL(32,6),"
		table_sql += "`ratio30m` DECIMAL(32,6),"
		table_sql += "`ratio1h` DECIMAL(32,6),"
		table_sql += "`ratio3h` DECIMAL(32,6),"
		table_sql += "`ratio6h` DECIMAL(32,6),"
		table_sql += "`ratio12h` DECIMAL(32,6),"
		table_sql += "`ratio24h` DECIMAL(32,6),"
		table_sql += "`ratio48h` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "users_blkstats":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`height` INT(10),"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`pow` VARCHAR(128),"
		table_sql += "`net_target` VARCHAR(128),"
		table_sql += "`submit` VARCHAR(64),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`accepts` DECIMAL(32,6),"
		table_sql += "`rejects` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "pool":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`miners` INT(10),"
		table_sql += "`normal` INT(10),"
		table_sql += "`abnormal` INT(10),"
		table_sql += "`offline` INT(10),"
		table_sql += "`mhszero` INT(10),"
		table_sql += "`mhslow` INT(10),"
		table_sql += "`highreject` INT(10),"
		table_sql += "`unstable` INT(10),"
		table_sql += "`net_target` VARCHAR(128),"
		table_sql += "`height` INT(10),"
		table_sql += "`submits` INT(10),"
		table_sql += "`blocks` INT(10),"
		table_sql += "`orphans` INT(10),"
		table_sql += "`orphan_ratio` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "pool_stats":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`mhs5m` DECIMAL(32,6),"
		table_sql += "`mhs15m` DECIMAL(32,6),"
		table_sql += "`mhs30m` DECIMAL(32,6),"
		table_sql += "`mhs1h` DECIMAL(32,6),"
		table_sql += "`mhs3h` DECIMAL(32,6),"
		table_sql += "`mhs6h` DECIMAL(32,6),"
		table_sql += "`mhs12h` DECIMAL(32,6),"
		table_sql += "`mhs24h` DECIMAL(32,6),"
		table_sql += "`mhs48h` DECIMAL(32,6),"
		table_sql += "`shares5m` DECIMAL(32,6),"
		table_sql += "`shares15m` DECIMAL(32,6),"
		table_sql += "`shares30m` DECIMAL(32,6),"
		table_sql += "`shares1h` DECIMAL(32,6),"
		table_sql += "`shares3h` DECIMAL(32,6),"
		table_sql += "`shares6h` DECIMAL(32,6),"
		table_sql += "`shares12h` DECIMAL(32,6),"
		table_sql += "`shares24h` DECIMAL(32,6),"
		table_sql += "`shares48h` DECIMAL(32,6),"
		table_sql += "`rejects5m` DECIMAL(32,6),"
		table_sql += "`rejects15m` DECIMAL(32,6),"
		table_sql += "`rejects30m` DECIMAL(32,6),"
		table_sql += "`rejects1h` DECIMAL(32,6),"
		table_sql += "`rejects3h` DECIMAL(32,6),"
		table_sql += "`rejects6h` DECIMAL(32,6),"
		table_sql += "`rejects12h` DECIMAL(32,6),"
		table_sql += "`rejects24h` DECIMAL(32,6),"
		table_sql += "`rejects48h` DECIMAL(32,6),"
		table_sql += "`ratio5m` DECIMAL(32,6),"
		table_sql += "`ratio15m` DECIMAL(32,6),"
		table_sql += "`ratio30m` DECIMAL(32,6),"
		table_sql += "`ratio1h` DECIMAL(32,6),"
		table_sql += "`ratio3h` DECIMAL(32,6),"
		table_sql += "`ratio6h` DECIMAL(32,6),"
		table_sql += "`ratio12h` DECIMAL(32,6),"
		table_sql += "`ratio24h` DECIMAL(32,6),"
		table_sql += "`ratio48h` DECIMAL(32,6),"
		table_sql += " PRIMARY KEY (`id`))"
		break*/
	case "pool_blkstats":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`height` INT(10),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`pow` VARCHAR(128),"
		table_sql += "`net_target` VARCHAR(128),"
		table_sql += "`submit` VARCHAR(64),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`accepts` DECIMAL(32,6),"
		table_sql += "`rejects` DECIMAL(32,6),"
		table_sql += "`reward` DECIMAL(32,6),"
		table_sql += "`fee` DECIMAL(32,6),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "blk_height_detail":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`from` INT(10),"
		table_sql += "`to` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "blk_detail":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`height` INT(10),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`user` VARCHAR(128),"
		table_sql += "`miner` VARCHAR(128),"
		table_sql += "`refindex` VARCHAR(128),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`miner_diff` DECIMAL(32,6),"
		table_sql += "`pool_diff` DECIMAL(32,6),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "blk_new":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) NOT NULL AUTO_INCREMENT,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`height` INT(10),"
		table_sql += "`hash` VARCHAR(128),"
		table_sql += "`success` TINYINT(1),"
		table_sql += "`nonce` VARCHAR(64),"
		table_sql += "`subidx` INT(10),"
		table_sql += " PRIMARY KEY (`id`))"
		break
	case "address":
		table_sql = "CREATE TABLE "
		table_sql += "`" + table_name + "`"
		table_sql += "(`id` INT(10) AUTO_INCREMENT UNIQUE,"
		table_sql += "`date` DATETIME NOT NULL,"
		table_sql += "`addr` VARCHAR(128),"
		table_sql += "`alias` VARCHAR(128),"
		table_sql += "`valid` TINYINT(1),"
		table_sql += " PRIMARY KEY (`addr`))"
		break
	default:
		log.Println("[db],create table unkown table")
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("create table unkown table:", table))
		break
	}
	//log.Println(table, table_sql)
	if strings.Contains(table, "blk_detail") || strings.Contains(table, "blk_new") || strings.Contains(table, "blk_height_detail") || strings.Contains(table, "block_detail") {
		_, err := DbCtx.Shares_obj.QueryPoolDb(table_sql)
		if err != nil {
			log.Println("[db],create table err: result:", err.Error())
			DbCtx.Shares_obj.Logg.Info("[db]", zap.String("create table err: result:", err.Error()))
		}
		return err
	}
	_, err := DbCtx.Db_obj.QueryPoolDb(table_sql)
	if err != nil {
		log.Println("[db],create table err: result:", err.Error())
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("create table err: result:", err.Error()))
	}
	return err
}

func createdb(DbCtx *DbContext) (int, error) {
	var result int = 0
	var db_sql string = DbCtx.DbCfg.Db.Username + ":" + DbCtx.DbCfg.Db.Password + "@tcp(" + DbCtx.DbCfg.Db.Ip + ":" + strconv.Itoa(DbCtx.DbCfg.Db.Port) + ")/" + DbCtx.DbCfg.Db.Dbname + "?charset=utf8"
	//log.Println("[db],create db sql:", db_sql)
	dbconnstr = db_sql
	db_obj, err := OpenPoolDb("mysql", db_sql)
	if err != nil {
		log.Println("[db],open db err:", err.Error())
		//DbCtx.Db_obj.Logg.Info("[db]", zap.String("open db err:", err.Error()))
		result = -1
	}
	DbCtx.Db_obj = db_obj

	var sharesdb_sql string = DbCtx.DbCfg.Shares.Username + ":" + DbCtx.DbCfg.Shares.Password + "@tcp(" + DbCtx.DbCfg.Shares.Ip + ":" + strconv.Itoa(DbCtx.DbCfg.Shares.Port) + ")/" + DbCtx.DbCfg.Shares.Dbname + "?charset=utf8"
	//log.Println("[db],create db sql:", db_sql)
	sharesdbconnstr = sharesdb_sql
	sharesdb_obj, err := OpenPoolDb("mysql", sharesdb_sql)
	if err != nil {
		log.Println("[db],open db err:", err.Error())
		//DbCtx.Shares_obj.Logg.Info("[db]", zap.String("open db err:", err.Error()))
		result = -1
	}
	DbCtx.Shares_obj = sharesdb_obj
	log.Println("open db!")
	return result, err
}

func do_handle_miners(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.Miners_ch
		switch msg.Msg {
		case "miners":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			curTableName := msg.MinerType + "_" + msg.Msg
			if DbCtx.Module == "server" {
				if msg.Date.Sub(DbCtx.LastMinersTime) >= 300*time.Second {
					prev := DbCtx.LastMinersTime
					DbCtx.LastMinersTime = msg.Date
					table_exist := true
					tableName := msg.MinerType + "_" + msg.Msg + "_" + prev.Format("20060102")
					query := fmt.Sprintf("SHOW TABLES LIKE '%s'", tableName)
					var result string
					err := DbCtx.Db_obj.QueryRow(query).Scan(&result)
					if err != nil {
						if err == sql.ErrNoRows {
							table_exist = false
						}
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
						table_exist = false
					}
					if !table_exist {
						createTableSQL := fmt.Sprintf("CREATE TABLE %s LIKE %s", tableName, curTableName)
						_, err = DbCtx.Db_obj.Exec(createTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("create miners table err", err.Error()))
							//continue
						}
						alterTableSQL := fmt.Sprintf("ALTER TABLE %s ADD COLUMN save_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP", tableName)
						_, err = DbCtx.Db_obj.Exec(alterTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("add miners column table err", err.Error()))
							//continue
						}
					}
					copyDataSQL := fmt.Sprintf("INSERT INTO %s (date, fromip, state, online, offline, retry, duration, protocol, user, miner, `refindex`, diff, height, accepts, rejects, ratio, staleds, lows, duplicates, formats, others, is_disabled, last_submit, submits, blocks, orphans, orphan_ratio, save_ts) SELECT date, fromip, state, online, offline, retry, duration, protocol, user, miner, `refindex`, diff, height, accepts, rejects, ratio, staleds, lows, duplicates, formats, others, is_disabled, last_submit, submits, blocks, orphans, orphan_ratio, '%s' FROM %s", tableName, prev.Format("2006-01-02 15:04:05"), curTableName)
					_, err = DbCtx.Db_obj.Exec(copyDataSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("add miners column table err", err.Error()))
						//continue
					}
				}
				found := CheckUserMinerFromTable(DbCtx, msg.MinerType+"_"+msg.Msg, msg.User, msg.Miner, msg.Index)
				if found {
					updateSQL := fmt.Sprintf("UPDATE %s SET date = ?, fromip = ?, state = ?, online = ?, offline = ?, retry = ?, duration = ?, protocol = ?, diff = ?, height = ?, accepts = ?, rejects = ?, ratio = ?, staleds = ?, lows = ?, duplicates = ?, formats = ?, others = ?, is_disabled = ?, last_submit = ?, submits = ?, blocks = ?, orphans = ?, orphan_ratio = ?  WHERE user = ? AND miner = ? AND `refindex` = ?", curTableName)
					count, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Date.Format("2006-01-02 15:04:05"), msg.Fromip, msg.State, msg.Online, msg.Offline, msg.Retry, msg.Duration, msg.Protocol, msg.Diff, msg.Height, msg.Accepts, msg.Rejects, msg.Ratio, msg.Staleds, msg.Lows, msg.Duplicates, msg.Formats, msg.Others, msg.Disabled, msg.Last_submit, msg.Submits, msg.Blocks, msg.Orphans, msg.Orphan_ratio, msg.User, msg.Miner, msg.Index)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update miners table err", err.Error()))
						//continue
					}
					DbCtx.Db_obj.Logg.Info("[db]", zap.Int64("update miners table count", count), zap.String("update miners table MinerType", msg.MinerType), zap.String("sql", updateSQL))
				} else {
					err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert miners table err", err.Error()))
					}
				}
			} else if DbCtx.Module == "gbt" {
				/*curTableName := msg.MinerType + "_" + msg.Msg
				last_blocks := GetLastBlocksFromTable(DbCtx, curTableName, msg.User, msg.Miner, msg.Index)
				if last_blocks >= 0 {
					last_blocks += 1
					UpdateBlocksToTable(DbCtx, curTableName, msg.User, msg.Miner, msg.Index, last_blocks)
				}*/

			} else if DbCtx.Module == "block" {
			}
			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_miners", "unkown msg "+msg.Msg))
			break
		}
	}
}

func do_handle_miners_stats(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.MinersStats_ch
		switch msg.Msg {
		case "miners_stats":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			curTableName := msg.MinerType + "_" + msg.Msg
			if DbCtx.Module == "server" {
				if msg.Date.Sub(DbCtx.LastMinersStatsTime) >= 300*time.Second {
					prev := DbCtx.LastMinersStatsTime
					DbCtx.LastMinersStatsTime = msg.Date
					table_exist := true
					tableName := msg.MinerType + "_" + msg.Msg + "_" + prev.Format("20060102")
					query := fmt.Sprintf("SHOW TABLES LIKE '%s'", tableName)
					var result string
					err := DbCtx.Db_obj.QueryRow(query).Scan(&result)
					if err != nil {
						if err == sql.ErrNoRows {
							table_exist = false
						}
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
						table_exist = false
					}
					if !table_exist {
						createTableSQL := fmt.Sprintf("CREATE TABLE %s LIKE %s", tableName, curTableName)
						_, err = DbCtx.Db_obj.Exec(createTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("create miners_stats table err", err.Error()))
							//continue
						}
						alterTableSQL := fmt.Sprintf("ALTER TABLE %s ADD COLUMN save_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP", tableName)
						_, err = DbCtx.Db_obj.Exec(alterTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("add miners_stats column table err", err.Error()))
							//continue
						}
					}
					copyDataSQL := fmt.Sprintf("INSERT INTO %s (date, user, miner, `refindex`, shares5m, shares15m, shares30m, shares1h, shares3h, shares6h, shares12h, shares24h, shares48h, rejects5m, rejects15m, rejects30m, rejects1h, rejects3h, rejects6h, rejects12h, rejects24h, rejects48h, mhs5m, mhs15m, mhs30m, mhs1h, mhs3h, mhs6h, mhs12h, mhs24h, mhs48h, ratio5m, ratio15m, ratio30m, ratio1h, ratio3h, ratio6h, ratio12h, ratio24h, ratio48h, save_ts) SELECT date, user, miner, `refindex`, shares5m, shares15m, shares30m, shares1h, shares3h, shares6h, shares12h, shares24h, shares48h, rejects5m, rejects15m, rejects30m, rejects1h, rejects3h, rejects6h, rejects12h, rejects24h, rejects48h, mhs5m, mhs15m, mhs30m, mhs1h, mhs3h, mhs6h, mhs12h, mhs24h, mhs48h, ratio5m, ratio15m, ratio30m, ratio1h, ratio3h, ratio6h, ratio12h, ratio24h, ratio48h, '%s' FROM %s", tableName, prev.Format("2006-01-02 15:04:05"), curTableName)
					_, err = DbCtx.Db_obj.Exec(copyDataSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("add miners_stats column table err", err.Error()))
						//continue
					}
				}
				found := CheckUserMinerFromTable(DbCtx, msg.MinerType+"_"+msg.Msg, msg.User, msg.Miner, msg.Index)
				if found {
					updateSQL := fmt.Sprintf("UPDATE %s SET date = ?, shares5m = ?, shares15m = ?, shares30m = ?, shares1h = ?, shares3h = ?, shares6h = ?, shares12h = ?, shares24h = ?, shares48h = ?, rejects5m = ?, rejects15m = ?, rejects30m = ?, rejects1h = ?, rejects3h = ?, rejects6h = ?, rejects12h = ?, rejects24h = ?, rejects48h = ?, mhs5m = ?, mhs15m = ?, mhs30m = ?, mhs1h = ?, mhs3h = ?, mhs6h = ?, mhs12h = ?, mhs24h = ?, mhs48h = ?, ratio5m = ?, ratio15m = ?, ratio30m = ?, ratio1h = ?, ratio3h = ?, ratio6h = ?, ratio12h = ?, ratio24h = ?, ratio48h = ? WHERE user = ? AND miner = ? AND `refindex` = ?", curTableName)
					count, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Date.Format("2006-01-02 15:04:05"), msg.Shares5m, msg.Shares15m, msg.Shares30m, msg.Shares1h, msg.Shares3h, msg.Shares6h, msg.Shares12h, msg.Shares24h, msg.Shares48h, msg.Rejects5m, msg.Rejects15m, msg.Rejects30m, msg.Rejects1h, msg.Rejects3h, msg.Rejects6h, msg.Rejects12h, msg.Rejects24h, msg.Rejects48h, msg.Mhs5m, msg.Mhs15m, msg.Mhs30m, msg.Mhs1h, msg.Mhs3h, msg.Mhs6h, msg.Mhs12h, msg.Mhs24h, msg.Mhs48h, msg.Ratio5m, msg.Ratio15m, msg.Ratio30m, msg.Ratio1h, msg.Ratio3h, msg.Ratio6h, msg.Ratio12h, msg.Ratio24h, msg.Ratio48h, msg.User, msg.Miner, msg.Index)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update miners_stats table err", err.Error()))
						//continue
					}
					DbCtx.Db_obj.Logg.Info("[db]", zap.Int64("update miners_stats table count", count), zap.String("update miners table MinerType", msg.MinerType), zap.String("sql", updateSQL))
				} else {
					err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert miners_stats table err", err.Error()))
					}
				}
			} else if DbCtx.Module == "gbt" {

			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_miners_stats", "unkown msg "+msg.Msg))
			break
		}
	}
}

/*func do_handle_miner(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.Miner_ch
		switch msg.Msg {
		case "miner":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				minerTableName := msg.MinerType + "_" + msg.Msg + "_" + msg.User + "_" + msg.Miner + "_" + msg.Index
				table_exist := true
				query := fmt.Sprintf("SHOW TABLES LIKE '%s'", minerTableName)
				var result string
				err := DbCtx.Db_obj.QueryRow(query).Scan(&result)
				if err != nil {
					if err == sql.ErrNoRows {
					table_exist = false
					}
					DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
					table_exist = false
				}
				if !table_exist {
					CreateTable2(DbCtx, msg.Msg, msg.MinerType, minerTableName)
				}
				DbCtx.LastMinerTime = GetLastTimeFromTable(DbCtx, minerTableName)

				newTableName := minerTableName + "_" + DbCtx.LastMinerTime.Format("20060102")
				//fmt.Printf("do_handle_miner %v,%v,%v", DbCtx.LastMinerTime, DbCtx.LastMinerTime.Format("20060102"), newTableName)
				if msg.Date.Format("2006-01-02") != DbCtx.LastMinerTime.Format("2006-01-02") {
					//DbCtx.LastMinerTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", minerTableName, newTableName)
					_, err := DbCtx.Db_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("miner rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable2(DbCtx, msg.Msg, msg.MinerType, minerTableName)
				}
				err = DbCtx.Db_obj.InsertPoolDb2(msg.Msg, msg.MinerType, minerTableName, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert miner table err", err.Error()))
				}

			} else if DbCtx.Module == "gbt" {
				minerTableName := msg.MinerType + "_" + msg.Msg + "_" + msg.User + "_" + msg.Miner + "_" + msg.Index
				updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", minerTableName)
				_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
				if err != nil {
					log.Printf("[db] update miner table err %s %s", minerTableName, err.Error())
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("update miner table err", err.Error()))
					//continue
				}
				//log.Printf("[db] update %s %d %s %d\n", minerTableName, msg.Height, msg.Nonce, msg.Success)
				now := time.Now()
				yesterday := now.AddDate(0, 0, -1)
				yesterdayTableName := minerTableName + "_" + yesterday.Format("20060102")
				if CheckTableIsExist(DbCtx, yesterdayTableName) {
					updateYesterdaySQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", yesterdayTableName)
					_, err = DbCtx.Db_obj.UpdatePoolDb(updateYesterdaySQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
						//continue
					}
				}
			} else if DbCtx.Module == "block" {
			}
			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_miner", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

/*func do_handle_users(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.Users_ch
		switch msg.Msg {
		case "users":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			curTableName := msg.MinerType + "_" + msg.Msg
			if DbCtx.Module == "server" {
				if msg.Date.Sub(DbCtx.LastUsersTime) >= 300*time.Second {

					msg.Normal = 0
					msg.Abnormal = 0

					msg.Offline = 0
					msg.MhsZero = 0
					msg.MhsLow = 0
					msg.HighRejects = 0
					msg.Unstable = 0

					startTime := time.Now().Add(-48 * time.Hour).Unix()
					minersTable := msg.MinerType + "_" + "miners"
					minersMhsTable := msg.MinerType + "_" + "miners_stats"

					query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE UNIX_TIMESTAMP(date) >= %d AND user = '%s'", minersTable, startTime, msg.User)
					var total_count int64 = 0
					err := DbCtx.Db_obj.QueryRow(query).Scan(&total_count)
					if err != nil {
						log.Printf("Error querying database total_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database total_count:", curTableName+" "+err.Error()))
					}
					//log.Printf("[db] users total_count %d %s\n", total_count, query)

					//query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND mhs5m >= 10 AND UNIX_TIMESTAMP(date) >= %d AND user = %s", minersTable, startTime, msg.User)
					query = fmt.Sprintf("SELECT COUNT(*) FROM %s po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m >= 10.0 AND UNIX_TIMESTAMP(po.`date`) >= %d AND po.user = '%s'", minersTable, minersMhsTable, startTime, msg.User)
					var normal_count int64 = 0
					err = DbCtx.Db_obj.QueryRow(query).Scan(&normal_count)
					if err != nil {
						log.Printf("Error querying database normal_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database normal_count:", curTableName+" "+err.Error()))
					}
					msg.Normal = normal_count
					msg.Abnormal = total_count - normal_count
					//log.Printf("[db] users normal_count %d %s\n", normal_count, query)

					query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'offline' AND UNIX_TIMESTAMP(date) >= %d AND user = '%s'", minersTable, startTime, msg.User)
					var offline_count int64 = 0
					err = DbCtx.Db_obj.QueryRow(query).Scan(&offline_count)
					if err != nil {
						log.Printf("Error querying database offline_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database offline_count:", curTableName+" "+err.Error()))
					}
					msg.Offline = offline_count
					//log.Printf("[db] users offline_count %d %s\n", offline_count, query)

					//query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND mhs5m <= 0 AND duration > 300 AND UNIX_TIMESTAMP(date) >= %d AND user = %s", minersTable, startTime, msg.User)
					query = fmt.Sprintf("SELECT COUNT(*) FROM %s po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m <= 0.0 AND po.duration > 300.0 AND UNIX_TIMESTAMP(po.`date`) >= %d AND po.user = '%s'", minersTable, minersMhsTable, startTime, msg.User)
					var mhszero_count int64
					err = DbCtx.Db_obj.QueryRow(query).Scan(&mhszero_count)
					if err != nil {
						log.Printf("Error querying database mhszero_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database mhszero_count:", curTableName+" "+err.Error()))
					}
					msg.MhsZero = mhszero_count
					//log.Printf("[db] users mhszero_count %d %s\n", mhszero_count, query)

					//query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND mhs5m < 10 AND duration > 300 AND UNIX_TIMESTAMP(date) >= %d AND user = '%s'", minersTable, startTime, msg.User)
					query = fmt.Sprintf("SELECT COUNT(*) FROM %s po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m < 10.0 AND po.duration > 300.0 AND UNIX_TIMESTAMP(po.date) >= %d AND po.user = '%s'", minersTable, minersMhsTable, startTime, msg.User)
					var mhslow_count int64
					err = DbCtx.Db_obj.QueryRow(query).Scan(&mhslow_count)
					if err != nil {
						log.Printf("Error querying database mhslow_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database mhslow_count:", curTableName+" "+err.Error()))
					}
					msg.MhsLow = mhslow_count
					//log.Printf("[db] users mhslow_count %d %s\n", mhslow_count, query)

					query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND ratio > 0.01  AND UNIX_TIMESTAMP(date) >= %d AND user = '%s'", minersTable, startTime, msg.User)
					var highreject_count int64
					err = DbCtx.Db_obj.QueryRow(query).Scan(&highreject_count)
					if err != nil {
						log.Printf("Error querying database highreject_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database highreject_count:", curTableName+" "+err.Error()))
					}
					msg.HighRejects = highreject_count
					//log.Printf("[db] users highreject_count %d %s\n", highreject_count, query)

					query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND retry > 10 AND UNIX_TIMESTAMP(date) >= %d AND user = '%s'", minersTable, startTime, msg.User)
					var unstable_count int64
					err = DbCtx.Db_obj.QueryRow(query).Scan(&unstable_count)
					if err != nil {
						log.Printf("Error querying database unstable_count: %s %v %s", minersTable, err, query)
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database unstable_count:", curTableName+" "+err.Error()))
					}
					msg.Unstable = unstable_count
					//log.Printf("[db] users unstable_count %d %s\n", unstable_count, query)

					prev := DbCtx.LastUsersTime
					DbCtx.LastUsersTime = msg.Date
					table_exist := true
					tableName := msg.MinerType + "_" + msg.Msg + "_" + prev.Format("20060102")
					query = fmt.Sprintf("SHOW TABLES LIKE '%s'", tableName)
					var result string
					err = DbCtx.Db_obj.QueryRow(query).Scan(&result)
					if err != nil {
						if err == sql.ErrNoRows {
							table_exist = false
						}
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
						table_exist = false
					}
					if !table_exist {
						createTableSQL := fmt.Sprintf("CREATE TABLE %s LIKE %s", tableName, curTableName)
						_, err = DbCtx.Db_obj.Exec(createTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("create users table err", err.Error()))
							//continue
						}
						alterTableSQL := fmt.Sprintf("ALTER TABLE %s ADD COLUMN save_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP", tableName)
						_, err = DbCtx.Db_obj.Exec(alterTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("add users column table err", err.Error()))
							//continue
						}
					}
					copyDataSQL := fmt.Sprintf("INSERT INTO %s (date,user,normal,abnormal,offline,mhszero,mhslow,highreject,unstable,submits,blocks,orphans,orphan_ratio,reward,fee, save_ts) SELECT date,user,normal,abnormal,offline,mhszero,mhslow,highreject,unstable,submits,blocks,orphans,orphan_ratio,reward,fee, '%s' FROM %s", tableName, prev.Format("2006-01-02 15:04:05"), curTableName)
					_, err = DbCtx.Db_obj.Exec(copyDataSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("add users column table err", err.Error()))
						//return
					}
				}
				found := CheckUserFromTable(DbCtx, msg.MinerType+"_"+msg.Msg, msg.User)
				if found {
					updateSQL := fmt.Sprintf("UPDATE %s SET date = ?, normal = ?, abnormal = ?, offline = ?, mhszero = ?, mhslow = ?, highreject = ?, unstable = ?, submits = ?, blocks = ?, orphans = ?, orphan_ratio = ?, reward = ?, fee = ? WHERE user = ?", curTableName)
					count, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Date.Format("2006-01-02 15:04:05"), msg.Normal, msg.Abnormal, msg.Offline, msg.MhsZero, msg.MhsLow, msg.HighRejects, msg.Unstable, msg.Submits, msg.Blocks, msg.Orphans, msg.Orphan_ratio, msg.Reward, msg.Fee, msg.User)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
						//continue
					}
					DbCtx.Db_obj.Logg.Info("[db]", zap.Int64("update users table count", count), zap.String("update miners table MinerType", msg.MinerType), zap.String("sql", updateSQL))
				} else {
					err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert users table err", err.Error()))
					}
				}
			} else if DbCtx.Module == "gbt" {
				curTableName := msg.MinerType + "_" + msg.Msg
				last_blocks := GetLastBlocksFromTable(DbCtx, curTableName, msg.User, "", "")
				if last_blocks >= 0 {
					last_blocks += 1
					UpdateBlocksToTable(DbCtx, curTableName, msg.User, "", "", last_blocks)
				}
			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_users", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

/*func do_handle_users_stats(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.UsersStats_ch
		switch msg.Msg {
		case "users_stats":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			curTableName := msg.MinerType + "_" + msg.Msg
			if DbCtx.Module == "server" {
				if msg.Date.Sub(DbCtx.LastUsersStatsTime) >= 300*time.Second {
					prev := DbCtx.LastUsersStatsTime
					DbCtx.LastUsersStatsTime = msg.Date
					table_exist := true
					tableName := msg.MinerType + "_" + msg.Msg + "_" + prev.Format("20060102")
					query := fmt.Sprintf("SHOW TABLES LIKE '%s'", tableName)
					var result string
					err := DbCtx.Db_obj.QueryRow(query).Scan(&result)
					if err != nil {
						if err == sql.ErrNoRows {
						table_exist = false
						}
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("check table existence failed:", tableName), zap.String("err", err.Error()))
						table_exist = false
					}
					if !table_exist {
						createTableSQL := fmt.Sprintf("CREATE TABLE %s LIKE %s", tableName, curTableName)
						_, err = DbCtx.Db_obj.Exec(createTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("create users_stats table err", err.Error()))
							//continue
						}
						alterTableSQL := fmt.Sprintf("ALTER TABLE %s ADD COLUMN save_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP", tableName)
						_, err = DbCtx.Db_obj.Exec(alterTableSQL)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("add users_stats column table err", err.Error()))
							//continue
						}
					}
					copyDataSQL := fmt.Sprintf("INSERT INTO %s (date,user,shares5m,shares15m,shares30m,shares1h,shares3h,shares6h,shares12h,shares24h,shares48h,rejects5m,rejects15m,rejects30m,rejects1h,rejects3h,rejects6h,rejects12h,rejects24h,rejects48h,mhs5m,mhs15m,mhs30m,mhs1h,mhs3h,mhs6h,mhs12h,mhs24h,mhs48h,ratio5m,ratio15m,ratio30m,ratio1h,ratio3h,ratio6h,ratio12h,ratio24h,ratio48h,save_ts) SELECT date,user,shares5m,shares15m,shares30m,shares1h,shares3h,shares6h,shares12h,shares24h,shares48h,rejects5m,rejects15m,rejects30m,rejects1h,rejects3h,rejects6h,rejects12h,rejects24h,rejects48h,mhs5m,mhs15m,mhs30m,mhs1h,mhs3h,mhs6h,mhs12h,mhs24h,mhs48h,ratio5m,ratio15m,ratio30m,ratio1h,ratio3h,ratio6h,ratio12h,ratio24h,ratio48h,'%s' FROM %s", tableName, prev.Format("2006-01-02 15:04:05"), curTableName)

					_, err = DbCtx.Db_obj.Exec(copyDataSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("add users_stats column table err", err.Error()))
						//continue
					}
				}
				found := CheckUserFromTable(DbCtx, msg.MinerType+"_"+msg.Msg, msg.User)
				if found {
					updateSQL := fmt.Sprintf("UPDATE %s SET date = ?, shares5m = ?, shares15m = ?, shares30m = ?, shares1h = ?, shares3h = ?, shares6h = ?, shares12h = ?, shares24h = ?, shares48h = ?, rejects5m = ?, rejects15m = ?, rejects30m = ?, rejects1h = ?, rejects3h = ?, rejects6h = ?, rejects12h = ?, rejects24h = ?, rejects48h = ?, mhs5m = ?, mhs15m = ?, mhs30m = ?, mhs1h = ?, mhs3h = ?, mhs6h = ?, mhs12h = ?, mhs24h = ?, mhs48h = ?, ratio5m = ?, ratio15m = ?, ratio30m = ?, ratio1h = ?, ratio3h = ?, ratio6h = ?, ratio12h = ?, ratio24h = ?, ratio48h = ?  WHERE user = ?", curTableName)
					count, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Date.Format("2006-01-02 15:04:05"), msg.Shares5m, msg.Shares15m, msg.Shares30m, msg.Shares1h, msg.Shares3h, msg.Shares6h, msg.Shares12h, msg.Shares24h, msg.Shares48h, msg.Rejects5m, msg.Rejects15m, msg.Rejects30m, msg.Rejects1h, msg.Rejects3h, msg.Rejects6h, msg.Rejects12h, msg.Rejects24h, msg.Rejects48h, msg.Mhs5m, msg.Mhs15m, msg.Mhs30m, msg.Mhs1h, msg.Mhs3h, msg.Mhs6h, msg.Mhs12h, msg.Mhs24h, msg.Mhs48h, msg.Ratio5m, msg.Ratio15m, msg.Ratio30m, msg.Ratio1h, msg.Ratio3h, msg.Ratio6h, msg.Ratio12h, msg.Ratio24h, msg.Ratio48h, msg.User)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update users_stats table err", err.Error()))
						//continue
					}
					DbCtx.Db_obj.Logg.Info("[db]", zap.Int64("update users_stats table count", count), zap.String("update miners table MinerType", msg.MinerType), zap.String("sql", updateSQL))
				} else {
					err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert users_stats table err", err.Error()))
					}
				}
			} else if DbCtx.Module == "gbt" {

			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_users", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

/*func do_handle_users_blkstats(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.UsersBlkStats_ch
		switch msg.Msg {
		case "users_blkstats":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastUsersBlkStatsTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastUsersBlkStatsTime.Format("2006-01-02") {
					DbCtx.LastUsersBlkStatsTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Db_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("users_blkstats rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}
				err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert users_blkstats table err", err.Error()))
				}
			} else if DbCtx.Module == "gbt" {
				curTableName := msg.MinerType + "_" + msg.Msg
				updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", curTableName)
				_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
					//continue
				}
				now := time.Now()
				yesterday := now.AddDate(0, 0, -1)
				yesterdayTableName := curTableName + "_" + yesterday.Format("20060102")
				if CheckTableIsExist(DbCtx, yesterdayTableName) {
					updateYesterdaySQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", yesterdayTableName)
					_, err = DbCtx.Db_obj.UpdatePoolDb(updateYesterdaySQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
						//continue
					}
				}
			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_users_blkstats", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

/*func do_handle_pool(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.Pool_ch
		switch msg.Msg {
		case "pool":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				tableName := msg.MinerType + "_" + msg.Msg

				msg.Miners = 0
				msg.Normal = 0
				msg.Abnormal = 0

				msg.Offline = 0
				msg.MhsZero = 0
				msg.MhsLow = 0
				msg.HighRejects = 0
				msg.Unstable = 0

				startTime := time.Now().Add(-48 * time.Hour).Unix()
				minersTable := msg.MinerType + "_" + "miners"
				minersMhsTable := msg.MinerType + "_" + "miners_stats"

				query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				var total_count int64 = 0
				err := DbCtx.Db_obj.QueryRow(query).Scan(&total_count)
				if err != nil {
					log.Printf("Error querying database total_count: %s %v %s", tableName, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database total_count:", tableName+" "+err.Error()))
				}
				msg.Miners = total_count
				//log.Printf("[db] pool total_count %d %s\n", total_count, query)

				//query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND mhs5m >= 10 AND UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				query = fmt.Sprintf("SELECT COUNT(*) FROM %s po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m >= 10.0 AND UNIX_TIMESTAMP(po.date) >= %d", minersTable, minersMhsTable, startTime)
				var normal_count int64 = 0
				err = DbCtx.Db_obj.QueryRow(query).Scan(&normal_count)
				if err != nil {
					log.Printf("Error querying database normal_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database normal_count:", tableName+" "+err.Error()))
				}
				msg.Normal = normal_count
				msg.Abnormal = msg.Miners - normal_count

				//log.Printf("[db] pool normal_count %d %s\n", normal_count, query)

				query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'offline' AND UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				var offline_count int64 = 0
				err = DbCtx.Db_obj.QueryRow(query).Scan(&offline_count)
				if err != nil {
					log.Printf("Error querying database offline_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database offline_count:", tableName+" "+err.Error()))
				}
				msg.Offline = offline_count
				//log.Printf("[db] pool offline_count %d %s\n", offline_count, query)

				//query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND mhs5m <= 0 AND duration > 300 AND UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				query = fmt.Sprintf("SELECT COUNT(*) FROM %s  po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m <= 0.0 AND po.duration > 300.0 AND UNIX_TIMESTAMP(po.date) >= %d", minersTable, minersMhsTable, startTime)
				var mhszero_count int64
				err = DbCtx.Db_obj.QueryRow(query).Scan(&mhszero_count)
				if err != nil {
					log.Printf("Error querying database mhszero_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database mhszero_count:", tableName+" "+err.Error()))
				}
				msg.MhsZero = mhszero_count
				//log.Printf("[db] pool mhszero_count %d %s\n", mhszero_count, query)

				query = fmt.Sprintf("SELECT COUNT(*) FROM %s po JOIN %s pm ON po.user = pm.user AND po.miner = pm.miner AND po.refindex = pm.refindex WHERE po.`state` = 'online' AND pm.mhs5m < 10.0 AND po.duration > 300.0 AND UNIX_TIMESTAMP(po.`date`) >= %d", minersTable, minersMhsTable, startTime)
				var mhslow_count int64
				err = DbCtx.Db_obj.QueryRow(query).Scan(&mhslow_count)
				if err != nil {
					log.Printf("Error querying database mhslow_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database mhslow_count:", tableName+" "+err.Error()))
				}
				msg.MhsLow = mhslow_count
				//log.Printf("[db] pool mhslow_count %d %s\n", mhslow_count, query)

				query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND ratio > 0.01  AND UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				var highreject_count int64
				err = DbCtx.Db_obj.QueryRow(query).Scan(&highreject_count)
				if err != nil {
					log.Printf("Error querying database highreject_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database highreject_count:", tableName+" "+err.Error()))
				}
				msg.HighRejects = highreject_count
				//log.Printf("[db] pool highreject_count %d %s\n", highreject_count, query)

				query = fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `state` = 'online' AND retry > 10 AND UNIX_TIMESTAMP(date) >= %d", minersTable, startTime)
				var unstable_count int64
				err = DbCtx.Db_obj.QueryRow(query).Scan(&unstable_count)
				if err != nil {
					log.Printf("Error querying database unstable_count: %s %v %s", minersTable, err, query)
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("Error querying database unstable_count:", tableName+" "+err.Error()))
				}
				msg.Unstable = unstable_count
				//log.Printf("[db] pool unstable_count %d %s\n", unstable_count, query)

				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastPoolTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastPoolTime.Format("2006-01-02") {
					DbCtx.LastPoolTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Db_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("pool rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}
				err = DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert pool table err", err.Error()))
				}

			} else if DbCtx.Module == "gbt" {
				curTableName := msg.MinerType + "_" + msg.Msg
				last_blocks := GetLastBlocksFromTable(DbCtx, curTableName, "", "", "")
				if last_blocks >= 0 {
					last_blocks += 1
					UpdateBlocksToTable(DbCtx, curTableName, "", "", "", last_blocks)
				}
				last_reward, last_fee := GetLastRewardFromTable(DbCtx, curTableName, "", "", "")
				if last_reward >= 0 {
					last_reward += msg.Reward
					last_fee += msg.Fee
					UpdateRewardToTable(DbCtx, curTableName, last_reward, last_fee)
				}
			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_pool", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

/*func do_handle_pool_stats(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.PoolStats_ch
		switch msg.Msg {
		case "pool_stats":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastPoolStatsTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastPoolStatsTime.Format("2006-01-02") {
					DbCtx.LastPoolStatsTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Db_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("pool_stats rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}
				err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert pool_stats table err", err.Error()))
				}

			} else if DbCtx.Module == "gbt" {
			} else if DbCtx.Module == "block" {
			}
			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_pool_stats", "unkown msg "+msg.Msg))
			break
		}
	}
}*/

func do_handle_pool_blkstats(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.PoolBlkStats_ch
		switch msg.Msg {
		case "pool_blkstats":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastPoolBlkStatsTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastPoolBlkStatsTime.Format("2006-01-02") {
					DbCtx.LastPoolBlkStatsTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Db_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Db_obj.Logg.Warn("[db]", zap.String("pool_blkstats rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}
				err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert pool_blkstats table err", err.Error()))
				}

			} else if DbCtx.Module == "gbt" {
				curTableName := msg.MinerType + "_" + msg.Msg

				if msg.Submit == "" {
					updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", curTableName)
					_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update pool_blkstats table err", err.Error()))
						//continue
					}
				} else {
					updateSQL := fmt.Sprintf("UPDATE %s SET `submit` = ? WHERE height = ? AND nonce = ?", curTableName)
					_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, msg.Submit, msg.Height, msg.Nonce)
					if err != nil {
						DbCtx.Db_obj.Logg.Error("[db]", zap.String("update pool_blkstats table err", err.Error()))
						//continue
					}
				}

				now := time.Now()
				yesterday := now.AddDate(0, 0, -1)
				yesterdayTableName := curTableName + "_" + yesterday.Format("20060102")
				if CheckTableIsExist(DbCtx, yesterdayTableName) {
					if msg.Submit == "" {
						updateYesterdaySQL := fmt.Sprintf("UPDATE %s SET `success` = ?, reward = ?, fee = ? WHERE height = ? AND nonce = ?", yesterdayTableName)
						_, err := DbCtx.Db_obj.UpdatePoolDb(updateYesterdaySQL, msg.Success, msg.Reward, msg.Fee, msg.Height, msg.Nonce)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("update pool_blkstats table err", err.Error()))
							//continue
						}
					} else {
						updateYesterdaySQL := fmt.Sprintf("UPDATE %s SET `submit` = ? WHERE height = ? AND nonce = ?", yesterdayTableName)
						_, err := DbCtx.Db_obj.UpdatePoolDb(updateYesterdaySQL, msg.Submit, msg.Height, msg.Nonce)
						if err != nil {
							DbCtx.Db_obj.Logg.Error("[db]", zap.String("update pool_blkstats table err", err.Error()))
							//continue
						}
					}
				}
			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_pool_blkstats", "unkown msg "+msg.Msg))
			break
		}
	}
}

func do_handle_blk_detail(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.BlkDetail_ch
		switch msg.Msg {
		case "blk_detail":
			ret := CheckSharesDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Shares_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_block_detail" + "_" + fmt.Sprint(DbCtx.LastBlockDetailHeight) + "_" + fmt.Sprint(msg.Height-1)

				if DbCtx.LastBlockDetailHeight > 0 {

					if msg.Height-DbCtx.LastBlockDetailHeight > 100 {
						var heightMsg BlkHeightDetail_db_msg
						heightMsg.From = DbCtx.LastBlockDetailHeight

						DbCtx.LastBlockDetailHeight = msg.Height
						log.Println("do_handle_blk_detail", tableName, newTableName)
						renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
						_, err := DbCtx.Shares_obj.Exec(renameTableSQL)
						if err != nil {
							DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("pool_detail rename ", "failed"), zap.String("err ", err.Error()))
							//continue
						}

						CreateTable(DbCtx, msg.Msg, msg.MinerType)

						heightMsg.Id = 0
						heightMsg.To = msg.Height
						heightMsg.MinerType = msg.MinerType
						heightMsg.Date = msg.Date
						heightMsg.Msg = "blk_height_detail"
						err = DbCtx.Shares_obj.InsertPoolDb(heightMsg.Msg, heightMsg.MinerType, heightMsg)
						if err != nil {
							DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_height_detail table err", err.Error()))
						}
					}
				}
				err := DbCtx.Shares_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_detail table err", err.Error()))
				}
			} else if DbCtx.Module == "gbt" {
				curTableName := msg.MinerType + "_" + msg.Msg
				updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", curTableName)
				_, err := DbCtx.Shares_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Height, msg.Nonce)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
					//continue
				}
				from, to := CheckHeightRangeFromTable(DbCtx, msg.MinerType+"_"+"blk_height_detail", msg.Height)
				if (from > 0) && (to > 0) {
					oldTableName := curTableName + "_" + fmt.Sprint(from) + "_" + fmt.Sprint(to)
					if CheckTableIsExist(DbCtx, oldTableName) {
						updateOldSQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", oldTableName)
						_, err := DbCtx.Shares_obj.UpdatePoolDb(updateOldSQL, msg.Success, msg.Height, msg.Nonce)
						if err != nil {
							DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
							//continue
						}
					}
				}
			} else if DbCtx.Module == "block" {
			}

			break
		default:
			DbCtx.Shares_obj.Logg.Error("[db]", zap.String("do_handle_blk_detail", "unkown msg "+msg.Msg))
			break
		}
	}
}

func Save_blk_detail(DbCtx *DbContext, msg *BlkDetail_db_msg) {
	switch msg.Msg {
	case "blk_detail":
		ret := CheckSharesDbAlive(DbCtx)
		if ret != 0 {
			DbCtx.Shares_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
			//continue
			break
		}
		if DbCtx.Module == "server" {
			tableName := msg.MinerType + "_" + msg.Msg
			newTableName := msg.MinerType + "_block_detail" + "_" + fmt.Sprint(DbCtx.LastBlockDetailHeight) + "_" + fmt.Sprint(msg.Height-1)

			if DbCtx.LastBlockDetailHeight > 0 {

				if msg.Height-DbCtx.LastBlockDetailHeight > 100 {
					var heightMsg BlkHeightDetail_db_msg
					heightMsg.From = DbCtx.LastBlockDetailHeight

					DbCtx.LastBlockDetailHeight = msg.Height
					log.Println("do_handle_blk_detail", tableName, newTableName)
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Shares_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("pool_detail rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)

					heightMsg.Id = 0
					heightMsg.To = msg.Height
					heightMsg.MinerType = msg.MinerType
					heightMsg.Date = msg.Date
					heightMsg.Msg = "blk_height_detail"
					err = DbCtx.Shares_obj.InsertPoolDb(heightMsg.Msg, heightMsg.MinerType, heightMsg)
					if err != nil {
						DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_height_detail table err", err.Error()))
					}
				}
			}
			err := DbCtx.Shares_obj.InsertPoolDb(msg.Msg, msg.MinerType, *msg)
			if err != nil {
				DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_detail table err", err.Error()))
			}
		} else if DbCtx.Module == "gbt" {
			curTableName := msg.MinerType + "_" + msg.Msg
			updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", curTableName)
			_, err := DbCtx.Shares_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Height, msg.Nonce)
			if err != nil {
				DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
				//continue
			}
			from, to := CheckHeightRangeFromTable(DbCtx, msg.MinerType+"_"+"blk_height_detail", msg.Height)
			if (from > 0) && (to > 0) {
				oldTableName := curTableName + "_" + fmt.Sprint(from) + "_" + fmt.Sprint(to)
				if CheckTableIsExist(DbCtx, oldTableName) {
					updateOldSQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", oldTableName)
					_, err := DbCtx.Shares_obj.UpdatePoolDb(updateOldSQL, msg.Success, msg.Height, msg.Nonce)
					if err != nil {
						DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
						//continue
					}
				}
			}
		} else if DbCtx.Module == "block" {
		}

		break
	default:
		DbCtx.Shares_obj.Logg.Error("[db]", zap.String("save_blk_detail", "unkown msg "+msg.Msg))
		break
	}
}

func do_handle_blk_new(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.BlkNew_ch
		switch msg.Msg {
		case "blk_new":
			ret := CheckSharesDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Shares_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				/*tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastBlockNewTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastBlockNewTime.Format("2006-01-02") {
					DbCtx.LastBlockNewTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Shares_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("block_new rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}*/
				/*err := DbCtx.Shares_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_blknew table err", err.Error()))
				}*/
			} else if DbCtx.Module == "gbt" {
				/*tableName := msg.MinerType + "_" + msg.Msg
				newTableName := msg.MinerType + "_" + msg.Msg + "_" + DbCtx.LastBlockNewTime.Format("20060102")

				if msg.Date.Format("2006-01-02") != DbCtx.LastBlockNewTime.Format("2006-01-02") {
					DbCtx.LastBlockNewTime = msg.Date
					renameTableSQL := fmt.Sprintf("RENAME TABLE %s TO %s", tableName, newTableName)
					_, err := DbCtx.Shares_obj.Exec(renameTableSQL)
					if err != nil {
						DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("block_new rename ", "failed"), zap.String("err ", err.Error()))
						//continue
					}

					CreateTable(DbCtx, msg.Msg, msg.MinerType)
				}*/
				err := DbCtx.Shares_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("insert pool_blknew table err", err.Error()))
				}
				/*curTableName := msg.MinerType + "_" + msg.Msg
				updateSQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", curTableName)
				_, err := DbCtx.Shares_obj.UpdatePoolDb(updateSQL, msg.Success, msg.Height, msg.Nonce)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
					//continue
				}

				now := time.Now()
				yesterday := now.AddDate(0, 0, -1)
				yesterdayTableName := curTableName + "_" + yesterday.Format("20060102")
				updateYesterdaySQL := fmt.Sprintf("UPDATE %s SET `success` = ? WHERE height = ? AND nonce = ?", yesterdayTableName)
				_, err = DbCtx.Shares_obj.UpdatePoolDb(updateYesterdaySQL, msg.Success, msg.Height, msg.Nonce)
				if err != nil {
					DbCtx.Shares_obj.Logg.Error("[db]", zap.String("update users table err", err.Error()))
					//continue
				}*/
			} else if DbCtx.Module == "block" {
			} else {
			}
			break
		default:
			DbCtx.Shares_obj.Logg.Error("[db]", zap.String("do_handle_blk_new", "unkown msg "+msg.Msg))
			break
		}
	}
}

func do_handle_address(DbCtx *DbContext) {
	for {
		if DbCtx.DbExit {
			return
		}
		msg := <-DbCtx.Address_ch
		switch msg.Msg {
		case "address":
			ret := CheckPoolDbAlive(DbCtx)
			if ret != 0 {
				DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
				continue
			}
			if DbCtx.Module == "server" {
				err := DbCtx.Db_obj.InsertPoolDb(msg.Msg, msg.MinerType, msg)
				if err != nil {
					DbCtx.Db_obj.Logg.Error("[db]", zap.String("insert address table err", err.Error()))
				}
			} else if DbCtx.Module == "gbt" {

			} else if DbCtx.Module == "block" {
			}
			break
		default:
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("do_handle_address", "unkown msg "+msg.Msg))
			break
		}
	}
}

func GetAddressFromTable(DbCtx *DbContext) []string {
	var addresses []string

	ret := CheckPoolDbAlive(DbCtx)
	if ret != 0 {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
		return addresses
	}
	query := "SELECT addr, alias, valid FROM " + DbCtx.Coin + "_address"
	rows, err := DbCtx.Db_obj.Query(query)
	if err != nil {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("query address from Pool db ", err.Error()))
		return addresses
	}
	defer rows.Close()

	for rows.Next() {
		var addr string
		var alias string
		var valid int = 0
		// 将每一行的字段值扫描到结构体中
		err := rows.Scan(&addr, &alias, &valid)
		if err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("scan address from Pool db ", err.Error()))
			continue
		}

		hash := md5.Sum([]byte(addr + "m2pool_alias"))
		hashString := hex.EncodeToString(hash[:])
		if hashString == alias {
			addresses = append(addresses, addr)
		}
	}
	return addresses
}

/*func UpdateBlocksToTable(DbCtx *DbContext, tableName string, user string, miner string, minerid string, update_blocks int64) {
	if len(miner) > 0 {
		updateSQL := fmt.Sprintf("UPDATE %s SET `blocks` = ? WHERE user = ? AND miner = ? AND refindex = ?", tableName)
		_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, update_blocks, user, miner, minerid)
		if err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("update table err", tableName+" "+err.Error()))
			//continue
		}
	} else if len(user) > 0 {
		updateSQL := fmt.Sprintf("UPDATE %s SET `blocks` = ? WHERE user = ?", tableName)
		_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, update_blocks, user)
		if err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("update table err", tableName+" "+err.Error()))
			//continue
		}
	} else {
		updateSQL := fmt.Sprintf("UPDATE %s SET `blocks` = ?", tableName)
		_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, update_blocks)
		if err != nil {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("update table err", tableName+" "+err.Error()))
			//continue
		}
	}
}*/

/*func GetLastBlocksFromTable(DbCtx *DbContext, tableName string, user string, miner string, minerid string) int64 {
	var last_blocks int64 = -1
	query := fmt.Sprintf("SELECT blocks FROM %s", tableName)
	if len(miner) > 0 {
		query = fmt.Sprintf("SELECT blocks FROM %s WHERE user = '%s' AND miner = '%s' AND refindex = '%s'", tableName, user, miner, minerid)
	} else if len(user) > 0 {
		query = fmt.Sprintf("SELECT blocks FROM %s WHERE user = '%s'", tableName, user)
	} else {
	}
	err := DbCtx.Db_obj.QueryRow(query).Scan(&last_blocks)
	if err != nil {
		DbCtx.Db_obj.Logg.Warn("[db]", zap.String("get blocks failed:", tableName), zap.String("err", err.Error()))
	}

	return last_blocks
}*/
/*
func UpdateRewardToTable(DbCtx *DbContext, tableName string, reward float64, fee float64) {
	updateSQL := fmt.Sprintf("UPDATE %s SET `reward` = ?, `fee` = ?", tableName)

	_, err := DbCtx.Db_obj.UpdatePoolDb(updateSQL, reward, fee)
	if err != nil {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("update table err", tableName+" "+err.Error()))
	}
}*/
/*
func GetLastRewardFromTable(DbCtx *DbContext, tableName string, user string, miner string, minerid string) (float64, float64) {
	var last_reward float64 = -1
	var last_fee float64 = -1
	query := fmt.Sprintf("SELECT reward,fee FROM %s", tableName)
	err := DbCtx.Db_obj.QueryRow(query).Scan(&last_reward, &last_fee)
	if err != nil {
		DbCtx.Db_obj.Logg.Warn("[db]", zap.String("get blocks failed:", tableName), zap.String("err", err.Error()))
	}

	return last_reward, last_fee
}*/

func GetLastTimeFromTable(DbCtx *DbContext, tableName string) time.Time {
	var last_time time.Time

	if !CheckTableIsExist(DbCtx, tableName) {
		last_time = time.Now()
		return last_time
	}

	var last_time_str sql.NullString

	query := fmt.Sprintf("SELECT DATE_FORMAT(date, '%%Y-%%m-%%d %%H:%%i:%%S') AS last_time FROM %s ORDER BY id DESC LIMIT 1", tableName)

	var err error
	if strings.Contains(tableName, "blk_new") || strings.Contains(tableName, "blk_detail") || strings.Contains(tableName, "blk_height_detail") || strings.Contains(tableName, "block_detail") {
		err = DbCtx.Shares_obj.QueryRow(query).Scan(&last_time_str)
		if err != nil {
			DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("get failed:", tableName), zap.String("err", err.Error()))
			last_time = time.Now()
		}
	} else {
		err = DbCtx.Db_obj.QueryRow(query).Scan(&last_time_str)
		if err != nil {
			DbCtx.Db_obj.Logg.Warn("[db]", zap.String("get failed:", tableName), zap.String("err", err.Error()))
			last_time = time.Now()
		}
	}

	if last_time_str.Valid {
		last_time, err = time.Parse("2006-01-02 15:04:05", last_time_str.String)
		if err != nil {
			DbCtx.Db_obj.Logg.Warn("[db]", zap.String("parse datetime error", err.Error()))
			last_time = time.Now()
		}
	}

	return last_time
}

/*func GetLastTimeFromTable(DbCtx *DbContext, tableName string) time.Time {
	var last_time time.Time
	var last_time_str sql.NullString
	read_ok := false
	query := fmt.Sprintf("SELECT DATE_FORMAT(date, '%Y-%m-%d %H:%i:%s') FROM %s ORDER BY id DESC LIMIT 1", tableName)
	if strings.Contains(tableName, "blk_new") || strings.Contains(tableName, "blk_detail") {
		err := DbCtx.Shares_obj.QueryRow(query).Scan(&last_time_str)
		if err != nil {
			DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("get failed:", tableName), zap.String("err ", err.Error()))
			last_time = time.Now()
		}
	} else {
		err := DbCtx.Db_obj.QueryRow(query).Scan(&last_time_str)
		if err != nil {
			DbCtx.Db_obj.Logg.Warn("[db]", zap.String("get failed:", tableName), zap.String("err ", err.Error()))
			last_time = time.Now()
		}
	}
	if read_ok {
		mysqlDateTimeFormat := "2006-01-02 15:04:05"
		last_time, _ = time.Parse(mysqlDateTimeFormat, datetimeStr)

	}
	return last_time
}*/

func GetLastHeightFromTable(DbCtx *DbContext, tableName string) int64 {
	var last_height int64
	query := fmt.Sprintf("SELECT height FROM %s ORDER BY id DESC LIMIT 1", tableName)
	err := DbCtx.Shares_obj.QueryRow(query).Scan(&last_height)
	if err != nil {
		DbCtx.Shares_obj.Logg.Warn("[db]", zap.String("get failed:", tableName), zap.String("err ", err.Error()))
		last_height = -1
	}
	return last_height
}

func InitDbData(DbCtx *DbContext, Module string) {
	ret := CheckPoolDbAlive(DbCtx)
	if ret != 0 {
		DbCtx.Db_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
	}
	ret = CheckSharesDbAlive(DbCtx)
	if ret != 0 {
		DbCtx.Shares_obj.Logg.Error("[db]", zap.String("Pool db ", "disconnected"))
	}
	if Module == "server" {
		DbCtx.LastMinersTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"miners")
		DbCtx.LastMinersStatsTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"miners_stats")
		//DbCtx.LastMinerTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"miner")
		/*DbCtx.LastUsersTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"users")
		DbCtx.LastUsersStatsTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"users_stats")
		DbCtx.LastUsersBlkStatsTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"users_blkstats")
		DbCtx.LastPoolTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"pool")
		DbCtx.LastPoolStatsTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"pool_stats")*/
		DbCtx.LastPoolBlkStatsTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"pool_blkstats")
		DbCtx.LastBlockDetailHeight = GetLastHeightFromTable(DbCtx, DbCtx.Coin+"_"+"blk_detail")
		DbCtx.LastBlockNewTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"blk_new")
		DbCtx.LastAddressTime = GetLastTimeFromTable(DbCtx, DbCtx.Coin+"_"+"address")
	}
}

func InitDb(Coin string, Module string) *DbContext {
	DbCtx.AppExit = make(chan bool, 256)

	DbCtx.Miners_ch = make(chan Miners_db_msg, 32768)
	DbCtx.MinersStats_ch = make(chan MinersStats_db_msg, 32768)
	/*DbCtx.Miner_ch = make(chan Miner_db_msg, 32768)

	DbCtx.Users_ch = make(chan Users_db_msg, 32768)
	DbCtx.UsersStats_ch = make(chan UsersStats_db_msg, 32768)
	DbCtx.UsersBlkStats_ch = make(chan UsersBlkStats_db_msg, 32768)

	DbCtx.Pool_ch = make(chan Pool_db_msg, 32768)
	DbCtx.PoolStats_ch = make(chan PoolStats_db_msg, 32768)*/
	DbCtx.PoolBlkStats_ch = make(chan PoolBlkStats_db_msg, 32768)

	DbCtx.BlkDetail_ch = make(chan BlkDetail_db_msg, 32768)
	DbCtx.BlkNew_ch = make(chan BlkNew_db_msg, 32768)

	DbCtx.Address_ch = make(chan Address_db_msg, 16)

	DbCtx.Module = Module
	DbCtx.Coin = Coin

	InitConfig(&(DbCtx.DbCfg))
	l, r, e := utility.InitLogg(&(DbCtx.DbCfg.Zaplog), &(DbCtx.DbCfg.Logrotae), Coin, "db")
	if e != nil {
		log.Fatalln("[db]", e)
		return nil
	}
	DbCtx.LogR = r

	var result int = 0
	result, err := createdb(&DbCtx)
	if result != 0 || err != nil {
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("create db failed: ", err.Error()))
		return nil
	}

	DbCtx.Db_obj.Logg = l
	DbCtx.Shares_obj.Logg = l

	InitDbData(&DbCtx, Module)

	go do_handle_miners(&DbCtx)
	go do_handle_miners_stats(&DbCtx)
	/*go do_handle_miner(&DbCtx)
	go do_handle_users(&DbCtx)
	go do_handle_users_stats(&DbCtx)
	go do_handle_users_blkstats(&DbCtx)
	go do_handle_pool(&DbCtx)
	go do_handle_pool_stats(&DbCtx)*/
	go do_handle_pool_blkstats(&DbCtx)
	go do_handle_blk_detail(&DbCtx)
	go do_handle_blk_new(&DbCtx)
	go do_handle_address(&DbCtx)

	if Module == "server" {
	} else if Module == "block" {
	} else if Module == "gbt" {
	} else if Module == "job" {
	} else {
	}

	return &DbCtx
}

func StopDb(coin string, App string) {
	DbCtx.DbExit = true
	defer close(DbCtx.Miners_ch)
	/*defer close(DbCtx.MinersStats_ch)
	defer close(DbCtx.Miner_ch)
	defer close(DbCtx.Users_ch)
	defer close(DbCtx.UsersStats_ch)
	defer close(DbCtx.UsersBlkStats_ch)
	defer close(DbCtx.Pool_ch)
	defer close(DbCtx.PoolStats_ch)*/
	defer close(DbCtx.PoolBlkStats_ch)
	defer close(DbCtx.BlkDetail_ch)
	defer close(DbCtx.BlkNew_ch)
	defer close(DbCtx.Address_ch)
	defer DbCtx.Db_obj.Logg.Sync()
	DbCtx.Db_obj.ClosePoolDb()
	DbCtx.Shares_obj.ClosePoolDb()
}

func (this *PoolDb) PingPoolDb(DbCtx *DbContext) int {
	for i := 0; i < 3; i++ {
		err := this.Ping()
		if err != nil {
			if DbCtx.DbExit {
				return -1
			}
			time.Sleep(200 * time.Millisecond)
			continue
		}
		return 0
	}
	return -1
}

func CheckPoolDbAlive(DbCtx *DbContext) int {
	//ping
	ret := DbCtx.Db_obj.PingPoolDb(DbCtx)
	if ret != 0 {
		backup_l := DbCtx.Db_obj.Logg
		DbCtx.Db_obj.ClosePoolDb()
		//reconnect
		db_obj, err := OpenPoolDb("mysql", dbconnstr)
		if err != nil {
			backup_l.Info("[db]", zap.String("reconnect db err", err.Error()))
			//log.Println("[db]reconnect db err", err.Error())
			return -1
		}
		DbCtx.Db_obj = db_obj
		DbCtx.Db_obj.Logg = backup_l

		//ping
		if DbCtx.Db_obj.PingPoolDb(DbCtx) != 0 {
			DbCtx.Db_obj.Logg.Error("[db]", zap.String("reconnect ping db", "failed"))
			DbCtx.Db_obj.ClosePoolDb()
			return -1
		}
		DbCtx.Db_obj.Logg.Info("[db]", zap.String("reconnect db sucess", dbconnstr))
	}
	return 0
}

func CheckSharesDbAlive(DbCtx *DbContext) int {
	//ping
	ret := DbCtx.Shares_obj.PingPoolDb(DbCtx)
	if ret != 0 {
		backup_l := DbCtx.Shares_obj.Logg
		DbCtx.Shares_obj.ClosePoolDb()
		//reconnect
		db_obj, err := OpenPoolDb("mysql", sharesdbconnstr)
		if err != nil {
			backup_l.Info("[db]", zap.String("reconnect db err", err.Error()))
			//log.Println("[db]reconnect db err", err.Error())
			return -1
		}
		DbCtx.Shares_obj = db_obj
		DbCtx.Shares_obj.Logg = backup_l

		//ping
		if DbCtx.Shares_obj.PingPoolDb(DbCtx) != 0 {
			DbCtx.Shares_obj.Logg.Error("[db]", zap.String("reconnect ping db", "failed"))
			DbCtx.Shares_obj.ClosePoolDb()
			return -1
		}
		DbCtx.Shares_obj.Logg.Info("[db]", zap.String("reconnect db sucess", sharesdbconnstr))
	}
	return 0
}

func CheckUserIsPermitted(User string) bool {
	//DbCtx.Db_obj.Logg.Info("[db]", zap.Any("CheckUserIsPermitted", User))
	//return true

	url := "https://m2pool.com/api/pool/checkAccount"
	data := map[string]string{
		"coin": "alph",
		"ma":   User,
	}
	//log.Println("CheckUserIsPermitted user =", User, data)
	jsonData, err := json.Marshal(data)
	if err != nil {
		log.Println("Error marshalling JSON:", err)
		return false
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Println("Error making POST request:", err)
		return false
	}

	defer resp.Body.Close()

	if resp.StatusCode == http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("Error reading response body:", err)
			return false
		}
		log.Println("CheckUserIsPermitted", string(body))
		if string(body) == "true" {
			return true
		}
	}

	return false
}
