Compare commits
48 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
65d34e17f2 | |
|
|
e7ae12b939 | |
|
|
8ed0a4c936 | |
|
|
3aecbceef8 | |
|
|
d2fae8858e | |
|
|
de0fde98c0 | |
|
|
a22a83f93c | |
|
|
13cd706505 | |
|
|
3ee707e60c | |
|
|
8de9252ae5 | |
|
|
9b7f627b0f | |
|
|
16c67e0b44 | |
|
|
d705073188 | |
|
|
ae30e2c0de | |
|
|
ccdcfc4ebc | |
|
|
1ba9b3ab0a | |
|
|
747da175d7 | |
|
|
a58cb65486 | |
|
|
de5704b90e | |
|
|
a589b8d32f | |
|
|
0c5879b6d3 | |
|
|
25515fd266 | |
|
|
d473317c7c | |
|
|
1310a49824 | |
|
|
bff14dcc82 | |
|
|
8c955c89ea | |
|
|
e856a26dd6 | |
|
|
1de0cb8203 | |
|
|
99c261ca91 | |
|
|
a490fea952 | |
|
|
8fddf71e5c | |
|
|
f998db645e | |
|
|
830b635af7 | |
|
|
fa8dded9f5 | |
|
|
ea9b6384af | |
|
|
1ceea92959 | |
|
|
054cbb910e | |
|
|
5903333242 | |
|
|
6903a40cc2 | |
|
|
aed016e7be | |
|
|
a7f76f00a9 | |
|
|
6c14e82c92 | |
|
|
a42b6770c9 | |
|
|
e386683768 | |
|
|
44b1fba8c8 | |
|
|
bc876f20d6 | |
|
|
14cb71f306 | |
|
|
666348870e |
|
|
@ -18,3 +18,4 @@ go.sum
|
||||||
tmp/
|
tmp/
|
||||||
.vscode/
|
.vscode/
|
||||||
logs/
|
logs/
|
||||||
|
snippet
|
||||||
|
|
@ -23,7 +23,7 @@ type Config struct {
|
||||||
//Init 初始化consul连接
|
//Init 初始化consul连接
|
||||||
func Init(config *Config) error {
|
func Init(config *Config) error {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
conf = &Config{
|
config = &Config{
|
||||||
Address: "127.0.0.1:8500",
|
Address: "127.0.0.1:8500",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +83,40 @@ func Register(name string, addr string, port int, tags ...string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//RegisterAPI 注册api服务到consul
|
||||||
|
func RegisterAPI(name string, addr string, port int, tags ...string) error {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if client == nil {
|
||||||
|
return errors.New("consul 实例空")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建注册到consul的服务到
|
||||||
|
registration := new(consulapi.AgentServiceRegistration)
|
||||||
|
registration.ID = fmt.Sprintf("%s-%s:%d", name, addr, port)
|
||||||
|
registration.Name = name
|
||||||
|
registration.Port = port
|
||||||
|
registration.Tags = tags
|
||||||
|
registration.Address = addr
|
||||||
|
|
||||||
|
// 增加consul健康检查回调函数
|
||||||
|
check := new(consulapi.AgentServiceCheck)
|
||||||
|
check.HTTP = fmt.Sprintf("http://%s:%d/health/check", registration.Address, registration.Port)
|
||||||
|
check.Timeout = "5s"
|
||||||
|
check.Interval = "5s"
|
||||||
|
check.DeregisterCriticalServiceAfter = "30s" // 故障检查失败30s后 consul自动将注册服务删除
|
||||||
|
|
||||||
|
registration.Check = check
|
||||||
|
|
||||||
|
// 注册服务到consul
|
||||||
|
if err := client.Agent().ServiceRegister(registration); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
//DeRegister 取消consul注册的服务
|
//DeRegister 取消consul注册的服务
|
||||||
func DeRegister(name string, addr string, port int) error {
|
func DeRegister(name string, addr string, port int) error {
|
||||||
client, err := New()
|
client, err := New()
|
||||||
|
|
@ -97,7 +131,7 @@ func DeRegister(name string, addr string, port int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
//FindNode 查找节点
|
//FindNode 查找节点
|
||||||
func FindNode(servicename string) (*consulapi.AgentService, error) {
|
func FindNode(servicename, tag string) (*consulapi.AgentService, error) {
|
||||||
client, err := New()
|
client, err := New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -106,7 +140,7 @@ func FindNode(servicename string) (*consulapi.AgentService, error) {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return nil, errors.New("consul 实例空")
|
return nil, errors.New("consul 实例空")
|
||||||
}
|
}
|
||||||
services, _, err := client.Health().Service(servicename, "", true, nil)
|
services, _, err := client.Health().Service(servicename, tag, true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -122,9 +156,9 @@ func FindNode(servicename string) (*consulapi.AgentService, error) {
|
||||||
return services[r.Intn(l)%l].Service, nil
|
return services[r.Intn(l)%l].Service, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//FindServer 从consul中发现服务
|
//FindService 从consul中发现服务,并返回grpc连接实例
|
||||||
func FindServer(servicename string) (*grpc.ClientConn, error) {
|
func FindService(servicename, tag string) (*grpc.ClientConn, error) {
|
||||||
node, err := FindNode(servicename)
|
node, err := FindNode(servicename, tag) //无tag视为grpc服务
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package exceptionless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Post posts to the Exceptionless Server
|
||||||
|
func Post(endpoint string, postBody string, authorization string) string {
|
||||||
|
url := conf.ServerURL + endpoint
|
||||||
|
var jsonStr = []byte(postBody)
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+authorization)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
// body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
return string(resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET makes api GET requests
|
||||||
|
func Get(endpoint string, authorization string) map[string]interface{} {
|
||||||
|
url := conf.ServerURL + endpoint
|
||||||
|
|
||||||
|
httpClient := &http.Client{}
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
// return "Error"
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("accept", "application/json")
|
||||||
|
req.Header.Add("Authorization", "Bearer "+authorization)
|
||||||
|
|
||||||
|
res, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
// return "Error"
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
// return "Error"
|
||||||
|
}
|
||||||
|
|
||||||
|
// resp := string(body)
|
||||||
|
var result map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(body), &result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
@ -1,99 +1,217 @@
|
||||||
package exceptionless
|
package exceptionless
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"math/rand"
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var config map[string]interface{} = nil
|
||||||
|
|
||||||
|
// Config type defines the client configuration structure
|
||||||
type Config struct {
|
type Config struct {
|
||||||
URL string
|
ApiKey string
|
||||||
Token string
|
ServerURL string
|
||||||
|
ProgramName string
|
||||||
|
UpdateSettingsWhenIdleInterval int32
|
||||||
}
|
}
|
||||||
|
|
||||||
var conf *Config
|
var conf *Config
|
||||||
|
|
||||||
func Init(config *Config) error {
|
func Init(config *Config) {
|
||||||
if config == nil {
|
|
||||||
return errors.New("nil of Config")
|
|
||||||
}
|
|
||||||
conf = config
|
conf = config
|
||||||
conf.Token = "Bearer " + conf.Token
|
if conf == nil {
|
||||||
return nil
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf.ApiKey != "" && conf.UpdateSettingsWhenIdleInterval > 0 {
|
||||||
|
poll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func post(uri string, body interface{}) (*[]byte, error) {
|
// GetConfig returns the project configuration
|
||||||
url := fmt.Sprintf(`%s/%s`, conf.URL, uri)
|
func GetConfig() map[string]interface{} {
|
||||||
reqbody, _ := json.Marshal(body)
|
return config
|
||||||
req, err := http.NewRequest("POST", url, strings.NewReader(string(reqbody)))
|
}
|
||||||
|
|
||||||
|
// SubmitEvent sends log events to Exceptionless
|
||||||
|
func SubmitEvent(eventBody string) string {
|
||||||
|
if conf.ApiKey == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
resp := Post("events", eventBody, conf.ApiKey)
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func poll() {
|
||||||
|
r := rand.New(rand.NewSource(99))
|
||||||
|
c := time.Tick(10 * time.Second)
|
||||||
|
for _ = range c {
|
||||||
|
resp := Get("projects/config", conf.ApiKey)
|
||||||
|
config = resp
|
||||||
|
jitter := time.Duration(r.Int31n(conf.UpdateSettingsWhenIdleInterval)) * time.Millisecond
|
||||||
|
time.Sleep(jitter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event is the main model for events
|
||||||
|
type Event struct {
|
||||||
|
EventType string `json:"type"`
|
||||||
|
Source string `json:"source,omitempty"`
|
||||||
|
Date string `json:"date,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Geo string `json:"geo,omitempty"`
|
||||||
|
Value uint `json:"value,omitempty"`
|
||||||
|
Data map[string]interface{} `json:"data,omitempty"`
|
||||||
|
ReferenceID string `json:"reference_id,omitempty"`
|
||||||
|
Count uint `json:"count,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBaseEvent returns an empty Event struct that can be built into any type of event.
|
||||||
|
func GetBaseEvent(eventType string, message string, date string) Event {
|
||||||
|
return Event{
|
||||||
|
EventType: eventType,
|
||||||
|
Message: message,
|
||||||
|
Date: date,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSource adds a string value source to an event
|
||||||
|
func AddSource(event Event, source string) Event {
|
||||||
|
event.Source = source
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTags adds a string array of tags for the event
|
||||||
|
func AddTags(event Event, tags []string) Event {
|
||||||
|
event.Tags = tags
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddGeo adds the lat and long location of the user the event impacted
|
||||||
|
func AddGeo(event Event, geo string) Event {
|
||||||
|
event.Geo = geo
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddValue adds an arbitrary number value to the event
|
||||||
|
func AddValue(event Event, value uint) Event {
|
||||||
|
event.Value = value
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddReferenceID adds an indentifier to later refer to this event
|
||||||
|
func AddReferenceID(event Event, referenceID uuid.UUID) Event {
|
||||||
|
event.ReferenceID = referenceID.String()
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCount adds a number to help track the number of times the event has occurred
|
||||||
|
func AddCount(event Event, count uint) Event {
|
||||||
|
event.Count = count
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddLogLevel(event Event, level string) Event {
|
||||||
|
var updatedEvent Event
|
||||||
|
if event.Data != nil {
|
||||||
|
event.Data["@level"] = level
|
||||||
|
updatedEvent = event
|
||||||
|
} else {
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
data["@level"] = level
|
||||||
|
updatedEvent = AddData(event, data)
|
||||||
|
}
|
||||||
|
return updatedEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddData adds a string mapping to create a data object of additional values
|
||||||
|
func AddData(event Event, data map[string]interface{}) Event {
|
||||||
|
event.Data = data
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubmitAppError(funcName string, proc string, reqid *string, err error) string {
|
||||||
|
referenceID := uuid.Must(uuid.NewUUID()).String()
|
||||||
|
|
||||||
|
if reqid != nil {
|
||||||
|
referenceID = *reqid
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMap := map[string]interface{}{}
|
||||||
|
errorMap["function"] = funcName
|
||||||
|
errorMap["type"] = "error"
|
||||||
|
errorMap["message"] = err.Error()
|
||||||
|
errorMap["date"] = time.Now().Format(time.RFC3339)
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
data["@simple_error"] = errorMap
|
||||||
|
var event = Event{
|
||||||
|
EventType: "error",
|
||||||
|
Message: fmt.Sprintf("%s - %s", funcName, proc),
|
||||||
|
Data: data,
|
||||||
|
ReferenceID: referenceID,
|
||||||
|
Source: conf.ProgramName,
|
||||||
|
}
|
||||||
|
json, err := json.Marshal(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err.Error()
|
||||||
}
|
}
|
||||||
|
resp := SubmitEvent(string(json))
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
req.Header.Add("Authorization", conf.Token)
|
// SubmitError is a convenience wrapper to quickly build and submit an error
|
||||||
req.Header.Add("Content-Type", "application/json")
|
func SubmitError(err error) string {
|
||||||
|
if conf.UpdateSettingsWhenIdleInterval > 0 {
|
||||||
tr := &http.Transport{
|
GetConfig()
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
referenceID := uuid.Must(uuid.NewUUID())
|
||||||
resp, err := client.Do(req)
|
errorMap := map[string]interface{}{}
|
||||||
|
errorMap["type"] = "error"
|
||||||
|
errorMap["message"] = err.Error()
|
||||||
|
errorMap["date"] = time.Now().Format(time.RFC3339)
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
data["@simple_error"] = errorMap
|
||||||
|
var mainEvent = Event{
|
||||||
|
EventType: "error",
|
||||||
|
Message: err.Error(),
|
||||||
|
Data: data,
|
||||||
|
ReferenceID: referenceID.String(),
|
||||||
|
}
|
||||||
|
json, err := json.Marshal(mainEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
fmt.Println(err)
|
||||||
|
return err.Error()
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
resp := SubmitEvent(string(json))
|
||||||
if resp.StatusCode == 202 {
|
return resp
|
||||||
return nil, nil
|
}
|
||||||
|
|
||||||
|
func SubmitLog(message string, level string) string {
|
||||||
|
referenceID := uuid.Must(uuid.NewUUID())
|
||||||
|
if conf.UpdateSettingsWhenIdleInterval > 0 {
|
||||||
|
config := GetConfig()
|
||||||
|
fmt.Println(config)
|
||||||
|
// We are stripping out info accoring to the config settings
|
||||||
|
// We would also prevent logs of levels below the log level set by the settings
|
||||||
}
|
}
|
||||||
respBody, err := ioutil.ReadAll(resp.Body)
|
var event Event
|
||||||
|
date := time.Now().Format(time.RFC3339)
|
||||||
|
event = GetBaseEvent("log", message, date)
|
||||||
|
event = AddReferenceID(event, referenceID)
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
data["@level"] = level
|
||||||
|
event = AddData(event, data)
|
||||||
|
|
||||||
|
json, err := json.Marshal(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
fmt.Println(err)
|
||||||
|
return err.Error()
|
||||||
}
|
}
|
||||||
return &respBody, nil
|
resp := SubmitEvent(string(json))
|
||||||
}
|
return resp
|
||||||
|
|
||||||
func WriteMessages(msg string) {
|
|
||||||
message := &struct {
|
|
||||||
Message string
|
|
||||||
}{
|
|
||||||
Message: msg,
|
|
||||||
}
|
|
||||||
post("api/v2/events", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WriteLogs(msg string) {
|
|
||||||
message := &struct {
|
|
||||||
Message string
|
|
||||||
Type string
|
|
||||||
Date string
|
|
||||||
}{
|
|
||||||
Type: "log",
|
|
||||||
Message: msg,
|
|
||||||
Date: time.Now().Format("2006-01-02 15:04:05"),
|
|
||||||
}
|
|
||||||
post("api/v2/events", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
func WriteErrors(msg string) {
|
|
||||||
message := &struct {
|
|
||||||
SimpleError interface{}
|
|
||||||
Type string
|
|
||||||
Date string
|
|
||||||
}{
|
|
||||||
Type: "error",
|
|
||||||
SimpleError: &struct {
|
|
||||||
Message string
|
|
||||||
}{
|
|
||||||
Message: msg,
|
|
||||||
},
|
|
||||||
Date: time.Now().Format("2006-01-02 15:04:05"),
|
|
||||||
}
|
|
||||||
post("api/v2/events", message)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package exceptionless
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestWriteMessage(t *testing.T) {
|
|
||||||
Init(&Config{
|
|
||||||
URL: "https://api.exceptionless.com",
|
|
||||||
Token: "MyNc2Rmfymq1XJ52rJdPW021zbQiAbzdxV92znbm",
|
|
||||||
})
|
|
||||||
// WriteMessages("adfasdfadsfsdf")
|
|
||||||
// WriteLogs("aaasfas222rwerwer")
|
|
||||||
WriteErrors("bbbbbb")
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"myschools.me/suguo/snippet/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 从redis中认证用户
|
||||||
|
func AuthUser() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
token := c.GetHeader("Authorization")
|
||||||
|
claims := cacheGet(&token)
|
||||||
|
if claims == nil {
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("user", claims)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从redis中获取用户信息,最佳实践经验建议把此代码放service层
|
||||||
|
func cacheGet(token *string) interface{} {
|
||||||
|
var user interface{}
|
||||||
|
b, err := redis.GetBytes(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(*b, &user); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &user
|
||||||
|
}
|
||||||
|
|
||||||
|
// gin拦截,基于微服务的拦截
|
||||||
|
// func AuthUserBS() gin.HandlerFunc {
|
||||||
|
// return func(c *gin.Context) {
|
||||||
|
// token := c.GetHeader("Authorization")
|
||||||
|
// claims := userAuthWithGrpc(&token)
|
||||||
|
// if claims == nil {
|
||||||
|
// yy.RespUnauth(c, "token无效或过期,请重新登录", nil, nil)
|
||||||
|
// c.Abort()
|
||||||
|
// }
|
||||||
|
// c.Set("user", claims)
|
||||||
|
// c.Next()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func userAuthWithGrpc(token *string) *yy.UserClaims {
|
||||||
|
// srv, err := consul.FindService("oauth", "v1")
|
||||||
|
// if err != nil {
|
||||||
|
// logrus.WithFields(logrus.Fields{
|
||||||
|
// "func": "userAuthWithGrpc",
|
||||||
|
// }).Errorf("consul.FindServer: %s", err.Error())
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// defer srv.Close()
|
||||||
|
// client := pb.NewCertificationClient(srv)
|
||||||
|
// resp, err := client.Auth(context.Background(), &pb.CertificationAuthRequest{
|
||||||
|
// Token: *token,
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// logrus.WithFields(logrus.Fields{
|
||||||
|
// "func": "userAuthWithGrpc",
|
||||||
|
// }).Errorf("client.Auth: %s", err.Error())
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// if resp.Result == "ok" {
|
||||||
|
// r := &yy.UserClaims{}
|
||||||
|
// if err := json.Unmarshal(resp.Data.Value, r); err != nil {
|
||||||
|
// logrus.WithFields(logrus.Fields{
|
||||||
|
// "func": "userAuthWithGrpc",
|
||||||
|
// }).Errorf("json.Unmarshal: %s", err.Error())
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// return r
|
||||||
|
// }
|
||||||
|
// logrus.WithFields(logrus.Fields{
|
||||||
|
// "func": "userAuthWithGrpc",
|
||||||
|
// }).Warnln("nil")
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
// GIN 配置
|
||||||
|
type Config struct {
|
||||||
|
RootPath string
|
||||||
|
Addr string
|
||||||
|
Port int
|
||||||
|
Ssl bool
|
||||||
|
SslPem string
|
||||||
|
SslKey string
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/unrolled/secure"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Service(conf *Config) {
|
||||||
|
if conf == nil {
|
||||||
|
conf = &Config{}
|
||||||
|
}
|
||||||
|
if conf.RootPath == "" {
|
||||||
|
conf.RootPath = "/"
|
||||||
|
}
|
||||||
|
if conf.Addr == "" {
|
||||||
|
conf.Addr = "0.0.0.0"
|
||||||
|
}
|
||||||
|
if conf.Port == 0 {
|
||||||
|
conf.Port = 8080
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
router := gin.New()
|
||||||
|
routerSetup(router, &conf.RootPath)
|
||||||
|
|
||||||
|
if conf.Ssl {
|
||||||
|
router.Use(tlsHandler(conf))
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", conf.Addr, conf.Port),
|
||||||
|
Handler: router,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
|
}
|
||||||
|
log.Printf("start service on %s", fmt.Sprintf("%s:%d", conf.Addr, conf.Port))
|
||||||
|
|
||||||
|
if conf.Ssl {
|
||||||
|
log.Fatal(s.ListenAndServeTLS(conf.SslPem, conf.SslKey))
|
||||||
|
} else {
|
||||||
|
log.Fatal(s.ListenAndServe())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func tlsHandler(conf *Config) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
secureMiddleware := secure.New(secure.Options{
|
||||||
|
SSLRedirect: true,
|
||||||
|
SSLHost: ":" + strconv.Itoa(conf.Port),
|
||||||
|
})
|
||||||
|
err := secureMiddleware.Process(c.Writer, c.Request)
|
||||||
|
|
||||||
|
// If there was an error, do not continue.
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 路由配置
|
||||||
|
func routerSetup(router *gin.Engine, rootpath *string) {
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
router.GET(`/health/check`)
|
||||||
|
|
||||||
|
r := router.Group(fmt.Sprintf("/%s", *rootpath))
|
||||||
|
{
|
||||||
|
r.POST(`/register`)
|
||||||
|
r.GET(`/accountcheck/:accname`)
|
||||||
|
r.POST(`/login`)
|
||||||
|
r.POST(`/forgot`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func filterUser() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
token := c.GetHeader("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
token = c.Query("Authorization")
|
||||||
|
}
|
||||||
|
|
||||||
|
staff, err := redis.UserGet(&token)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"func": "authUser",
|
||||||
|
}).Errorf("redis.UserGet: %s", err.Error())
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"data": "无效TOKEN, 请重新登录!",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if staff == nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||||
|
"data": "无效TOKEN, 请重新登录!",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("user", staff)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/unrolled/secure"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rootPath string
|
||||||
|
addr string
|
||||||
|
port int
|
||||||
|
ssl string
|
||||||
|
sslPem string
|
||||||
|
sslKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
func Service() {
|
||||||
|
addr = os.Getenv("GIN_ADDR")
|
||||||
|
if addr == "" {
|
||||||
|
addr = "0.0.0.0"
|
||||||
|
}
|
||||||
|
port, _ = strconv.Atoi(os.Getenv("GIN_PORT"))
|
||||||
|
if port == 0 {
|
||||||
|
port = 8080
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl = os.Getenv("GIN_SSL")
|
||||||
|
sslPem = os.Getenv("GIN_SSL_PEM")
|
||||||
|
sslKey = os.Getenv("GIN_SSL_KEY")
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
gin.DefaultWriter = io.Discard
|
||||||
|
router := gin.New()
|
||||||
|
routerSetup(router)
|
||||||
|
|
||||||
|
if ssl == "true" {
|
||||||
|
router.Use(tlsHandler())
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", addr, port),
|
||||||
|
Handler: router,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"func": "Service",
|
||||||
|
}).Infof("start service on %s:%d", addr, port)
|
||||||
|
|
||||||
|
if ssl == "true" {
|
||||||
|
log.Fatal(s.ListenAndServeTLS(sslPem, sslKey))
|
||||||
|
} else {
|
||||||
|
log.Fatal(s.ListenAndServe())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func tlsHandler() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
secureMiddleware := secure.New(secure.Options{
|
||||||
|
SSLRedirect: true,
|
||||||
|
SSLHost: ":" + strconv.Itoa(port),
|
||||||
|
})
|
||||||
|
err := secureMiddleware.Process(c.Writer, c.Request)
|
||||||
|
|
||||||
|
// If there was an error, do not continue.
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 路由配置
|
||||||
|
func routerSetup(router *gin.Engine) {
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
|
||||||
|
r := router.Group(`/`)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
58
go.mod
58
go.mod
|
|
@ -3,55 +3,67 @@ module myschools.me/suguo/snippet
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||||
github.com/gin-gonic/gin v1.7.4
|
github.com/gin-gonic/gin v1.7.4
|
||||||
github.com/gomodule/redigo v1.8.5
|
github.com/gomodule/redigo v1.8.5
|
||||||
|
github.com/google/uuid v1.1.2
|
||||||
github.com/hashicorp/consul/api v1.10.1
|
github.com/hashicorp/consul/api v1.10.1
|
||||||
google.golang.org/grpc v1.40.0
|
github.com/influxdata/influxdb v1.9.5
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
|
go.mongodb.org/mongo-driver v1.7.4
|
||||||
|
google.golang.org/grpc v1.41.0
|
||||||
gorm.io/driver/mysql v1.1.2
|
gorm.io/driver/mysql v1.1.2
|
||||||
gorm.io/driver/sqlite v1.1.4
|
gorm.io/driver/sqlite v1.1.4
|
||||||
gorm.io/gorm v1.21.15
|
gorm.io/gorm v1.21.15
|
||||||
gorm.io/plugin/dbresolver v1.1.0
|
gorm.io/plugin/dbresolver v1.1.0
|
||||||
myschools.me/wodeschool/ws-base v1.0.7
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
|
github.com/armon/go-metrics v0.3.3 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/fatih/color v1.9.0 // indirect
|
github.com/fatih/color v1.9.0 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.13.0 // indirect
|
github.com/go-playground/locales v0.14.0 // indirect
|
||||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||||
|
github.com/go-stack/stack v1.8.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.6 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||||
github.com/hashicorp/go-hclog v0.12.0 // indirect
|
github.com/hashicorp/go-hclog v0.12.2 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
|
github.com/hashicorp/go-immutable-radix v1.2.0 // indirect
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/hashicorp/serf v0.9.5 // indirect
|
github.com/hashicorp/serf v0.9.5 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.2 // indirect
|
github.com/jinzhu/now v1.1.2 // indirect
|
||||||
github.com/json-iterator/go v1.1.11 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/klauspost/compress v1.13.6 // indirect
|
||||||
github.com/leodido/go-urn v1.2.0 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.5 // indirect
|
github.com/mattn/go-sqlite3 v1.14.5 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
github.com/mitchellh/mapstructure v1.4.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/stretchr/testify v1.7.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/ugorji/go/codec v1.1.13 // indirect
|
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
|
github.com/xdg-go/scram v1.0.2 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
|
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect
|
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
23
grpc/grpc.go
23
grpc/grpc.go
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/reflection"
|
"google.golang.org/grpc/reflection"
|
||||||
|
|
@ -17,6 +18,7 @@ type Config struct {
|
||||||
Address string
|
Address string
|
||||||
Port int
|
Port int
|
||||||
AppName string
|
AppName string
|
||||||
|
Opts []grpc.ServerOption
|
||||||
}
|
}
|
||||||
|
|
||||||
var rpc *grpc.Server
|
var rpc *grpc.Server
|
||||||
|
|
@ -25,15 +27,16 @@ var conf *Config
|
||||||
func Init(config *Config) *grpc.Server {
|
func Init(config *Config) *grpc.Server {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
config = &Config{
|
config = &Config{
|
||||||
Address: "",
|
Address: "0.0.0.0",
|
||||||
Port: 0,
|
Port: 0,
|
||||||
AppName: "dev",
|
AppName: "unknown",
|
||||||
|
Opts: []grpc.ServerOption{grpc.MaxRecvMsgSize(1024 * 1024), grpc.MaxSendMsgSize(1024 * 1024)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf = config
|
conf = config
|
||||||
|
|
||||||
if rpc == nil {
|
if rpc == nil {
|
||||||
rpc = grpc.NewServer(grpc.MaxRecvMsgSize(1024*1024), grpc.MaxSendMsgSize(1024*1024))
|
rpc = grpc.NewServer(conf.Opts...)
|
||||||
}
|
}
|
||||||
return rpc
|
return rpc
|
||||||
}
|
}
|
||||||
|
|
@ -49,28 +52,26 @@ func Port() int {
|
||||||
func Start() {
|
func Start() {
|
||||||
//注册反射 用于grpcurl调试
|
//注册反射 用于grpcurl调试
|
||||||
reflection.Register(rpc)
|
reflection.Register(rpc)
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
// grpc服务启动
|
// grpc服务启动
|
||||||
go func() {
|
go func() {
|
||||||
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", conf.Address, conf.Port))
|
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", conf.Address, conf.Port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("net.ResolveTCPAddr", err)
|
log.Fatal("net.ResolveTCPAddr", err)
|
||||||
}
|
}
|
||||||
if addr.IP.String() != conf.Address {
|
|
||||||
conf.Address = addr.IP.String()
|
|
||||||
}
|
|
||||||
if addr.Port != conf.Port {
|
|
||||||
conf.Port = addr.Port
|
|
||||||
}
|
|
||||||
log.Printf("starting grpc service on %s:%d", addr.IP, addr.Port)
|
|
||||||
lis, err := net.ListenTCP("tcp", addr)
|
lis, err := net.ListenTCP("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("fail to open port: ", err)
|
log.Fatal("fail to open port: ", err)
|
||||||
}
|
}
|
||||||
defer lis.Close()
|
defer lis.Close()
|
||||||
|
conf.Port = lis.Addr().(*net.TCPAddr).Port
|
||||||
|
wg.Done()
|
||||||
|
log.Printf("starting grpc service on %s:%d", addr.IP, conf.Port)
|
||||||
err = rpc.Serve(lis)
|
err = rpc.Serve(lis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("fail to open microservice: ", err)
|
log.Fatal("fail to open microservice: ", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package influx
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Address string
|
||||||
|
DBName string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
//单位:秒
|
||||||
|
Timeout int
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
package influx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/influxdata/influxdb/client/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conf *Config
|
||||||
|
|
||||||
|
//配置初始化
|
||||||
|
func Init(_conf *Config) {
|
||||||
|
conf = _conf
|
||||||
|
if conf == nil {
|
||||||
|
conf = &Config{
|
||||||
|
Address: "127.0.0.1",
|
||||||
|
Timeout: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//实例
|
||||||
|
func New() (client.Client, error) {
|
||||||
|
cli, err := client.NewHTTPClient(client.HTTPConfig{
|
||||||
|
Addr: conf.Address,
|
||||||
|
Username: conf.Username,
|
||||||
|
Password: conf.Password,
|
||||||
|
Timeout: time.Duration(conf.Timeout) * time.Second,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cli, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入例子
|
||||||
|
func WriteSample() error {
|
||||||
|
cli, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cli.Close()
|
||||||
|
bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
|
||||||
|
Database: func() string {
|
||||||
|
if conf.DBName == "" {
|
||||||
|
return "sample"
|
||||||
|
}
|
||||||
|
return conf.DBName
|
||||||
|
}(),
|
||||||
|
Precision: "s",
|
||||||
|
})
|
||||||
|
|
||||||
|
fields := make(map[string]interface{})
|
||||||
|
fields["f1"] = "F1"
|
||||||
|
fields["f2"] = 1
|
||||||
|
|
||||||
|
pt, _ := client.NewPoint(
|
||||||
|
"heartrate",
|
||||||
|
map[string]string{"platform": "ws", "orgid": "a001"},
|
||||||
|
fields,
|
||||||
|
time.Now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
bp.AddPoint(pt)
|
||||||
|
if err := cli.Write(bp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadSample() error {
|
||||||
|
query, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer query.Close()
|
||||||
|
|
||||||
|
resp, err := query.QueryCtx(context.Background(), client.Query{
|
||||||
|
Command: `select * from heartrate where time>'` + time.Now().Add(-12*time.Hour).Format("2006-01-02T15:04:05") + `' group by time(10m) tz('Asia/Shanghai')`,
|
||||||
|
Database: func() string {
|
||||||
|
if conf.DBName == "" {
|
||||||
|
return "sample"
|
||||||
|
}
|
||||||
|
return conf.DBName
|
||||||
|
}(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range resp.Results[0].Series[0].Values {
|
||||||
|
//fmt.Println(reflect.TypeOf(s[1]))
|
||||||
|
f1 := s[1].(json.Number).String()
|
||||||
|
f2, _ := s[2].(json.Number).Int64()
|
||||||
|
platform := s[3].(json.Number).String()
|
||||||
|
fmt.Println(f1, f2, platform)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建数据库,并配置默认过期策略(单位:天)
|
||||||
|
func CreateDB(dbname string, expired uint) error {
|
||||||
|
if dbname == "" || expired == 0 {
|
||||||
|
return errors.New("无效参数")
|
||||||
|
}
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
createDbSQL := client.NewQuery(fmt.Sprintf("CREATE DATABASE %s", dbname), "", "")
|
||||||
|
result, err := db.Query(createDbSQL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if result.Error() != nil {
|
||||||
|
return result.Error()
|
||||||
|
}
|
||||||
|
// 过期策略
|
||||||
|
createRPSQL := client.NewQuery(fmt.Sprintf("CREATE RETENTION POLICY default ON %s DURATION %dd REPLICATION 1 DEFAULT", dbname, expired), dbname, "")
|
||||||
|
result, err = db.Query(createRPSQL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return result.Error()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package influx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
|
||||||
|
"github.com/influxdata/influxdb-client-go/v2/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
influx_dsn string
|
||||||
|
influx_token string
|
||||||
|
influx_org string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
influx_dsn = os.Getenv("INFLUX_DSN")
|
||||||
|
if influx_dsn == "" {
|
||||||
|
influx_dsn = "http://influx:8086"
|
||||||
|
}
|
||||||
|
influx_token = os.Getenv("INFLUX_TOKEN")
|
||||||
|
influx_org = os.Getenv("INFLUX_ORG")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实例
|
||||||
|
func newInstance() influxdb2.Client {
|
||||||
|
client := influxdb2.NewClient(influx_dsn, influx_token)
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入例子
|
||||||
|
func write(bucket, measurement string, tags map[string]string, fields map[string]interface{}) error {
|
||||||
|
client := newInstance()
|
||||||
|
defer client.Close()
|
||||||
|
writeAPI := client.WriteAPIBlocking(influx_org, bucket)
|
||||||
|
// Create point using full params constructor
|
||||||
|
p := influxdb2.NewPoint(measurement,
|
||||||
|
tags,
|
||||||
|
fields,
|
||||||
|
time.Now())
|
||||||
|
// write point immediately
|
||||||
|
if err := writeAPI.WritePoint(context.Background(), p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Or write directly line protocol
|
||||||
|
// line := fmt.Sprintf("stat,unit=temperature avg=%f,max=%f", 23.5, 45.0)
|
||||||
|
// err = writeAPI.WriteRecord(context.Background(), line)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeLine(bucket, line string) error {
|
||||||
|
client := newInstance()
|
||||||
|
defer client.Close()
|
||||||
|
writeAPI := client.WriteAPIBlocking(influx_org, bucket)
|
||||||
|
// Create point using full params constructor
|
||||||
|
p := influxdb2.NewPoint(line,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
time.Now())
|
||||||
|
// write point immediately
|
||||||
|
if err := writeAPI.WritePoint(context.Background(), p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Query(sql string) (*api.QueryTableResult, error) {
|
||||||
|
client := newInstance()
|
||||||
|
defer client.Close()
|
||||||
|
queryAPI := client.QueryAPI(influx_org)
|
||||||
|
result, err := queryAPI.Query(context.Background(), sql)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func QuerySimple() {
|
||||||
|
client := newInstance()
|
||||||
|
defer client.Close()
|
||||||
|
// Get query client
|
||||||
|
queryAPI := client.QueryAPI(influx_org)
|
||||||
|
// Get parser flux query result
|
||||||
|
result, err := queryAPI.Query(context.Background(), `from(bucket:"my-bucket")|> range(start: -1h) |> filter(fn: (r) => r._measurement == "stat")`)
|
||||||
|
if err == nil {
|
||||||
|
// Use Next() to iterate over query result lines
|
||||||
|
for result.Next() {
|
||||||
|
// Observe when there is new grouping key producing new table
|
||||||
|
if result.TableChanged() {
|
||||||
|
fmt.Printf("table: %s\n", result.TableMetadata().String())
|
||||||
|
}
|
||||||
|
// read result
|
||||||
|
fmt.Printf("row: %s\n", result.Record().String())
|
||||||
|
}
|
||||||
|
if result.Err() != nil {
|
||||||
|
fmt.Printf("Query error: %s\n", result.Err().Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Ensures background processes finishes
|
||||||
|
client.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 示例,不要进行生产环境调用
|
||||||
|
func WriteSimple(bucketName string) {
|
||||||
|
client := newInstance()
|
||||||
|
writeAPI := client.WriteAPIBlocking(influx_org, bucketName)
|
||||||
|
// Create point using full params constructor
|
||||||
|
p := influxdb2.NewPoint("stat",
|
||||||
|
map[string]string{"unit": "temperature"},
|
||||||
|
map[string]interface{}{"avg": 24.5, "max": 45.0},
|
||||||
|
time.Now())
|
||||||
|
// write point immediately
|
||||||
|
writeAPI.WritePoint(context.Background(), p)
|
||||||
|
// Create point using fluent style
|
||||||
|
p = influxdb2.NewPointWithMeasurement("stat").
|
||||||
|
AddTag("unit", "temperature").
|
||||||
|
AddField("avg", 23.2).
|
||||||
|
AddField("max", 45.0).
|
||||||
|
SetTime(time.Now())
|
||||||
|
if err := writeAPI.WritePoint(context.Background(), p); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Or write directly line protocol
|
||||||
|
line := fmt.Sprintf("stat,unit=temperature avg=%f,max=%f", 23.5, 45.0)
|
||||||
|
if err := writeAPI.WriteRecord(context.Background(), line); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package leveldb
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package leveldb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _db *leveldb.DB
|
||||||
|
var config *Config
|
||||||
|
|
||||||
|
func Init(conf *Config) {
|
||||||
|
config = conf
|
||||||
|
if config == nil {
|
||||||
|
config = &Config{
|
||||||
|
Path: "./",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() (*leveldb.DB, error) {
|
||||||
|
if _db != nil {
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
db, err := leveldb.OpenFile(config.Path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_db = db
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Close() {
|
||||||
|
if _db != nil {
|
||||||
|
_db.Close()
|
||||||
|
}
|
||||||
|
_db = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get(key *string) (*[]byte, error) {
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if db == nil {
|
||||||
|
return nil, errors.New("leveldb is nil")
|
||||||
|
}
|
||||||
|
ret, err := db.Has([]byte(*key), &opt.ReadOptions{
|
||||||
|
DontFillCache: false,
|
||||||
|
Strict: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("key检查异常")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ret {
|
||||||
|
return nil, errors.New("key不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := db.Get([]byte(*key), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(val) == 0 {
|
||||||
|
return nil, errors.New("key empty")
|
||||||
|
}
|
||||||
|
return &val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Put(key *string, payload *[]byte) error {
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db == nil {
|
||||||
|
return errors.New("leveldb is busy now")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Put([]byte(*key), *payload, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Delete(key *string) error {
|
||||||
|
db, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if db == nil {
|
||||||
|
return errors.New("leveldb is busy now")
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := db.Has([]byte(*key), &opt.ReadOptions{
|
||||||
|
DontFillCache: false,
|
||||||
|
Strict: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ret {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Delete([]byte(*key), nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||||
|
"github.com/rifflock/lfshook"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
注意,当天文件放项目根目录下
|
||||||
|
|
||||||
|
env LOGLEVEL=debug
|
||||||
|
*/
|
||||||
|
func init() {
|
||||||
|
//日志初始化
|
||||||
|
level := os.Getenv("LOGLEVEL")
|
||||||
|
|
||||||
|
switch level {
|
||||||
|
case "debug":
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
case "info":
|
||||||
|
logrus.SetLevel(logrus.InfoLevel)
|
||||||
|
case "warn":
|
||||||
|
logrus.SetLevel(logrus.WarnLevel)
|
||||||
|
case "error":
|
||||||
|
logrus.SetLevel(logrus.ErrorLevel)
|
||||||
|
case "fatal":
|
||||||
|
logrus.SetLevel(logrus.FatalLevel)
|
||||||
|
default:
|
||||||
|
logrus.SetLevel(logrus.PanicLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.AddHook(newLfsHook(72))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLfsHook(maxRemainCnt uint) logrus.Hook {
|
||||||
|
//检查与创建日志文件夹
|
||||||
|
_, err := os.Stat("logs")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
os.Mkdir("logs", 0755)
|
||||||
|
}
|
||||||
|
|
||||||
|
logName := fmt.Sprintf(`logs/%s`, "device-wg")
|
||||||
|
writer, err := rotatelogs.New(
|
||||||
|
logName+"%Y%m%d.log",
|
||||||
|
// WithLinkName为最新的日志建立软连接,以方便随着找到当前日志文件
|
||||||
|
rotatelogs.WithLinkName(logName),
|
||||||
|
|
||||||
|
// WithRotationTime设置日志分割的时间,这里设置为一小时分割一次
|
||||||
|
rotatelogs.WithRotationTime(24*time.Hour),
|
||||||
|
|
||||||
|
// WithMaxAge和WithRotationCount二者只能设置一个,
|
||||||
|
// WithMaxAge设置文件清理前的最长保存时间,
|
||||||
|
// WithRotationCount设置文件清理前最多保存的个数。
|
||||||
|
//rotatelogs.WithMaxAge(time.Hour*24),
|
||||||
|
rotatelogs.WithRotationCount(maxRemainCnt),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic("config local file system for logger error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lfsHook := lfshook.NewHook(lfshook.WriterMap{
|
||||||
|
logrus.DebugLevel: writer,
|
||||||
|
logrus.InfoLevel: writer,
|
||||||
|
logrus.WarnLevel: writer,
|
||||||
|
logrus.ErrorLevel: writer,
|
||||||
|
logrus.FatalLevel: writer,
|
||||||
|
logrus.PanicLevel: writer,
|
||||||
|
}, &logrus.TextFormatter{DisableColors: true})
|
||||||
|
|
||||||
|
return lfsHook
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
当前包适合放根目录下使用
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package mongo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Uri string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Database string
|
||||||
|
Timeout int
|
||||||
|
}
|
||||||
|
|
||||||
|
var config *Config
|
||||||
|
|
||||||
|
func Init(conf *Config) {
|
||||||
|
config = conf
|
||||||
|
if config == nil {
|
||||||
|
config = &Config{
|
||||||
|
Uri: "mongodb://localhost:27017",
|
||||||
|
Database: "admin",
|
||||||
|
Timeout: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//New 获取mongo客户端
|
||||||
|
//// "mongodb://user:password@localhost:27017"
|
||||||
|
func New() (*mongo.Client, error) {
|
||||||
|
clientOpts := options.Client().ApplyURI(config.Uri)
|
||||||
|
|
||||||
|
if config.Username != "" && config.Password != "" {
|
||||||
|
clientOpts = clientOpts.SetAuth(options.Credential{
|
||||||
|
AuthMechanism: "SCRAM-SHA-256",
|
||||||
|
AuthSource: config.Database,
|
||||||
|
Username: config.Username,
|
||||||
|
Password: config.Password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Timeout)*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
return mongo.Connect(ctx, clientOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ping() error {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.Timeout)*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
return client.Ping(ctx, readpref.Primary())
|
||||||
|
}
|
||||||
|
|
||||||
|
//Collection 获取集合
|
||||||
|
func Collection(client *mongo.Client, cname string) (*mongo.Collection, error) {
|
||||||
|
collection := client.Database(config.Database).Collection(cname)
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//CollectionMulti 支持多数据库直接获取collection
|
||||||
|
func CollectionMulti(client *mongo.Client, cname string) (*mongo.Collection, error) {
|
||||||
|
name := strings.Split(cname, ".")
|
||||||
|
if len(name) != 2 {
|
||||||
|
return nil, errors.New("collection名称不正确,请使用[database.collection]方式使用")
|
||||||
|
}
|
||||||
|
if name[0] == "" || name[1] == "" {
|
||||||
|
return nil, errors.New("名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := client.Database(name[0]).Collection(name[1])
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
package mongo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Init(&Config{
|
||||||
|
Uri: "mongodb://192.168.0.254:27017",
|
||||||
|
Database: "test",
|
||||||
|
Username: "test",
|
||||||
|
Password: "Test1231",
|
||||||
|
Timeout: 3,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMongo(t *testing.T) {
|
||||||
|
if err := Ping(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Student struct {
|
||||||
|
ID primitive.ObjectID `bson:"_id" json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Sex string `json:"sex,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// ret, err := col.InsertOne(ctx, Student{Name: "张惠", Sex: "女"})
|
||||||
|
ret, err := col.InsertOne(ctx, Student{ID: primitive.NewObjectID(), Name: "张惠", Sex: "女"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := col.FindOneAndDelete(ctx, bson.D{{"name", "张惠"}}).Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSingleResult(t *testing.T) {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var result Student
|
||||||
|
// if err := col.FindOne(ctx, bson.D{{"name", "张惠"}}).Decode(&result); err != nil {
|
||||||
|
if err := col.FindOne(ctx, bson.M{"name": "张惠"}).Decode(&result); err != nil {
|
||||||
|
if err != mongo.ErrNoDocuments {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindAll(t *testing.T) {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur, err := col.Find(ctx, bson.D{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cur.Close(ctx)
|
||||||
|
for cur.Next(ctx) {
|
||||||
|
var result Student
|
||||||
|
if err := cur.Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local())
|
||||||
|
}
|
||||||
|
if err := cur.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFind(t *testing.T) {
|
||||||
|
client, err := New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur, err := col.Find(ctx, bson.M{"name": bson.M{"$ne": "张惠"}}) //注意这里的格式$ne不相等,$gt大于,$gte大于等于,$in in,$nin no in ,$exists是否包含这个键...
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cur.Close(ctx)
|
||||||
|
for cur.Next(ctx) {
|
||||||
|
var result Student
|
||||||
|
if err := cur.Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local())
|
||||||
|
}
|
||||||
|
if err := cur.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
package mongo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mongo_uri string
|
||||||
|
mongo_database string
|
||||||
|
mongo_username string
|
||||||
|
mongo_password string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
mongo_uri = os.Getenv("MONGO_URI")
|
||||||
|
if mongo_uri == "" {
|
||||||
|
mongo_uri = "mongodb://localhost:27017"
|
||||||
|
}
|
||||||
|
mongo_database = os.Getenv("MONGO_DB")
|
||||||
|
if mongo_database == "" {
|
||||||
|
mongo_database = "admin"
|
||||||
|
}
|
||||||
|
mongo_username = os.Getenv("MONGO_USERNAME")
|
||||||
|
mongo_password = os.Getenv("MONGO_PASSWORD")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新连接获取
|
||||||
|
func newConnect() (*mongo.Client, error) {
|
||||||
|
clientOpts := options.Client().ApplyURI(mongo_uri).SetConnectTimeout(3 * time.Second)
|
||||||
|
|
||||||
|
if mongo_username != "" && mongo_password != "" {
|
||||||
|
clientOpts = clientOpts.SetAuth(options.Credential{
|
||||||
|
AuthMechanism: "SCRAM-SHA-256",
|
||||||
|
AuthSource: "admin",
|
||||||
|
Username: mongo_username,
|
||||||
|
Password: mongo_password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
return mongo.Connect(ctx, clientOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDB(client *mongo.Client, dbname string) (*mongo.Database, error) {
|
||||||
|
db := dbname
|
||||||
|
if db == "" {
|
||||||
|
db = mongo_database
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Database(db), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCollection(client *mongo.Client, dbname, colname string) (*mongo.Collection, error) {
|
||||||
|
db, err := newDB(client, dbname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return db.Collection(colname), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取默认集合,即数据库名已指定的库
|
||||||
|
func newDefaultCollection(client *mongo.Client, colname string) (*mongo.Collection, error) {
|
||||||
|
db, err := newDB(client, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return db.Collection(colname), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ping() error {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
return client.Ping(ctx, readpref.Primary())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collection 获取集合
|
||||||
|
func Collection(client *mongo.Client, cname string) (*mongo.Collection, error) {
|
||||||
|
collection := client.Database(mongo_database).Collection(cname)
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectionMulti 支持多数据库直接获取collection
|
||||||
|
func CollectionMulti(client *mongo.Client, cname string) (*mongo.Collection, error) {
|
||||||
|
name := strings.Split(cname, ".")
|
||||||
|
if len(name) != 2 {
|
||||||
|
return nil, errors.New("collection名称不正确,请使用[database.collection]方式使用")
|
||||||
|
}
|
||||||
|
if name[0] == "" || name[1] == "" {
|
||||||
|
return nil, errors.New("名称不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
collection := client.Database(name[0]).Collection(name[1])
|
||||||
|
return collection, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,270 @@
|
||||||
|
package mongo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
mongo_uri = "mongodb://192.168.0.254:27017"
|
||||||
|
mongo_database = "sample"
|
||||||
|
mongo_username = "aaa"
|
||||||
|
mongo_password = "bbb123"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPing(t *testing.T) {
|
||||||
|
if err := ping(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Student struct {
|
||||||
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` //确保在 BSON 编码/解码时,当 _id 为空时不会将其包含在文档中。在插入文档时,可以不设置 ID 字段,MongoDB 驱动会自动为其生成一个唯一的 ObjectID。
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Sex string `json:"sex,omitempty"`
|
||||||
|
CourseID int `bson:"courseid,omitempty" json:"course_id,omitempty"`
|
||||||
|
StudentID int `json:"student_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Disconnect(context.Background())
|
||||||
|
|
||||||
|
for i := 0; i < 10000; i++ {
|
||||||
|
collection, err := newCollection(client, "", "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
n := fmt.Sprintf("张小凡%d", i)
|
||||||
|
ret, err := collection.InsertOne(context.Background(), &Student{Name: n, Sex: "女", StudentID: i, CourseID: i % 10})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(i, ret)
|
||||||
|
fmt.Println(ret.InsertedID.(primitive.ObjectID).Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertCourse(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Disconnect(context.Background())
|
||||||
|
|
||||||
|
for i := 2; i < 10; i++ {
|
||||||
|
collection, err := newCollection(client, "", "course")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
n := fmt.Sprintf("sports%d", i)
|
||||||
|
ret, err := collection.InsertOne(context.Background(), &Course{ID: i, Name: n, Title: "sports"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(i, ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Disconnect(context.Background())
|
||||||
|
col, err := newCollection(client, "", "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := col.FindOneAndDelete(context.Background(), bson.D{{"name", "张惠"}}).Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ret, err := col.DeleteOne(context.Background(), bson.D{{"name", "张惠"}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(ret)
|
||||||
|
ret, err = col.DeleteMany(context.Background(), bson.D{{"name", "张惠"}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSingleResult(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := Collection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var result Student
|
||||||
|
// if err := col.FindOne(ctx, bson.D{{"name", "张惠"}}).Decode(&result); err != nil {
|
||||||
|
if err := col.FindOne(ctx, bson.M{"name": "张惠0"}).Decode(&result); err != nil {
|
||||||
|
if err != mongo.ErrNoDocuments {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindAll(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := newCollection(client, "", "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur, err := col.Find(ctx, bson.D{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cur.Close(ctx)
|
||||||
|
for cur.Next(ctx) {
|
||||||
|
var result Student
|
||||||
|
if err := cur.Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local())
|
||||||
|
}
|
||||||
|
if err := cur.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFind(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := newDefaultCollection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur, err := col.Find(ctx, bson.M{"name": "张小凡1"}) //注意这里的格式$ne不相等,$gt大于,$gte大于等于,$in in,$nin no in ,$exists是否包含这个键...
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cur.Close(ctx)
|
||||||
|
for cur.Next(ctx) {
|
||||||
|
var result Student
|
||||||
|
if err := cur.Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local())
|
||||||
|
}
|
||||||
|
if err := cur.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPage(t *testing.T) {
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
defer client.Disconnect(ctx)
|
||||||
|
col, err := newDefaultCollection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cur, err := col.Find(ctx, bson.M{}, options.Find().SetSkip(1000).SetLimit(1000))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cur.Close(ctx)
|
||||||
|
for cur.Next(ctx) {
|
||||||
|
var result Student
|
||||||
|
if err := cur.Decode(&result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result, result.ID.String(), result.ID.Timestamp(), result.ID.Timestamp().Local())
|
||||||
|
}
|
||||||
|
if err := cur.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Course struct {
|
||||||
|
ID int `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关连表查询
|
||||||
|
func TestAggregate(t *testing.T) {
|
||||||
|
// 建立 MongoDB 连接
|
||||||
|
client, err := newConnect()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Disconnect(context.Background())
|
||||||
|
|
||||||
|
// 选择数据库和集合
|
||||||
|
studentsCollection, err := newDefaultCollection(client, "student")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行关联查询
|
||||||
|
pipeline := bson.A{
|
||||||
|
bson.D{
|
||||||
|
{"$match", bson.D{
|
||||||
|
{"name", "张小凡1"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
bson.D{
|
||||||
|
{"$lookup", bson.D{
|
||||||
|
{"from", "course"},
|
||||||
|
{"localField", "courseid"},
|
||||||
|
{"foreignField", "_id"},
|
||||||
|
{"as", "courses"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行聚合查询,结果OK
|
||||||
|
cursor, err := studentsCollection.Aggregate(context.Background(), pipeline)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cursor.Close(context.Background())
|
||||||
|
|
||||||
|
// 解码查询结果
|
||||||
|
var result []bson.M
|
||||||
|
if err := cursor.All(context.Background(), &result); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印查询结果
|
||||||
|
fmt.Println("Result:")
|
||||||
|
for _, doc := range result {
|
||||||
|
fmt.Println(doc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package mqtt
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Host string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
ClientID string
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package mqtt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
MQTT "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
var connHandler MQTT.OnConnectHandler = func(client MQTT.Client) {
|
||||||
|
token := client.Subscribe("#", 0, serviceHandler)
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
fmt.Println(token.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var connLostHandler MQTT.ConnectionLostHandler = func(client MQTT.Client, err error) {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 具体业务订阅的处理,此处为示例
|
||||||
|
var serviceHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
|
||||||
|
fmt.Println(msg.Topic())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package mqtt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
MQTT "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientSubscribe, clientDistribute MQTT.Client
|
||||||
|
config *Config
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init(c *Config) {
|
||||||
|
config = c
|
||||||
|
if config == nil {
|
||||||
|
config = &Config{
|
||||||
|
Host: "tcp://127.0.0.1:1883",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Options() *MQTT.ClientOptions {
|
||||||
|
opts := MQTT.NewClientOptions()
|
||||||
|
opts.AddBroker(config.Host)
|
||||||
|
opts.Username = config.Username
|
||||||
|
opts.Password = config.Password
|
||||||
|
opts.ClientID = config.ClientID
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() (MQTT.Client, error) {
|
||||||
|
if clientDistribute != nil {
|
||||||
|
return clientDistribute, nil
|
||||||
|
}
|
||||||
|
opts := Options()
|
||||||
|
clientDistribute = MQTT.NewClient(opts)
|
||||||
|
token := clientDistribute.Connect()
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
clientDistribute = nil
|
||||||
|
return nil, token.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientDistribute, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅,当事件为nil时可获取client
|
||||||
|
func Subscribe(connHandler MQTT.OnConnectHandler, lostHandler MQTT.ConnectionLostHandler) error {
|
||||||
|
if connHandler == nil {
|
||||||
|
return errors.New("handler is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := Options()
|
||||||
|
opts.OnConnect = connHandler //当连接成功后调用注册
|
||||||
|
if lostHandler != nil {
|
||||||
|
opts.OnConnectionLost = lostHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
if clientSubscribe == nil {
|
||||||
|
clientSubscribe = MQTT.NewClient(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := clientSubscribe.Connect()
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
clientSubscribe = nil
|
||||||
|
return token.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消订阅
|
||||||
|
func UnSubscribe(topic string) {
|
||||||
|
if clientSubscribe == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c := clientSubscribe
|
||||||
|
c.Unsubscribe(topic)
|
||||||
|
c.Disconnect(250)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分发
|
||||||
|
func Distribute(topic *string, qos int, retained bool, payload *[]byte) error {
|
||||||
|
c, err := New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := c.Publish(*topic, byte(qos), retained, *payload)
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
return token.Error()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分发Object
|
||||||
|
func DistributeObject(topic *string, qos int, retained bool, obj interface{}) error {
|
||||||
|
payload, err := json.Marshal(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return Distribute(topic, qos, retained, &payload)
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
"gorm.io/plugin/dbresolver"
|
"gorm.io/plugin/dbresolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,35 +21,58 @@ type Config struct {
|
||||||
ConnMaxLifetime int64 //ConnMaxLifetime 最大连接时间,单位:小时
|
ConnMaxLifetime int64 //ConnMaxLifetime 最大连接时间,单位:小时
|
||||||
MaxIdleConns int
|
MaxIdleConns int
|
||||||
MaxOpenConns int
|
MaxOpenConns int
|
||||||
|
InitTable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//Init mysql初始化
|
// Init mysql初始化
|
||||||
func Init(config *Config) {
|
func Init(config *Config) {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
config = &Config{
|
config = &Config{
|
||||||
ConnString: "root:root@tcp(127.0.0.1:3306)/sample?charset=utf8&parseTime=True&loc=Local",
|
|
||||||
ConnMaxLifetime: 1,
|
|
||||||
MaxIdleConns: 10,
|
MaxIdleConns: 10,
|
||||||
MaxOpenConns: 100,
|
MaxOpenConns: 100,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.ConnString == "" {
|
||||||
|
config.ConnString = "root:root@tcp(127.0.0.1:3306)/mysql?charset=utf8&parseTime=True&loc=Local"
|
||||||
|
}
|
||||||
|
if config.ConnMaxLifetime < 1 {
|
||||||
|
config.ConnMaxLifetime = 1
|
||||||
|
}
|
||||||
|
if config.ConnMaxLifetime > 6 {
|
||||||
|
config.ConnMaxLifetime = 6
|
||||||
|
}
|
||||||
|
if config.MaxIdleConns < 1 {
|
||||||
|
config.MaxIdleConns = 1
|
||||||
|
}
|
||||||
|
if config.MaxIdleConns > 50 {
|
||||||
|
config.MaxIdleConns = 50
|
||||||
|
}
|
||||||
|
if config.MaxOpenConns < 1 {
|
||||||
|
config.MaxOpenConns = 1
|
||||||
|
}
|
||||||
|
if config.MaxOpenConns > 500 {
|
||||||
|
config.MaxOpenConns = 500
|
||||||
|
}
|
||||||
_conf = config
|
_conf = config
|
||||||
}
|
}
|
||||||
|
|
||||||
//New 创建实例
|
// New 创建实例
|
||||||
func New() (*gorm.DB, error) {
|
func New() (*gorm.DB, error) {
|
||||||
if _db != nil {
|
if _db != nil {
|
||||||
return _db, nil
|
return _db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _conf == nil {
|
if _conf == nil {
|
||||||
return nil, errors.New("组件未初始化,请执行Init!")
|
return nil, errors.New("组件未初始化,请执行Init!")
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
_db, err = gorm.Open(mysql.Open(_conf.ConnString), &gorm.Config{
|
_db, err = gorm.Open(mysql.Open(_conf.ConnString), &gorm.Config{
|
||||||
SkipDefaultTransaction: true,
|
SkipDefaultTransaction: true,
|
||||||
Logger: logger.Default.LogMode(logger.Silent),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
SingularTable: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
func InitTable() error {
|
||||||
|
//不初始化表时返回
|
||||||
|
if !_conf.InitTable {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//成功初始化后返回
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
docker配置
|
||||||
|
|
||||||
|
env MYSQL_DSN=root:root@tcp(mysql:3306)/sample?charset=utf8mb4&parseTime=True&loc=Local
|
||||||
|
env MYSQL_MAXLIFETIME=2
|
||||||
|
env MYSQL_MAXIDLECONNS=2
|
||||||
|
env MYSQL_MAXOPENCONNS=200
|
||||||
|
env MYSQL_INIT=true
|
||||||
|
*/
|
||||||
|
var (
|
||||||
|
_db *gorm.DB
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建实例
|
||||||
|
func newDB() (*gorm.DB, error) {
|
||||||
|
if _db != nil {
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dsn := os.Getenv("MYSQL_DSN")
|
||||||
|
if dsn == "" {
|
||||||
|
dsn = "root:root@tcp(127.0.0.1:3306)/mysql?charset=utf8&parseTime=True&loc=Local"
|
||||||
|
}
|
||||||
|
maxLifetime := func() int {
|
||||||
|
c := os.Getenv("MYSQL_MAXLIFETIME")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc <= 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
maxIdleConns := func() int {
|
||||||
|
c := os.Getenv("MYSQL_MAXIDLECONNS")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
maxOpenConns := func() int {
|
||||||
|
c := os.Getenv("MYSQL_MAXOPENCONNS")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
_db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||||
|
SkipDefaultTransaction: true,
|
||||||
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
SingularTable: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_db.Use(
|
||||||
|
dbresolver.Register(dbresolver.Config{
|
||||||
|
Sources: []gorm.Dialector{mysql.Open(dsn)},
|
||||||
|
Replicas: []gorm.Dialector{mysql.Open(dsn)},
|
||||||
|
Policy: dbresolver.RandomPolicy{},
|
||||||
|
}).SetConnMaxIdleTime(time.Hour).
|
||||||
|
SetConnMaxLifetime(time.Duration(maxLifetime) * time.Hour).
|
||||||
|
SetMaxIdleConns(maxIdleConns).
|
||||||
|
SetMaxOpenConns(maxOpenConns))
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
MYSQL_DSN=root:root@tcp(127.0.0.1:3306)/mysql?charset=utf8&parseTime=True&loc=Local
|
||||||
|
MYSQL_MAXLIFETIME=1
|
||||||
|
MYSQL_MAXIDLECONNS=1
|
||||||
|
MYSQL_MAXOPENCONNS=1
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"myschools.me/suguo/intelligent-community/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
//不初始化表时返回
|
||||||
|
if os.Getenv("MYSQL_INIT") != "true" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := newDB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := db.AutoMigrate(&model.User{}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
"gorm.io/plugin/dbresolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_db *gorm.DB
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建实例
|
||||||
|
func newDB() (*gorm.DB, error) {
|
||||||
|
if _db != nil {
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dsn := os.Getenv("POSTGRES_DSN")
|
||||||
|
if dsn == "" {
|
||||||
|
dsn = "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Shanghai"
|
||||||
|
}
|
||||||
|
maxLifetime := func() int {
|
||||||
|
c := os.Getenv("MAXLIFETIME")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc <= 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
maxIdleConns := func() int {
|
||||||
|
c := os.Getenv("MAXIDLECONNS")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
maxOpenConns := func() int {
|
||||||
|
c := os.Getenv("MAXOPENCONNS")
|
||||||
|
cc, err := strconv.Atoi(c)
|
||||||
|
if err != nil {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if cc >= 1000 {
|
||||||
|
cc = 1000
|
||||||
|
}
|
||||||
|
return cc
|
||||||
|
}()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
_db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||||
|
SkipDefaultTransaction: true,
|
||||||
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
SingularTable: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_db.Use(
|
||||||
|
dbresolver.Register(dbresolver.Config{
|
||||||
|
Sources: []gorm.Dialector{postgres.Open(dsn)},
|
||||||
|
Replicas: []gorm.Dialector{postgres.Open(dsn)},
|
||||||
|
Policy: dbresolver.RandomPolicy{},
|
||||||
|
}).SetConnMaxIdleTime(time.Hour).
|
||||||
|
SetConnMaxLifetime(time.Duration(maxLifetime) * time.Hour).
|
||||||
|
SetMaxIdleConns(maxIdleConns).
|
||||||
|
SetMaxOpenConns(maxOpenConns))
|
||||||
|
return _db, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"myschools.me/community/community-api/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if os.Getenv("POSTGRES_INIT") != "true" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := newDB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := db.AutoMigrate(&model.User{}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := db.AutoMigrate(&model.Premises{}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := db.AutoMigrate(&model.Application{}, &model.ApplicationMenu{}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
var pool *redigo.Pool
|
var pool *redigo.Pool
|
||||||
|
|
||||||
//Config 配置
|
// Config 配置
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Host string `yml:"host" json:"host"`
|
Host string `yml:"host" json:"host"`
|
||||||
Password string `yml:"password" json:"password"`
|
Password string `yml:"password" json:"password"`
|
||||||
|
|
@ -19,17 +19,23 @@ type Config struct {
|
||||||
IdleTimeout int `yml:"idle_timeout" json:"idle_timeout"` //second
|
IdleTimeout int `yml:"idle_timeout" json:"idle_timeout"` //second
|
||||||
}
|
}
|
||||||
|
|
||||||
//Init init
|
// Init init
|
||||||
func Init(opts *Config) error {
|
func Init(opts *Config) error {
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = &Config{
|
opts = &Config{}
|
||||||
Host: "127.0.0.1:6379",
|
|
||||||
Password: "",
|
|
||||||
Database: 0,
|
|
||||||
MaxIdle: 10,
|
|
||||||
MaxActive: 100,
|
|
||||||
IdleTimeout: 600,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.Host == "" {
|
||||||
|
opts.Host = "127.0.0.1:6379"
|
||||||
|
}
|
||||||
|
if opts.MaxIdle == 0 {
|
||||||
|
opts.MaxIdle = 1
|
||||||
|
}
|
||||||
|
if opts.MaxActive == 0 {
|
||||||
|
opts.MaxActive = 10
|
||||||
|
}
|
||||||
|
if opts.IdleTimeout == 0 {
|
||||||
|
opts.IdleTimeout = 600
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = &redigo.Pool{
|
pool = &redigo.Pool{
|
||||||
|
|
@ -53,7 +59,7 @@ func Init(opts *Config) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//GetBytes 获取一个字节数组值
|
// GetBytes 获取一个字节数组值
|
||||||
func GetBytes(key *string) (*[]byte, error) {
|
func GetBytes(key *string) (*[]byte, error) {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
@ -62,7 +68,7 @@ func GetBytes(key *string) (*[]byte, error) {
|
||||||
return &data, err
|
return &data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get 获取一个值
|
// Get 获取一个值
|
||||||
func Get(key string) interface{} {
|
func Get(key string) interface{} {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
@ -80,22 +86,64 @@ func Get(key string) interface{} {
|
||||||
return reply
|
return reply
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set 设置一个值
|
// 集合Set增加元素
|
||||||
func Set(key string, val interface{}, timeout time.Duration) (err error) {
|
func SetAdd(key string, data ...interface{}) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
var err error
|
||||||
|
for _, d := range data {
|
||||||
|
_, e := conn.Do("SADD", key, d)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集合Set删除元素
|
||||||
|
func SetRem(key string, data ...interface{}) error {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
var data []byte
|
var err error
|
||||||
if data, err = json.Marshal(val); err != nil {
|
for _, d := range data {
|
||||||
return
|
_, e := conn.Do("SREM", key, d)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Do("SETEX", key, int64(timeout/time.Second), data)
|
return err
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//IsExist 判断key是否存在
|
// 集合Set判断是否存在成员member,结果.(int64)==1表示存在
|
||||||
|
func SetIsMember(key string, member interface{}) (interface{}, error) {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
return conn.Do("SISMEMBER", key, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置一个值
|
||||||
|
func Set(key string, val interface{}, timeout time.Duration) error {
|
||||||
|
data, err := json.Marshal(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return SetBytes(&key, &data, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBytes(key *string, data *[]byte, timeout time.Duration) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
_, err := conn.Do("SETEX", *key, int64(timeout/time.Second), *data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExist 判断key是否存在
|
||||||
func IsExist(key string) bool {
|
func IsExist(key string) bool {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
@ -105,7 +153,7 @@ func IsExist(key string) bool {
|
||||||
return i > 0
|
return i > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//Delete 删除
|
// Delete 删除
|
||||||
func Delete(key string) error {
|
func Delete(key string) error {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
@ -117,7 +165,7 @@ func Delete(key string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Expire 失效时间配置
|
// Expire 失效时间配置
|
||||||
func Expire(key string, t int64) error {
|
func Expire(key string, t int64) error {
|
||||||
conn := pool.Get()
|
conn := pool.Get()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRedis(t *testing.T) {
|
||||||
|
Init(&Config{
|
||||||
|
Host: "192.168.0.254:6379",
|
||||||
|
Password: "",
|
||||||
|
Database: 0,
|
||||||
|
MaxIdle: 3,
|
||||||
|
MaxActive: 10,
|
||||||
|
IdleTimeout: 600,
|
||||||
|
})
|
||||||
|
|
||||||
|
err := SetAdd("aaa", "aaa", "aa1", "aa2", "aa4", "aa3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
Expire("aaa", 100)
|
||||||
|
ret, err := SetIsMember("aaa", "aa1")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(ret, ret.(int64))
|
||||||
|
err = SetRem("aaa", "aa2", "aa3")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = Delete("aaa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
REDIS_DSN=172.17.0.4:6379
|
||||||
|
REDIS_DB=eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
|
||||||
|
REDIS_PWD=1
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
redigo "github.com/gomodule/redigo/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
env REDIS_DSN=127.0.0.1:6379
|
||||||
|
env REDIS_PWD=
|
||||||
|
env REDIS_DB=0
|
||||||
|
*/
|
||||||
|
var pool *redigo.Pool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbNumber := func() int {
|
||||||
|
db := os.Getenv("REDIS_DB")
|
||||||
|
database, err := strconv.Atoi(db)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if database < 0 {
|
||||||
|
database = 0
|
||||||
|
}
|
||||||
|
if database > 16 {
|
||||||
|
database = 0
|
||||||
|
}
|
||||||
|
return database
|
||||||
|
}()
|
||||||
|
pool = &redigo.Pool{
|
||||||
|
MaxActive: 100,
|
||||||
|
MaxIdle: 1,
|
||||||
|
IdleTimeout: time.Second * time.Duration(60),
|
||||||
|
Dial: func() (redigo.Conn, error) {
|
||||||
|
return redigo.Dial("tcp", os.Getenv("REDIS_DSN"),
|
||||||
|
redigo.DialDatabase(dbNumber),
|
||||||
|
redigo.DialPassword(os.Getenv("REDIS_PWD")),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
TestOnBorrow: func(conn redigo.Conn, t time.Time) error {
|
||||||
|
if time.Since(t) < time.Minute {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := conn.Do("PING")
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes 获取一个字节数组值
|
||||||
|
func GetBytes(key *string) (*[]byte, error) {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
data, err := redigo.Bytes(conn.Do("GET", *key))
|
||||||
|
return &data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取一个值
|
||||||
|
func Get(key string) interface{} {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
if data, err = redigo.Bytes(conn.Do("GET", key)); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var reply interface{}
|
||||||
|
if err = json.Unmarshal(data, &reply); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集合Set增加元素
|
||||||
|
func SetAdd(key string, data ...interface{}) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
var err error
|
||||||
|
for _, d := range data {
|
||||||
|
_, e := conn.Do("SADD", key, d)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集合Set删除元素
|
||||||
|
func SetRem(key string, data ...interface{}) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _, d := range data {
|
||||||
|
_, e := conn.Do("SREM", key, d)
|
||||||
|
if e != nil {
|
||||||
|
err = e
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集合Set判断是否存在成员member,结果.(int64)==1表示存在
|
||||||
|
func SetIsMember(key string, member interface{}) (interface{}, error) {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
return conn.Do("SISMEMBER", key, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置一个值
|
||||||
|
func Set(key string, val interface{}, timeout time.Duration) error {
|
||||||
|
data, err := json.Marshal(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return SetBytes(&key, &data, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBytes(key *string, data *[]byte, timeout time.Duration) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
_, err := conn.Do("SETEX", *key, int64(timeout/time.Second), *data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExist 判断key是否存在
|
||||||
|
func IsExist(key string) bool {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
a, _ := conn.Do("EXISTS", key)
|
||||||
|
i := a.(int64)
|
||||||
|
return i > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除
|
||||||
|
func Delete(key string) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if _, err := conn.Do("DEL", key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expire 失效时间配置
|
||||||
|
func Expire(key string, t int64) error {
|
||||||
|
conn := pool.Get()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if _, err := conn.Do("expire", key, t); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"myschools.me/suguo/intelligent-community/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 存储用户的Token
|
||||||
|
func UserTokenSet(key *string, usr *model.User) error {
|
||||||
|
|
||||||
|
err := Set(*key, usr, 7210*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"func": "UserTokenSet",
|
||||||
|
}).Warnf("Set: %s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从redis中获取用户信息,最佳实践经验建议把此代码放service层
|
||||||
|
func UserTokenGet(token *string) (*model.User, error) {
|
||||||
|
b, err := GetBytes(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if b == nil {
|
||||||
|
return nil, errors.New("无效token,请重新登录!")
|
||||||
|
}
|
||||||
|
|
||||||
|
var user *model.User
|
||||||
|
if err := json.Unmarshal(*b, user); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
health "myschools.me/wodeschool/ws-base/health"
|
|
||||||
)
|
|
||||||
|
|
||||||
//Server consul心跳处理
|
|
||||||
type Health struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check 实现微服务接口
|
|
||||||
func (h *Health) Check(ctx context.Context, req *health.HealthCheckRequest) (*health.HealthCheckResponse, error) {
|
|
||||||
resp := &health.HealthCheckResponse{
|
|
||||||
Status: health.HealthCheckResponse_SERVING,
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//Watch 实现微服务接口stream
|
|
||||||
func (h *Health) Watch(req *health.HealthCheckRequest, out health.Health_WatchServer) error {
|
|
||||||
out.Send(&health.HealthCheckResponse{
|
|
||||||
Status: health.HealthCheckResponse_SERVING,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
MQTT "github.com/eclipse/paho.mqtt.golang"
|
||||||
|
"myschools.me/suguo/snippet/mosquitto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSubscribe(t *testing.T) {
|
||||||
|
mosquitto.Init(&mosquitto.Config{})
|
||||||
|
if err := mosquitto.Subscribe(connHandler, connLostHandler); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
topic := "xtj/aaaa"
|
||||||
|
payload := []byte("sadfdsaf")
|
||||||
|
mosquitto.Distribute(&topic, 0, false, &payload)
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
var connHandler MQTT.OnConnectHandler = func(client MQTT.Client) {
|
||||||
|
token := client.Subscribe("#", 0, serviceHandler)
|
||||||
|
if token.Wait() && token.Error() != nil {
|
||||||
|
fmt.Println(token.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var connLostHandler MQTT.ConnectionLostHandler = func(client MQTT.Client, err error) {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
//具体业务订阅的处理,此处为示例
|
||||||
|
var serviceHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
|
||||||
|
fmt.Println(msg.Topic())
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"myschools.me/suguo/snippet/sqlite"
|
"myschools.me/suguo/snippet/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -22,22 +23,17 @@ type CBA struct {
|
||||||
|
|
||||||
func TestSqlite(t *testing.T) {
|
func TestSqlite(t *testing.T) {
|
||||||
conf := &sqlite.Config{
|
conf := &sqlite.Config{
|
||||||
DBFile: "tmp1/abc/aaaaa/abc.db",
|
DBFile: "tmp/abc.db",
|
||||||
}
|
}
|
||||||
if err := sqlite.Init(conf); err != nil {
|
if err := sqlite.Init(conf); err != nil {
|
||||||
t.Fatal(err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
db, err := sqlite.New()
|
db, err := sqlite.New()
|
||||||
if err != nil {
|
assert.Nil(t, err)
|
||||||
t.Fatal(err)
|
assert.NotNil(t, db)
|
||||||
}
|
|
||||||
|
|
||||||
if db == nil {
|
|
||||||
t.Error("DB nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sqlite.Migrate(&ABC{}, &CBA{}); err != nil {
|
if err := sqlite.Migrate(&ABC{}, &CBA{}); err != nil {
|
||||||
t.Fatal(err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue