在Alibaba Cloud Linux上安装MongoDB

安装步骤 查询系统版本 执行命令lsb_release -a返回下面的内容 LSB Version: :core-4.1-amd64:core-4.1-noarch Distributor ID: AlibabaCloud Description: Alibaba Cloud Linux release 3 (Soaring Falcon) Release: 3 Codename: SoaringFalcon 添加yum源 创建repo文件etc/yum.repos.d/mongodb.repo并输入下面的内容,这里安装的mongodb版本为6.0,其他版本请参考官网 (配置偶数版本,奇数版不适合生产使用)。 官网的配置文件如下: [mongodb-org-6.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/6.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc 使用这个配置文件是安装不了的,需要修改$releasever为相应的版本,Alibaba Cloud Linux 3修改为8 (设置一个releasever的环境变量也许也可以,没有验证。)即可。即下面的样子 [mongodb-org-6.0] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/8/mongodb-org/6.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc 使用命令 yum -y install mongodb-org 安装即可。另外阿里云也提供了国内的镜像源,上面的配置文件可以修改为下面的内容,也是等效的。 [mongodb-org-6.0] name=MongoDB Repository baseurl=http://mirrors.aliyun.com/mongodb/yum/redhat/8/mongodb-org/6.0/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc 参考链接 如何在Alibaba Cloud Linux 3上安装MongoDB 5.0

2022-08-30 · 1 分钟 · czyt

golang http客户端使用自定义dns

摘自互联网 原文 package main import ( "context" "io/ioutil" "log" "net" "net/http" "time" ) func main() { var ( dnsResolverIP = "8.8.8.8:53" // Google DNS resolver. dnsResolverProto = "udp" // Protocol to use for the DNS resolver dnsResolverTimeoutMs = 5000 // Timeout (ms) for the DNS resolver (optional) ) dialer := &net.Dialer{ Resolver: &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Duration(dnsResolverTimeoutMs) * time.Millisecond, } return d.DialContext(ctx, dnsResolverProto, dnsResolverIP) }, }, } dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.DialContext(ctx, network, addr) } http.DefaultTransport.(*http.Transport).DialContext = dialContext httpClient := &http.Client{} // Testing the new HTTP client with the custom DNS resolver. resp, err := httpClient.Get("https://www.violetnorth.com") if err != nil { log.Fatalln(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } log.Println(string(body))

2022-08-22 · 1 分钟 · czyt

go-kratos使用备忘

我搭建的一个kratos项目模板,欢迎使用,仓库地址 需要特别注意的一些建议 API路由覆盖的问题 比如有两个接口 A get /v1/user/{user_id}和 B get /v1/user/profile如果A定义在B之前,那么B可能会被A覆盖路由。需要将A放到B之前。 JWT使用的建议 摘自极客时间课程《高并发系统实战课》 通讯过程必须使用 HTTPS 协议,这样才可以降低被拦截的可能。 要注意限制 token 的更换次数,并定期刷新 token,比如用户的 access_token 每天只能更换 50 次,超过了就要求用户重新登陆,同时 token 每隔 15 分钟更换一次。这样可以降低 token 被盗取后给用户带来的影响。 Web 用户的 token 保存在 cookie 中时,建议加上 httponly、SameSite=Strict 限制,以防止 cookie 被一些特殊脚本偷走。 配置文件 配置文件校验 配合buf的validate可以方便地进行配置文件的校验,在程序启动之前就对配置文件进行一次校验。下面是一个简单的proto配置定义 syntax = "proto3"; package conf; import "buf/validate/validate.proto"; import "google/protobuf/duration.proto"; option go_package = "github.com/tpl-x/kratos/internal/conf;conf"; message Bootstrap { Server server = 1; Data data = 2; Log log = 3; } message Server { message HTTP { string network = 1; string addr = 2; google.protobuf.Duration timeout = 3 [ // the field is required (buf.validate.field).required = true, // duration must be longer than 1 second but no longer than 10 min. (buf.validate.field).duration = { // Validates that duration is greater than 1 second gt: {seconds: 1} // Validates that duration is less than or equal to 10 min. lte: {seconds: 600} } ]; } message GRPC { string network = 1; string addr = 2; google.protobuf.Duration timeout = 3 [ // the field is required (buf.validate.field).required = true, // duration must be longer than 1 second but no longer than 10 min. (buf.validate.field).duration = { // Validates that duration is greater than 1 second gt: {seconds: 1} // Validates that duration is less than or equal to 10 min. lte: {seconds: 600} } ]; } HTTP http = 1; GRPC grpc = 2; } message Data { message Database { string driver = 1; string source = 2; } message Redis { string network = 1; string addr = 2; google.protobuf.Duration read_timeout = 3; google.protobuf.Duration write_timeout = 4; } Database database = 1; Redis redis = 2; } enum LogLevel { Debug = 0; Info = 1; Warn = 2; Error = 3; Fatal = 4; } message Log { string log_path = 1; LogLevel log_level = 2 [(buf.validate.field).enum = { defined_only: true in: [ 0, 1, 2, 3, 4 ] }]; int32 max_size = 3; int32 max_keep_days = 4; int32 max_keep_files = 5; bool compress = 6; } 生成proto对应的go文件中以后,就可以通过下面的方式进行校验: ...

2022-08-12 · 36 分钟 · czyt

golang转换任意长度[] byte为int

package main import ( "encoding/binary" "fmt" ) func main() { slices := [][]byte{ {1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6, 7}, {1, 2, 3, 4, 5, 6, 7, 8}, } for _, s := range slices { fmt.Println(getInt1(s), getInt2(s)) } } func getInt1(s []byte) int { var b [8]byte copy(b[8-len(s):], s) return int(binary.BigEndian.Uint64(b[:])) } func getInt2(s []byte) int { var res int for _, v := range s { res <<= 8 res |= int(v) } return res } 参考 ● https://www.reddit.com/r/golang/comments/4xn341/converting_byte_to_int32/ ● https://forum.golangbridge.org/t/converting-single-byte-slice-to-int

2022-07-30 · 1 分钟 · czyt

Protobuf golang小札

Oneof 如果您有许多字段的消息,并且最多可以同时设置一个字段,则可以使用Oneof功能来执行此行为并保存内存。一个字段就像常规字段一样,除了单一共享内存中的所有字段,最多可以同时设置一个字段。设置Oneof的任何成员都会自动清除所有其他成员。 ​ Google protobuf 文档#Oneof 示例proto 创建protoOneof.proto 的proto文件 syntax = "proto3"; package oneof_test; option go_package ='.;oneof'; message WeiboUser{ string user_id = 1; string user_nick = 2; } message DouyinUser{ string auth_token = 1; string nick_name = 2; } message User{ oneof user_source{ string weibo_url = 1; string douyin_url = 2; } oneof user_info{ WeiboUser weibo_user_info = 3; DouyinUser douyin_user_info = 4; } } 使用命令生成go代码 protoc --proto_path=. --go_out=paths=source_relative:./oneof ./protoOneof.proto 生成的protoOneof.pb.go代码如下: // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 // protoc v3.21.3 // source: protoOneof.proto package oneof import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type WeiboUser struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` UserNick string `protobuf:"bytes,2,opt,name=user_nick,json=userNick,proto3" json:"user_nick,omitempty"` } func (x *WeiboUser) Reset() { *x = WeiboUser{} if protoimpl.UnsafeEnabled { mi := &file_protoOneof_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *WeiboUser) String() string { return protoimpl.X.MessageStringOf(x) } func (*WeiboUser) ProtoMessage() {} func (x *WeiboUser) ProtoReflect() protoreflect.Message { mi := &file_protoOneof_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use WeiboUser.ProtoReflect.Descriptor instead. func (*WeiboUser) Descriptor() ([]byte, []int) { return file_protoOneof_proto_rawDescGZIP(), []int{0} } func (x *WeiboUser) GetUserId() string { if x != nil { return x.UserId } return "" } func (x *WeiboUser) GetUserNick() string { if x != nil { return x.UserNick } return "" } type DouyinUser struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields AuthToken string `protobuf:"bytes,1,opt,name=auth_token,json=authToken,proto3" json:"auth_token,omitempty"` NickName string `protobuf:"bytes,2,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` } func (x *DouyinUser) Reset() { *x = DouyinUser{} if protoimpl.UnsafeEnabled { mi := &file_protoOneof_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *DouyinUser) String() string { return protoimpl.X.MessageStringOf(x) } func (*DouyinUser) ProtoMessage() {} func (x *DouyinUser) ProtoReflect() protoreflect.Message { mi := &file_protoOneof_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use DouyinUser.ProtoReflect.Descriptor instead. func (*DouyinUser) Descriptor() ([]byte, []int) { return file_protoOneof_proto_rawDescGZIP(), []int{1} } func (x *DouyinUser) GetAuthToken() string { if x != nil { return x.AuthToken } return "" } func (x *DouyinUser) GetNickName() string { if x != nil { return x.NickName } return "" } type User struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Types that are assignable to UserSource: // *User_WeiboUrl // *User_DouyinUrl UserSource isUser_UserSource `protobuf_oneof:"user_source"` // Types that are assignable to UserInfo: // *User_WeiboUserInfo // *User_DouyinUserInfo UserInfo isUser_UserInfo `protobuf_oneof:"user_info"` } func (x *User) Reset() { *x = User{} if protoimpl.UnsafeEnabled { mi := &file_protoOneof_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *User) String() string { return protoimpl.X.MessageStringOf(x) } func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { mi := &file_protoOneof_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { return file_protoOneof_proto_rawDescGZIP(), []int{2} } func (m *User) GetUserSource() isUser_UserSource { if m != nil { return m.UserSource } return nil } func (x *User) GetWeiboUrl() string { if x, ok := x.GetUserSource().(*User_WeiboUrl); ok { return x.WeiboUrl } return "" } func (x *User) GetDouyinUrl() string { if x, ok := x.GetUserSource().(*User_DouyinUrl); ok { return x.DouyinUrl } return "" } func (m *User) GetUserInfo() isUser_UserInfo { if m != nil { return m.UserInfo } return nil } func (x *User) GetWeiboUserInfo() *WeiboUser { if x, ok := x.GetUserInfo().(*User_WeiboUserInfo); ok { return x.WeiboUserInfo } return nil } func (x *User) GetDouyinUserInfo() *DouyinUser { if x, ok := x.GetUserInfo().(*User_DouyinUserInfo); ok { return x.DouyinUserInfo } return nil } type isUser_UserSource interface { isUser_UserSource() } type User_WeiboUrl struct { WeiboUrl string `protobuf:"bytes,1,opt,name=weibo_url,json=weiboUrl,proto3,oneof"` } type User_DouyinUrl struct { DouyinUrl string `protobuf:"bytes,2,opt,name=douyin_url,json=douyinUrl,proto3,oneof"` } func (*User_WeiboUrl) isUser_UserSource() {} func (*User_DouyinUrl) isUser_UserSource() {} type isUser_UserInfo interface { isUser_UserInfo() } type User_WeiboUserInfo struct { WeiboUserInfo *WeiboUser `protobuf:"bytes,3,opt,name=weibo_user_info,json=weiboUserInfo,proto3,oneof"` } type User_DouyinUserInfo struct { DouyinUserInfo *DouyinUser `protobuf:"bytes,4,opt,name=douyin_user_info,json=douyinUserInfo,proto3,oneof"` } func (*User_WeiboUserInfo) isUser_UserInfo() {} func (*User_DouyinUserInfo) isUser_UserInfo() {} var File_protoOneof_proto protoreflect.FileDescriptor var file_protoOneof_proto_rawDesc = []byte{ 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x4f, 0x6e, 0x65, 0x6f, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x22, 0x41, 0x0a, 0x09, 0x57, 0x65, 0x69, 0x62, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x69, 0x63, 0x6b, 0x22, 0x48, 0x0a, 0x0a, 0x44, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xe7, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x09, 0x77, 0x65, 0x69, 0x62, 0x6f, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x77, 0x65, 0x69, 0x62, 0x6f, 0x55, 0x72, 0x6c, 0x12, 0x1f, 0x0a, 0x0a, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x3f, 0x0a, 0x0f, 0x77, 0x65, 0x69, 0x62, 0x6f, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x65, 0x69, 0x62, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x48, 0x01, 0x52, 0x0d, 0x77, 0x65, 0x69, 0x62, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x0a, 0x10, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x44, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x48, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x75, 0x79, 0x69, 0x6e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x0d, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_protoOneof_proto_rawDescOnce sync.Once file_protoOneof_proto_rawDescData = file_protoOneof_proto_rawDesc ) func file_protoOneof_proto_rawDescGZIP() []byte { file_protoOneof_proto_rawDescOnce.Do(func() { file_protoOneof_proto_rawDescData = protoimpl.X.CompressGZIP(file_protoOneof_proto_rawDescData) }) return file_protoOneof_proto_rawDescData } var file_protoOneof_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_protoOneof_proto_goTypes = []interface{}{ (*WeiboUser)(nil), // 0: oneof_test.WeiboUser (*DouyinUser)(nil), // 1: oneof_test.DouyinUser (*User)(nil), // 2: oneof_test.User } var file_protoOneof_proto_depIdxs = []int32{ 0, // 0: oneof_test.User.weibo_user_info:type_name -> oneof_test.WeiboUser 1, // 1: oneof_test.User.douyin_user_info:type_name -> oneof_test.DouyinUser 2, // [2:2] is the sub-list for method output_type 2, // [2:2] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name } func init() { file_protoOneof_proto_init() } func file_protoOneof_proto_init() { if File_protoOneof_proto != nil { return } if !protoimpl.UnsafeEnabled { file_protoOneof_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WeiboUser); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_protoOneof_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DouyinUser); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_protoOneof_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*User); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } file_protoOneof_proto_msgTypes[2].OneofWrappers = []interface{}{ (*User_WeiboUrl)(nil), (*User_DouyinUrl)(nil), (*User_WeiboUserInfo)(nil), (*User_DouyinUserInfo)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_protoOneof_proto_rawDesc, NumEnums: 0, NumMessages: 3, NumExtensions: 0, NumServices: 0, }, GoTypes: file_protoOneof_proto_goTypes, DependencyIndexes: file_protoOneof_proto_depIdxs, MessageInfos: file_protoOneof_proto_msgTypes, }.Build() File_protoOneof_proto = out.File file_protoOneof_proto_rawDesc = nil file_protoOneof_proto_goTypes = nil file_protoOneof_proto_depIdxs = nil } 测试代码: ...

2022-07-25 · 12 分钟 · czyt

使用gotests生成表驱动测试

使用gotests可以很方便的生成表驱动测试代码,表驱动测试的具体内容,请参考go官方的wiki 。下面是具体的使用方法。 安装 使用下面命令进行安装 go install github.com/cweill/gotests/gotests@latest 如果是go1.16之前的版本,可以使用命令 go get -u github.com/cweill/gotests/...来进行安装。 使用 gotests支持的参数如下: Usage of C:\Users\czyt\go\bin\gotests.exe: -all generate tests for all functions and methods -excl string regexp. generate tests for functions and methods that don't match. Takes precedence over -only, -exported, and -all -exported generate tests for exported functions and methods. Takes precedence over -only and -all -i print test inputs in error messages -nosubtests disable generating tests using the Go 1.7 subtests feature -only string regexp. generate tests for functions and methods that match only. Takes precedence over -all -parallel enable generating parallel subtests -template string optional. Specify custom test code templates, e.g. testify. This can also be set via environment variable GOTESTS_TEMPLATE -template_dir string optional. Path to a directory containing custom test code templates. Takes precedence over -template. This can also be set via environment variable GOTESTS_TEMPLATE_DIR -template_params string read external parameters to template by json with stdin -template_params_file string read external parameters to template by json with file -w write output to (test) files instead of stdout 小试牛刀 新建一个go文件,命名为greeter.go ...

2022-07-22 · 2 分钟 · czyt

ETCD一键安装脚本

最近要使用ETCD,脚本根据官方GitHub脚本修改而来 #!/usr/bin/bash ETCD_VER=v3.5.4 # choose either URL GOOGLE_URL=https://storage.googleapis.com/etcd GITHUB_URL=https://fastgit.czyt.tech/https://github.com/etcd-io/etcd/releases/download ARCH=linux-arm64 DOWNLOAD_URL=${GITHUB_URL} INSTALL_DIR=/opt/etcd rm -f /tmp/etcd-${ETCD_VER}-${ARCH}.tar.gz rm -rf ${INSTALL_DIR} && mkdir -p ${INSTALL_DIR} curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-${ARCH}.tar.gz -o /tmp/etcd-${ETCD_VER}-${ARCH}.tar.gz tar xzvf /tmp/etcd-${ETCD_VER}-${ARCH}.tar.gz -C ${INSTALL_DIR} --strip-components=1 rm -f /tmp/etcd-${ETCD_VER}-${ARCH}.tar.gz ${INSTALL_DIR}/etcd --version ${INSTALL_DIR}/etcdctl version ${INSTALL_DIR}/etcdutl version 其中的ARCH请根据实际情况修改。 参考 https://etcd.io/docs/v3.5/demo/

2022-07-21 · 1 分钟 · czyt

Golang Expr不完全指南

安装 库的说明 Expr package provides an engine that can compile and evaluate expressions. An expression is a one-liner that returns a value (mostly, but not limited to, booleans). It is designed for simplicity, speed and safety. The purpose of the package is to allow users to use expressions inside configuration for more complex logic. It is a perfect candidate for the foundation of a business rule engine. 安装 go get -u github.com/antonmedv/expr 新版已经变为组织,官网为 https://expr-lang.org 对应的仓库变为 github.com/expr-lang/expr ...

2022-07-13 · 9 分钟 · czyt

Golang DSL参考

ANTLR 4 图书 The definitive ANTLR 4 reference (2014) 英文版下载 中文版下载 文章 使用ANTLR和Go实现DSL入门 手把手教你使用ANTLR和Go实现一门DSL语言part1 part2 part3 part4 part5 Parsing with ANTLR 4 and Go 实例代码 bilibili gengine link go-zero link grule-rule-engine https://github.com/kulics-works/feel-go monkey.go windows 环境配置 配置好Java环境,然后将下面的批处理加入系统环境变量: antlr.cmd @echo off java -classpath %~dp0antlr-4.12.0-complete.jar org.antlr.v4.Tool %* grun.cmd @echo off java -classpath %~dp0antlr-4.12.0-complete.jar org.antlr.v4.gui.TestRig %* Others 图书 Writing A Compiler In Go Writing an Interpreter in Go µGo语言实现——从头开发一个迷你Go语言编译器 文章 Build your own DSL with Go & HCL ...

2022-07-11 · 1 分钟 · czyt

Vue 相关资源

Vue - The Complete Guide (incl. Router & Composition API) The Vue.js 3 Masterclass TypeScript Friendly Vue 3 Vue.js Fundamentals

2022-06-30 · 1 分钟 · czyt