本文整理汇总了Golang中github.com/flike/kingshard/core/golog.Error函数的典型用法代码示例。如果您正苦于以下问题:Golang Error函数的具体用法?Golang Error怎么用?Golang Error使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了Error函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: onConn
func (s *Server) onConn(c net.Conn) {
conn := s.newClientConn(c) //新建一个conn
defer func() {
err := recover()
if err != nil {
const size = 4096
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)] //获得当前goroutine的stacktrace
golog.Error("server", "onConn", "error", 0,
"remoteAddr", c.RemoteAddr().String(),
"stack", string(buf),
)
}
conn.Close()
}()
if allowConnect := conn.IsAllowConnect(); allowConnect == false {
err := mysql.NewError(mysql.ER_ACCESS_DENIED_ERROR, "ip address access denied by kingshard.")
conn.writeError(err)
conn.Close()
return
}
if err := conn.Handshake(); err != nil {
golog.Error("server", "onConn", err.Error(), 0)
c.Close()
return
}
conn.Run()
}
开发者ID:jazzsun,项目名称:kingshard,代码行数:32,代码来源:server.go
示例2: Handshake
func (c *ClientConn) Handshake() error {
if err := c.writeInitialHandshake(); err != nil {
golog.Error("server", "Handshake", err.Error(),
c.connectionId, "msg", "send initial handshake error")
return err
}
if err := c.readHandshakeResponse(); err != nil {
golog.Error("server", "readHandshakeResponse",
err.Error(), c.connectionId,
"msg", "read Handshake Response error")
c.writeError(err)
return err
}
if err := c.writeOK(nil); err != nil {
golog.Error("server", "readHandshakeResponse",
"write ok fail",
c.connectionId, "error", err.Error())
return err
}
c.pkg.Sequence = 0
return nil
}
开发者ID:GavinChangCN,项目名称:kingshard,代码行数:28,代码来源:conn.go
示例3: buildDeletePlan
func (r *Router) buildDeletePlan(db string, statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
var where *sqlparser.Where
var err error
stmt := statement.(*sqlparser.Delete)
plan.Rule = r.GetRule(db, sqlparser.String(stmt.Table))
where = stmt.Where
if where != nil {
plan.Criteria = where.Expr //路由条件
err = plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildUpdatePlan", err.Error(), 0)
return nil, err
}
} else {
//if shard delete without where,send to all nodes and all tables
plan.RouteTableIndexs = plan.Rule.SubTableIndexs
plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes))
}
if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 {
golog.Error("Route", "BuildDeletePlan", errors.ErrNoCriteria.Error(), 0)
return nil, errors.ErrNoCriteria
}
//generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node
err = r.generateDeleteSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:flike,项目名称:kingshard,代码行数:33,代码来源:router.go
示例4: handleSelect
/*处理select语句*/
func (c *ClientConn) handleSelect(stmt *sqlparser.Select, sql string, args []interface{}) error {
bindVars := makeBindVars(args) //对于select语句,arg为空,不考虑
conns, err := c.getShardConns(true, stmt, bindVars)
if err != nil {
golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId)
return err
} else if conns == nil {
r := c.newEmptyResultset(stmt)
return c.writeResultset(c.status, r)
}
var rs []*Result
rs, err = c.executeInShard(conns, sql, args)
c.closeShardConns(conns, false)
if err != nil {
golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId)
return err
}
err = c.mergeSelectResult(rs, stmt)
if err != nil {
golog.Error("ClientConn", "handleSelect", err.Error(), c.connectionId)
}
return err
}
开发者ID:jin06,项目名称:kingshard,代码行数:31,代码来源:conn_query.go
示例5: checkMaster
func (n *Node) checkMaster() {
db := n.Master
if db == nil {
golog.Error("Node", "checkMaster", "Master is no alive", 0)
return
}
if atomic.LoadInt32(&(db.state)) == Down {
return
}
if err := db.Ping(); err != nil {
golog.Error("Node", "checkMaster", "Ping", 0, "db.Addr", db.Addr(), "error", err.Error())
} else {
n.LastMasterPing = time.Now().Unix()
atomic.StoreInt32(&(db.state), Up)
return
}
if int64(n.DownAfterNoAlive) > 0 && time.Now().Unix()-n.LastMasterPing > int64(n.DownAfterNoAlive/time.Second) {
golog.Info("Node", "checkMaster", "Master down", 0,
"db.Addr", db.Addr(),
"Master_down_time", int64(n.DownAfterNoAlive/time.Second))
n.DownMaster(db.addr)
}
}
开发者ID:cch123,项目名称:kingshard,代码行数:25,代码来源:node.go
示例6: buildDeletePlan
func (r *Router) buildDeletePlan(statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
var where *sqlparser.Where
stmt := statement.(*sqlparser.Delete)
plan.Rule = r.GetRule(sqlparser.String(stmt.Table))
where = stmt.Where
if where != nil {
plan.Criteria = where.Expr /*路由条件*/
} else {
plan.Rule = r.DefaultRule
}
plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode))
err := plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildDeletePlan", err.Error(), 0)
return nil, err
}
if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 {
golog.Error("Route", "BuildDeletePlan", errors.ErrNoCriteria.Error(), 0)
return nil, errors.ErrNoCriteria
}
//generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node
err = r.generateDeleteSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:velsai,项目名称:kingshard,代码行数:33,代码来源:router.go
示例7: handlePrepareSelect
func (c *ClientConn) handlePrepareSelect(stmt *sqlparser.Select, sql string, args []interface{}) error {
defaultRule := c.schema.rule.DefaultRule
if len(defaultRule.Nodes) == 0 {
return ErrNoDefaultNode
}
defaultNode := c.proxy.GetNode(defaultRule.Nodes[0])
//execute in Master DB
conn, err := c.getBackendConn(defaultNode, false)
if err != nil {
return err
}
if conn == nil {
r := c.newEmptyResultset(stmt)
return c.writeResultset(c.status, r)
}
var rs []*Result
rs, err = c.executeInNode(conn, sql, args)
c.closeConn(conn, false)
if err != nil {
golog.Error("ClientConn", "handlePrepareSelect", err.Error(), c.connectionId)
return err
}
err = c.mergeSelectResult(rs, stmt)
if err != nil {
golog.Error("ClientConn", "handlePrepareSelect", err.Error(), c.connectionId)
}
return err
}
开发者ID:npk,项目名称:kingshard,代码行数:34,代码来源:conn_stmt.go
示例8: handleQuery
/*处理query语句*/
func (c *ClientConn) handleQuery(sql string) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("execute %s error %v", sql, e)
golog.OutputSql("Error", "%s", sql)
return
}
golog.OutputSql("INFO", "%s", sql)
}()
sql = strings.TrimRight(sql, ";") //删除sql语句最后的分号
hasHandled, err := c.handleUnsupport(sql)
if err != nil {
golog.Error("server", "parse", err.Error(), 0, "hasHandled", hasHandled)
return err
}
if hasHandled {
return nil
}
var stmt sqlparser.Statement
stmt, err = sqlparser.Parse(sql) //解析sql语句,得到的stmt是一个interface
if err != nil {
golog.Error("server", "parse", err.Error(), 0, "hasHandled", hasHandled)
return err
}
switch v := stmt.(type) {
case *sqlparser.Select:
return c.handleSelect(v, sql, nil)
case *sqlparser.Insert:
return c.handleExec(stmt, sql, nil)
case *sqlparser.Update:
return c.handleExec(stmt, sql, nil)
case *sqlparser.Delete:
return c.handleExec(stmt, sql, nil)
case *sqlparser.Replace:
return c.handleExec(stmt, sql, nil)
case *sqlparser.Set:
return c.handleSet(v)
case *sqlparser.Begin:
return c.handleBegin()
case *sqlparser.Commit:
return c.handleCommit()
case *sqlparser.Rollback:
return c.handleRollback()
case *sqlparser.SimpleSelect:
return c.handleSimpleSelect(sql, v)
case *sqlparser.Show:
return c.handleShow(sql, v)
case *sqlparser.Admin:
return c.handleAdmin(v)
default:
return fmt.Errorf("statement %T not support now", stmt)
}
return nil
}
开发者ID:jin06,项目名称:kingshard,代码行数:60,代码来源:conn_query.go
示例9: buildSelectPlan
func (r *Router) buildSelectPlan(statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
var where *sqlparser.Where
var err error
var tableName string
stmt := statement.(*sqlparser.Select)
switch v := (stmt.From[0]).(type) {
case *sqlparser.AliasedTableExpr:
tableName = sqlparser.String(v.Expr)
case *sqlparser.JoinTableExpr:
if ate, ok := (v.LeftExpr).(*sqlparser.AliasedTableExpr); ok {
tableName = sqlparser.String(ate.Expr)
} else {
tableName = sqlparser.String(v)
}
default:
tableName = sqlparser.String(v)
}
plan.Rule = r.GetRule(tableName) //根据表名获得分表规则
where = stmt.Where
plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode))
if where != nil {
plan.Criteria = where.Expr //路由条件
err = plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildSelectPlan", err.Error(), 0)
return nil, err
}
} else {
//if shard select without where,send to all nodes and all tables
plan.RouteTableIndexs = plan.TableIndexs
plan.RouteNodeIndexs = makeList(0, len(plan.Rule.Nodes))
}
if plan.Rule.Type != DefaultRuleType && len(plan.RouteTableIndexs) == 0 {
golog.Error("Route", "BuildSelectPlan", errors.ErrNoCriteria.Error(), 0)
return nil, errors.ErrNoCriteria
}
//generate sql,如果routeTableindexs为空则表示不分表,不分表则发default node
err = r.generateSelectSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:zhaoweikid,项目名称:kingshard,代码行数:48,代码来源:router.go
示例10: handleExec
func (c *ClientConn) handleExec(stmt sqlparser.Statement, args []interface{}) error {
plan, err := c.schema.rule.BuildPlan(stmt)
conns, err := c.getShardConns(false, plan)
if err != nil {
golog.Error("ClientConn", "handleExec", err.Error(), c.connectionId)
return err
}
if conns == nil {
return c.writeOK(nil)
}
var rs []*mysql.Result
if 1 < len(conns) {
return errors.ErrExecInMulti
}
if 1 < len(plan.RewrittenSqls) {
nodeIndex := plan.RouteNodeIndexs[0]
nodeName := plan.Rule.Nodes[nodeIndex]
txSqls := []string{"begin;"}
txSqls = append(txSqls, plan.RewrittenSqls[nodeName]...)
txSqls = append(txSqls, "commit;")
plan.RewrittenSqls[nodeName] = txSqls
}
rs, err = c.executeInMultiNodes(conns, plan.RewrittenSqls, args)
c.closeShardConns(conns, err != nil)
if err == nil {
err = c.mergeExecResult(rs)
}
return err
}
开发者ID:velsai,项目名称:kingshard,代码行数:32,代码来源:conn_query.go
示例11: buildReplacePlan
func (r *Router) buildReplacePlan(statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
stmt := statement.(*sqlparser.Replace)
if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok {
panic(sqlparser.NewParserError("select in replace not allowed"))
}
plan.Rule = r.GetRule(sqlparser.String(stmt.Table))
plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values))
plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode))
err := plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildReplacePlan", err.Error(), 0)
return nil, err
}
err = r.generateReplaceSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:velsai,项目名称:kingshard,代码行数:25,代码来源:router.go
示例12: buildInsertPlan
func (r *Router) buildInsertPlan(statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
stmt := statement.(*sqlparser.Insert)
if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok {
return nil, errors.ErrSelectInInsert
}
/*根据sql语句的表,获得对应的分片规则*/
plan.Rule = r.GetRule(sqlparser.String(stmt.Table))
if stmt.OnDup != nil {
err := plan.Rule.checkUpdateExprs(sqlparser.UpdateExprs(stmt.OnDup))
if err != nil {
return nil, err
}
}
plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values))
plan.TableIndexs = makeList(0, len(plan.Rule.TableToNode))
err := plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildInsertPlan", err.Error(), 0)
return nil, err
}
err = r.generateInsertSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:velsai,项目名称:kingshard,代码行数:31,代码来源:router.go
示例13: calRouteIndexs
/*计算表下标和node下标 */
func (plan *Plan) calRouteIndexs() error {
nodesCount := len(plan.Rule.Nodes)
if plan.Rule.Type == DefaultRuleType {
plan.RouteNodeIndexs = []int{0}
return nil
}
if plan.Criteria == nil { //如果没有分表条件,则是全子表扫描
if plan.Rule.Type != DefaultRuleType {
golog.Error("Plan", "calRouteIndexs", "plan have no criteria", 0,
"type", plan.Rule.Type)
return ErrNoCriteria
}
}
switch criteria := plan.Criteria.(type) {
case sqlparser.Values: //代表insert中values
tindex := plan.getInsertTableIndex(criteria)
plan.RouteTableIndexs = []int{tindex}
plan.RouteNodeIndexs = plan.TindexsToNindexs([]int{tindex})
return nil
case sqlparser.BoolExpr:
plan.RouteTableIndexs = plan.getTableIndexByBoolExpr(criteria)
plan.RouteNodeIndexs = plan.TindexsToNindexs(plan.RouteTableIndexs)
return nil
default:
plan.RouteTableIndexs = plan.TableIndexs
plan.RouteNodeIndexs = makeList(0, nodesCount)
return nil
}
}
开发者ID:rainslytherin,项目名称:kingshard,代码行数:34,代码来源:planbuilder.go
示例14: buildReplacePlan
func (r *Router) buildReplacePlan(db string, statement sqlparser.Statement) (*Plan, error) {
plan := &Plan{}
plan.Rows = make(map[int]sqlparser.Values)
stmt := statement.(*sqlparser.Replace)
if _, ok := stmt.Rows.(sqlparser.SelectStatement); ok {
panic(sqlparser.NewParserError("select in replace not allowed"))
}
if stmt.Columns == nil {
return nil, errors.ErrIRNoColumns
}
plan.Rule = r.GetRule(db, sqlparser.String(stmt.Table))
err := plan.GetIRKeyIndex(stmt.Columns)
if err != nil {
return nil, err
}
plan.Criteria = plan.checkValuesType(stmt.Rows.(sqlparser.Values))
err = plan.calRouteIndexs()
if err != nil {
golog.Error("Route", "BuildReplacePlan", err.Error(), 0)
return nil, err
}
err = r.generateReplaceSql(plan, stmt)
if err != nil {
return nil, err
}
return plan, nil
}
开发者ID:flike,项目名称:kingshard,代码行数:34,代码来源:router.go
示例15: checkSlave
func (n *Node) checkSlave() {
n.RLock()
if n.Slave == nil {
n.RUnlock()
return
}
slaves := make([]*DB, len(n.Slave))
copy(slaves, n.Slave)
n.RUnlock()
for i := 0; i < len(slaves); i++ {
if atomic.LoadInt32(&(slaves[i].state)) == Down {
continue
}
if err := slaves[i].Ping(); err != nil {
golog.Error("Node", "checkSlave", "Ping", 0, "db.Addr", slaves[i].Addr(), "error", err.Error())
} else {
n.LastSlavePing = time.Now().Unix()
atomic.StoreInt32(&(slaves[i].state), Up)
continue
}
if int64(n.DownAfterNoAlive) > 0 && time.Now().Unix()-n.LastSlavePing > int64(n.DownAfterNoAlive/time.Second) {
golog.Info("Node", "checkMaster", "Master down", 0,
"db.Addr", slaves[i].Addr(),
"slave_down_time", int64(n.DownAfterNoAlive/time.Second))
//If can't ping slave after DownAfterNoAlive, set slave Down
n.DownSlave(slaves[i].addr)
}
}
}
开发者ID:cch123,项目名称:kingshard,代码行数:32,代码来源:node.go
示例16: readHandshakeResponse
func (c *ClientConn) readHandshakeResponse() error {
data, err := c.readPacket()
if err != nil {
return err
}
pos := 0
//capability
c.capability = binary.LittleEndian.Uint32(data[:4])
pos += 4
//skip max packet size
pos += 4
//charset, skip, if you want to use another charset, use set names
//c.collation = CollationId(data[pos])
pos++
//skip reserved 23[00]
pos += 23
//user name
c.user = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)])
pos += len(c.user) + 1
//auth length and auth
authLen := int(data[pos])
pos++
auth := data[pos : pos+authLen]
checkAuth := mysql.CalcPassword(c.salt, []byte(c.proxy.cfg.Password))
if c.user != c.proxy.cfg.User || !bytes.Equal(auth, checkAuth) {
golog.Error("ClientConn", "readHandshakeResponse", "error", 0,
"auth", auth,
"checkAuth", checkAuth,
"client_user", c.user,
"config_set_user", c.proxy.cfg.User,
"passworld", c.proxy.cfg.Password)
return mysql.NewDefaultError(mysql.ER_ACCESS_DENIED_ERROR, c.user, c.c.RemoteAddr().String(), "Yes")
}
pos += authLen
var db string
if c.capability&mysql.CLIENT_CONNECT_WITH_DB > 0 {
if len(data[pos:]) == 0 {
return nil
}
db = string(data[pos : pos+bytes.IndexByte(data[pos:], 0)])
pos += len(c.db) + 1
}
c.db = db
return nil
}
开发者ID:flike,项目名称:kingshard,代码行数:60,代码来源:conn.go
示例17: handleAdmin
func (c *ClientConn) handleAdmin(admin *sqlparser.Admin) error {
var err error
var result *mysql.Resultset
region := sqlparser.String(admin.Region)
err = c.checkCmdOrder(region, admin.Columns)
if err != nil {
return err
}
switch strings.ToLower(region) {
case NodeRegion:
err = c.handleNodeCmd(admin.Rows)
case ServerRegion:
result, err = c.handleServerCmd(admin.Rows)
default:
return fmt.Errorf("admin %s not supported now", region)
}
if err != nil {
golog.Error("ClientConn", "handleAdmin", err.Error(),
c.connectionId, "sql", sqlparser.String(admin))
return err
}
if result != nil {
return c.writeResultset(c.status, result)
}
return c.writeOK(nil)
}
开发者ID:GavinChangCN,项目名称:kingshard,代码行数:32,代码来源:conn_admin.go
示例18: handleUnsupport
//返回true表示已经处理,false表示未处理
func (c *ClientConn) handleUnsupport(sql string) (bool, error) {
var rs []*Result
var TK_FROM string = "from"
sql = strings.ToLower(sql)
tokens := strings.Fields(sql)
tokensLen := len(tokens)
if 0 < tokensLen {
//token is in WHITE_TOKEN_MAP
if 0 < WHITE_TOKEN_MAP[tokens[0]] {
//select
if 1 < WHITE_TOKEN_MAP[tokens[0]] {
for i := 1; i < tokensLen; i++ {
if tokens[i] == TK_FROM {
return false, nil
}
}
} else {
return false, nil
}
}
}
defaultRule := c.schema.rule.DefaultRule
if len(defaultRule.Nodes) == 0 {
return false, ErrNoDefaultNode
}
defaultNode := c.proxy.GetNode(defaultRule.Nodes[0])
//execute in Master DB
conn, err := c.getBackendConn(defaultNode, false)
if err != nil {
return false, err
}
rs, err = c.executeInNode(conn, sql, nil)
if err != nil {
return false, err
}
c.closeConn(conn, false)
if len(rs) == 0 {
msg := fmt.Sprintf("result is empty")
golog.Error("ClientConn", "handleUnsupport", msg, c.connectionId)
return false, NewError(ER_UNKNOWN_ERROR, msg)
}
if rs[0].Resultset != nil {
err = c.writeResultset(c.status, rs[0].Resultset)
} else {
err = c.writeOK(rs[0])
}
if err != nil {
return false, err
}
return true, nil
}
开发者ID:9466,项目名称:kingshard,代码行数:61,代码来源:conn_query.go
示例19: parseNode
func (s *Server) parseNode(cfg config.NodeConfig) (*backend.Node, error) {
n := new(backend.Node)
//n.server = s
n.Cfg = cfg
n.DownAfterNoAlive = time.Duration(cfg.DownAfterNoAlive) * time.Second
if len(cfg.Master) == 0 {
return nil, fmt.Errorf("must setting master MySQL node.")
}
var err error
if n.Master, err = n.OpenDB(cfg.Master); err != nil {
return nil, err
}
//n.db = n.Master
if len(cfg.Slave) > 0 {
if n.Slave, err = n.OpenDB(cfg.Slave); err != nil {
golog.Error("ClientConn", "handleShowProxy", err.Error(), 0)
n.Slave = nil
}
}
go n.Run()
return n, nil
}
开发者ID:jin06,项目名称:kingshard,代码行数:29,代码来源:server.go
示例20: handleNodeCmd
func (c *ClientConn) handleNodeCmd(rows sqlparser.InsertRows) error {
var err error
var opt, nodeName, role, addr string
vals := rows.(sqlparser.Values)
if len(vals) == 0 {
return errors.ErrCmdUnsupport
}
tuple := vals[0].(sqlparser.ValTuple)
if len(tuple) != len(cmdNodeOrder) {
return errors.ErrCmdUnsupport
}
opt = sqlparser.String(tuple[0])
opt = strings.Trim(opt, "'")
nodeName = sqlparser.String(tuple[1])
nodeName = strings.Trim(nodeName, "'")
role = sqlparser.String(tuple[2])
role = strings.Trim(role, "'")
addr = sqlparser.String(tuple[3])
addr = strings.Trim(addr, "'")
switch strings.ToLower(opt) {
case ADMIN_OPT_ADD:
err = c.AddDatabase(
nodeName,
role,
addr,
)
case ADMIN_OPT_DEL:
err = c.DeleteDatabase(
nodeName,
role,
addr,
)
case ADMIN_OPT_UP:
err = c.UpDatabase(
nodeName,
role,
addr,
)
case ADMIN_OPT_DOWN:
err = c.DownDatabase(
nodeName,
role,
addr,
)
default:
err = errors.ErrCmdUnsupport
golog.Error("ClientConn", "handleNodeCmd", err.Error(),
c.connectionId, "opt", opt)
}
return err
}
开发者ID:GavinChangCN,项目名称:kingshard,代码行数:59,代码来源:conn_admin.go
注:本文中的github.com/flike/kingshard/core/golog.Error函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论