├── LICENSE ├── README.md ├── README_zh.md ├── adm ├── handle.go ├── processor.go ├── service.go └── util.go ├── amr ├── account.go ├── amr.go ├── block.go ├── csaccess.go ├── etcdamr.go ├── raftxamr.go ├── redisamr.go ├── token.go ├── util.go ├── vnode.go └── zkamr.go ├── branch ├── branch.go └── util.go ├── cache ├── account.go ├── auth.go ├── block.go ├── cache.go ├── csaccess.go └── token.go ├── dao ├── timblock.go ├── timblockroom.go ├── timdomain.go ├── timgroup.go ├── timmessage.go ├── timmucroster.go ├── timoffline.go ├── timrelate.go ├── timroster.go ├── timuser.go └── util.go ├── data ├── cdhandle.go ├── cdutil.go ├── exbranch.go ├── exdb.go ├── exhandle.go ├── gdao.go ├── inhandle.go ├── inutil.go ├── mnhandle.go ├── nohandle.go ├── service.go ├── tldbbranch.go ├── tldbdao.go ├── tldbhandle.go ├── tldbutil.go └── util.go ├── errs └── err.go ├── go.mod ├── inet ├── inet.go └── util.go ├── keystore ├── admin.go └── ks.go ├── log └── log.go ├── mesh ├── handler.go ├── itnetserv.go ├── merge2.go ├── node.go ├── process.go ├── tnet.go ├── tserver2.go └── util.go ├── mq └── mq.go ├── service ├── branch.go ├── processor.go ├── service.go ├── sock.go └── util.go ├── stub ├── adm.go ├── bean.go ├── cs.go ├── stub.go └── stub_test.go ├── sys ├── const.go ├── flag.go ├── sys.go ├── timEg.go └── var.go ├── tc ├── adm.go ├── admin.go ├── admsock.go ├── bean.go ├── bootstrap.go ├── debug.go ├── monitor.go ├── opHandler.go ├── processor.go ├── templ.go ├── templ_en.go ├── templ_zh.go └── util.go ├── tim.go ├── tim_test.go ├── trans ├── itnet.go ├── processor.go ├── route.go ├── trans.go ├── transware.go └── tservice.go ├── util ├── util.go └── util_test.go └── vgate └── vgate.go /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2023 donnie4w 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /adm/service.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of t source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package adm 9 | 10 | import ( 11 | "context" 12 | "crypto/tls" 13 | "errors" 14 | "fmt" 15 | "github.com/donnie4w/tim/log" 16 | "github.com/donnie4w/tim/stub" 17 | "os" 18 | "strings" 19 | "sync" 20 | "time" 21 | 22 | goutil "github.com/donnie4w/gofer/util" 23 | "github.com/donnie4w/gothrift/thrift" 24 | "github.com/donnie4w/tim/sys" 25 | "github.com/donnie4w/tim/util" 26 | ) 27 | 28 | func init() { 29 | sys.Service(sys.INIT_ADM, new(service)) 30 | } 31 | 32 | var transportFactory = thrift.NewTBufferedTransportFactory(1 << 13) 33 | var tcompactProtocolFactory = thrift.NewTCompactProtocolFactoryConf(&thrift.TConfiguration{}) 34 | var socketTimeout = 10 * time.Second 35 | 36 | type service struct { 37 | isClose bool 38 | serverTransport thrift.TServerTransport 39 | } 40 | 41 | func (t *service) _server(addr string, processor thrift.TProcessor, TLS bool, serverCrt, serverKey string) (err error) { 42 | if addr, err = util.ParseAddr(addr); err != nil { 43 | log.FmtPrint("Server API Service ParseAddr error:", err.Error()) 44 | os.Exit(1) 45 | } 46 | 47 | if TLS { 48 | cfg := &tls.Config{} 49 | var cert tls.Certificate 50 | if cert, err = tls.LoadX509KeyPair(serverCrt, serverKey); err == nil { 51 | cfg.Certificates = append(cfg.Certificates, cert) 52 | t.serverTransport, err = thrift.NewTSSLServerSocketTimeout(addr, cfg, socketTimeout) 53 | } 54 | } else { 55 | t.serverTransport, err = thrift.NewTServerSocketTimeout(addr, socketTimeout) 56 | } 57 | 58 | if err == nil && t.serverTransport != nil { 59 | server := thrift.NewTSimpleServer4(processor, t.serverTransport, nil, nil) 60 | if err = server.Listen(); err == nil { 61 | s := fmt.Sprint("Server API Service start[", addr, "]") 62 | if TLS { 63 | s = fmt.Sprint("Server API Service start tls[", addr, "]") 64 | } 65 | log.FmtPrint(s) 66 | for { 67 | if _transport, err := server.ServerTransport().Accept(); err == nil { 68 | go func() { 69 | defer util.Recover() 70 | cc := newCliContext(_transport) 71 | defer cc.close() 72 | defaultCtx := context.WithValue(context.Background(), "CliContext", cc) 73 | if inputTransport, err := transportFactory.GetTransport(_transport); err == nil { 74 | inputProtocol := tcompactProtocolFactory.GetProtocol(inputTransport) 75 | for { 76 | ok, err := processor.Process(defaultCtx, inputProtocol, inputProtocol) 77 | if errors.Is(err, thrift.ErrAbandonRequest) { 78 | break 79 | } 80 | if errors.As(err, new(thrift.TTransportException)) && err != nil { 81 | break 82 | } 83 | if !ok { 84 | break 85 | } 86 | } 87 | } 88 | }() 89 | } 90 | } 91 | } 92 | } 93 | if !t.isClose && err != nil { 94 | fmt.Println("Server API Service start failed:", err) 95 | os.Exit(1) 96 | } 97 | return 98 | } 99 | 100 | func (t *service) Close() (err error) { 101 | defer util.Recover() 102 | if sys.Conf.AdmListen != nil { 103 | t.isClose = true 104 | err = t.serverTransport.Close() 105 | } 106 | return 107 | } 108 | 109 | func (t *service) Serve() (err error) { 110 | if sys.Conf.AdmListen != nil { 111 | tls := false 112 | if sys.Conf.Ssl_crt != "" && sys.Conf.Ssl_crt_key != "" { 113 | tls = true 114 | } 115 | go t._server(strings.TrimSpace(*sys.Conf.AdmListen), stub.NewAdmifaceProcessor(admProcessor), tls, sys.Conf.Ssl_crt, sys.Conf.Ssl_crt_key) 116 | } else { 117 | log.FmtPrint("No Server API Service") 118 | } 119 | return 120 | } 121 | 122 | type pcontext struct { 123 | Id int64 124 | isAuth bool 125 | tt thrift.TTransport 126 | mux *sync.Mutex 127 | _isClose bool 128 | } 129 | 130 | func newCliContext(tt thrift.TTransport) (cc *pcontext) { 131 | cc = &pcontext{goutil.UUID64(), false, tt, &sync.Mutex{}, false} 132 | return 133 | } 134 | 135 | func (t *pcontext) close() { 136 | defer util.Recover() 137 | t.mux.Lock() 138 | defer t.mux.Unlock() 139 | if !t._isClose { 140 | t._isClose = true 141 | t.tt.Close() 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /adm/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of t source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package adm 9 | 10 | import ( 11 | "context" 12 | "github.com/donnie4w/tim/data" 13 | "github.com/donnie4w/tim/errs" 14 | "github.com/donnie4w/tim/stub" 15 | "github.com/donnie4w/tim/sys" 16 | "strings" 17 | 18 | goutil "github.com/donnie4w/gofer/util" 19 | "github.com/donnie4w/tim/keystore" 20 | ) 21 | 22 | func ctx2CliContext(ctx context.Context) *pcontext { 23 | return ctx.Value("CliContext").(*pcontext) 24 | } 25 | 26 | func auth(name, pwd, domain string) (b bool) { 27 | if sys.Conf.UseTimDomain { 28 | return data.Service.TimAdminAuth(name, pwd, domain) 29 | } else if _r, ok := keystore.Admin.GetAdmin(name); ok { 30 | b = strings.EqualFold(_r.Pwd, goutil.Md5Str(pwd)) 31 | } 32 | return 33 | } 34 | 35 | func noAuthAndClose(cc *pcontext) (err errs.ERROR) { 36 | if !cc.isAuth { 37 | cc.tt.Close() 38 | return errs.ERR_PERM_DENIED 39 | } 40 | return nil 41 | } 42 | 43 | func newAdmAck(ok bool) *stub.AdmAck { 44 | return &stub.AdmAck{Ok: &ok} 45 | } 46 | 47 | func nodeToTid(node, domain *string) (_r *stub.Tid) { 48 | if node != nil { 49 | _r = &stub.Tid{Node: *node, Domain: domain} 50 | } 51 | return 52 | } 53 | 54 | func admMessageToTimMessage(amb *stub.AdmMessage) *stub.TimMessage { 55 | tm := stub.NewTimMessage() 56 | tm.MsType = amb.MsType 57 | tm.OdType = amb.OdType 58 | tm.ID = amb.ID 59 | tm.Mid = amb.Mid 60 | tm.BnType = amb.BnType 61 | tm.FromTid = nodeToTid(amb.FromNode, amb.Domain) 62 | tm.ToTid = nodeToTid(amb.ToNode, amb.Domain) 63 | tm.RoomTid = nodeToTid(amb.RoomNode, amb.Domain) 64 | tm.DataBinary = amb.DataBinary 65 | tm.DataString = amb.DataString 66 | tm.Udtype = amb.Udtype 67 | tm.Udshow = amb.Udshow 68 | tm.Extend = amb.Extend 69 | tm.Extra = amb.Extra 70 | return tm 71 | } 72 | 73 | func timMessageToAdmMessage(tm *stub.TimMessage) *stub.AdmMessage { 74 | am := stub.NewAdmMessage() 75 | am.MsType = tm.MsType 76 | am.OdType = tm.OdType 77 | am.ID = tm.ID 78 | am.Mid = tm.Mid 79 | am.BnType = tm.BnType 80 | 81 | if tm.FromTid != nil { 82 | am.FromNode = &tm.FromTid.Node 83 | } 84 | 85 | if tm.ToTid != nil { 86 | am.ToNode = &tm.ToTid.Node 87 | } 88 | 89 | if tm.RoomTid != nil { 90 | am.RoomNode = &tm.RoomTid.Node 91 | } 92 | 93 | am.DataBinary = tm.DataBinary 94 | am.DataString = tm.DataString 95 | am.Udtype = tm.Udtype 96 | am.Udshow = tm.Udshow 97 | am.Extend = tm.Extend 98 | am.Extra = tm.Extra 99 | return am 100 | } 101 | 102 | func admPresenceToTimPresence(amp *stub.AdmPresence) *stub.TimPresence { 103 | tp := stub.NewTimPresence() 104 | tp.ID = amp.ID 105 | tp.FromTid = nodeToTid(amp.FromNode, nil) 106 | tp.ToTid = nodeToTid(amp.ToNode, nil) 107 | tp.ToList = amp.ToList 108 | tp.Offline = amp.Offline 109 | tp.Status = amp.Status 110 | tp.Show = amp.Show 111 | tp.Extra = amp.Extra 112 | tp.Extend = amp.Extend 113 | tp.Extra = amp.Extra 114 | return tp 115 | } 116 | 117 | func admUserBeanToTimUserBean(aub *stub.AdmUserBean) *stub.TimUserBean { 118 | ub := stub.NewTimUserBean() 119 | ub.Name = aub.Name 120 | ub.NickName = aub.NickName 121 | ub.Brithday = aub.Brithday 122 | ub.Gender = aub.Gender 123 | ub.Cover = aub.Cover 124 | ub.Area = aub.Area 125 | ub.Createtime = aub.Createtime 126 | ub.PhotoTidAlbum = aub.PhotoTidAlbum 127 | ub.Extend = aub.Extend 128 | ub.Extra = aub.Extra 129 | return ub 130 | } 131 | 132 | func timTidToAdmTid(tid *stub.Tid) *stub.AdmTid { 133 | at := stub.NewAdmTid() 134 | at.Node = tid.Node 135 | at.Domain = tid.Domain 136 | at.Resource = tid.Resource 137 | at.Termtyp = tid.Termtyp 138 | at.Extend = tid.Extend 139 | return at 140 | } 141 | 142 | func admTimRoomToTimRoom(atr *stub.AdmTimRoom) *stub.TimRoomBean { 143 | rb := stub.NewTimRoomBean() 144 | rb.Founder = atr.Founder 145 | rb.Managers = atr.Managers 146 | rb.Cover = atr.Cover 147 | rb.Topic = atr.Topic 148 | rb.Label = atr.Label 149 | rb.Gtype = atr.Gtype 150 | rb.Kind = atr.Kind 151 | rb.Createtime = atr.Createtime 152 | rb.Extend = atr.Extend 153 | rb.Extra = atr.Extra 154 | return rb 155 | } 156 | 157 | func timAckToAdmAck(ta *stub.TimAck) *stub.AdmAck { 158 | if ta != nil { 159 | aa := stub.NewAdmAck() 160 | aa.Ok = &ta.Ok 161 | aa.T = ta.T 162 | aa.T2 = ta.T2 163 | aa.N = ta.N 164 | aa.N2 = ta.N2 165 | if ta.TimType != 0 { 166 | aa.TimType = &ta.TimType 167 | } 168 | if ta.Error != nil { 169 | aa.Errcode = ta.Error.Code 170 | } 171 | return aa 172 | } 173 | return nil 174 | } 175 | -------------------------------------------------------------------------------- /amr/account.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/cache" 13 | "github.com/donnie4w/tim/sys" 14 | ) 15 | 16 | func AddAccount(node string) error { 17 | if islocalamr { 18 | return nil 19 | } 20 | return amr.append(ACCOUNT, util.Int64ToBytes(int64(util.FNVHash64([]byte(node)))), util.Int64ToBytes(sys.UUID), sys.Conf.TTL) 21 | } 22 | 23 | func RemoveAccount(node string) { 24 | if islocalamr { 25 | return 26 | } 27 | amr.removeKV(ACCOUNT, util.Int64ToBytes(int64(util.FNVHash64([]byte(node)))), util.Int64ToBytes(sys.UUID)) 28 | cache.AccountCache.Del(node) 29 | } 30 | 31 | func GetAccount(node string) (r []int64) { 32 | if islocalamr { 33 | return []int64{sys.UUID} 34 | } 35 | if r = cache.AccountCache.Get(node); len(r) > 0 { 36 | return 37 | } 38 | if vs := amr.getMutil(ACCOUNT, util.Int64ToBytes(int64(util.FNVHash64([]byte(node))))); len(vs) > 0 { 39 | if len(vs) > 1 { 40 | r = make([]int64, 0, len(vs)) 41 | m := make(map[int64]bool) 42 | for _, v := range vs { 43 | k := util.BytesToInt64(v) 44 | if _, b := m[k]; !b { 45 | r = append(r, k) 46 | m[k] = true 47 | } 48 | } 49 | } else { 50 | r = []int64{util.BytesToInt64(vs[0])} 51 | } 52 | cache.AccountCache.Put(node, r) 53 | } 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /amr/amr.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/tim/log" 12 | "github.com/donnie4w/tim/sys" 13 | "os" 14 | ) 15 | 16 | type amrStore interface { 17 | put(atype AMRTYPE, key, value []byte, ttl uint64) error 18 | get(atype AMRTYPE, key []byte) ([]byte, error) 19 | remove(atype AMRTYPE, key []byte) error 20 | append(atype AMRTYPE, key, value []byte, ttl uint64) error 21 | getMutil(atype AMRTYPE, key []byte) [][]byte 22 | removeKV(atype AMRTYPE, key, value []byte) error 23 | close() error 24 | } 25 | 26 | var amr amrStore 27 | 28 | type amrservie byte 29 | 30 | func (amrservie) Serve() error { 31 | switch sys.GetCstype() { 32 | case sys.CS_RAFTX: 33 | amr = newRaftxAmr() 34 | case sys.CS_RAX: 35 | log.FmtPrint("unrealized rax") 36 | case sys.CS_REDIS: 37 | amr = newRedisAmr() 38 | case sys.CS_ETCD: 39 | amr = newEtcdAmr() 40 | case sys.CS_ZOOKEEPER: 41 | amr = newZkAmr() 42 | default: 43 | log.FmtPrint("No Cluster Service") 44 | amr = localAmr(1) 45 | islocalamr = true 46 | } 47 | if amr == nil { 48 | log.FmtPrint("amr init failed") 49 | os.Exit(1) 50 | } 51 | return nil 52 | } 53 | 54 | func (amrservie) Close() error { 55 | if amr == nil { 56 | return nil 57 | } 58 | return amr.close() 59 | } 60 | 61 | type localAmr byte 62 | 63 | func (a localAmr) put(atype AMRTYPE, key, value []byte, ttl uint64) error { return nil } 64 | func (a localAmr) get(atype AMRTYPE, key []byte) ([]byte, error) { 65 | return nil, nil 66 | } 67 | func (a localAmr) remove(atype AMRTYPE, key []byte) error { return nil } 68 | 69 | func (a localAmr) append(atype AMRTYPE, key, value []byte, ttl uint64) error { return nil } 70 | 71 | func (a localAmr) getMutil(atype AMRTYPE, key []byte) [][]byte { 72 | return [][]byte{} 73 | } 74 | 75 | func (a localAmr) removeKV(atype AMRTYPE, key, value []byte) error { return nil } 76 | 77 | func (a localAmr) close() error { 78 | return nil 79 | } 80 | -------------------------------------------------------------------------------- /amr/block.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/cache" 13 | ) 14 | 15 | func PutBlock(node string, expried int64) { 16 | if islocalamr { 17 | cache.BlockUserCache.Put(node, expried) 18 | } else { 19 | amr.put(BLOCK, []byte(node), util.Int64ToBytes(expried), uint64(expried)) 20 | } 21 | } 22 | 23 | func GetBlock(node string) int64 { 24 | if islocalamr { 25 | return cache.BlockUserCache.Get(node) 26 | } else { 27 | if bs, _ := amr.get(BLOCK, []byte(node)); len(bs) > 0 { 28 | return util.BytesToInt64(bs) 29 | } 30 | } 31 | return 0 32 | } 33 | 34 | func DelBlock(node string) { 35 | if islocalamr { 36 | cache.BlockUserCache.Del(node) 37 | } else { 38 | amr.remove(BLOCK, []byte(node)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /amr/csaccess.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/cache" 13 | "github.com/donnie4w/tim/sys" 14 | ) 15 | 16 | func GetCsAccess(uuid int64) (r string, err error) { 17 | if r = cache.CsAccessCache.Get(uuid); r != "" { 18 | return 19 | } 20 | if bs, err := amr.get(UUID, util.Int64ToBytes(uuid)); err == nil && len(bs) > 0 { 21 | r = string(bs) 22 | cache.CsAccessCache.Put(uuid, r) 23 | } else { 24 | return r, err 25 | } 26 | return 27 | } 28 | 29 | func PutCsAccess() (err error) { 30 | defer util.Recover(&err) 31 | return amr.put(UUID, util.Int64ToBytes(sys.UUID), []byte(sys.Conf.CsAccess), uint64(sys.UUIDCSTIME)) 32 | } 33 | -------------------------------------------------------------------------------- /amr/etcdamr.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "context" 12 | "crypto/tls" 13 | "crypto/x509" 14 | "github.com/donnie4w/tim/log" 15 | "github.com/donnie4w/tim/sys" 16 | etcd "go.etcd.io/etcd/client/v3" 17 | "os" 18 | "time" 19 | ) 20 | 21 | type etcdAmr struct { 22 | client *etcd.Client 23 | ctx context.Context 24 | } 25 | 26 | func newEtcdAmr() amrStore { 27 | if sys.Conf.Etcd == nil { 28 | log.FmtPrint("Etcd configuration is not initialized") 29 | return nil 30 | } 31 | 32 | cfg := etcd.Config{ 33 | Endpoints: sys.Conf.Etcd.Endpoints, 34 | DialTimeout: time.Second * 5, 35 | } 36 | 37 | if sys.Conf.Etcd.Username != "" && sys.Conf.Etcd.Password != "" { 38 | cfg.Username = sys.Conf.Etcd.Username 39 | cfg.Password = sys.Conf.Etcd.Password 40 | } 41 | 42 | tlsConfig := &tls.Config{} 43 | if sys.Conf.Etcd.CAFile != "" || sys.Conf.Etcd.CertFile != "" || sys.Conf.Etcd.KeyFile != "" { 44 | if sys.Conf.Etcd.CAFile != "" { 45 | caCert, err := os.ReadFile(sys.Conf.Etcd.CAFile) 46 | if err != nil { 47 | log.FmtPrint("etcd:failed to read CA file:", err) 48 | return nil 49 | } 50 | caCertPool := x509.NewCertPool() 51 | if ok := caCertPool.AppendCertsFromPEM(caCert); !ok { 52 | log.FmtPrint("etcd:failed to append CA certs") 53 | return nil 54 | } 55 | tlsConfig.RootCAs = caCertPool 56 | } 57 | 58 | if sys.Conf.Etcd.CertFile != "" && sys.Conf.Etcd.KeyFile != "" { 59 | cert, err := tls.LoadX509KeyPair(sys.Conf.Etcd.CertFile, sys.Conf.Etcd.KeyFile) 60 | if err != nil { 61 | log.FmtPrint("etcd:failed to load client cert and key: ", err) 62 | return nil 63 | } 64 | tlsConfig.Certificates = []tls.Certificate{cert} 65 | } 66 | 67 | tlsConfig.InsecureSkipVerify = false 68 | cfg.TLS = tlsConfig 69 | } 70 | 71 | client, err := etcd.New(cfg) 72 | if err != nil { 73 | log.FmtPrint("failed to connect to etcd:", err) 74 | return nil 75 | } 76 | 77 | if _, err = client.Status(context.Background(), sys.Conf.Etcd.Endpoints[0]); err != nil { 78 | log.FmtPrint("failed to connect to etcd: ", err) 79 | return nil 80 | } 81 | log.FmtPrint("Etcd connection established") 82 | return &etcdAmr{ 83 | client: client, 84 | ctx: context.Background(), 85 | } 86 | } 87 | 88 | func (s *etcdAmr) put(atype AMRTYPE, key, value []byte, ttl uint64) error { 89 | resp, err := s.client.Grant(s.ctx, int64(ttl)) 90 | if err != nil { 91 | return err 92 | } 93 | _, err = s.client.Put(s.ctx, string(amrKey(atype, key)), string(value), etcd.WithLease(resp.ID)) 94 | return err 95 | } 96 | 97 | func (s *etcdAmr) get(atype AMRTYPE, key []byte) ([]byte, error) { 98 | resp, err := s.client.Get(s.ctx, string(amrKey(atype, key))) 99 | if err != nil { 100 | return nil, err 101 | } 102 | if len(resp.Kvs) == 0 { 103 | return nil, nil 104 | } 105 | return resp.Kvs[0].Value, nil 106 | } 107 | 108 | func (s *etcdAmr) remove(atype AMRTYPE, key []byte) error { 109 | _, err := s.client.Delete(s.ctx, string(amrKey(atype, key))) 110 | return err 111 | } 112 | 113 | func (s *etcdAmr) append(atype AMRTYPE, key, value []byte, ttl uint64) error { 114 | setKey := string(amrKey(atype, key)) + "/" + string(value) 115 | var leaseID etcd.LeaseID 116 | if ttl > 0 { 117 | resp, err := s.client.Grant(s.ctx, int64(ttl)) 118 | if err != nil { 119 | return err 120 | } 121 | leaseID = resp.ID 122 | } 123 | _, err := s.client.Put(s.ctx, setKey, "", etcd.WithLease(leaseID)) 124 | return err 125 | } 126 | 127 | func (s *etcdAmr) getMutil(atype AMRTYPE, key []byte) [][]byte { 128 | prefix := string(amrKey(atype, key)) + "/" 129 | resp, err := s.client.Get(s.ctx, prefix, etcd.WithPrefix()) 130 | if err != nil { 131 | return nil 132 | } 133 | results := make([][]byte, 0, len(resp.Kvs)) 134 | for _, kv := range resp.Kvs { 135 | results = append(results, kv.Key[len(prefix):]) 136 | } 137 | return results 138 | } 139 | 140 | func (s *etcdAmr) removeKV(atype AMRTYPE, key, value []byte) error { 141 | setKey := string(amrKey(atype, key)) + "/" + string(value) 142 | _, err := s.client.Delete(s.ctx, setKey) 143 | return err 144 | } 145 | 146 | func (s *etcdAmr) close() error { 147 | return s.client.Close() 148 | } 149 | -------------------------------------------------------------------------------- /amr/raftxamr.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/raftx" 12 | "github.com/donnie4w/raftx/raft" 13 | "github.com/donnie4w/tim/log" 14 | "github.com/donnie4w/tim/sys" 15 | "time" 16 | ) 17 | 18 | type raftxAmr struct { 19 | raft raftx.Raftx 20 | ctime int64 21 | getlocal bool 22 | } 23 | 24 | func newRaftxAmr() amrStore { 25 | if sys.Conf.Raftx == nil || len(sys.Conf.Raftx.Peers) <= 1 { 26 | log.Error("Cluster raftx Service start failed:", "no raftx peers") 27 | return nil 28 | } 29 | rx := raftx.NewRaftx(&raft.Config{ListenAddr: sys.Conf.Raftx.ListenAddr, PeerAddr: sys.Conf.Raftx.Peers}) 30 | if err := rx.Open(); err != nil { 31 | log.Error("Raftx Service start failed:", err) 32 | return nil 33 | } else { 34 | log.FmtPrint("Raftx Service start: [", sys.Conf.Raftx.ListenAddr, "]") 35 | } 36 | log.FmtPrint("Raftx Wait init...") 37 | rx.WaitRun() 38 | return &raftxAmr{raft: rx, ctime: time.Now().UnixNano()} 39 | } 40 | 41 | func (ra *raftxAmr) put(atype AMRTYPE, key, value []byte, ttl uint64) error { 42 | return ra.raft.MemCommand(amrKey(atype, key), value, ttl, raft.MEM_PUT) 43 | } 44 | 45 | func (ra *raftxAmr) get(atype AMRTYPE, key []byte) ([]byte, error) { 46 | return ra.raft.GetMemValue(amrKey(atype, key)) 47 | } 48 | 49 | func (ra *raftxAmr) remove(atype AMRTYPE, key []byte) error { 50 | return ra.raft.MemCommand(amrKey(atype, key), nil, 0, raft.MEM_DEL) 51 | } 52 | 53 | func (ra *raftxAmr) append(atype AMRTYPE, key, value []byte, ttl uint64) error { 54 | return ra.raft.MemCommand(amrKey(atype, key), value, ttl, raft.MEM_APPEND) 55 | } 56 | 57 | func (ra *raftxAmr) getMutil(atype AMRTYPE, key []byte) [][]byte { 58 | key = amrKey(atype, key) 59 | if ra.getlocal { 60 | return ra.raft.GetLocalMemMultiValue(key) 61 | } else { 62 | if ra.ctime+int64(sys.Conf.TTL*1e9) > time.Now().UnixNano() { 63 | v, _ := ra.raft.GetMemMultiValue(key) 64 | return v 65 | } else { 66 | ra.getlocal = true 67 | return ra.raft.GetLocalMemMultiValue(key) 68 | } 69 | } 70 | } 71 | 72 | func (ra *raftxAmr) removeKV(atype AMRTYPE, key, value []byte) error { 73 | return ra.raft.MemCommand(amrKey(atype, key), value, 0, raft.MEM_DELKV) 74 | } 75 | 76 | func (ra *raftxAmr) close() error { 77 | return ra.raft.Stop() 78 | } 79 | -------------------------------------------------------------------------------- /amr/redisamr.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "context" 12 | "errors" 13 | "github.com/donnie4w/tim/log" 14 | "github.com/donnie4w/tim/sys" 15 | "github.com/redis/go-redis/v9" 16 | "time" 17 | ) 18 | 19 | type redisAmr struct { 20 | client redis.Cmdable 21 | ctx context.Context 22 | } 23 | 24 | func newRedisAmr() amrStore { 25 | if sys.Conf.Redis == nil { 26 | log.FmtPrint("Redis configuration is not initialized") 27 | return nil 28 | } 29 | 30 | var client redis.Cmdable 31 | if len(sys.Conf.Redis.Addr) == 1 { 32 | opt := &redis.Options{ 33 | Addr: sys.Conf.Redis.Addr[0], 34 | Username: sys.Conf.Redis.Username, 35 | Password: sys.Conf.Redis.Password, 36 | DB: sys.Conf.Redis.DB, 37 | Protocol: sys.Conf.Redis.Protocol, 38 | } 39 | client = redis.NewClient(opt) 40 | } else { 41 | opt := &redis.ClusterOptions{ 42 | Addrs: sys.Conf.Redis.Addr, 43 | Username: sys.Conf.Redis.Username, 44 | Password: sys.Conf.Redis.Password, 45 | Protocol: sys.Conf.Redis.Protocol, 46 | } 47 | client = redis.NewClusterClient(opt) 48 | } 49 | 50 | if err := client.Ping(context.TODO()).Err(); err != nil { 51 | log.FmtPrint("redis connect fail:", err) 52 | return nil 53 | } 54 | log.FmtPrint("Redis connection established") 55 | return &redisAmr{ 56 | client: client, 57 | ctx: context.Background(), 58 | } 59 | } 60 | 61 | func (s *redisAmr) put(atype AMRTYPE, key, value []byte, ttl uint64) error { 62 | return s.client.Set(s.ctx, string(amrKey(atype, key)), value, time.Duration(ttl)*time.Second).Err() 63 | } 64 | 65 | func (s *redisAmr) get(atype AMRTYPE, key []byte) ([]byte, error) { 66 | return s.client.Get(s.ctx, string(amrKey(atype, key))).Bytes() 67 | } 68 | 69 | func (s *redisAmr) remove(atype AMRTYPE, key []byte) error { 70 | return s.client.Del(s.ctx, string(amrKey(atype, key))).Err() 71 | } 72 | 73 | func (s *redisAmr) append(atype AMRTYPE, key, value []byte, ttl uint64) (err error) { 74 | fullKey := string(amrKey(atype, key)) 75 | if err = s.client.SAdd(s.ctx, fullKey, string(value)).Err(); err == nil && ttl > 0 { 76 | err = s.client.Expire(s.ctx, fullKey, time.Duration(ttl)*time.Second).Err() 77 | } 78 | return 79 | } 80 | 81 | func (s *redisAmr) getMutil(atype AMRTYPE, key []byte) [][]byte { 82 | if members, err := s.client.SMembers(s.ctx, string(amrKey(atype, key))).Result(); err == nil && len(members) > 0 { 83 | results := make([][]byte, len(members)) 84 | for i := range members { 85 | results[i] = []byte(members[i]) 86 | } 87 | return results 88 | } 89 | return nil 90 | } 91 | 92 | func (s *redisAmr) removeKV(atype AMRTYPE, key, value []byte) error { 93 | return s.client.SRem(s.ctx, string(amrKey(atype, key)), value).Err() 94 | } 95 | 96 | func (s *redisAmr) close() error { 97 | switch v := s.client.(type) { 98 | case *redis.Client: 99 | return v.Close() 100 | case *redis.ClusterClient: 101 | return v.Close() 102 | default: 103 | return errors.New("unknown client type") 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /amr/token.go: -------------------------------------------------------------------------------- 1 | package amr 2 | 3 | import ( 4 | "github.com/donnie4w/gofer/util" 5 | "github.com/donnie4w/tim/cache" 6 | "github.com/donnie4w/tim/stub" 7 | "github.com/donnie4w/tim/sys" 8 | ) 9 | 10 | func PutToken(token string, tid *stub.Tid) { 11 | if islocalamr { 12 | cache.TokenCache.Put(token, tid) 13 | } else { 14 | amr.put(TOKEN, []byte(token), util.TEncode(tid), uint64(sys.Conf.TokenTimeout)) 15 | } 16 | } 17 | 18 | func GetToken(token string) *stub.Tid { 19 | if cache.TokenUsedCache.Contains([]byte(token)) { 20 | return nil 21 | } 22 | if islocalamr { 23 | return cache.TokenCache.Get(token) 24 | } else { 25 | if bs, _ := amr.get(TOKEN, []byte(token)); len(bs) > 0 { 26 | r, _ := util.TDecode[*stub.Tid](bs, stub.NewTid()) 27 | return r 28 | } 29 | } 30 | return nil 31 | } 32 | 33 | func DelToken(token string) { 34 | if islocalamr { 35 | cache.TokenCache.Del(token) 36 | } else { 37 | amr.remove(TOKEN, []byte(token)) 38 | } 39 | cache.TokenUsedCache.Add([]byte(token)) 40 | } 41 | -------------------------------------------------------------------------------- /amr/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/tim/sys" 12 | ) 13 | 14 | type AMRTYPE byte 15 | 16 | const ( 17 | ACCOUNT AMRTYPE = 1 18 | TOKEN AMRTYPE = 2 19 | VNODE AMRTYPE = 3 20 | BLOCK AMRTYPE = 4 21 | UUID AMRTYPE = 5 22 | ) 23 | 24 | var islocalamr = false 25 | 26 | func init() { 27 | sys.Service(sys.INIT_AMR, (amrservie)(0)) 28 | } 29 | 30 | func amrKey(atype AMRTYPE, key []byte) []byte { 31 | bs := make([]byte, len(key)+1) 32 | bs[0] = byte(atype) 33 | copy(bs[1:], key) 34 | return bs 35 | } 36 | -------------------------------------------------------------------------------- /amr/vnode.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/cache" 13 | "github.com/donnie4w/tim/errs" 14 | "github.com/donnie4w/tim/sys" 15 | ) 16 | 17 | func GetVnode(vnode string) int64 { 18 | if islocalamr { 19 | return sys.UUID 20 | } else { 21 | fh := util.FNVHash64([]byte(vnode)) 22 | if v, b := cache.VnodeCache.Get(fh); b { 23 | return v 24 | } 25 | if bs, _ := amr.get(VNODE, []byte(vnode)); len(bs) > 0 { 26 | r := util.BytesToInt64(bs) 27 | cache.VnodeCache.Put(fh, r) 28 | return r 29 | } 30 | } 31 | return 0 32 | } 33 | 34 | func PutVnode(vnode string) error { 35 | if islocalamr { 36 | return nil 37 | } 38 | if vnode != "" { 39 | return amr.put(VNODE, []byte(vnode), util.Int64ToBytes(sys.UUID), 86400) 40 | } else { 41 | return errs.ERR_PARAMS.Error() 42 | } 43 | } 44 | 45 | func DelVnode(vnode string) { 46 | if vnode != "" { 47 | amr.remove(VNODE, []byte(vnode)) 48 | cache.VnodeCache.Del(util.FNVHash64([]byte(vnode))) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /amr/zkamr.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package amr 9 | 10 | import ( 11 | "errors" 12 | "fmt" 13 | "github.com/donnie4w/tim/log" 14 | "github.com/donnie4w/tim/sys" 15 | "github.com/go-zookeeper/zk" 16 | "time" 17 | ) 18 | 19 | type zkAmr struct { 20 | conn *zk.Conn 21 | } 22 | 23 | func newZkAmr() amrStore { 24 | if sys.Conf.ZooKeeper == nil { 25 | log.FmtPrint("Zookeeper configuration is not initialized") 26 | return nil 27 | } 28 | 29 | zkConn, _, err := zk.Connect(sys.Conf.ZooKeeper.Servers, time.Duration(sys.Conf.ZooKeeper.SessionTimeout)*time.Second) 30 | if err != nil { 31 | log.FmtPrint("failed to connect to Zookeeper: ", err) 32 | return nil 33 | } 34 | 35 | if sys.Conf.ZooKeeper.Username != "" && sys.Conf.ZooKeeper.Password != "" { 36 | auth := fmt.Sprintf("%s:%s", sys.Conf.ZooKeeper.Username, sys.Conf.ZooKeeper.Password) 37 | if err = zkConn.AddAuth("digest", []byte(auth)); err != nil { 38 | log.FmtPrint("failed to authenticate with Zookeeper: ", err) 39 | return nil 40 | } 41 | } 42 | log.FmtPrint("Zookeeper connection established") 43 | return &zkAmr{ 44 | conn: zkConn, 45 | } 46 | } 47 | 48 | func (s *zkAmr) put(atype AMRTYPE, key, value []byte, ttl uint64) (err error) { 49 | fullKey := string(amrKey(atype, key)) 50 | _, err = s.conn.Set(fullKey, value, -1) 51 | if err != nil && errors.Is(err, zk.ErrNoNode) { 52 | _, err = s.conn.Create(fullKey, value, zk.FlagEphemeral, zk.WorldACL(zk.PermAll)) 53 | } 54 | return 55 | } 56 | func (s *zkAmr) get(atype AMRTYPE, key []byte) ([]byte, error) { 57 | data, _, err := s.conn.Get(string(amrKey(atype, key))) 58 | return data, err 59 | } 60 | 61 | func (s *zkAmr) remove(atype AMRTYPE, key []byte) error { 62 | return s.conn.Delete(string(amrKey(atype, key)), -1) 63 | } 64 | 65 | func (s *zkAmr) append(atype AMRTYPE, key, value []byte, ttl uint64) error { 66 | _, err := s.conn.Create(string(amrKey(atype, key))+"/"+string(value), nil, zk.FlagEphemeral, zk.WorldACL(zk.PermAll)) 67 | return err 68 | } 69 | 70 | func (s *zkAmr) getMutil(atype AMRTYPE, key []byte) [][]byte { 71 | if children, _, err := s.conn.Children(string(amrKey(atype, key))); err == nil { 72 | results := make([][]byte, len(children)) 73 | for i := range children { 74 | results[i] = []byte(children[i]) 75 | } 76 | return results 77 | } 78 | return nil 79 | } 80 | func (s *zkAmr) removeKV(atype AMRTYPE, key, value []byte) error { 81 | return s.conn.Delete(string(amrKey(atype, key))+"/"+string(value), -1) 82 | } 83 | 84 | func (s *zkAmr) close() error { 85 | s.conn.Close() 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /branch/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package branch 9 | 10 | import "github.com/donnie4w/tim/stub" 11 | 12 | func newTid(node string, domain *string) *stub.Tid { 13 | tid := stub.NewTid() 14 | tid.Node = node 15 | tid.Domain = domain 16 | return tid 17 | } 18 | -------------------------------------------------------------------------------- /cache/account.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "github.com/donnie4w/gofer/util" 13 | "time" 14 | ) 15 | 16 | type accountBean struct { 17 | uuids []int64 18 | timestamp int64 19 | } 20 | 21 | type accountPool struct { 22 | mm *hashmap.LinkedHashMap[int64, *accountBean] 23 | } 24 | 25 | func newAccountPool() *accountPool { 26 | ap := &accountPool{mm: hashmap.NewLinkedHashMap[int64, *accountBean](1 << 17)} 27 | go ap.ticker() 28 | return ap 29 | } 30 | 31 | func (t *accountPool) Put(node string, uuids []int64) { 32 | t.mm.Put(int64(util.FNVHash64([]byte(node))), &accountBean{uuids: uuids, timestamp: time.Now().UnixNano()}) 33 | } 34 | 35 | func (t *accountPool) Get(node string) []int64 { 36 | if r, _ := t.mm.Get(int64(util.FNVHash64([]byte(node)))); r != nil { 37 | return r.uuids 38 | } 39 | return nil 40 | } 41 | 42 | func (t *accountPool) Del(node string) { 43 | t.mm.Delete(int64(util.FNVHash64([]byte(node)))) 44 | } 45 | 46 | func (t *accountPool) ticker() { 47 | tk := time.NewTicker(5 * time.Second) 48 | for { 49 | select { 50 | case <-tk.C: 51 | func() { 52 | defer util.Recover(nil) 53 | iterator := t.mm.Iterator(false) 54 | for { 55 | if k, v, b := iterator.Next(); b { 56 | if time.Now().UnixNano() > v.timestamp+time.Minute.Nanoseconds() { 57 | t.mm.Delete(k) 58 | continue 59 | } 60 | } 61 | break 62 | } 63 | }() 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cache/auth.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "github.com/donnie4w/gofer/lock" 13 | goutil "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/data" 15 | "github.com/donnie4w/tim/sys" 16 | "github.com/donnie4w/tim/util" 17 | "time" 18 | ) 19 | 20 | type auth struct { 21 | mm *hashmap.LimitHashMap[uint64, int64] 22 | strlock *lock.Strlock 23 | } 24 | 25 | func newAuth() *auth { 26 | return &auth{mm: hashmap.NewLimitHashMapWithSegment[uint64, int64](1<<20, 1<<10), strlock: lock.NewStrlock(1 << 10)} 27 | } 28 | 29 | func (a *auth) Has(fnode, tnode string, domain *string, group bool) bool { 30 | var idx []byte 31 | if group { 32 | idx = util.RelateIdForGroup(fnode, tnode, domain) 33 | } else { 34 | idx = util.ChatIdByNode(fnode, tnode, domain) 35 | } 36 | if r, _ := a.mm.Get(goutil.FNVHash64(idx)); r > 0 { 37 | if v := time.Now().Unix() - r; v < sys.Conf.CacheAuthExpire { 38 | if v < sys.Conf.CacheAuthExpire/2 { 39 | go a.check(fnode, tnode, domain, group) 40 | } 41 | return true 42 | } 43 | } 44 | return false 45 | } 46 | 47 | func (a *auth) Put(fnode, tnode string, domain *string, group bool) { 48 | if group { 49 | rid := util.RelateIdForGroup(fnode, tnode, domain) 50 | a.mm.Put(goutil.FNVHash64(rid), time.Now().Unix()) 51 | } else { 52 | cid := util.ChatIdByNode(fnode, tnode, domain) 53 | a.mm.Put(goutil.FNVHash64(cid), time.Now().Unix()) 54 | } 55 | } 56 | 57 | func (a *auth) Delete(key uint64) { 58 | a.mm.Del(key) 59 | } 60 | 61 | func (a *auth) DeleteWithNode(fnode, tnode string, domain *string, group bool) { 62 | if group { 63 | a.Delete(goutil.FNVHash64(util.RelateIdForGroup(fnode, tnode, domain))) 64 | } else { 65 | a.Delete(goutil.FNVHash64(util.ChatIdByNode(fnode, tnode, domain))) 66 | } 67 | } 68 | 69 | func (a *auth) check(fnode, tnode string, domain *string, group bool) { 70 | if lock, ok := a.strlock.TryLock(fnode + tnode); ok { 71 | defer lock.Unlock() 72 | var b bool 73 | if group { 74 | b, _ = data.Service.AuthGroupAndUser(fnode, tnode, domain) 75 | } else { 76 | b = data.Service.AuthUserAndUser(fnode, tnode, domain) 77 | } 78 | if b { 79 | a.Put(fnode, tnode, domain, group) 80 | } else { 81 | a.DeleteWithNode(fnode, tnode, domain, group) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /cache/block.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "time" 13 | ) 14 | 15 | type blockPool struct { 16 | mm *hashmap.Map[string, int64] 17 | } 18 | 19 | func newBlockPool() *blockPool { 20 | bp := &blockPool{mm: hashmap.NewMap[string, int64]()} 21 | go bp.tick() 22 | return bp 23 | } 24 | 25 | func (bp *blockPool) Put(key string, value int64) { 26 | bp.mm.Put(key, value+time.Now().Unix()) 27 | } 28 | 29 | func (bp *blockPool) Get(key string) int64 { 30 | r, _ := bp.mm.Get(key) 31 | return r 32 | } 33 | 34 | func (bp *blockPool) Del(key string) { 35 | bp.mm.Del(key) 36 | } 37 | 38 | func (bp *blockPool) tick() int { 39 | tk := time.NewTicker(5 * time.Second) 40 | for { 41 | select { 42 | case <-tk.C: 43 | bp.mm.Range(func(k string, v int64) bool { 44 | if v < time.Now().Unix() { 45 | bp.Del(k) 46 | } 47 | return true 48 | }) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cache/cache.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | gocache "github.com/donnie4w/gofer/cache" 12 | "github.com/donnie4w/gofer/hashmap" 13 | ) 14 | 15 | var TokenCache = newTokenPool() 16 | 17 | var AuthCache = newAuth() 18 | 19 | var AccountCache = newAccountPool() 20 | 21 | var TokenUsedCache = gocache.NewBloomFilter(1<<19, 0.01) 22 | 23 | var BlockUserCache = newBlockPool() 24 | 25 | var VnodeCache = hashmap.NewLimitHashMap[uint64, int64](1 << 18) 26 | 27 | var CsAccessCache = newCsAccessPool() 28 | -------------------------------------------------------------------------------- /cache/csaccess.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "github.com/donnie4w/tim/util" 13 | "time" 14 | ) 15 | 16 | type csAccessBean struct { 17 | csaddr string 18 | timestamp int64 19 | } 20 | 21 | type csAccessPool struct { 22 | mm *hashmap.LinkedHashMap[int64, *csAccessBean] 23 | } 24 | 25 | func newCsAccessPool() *csAccessPool { 26 | tp := &csAccessPool{mm: hashmap.NewLinkedHashMap[int64, *csAccessBean](1 << 10)} 27 | go tp.ticker() 28 | return tp 29 | } 30 | 31 | func (t *csAccessPool) Put(uuid int64, csAddr string) { 32 | t.mm.Put(uuid, &csAccessBean{csaddr: csAddr, timestamp: time.Now().UnixNano()}) 33 | } 34 | 35 | func (t *csAccessPool) Get(uuid int64) string { 36 | if r, _ := t.mm.Get(uuid); r != nil { 37 | return r.csaddr 38 | } 39 | return "" 40 | } 41 | 42 | func (t *csAccessPool) Del(uuid int64) { 43 | t.mm.Delete(uuid) 44 | } 45 | 46 | func (t *csAccessPool) ticker() { 47 | tk := time.NewTicker(10 * time.Second) 48 | for { 49 | select { 50 | case <-tk.C: 51 | func() { 52 | defer util.Recover() 53 | iterator := t.mm.Iterator(false) 54 | for { 55 | if k, v, b := iterator.Next(); b { 56 | if time.Now().UnixNano() > v.timestamp+time.Minute.Nanoseconds() { 57 | t.mm.Delete(k) 58 | continue 59 | } 60 | } 61 | break 62 | } 63 | }() 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cache/token.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package cache 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "github.com/donnie4w/tim/stub" 13 | "github.com/donnie4w/tim/sys" 14 | "github.com/donnie4w/tim/util" 15 | "time" 16 | ) 17 | 18 | type tokenBean struct { 19 | tid *stub.Tid 20 | timestamp int64 21 | } 22 | 23 | type tokenPool struct { 24 | mm *hashmap.LinkedHashMap[string, *tokenBean] 25 | } 26 | 27 | func newTokenPool() *tokenPool { 28 | tp := &tokenPool{mm: hashmap.NewLinkedHashMap[string, *tokenBean](1 << 16)} 29 | go tp.ticker() 30 | return tp 31 | } 32 | 33 | func (t *tokenPool) Put(token string, tid *stub.Tid) { 34 | t.mm.Put(token, &tokenBean{tid: tid, timestamp: time.Now().UnixNano()}) 35 | } 36 | 37 | func (t *tokenPool) Get(token string) *stub.Tid { 38 | if r, _ := t.mm.Get(token); r != nil { 39 | return r.tid 40 | } 41 | return nil 42 | } 43 | 44 | func (t *tokenPool) Del(token string) { 45 | t.mm.Delete(token) 46 | } 47 | 48 | func (t *tokenPool) ticker() { 49 | tk := time.NewTicker(10 * time.Second) 50 | for { 51 | select { 52 | case <-tk.C: 53 | func() { 54 | defer util.Recover() 55 | iterator := t.mm.Iterator(false) 56 | for { 57 | if k, v, b := iterator.Next(); b { 58 | if time.Now().UnixNano() > v.timestamp+sys.Conf.TokenTimeout { 59 | t.mm.Delete(k) 60 | continue 61 | } 62 | } 63 | break 64 | } 65 | }() 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /dao/timblock.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timblock 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timblock struct { 22 | gdao.Table[Timblock] 23 | 24 | ID *base.Field[Timblock] 25 | UNIKID *base.Field[Timblock] 26 | UUID *base.Field[Timblock] 27 | TUUID *base.Field[Timblock] 28 | TIMESERIES *base.Field[Timblock] 29 | _ID *int64 30 | _UNIKID []byte 31 | _UUID *int64 32 | _TUUID *int64 33 | _TIMESERIES *int64 34 | } 35 | 36 | var _Timblock_ID = &base.Field[Timblock]{"id"} 37 | var _Timblock_UNIKID = &base.Field[Timblock]{"unikid"} 38 | var _Timblock_UUID = &base.Field[Timblock]{"uuid"} 39 | var _Timblock_TUUID = &base.Field[Timblock]{"tuuid"} 40 | var _Timblock_TIMESERIES = &base.Field[Timblock]{"timeseries"} 41 | 42 | func (u *Timblock) GetId() (_r int64){ 43 | if u._ID != nil { 44 | _r = *u._ID 45 | } 46 | return 47 | } 48 | 49 | func (u *Timblock) SetId(arg int64) *Timblock{ 50 | u.Put0(u.ID.FieldName, arg) 51 | u._ID = &arg 52 | return u 53 | } 54 | 55 | func (u *Timblock) GetUnikid() (_r []byte){ 56 | _r = u._UNIKID 57 | return 58 | } 59 | 60 | func (u *Timblock) SetUnikid(arg []byte) *Timblock{ 61 | u.Put0(u.UNIKID.FieldName, arg) 62 | u._UNIKID = arg 63 | return u 64 | } 65 | 66 | func (u *Timblock) GetUuid() (_r int64){ 67 | if u._UUID != nil { 68 | _r = *u._UUID 69 | } 70 | return 71 | } 72 | 73 | func (u *Timblock) SetUuid(arg int64) *Timblock{ 74 | u.Put0(u.UUID.FieldName, arg) 75 | u._UUID = &arg 76 | return u 77 | } 78 | 79 | func (u *Timblock) GetTuuid() (_r int64){ 80 | if u._TUUID != nil { 81 | _r = *u._TUUID 82 | } 83 | return 84 | } 85 | 86 | func (u *Timblock) SetTuuid(arg int64) *Timblock{ 87 | u.Put0(u.TUUID.FieldName, arg) 88 | u._TUUID = &arg 89 | return u 90 | } 91 | 92 | func (u *Timblock) GetTimeseries() (_r int64){ 93 | if u._TIMESERIES != nil { 94 | _r = *u._TIMESERIES 95 | } 96 | return 97 | } 98 | 99 | func (u *Timblock) SetTimeseries(arg int64) *Timblock{ 100 | u.Put0(u.TIMESERIES.FieldName, arg) 101 | u._TIMESERIES = &arg 102 | return u 103 | } 104 | 105 | 106 | func (u *Timblock) Scan(fieldname string, value any) { 107 | switch fieldname { 108 | case "id": 109 | u.SetId(base.AsInt64(value)) 110 | case "unikid": 111 | u.SetUnikid(base.AsBytes(value)) 112 | case "uuid": 113 | u.SetUuid(base.AsInt64(value)) 114 | case "tuuid": 115 | u.SetTuuid(base.AsInt64(value)) 116 | case "timeseries": 117 | u.SetTimeseries(base.AsInt64(value)) 118 | } 119 | } 120 | 121 | func (t *Timblock) ToGdao() { 122 | t.init("timblock") 123 | } 124 | 125 | func (t *Timblock) Copy(h *Timblock) *Timblock{ 126 | t.SetId(h.GetId()) 127 | t.SetUnikid(h.GetUnikid()) 128 | t.SetUuid(h.GetUuid()) 129 | t.SetTuuid(h.GetTuuid()) 130 | t.SetTimeseries(h.GetTimeseries()) 131 | return t 132 | } 133 | 134 | func (t *Timblock) String() string { 135 | return fmt.Sprint("Id:",t.GetId(), ",","Unikid:",t.GetUnikid(), ",","Uuid:",t.GetUuid(), ",","Tuuid:",t.GetTuuid(), ",","Timeseries:",t.GetTimeseries()) 136 | } 137 | 138 | func (t *Timblock)init(tablename string) { 139 | t.ID = _Timblock_ID 140 | t.UNIKID = _Timblock_UNIKID 141 | t.UUID = _Timblock_UUID 142 | t.TUUID = _Timblock_TUUID 143 | t.TIMESERIES = _Timblock_TIMESERIES 144 | t.Init(tablename, []base.Column[Timblock]{t.ID,t.UNIKID,t.UUID,t.TUUID,t.TIMESERIES}) 145 | } 146 | 147 | func NewTimblock(tablename ...string) (_r *Timblock) { 148 | _r = &Timblock{} 149 | s := "timblock" 150 | if len(tablename) > 0 && tablename[0] != "" { 151 | s = tablename[0] 152 | } 153 | _r.init(s) 154 | return 155 | } 156 | 157 | func (t *Timblock) Encode() ([]byte, error) { 158 | m := make(map[string]any, 0) 159 | m["id"] = t.GetId() 160 | m["unikid"] = t.GetUnikid() 161 | m["uuid"] = t.GetUuid() 162 | m["tuuid"] = t.GetTuuid() 163 | m["timeseries"] = t.GetTimeseries() 164 | return t.Table.Encode(m) 165 | } 166 | 167 | func (t *Timblock) Decode(bs []byte) (err error) { 168 | var m map[string]any 169 | if m, err = t.Table.Decode(bs); err == nil { 170 | if !t.IsInit() { 171 | t.ToGdao() 172 | } 173 | for name, bean := range m { 174 | t.Scan(name, bean) 175 | } 176 | } 177 | return 178 | } 179 | 180 | -------------------------------------------------------------------------------- /dao/timblockroom.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timblockroom 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timblockroom struct { 22 | gdao.Table[Timblockroom] 23 | 24 | ID *base.Field[Timblockroom] 25 | UNIKID *base.Field[Timblockroom] 26 | UUID *base.Field[Timblockroom] 27 | TUUID *base.Field[Timblockroom] 28 | TIMESERIES *base.Field[Timblockroom] 29 | _ID *int64 30 | _UNIKID []byte 31 | _UUID *int64 32 | _TUUID *int64 33 | _TIMESERIES *int64 34 | } 35 | 36 | var _Timblockroom_ID = &base.Field[Timblockroom]{"id"} 37 | var _Timblockroom_UNIKID = &base.Field[Timblockroom]{"unikid"} 38 | var _Timblockroom_UUID = &base.Field[Timblockroom]{"uuid"} 39 | var _Timblockroom_TUUID = &base.Field[Timblockroom]{"tuuid"} 40 | var _Timblockroom_TIMESERIES = &base.Field[Timblockroom]{"timeseries"} 41 | 42 | func (u *Timblockroom) GetId() (_r int64){ 43 | if u._ID != nil { 44 | _r = *u._ID 45 | } 46 | return 47 | } 48 | 49 | func (u *Timblockroom) SetId(arg int64) *Timblockroom{ 50 | u.Put0(u.ID.FieldName, arg) 51 | u._ID = &arg 52 | return u 53 | } 54 | 55 | func (u *Timblockroom) GetUnikid() (_r []byte){ 56 | _r = u._UNIKID 57 | return 58 | } 59 | 60 | func (u *Timblockroom) SetUnikid(arg []byte) *Timblockroom{ 61 | u.Put0(u.UNIKID.FieldName, arg) 62 | u._UNIKID = arg 63 | return u 64 | } 65 | 66 | func (u *Timblockroom) GetUuid() (_r int64){ 67 | if u._UUID != nil { 68 | _r = *u._UUID 69 | } 70 | return 71 | } 72 | 73 | func (u *Timblockroom) SetUuid(arg int64) *Timblockroom{ 74 | u.Put0(u.UUID.FieldName, arg) 75 | u._UUID = &arg 76 | return u 77 | } 78 | 79 | func (u *Timblockroom) GetTuuid() (_r int64){ 80 | if u._TUUID != nil { 81 | _r = *u._TUUID 82 | } 83 | return 84 | } 85 | 86 | func (u *Timblockroom) SetTuuid(arg int64) *Timblockroom{ 87 | u.Put0(u.TUUID.FieldName, arg) 88 | u._TUUID = &arg 89 | return u 90 | } 91 | 92 | func (u *Timblockroom) GetTimeseries() (_r int64){ 93 | if u._TIMESERIES != nil { 94 | _r = *u._TIMESERIES 95 | } 96 | return 97 | } 98 | 99 | func (u *Timblockroom) SetTimeseries(arg int64) *Timblockroom{ 100 | u.Put0(u.TIMESERIES.FieldName, arg) 101 | u._TIMESERIES = &arg 102 | return u 103 | } 104 | 105 | 106 | func (u *Timblockroom) Scan(fieldname string, value any) { 107 | switch fieldname { 108 | case "id": 109 | u.SetId(base.AsInt64(value)) 110 | case "unikid": 111 | u.SetUnikid(base.AsBytes(value)) 112 | case "uuid": 113 | u.SetUuid(base.AsInt64(value)) 114 | case "tuuid": 115 | u.SetTuuid(base.AsInt64(value)) 116 | case "timeseries": 117 | u.SetTimeseries(base.AsInt64(value)) 118 | } 119 | } 120 | 121 | func (t *Timblockroom) ToGdao() { 122 | t.init("timblockroom") 123 | } 124 | 125 | func (t *Timblockroom) Copy(h *Timblockroom) *Timblockroom{ 126 | t.SetId(h.GetId()) 127 | t.SetUnikid(h.GetUnikid()) 128 | t.SetUuid(h.GetUuid()) 129 | t.SetTuuid(h.GetTuuid()) 130 | t.SetTimeseries(h.GetTimeseries()) 131 | return t 132 | } 133 | 134 | func (t *Timblockroom) String() string { 135 | return fmt.Sprint("Id:",t.GetId(), ",","Unikid:",t.GetUnikid(), ",","Uuid:",t.GetUuid(), ",","Tuuid:",t.GetTuuid(), ",","Timeseries:",t.GetTimeseries()) 136 | } 137 | 138 | func (t *Timblockroom)init(tablename string) { 139 | t.ID = _Timblockroom_ID 140 | t.UNIKID = _Timblockroom_UNIKID 141 | t.UUID = _Timblockroom_UUID 142 | t.TUUID = _Timblockroom_TUUID 143 | t.TIMESERIES = _Timblockroom_TIMESERIES 144 | t.Init(tablename, []base.Column[Timblockroom]{t.ID,t.UNIKID,t.UUID,t.TUUID,t.TIMESERIES}) 145 | } 146 | 147 | func NewTimblockroom(tablename ...string) (_r *Timblockroom) { 148 | _r = &Timblockroom{} 149 | s := "timblockroom" 150 | if len(tablename) > 0 && tablename[0] != "" { 151 | s = tablename[0] 152 | } 153 | _r.init(s) 154 | return 155 | } 156 | 157 | func (t *Timblockroom) Encode() ([]byte, error) { 158 | m := make(map[string]any, 0) 159 | m["id"] = t.GetId() 160 | m["unikid"] = t.GetUnikid() 161 | m["uuid"] = t.GetUuid() 162 | m["tuuid"] = t.GetTuuid() 163 | m["timeseries"] = t.GetTimeseries() 164 | return t.Table.Encode(m) 165 | } 166 | 167 | func (t *Timblockroom) Decode(bs []byte) (err error) { 168 | var m map[string]any 169 | if m, err = t.Table.Decode(bs); err == nil { 170 | if !t.IsInit() { 171 | t.ToGdao() 172 | } 173 | for name, bean := range m { 174 | t.Scan(name, bean) 175 | } 176 | } 177 | return 178 | } 179 | 180 | -------------------------------------------------------------------------------- /dao/timdomain.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timdomain 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timdomain struct { 22 | gdao.Table[Timdomain] 23 | 24 | ID *base.Field[Timdomain] 25 | ADMINACCOUNT *base.Field[Timdomain] 26 | ADMINPASSWORD *base.Field[Timdomain] 27 | TIMDOMAIN *base.Field[Timdomain] 28 | CREATETIME *base.Field[Timdomain] 29 | TIMESERIES *base.Field[Timdomain] 30 | _ID *int64 31 | _ADMINACCOUNT *string 32 | _ADMINPASSWORD *string 33 | _TIMDOMAIN *string 34 | _CREATETIME *int64 35 | _TIMESERIES *int64 36 | } 37 | 38 | var _Timdomain_ID = &base.Field[Timdomain]{"id"} 39 | var _Timdomain_ADMINACCOUNT = &base.Field[Timdomain]{"adminaccount"} 40 | var _Timdomain_ADMINPASSWORD = &base.Field[Timdomain]{"adminpassword"} 41 | var _Timdomain_TIMDOMAIN = &base.Field[Timdomain]{"timdomain"} 42 | var _Timdomain_CREATETIME = &base.Field[Timdomain]{"createtime"} 43 | var _Timdomain_TIMESERIES = &base.Field[Timdomain]{"timeseries"} 44 | 45 | func (u *Timdomain) GetId() (_r int64){ 46 | if u._ID != nil { 47 | _r = *u._ID 48 | } 49 | return 50 | } 51 | 52 | func (u *Timdomain) SetId(arg int64) *Timdomain{ 53 | u.Put0(u.ID.FieldName, arg) 54 | u._ID = &arg 55 | return u 56 | } 57 | 58 | func (u *Timdomain) GetAdminaccount() (_r string){ 59 | if u._ADMINACCOUNT != nil { 60 | _r = *u._ADMINACCOUNT 61 | } 62 | return 63 | } 64 | 65 | func (u *Timdomain) SetAdminaccount(arg string) *Timdomain{ 66 | u.Put0(u.ADMINACCOUNT.FieldName, arg) 67 | u._ADMINACCOUNT = &arg 68 | return u 69 | } 70 | 71 | func (u *Timdomain) GetAdminpassword() (_r string){ 72 | if u._ADMINPASSWORD != nil { 73 | _r = *u._ADMINPASSWORD 74 | } 75 | return 76 | } 77 | 78 | func (u *Timdomain) SetAdminpassword(arg string) *Timdomain{ 79 | u.Put0(u.ADMINPASSWORD.FieldName, arg) 80 | u._ADMINPASSWORD = &arg 81 | return u 82 | } 83 | 84 | func (u *Timdomain) GetTimdomain() (_r string){ 85 | if u._TIMDOMAIN != nil { 86 | _r = *u._TIMDOMAIN 87 | } 88 | return 89 | } 90 | 91 | func (u *Timdomain) SetTimdomain(arg string) *Timdomain{ 92 | u.Put0(u.TIMDOMAIN.FieldName, arg) 93 | u._TIMDOMAIN = &arg 94 | return u 95 | } 96 | 97 | func (u *Timdomain) GetCreatetime() (_r int64){ 98 | if u._CREATETIME != nil { 99 | _r = *u._CREATETIME 100 | } 101 | return 102 | } 103 | 104 | func (u *Timdomain) SetCreatetime(arg int64) *Timdomain{ 105 | u.Put0(u.CREATETIME.FieldName, arg) 106 | u._CREATETIME = &arg 107 | return u 108 | } 109 | 110 | func (u *Timdomain) GetTimeseries() (_r int64){ 111 | if u._TIMESERIES != nil { 112 | _r = *u._TIMESERIES 113 | } 114 | return 115 | } 116 | 117 | func (u *Timdomain) SetTimeseries(arg int64) *Timdomain{ 118 | u.Put0(u.TIMESERIES.FieldName, arg) 119 | u._TIMESERIES = &arg 120 | return u 121 | } 122 | 123 | 124 | func (u *Timdomain) Scan(fieldname string, value any) { 125 | switch fieldname { 126 | case "id": 127 | u.SetId(base.AsInt64(value)) 128 | case "adminaccount": 129 | u.SetAdminaccount(base.AsString(value)) 130 | case "adminpassword": 131 | u.SetAdminpassword(base.AsString(value)) 132 | case "timdomain": 133 | u.SetTimdomain(base.AsString(value)) 134 | case "createtime": 135 | u.SetCreatetime(base.AsInt64(value)) 136 | case "timeseries": 137 | u.SetTimeseries(base.AsInt64(value)) 138 | } 139 | } 140 | 141 | func (t *Timdomain) ToGdao() { 142 | t.init("timdomain") 143 | } 144 | 145 | func (t *Timdomain) Copy(h *Timdomain) *Timdomain{ 146 | t.SetId(h.GetId()) 147 | t.SetAdminaccount(h.GetAdminaccount()) 148 | t.SetAdminpassword(h.GetAdminpassword()) 149 | t.SetTimdomain(h.GetTimdomain()) 150 | t.SetCreatetime(h.GetCreatetime()) 151 | t.SetTimeseries(h.GetTimeseries()) 152 | return t 153 | } 154 | 155 | func (t *Timdomain) String() string { 156 | return fmt.Sprint("Id:",t.GetId(), ",","Adminaccount:",t.GetAdminaccount(), ",","Adminpassword:",t.GetAdminpassword(), ",","Timdomain:",t.GetTimdomain(), ",","Createtime:",t.GetCreatetime(), ",","Timeseries:",t.GetTimeseries()) 157 | } 158 | 159 | func (t *Timdomain)init(tablename string) { 160 | t.ID = _Timdomain_ID 161 | t.ADMINACCOUNT = _Timdomain_ADMINACCOUNT 162 | t.ADMINPASSWORD = _Timdomain_ADMINPASSWORD 163 | t.TIMDOMAIN = _Timdomain_TIMDOMAIN 164 | t.CREATETIME = _Timdomain_CREATETIME 165 | t.TIMESERIES = _Timdomain_TIMESERIES 166 | t.Init(tablename, []base.Column[Timdomain]{t.ID,t.ADMINACCOUNT,t.ADMINPASSWORD,t.TIMDOMAIN,t.CREATETIME,t.TIMESERIES}) 167 | } 168 | 169 | func NewTimdomain(tablename ...string) (_r *Timdomain) { 170 | _r = &Timdomain{} 171 | s := "timdomain" 172 | if len(tablename) > 0 && tablename[0] != "" { 173 | s = tablename[0] 174 | } 175 | _r.init(s) 176 | return 177 | } 178 | 179 | func (t *Timdomain) Encode() ([]byte, error) { 180 | m := make(map[string]any, 0) 181 | m["id"] = t.GetId() 182 | m["adminaccount"] = t.GetAdminaccount() 183 | m["adminpassword"] = t.GetAdminpassword() 184 | m["timdomain"] = t.GetTimdomain() 185 | m["createtime"] = t.GetCreatetime() 186 | m["timeseries"] = t.GetTimeseries() 187 | return t.Table.Encode(m) 188 | } 189 | 190 | func (t *Timdomain) Decode(bs []byte) (err error) { 191 | var m map[string]any 192 | if m, err = t.Table.Decode(bs); err == nil { 193 | if !t.IsInit() { 194 | t.ToGdao() 195 | } 196 | for name, bean := range m { 197 | t.Scan(name, bean) 198 | } 199 | } 200 | return 201 | } 202 | 203 | -------------------------------------------------------------------------------- /dao/timgroup.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timgroup 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timgroup struct { 22 | gdao.Table[Timgroup] 23 | 24 | ID *base.Field[Timgroup] 25 | GTYPE *base.Field[Timgroup] 26 | UUID *base.Field[Timgroup] 27 | CREATETIME *base.Field[Timgroup] 28 | STATUS *base.Field[Timgroup] 29 | RBEAN *base.Field[Timgroup] 30 | TIMESERIES *base.Field[Timgroup] 31 | _ID *int64 32 | _GTYPE *int64 33 | _UUID *int64 34 | _CREATETIME *int64 35 | _STATUS *int64 36 | _RBEAN []byte 37 | _TIMESERIES *int64 38 | } 39 | 40 | var _Timgroup_ID = &base.Field[Timgroup]{"id"} 41 | var _Timgroup_GTYPE = &base.Field[Timgroup]{"gtype"} 42 | var _Timgroup_UUID = &base.Field[Timgroup]{"uuid"} 43 | var _Timgroup_CREATETIME = &base.Field[Timgroup]{"createtime"} 44 | var _Timgroup_STATUS = &base.Field[Timgroup]{"status"} 45 | var _Timgroup_RBEAN = &base.Field[Timgroup]{"rbean"} 46 | var _Timgroup_TIMESERIES = &base.Field[Timgroup]{"timeseries"} 47 | 48 | func (u *Timgroup) GetId() (_r int64){ 49 | if u._ID != nil { 50 | _r = *u._ID 51 | } 52 | return 53 | } 54 | 55 | func (u *Timgroup) SetId(arg int64) *Timgroup{ 56 | u.Put0(u.ID.FieldName, arg) 57 | u._ID = &arg 58 | return u 59 | } 60 | 61 | func (u *Timgroup) GetGtype() (_r int64){ 62 | if u._GTYPE != nil { 63 | _r = *u._GTYPE 64 | } 65 | return 66 | } 67 | 68 | func (u *Timgroup) SetGtype(arg int64) *Timgroup{ 69 | u.Put0(u.GTYPE.FieldName, arg) 70 | u._GTYPE = &arg 71 | return u 72 | } 73 | 74 | func (u *Timgroup) GetUuid() (_r int64){ 75 | if u._UUID != nil { 76 | _r = *u._UUID 77 | } 78 | return 79 | } 80 | 81 | func (u *Timgroup) SetUuid(arg int64) *Timgroup{ 82 | u.Put0(u.UUID.FieldName, arg) 83 | u._UUID = &arg 84 | return u 85 | } 86 | 87 | func (u *Timgroup) GetCreatetime() (_r int64){ 88 | if u._CREATETIME != nil { 89 | _r = *u._CREATETIME 90 | } 91 | return 92 | } 93 | 94 | func (u *Timgroup) SetCreatetime(arg int64) *Timgroup{ 95 | u.Put0(u.CREATETIME.FieldName, arg) 96 | u._CREATETIME = &arg 97 | return u 98 | } 99 | 100 | func (u *Timgroup) GetStatus() (_r int64){ 101 | if u._STATUS != nil { 102 | _r = *u._STATUS 103 | } 104 | return 105 | } 106 | 107 | func (u *Timgroup) SetStatus(arg int64) *Timgroup{ 108 | u.Put0(u.STATUS.FieldName, arg) 109 | u._STATUS = &arg 110 | return u 111 | } 112 | 113 | func (u *Timgroup) GetRbean() (_r []byte){ 114 | _r = u._RBEAN 115 | return 116 | } 117 | 118 | func (u *Timgroup) SetRbean(arg []byte) *Timgroup{ 119 | u.Put0(u.RBEAN.FieldName, arg) 120 | u._RBEAN = arg 121 | return u 122 | } 123 | 124 | func (u *Timgroup) GetTimeseries() (_r int64){ 125 | if u._TIMESERIES != nil { 126 | _r = *u._TIMESERIES 127 | } 128 | return 129 | } 130 | 131 | func (u *Timgroup) SetTimeseries(arg int64) *Timgroup{ 132 | u.Put0(u.TIMESERIES.FieldName, arg) 133 | u._TIMESERIES = &arg 134 | return u 135 | } 136 | 137 | 138 | func (u *Timgroup) Scan(fieldname string, value any) { 139 | switch fieldname { 140 | case "id": 141 | u.SetId(base.AsInt64(value)) 142 | case "gtype": 143 | u.SetGtype(base.AsInt64(value)) 144 | case "uuid": 145 | u.SetUuid(base.AsInt64(value)) 146 | case "createtime": 147 | u.SetCreatetime(base.AsInt64(value)) 148 | case "status": 149 | u.SetStatus(base.AsInt64(value)) 150 | case "rbean": 151 | u.SetRbean(base.AsBytes(value)) 152 | case "timeseries": 153 | u.SetTimeseries(base.AsInt64(value)) 154 | } 155 | } 156 | 157 | func (t *Timgroup) ToGdao() { 158 | t.init("timgroup") 159 | } 160 | 161 | func (t *Timgroup) Copy(h *Timgroup) *Timgroup{ 162 | t.SetId(h.GetId()) 163 | t.SetGtype(h.GetGtype()) 164 | t.SetUuid(h.GetUuid()) 165 | t.SetCreatetime(h.GetCreatetime()) 166 | t.SetStatus(h.GetStatus()) 167 | t.SetRbean(h.GetRbean()) 168 | t.SetTimeseries(h.GetTimeseries()) 169 | return t 170 | } 171 | 172 | func (t *Timgroup) String() string { 173 | return fmt.Sprint("Id:",t.GetId(), ",","Gtype:",t.GetGtype(), ",","Uuid:",t.GetUuid(), ",","Createtime:",t.GetCreatetime(), ",","Status:",t.GetStatus(), ",","Rbean:",t.GetRbean(), ",","Timeseries:",t.GetTimeseries()) 174 | } 175 | 176 | func (t *Timgroup)init(tablename string) { 177 | t.ID = _Timgroup_ID 178 | t.GTYPE = _Timgroup_GTYPE 179 | t.UUID = _Timgroup_UUID 180 | t.CREATETIME = _Timgroup_CREATETIME 181 | t.STATUS = _Timgroup_STATUS 182 | t.RBEAN = _Timgroup_RBEAN 183 | t.TIMESERIES = _Timgroup_TIMESERIES 184 | t.Init(tablename, []base.Column[Timgroup]{t.ID,t.GTYPE,t.UUID,t.CREATETIME,t.STATUS,t.RBEAN,t.TIMESERIES}) 185 | } 186 | 187 | func NewTimgroup(tablename ...string) (_r *Timgroup) { 188 | _r = &Timgroup{} 189 | s := "timgroup" 190 | if len(tablename) > 0 && tablename[0] != "" { 191 | s = tablename[0] 192 | } 193 | _r.init(s) 194 | return 195 | } 196 | 197 | func (t *Timgroup) Encode() ([]byte, error) { 198 | m := make(map[string]any, 0) 199 | m["id"] = t.GetId() 200 | m["gtype"] = t.GetGtype() 201 | m["uuid"] = t.GetUuid() 202 | m["createtime"] = t.GetCreatetime() 203 | m["status"] = t.GetStatus() 204 | m["rbean"] = t.GetRbean() 205 | m["timeseries"] = t.GetTimeseries() 206 | return t.Table.Encode(m) 207 | } 208 | 209 | func (t *Timgroup) Decode(bs []byte) (err error) { 210 | var m map[string]any 211 | if m, err = t.Table.Decode(bs); err == nil { 212 | if !t.IsInit() { 213 | t.ToGdao() 214 | } 215 | for name, bean := range m { 216 | t.Scan(name, bean) 217 | } 218 | } 219 | return 220 | } 221 | 222 | -------------------------------------------------------------------------------- /dao/timmessage.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timmessage 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timmessage struct { 22 | gdao.Table[Timmessage] 23 | 24 | ID *base.Field[Timmessage] 25 | CHATID *base.Field[Timmessage] 26 | FID *base.Field[Timmessage] 27 | STANZA *base.Field[Timmessage] 28 | TIMESERIES *base.Field[Timmessage] 29 | _ID *int64 30 | _CHATID []byte 31 | _FID *int64 32 | _STANZA []byte 33 | _TIMESERIES *int64 34 | } 35 | 36 | var _Timmessage_ID = &base.Field[Timmessage]{"id"} 37 | var _Timmessage_CHATID = &base.Field[Timmessage]{"chatid"} 38 | var _Timmessage_FID = &base.Field[Timmessage]{"fid"} 39 | var _Timmessage_STANZA = &base.Field[Timmessage]{"stanza"} 40 | var _Timmessage_TIMESERIES = &base.Field[Timmessage]{"timeseries"} 41 | 42 | func (u *Timmessage) GetId() (_r int64){ 43 | if u._ID != nil { 44 | _r = *u._ID 45 | } 46 | return 47 | } 48 | 49 | func (u *Timmessage) SetId(arg int64) *Timmessage{ 50 | u.Put0(u.ID.FieldName, arg) 51 | u._ID = &arg 52 | return u 53 | } 54 | 55 | func (u *Timmessage) GetChatid() (_r []byte){ 56 | _r = u._CHATID 57 | return 58 | } 59 | 60 | func (u *Timmessage) SetChatid(arg []byte) *Timmessage{ 61 | u.Put0(u.CHATID.FieldName, arg) 62 | u._CHATID = arg 63 | return u 64 | } 65 | 66 | func (u *Timmessage) GetFid() (_r int64){ 67 | if u._FID != nil { 68 | _r = *u._FID 69 | } 70 | return 71 | } 72 | 73 | func (u *Timmessage) SetFid(arg int64) *Timmessage{ 74 | u.Put0(u.FID.FieldName, arg) 75 | u._FID = &arg 76 | return u 77 | } 78 | 79 | func (u *Timmessage) GetStanza() (_r []byte){ 80 | _r = u._STANZA 81 | return 82 | } 83 | 84 | func (u *Timmessage) SetStanza(arg []byte) *Timmessage{ 85 | u.Put0(u.STANZA.FieldName, arg) 86 | u._STANZA = arg 87 | return u 88 | } 89 | 90 | func (u *Timmessage) GetTimeseries() (_r int64){ 91 | if u._TIMESERIES != nil { 92 | _r = *u._TIMESERIES 93 | } 94 | return 95 | } 96 | 97 | func (u *Timmessage) SetTimeseries(arg int64) *Timmessage{ 98 | u.Put0(u.TIMESERIES.FieldName, arg) 99 | u._TIMESERIES = &arg 100 | return u 101 | } 102 | 103 | 104 | func (u *Timmessage) Scan(fieldname string, value any) { 105 | switch fieldname { 106 | case "id": 107 | u.SetId(base.AsInt64(value)) 108 | case "chatid": 109 | u.SetChatid(base.AsBytes(value)) 110 | case "fid": 111 | u.SetFid(base.AsInt64(value)) 112 | case "stanza": 113 | u.SetStanza(base.AsBytes(value)) 114 | case "timeseries": 115 | u.SetTimeseries(base.AsInt64(value)) 116 | } 117 | } 118 | 119 | func (t *Timmessage) ToGdao() { 120 | t.init("timmessage") 121 | } 122 | 123 | func (t *Timmessage) Copy(h *Timmessage) *Timmessage{ 124 | t.SetId(h.GetId()) 125 | t.SetChatid(h.GetChatid()) 126 | t.SetFid(h.GetFid()) 127 | t.SetStanza(h.GetStanza()) 128 | t.SetTimeseries(h.GetTimeseries()) 129 | return t 130 | } 131 | 132 | func (t *Timmessage) String() string { 133 | return fmt.Sprint("Id:",t.GetId(), ",","Chatid:",t.GetChatid(), ",","Fid:",t.GetFid(), ",","Stanza:",t.GetStanza(), ",","Timeseries:",t.GetTimeseries()) 134 | } 135 | 136 | func (t *Timmessage)init(tablename string) { 137 | t.ID = _Timmessage_ID 138 | t.CHATID = _Timmessage_CHATID 139 | t.FID = _Timmessage_FID 140 | t.STANZA = _Timmessage_STANZA 141 | t.TIMESERIES = _Timmessage_TIMESERIES 142 | t.Init(tablename, []base.Column[Timmessage]{t.ID,t.CHATID,t.FID,t.STANZA,t.TIMESERIES}) 143 | } 144 | 145 | func NewTimmessage(tablename ...string) (_r *Timmessage) { 146 | _r = &Timmessage{} 147 | s := "timmessage" 148 | if len(tablename) > 0 && tablename[0] != "" { 149 | s = tablename[0] 150 | } 151 | _r.init(s) 152 | return 153 | } 154 | 155 | func (t *Timmessage) Encode() ([]byte, error) { 156 | m := make(map[string]any, 0) 157 | m["id"] = t.GetId() 158 | m["chatid"] = t.GetChatid() 159 | m["fid"] = t.GetFid() 160 | m["stanza"] = t.GetStanza() 161 | m["timeseries"] = t.GetTimeseries() 162 | return t.Table.Encode(m) 163 | } 164 | 165 | func (t *Timmessage) Decode(bs []byte) (err error) { 166 | var m map[string]any 167 | if m, err = t.Table.Decode(bs); err == nil { 168 | if !t.IsInit() { 169 | t.ToGdao() 170 | } 171 | for name, bean := range m { 172 | t.Scan(name, bean) 173 | } 174 | } 175 | return 176 | } 177 | 178 | -------------------------------------------------------------------------------- /dao/timmucroster.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timmucroster 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timmucroster struct { 22 | gdao.Table[Timmucroster] 23 | 24 | ID *base.Field[Timmucroster] 25 | UNIKID *base.Field[Timmucroster] 26 | UUID *base.Field[Timmucroster] 27 | TUUID *base.Field[Timmucroster] 28 | TIMESERIES *base.Field[Timmucroster] 29 | _ID *int64 30 | _UNIKID []byte 31 | _UUID *int64 32 | _TUUID *int64 33 | _TIMESERIES *int64 34 | } 35 | 36 | var _Timmucroster_ID = &base.Field[Timmucroster]{"id"} 37 | var _Timmucroster_UNIKID = &base.Field[Timmucroster]{"unikid"} 38 | var _Timmucroster_UUID = &base.Field[Timmucroster]{"uuid"} 39 | var _Timmucroster_TUUID = &base.Field[Timmucroster]{"tuuid"} 40 | var _Timmucroster_TIMESERIES = &base.Field[Timmucroster]{"timeseries"} 41 | 42 | func (u *Timmucroster) GetId() (_r int64){ 43 | if u._ID != nil { 44 | _r = *u._ID 45 | } 46 | return 47 | } 48 | 49 | func (u *Timmucroster) SetId(arg int64) *Timmucroster{ 50 | u.Put0(u.ID.FieldName, arg) 51 | u._ID = &arg 52 | return u 53 | } 54 | 55 | func (u *Timmucroster) GetUnikid() (_r []byte){ 56 | _r = u._UNIKID 57 | return 58 | } 59 | 60 | func (u *Timmucroster) SetUnikid(arg []byte) *Timmucroster{ 61 | u.Put0(u.UNIKID.FieldName, arg) 62 | u._UNIKID = arg 63 | return u 64 | } 65 | 66 | func (u *Timmucroster) GetUuid() (_r int64){ 67 | if u._UUID != nil { 68 | _r = *u._UUID 69 | } 70 | return 71 | } 72 | 73 | func (u *Timmucroster) SetUuid(arg int64) *Timmucroster{ 74 | u.Put0(u.UUID.FieldName, arg) 75 | u._UUID = &arg 76 | return u 77 | } 78 | 79 | func (u *Timmucroster) GetTuuid() (_r int64){ 80 | if u._TUUID != nil { 81 | _r = *u._TUUID 82 | } 83 | return 84 | } 85 | 86 | func (u *Timmucroster) SetTuuid(arg int64) *Timmucroster{ 87 | u.Put0(u.TUUID.FieldName, arg) 88 | u._TUUID = &arg 89 | return u 90 | } 91 | 92 | func (u *Timmucroster) GetTimeseries() (_r int64){ 93 | if u._TIMESERIES != nil { 94 | _r = *u._TIMESERIES 95 | } 96 | return 97 | } 98 | 99 | func (u *Timmucroster) SetTimeseries(arg int64) *Timmucroster{ 100 | u.Put0(u.TIMESERIES.FieldName, arg) 101 | u._TIMESERIES = &arg 102 | return u 103 | } 104 | 105 | 106 | func (u *Timmucroster) Scan(fieldname string, value any) { 107 | switch fieldname { 108 | case "id": 109 | u.SetId(base.AsInt64(value)) 110 | case "unikid": 111 | u.SetUnikid(base.AsBytes(value)) 112 | case "uuid": 113 | u.SetUuid(base.AsInt64(value)) 114 | case "tuuid": 115 | u.SetTuuid(base.AsInt64(value)) 116 | case "timeseries": 117 | u.SetTimeseries(base.AsInt64(value)) 118 | } 119 | } 120 | 121 | func (t *Timmucroster) ToGdao() { 122 | t.init("timmucroster") 123 | } 124 | 125 | func (t *Timmucroster) Copy(h *Timmucroster) *Timmucroster{ 126 | t.SetId(h.GetId()) 127 | t.SetUnikid(h.GetUnikid()) 128 | t.SetUuid(h.GetUuid()) 129 | t.SetTuuid(h.GetTuuid()) 130 | t.SetTimeseries(h.GetTimeseries()) 131 | return t 132 | } 133 | 134 | func (t *Timmucroster) String() string { 135 | return fmt.Sprint("Id:",t.GetId(), ",","Unikid:",t.GetUnikid(), ",","Uuid:",t.GetUuid(), ",","Tuuid:",t.GetTuuid(), ",","Timeseries:",t.GetTimeseries()) 136 | } 137 | 138 | func (t *Timmucroster)init(tablename string) { 139 | t.ID = _Timmucroster_ID 140 | t.UNIKID = _Timmucroster_UNIKID 141 | t.UUID = _Timmucroster_UUID 142 | t.TUUID = _Timmucroster_TUUID 143 | t.TIMESERIES = _Timmucroster_TIMESERIES 144 | t.Init(tablename, []base.Column[Timmucroster]{t.ID,t.UNIKID,t.UUID,t.TUUID,t.TIMESERIES}) 145 | } 146 | 147 | func NewTimmucroster(tablename ...string) (_r *Timmucroster) { 148 | _r = &Timmucroster{} 149 | s := "timmucroster" 150 | if len(tablename) > 0 && tablename[0] != "" { 151 | s = tablename[0] 152 | } 153 | _r.init(s) 154 | return 155 | } 156 | 157 | func (t *Timmucroster) Encode() ([]byte, error) { 158 | m := make(map[string]any, 0) 159 | m["id"] = t.GetId() 160 | m["unikid"] = t.GetUnikid() 161 | m["uuid"] = t.GetUuid() 162 | m["tuuid"] = t.GetTuuid() 163 | m["timeseries"] = t.GetTimeseries() 164 | return t.Table.Encode(m) 165 | } 166 | 167 | func (t *Timmucroster) Decode(bs []byte) (err error) { 168 | var m map[string]any 169 | if m, err = t.Table.Decode(bs); err == nil { 170 | if !t.IsInit() { 171 | t.ToGdao() 172 | } 173 | for name, bean := range m { 174 | t.Scan(name, bean) 175 | } 176 | } 177 | return 178 | } 179 | 180 | -------------------------------------------------------------------------------- /dao/timoffline.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timoffline 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timoffline struct { 22 | gdao.Table[Timoffline] 23 | 24 | ID *base.Field[Timoffline] 25 | UUID *base.Field[Timoffline] 26 | CHATID *base.Field[Timoffline] 27 | STANZA *base.Field[Timoffline] 28 | MID *base.Field[Timoffline] 29 | TIMESERIES *base.Field[Timoffline] 30 | _ID *int64 31 | _UUID *int64 32 | _CHATID []byte 33 | _STANZA []byte 34 | _MID *int64 35 | _TIMESERIES *int64 36 | } 37 | 38 | var _Timoffline_ID = &base.Field[Timoffline]{"id"} 39 | var _Timoffline_UUID = &base.Field[Timoffline]{"uuid"} 40 | var _Timoffline_CHATID = &base.Field[Timoffline]{"chatid"} 41 | var _Timoffline_STANZA = &base.Field[Timoffline]{"stanza"} 42 | var _Timoffline_MID = &base.Field[Timoffline]{"mid"} 43 | var _Timoffline_TIMESERIES = &base.Field[Timoffline]{"timeseries"} 44 | 45 | func (u *Timoffline) GetId() (_r int64){ 46 | if u._ID != nil { 47 | _r = *u._ID 48 | } 49 | return 50 | } 51 | 52 | func (u *Timoffline) SetId(arg int64) *Timoffline{ 53 | u.Put0(u.ID.FieldName, arg) 54 | u._ID = &arg 55 | return u 56 | } 57 | 58 | func (u *Timoffline) GetUuid() (_r int64){ 59 | if u._UUID != nil { 60 | _r = *u._UUID 61 | } 62 | return 63 | } 64 | 65 | func (u *Timoffline) SetUuid(arg int64) *Timoffline{ 66 | u.Put0(u.UUID.FieldName, arg) 67 | u._UUID = &arg 68 | return u 69 | } 70 | 71 | func (u *Timoffline) GetChatid() (_r []byte){ 72 | _r = u._CHATID 73 | return 74 | } 75 | 76 | func (u *Timoffline) SetChatid(arg []byte) *Timoffline{ 77 | u.Put0(u.CHATID.FieldName, arg) 78 | u._CHATID = arg 79 | return u 80 | } 81 | 82 | func (u *Timoffline) GetStanza() (_r []byte){ 83 | _r = u._STANZA 84 | return 85 | } 86 | 87 | func (u *Timoffline) SetStanza(arg []byte) *Timoffline{ 88 | u.Put0(u.STANZA.FieldName, arg) 89 | u._STANZA = arg 90 | return u 91 | } 92 | 93 | func (u *Timoffline) GetMid() (_r int64){ 94 | if u._MID != nil { 95 | _r = *u._MID 96 | } 97 | return 98 | } 99 | 100 | func (u *Timoffline) SetMid(arg int64) *Timoffline{ 101 | u.Put0(u.MID.FieldName, arg) 102 | u._MID = &arg 103 | return u 104 | } 105 | 106 | func (u *Timoffline) GetTimeseries() (_r int64){ 107 | if u._TIMESERIES != nil { 108 | _r = *u._TIMESERIES 109 | } 110 | return 111 | } 112 | 113 | func (u *Timoffline) SetTimeseries(arg int64) *Timoffline{ 114 | u.Put0(u.TIMESERIES.FieldName, arg) 115 | u._TIMESERIES = &arg 116 | return u 117 | } 118 | 119 | 120 | func (u *Timoffline) Scan(fieldname string, value any) { 121 | switch fieldname { 122 | case "id": 123 | u.SetId(base.AsInt64(value)) 124 | case "uuid": 125 | u.SetUuid(base.AsInt64(value)) 126 | case "chatid": 127 | u.SetChatid(base.AsBytes(value)) 128 | case "stanza": 129 | u.SetStanza(base.AsBytes(value)) 130 | case "mid": 131 | u.SetMid(base.AsInt64(value)) 132 | case "timeseries": 133 | u.SetTimeseries(base.AsInt64(value)) 134 | } 135 | } 136 | 137 | func (t *Timoffline) ToGdao() { 138 | t.init("timoffline") 139 | } 140 | 141 | func (t *Timoffline) Copy(h *Timoffline) *Timoffline{ 142 | t.SetId(h.GetId()) 143 | t.SetUuid(h.GetUuid()) 144 | t.SetChatid(h.GetChatid()) 145 | t.SetStanza(h.GetStanza()) 146 | t.SetMid(h.GetMid()) 147 | t.SetTimeseries(h.GetTimeseries()) 148 | return t 149 | } 150 | 151 | func (t *Timoffline) String() string { 152 | return fmt.Sprint("Id:",t.GetId(), ",","Uuid:",t.GetUuid(), ",","Chatid:",t.GetChatid(), ",","Stanza:",t.GetStanza(), ",","Mid:",t.GetMid(), ",","Timeseries:",t.GetTimeseries()) 153 | } 154 | 155 | func (t *Timoffline)init(tablename string) { 156 | t.ID = _Timoffline_ID 157 | t.UUID = _Timoffline_UUID 158 | t.CHATID = _Timoffline_CHATID 159 | t.STANZA = _Timoffline_STANZA 160 | t.MID = _Timoffline_MID 161 | t.TIMESERIES = _Timoffline_TIMESERIES 162 | t.Init(tablename, []base.Column[Timoffline]{t.ID,t.UUID,t.CHATID,t.STANZA,t.MID,t.TIMESERIES}) 163 | } 164 | 165 | func NewTimoffline(tablename ...string) (_r *Timoffline) { 166 | _r = &Timoffline{} 167 | s := "timoffline" 168 | if len(tablename) > 0 && tablename[0] != "" { 169 | s = tablename[0] 170 | } 171 | _r.init(s) 172 | return 173 | } 174 | 175 | func (t *Timoffline) Encode() ([]byte, error) { 176 | m := make(map[string]any, 0) 177 | m["id"] = t.GetId() 178 | m["uuid"] = t.GetUuid() 179 | m["chatid"] = t.GetChatid() 180 | m["stanza"] = t.GetStanza() 181 | m["mid"] = t.GetMid() 182 | m["timeseries"] = t.GetTimeseries() 183 | return t.Table.Encode(m) 184 | } 185 | 186 | func (t *Timoffline) Decode(bs []byte) (err error) { 187 | var m map[string]any 188 | if m, err = t.Table.Decode(bs); err == nil { 189 | if !t.IsInit() { 190 | t.ToGdao() 191 | } 192 | for name, bean := range m { 193 | t.Scan(name, bean) 194 | } 195 | } 196 | return 197 | } 198 | 199 | -------------------------------------------------------------------------------- /dao/timrelate.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timrelate 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timrelate struct { 22 | gdao.Table[Timrelate] 23 | 24 | ID *base.Field[Timrelate] 25 | UUID *base.Field[Timrelate] 26 | STATUS *base.Field[Timrelate] 27 | TIMESERIES *base.Field[Timrelate] 28 | _ID *int64 29 | _UUID []byte 30 | _STATUS *int64 31 | _TIMESERIES *int64 32 | } 33 | 34 | var _Timrelate_ID = &base.Field[Timrelate]{"id"} 35 | var _Timrelate_UUID = &base.Field[Timrelate]{"uuid"} 36 | var _Timrelate_STATUS = &base.Field[Timrelate]{"status"} 37 | var _Timrelate_TIMESERIES = &base.Field[Timrelate]{"timeseries"} 38 | 39 | func (u *Timrelate) GetId() (_r int64){ 40 | if u._ID != nil { 41 | _r = *u._ID 42 | } 43 | return 44 | } 45 | 46 | func (u *Timrelate) SetId(arg int64) *Timrelate{ 47 | u.Put0(u.ID.FieldName, arg) 48 | u._ID = &arg 49 | return u 50 | } 51 | 52 | func (u *Timrelate) GetUuid() (_r []byte){ 53 | _r = u._UUID 54 | return 55 | } 56 | 57 | func (u *Timrelate) SetUuid(arg []byte) *Timrelate{ 58 | u.Put0(u.UUID.FieldName, arg) 59 | u._UUID = arg 60 | return u 61 | } 62 | 63 | func (u *Timrelate) GetStatus() (_r int64){ 64 | if u._STATUS != nil { 65 | _r = *u._STATUS 66 | } 67 | return 68 | } 69 | 70 | func (u *Timrelate) SetStatus(arg int64) *Timrelate{ 71 | u.Put0(u.STATUS.FieldName, arg) 72 | u._STATUS = &arg 73 | return u 74 | } 75 | 76 | func (u *Timrelate) GetTimeseries() (_r int64){ 77 | if u._TIMESERIES != nil { 78 | _r = *u._TIMESERIES 79 | } 80 | return 81 | } 82 | 83 | func (u *Timrelate) SetTimeseries(arg int64) *Timrelate{ 84 | u.Put0(u.TIMESERIES.FieldName, arg) 85 | u._TIMESERIES = &arg 86 | return u 87 | } 88 | 89 | 90 | func (u *Timrelate) Scan(fieldname string, value any) { 91 | switch fieldname { 92 | case "id": 93 | u.SetId(base.AsInt64(value)) 94 | case "uuid": 95 | u.SetUuid(base.AsBytes(value)) 96 | case "status": 97 | u.SetStatus(base.AsInt64(value)) 98 | case "timeseries": 99 | u.SetTimeseries(base.AsInt64(value)) 100 | } 101 | } 102 | 103 | func (t *Timrelate) ToGdao() { 104 | t.init("timrelate") 105 | } 106 | 107 | func (t *Timrelate) Copy(h *Timrelate) *Timrelate{ 108 | t.SetId(h.GetId()) 109 | t.SetUuid(h.GetUuid()) 110 | t.SetStatus(h.GetStatus()) 111 | t.SetTimeseries(h.GetTimeseries()) 112 | return t 113 | } 114 | 115 | func (t *Timrelate) String() string { 116 | return fmt.Sprint("Id:",t.GetId(), ",","Uuid:",t.GetUuid(), ",","Status:",t.GetStatus(), ",","Timeseries:",t.GetTimeseries()) 117 | } 118 | 119 | func (t *Timrelate)init(tablename string) { 120 | t.ID = _Timrelate_ID 121 | t.UUID = _Timrelate_UUID 122 | t.STATUS = _Timrelate_STATUS 123 | t.TIMESERIES = _Timrelate_TIMESERIES 124 | t.Init(tablename, []base.Column[Timrelate]{t.ID,t.UUID,t.STATUS,t.TIMESERIES}) 125 | } 126 | 127 | func NewTimrelate(tablename ...string) (_r *Timrelate) { 128 | _r = &Timrelate{} 129 | s := "timrelate" 130 | if len(tablename) > 0 && tablename[0] != "" { 131 | s = tablename[0] 132 | } 133 | _r.init(s) 134 | return 135 | } 136 | 137 | func (t *Timrelate) Encode() ([]byte, error) { 138 | m := make(map[string]any, 0) 139 | m["id"] = t.GetId() 140 | m["uuid"] = t.GetUuid() 141 | m["status"] = t.GetStatus() 142 | m["timeseries"] = t.GetTimeseries() 143 | return t.Table.Encode(m) 144 | } 145 | 146 | func (t *Timrelate) Decode(bs []byte) (err error) { 147 | var m map[string]any 148 | if m, err = t.Table.Decode(bs); err == nil { 149 | if !t.IsInit() { 150 | t.ToGdao() 151 | } 152 | for name, bean := range m { 153 | t.Scan(name, bean) 154 | } 155 | } 156 | return 157 | } 158 | 159 | -------------------------------------------------------------------------------- /dao/timroster.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timroster 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timroster struct { 22 | gdao.Table[Timroster] 23 | 24 | ID *base.Field[Timroster] 25 | UNIKID *base.Field[Timroster] 26 | UUID *base.Field[Timroster] 27 | TUUID *base.Field[Timroster] 28 | TIMESERIES *base.Field[Timroster] 29 | _ID *int64 30 | _UNIKID []byte 31 | _UUID *int64 32 | _TUUID *int64 33 | _TIMESERIES *int64 34 | } 35 | 36 | var _Timroster_ID = &base.Field[Timroster]{"id"} 37 | var _Timroster_UNIKID = &base.Field[Timroster]{"unikid"} 38 | var _Timroster_UUID = &base.Field[Timroster]{"uuid"} 39 | var _Timroster_TUUID = &base.Field[Timroster]{"tuuid"} 40 | var _Timroster_TIMESERIES = &base.Field[Timroster]{"timeseries"} 41 | 42 | func (u *Timroster) GetId() (_r int64){ 43 | if u._ID != nil { 44 | _r = *u._ID 45 | } 46 | return 47 | } 48 | 49 | func (u *Timroster) SetId(arg int64) *Timroster{ 50 | u.Put0(u.ID.FieldName, arg) 51 | u._ID = &arg 52 | return u 53 | } 54 | 55 | func (u *Timroster) GetUnikid() (_r []byte){ 56 | _r = u._UNIKID 57 | return 58 | } 59 | 60 | func (u *Timroster) SetUnikid(arg []byte) *Timroster{ 61 | u.Put0(u.UNIKID.FieldName, arg) 62 | u._UNIKID = arg 63 | return u 64 | } 65 | 66 | func (u *Timroster) GetUuid() (_r int64){ 67 | if u._UUID != nil { 68 | _r = *u._UUID 69 | } 70 | return 71 | } 72 | 73 | func (u *Timroster) SetUuid(arg int64) *Timroster{ 74 | u.Put0(u.UUID.FieldName, arg) 75 | u._UUID = &arg 76 | return u 77 | } 78 | 79 | func (u *Timroster) GetTuuid() (_r int64){ 80 | if u._TUUID != nil { 81 | _r = *u._TUUID 82 | } 83 | return 84 | } 85 | 86 | func (u *Timroster) SetTuuid(arg int64) *Timroster{ 87 | u.Put0(u.TUUID.FieldName, arg) 88 | u._TUUID = &arg 89 | return u 90 | } 91 | 92 | func (u *Timroster) GetTimeseries() (_r int64){ 93 | if u._TIMESERIES != nil { 94 | _r = *u._TIMESERIES 95 | } 96 | return 97 | } 98 | 99 | func (u *Timroster) SetTimeseries(arg int64) *Timroster{ 100 | u.Put0(u.TIMESERIES.FieldName, arg) 101 | u._TIMESERIES = &arg 102 | return u 103 | } 104 | 105 | 106 | func (u *Timroster) Scan(fieldname string, value any) { 107 | switch fieldname { 108 | case "id": 109 | u.SetId(base.AsInt64(value)) 110 | case "unikid": 111 | u.SetUnikid(base.AsBytes(value)) 112 | case "uuid": 113 | u.SetUuid(base.AsInt64(value)) 114 | case "tuuid": 115 | u.SetTuuid(base.AsInt64(value)) 116 | case "timeseries": 117 | u.SetTimeseries(base.AsInt64(value)) 118 | } 119 | } 120 | 121 | func (t *Timroster) ToGdao() { 122 | t.init("timroster") 123 | } 124 | 125 | func (t *Timroster) Copy(h *Timroster) *Timroster{ 126 | t.SetId(h.GetId()) 127 | t.SetUnikid(h.GetUnikid()) 128 | t.SetUuid(h.GetUuid()) 129 | t.SetTuuid(h.GetTuuid()) 130 | t.SetTimeseries(h.GetTimeseries()) 131 | return t 132 | } 133 | 134 | func (t *Timroster) String() string { 135 | return fmt.Sprint("Id:",t.GetId(), ",","Unikid:",t.GetUnikid(), ",","Uuid:",t.GetUuid(), ",","Tuuid:",t.GetTuuid(), ",","Timeseries:",t.GetTimeseries()) 136 | } 137 | 138 | func (t *Timroster)init(tablename string) { 139 | t.ID = _Timroster_ID 140 | t.UNIKID = _Timroster_UNIKID 141 | t.UUID = _Timroster_UUID 142 | t.TUUID = _Timroster_TUUID 143 | t.TIMESERIES = _Timroster_TIMESERIES 144 | t.Init(tablename, []base.Column[Timroster]{t.ID,t.UNIKID,t.UUID,t.TUUID,t.TIMESERIES}) 145 | } 146 | 147 | func NewTimroster(tablename ...string) (_r *Timroster) { 148 | _r = &Timroster{} 149 | s := "timroster" 150 | if len(tablename) > 0 && tablename[0] != "" { 151 | s = tablename[0] 152 | } 153 | _r.init(s) 154 | return 155 | } 156 | 157 | func (t *Timroster) Encode() ([]byte, error) { 158 | m := make(map[string]any, 0) 159 | m["id"] = t.GetId() 160 | m["unikid"] = t.GetUnikid() 161 | m["uuid"] = t.GetUuid() 162 | m["tuuid"] = t.GetTuuid() 163 | m["timeseries"] = t.GetTimeseries() 164 | return t.Table.Encode(m) 165 | } 166 | 167 | func (t *Timroster) Decode(bs []byte) (err error) { 168 | var m map[string]any 169 | if m, err = t.Table.Decode(bs); err == nil { 170 | if !t.IsInit() { 171 | t.ToGdao() 172 | } 173 | for name, bean := range m { 174 | t.Scan(name, bean) 175 | } 176 | } 177 | return 178 | } 179 | 180 | -------------------------------------------------------------------------------- /dao/timuser.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/gdao 7 | // 8 | // datetime :2025-01-06 18:18:47 9 | // gdao version 1.2.0 10 | // dbtype:sqlite ,database:timdb ,tablename:timuser 11 | 12 | package dao 13 | 14 | import ( 15 | "fmt" 16 | "github.com/donnie4w/gdao" 17 | "github.com/donnie4w/gdao/base" 18 | 19 | ) 20 | 21 | type Timuser struct { 22 | gdao.Table[Timuser] 23 | 24 | ID *base.Field[Timuser] 25 | UUID *base.Field[Timuser] 26 | PWD *base.Field[Timuser] 27 | CREATETIME *base.Field[Timuser] 28 | UBEAN *base.Field[Timuser] 29 | TIMESERIES *base.Field[Timuser] 30 | _ID *int64 31 | _UUID *int64 32 | _PWD *string 33 | _CREATETIME *int64 34 | _UBEAN []byte 35 | _TIMESERIES *int64 36 | } 37 | 38 | var _Timuser_ID = &base.Field[Timuser]{"id"} 39 | var _Timuser_UUID = &base.Field[Timuser]{"uuid"} 40 | var _Timuser_PWD = &base.Field[Timuser]{"pwd"} 41 | var _Timuser_CREATETIME = &base.Field[Timuser]{"createtime"} 42 | var _Timuser_UBEAN = &base.Field[Timuser]{"ubean"} 43 | var _Timuser_TIMESERIES = &base.Field[Timuser]{"timeseries"} 44 | 45 | func (u *Timuser) GetId() (_r int64){ 46 | if u._ID != nil { 47 | _r = *u._ID 48 | } 49 | return 50 | } 51 | 52 | func (u *Timuser) SetId(arg int64) *Timuser{ 53 | u.Put0(u.ID.FieldName, arg) 54 | u._ID = &arg 55 | return u 56 | } 57 | 58 | func (u *Timuser) GetUuid() (_r int64){ 59 | if u._UUID != nil { 60 | _r = *u._UUID 61 | } 62 | return 63 | } 64 | 65 | func (u *Timuser) SetUuid(arg int64) *Timuser{ 66 | u.Put0(u.UUID.FieldName, arg) 67 | u._UUID = &arg 68 | return u 69 | } 70 | 71 | func (u *Timuser) GetPwd() (_r string){ 72 | if u._PWD != nil { 73 | _r = *u._PWD 74 | } 75 | return 76 | } 77 | 78 | func (u *Timuser) SetPwd(arg string) *Timuser{ 79 | u.Put0(u.PWD.FieldName, arg) 80 | u._PWD = &arg 81 | return u 82 | } 83 | 84 | func (u *Timuser) GetCreatetime() (_r int64){ 85 | if u._CREATETIME != nil { 86 | _r = *u._CREATETIME 87 | } 88 | return 89 | } 90 | 91 | func (u *Timuser) SetCreatetime(arg int64) *Timuser{ 92 | u.Put0(u.CREATETIME.FieldName, arg) 93 | u._CREATETIME = &arg 94 | return u 95 | } 96 | 97 | func (u *Timuser) GetUbean() (_r []byte){ 98 | _r = u._UBEAN 99 | return 100 | } 101 | 102 | func (u *Timuser) SetUbean(arg []byte) *Timuser{ 103 | u.Put0(u.UBEAN.FieldName, arg) 104 | u._UBEAN = arg 105 | return u 106 | } 107 | 108 | func (u *Timuser) GetTimeseries() (_r int64){ 109 | if u._TIMESERIES != nil { 110 | _r = *u._TIMESERIES 111 | } 112 | return 113 | } 114 | 115 | func (u *Timuser) SetTimeseries(arg int64) *Timuser{ 116 | u.Put0(u.TIMESERIES.FieldName, arg) 117 | u._TIMESERIES = &arg 118 | return u 119 | } 120 | 121 | 122 | func (u *Timuser) Scan(fieldname string, value any) { 123 | switch fieldname { 124 | case "id": 125 | u.SetId(base.AsInt64(value)) 126 | case "uuid": 127 | u.SetUuid(base.AsInt64(value)) 128 | case "pwd": 129 | u.SetPwd(base.AsString(value)) 130 | case "createtime": 131 | u.SetCreatetime(base.AsInt64(value)) 132 | case "ubean": 133 | u.SetUbean(base.AsBytes(value)) 134 | case "timeseries": 135 | u.SetTimeseries(base.AsInt64(value)) 136 | } 137 | } 138 | 139 | func (t *Timuser) ToGdao() { 140 | t.init("timuser") 141 | } 142 | 143 | func (t *Timuser) Copy(h *Timuser) *Timuser{ 144 | t.SetId(h.GetId()) 145 | t.SetUuid(h.GetUuid()) 146 | t.SetPwd(h.GetPwd()) 147 | t.SetCreatetime(h.GetCreatetime()) 148 | t.SetUbean(h.GetUbean()) 149 | t.SetTimeseries(h.GetTimeseries()) 150 | return t 151 | } 152 | 153 | func (t *Timuser) String() string { 154 | return fmt.Sprint("Id:",t.GetId(), ",","Uuid:",t.GetUuid(), ",","Pwd:",t.GetPwd(), ",","Createtime:",t.GetCreatetime(), ",","Ubean:",t.GetUbean(), ",","Timeseries:",t.GetTimeseries()) 155 | } 156 | 157 | func (t *Timuser)init(tablename string) { 158 | t.ID = _Timuser_ID 159 | t.UUID = _Timuser_UUID 160 | t.PWD = _Timuser_PWD 161 | t.CREATETIME = _Timuser_CREATETIME 162 | t.UBEAN = _Timuser_UBEAN 163 | t.TIMESERIES = _Timuser_TIMESERIES 164 | t.Init(tablename, []base.Column[Timuser]{t.ID,t.UUID,t.PWD,t.CREATETIME,t.UBEAN,t.TIMESERIES}) 165 | } 166 | 167 | func NewTimuser(tablename ...string) (_r *Timuser) { 168 | _r = &Timuser{} 169 | s := "timuser" 170 | if len(tablename) > 0 && tablename[0] != "" { 171 | s = tablename[0] 172 | } 173 | _r.init(s) 174 | return 175 | } 176 | 177 | func (t *Timuser) Encode() ([]byte, error) { 178 | m := make(map[string]any, 0) 179 | m["id"] = t.GetId() 180 | m["uuid"] = t.GetUuid() 181 | m["pwd"] = t.GetPwd() 182 | m["createtime"] = t.GetCreatetime() 183 | m["ubean"] = t.GetUbean() 184 | m["timeseries"] = t.GetTimeseries() 185 | return t.Table.Encode(m) 186 | } 187 | 188 | func (t *Timuser) Decode(bs []byte) (err error) { 189 | var m map[string]any 190 | if m, err = t.Table.Decode(bs); err == nil { 191 | if !t.IsInit() { 192 | t.ToGdao() 193 | } 194 | for name, bean := range m { 195 | t.Scan(name, bean) 196 | } 197 | } 198 | return 199 | } 200 | 201 | -------------------------------------------------------------------------------- /dao/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package dao 9 | 10 | import "github.com/donnie4w/gofer/util" 11 | 12 | func (u *Timblock) Tid() uint64 { 13 | return uint64(u.GetUuid()) 14 | } 15 | 16 | func (u *Timuser) Tid() uint64 { 17 | return uint64(u.GetUuid()) 18 | } 19 | 20 | func (u *Timblockroom) Tid() uint64 { 21 | return uint64(u.GetUuid()) 22 | } 23 | 24 | func (u *Timroster) Tid() uint64 { 25 | return uint64(u.GetUuid()) 26 | } 27 | 28 | func (u *Timmessage) Tid() uint64 { 29 | return util.FNVHash64(u.GetChatid()) 30 | } 31 | 32 | func (u *Timrelate) Tid() uint64 { 33 | return util.FNVHash64(u.GetUuid()) 34 | } 35 | 36 | func (u *Timmucroster) Tid() uint64 { 37 | return uint64(u.GetUuid()) 38 | } 39 | 40 | func (u *Timoffline) Tid() uint64 { 41 | return uint64(u.GetUuid()) 42 | } 43 | 44 | func (u *Timdomain) Tid() uint64 { 45 | return uint64(u.GetId()) 46 | } 47 | -------------------------------------------------------------------------------- /data/cdhandle.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/tim/errs" 12 | "github.com/donnie4w/tim/stub" 13 | "github.com/donnie4w/tim/sys" 14 | ) 15 | 16 | type cassandraHandle struct{} 17 | 18 | func (ch *cassandraHandle) init() service { 19 | if err := camanager.init(); err != nil { 20 | panic(err) 21 | } 22 | return ch 23 | } 24 | 25 | func (ch *cassandraHandle) Register(username, pwd string, domain *string) (node string, e errs.ERROR) { 26 | e = errs.ERR_DATABASE 27 | return 28 | } 29 | 30 | func (ch *cassandraHandle) Login(username, pwd string, domain *string) (_r string, e errs.ERROR) { 31 | _r = username 32 | return 33 | } 34 | 35 | func (ch *cassandraHandle) Modify(uint64, *string, string, *string) (e errs.ERROR) { 36 | return 37 | } 38 | 39 | func (ch *cassandraHandle) AuthNode(username, pwd string, domain *string) (_r string, err errs.ERROR) { 40 | _r = username 41 | return 42 | } 43 | 44 | func (ch *cassandraHandle) SaveMessage(tm *stub.TimMessage) (err error) { 45 | return 46 | } 47 | 48 | func (ch *cassandraHandle) GetMessage(fromNode string, domain *string, rtype int8, to string, mid, timestamp, limit int64) (tmList []*stub.TimMessage, err error) { 49 | return 50 | } 51 | 52 | func (ch *cassandraHandle) GetFidByMid(tid []byte, mid int64) (fid int64, err error) { 53 | return 54 | } 55 | 56 | func (ch *cassandraHandle) DelMessageByMid(tid []byte, mid int64) (err error) { 57 | return 58 | } 59 | 60 | func (ch *cassandraHandle) SaveOfflineMessage(string, *stub.TimMessage) (err error) { 61 | return 62 | } 63 | 64 | func (ch *cassandraHandle) GetOfflineMessage(node string, limit int) (oblist []*OfflineBean, err error) { 65 | return 66 | } 67 | 68 | func (ch *cassandraHandle) DelOfflineMessage(tid uint64, ids ...any) (_r int64, err error) { 69 | return 70 | } 71 | 72 | func (ch *cassandraHandle) UserGroup(node string, domain *string) (_r []string) { 73 | return 74 | } 75 | 76 | func (ch *cassandraHandle) GroupRoster(groupnode string) (_r []string) { 77 | return 78 | } 79 | 80 | func (ch *cassandraHandle) AuthGroupAndUser(groupnode, usernode string, domain *string) (ok bool, err error) { 81 | ok = true 82 | return 83 | } 84 | 85 | /***************************************************************************************************************/ 86 | 87 | func (ch *cassandraHandle) Roster(node string) (_r []string) { 88 | return 89 | } 90 | 91 | func (ch *cassandraHandle) Blockrosterlist(string) (_r []string) { 92 | return 93 | } 94 | func (ch *cassandraHandle) Blockroomlist(string) (_r []string) { 95 | return 96 | } 97 | func (ch *cassandraHandle) Blockroommemberlist(string, string) (_r []string) { 98 | return 99 | } 100 | 101 | func (ch *cassandraHandle) AuthUserAndUser(fnode, tnode string, domain *string) (_r bool) { 102 | return true 103 | } 104 | 105 | func (ch *cassandraHandle) ExistUser(node string) (_r bool) { 106 | return true 107 | } 108 | 109 | func (ch *cassandraHandle) ExistGroup(node string) (_r bool) { 110 | return true 111 | } 112 | 113 | func (ch *cassandraHandle) Addroster(fnode, tnode string, domain *string) (status int8, err errs.ERROR) { 114 | err = errs.ERR_DATABASE 115 | return 116 | } 117 | 118 | func (ch *cassandraHandle) Rmroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 119 | ok = false 120 | return 121 | } 122 | 123 | func (ch *cassandraHandle) Blockroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 124 | ok = false 125 | return 126 | } 127 | 128 | func (ch *cassandraHandle) GroupGtype(groupnode string, domain *string) (gtype int8, err errs.ERROR) { 129 | err = errs.ERR_DATABASE 130 | return 131 | } 132 | 133 | func (ch *cassandraHandle) GroupManagers(groupnode string, domain *string) (s []string, err errs.ERROR) { 134 | return 135 | } 136 | 137 | func (ch *cassandraHandle) Newgroup(fnode, groupname string, gtype sys.TIMTYPE, domain *string) (gnode string, err errs.ERROR) { 138 | return 139 | } 140 | 141 | func (ch *cassandraHandle) Addgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 142 | return errs.ERR_DATABASE 143 | } 144 | 145 | func (ch *cassandraHandle) Pullgroup(groupnode, fromnode, tonode string, domain *string) (isReq bool, err errs.ERROR) { 146 | err = errs.ERR_DATABASE 147 | return 148 | } 149 | 150 | func (ch *cassandraHandle) Nopassgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 151 | return errs.ERR_DATABASE 152 | } 153 | 154 | func (ch *cassandraHandle) Kickgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 155 | return errs.ERR_DATABASE 156 | } 157 | func (ch *cassandraHandle) Leavegroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 158 | return errs.ERR_DATABASE 159 | } 160 | 161 | func (ch *cassandraHandle) Cancelgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 162 | return errs.ERR_DATABASE 163 | } 164 | 165 | func (ch *cassandraHandle) Blockgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 166 | return errs.ERR_DATABASE 167 | } 168 | func (ch *cassandraHandle) Blockgroupmember(groupnode, fromnode, tonodme string, domain *string) (err errs.ERROR) { 169 | return errs.ERR_DATABASE 170 | } 171 | 172 | func (ch *cassandraHandle) ModifygroupInfo(node, fnode string, tu *stub.TimRoomBean, admin bool) (err errs.ERROR) { 173 | return errs.ERR_DATABASE 174 | } 175 | func (ch *cassandraHandle) GetGroupInfo(node []string) (m map[string]*stub.TimRoomBean, err errs.ERROR) { 176 | err = errs.ERR_DATABASE 177 | return 178 | } 179 | func (ch *cassandraHandle) ModifyUserInfo(node string, tu *stub.TimUserBean) (err errs.ERROR) { 180 | return errs.ERR_DATABASE 181 | } 182 | func (ch *cassandraHandle) GetUserInfo(node []string) (m map[string]*stub.TimUserBean, err errs.ERROR) { 183 | err = errs.ERR_DATABASE 184 | return 185 | } 186 | func (ch *cassandraHandle) TimAdminAuth(account, password, domain string) bool { 187 | return true 188 | } 189 | -------------------------------------------------------------------------------- /data/exbranch.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/tim/errs" 12 | "github.com/donnie4w/tim/stub" 13 | "github.com/donnie4w/tim/sys" 14 | ) 15 | 16 | func (eh *externHandle) UserGroup(node string, domain *string) []string { 17 | return eh.externdb.userGroup(node) 18 | } 19 | 20 | func (eh *externHandle) GroupRoster(groupnode string) []string { 21 | return eh.externdb.groupRoster(groupnode) 22 | } 23 | 24 | func (eh *externHandle) Roster(node string) []string { 25 | return eh.externdb.roster(node) 26 | } 27 | 28 | func (eh *externHandle) Blockrosterlist(string) (_r []string) { 29 | return 30 | } 31 | 32 | func (eh *externHandle) Blockroomlist(string) (_r []string) { 33 | return 34 | } 35 | 36 | func (eh *externHandle) Blockroommemberlist(string, string) (_r []string) { 37 | return 38 | } 39 | 40 | func (eh *externHandle) AuthUserAndUser(fnode, tnode string, domain *string) (_r bool) { 41 | _r, _ = eh.externdb.authUser(fnode, tnode) 42 | return 43 | } 44 | 45 | func (eh *externHandle) ExistUser(node string) (_r bool) { 46 | _r, _ = eh.externdb.existUser(node) 47 | return 48 | } 49 | 50 | func (eh *externHandle) ExistGroup(node string) (_r bool) { 51 | _r, _ = eh.externdb.existGroup(node) 52 | return 53 | } 54 | 55 | func (eh *externHandle) Addroster(fnode, tnode string, domain *string) (status int8, err errs.ERROR) { 56 | err = errs.ERR_INTERFACE 57 | return 58 | } 59 | 60 | func (eh *externHandle) Rmroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 61 | return 62 | } 63 | 64 | func (eh *externHandle) Blockroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 65 | return 66 | } 67 | 68 | func (eh *externHandle) GroupGtype(groupnode string, domain *string) (gtype int8, err errs.ERROR) { 69 | err = errs.ERR_INTERFACE 70 | return 71 | } 72 | 73 | func (eh *externHandle) GroupManagers(groupnode string, domain *string) (s []string, err errs.ERROR) { 74 | err = errs.ERR_INTERFACE 75 | return 76 | } 77 | 78 | func (eh *externHandle) Newgroup(fnode, groupname string, gtype sys.TIMTYPE, domain *string) (gnode string, err errs.ERROR) { 79 | err = errs.ERR_INTERFACE 80 | return 81 | } 82 | 83 | func (eh *externHandle) Addgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 84 | err = errs.ERR_INTERFACE 85 | return 86 | } 87 | 88 | func (eh *externHandle) Pullgroup(groupnode, fromnode, tonode string, domain *string) (isReq bool, err errs.ERROR) { 89 | err = errs.ERR_INTERFACE 90 | return 91 | } 92 | 93 | func (eh *externHandle) Nopassgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 94 | err = errs.ERR_INTERFACE 95 | return 96 | } 97 | 98 | func (eh *externHandle) Kickgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 99 | err = errs.ERR_INTERFACE 100 | return 101 | } 102 | func (eh *externHandle) Leavegroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 103 | err = errs.ERR_INTERFACE 104 | return 105 | } 106 | 107 | func (eh *externHandle) Cancelgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 108 | err = errs.ERR_INTERFACE 109 | return 110 | } 111 | 112 | func (eh *externHandle) Blockgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 113 | err = errs.ERR_INTERFACE 114 | return 115 | } 116 | 117 | func (eh *externHandle) Blockgroupmember(groupnode, fromnode, tonodme string, domain *string) (err errs.ERROR) { 118 | err = errs.ERR_INTERFACE 119 | return 120 | } 121 | 122 | func (eh *externHandle) ModifyUserInfo(node string, tu *stub.TimUserBean) (err errs.ERROR) { 123 | return 124 | } 125 | func (eh *externHandle) GetUserInfo(node []string) (m map[string]*stub.TimUserBean, err errs.ERROR) { 126 | return 127 | } 128 | 129 | func (eh *externHandle) ModifygroupInfo(node, fnode string, tu *stub.TimRoomBean, admin bool) (err errs.ERROR) { 130 | return 131 | } 132 | func (eh *externHandle) GetGroupInfo(node []string) (m map[string]*stub.TimRoomBean, err errs.ERROR) { 133 | return 134 | } 135 | 136 | func (eh *externHandle) TimAdminAuth(account, password, domain string) bool { 137 | return false 138 | } 139 | -------------------------------------------------------------------------------- /data/exhandle.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | goutil "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/errs" 13 | "github.com/donnie4w/tim/stub" 14 | "github.com/donnie4w/tim/sys" 15 | "github.com/donnie4w/tim/util" 16 | ) 17 | 18 | type externHandle struct { 19 | externdb *externdb 20 | } 21 | 22 | func (eh *externHandle) init() service { 23 | eh.externdb = &externdb{} 24 | eh.externdb.init() 25 | return eh 26 | } 27 | 28 | func (eh *externHandle) Register(username, pwd string, domain *string) (node string, e errs.ERROR) { 29 | e = errs.ERR_INTERFACE 30 | return 31 | } 32 | 33 | func (eh *externHandle) Login(username, pwd string, domain *string) (_r string, e errs.ERROR) { 34 | if _r, _ = eh.externdb.login(username, pwd); _r != "" { 35 | return 36 | } 37 | e = errs.ERR_NOPASS 38 | return 39 | } 40 | 41 | func (eh *externHandle) Modify(uint64, *string, string, *string) errs.ERROR { 42 | return errs.ERR_PERM_DENIED 43 | } 44 | 45 | func (eh *externHandle) AuthNode(username, pwd string, domain *string) (node string, err errs.ERROR) { 46 | if node, _ = eh.externdb.authNode(username, pwd); node != "" { 47 | return 48 | } 49 | err = errs.ERR_NOPASS 50 | return 51 | } 52 | 53 | func (eh *externHandle) SaveMessage(tm *stub.TimMessage) (err error) { 54 | id := *tm.ID 55 | tm.ID = nil 56 | var chatId []byte 57 | if tm.MsType == sys.SOURCE_ROOM { 58 | chatId = util.ChatIdByRoom(tm.RoomTid.Node, tm.FromTid.Domain) 59 | } else { 60 | chatId = util.ChatIdByNode(tm.FromTid.Node, tm.ToTid.Node, tm.FromTid.Domain) 61 | } 62 | fid := tm.FromTid 63 | tm.FromTid = &stub.Tid{Node: fid.Node} 64 | stanze := util.Mask(goutil.TEncode(tm)) 65 | var mid int64 66 | mid, err = eh.externdb.saveMessage(chatId, int32(goutil.FNVHash32([]byte(fid.Node))), stanze) 67 | tm.Mid = &mid 68 | if id == 0 { 69 | id = goutil.UUID64() 70 | } 71 | tm.ID = &id 72 | tm.FromTid = fid 73 | return 74 | } 75 | 76 | func (eh *externHandle) GetMessage(fromNode string, domain *string, rtype int8, to string, mid, timeseries, limit int64) (tmList []*stub.TimMessage, err error) { 77 | var chatId []byte 78 | if rtype == 1 { 79 | chatId = util.ChatIdByNode(fromNode, to, domain) 80 | } else { 81 | chatId = util.ChatIdByRoom(to, domain) 82 | } 83 | if rs, e := eh.externdb.getmessage(chatId, mid, timeseries, limit); e == nil { 84 | tmList = make([]*stub.TimMessage, 0) 85 | for k, v := range rs { 86 | if tm, err := goutil.TDecode(util.Mask(v), &stub.TimMessage{}); err == nil { 87 | tm.Mid = &k 88 | tmList = append(tmList, tm) 89 | } 90 | } 91 | } else { 92 | err = e 93 | } 94 | return 95 | } 96 | 97 | func (eh *externHandle) GetFidByMid(tid []byte, mid int64) (int64, error) { 98 | if mid <= 0 { 99 | return 0, errs.ERR_PARAMS.Error() 100 | } 101 | return eh.externdb.getFidById(tid, mid) 102 | } 103 | 104 | func (eh *externHandle) DelMessageByMid(tid []byte, mid int64) (err error) { 105 | return eh.externdb.delMessageById(mid) 106 | } 107 | 108 | func (eh *externHandle) SaveOfflineMessage(tnode string, tm *stub.TimMessage) (err error) { 109 | fid := tm.FromTid 110 | if fid != nil { 111 | tm.FromTid = &stub.Tid{Node: fid.Node} 112 | } 113 | mid := int64(0) 114 | if tm.OdType == sys.ORDER_INOF { 115 | mid = tm.GetMid() 116 | } 117 | err = eh.externdb.saveOfflineMessage(tnode, tm.GetID(), util.Mask(goutil.TEncode(tm)), mid) 118 | tm.FromTid = fid 119 | return 120 | } 121 | 122 | func (eh *externHandle) GetOfflineMessage(node string, limit int) (oblist []*OfflineBean, err error) { 123 | if oblist, err = eh.externdb.getOfflineMessage(node, limit); err == nil { 124 | for _, ob := range oblist { 125 | ob.Stanze = util.Mask(ob.Stanze) 126 | } 127 | } 128 | return 129 | } 130 | 131 | func (eh *externHandle) DelOfflineMessage(tid uint64, ids ...any) (_r int64, err error) { 132 | return eh.externdb.delOfflineMessage(ids...) 133 | } 134 | 135 | func (eh *externHandle) AuthGroupAndUser(groupnode, usernode string, domain *string) (ok bool, err error) { 136 | return eh.externdb.authGroup(groupnode, usernode) 137 | } 138 | -------------------------------------------------------------------------------- /data/gdao.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "database/sql" 12 | _ "github.com/denisenkom/go-mssqldb" 13 | "github.com/donnie4w/gdao" 14 | "github.com/donnie4w/gdao/base" 15 | "github.com/donnie4w/tim/stub" 16 | "github.com/donnie4w/tim/sys" 17 | _ "github.com/go-sql-driver/mysql" 18 | _ "github.com/godror/godror" 19 | _ "github.com/lib/pq" 20 | _ "github.com/mattn/go-sqlite3" 21 | "sort" 22 | ) 23 | 24 | func getDBhandle(driverName, dsn string) (dbhandle base.DBhandle, err error) { 25 | if db, er := sql.Open(driverName, dsn); er == nil { 26 | if err = db.Ping(); err == nil { 27 | dbhandle = gdao.NewDBHandle(db, getDBtype(driverName)) 28 | } 29 | } else { 30 | err = er 31 | } 32 | return 33 | } 34 | 35 | func getDBtype(driverName string) (dbType base.DBType) { 36 | switch driverName { 37 | case Driver_Mysql: 38 | dbType = gdao.MYSQL 39 | case Driver_Postgres: 40 | dbType = gdao.POSTGRESQL 41 | case Driver_Sqlite: 42 | dbType = gdao.SQLITE 43 | case Driver_Oracle: 44 | dbType = gdao.ORACLE 45 | case Driver_Sqlserver: 46 | dbType = gdao.SQLSERVER 47 | } 48 | return 49 | } 50 | 51 | var gdaoHandle = &sourceHandle{dbsource: make([]*sqlsource, 0)} 52 | 53 | type sqlsource struct { 54 | extent int 55 | dbhandle base.DBhandle 56 | } 57 | 58 | type sourceHandle struct { 59 | dbsource []*sqlsource 60 | } 61 | 62 | func (sh *sourceHandle) AddConnect(dbType base.DBType, connect *stub.Connect, extent int) error { 63 | if extent == 0 { 64 | extent = sys.MB 65 | } 66 | driver, dsn := connect.DSN(dbType) 67 | if dbhandle, err := getDBhandle(driver, dsn); err == nil { 68 | initLocalDB(dbhandle, driver) 69 | sh.dbsource = append(sh.dbsource, &sqlsource{extent: extent, dbhandle: dbhandle}) 70 | } else { 71 | return err 72 | } 73 | sort.Slice(sh.dbsource, func(i, j int) bool { return sh.dbsource[i].extent < sh.dbsource[j].extent }) 74 | return nil 75 | } 76 | 77 | func (sh *sourceHandle) AddInlineDB(v *stub.InlineDB) error { 78 | if v.SQLITE != nil { 79 | return sh.AddConnect(gdao.SQLITE, v.SQLITE, v.ExtentMax) 80 | } else if v.POSTGRESQL != nil { 81 | return sh.AddConnect(gdao.POSTGRESQL, v.POSTGRESQL, v.ExtentMax) 82 | } else if v.GREENPLUM != nil { 83 | return sh.AddConnect(gdao.GREENPLUM, v.GREENPLUM, v.ExtentMax) 84 | } else if v.OPENGAUSS != nil { 85 | return sh.AddConnect(gdao.OPENGAUSS, v.OPENGAUSS, v.ExtentMax) 86 | } else if v.COCKROACHDB != nil { 87 | return sh.AddConnect(gdao.COCKROACHDB, v.COCKROACHDB, v.ExtentMax) 88 | } else if v.ENTERPRISEDB != nil { 89 | return sh.AddConnect(gdao.ENTERPRISEDB, v.ENTERPRISEDB, v.ExtentMax) 90 | } else if v.MYSQL != nil { 91 | return sh.AddConnect(gdao.MYSQL, v.MYSQL, v.ExtentMax) 92 | } else if v.MARIADB != nil { 93 | return sh.AddConnect(gdao.MARIADB, v.MARIADB, v.ExtentMax) 94 | } else if v.OCEANBASE != nil { 95 | return sh.AddConnect(gdao.OCEANBASE, v.OCEANBASE, v.ExtentMax) 96 | } else if v.TIDB != nil { 97 | return sh.AddConnect(gdao.TIDB, v.TIDB, v.ExtentMax) 98 | } else if v.SQLSERVER != nil { 99 | return sh.AddConnect(gdao.SQLSERVER, v.SQLSERVER, v.ExtentMax) 100 | } else if v.ORACLE != nil { 101 | return sh.AddConnect(gdao.ORACLE, v.ORACLE, v.ExtentMax) 102 | } else { 103 | return sh.AddConnect(gdao.SQLITE, &stub.Connect{DBname: localdb}, v.ExtentMax) 104 | } 105 | } 106 | 107 | func (sh *sourceHandle) GetDBHandle(tid uint64) base.DBhandle { 108 | if len(sh.dbsource) == 0 { 109 | return nil 110 | } 111 | if len(sh.dbsource) == 1 || (tid == 0) { 112 | return sh.dbsource[0].dbhandle 113 | } 114 | idx := 0 115 | if idx = sort.Search(len(sh.dbsource), func(i int) bool { return sh.dbsource[i].extent >= int(tid%sys.MB) }); idx >= len(sh.dbsource) { 116 | idx = 0 117 | } 118 | return sh.dbsource[idx].dbhandle 119 | } 120 | 121 | func (sh *sourceHandle) FirstDBHandle() base.DBhandle { 122 | if len(sh.dbsource) > 0 { 123 | return sh.dbsource[0].dbhandle 124 | } 125 | return nil 126 | } 127 | -------------------------------------------------------------------------------- /data/inutil.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of t source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | goutil "github.com/donnie4w/gofer/util" 12 | "github.com/donnie4w/tim/dao" 13 | "github.com/donnie4w/tim/stub" 14 | ) 15 | 16 | func newTimuser(uuid uint64) *dao.Timuser { 17 | tu := dao.NewTimuser() 18 | tu.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 19 | return tu 20 | } 21 | 22 | func newTimmessage(chatId uint64) *dao.Timmessage { 23 | tm := dao.NewTimmessage() 24 | tm.UseDBHandle(gdaoHandle.GetDBHandle(chatId)) 25 | return tm 26 | } 27 | 28 | func newTimblock(uuid uint64) *dao.Timblock { 29 | tm := dao.NewTimblock() 30 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 31 | return tm 32 | } 33 | 34 | func newTimblockroom(uuid uint64) *dao.Timblockroom { 35 | tm := dao.NewTimblockroom() 36 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 37 | return tm 38 | } 39 | 40 | func newTimoffline(uuid uint64) *dao.Timoffline { 41 | tm := dao.NewTimoffline() 42 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 43 | return tm 44 | } 45 | 46 | func newTimgroup(uuid uint64) *dao.Timgroup { 47 | tm := dao.NewTimgroup() 48 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 49 | return tm 50 | } 51 | 52 | func newTimrelate(uuid uint64) *dao.Timrelate { 53 | tm := dao.NewTimrelate() 54 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 55 | return tm 56 | } 57 | 58 | func newTimroster(uuid uint64) *dao.Timroster { 59 | tm := dao.NewTimroster() 60 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 61 | return tm 62 | } 63 | 64 | func newTimmucroster(uuid uint64) *dao.Timmucroster { 65 | tm := dao.NewTimmucroster() 66 | tm.UseDBHandle(gdaoHandle.GetDBHandle(uuid)) 67 | return tm 68 | } 69 | 70 | func newTimdomain() *dao.Timdomain { 71 | tm := dao.NewTimdomain() 72 | tm.UseDBHandle(gdaoHandle.GetDBHandle(0)) 73 | return tm 74 | } 75 | 76 | func checkuseruuidGdao(uuids ...uint64) bool { 77 | for _, uuid := range uuids { 78 | idbs := goutil.Int64ToBytes(int64(uuid)) 79 | if uuidCache.Contains(idbs) { 80 | continue 81 | } 82 | tu := newTimuser(uuid) 83 | tu.Where(tu.UUID.EQ(int64(uuid))) 84 | if tu, _ := tu.Select(tu.ID); tu != nil && tu.GetId() > 0 { 85 | uuidCache.Add(idbs) 86 | continue 87 | } else { 88 | return false 89 | } 90 | } 91 | return true 92 | } 93 | 94 | func checkgroupuuid(uuids ...uint64) bool { 95 | for _, uuid := range uuids { 96 | idbs := goutil.Int64ToBytes(int64(uuid)) 97 | if uuidCache.Contains(idbs) { 98 | continue 99 | } 100 | tu := newTimgroup(uuid) 101 | tu.Where(tu.UUID.EQ(int64(uuid))) 102 | if tu, _ := tu.Select(tu.ID); tu != nil && tu.GetId() > 0 { 103 | uuidCache.Add(idbs) 104 | continue 105 | } else { 106 | return false 107 | } 108 | } 109 | return true 110 | } 111 | 112 | func defaultInlineDB() *stub.InlineDB { 113 | return &stub.InlineDB{SQLITE: &stub.Connect{DBname: "tim.db"}} 114 | } 115 | -------------------------------------------------------------------------------- /data/nohandle.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of n source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/tim/errs" 12 | "github.com/donnie4w/tim/log" 13 | . "github.com/donnie4w/tim/stub" 14 | "github.com/donnie4w/tim/sys" 15 | ) 16 | 17 | type nodbHandle struct{} 18 | 19 | func (n *nodbHandle) init() service { 20 | log.FmtPrint("No database schema") 21 | return n 22 | } 23 | 24 | func (n *nodbHandle) Register(username, pwd string, domain *string) (node string, e errs.ERROR) { 25 | e = errs.ERR_DATABASE 26 | return 27 | } 28 | 29 | func (n *nodbHandle) Login(username, pwd string, domain *string) (_r string, e errs.ERROR) { 30 | _r = username 31 | return 32 | } 33 | 34 | func (n *nodbHandle) Modify(uint64, *string, string, *string) (e errs.ERROR) { 35 | return 36 | } 37 | 38 | func (n *nodbHandle) AuthNode(username, pwd string, domain *string) (_r string, err errs.ERROR) { 39 | _r = username 40 | return 41 | } 42 | 43 | func (n *nodbHandle) SaveMessage(tm *TimMessage) (err error) { 44 | return 45 | } 46 | 47 | func (n *nodbHandle) GetMessage(fromNode string, domain *string, rtype int8, to string, mid, timestamp, limit int64) (tmList []*TimMessage, err error) { 48 | return 49 | } 50 | 51 | func (n *nodbHandle) GetFidByMid(tid []byte, mid int64) (fid int64, err error) { 52 | return 53 | } 54 | 55 | func (n *nodbHandle) DelMessageByMid(tid []byte, mid int64) (err error) { 56 | return 57 | } 58 | 59 | func (n *nodbHandle) SaveOfflineMessage(string, *TimMessage) (err error) { 60 | return 61 | } 62 | 63 | func (n *nodbHandle) GetOfflineMessage(node string, limit int) (oblist []*OfflineBean, err error) { 64 | return 65 | } 66 | 67 | func (n *nodbHandle) DelOfflineMessage(tid uint64, ids ...any) (_r int64, err error) { 68 | return 69 | } 70 | 71 | func (n *nodbHandle) UserGroup(node string, domain *string) (_r []string) { 72 | return 73 | } 74 | 75 | func (n *nodbHandle) GroupRoster(groupnode string) (_r []string) { 76 | return 77 | } 78 | 79 | func (n *nodbHandle) AuthGroupAndUser(groupnode, usernode string, domain *string) (ok bool, err error) { 80 | ok = true 81 | return 82 | } 83 | 84 | /***************************************************************************************************************/ 85 | 86 | func (n *nodbHandle) Roster(node string) (_r []string) { 87 | return 88 | } 89 | 90 | func (n *nodbHandle) Blockrosterlist(string) (_r []string) { 91 | return 92 | } 93 | func (n *nodbHandle) Blockroomlist(string) (_r []string) { 94 | return 95 | } 96 | func (n *nodbHandle) Blockroommemberlist(string, string) (_r []string) { 97 | return 98 | } 99 | 100 | func (n *nodbHandle) AuthUserAndUser(fnode, tnode string, domain *string) (_r bool) { 101 | return true 102 | } 103 | 104 | func (n *nodbHandle) ExistUser(node string) (_r bool) { 105 | return true 106 | } 107 | 108 | func (n *nodbHandle) ExistGroup(node string) (_r bool) { 109 | return true 110 | } 111 | 112 | func (n *nodbHandle) Addroster(fnode, tnode string, domain *string) (status int8, err errs.ERROR) { 113 | err = errs.ERR_DATABASE 114 | return 115 | } 116 | 117 | func (n *nodbHandle) Rmroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 118 | ok = false 119 | return 120 | } 121 | 122 | func (n *nodbHandle) Blockroster(fnode, tnode string, domain *string) (mstell bool, ok bool) { 123 | ok = false 124 | return 125 | } 126 | 127 | func (n *nodbHandle) GroupGtype(groupnode string, domain *string) (gtype int8, err errs.ERROR) { 128 | err = errs.ERR_DATABASE 129 | return 130 | } 131 | 132 | func (n *nodbHandle) GroupManagers(groupnode string, domain *string) (s []string, err errs.ERROR) { 133 | return 134 | } 135 | 136 | func (n *nodbHandle) Newgroup(fnode, groupname string, gtype sys.TIMTYPE, domain *string) (gnode string, err errs.ERROR) { 137 | return 138 | } 139 | 140 | func (n *nodbHandle) Addgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 141 | return errs.ERR_DATABASE 142 | } 143 | 144 | func (n *nodbHandle) Pullgroup(groupnode, fromnode, tonode string, domain *string) (isReq bool, err errs.ERROR) { 145 | err = errs.ERR_DATABASE 146 | return 147 | } 148 | 149 | func (n *nodbHandle) Nopassgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 150 | return errs.ERR_DATABASE 151 | } 152 | 153 | func (n *nodbHandle) Kickgroup(groupnode, fromnode, tonode string, domain *string) (err errs.ERROR) { 154 | return errs.ERR_DATABASE 155 | } 156 | func (n *nodbHandle) Leavegroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 157 | return errs.ERR_DATABASE 158 | } 159 | 160 | func (n *nodbHandle) Cancelgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 161 | return errs.ERR_DATABASE 162 | } 163 | 164 | func (n *nodbHandle) Blockgroup(groupnode, fromnode string, domain *string) (err errs.ERROR) { 165 | return errs.ERR_DATABASE 166 | } 167 | func (n *nodbHandle) Blockgroupmember(groupnode, fromnode, tonodme string, domain *string) (err errs.ERROR) { 168 | return errs.ERR_DATABASE 169 | } 170 | 171 | func (n *nodbHandle) ModifygroupInfo(node, fnode string, tu *TimRoomBean, admin bool) (err errs.ERROR) { 172 | return errs.ERR_DATABASE 173 | } 174 | func (n *nodbHandle) GetGroupInfo(node []string) (m map[string]*TimRoomBean, err errs.ERROR) { 175 | err = errs.ERR_DATABASE 176 | return 177 | } 178 | func (n *nodbHandle) ModifyUserInfo(node string, tu *TimUserBean) (err errs.ERROR) { 179 | return errs.ERR_DATABASE 180 | } 181 | func (n *nodbHandle) GetUserInfo(node []string) (m map[string]*TimUserBean, err errs.ERROR) { 182 | err = errs.ERR_DATABASE 183 | return 184 | } 185 | func (n *nodbHandle) TimAdminAuth(account, password, domain string) bool { 186 | return true 187 | } 188 | -------------------------------------------------------------------------------- /data/service.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/tim/errs" 12 | . "github.com/donnie4w/tim/stub" 13 | "github.com/donnie4w/tim/sys" 14 | ) 15 | 16 | type service interface { 17 | Login(string, string, *string) (string, errs.ERROR) 18 | Register(string, string, *string) (string, errs.ERROR) 19 | AuthNode(string, string, *string) (string, errs.ERROR) 20 | Modify(uint64, *string, string, *string) errs.ERROR 21 | SaveMessage(*TimMessage) error 22 | SaveOfflineMessage(*TimMessage) error 23 | DelMessageByMid(uint64, int64) error 24 | DelOfflineMessage(uint64, ...int64) (int64, error) 25 | 26 | ExistGroup(string) bool 27 | ExistUser(string) bool 28 | AuthGroupAndUser(string, string, *string) (bool, error) 29 | AuthUserAndUser(string, string, *string) bool 30 | 31 | GetMessage(string, *string, int8, string, int64, int64) ([]*TimMessage, error) 32 | GetMessageByMid(uint64, int64) (*TimMessage, error) 33 | GetOfflineMessage(string, int) ([]*OfflineBean, error) 34 | 35 | Addroster(string, string, *string) (int8, errs.ERROR) 36 | Blockrosterlist(string) []string 37 | Rmroster(string, string, *string) (bool, bool) 38 | Roster(string) []string 39 | UserGroup(string, *string) []string 40 | Blockroster(string, string, *string) (bool, bool) 41 | ModifyUserInfo(string, *TimUserBean) errs.ERROR 42 | GetUserInfo([]string) (map[string]*TimUserBean, errs.ERROR) 43 | 44 | Newgroup(string, string, sys.TIMTYPE, *string) (string, errs.ERROR) 45 | Addgroup(string, string, *string) errs.ERROR 46 | Blockroomlist(string) []string 47 | Blockroommemberlist(string, string) []string 48 | GroupManagers(string, *string) ([]string, errs.ERROR) 49 | GroupRoster(string) []string 50 | GroupGtype(string, *string) (int8, errs.ERROR) 51 | Kickgroup(string, string, string, *string) errs.ERROR 52 | Leavegroup(string, string, *string) (err errs.ERROR) 53 | Nopassgroup(string, string, string, *string) errs.ERROR 54 | Pullgroup(string, string, string, *string) (bool, errs.ERROR) 55 | Blockgroup(string, string, *string) errs.ERROR 56 | Blockgroupmember(string, string, string, *string) errs.ERROR 57 | Cancelgroup(string, string, *string) errs.ERROR 58 | ModifygroupInfo(string, string, *TimRoomBean) errs.ERROR 59 | GetGroupInfo([]string) (map[string]*TimRoomBean, errs.ERROR) 60 | TimAdminAuth(account, password, domain string) bool 61 | } 62 | -------------------------------------------------------------------------------- /data/tldbdao.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/util" 12 | ) 13 | 14 | type timmessage struct { 15 | Id int64 16 | ChatId []byte `idx:"1"` 17 | Fid int64 18 | Stanza []byte 19 | Timeseries int64 `idx:"1"` 20 | } 21 | 22 | func (this timmessage) Tid() uint64 { return util.FNVHash64(this.ChatId) } 23 | 24 | type timuser struct { 25 | Id int64 26 | UUID uint64 `idx:"1"` 27 | Pwd string 28 | Createtime int64 29 | UBean []byte 30 | Timeseries int64 `idx:"1"` 31 | } 32 | 33 | func (this timuser) Tid() uint64 { return this.UUID } 34 | 35 | type timgroup struct { 36 | Id int64 37 | Gtype int8 38 | UUID uint64 `idx:"1"` 39 | Createtime int64 40 | Status int8 41 | RBean []byte 42 | Timeseries int64 `idx:"1"` 43 | } 44 | 45 | func (this timgroup) Tid() uint64 { return this.UUID } 46 | 47 | type timoffline struct { 48 | Id int64 49 | UUID uint64 `idx:"1"` 50 | ChatId []byte 51 | Stanza []byte 52 | Mid int64 53 | Timeseries int64 `idx:"1"` 54 | } 55 | 56 | func (this timoffline) Tid() uint64 { return this.UUID } 57 | 58 | type timrelate struct { 59 | Id int64 60 | UUID []byte `idx:"1"` 61 | Status uint8 62 | Timeseries int64 `idx:"1"` 63 | } 64 | 65 | func (this timrelate) Tid() uint64 { return util.FNVHash64(this.UUID) } 66 | 67 | type timroster struct { 68 | Id int64 69 | Unikid []byte `idx:"1"` 70 | UUID uint64 `idx:"1"` 71 | TUUID uint64 72 | Timeseries int64 `idx:"1"` 73 | } 74 | 75 | func (this timroster) Tid() uint64 { return this.UUID } 76 | 77 | type timmucroster struct { 78 | Id int64 79 | Unikid []byte `idx:"1"` 80 | UUID uint64 `idx:"1"` 81 | TUUID uint64 82 | Timeseries int64 `idx:"1"` 83 | } 84 | 85 | func (this timmucroster) Tid() uint64 { return this.UUID } 86 | 87 | type timblock struct { 88 | Id int64 89 | UnikId []byte `idx:"1"` 90 | UUID uint64 `idx:"1"` 91 | TUUID uint64 92 | Timeseries int64 `idx:"1"` 93 | } 94 | 95 | func (this timblock) Tid() uint64 { return this.UUID } 96 | 97 | type timblockroom struct { 98 | Id int64 99 | UnikId []byte `idx:"1"` 100 | UUID uint64 `idx:"1"` 101 | TUUID uint64 102 | Timeseries int64 `idx:"1"` 103 | } 104 | 105 | func (this timblockroom) Tid() uint64 { return this.UUID } 106 | 107 | type timstruct interface { 108 | Tid() uint64 109 | } 110 | 111 | type OfflineBean struct { 112 | Id any 113 | Mid int64 114 | Stanze []byte 115 | Timeseries int64 `idx:"1"` 116 | } 117 | -------------------------------------------------------------------------------- /data/tldbutil.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "fmt" 12 | "sort" 13 | 14 | "github.com/donnie4w/gofer/util" 15 | "github.com/donnie4w/tim/sys" 16 | "github.com/donnie4w/tlcli-go/tlcli" 17 | "github.com/donnie4w/tlorm-go/orm" 18 | ) 19 | 20 | func Create[T any]() (err error) { 21 | return orm.Create[T]() 22 | } 23 | 24 | func Insert(a timstruct) (seq int64, err error) { 25 | return orm.Table[byte](tldbCli(a.Tid())).Insert(a) 26 | } 27 | 28 | // update data for non nil 29 | // func Update(a timstruct) (err error) { 30 | // return orm.Table[byte](tldbCli(a.Tid())).Update(a) 31 | // } 32 | 33 | // Delete data for non nil 34 | func Delete[T any](tid uint64, id int64) (err error) { 35 | return orm.Table[T](tldbCli(tid)).Delete(id) 36 | } 37 | 38 | // UpdateNonzero data for non zero 39 | func UpdateNonzero(a timstruct) (err error) { 40 | return orm.Table[byte](tldbCli(a.Tid())).UpdateNonzero(a) 41 | } 42 | 43 | func SelectIdByIdx[T timstruct](columnName string, columnValue []byte) (id int64, err error) { 44 | return orm.Table[T](tldbCli(util.FNVHash64(columnValue))).SelectIdByIdx(columnName, columnValue) 45 | } 46 | 47 | func SelectById[T timstruct](tid []byte, id int64) (a *T, err error) { 48 | return orm.Table[T](tldbCli(util.FNVHash64(tid))).SelectById(id) 49 | } 50 | 51 | func SelectByIdx[T any](columnName string, columnValue []byte) (a *T, err error) { 52 | return orm.Table[T](tldbCli(util.FNVHash64(columnValue))).SelectByIdx(columnName, columnValue) 53 | } 54 | 55 | func SelectByIdxWithInt[T any](columnName string, columnValue uint64) (a *T, err error) { 56 | return orm.Table[T](tldbCli(columnValue)).SelectByIdx(columnName, columnValue) 57 | } 58 | 59 | func SelectByIdxWithTid[T any](tid uint64, columnName string, columnValue []byte) (a *T, err error) { 60 | return orm.Table[T](tldbCli(tid)).SelectByIdx(columnName, columnValue) 61 | } 62 | 63 | func SelectAllByIdx[T any](columnName string, columnValue uint64) (as []*T, err error) { 64 | return orm.Table[T](tldbCli(columnValue)).SelectAllByIdx(columnName, columnValue) 65 | } 66 | 67 | func SelectAllByIdxWithTid[T any](tid uint64, columnName string, columnValue []byte) (as []*T, err error) { 68 | return orm.Table[T](tldbCli(tid)).SelectAllByIdx(columnName, columnValue) 69 | } 70 | 71 | func SelectByIdxLimit[T any](startId, limit int64, columnName string, columnValue uint64) (as []*T, err error) { 72 | return orm.Table[T](tldbCli(columnValue)).SelectByIdxLimit(startId, limit, columnName, columnValue) 73 | } 74 | 75 | func SelectByIdxDescLimit[T any](id, limit int64, columnName string, columnValue []byte) (as []*T, err error) { 76 | return orm.Table[T](tldbCli(util.FNVHash64(columnValue))).SelectByIdxDescLimit(columnName, columnValue, id, limit) 77 | } 78 | 79 | func SelectIdByIdxSeq[T any](columnName string, columnValue []byte, id int64) (_r int64, err error) { 80 | return orm.Table[T](tldbCli(util.FNVHash64(columnValue))).SelectIdByIdxSeq(columnName, columnValue, id) 81 | } 82 | 83 | var tldbsources = make([]*tldbsource, 0) 84 | 85 | type tldbsource struct { 86 | extent int 87 | client *tlcli.Client 88 | } 89 | 90 | func tldbInit() error { 91 | if len(sys.Conf.TldbExtent) > 0 { 92 | for _, te := range sys.Conf.TldbExtent { 93 | if cli, e := orm.NewConn(te.Tls, te.Addr, te.Auth); e == nil { 94 | extent := sys.MB 95 | if te.ExtentMax > 0 && te.ExtentMax < extent { 96 | extent = te.ExtentMax 97 | } 98 | tldbsources = append(tldbsources, &tldbsource{extent: extent, client: cli}) 99 | initTable(cli) 100 | } else { 101 | return fmt.Errorf("%s", "tldb init error:"+e.Error()) 102 | } 103 | } 104 | sort.Slice(tldbsources, func(i, j int) bool { return tldbsources[i].extent < tldbsources[j].extent }) 105 | } else if sys.Conf.Tldb != nil { 106 | if cli, e := orm.NewConn(sys.Conf.Tldb.Tls, sys.Conf.Tldb.Addr, sys.Conf.Tldb.Auth); e == nil { 107 | tldbsources = append(tldbsources, &tldbsource{extent: sys.MB, client: cli}) 108 | initTable(cli) 109 | } else { 110 | return fmt.Errorf("%s", "tldb init error:"+e.Error()) 111 | } 112 | } else { 113 | panic("tldb init error") 114 | } 115 | return nil 116 | } 117 | 118 | func initTable(cli *tlcli.Client) { 119 | orm.Table[timgroup](cli).Create() 120 | orm.Table[timmessage](cli).Create() 121 | orm.Table[timoffline](cli).Create() 122 | orm.Table[timuser](cli).Create() 123 | orm.Table[timrelate](cli).Create() 124 | orm.Table[timmucroster](cli).Create() 125 | orm.Table[timroster](cli).Create() 126 | orm.Table[timblock](cli).Create() 127 | orm.Table[timblockroom](cli).Create() 128 | } 129 | 130 | func tldbCli(tid uint64) *tlcli.Client { 131 | if len(tldbsources) == 1 { 132 | return tldbsources[0].client 133 | } 134 | idx := 0 135 | if idx = sort.Search(len(tldbsources), func(i int) bool { return tldbsources[i].extent >= int(tid%sys.MB) }); idx >= len(tldbsources) { 136 | idx = 0 137 | } 138 | return tldbsources[idx].client 139 | } 140 | -------------------------------------------------------------------------------- /data/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package data 9 | 10 | import ( 11 | "github.com/donnie4w/gdao/base" 12 | gocache "github.com/donnie4w/gofer/cache" 13 | "github.com/donnie4w/gofer/lock" 14 | goutil "github.com/donnie4w/gofer/util" 15 | "github.com/donnie4w/tim/log" 16 | "github.com/donnie4w/tim/sys" 17 | "math/rand" 18 | "os" 19 | "strconv" 20 | "time" 21 | ) 22 | 23 | var Service service 24 | var numlock = lock.NewNumLock(1 << 9) 25 | var strlock = lock.NewStrlock(1 << 9) 26 | 27 | func getService() service { 28 | switch sys.GetDBMOD() { 29 | case sys.INLINEDB: 30 | return new(inlineHandle).init() 31 | case sys.TLDB: 32 | return new(tldbHandle).init() 33 | case sys.MONGODB: 34 | return new(mongoHandle).init() 35 | case sys.EXTERNALDB: 36 | return new(externHandle).init() 37 | case sys.NODB: 38 | return new(nodbHandle).init() 39 | case sys.CASSANDRA: 40 | return new(cassandraHandle).init() 41 | } 42 | return nil 43 | } 44 | 45 | func init() { 46 | sys.Service(sys.INIT_DATA, serv(1)) 47 | } 48 | 49 | type serv byte 50 | 51 | func (serv) Serve() error { 52 | defer func() { 53 | if err := recover(); err != nil { 54 | log.FmtPrint(err) 55 | os.Exit(1) 56 | } 57 | }() 58 | if Service = getService(); Service == nil { 59 | panic("no database service found") 60 | } 61 | return nil 62 | } 63 | 64 | func (serv) Close() error { 65 | return nil 66 | } 67 | 68 | var uuidCache = gocache.NewBloomFilter(1<<19, 0.01) 69 | 70 | func _getString(a any) (_r string) { 71 | switch a.(type) { 72 | case string: 73 | _r = a.(string) 74 | case []uint8: 75 | _r = string(a.([]uint8)) 76 | case int8, int16, int32, int64, int, uint, uint8, uint16, uint32, uint64: 77 | _r = strconv.FormatInt(_getInt64(a), 10) 78 | } 79 | return 80 | } 81 | 82 | func _getBytes(a any) (_r []byte) { 83 | switch a.(type) { 84 | case string: 85 | _r = []byte(a.(string)) 86 | case []uint8: 87 | _r = a.([]uint8) 88 | } 89 | return 90 | } 91 | 92 | func _getInt64(a any) (_r int64) { 93 | switch a.(type) { 94 | case int8: 95 | _r = int64(a.(int8)) 96 | case int16: 97 | _r = int64(a.(int16)) 98 | case int32: 99 | _r = int64(a.(int32)) 100 | case int64: 101 | _r = a.(int64) 102 | case int: 103 | _r = int64(a.(int)) 104 | case uint: 105 | _r = int64(a.(uint)) 106 | case uint8: 107 | _r = int64(a.(uint8)) 108 | case uint16: 109 | _r = int64(a.(uint16)) 110 | case uint32: 111 | _r = int64(a.(uint32)) 112 | case uint64: 113 | _r = int64(a.(uint64)) 114 | } 115 | return 116 | } 117 | 118 | const ( 119 | Driver_Sqlite = "sqlite3" 120 | Driver_Postgres = "postgres" 121 | Driver_Mysql = "mysql" 122 | Driver_Sqlserver = "sqlserver" 123 | Driver_Oracle = "godror" 124 | ) 125 | 126 | const localdb = "tim.db" 127 | 128 | func initLocalDB(dbhandle base.DBhandle, driver string) { 129 | var ss []string 130 | switch driver { 131 | case Driver_Sqlite: 132 | ss = Sqlite("").CreateSql() 133 | case Driver_Postgres: 134 | ss = PostgreSql("").CreateSql() 135 | case Driver_Mysql: 136 | ss = Mysql("").CreateSql() 137 | case Driver_Sqlserver: 138 | ss = SqlServer("").CreateSql() 139 | case Driver_Oracle: 140 | ss = Oracle("").CreateSql() 141 | } 142 | if len(ss) > 0 { 143 | for _, s := range ss { 144 | dbhandle.ExecuteUpdate(s) 145 | } 146 | } 147 | } 148 | 149 | func TimeNano() int64 { 150 | return timenano.unix() 151 | } 152 | 153 | var timenano = newNano() 154 | 155 | type nano struct { 156 | precision byte 157 | count uint64 158 | } 159 | 160 | func newNano() *nano { 161 | t := time.Now() 162 | if t.UnixNano() == t.UnixNano()/1e3*1e3 { 163 | return &nano{precision: 3} 164 | } else if t.UnixNano() == t.UnixNano()/1e2*1e2 { 165 | return &nano{precision: 2} 166 | } else if t.UnixNano() == t.UnixNano()/1e1*1e1 { 167 | return &nano{precision: 1} 168 | } else { 169 | return &nano{precision: 0} 170 | } 171 | } 172 | 173 | func (n *nano) unix() (r int64) { 174 | switch n.precision { 175 | case 3: 176 | r = time.Now().UnixNano() + int64(n.count%1e3) 177 | case 2: 178 | r = time.Now().UnixNano() + int64(n.count%1e2) 179 | case 1: 180 | r = time.Now().UnixNano() + int64(n.count%1e1) 181 | default: 182 | r = time.Now().UnixNano() 183 | } 184 | n.count++ 185 | return r 186 | } 187 | 188 | var r = rand.New(rand.NewSource(goutil.UUID64())) 189 | 190 | func midUUID() int64 { 191 | switch sys.Conf.UuidBits { 192 | case 32: 193 | return int64(goutil.UUID32()) 194 | case 53: 195 | uuid32 := uint32(goutil.UUID32()) 196 | return int64(uuid32)<<21 | r.Int63n(1<<21) 197 | default: 198 | return goutil.UUID64() 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /errs/err.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package errs 9 | 10 | import ( 11 | "fmt" 12 | 13 | . "github.com/donnie4w/tim/stub" 14 | ) 15 | 16 | var ERR_HASEXIST = err(4101, "has exist") 17 | var ERR_NOPASS = err(4102, "no pass") 18 | var ERR_EXPIREOP = err(4103, "expire operate") 19 | var ERR_PARAMS = err(4104, "parameter incorrect") 20 | var ERR_PERM_DENIED = err(4105, "permission denied") 21 | var ERR_ACCOUNT = err(4106, "account incorrect") 22 | var ERR_INTERFACE = err(4107, "interface incorrect") 23 | var ERR_CANCEL = err(4108, "must not be a cancle object") 24 | var ERR_NOEXIST = err(4109, "must not be a no exist object") 25 | var ERR_BLOCK = err(4110, "blocked object") 26 | var ERR_OVERENTRY = err(4111, "over entry") 27 | var ERR_MODIFYAUTH = err(4112, "modify password failed") 28 | var ERR_FORMAT = err(4113, "format error") 29 | var ERR_BIGDATA = err(4114, "big data error") 30 | var ERR_TOKEN = err(4115, "error token") 31 | var ERR_PING = err(4116, "error ping count") 32 | var ERR_REPEAT = err(4117, "error repetitive operation") 33 | 34 | var ERR_UNDEFINED = err(5101, "undefined error") 35 | var ERR_BLOCKHANDLE = err(5102, "blocking operation") 36 | var ERR_DATABASE = err(5103, "database error") 37 | var ERR_OVERLOAD = err(5104, "heavy server load") 38 | var ERR_OVERHZ = err(5105, "freq out of limit") 39 | 40 | var ERR_UUID_REUSE = err(1101, "uuid reuse") 41 | var ERR_OVERTIME = err(1102, "overtime") 42 | var ERR_CONNECT = err(1103, "connect error") 43 | 44 | type ERROR interface { 45 | TimError() *TimError 46 | Error() error 47 | } 48 | 49 | type timerror struct { 50 | code int32 51 | info string 52 | } 53 | 54 | func err(code int32, info string) ERROR { 55 | return &timerror{code, info} 56 | } 57 | 58 | func (t *timerror) TimError() *TimError { 59 | return &TimError{Code: &t.code, Info: &t.info} 60 | } 61 | 62 | func (t *timerror) Error() error { 63 | return fmt.Errorf("code:%d,info:%s", t.code, t.info) 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/donnie4w/tim 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/denisenkom/go-mssqldb v0.12.3 7 | github.com/donnie4w/gofer v0.0.0-20240311114551-d52fdfcd46a9 8 | github.com/donnie4w/gothrift v0.0.1 9 | github.com/donnie4w/simplelog v0.0.1 10 | github.com/donnie4w/tlcli-go v0.0.0-20231107171801-d17da8836864 11 | github.com/donnie4w/tlnet v0.0.1 12 | github.com/donnie4w/tlorm-go v0.0.0-20231108024405-1cc4c5b9072b 13 | github.com/donnie4w/tsf v0.0.1 14 | github.com/go-sql-driver/mysql v1.8.0 15 | github.com/godror/godror v0.42.0 16 | github.com/lib/pq v1.10.9 17 | github.com/shirou/gopsutil/v3 v3.24.2 18 | ) 19 | 20 | require ( 21 | filippo.io/edwards25519 v1.1.0 // indirect 22 | github.com/apache/thrift v0.19.0 // indirect 23 | github.com/go-logfmt/logfmt v0.6.0 // indirect 24 | github.com/go-ole/go-ole v1.3.0 // indirect 25 | github.com/godror/knownpb v0.1.1 // indirect 26 | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect 27 | github.com/golang-sql/sqlexp v0.1.0 // indirect 28 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 29 | github.com/golang/snappy v0.0.4 // indirect 30 | github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a // indirect 31 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect 32 | github.com/shoenig/go-m1cpu v0.1.6 // indirect 33 | github.com/tklauser/go-sysconf v0.3.13 // indirect 34 | github.com/tklauser/numcpus v0.7.0 // indirect 35 | github.com/yusufpapurcu/wmi v1.2.4 // indirect 36 | golang.org/x/crypto v0.21.0 // indirect 37 | golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect 38 | golang.org/x/net v0.22.0 // indirect 39 | golang.org/x/sys v0.18.0 // indirect 40 | google.golang.org/protobuf v1.33.0 // indirect 41 | ) 42 | -------------------------------------------------------------------------------- /inet/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package inet 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/buffer" 12 | "github.com/donnie4w/gofer/hashmap" 13 | "github.com/donnie4w/gofer/httpclient" 14 | goutil "github.com/donnie4w/gofer/util" 15 | "github.com/donnie4w/tim/errs" 16 | "github.com/donnie4w/tim/stub" 17 | "github.com/donnie4w/tim/sys" 18 | "github.com/donnie4w/tim/util" 19 | "github.com/donnie4w/tlnet" 20 | "sync/atomic" 21 | "time" 22 | ) 23 | 24 | //func isForBidRegister() bool { 25 | // return sys.Conf.Security != nil && sys.Conf.Security.ForBidRegister 26 | //} 27 | 28 | //func isForBidToken() bool { 29 | // return sys.Conf.Security != nil && sys.Conf.Security.ForBidToken 30 | //} 31 | 32 | func reqHzSecond() int { 33 | if sys.Conf.Security != nil { 34 | return sys.Conf.Security.ReqHzSecond 35 | } 36 | return 0 37 | } 38 | 39 | var hzmap = hashmap.NewLimitMap[int64, []int64](1 << 17) 40 | 41 | func overHz(hc *tlnet.HttpContext) (b bool) { 42 | defer util.Recover() 43 | if reqHzSecond() > 0 { 44 | if t, ok := hzmap.Get(hc.WS.Id); ok { 45 | if time.Now().UnixNano()-t[0] < int64(int(time.Second/time.Nanosecond)/reqHzSecond()) { 46 | hzmap.Put(hc.WS.Id, []int64{time.Now().UnixNano(), atomic.AddInt64(&t[1], 1)}) 47 | if b = t[1] > 5; b { 48 | hc.WS.Close() 49 | } 50 | } 51 | } 52 | hzmap.Put(hc.WS.Id, []int64{time.Now().UnixNano(), 0}) 53 | } 54 | return 55 | } 56 | 57 | func overMaxData(ws *tlnet.Websocket, length int64) (_r bool) { 58 | if sys.Conf.Security != nil && sys.Conf.Security.MaxDatalimit > 0 { 59 | if sys.Conf.Security.MaxDatalimit > length { 60 | if ws != nil { 61 | ws.Close() 62 | } 63 | _r = true 64 | } 65 | } 66 | return 67 | } 68 | 69 | func newAuth(bs []byte) (ta *stub.TimAuth) { 70 | if util.JTP(bs[0]) { 71 | ta, _ = goutil.JsonDecode[*stub.TimAuth](bs[1:]) 72 | } else { 73 | ta, _ = goutil.TDecode(bs[1:], &stub.TimAuth{}) 74 | } 75 | return 76 | } 77 | 78 | func connectAuth(bs []byte) (_r bool) { 79 | defer util.Recover() 80 | if sys.Conf.Security != nil && sys.Conf.Security.ConnectAuthUrl != nil { 81 | if ta := newAuth(bs); ta != nil { 82 | if bs, err := httpclient.Post2(goutil.JsonEncode(ta), true, *sys.Conf.Security.ConnectAuthUrl); err == nil && bs != nil { 83 | _r = bs[0] == 1 84 | } 85 | } 86 | } else { 87 | return true 88 | } 89 | return 90 | } 91 | 92 | var bigMap = hashmap.NewMap[int64, *bm]() 93 | 94 | type bm struct { 95 | buf *buffer.Buffer 96 | length int 97 | } 98 | 99 | func (this *bm) addData(bs []byte) (_bs []byte, ok bool) { 100 | if l := this.length - this.buf.Len() - len(bs); l > 0 { 101 | this.buf.Write(bs) 102 | return nil, false 103 | } else if l == 0 { 104 | this.buf.Write(bs) 105 | return this.buf.Bytes(), true 106 | } else if l < 0 { 107 | return bs, true 108 | } 109 | return 110 | } 111 | 112 | func addBigData(hc *tlnet.HttpContext, bs []byte) { 113 | if m, ok := bigMap.Get(hc.WS.Id); ok { 114 | if _bs, b := m.addData(bs); b { 115 | bigMap.Del(hc.WS.Id) 116 | parseWsData(_bs, hc) 117 | } 118 | } 119 | } 120 | 121 | func newBigData(hc *tlnet.HttpContext, bs []byte, len int) { 122 | bigMap.Put(hc.WS.Id, &bm{buf: buffer.NewBufferBySlice(bs), length: len}) 123 | } 124 | 125 | func parseBigData(hc *tlnet.HttpContext, bs []byte) { 126 | if len(bs) < 6 { 127 | return 128 | } 129 | length := int(goutil.BytesToInt32(bs[1:5])) 130 | if fg := length - len(bs); fg == 0 { 131 | parseWsData(bs, hc) 132 | } else if fg > 0 { 133 | newBigData(hc, bs, length) 134 | } else { 135 | go sys.SendWs(hc.WS.Id, &stub.TimAck{Ok: false, TimType: int8(sys.TIMBIGBINARY), Error: errs.ERR_BIGDATA.TimError()}, sys.TIMACK) 136 | } 137 | } 138 | 139 | func rmBigDataId(id int64) { 140 | bigMap.Del(id) 141 | } 142 | 143 | func isBigData(id int64) bool { 144 | return bigMap.Has(id) 145 | } 146 | 147 | //func isForBitIface(b byte) bool { 148 | // if sys.BlockApiMap != nil { 149 | // return sys.BlockApiMap.Has(sys.TIMTYPE(b & 0x7f)) 150 | // } 151 | // return false 152 | //} 153 | 154 | func isForBitApi(b byte) bool { 155 | switch sys.TIMTYPE(b) { 156 | case sys.TIMREGISTER: 157 | return sys.Conf.DeactivateApi.TIMREGISTER 158 | case sys.TIMTOKEN: 159 | return sys.Conf.DeactivateApi.TIMTOKEN 160 | case sys.TIMAUTH: 161 | return sys.Conf.DeactivateApi.TIMAUTH 162 | case sys.TIMOFFLINEMSG: 163 | return sys.Conf.DeactivateApi.TIMOFFLINEMSG 164 | case sys.TIMOFFLINEMSGEND: 165 | return sys.Conf.DeactivateApi.TIMOFFLINEMSGEND 166 | case sys.TIMBROADPRESENCE: 167 | return sys.Conf.DeactivateApi.TIMBROADPRESENCE 168 | case sys.TIMLOGOUT: 169 | return sys.Conf.DeactivateApi.TIMLOGOUT 170 | case sys.TIMPULLMESSAGE: 171 | return sys.Conf.DeactivateApi.TIMPULLMESSAGE 172 | case sys.TIMVROOM: 173 | return sys.Conf.DeactivateApi.TIMVROOM 174 | case sys.TIMBUSINESS: 175 | return sys.Conf.DeactivateApi.TIMBUSINESS 176 | case sys.TIMNODES: 177 | return sys.Conf.DeactivateApi.TIMNODES 178 | case sys.TIMMESSAGE: 179 | return sys.Conf.DeactivateApi.TIMMESSAGE 180 | case sys.TIMPRESENCE: 181 | return sys.Conf.DeactivateApi.TIMPRESENCE 182 | case sys.TIMREVOKEMESSAGE: 183 | return sys.Conf.DeactivateApi.TIMREVOKEMESSAGE 184 | case sys.TIMBURNMESSAGE: 185 | return sys.Conf.DeactivateApi.TIMBURNMESSAGE 186 | case sys.TIMSTREAM: 187 | return sys.Conf.DeactivateApi.TIMSTREAM 188 | case sys.TIMBIGSTRING: 189 | return sys.Conf.DeactivateApi.TIMBIGSTRING 190 | case sys.TIMBIGBINARY: 191 | return sys.Conf.DeactivateApi.TIMBIGBINARY 192 | case sys.TIMBIGBINARYSTREAM: 193 | return sys.Conf.DeactivateApi.TIMBIGBINARYSTREAM 194 | } 195 | return false 196 | } 197 | -------------------------------------------------------------------------------- /keystore/admin.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package keystore 9 | 10 | import ( 11 | ks "github.com/donnie4w/gofer/keystore" 12 | ) 13 | 14 | var Admin = ks.NewStoreAdmin() 15 | -------------------------------------------------------------------------------- /keystore/ks.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package keystore 9 | 10 | import ( 11 | "fmt" 12 | ks "github.com/donnie4w/gofer/keystore" 13 | "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/log" 15 | "github.com/donnie4w/tim/sys" 16 | "os" 17 | "strconv" 18 | "time" 19 | ) 20 | 21 | func init() { 22 | sys.Service(sys.INIT_KEYSTORE, serv(1)) 23 | } 24 | 25 | type serv byte 26 | 27 | func (s serv) Serve() error { 28 | s.init(sys.Conf.KsDir) 29 | return nil 30 | } 31 | 32 | func (serv) Close() error { 33 | return nil 34 | } 35 | 36 | func (s serv) init(dir string) { 37 | if dir == "" { 38 | dir, _ = os.Getwd() 39 | } 40 | if err := s.initAdmin(dir); err != nil { 41 | log.FmtPrint("Keystore init failed") 42 | os.Exit(1) 43 | } 44 | if sys.OpenSSL.PublicPath != "" || sys.OpenSSL.PrivatePath != "" { 45 | a := fmt.Sprint(time.Now().UnixNano()) 46 | var err error 47 | var bs []byte 48 | var ok bool 49 | if bs, err = ks.RsaEncrypt([]byte(a), sys.OpenSSL.PublicPath); err == nil { 50 | if bs, err = ks.RsaDecrypt(bs, sys.OpenSSL.PrivatePath); err == nil { 51 | ok = a == string(bs) 52 | } 53 | } 54 | if err != nil || !ok { 55 | panic("publickey and privatekey authFailed") 56 | } 57 | } 58 | } 59 | 60 | func (serv) initAdmin(dir string) (err error) { 61 | if ks.KeyStore, err = ks.NewKeyStore(dir, "tim.ks"); err == nil { 62 | Admin.Load() 63 | if v, ok := Admin.GetOther("TIMUUID"); ok { 64 | id, _ := strconv.ParseUint(v, 10, 64) 65 | sys.UUID = int64(id) 66 | } else { 67 | sys.UUID = int64(util.UUID32()) 68 | Admin.PutOther("TIMUUID", fmt.Sprint(sys.UUID)) 69 | } 70 | } 71 | log.FmtPrint("UUID [", sys.UUID, "]") 72 | return 73 | } 74 | -------------------------------------------------------------------------------- /log/log.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package log 9 | 10 | import ( 11 | "fmt" 12 | "github.com/donnie4w/go-logger/logger" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | var log = logger.NewLogger() 18 | 19 | func init() { 20 | SetFile("tim.log") 21 | } 22 | 23 | func SetFile(filepath string) { 24 | log.SetOption(&logger.Option{CallDepth: 1, FileOption: &logger.FileSizeMode{Filename: filepath, Maxsize: 1 << 30, Maxbuckup: 30, IsCompress: true}}) 25 | log.SetLevelOption(logger.LEVEL_WARN, &logger.LevelOption{Format: logger.FORMAT_NANO}) 26 | log.SetConsole(true).SetFormat(logger.FORMAT_DATE | logger.FORMAT_TIME) 27 | } 28 | 29 | func SetConsole(ok bool) { 30 | log.SetConsole(ok) 31 | } 32 | 33 | func SetLevel(level logger.LEVELTYPE) { 34 | log.SetLevel(level) 35 | } 36 | 37 | func Debug(v ...interface{}) { 38 | log.Debug(v...) 39 | } 40 | 41 | func FmtPrint(v ...interface{}) { 42 | info := fmt.Sprint(v...) 43 | const ll = 80 44 | if len(info) >= ll { 45 | log.Info(info) 46 | return 47 | } 48 | padLen := (ll - len(info)) / 2 49 | padding := strings.Repeat("═", padLen) 50 | extraPadding := "" 51 | if len(info)+padLen*2 < ll { 52 | extraPadding = " " 53 | } 54 | log.Infof("%s %s%s %s", padding, extraPadding, info, padding) 55 | } 56 | 57 | func DelayPrint(v ...any) { 58 | go func() { 59 | time.Sleep(2 * time.Second) 60 | log.Warn(fmt.Sprint(v...)) 61 | }() 62 | } 63 | 64 | func Info(v ...interface{}) { 65 | log.Info(v...) 66 | } 67 | 68 | func Warn(v ...interface{}) { 69 | log.Warn(v...) 70 | } 71 | 72 | func Error(v ...interface{}) { 73 | log.Error(v...) 74 | } 75 | 76 | func Debugf(format string, v ...interface{}) { 77 | log.Debugf(format, v...) 78 | } 79 | 80 | func Infof(format string, v ...interface{}) { 81 | log.Infof(format, v...) 82 | } 83 | 84 | func Warnf(format string, v ...interface{}) { 85 | log.Warnf(format, v...) 86 | } 87 | 88 | func Errorf(format string, v ...interface{}) { 89 | log.Errorf(format, v...) 90 | } 91 | -------------------------------------------------------------------------------- /mesh/handler.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mesh 9 | 10 | import ( 11 | "context" 12 | . "github.com/donnie4w/gofer/util" 13 | "github.com/donnie4w/tim/log" 14 | . "github.com/donnie4w/tim/stub" 15 | "github.com/donnie4w/tim/util" 16 | "sync/atomic" 17 | "time" 18 | ) 19 | 20 | type tnetServer struct { 21 | servermux *serverMux 22 | ok []byte 23 | } 24 | 25 | func (this *tnetServer) handle(processor Itnet, handler func(tc *tlContext), cliError func(tc *tlContext)) { 26 | if this.servermux == nil { 27 | this.servermux = &serverMux{} 28 | this.servermux.Handle(processor, handler, cliError) 29 | } 30 | } 31 | 32 | func (this *tnetServer) Serve(_addr string) (err error) { 33 | if _addr, err = util.ParseAddr(_addr); err != nil { 34 | return 35 | } 36 | err = tsfclientserver.server(_addr, this.servermux.processor, this.servermux.handler, this.servermux.cliError, this.ok) 37 | return 38 | } 39 | 40 | func (this *tnetServer) Connect(_addr string, async bool) (err error) { 41 | if _addr, err = util.ParseAddr(_addr); err != nil { 42 | return 43 | } 44 | return tsfserverclient.server(_addr, this.servermux.processor, this.servermux.handler, this.servermux.cliError, async) 45 | } 46 | 47 | type serverMux struct { 48 | processor Itnet 49 | handler func(tc *tlContext) 50 | cliError func(tc *tlContext) 51 | } 52 | 53 | func (this *serverMux) Handle(processor Itnet, handler func(tc *tlContext), cliError func(tc *tlContext)) { 54 | this.processor = processor 55 | this.handler = handler 56 | this.cliError = cliError 57 | } 58 | 59 | func myServer2ClientHandler(tc *tlContext) { 60 | } 61 | 62 | func myClient2ServerHandler(tc *tlContext) { 63 | defer util.Recover() 64 | if !tc.isClose { 65 | ab := newchapBean() 66 | ab.IDcard = tc.id 67 | if bs, err := encodeChapBean(ab); err == nil { 68 | if err := tc.csnet.Chap(context.Background(), bs); err != nil { 69 | log.Error(err) 70 | } 71 | } 72 | } 73 | } 74 | 75 | func mySecvErrorHandler(tc *tlContext) { 76 | go reconn(tc) 77 | } 78 | 79 | func myCliErrorHandler(tc *tlContext) { 80 | clientLinkCache.Del(tc.remoteAddr) 81 | go reconn(tc) 82 | } 83 | 84 | func reconn(tc *tlContext) { 85 | if tc == nil || tc.remoteAddr == "" || tc.remoteUuid == 0 { 86 | return 87 | } 88 | defer util.Recover() 89 | log.Info(">>>[", tc.remoteUuid, "][", tc.remoteAddr, "]") 90 | nodeWare.del(tc) 91 | if !tc.isServer && !tc._do_reconn { 92 | tc._do_reconn = true 93 | i := 0 94 | for !nodeWare.hasUUID(tc.remoteUuid) { 95 | if clientLinkCache.Has(tc.remoteAddr) { 96 | <-time.After(time.Duration(RandUint(6)) * time.Second) 97 | } else { 98 | if err1, err2 := tnetservice.Connect(tc.remoteAddr, false); err1 != nil { 99 | break 100 | } else if err2 != nil { 101 | if i < 100 { 102 | i++ 103 | } else if i > 1<<13 { 104 | break 105 | } 106 | <-time.After(time.Duration(RandUint(uint(6+i))) * time.Second) 107 | } 108 | } 109 | } 110 | } 111 | } 112 | 113 | func heardbeat() { 114 | ticker := time.NewTicker(5 * time.Second) 115 | for { 116 | select { 117 | case <-ticker.C: 118 | <-time.After(time.Duration(RandUint(5)) * time.Second) 119 | _heardbeat(nodeWare.GetAllTlContext()) 120 | } 121 | } 122 | } 123 | 124 | func _heardbeat(tcs []*tlContext) { 125 | defer util.Recover() 126 | for _, tc := range tcs { 127 | func(tc *tlContext) { 128 | defer util.Recover() 129 | tc.csnet.Ping(context.TODO(), piBs(tc)) 130 | if atomic.AddInt64(&tc.pingNum, 1) > 8 { 131 | log.Error("ping failed:[", tc.remoteUuid, "][", tc.remoteAddr, "] ping number:", tc.pingNum) 132 | go reconn(tc) 133 | } 134 | }(tc) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /mesh/merge2.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mesh 9 | 10 | import ( 11 | "context" 12 | "github.com/donnie4w/tim/util" 13 | "sync/atomic" 14 | "time" 15 | ) 16 | 17 | func syncMerge(tlcontext *tlContext) { 18 | defer util.Recover() 19 | defer tlcontext.mergemux.Unlock() 20 | _syncMerge(tlcontext) 21 | } 22 | 23 | func _syncMerge(tlcontext *tlContext) { 24 | m := make(map[int64]int8, 0) 25 | for sb := range tlcontext.mergeChan { 26 | m[sb.SyncId] = sb.Result 27 | if atomic.AddInt64(&tlcontext.mergeCount, -1) <= 0 { 28 | break 29 | } 30 | } 31 | syncTxMerge(m, tlcontext.remoteUuid) 32 | if tlcontext.mergeCount > 0 { 33 | _syncMerge(tlcontext) 34 | } 35 | } 36 | 37 | func syncTxMerge(syncList map[int64]int8, uuid int64) (err error) { 38 | i := 10 39 | for i > 0 { 40 | i-- 41 | if tc := nodeWare.GetTlContext(uuid); tc != nil { 42 | if err = tc.csnet.SyncTxMerge(context.Background(), syncList); err == nil { 43 | break 44 | } 45 | } else { 46 | <-time.After(1 * time.Second) 47 | } 48 | } 49 | return 50 | } 51 | -------------------------------------------------------------------------------- /mesh/process.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mesh 9 | 10 | import ( 11 | "context" 12 | . "github.com/donnie4w/gofer/hashmap" 13 | . "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/gothrift/thrift" 15 | . "github.com/donnie4w/tim/stub" 16 | "github.com/donnie4w/tim/sys" 17 | "github.com/donnie4w/tim/util" 18 | . "github.com/donnie4w/tsf" 19 | "strings" 20 | "sync" 21 | "time" 22 | ) 23 | 24 | const tlContextCtx = "tlContext" 25 | 26 | type tlContext struct { 27 | id int64 28 | csnet Itnet 29 | remoteAddr string 30 | remoteUuid int64 31 | remoteIP string 32 | remoteHost2 string 33 | remoteCsNum int32 34 | verifycode int64 35 | selfPing int64 36 | selfPong uint32 37 | tsfSocket TsfSocket 38 | mux *sync.Mutex 39 | defaultCtx context.Context 40 | cancleChan chan byte 41 | mergeChan chan *syncBean 42 | mergeCount int64 43 | mergemux *sync.Mutex 44 | 45 | isServer bool 46 | isClose bool 47 | pingNum int64 48 | pongNum int64 49 | isAuth bool 50 | onNum int64 51 | _do_reconn bool 52 | } 53 | 54 | type syncBean struct { 55 | SyncId int64 56 | Result int8 57 | } 58 | 59 | func (this *tlContext) SetId(_id int64) { 60 | this.id = _id 61 | } 62 | 63 | func (this *tlContext) Close() { 64 | defer util.Recover() 65 | this.mux.Lock() 66 | defer this.mux.Unlock() 67 | if !this.isClose { 68 | this.isClose = true 69 | nodeWare.del(this) 70 | this.tsfSocket.Close() 71 | close(this.cancleChan) 72 | } 73 | } 74 | 75 | func (this *tlContext) CloseAndEnd() (err error) { 76 | this._do_reconn = true 77 | this.Close() 78 | return 79 | } 80 | 81 | func newTlContext2(socket TsfSocket) (tc *tlContext) { 82 | tc = &tlContext{id: UUID64(), mux: new(sync.Mutex), mergeChan: make(chan *syncBean, 1<<17), mergemux: &sync.Mutex{}} 83 | tc.tsfSocket = socket 84 | tc.csnet = &ItnetImpl{socket} 85 | go func() { 86 | availMap.Put(tc, time.Now().Unix()) 87 | if availmux.TryLock() { 88 | availtk() 89 | } 90 | }() 91 | return 92 | } 93 | 94 | func remoteHost(transport thrift.TTransport) (_r string) { 95 | defer recover() 96 | if addr := transport.(*thrift.TSocket).Conn().RemoteAddr(); addr != nil { 97 | if ss := strings.Split(addr.String(), ":"); len(ss) == 2 { 98 | _r = ss[0] 99 | } 100 | } 101 | return 102 | } 103 | 104 | func remoteHost2(tsocket TsfSocket) (string, string) { 105 | defer util.Recover() 106 | if addr := tsocket.Conn().RemoteAddr(); addr != nil { 107 | if ss := strings.Split(addr.String(), ":"); len(ss) == 2 { 108 | return ss[0], ss[1] 109 | } 110 | } 111 | return "", "" 112 | } 113 | 114 | var availMap = NewMapL[*tlContext, int64]() 115 | var availmux = &sync.Mutex{} 116 | 117 | func availtk() { 118 | defer availmux.Unlock() 119 | tk := time.NewTicker(10 * time.Second) 120 | for { 121 | if availMap.Len() == 0 { 122 | break 123 | } 124 | select { 125 | case <-tk.C: 126 | availMap.Range(func(k *tlContext, v int64) bool { 127 | if v+30 < time.Now().Unix() { 128 | k.CloseAndEnd() 129 | availMap.Del(k) 130 | } 131 | return true 132 | }) 133 | } 134 | } 135 | } 136 | 137 | type chapBean struct { 138 | Stat int8 139 | Code int64 140 | Key string 141 | TcId int64 142 | UUID int64 143 | Time int64 144 | TxId int64 145 | IDcard int64 146 | } 147 | 148 | func newchapBean() (a *chapBean) { 149 | a = &chapBean{Stat: 1, Code: 0, Key: sys.Conf.Pwd, TcId: 0, UUID: sys.UUID, Time: time.Now().UnixNano(), TxId: UUID64()} 150 | return 151 | } 152 | -------------------------------------------------------------------------------- /mesh/tnet.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mesh 9 | 10 | import ( 11 | "errors" 12 | . "github.com/donnie4w/gofer/hashmap" 13 | . "github.com/donnie4w/gofer/lock" 14 | "github.com/donnie4w/tim/log" 15 | . "github.com/donnie4w/tim/stub" 16 | "github.com/donnie4w/tim/sys" 17 | "os" 18 | "strings" 19 | "sync" 20 | "sync/atomic" 21 | "time" 22 | ) 23 | 24 | var clientLinkCache = NewMapL[string, int8]() 25 | var await = NewAwait[int8](1 << 8) 26 | var awaitCsBean = NewAwait[*CsBean](1 << 8) 27 | var strLock = NewStrlock(1 << 8) 28 | var once = &sync.Once{} 29 | var tnetservice = &tnetService{ok: []byte{5}} 30 | var chapTxTemp = NewLimitHashMap[int64, int8](1 << 15) 31 | var reTx = NewLimitHashMap[int64, int8](1 << 18) 32 | var reStream = NewLimitHashMap[int64, int8](1 << 18) 33 | var reStreamUUID = NewLimitHashMap[uint64, int32](1 << 18) 34 | 35 | var nodeCache = NewLimitHashMap[string, []int64](1 << 15) 36 | 37 | func init() { 38 | //sys.Client2Serve = client2Serve 39 | //sys.GetALLUUIDS = nodeWare.GetALLUUID 40 | //sys.GetRemoteNode = getRemoteNode 41 | //sys.Csuser = nodeWare.csuser 42 | //sys.WssTt = nodeWare.wsstt 43 | //sys.Unaccess = nodeWare.unaccess 44 | //sys.CsMessage = nodeWare.csmessage 45 | //sys.CsPresence = nodeWare.cspresence 46 | //sys.CsWssInfo = nodeWare.cswssinfo 47 | //sys.CsVBean = nodeWare.csVbean 48 | //sys.CsNode = nodeWare.csnode 49 | } 50 | 51 | type tnetService struct { 52 | ok []byte 53 | } 54 | 55 | func (this *tnetService) Serve() (err error) { 56 | if sys.Conf.CsListen != "" { 57 | err = this._serve(sys.Conf.CsListen) 58 | } 59 | return 60 | } 61 | 62 | func (this *tnetService) _serve(addr string) (err error) { 63 | tnetserver := &tnetServer{ok: this.ok} 64 | tnetserver.handle(&itnetServ{NewNumLock(64)}, myServer2ClientHandler, mySecvErrorHandler) 65 | go once.Do(heardbeat) 66 | return tnetserver.Serve(addr) 67 | } 68 | 69 | func (this *tnetService) Connect(addr string, async bool) (err1, err2 error) { 70 | if nodeWare.LenByAddr(addr) > 0 { 71 | err1 = errors.New("addr:" + addr + " already existed") 72 | } 73 | if addr == sys.Conf.CsAccess { 74 | err1 = errors.New("addr:" + addr + " is local addr") 75 | } 76 | if addr = strings.Trim(addr, " "); addr == "" { 77 | err1 = errors.New("addr is bad") 78 | } 79 | if err1 != nil { 80 | return 81 | } 82 | log.Debug("conn:", addr) 83 | tnetserver := new(tnetServer) 84 | tnetserver.handle(&itnetServ{NewNumLock(64)}, myClient2ServerHandler, myCliErrorHandler) 85 | err2 = tnetserver.Connect(addr, async) 86 | return 87 | } 88 | 89 | func (this *tnetService) connectLoop(addr string, async bool, loopNum int) (err1, err2 error) { 90 | i := 0 91 | for i < loopNum { 92 | i++ 93 | err1, err2 = this.Connect(addr, async) 94 | if err1 != nil { 95 | return 96 | } 97 | if err1 == nil && err2 == nil { 98 | return 99 | } 100 | <-time.After(time.Second) 101 | } 102 | return 103 | } 104 | 105 | func (this *tnetService) Close() (err error) { 106 | if sys.Conf.CsListen != "" { 107 | tsfclientserver.close() 108 | nodeWare.close() 109 | } 110 | return 111 | } 112 | 113 | func (this *tnetService) Ok() bool { 114 | return this.ok[0] == 1 115 | } 116 | 117 | func client2Serve(addr string) (err error) { 118 | if sys.Conf.CsListen == "" { 119 | return errors.New("node is stand-alone") 120 | } 121 | if nodeWare.LenByAddr(addr) > 0 { 122 | return errors.New("addr:" + addr + " already existed") 123 | } 124 | if addr == sys.Conf.CsListen { 125 | return errors.New("addr:" + addr + " is local addr") 126 | } 127 | if addr = strings.Trim(addr, " "); addr == "" { 128 | return errors.New("addr is bad") 129 | } 130 | err1, err2 := tnetservice.Connect(addr, true) 131 | if err1 != nil { 132 | err = err1 133 | } 134 | if err2 != nil { 135 | err = err2 136 | } 137 | return 138 | } 139 | 140 | var lnetservice = &lnetService{} 141 | 142 | type lnetService struct { 143 | v int8 144 | c int64 145 | } 146 | 147 | func (this *lnetService) Serve() (err error) { 148 | if sys.Conf.Public != "" { 149 | _, err = tnetservice.connectLoop(sys.Conf.Public, true, 15) 150 | } 151 | return 152 | } 153 | 154 | func (this *lnetService) _server(node string) (err error) { 155 | this.v++ 156 | go this.connect(this.v) 157 | <-time.After(5 * time.Second) 158 | sys.LA = false 159 | if err = tnetservice._serve(node); err != nil && this.c < 10 { 160 | this.c++ 161 | sys.LA = true 162 | this.Serve() 163 | } else if this.c >= 10 { 164 | this.Close() 165 | } 166 | return 167 | } 168 | 169 | func (this *lnetService) Connect(addr string, async bool) (err1, err2 error) { 170 | return 171 | } 172 | func (this *lnetService) Close() (err error) { 173 | os.Exit(0) 174 | return 175 | } 176 | 177 | func (this *lnetService) connect(v int8) { 178 | i := int32(0) 179 | for !tnetservice.Ok() && v == this.v { 180 | if atomic.AddInt32(&i, 1) > 60 { 181 | break 182 | } 183 | <-time.After(1 * time.Second) 184 | } 185 | if tnetservice.Ok() && v == this.v { 186 | this.Serve() 187 | } 188 | } 189 | 190 | func getRemoteNode() []*RemoteNode { 191 | return nodeWare.getRemoteNodes() 192 | } 193 | 194 | var netservice = &netService{} 195 | 196 | type netService struct { 197 | service sys.Server 198 | } 199 | 200 | func (this *netService) Serve() (err error) { 201 | if sys.LA { 202 | this.service = lnetservice 203 | } else { 204 | this.service = tnetservice 205 | } 206 | go this.service.Serve() 207 | return nil 208 | } 209 | 210 | func (this *netService) Close() (err error) { 211 | return this.service.Close() 212 | } 213 | -------------------------------------------------------------------------------- /mesh/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mesh 9 | 10 | import ( 11 | . "github.com/donnie4w/gofer/buffer" 12 | . "github.com/donnie4w/gofer/hashmap" 13 | . "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/errs" 15 | . "github.com/donnie4w/tim/stub" 16 | "github.com/donnie4w/tim/sys" 17 | "github.com/donnie4w/tim/vgate" 18 | "sync/atomic" 19 | ) 20 | 21 | func bkCsuserBatch(nodem map[string]int8, srcUuid int64, stat int8) { 22 | if sys.MaxBackup > 0 { 23 | bkm := map[int64]map[string]int64{} 24 | for k := range nodem { 25 | if bckNode, ok := nodeWare.bkuuid(k); ok && len(bckNode) > 0 { 26 | for _, n := range bckNode { 27 | if n != srcUuid { 28 | if bn, ok := bkm[n]; ok { 29 | bn[k] = srcUuid 30 | } else { 31 | bkm[n] = map[string]int64{k: srcUuid} 32 | } 33 | } 34 | } 35 | } 36 | } 37 | for k, bn := range bkm { 38 | nodeWare.csuserHandle(k, &CsUser{Stat: stat, BkNode: bn}) 39 | } 40 | } 41 | } 42 | 43 | func bkCsVr(vb *VBean, srcuuid int64) { 44 | if nodes, ok := nodeWare.bkuuid(vb.Vnode); ok && len(nodes) > 0 { 45 | vb.Rtype = vb.Rtype + 50 46 | for _, u := range nodes { 47 | if u != srcuuid { 48 | nodeWare.csVrHandle(u, 0, vb) 49 | } 50 | } 51 | } 52 | } 53 | 54 | func processVBean(vrb *VBean, srcuuid int64) { 55 | switch vrb.Rtype { 56 | case 1: 57 | vgate.VGate.Register(*vrb.FoundNode, vrb.Vnode) 58 | bkCsVr(vrb, srcuuid) 59 | case 2: 60 | vgate.VGate.Remove(*vrb.FoundNode, vrb.Vnode) 61 | bkCsVr(vrb, srcuuid) 62 | case 3: 63 | //vgate.VGate.AddAuth(vrb.Vnode, *vrb.FoundNode, *vrb.Rnode) 64 | //bkCsVr(vrb, srcuuid) 65 | case 4: 66 | //vgate.VGate.DelAuth(vrb.Vnode, *vrb.FoundNode, *vrb.Rnode) 67 | //bkCsVr(vrb, srcuuid) 68 | case 5: 69 | if _, b := vgate.VGate.GetVroom(vrb.Vnode); b { 70 | vgate.VGate.Sub(vrb.Vnode, srcuuid, 0) 71 | } else { 72 | nodeWare.csVrHandle(srcuuid, 0, &VBean{Rtype: 10, Vnode: vrb.Vnode, Rnode: vrb.Rnode}) 73 | } 74 | case 6: 75 | vgate.VGate.UnSubWithUUID(vrb.Vnode, srcuuid) 76 | case 7: 77 | go sys.TimSteamProcessor(vrb, sys.TRANS_SOURCE) 78 | if vr, ok := vgate.VGate.GetVroom(vrb.Vnode); ok { 79 | if !vr.AuthStream(*vrb.Rnode) { 80 | nodeWare.csVrHandle(srcuuid, 0, &VBean{Rtype: 9, Vnode: vrb.Vnode, Rnode: vrb.Rnode}) 81 | return 82 | } 83 | vr.Updatetime() 84 | vrb.Rtype = 50 + vrb.Rtype 85 | m := map[int64]int8{} 86 | vgate.VGate.GetSubUUID(vrb.Vnode).Range(func(k int64, _ int8) bool { 87 | if k != srcuuid { 88 | m[k] = 0 89 | nodeWare.csVrHandle(k, 0, vrb) 90 | } 91 | return true 92 | }) 93 | if li, ok := nodeWare.bkuuid(vrb.Vnode); ok && len(li) > 0 { 94 | for _, u := range li { 95 | if _, ok := m[u]; !ok && u != srcuuid { 96 | m[u] = 0 97 | nodeWare.csVrHandle(u, 0, vrb) 98 | } 99 | } 100 | } 101 | } else { 102 | nodeWare.csVrHandle(srcuuid, 0, &VBean{Rtype: 8, Vnode: vrb.Vnode, Rnode: vrb.Rnode}) 103 | } 104 | case 8: 105 | f := false 106 | if vr, ok := vgate.VGate.GetVroom(vrb.Vnode); ok { 107 | if vr.FoundNode != "" { 108 | nodeWare.csVrHandle(srcuuid, 0, &VBean{Rtype: 1, Vnode: vrb.Vnode, FoundNode: &vr.FoundNode}) 109 | //vr.AuthMap().Range(func(k string, _ int8) bool { 110 | // nodeWare.csVrHandle(srcuuid, 0, &VBean{Rtype: 3, Vnode: vrb.Vnode, FoundNode: &vr.FoundNode, Rnode: &k}) 111 | // return true 112 | //}) 113 | f = true 114 | } 115 | } 116 | if !f { 117 | sys.SendNode(*vrb.Rnode, &TimAck{Ok: false, TimType: int8(sys.TIMSTREAM), Error: errs.ERR_NOEXIST.TimError()}, sys.TIMACK) 118 | } 119 | case 9: 120 | sys.SendNode(*vrb.Rnode, &TimAck{Ok: false, TimType: int8(sys.TIMSTREAM), Error: errs.ERR_PERM_DENIED.TimError(), N: &vrb.Vnode}, sys.TIMACK) 121 | case 10: 122 | sys.SendNode(*vrb.Rnode, &TimAck{Ok: false, TimType: int8(sys.TIMVROOM), Error: errs.ERR_NOEXIST.TimError(), N: &vrb.Vnode}, sys.TIMACK) 123 | case 51: 124 | vgate.VGate.Register(*vrb.FoundNode, vrb.Vnode) 125 | case 52: 126 | vgate.VGate.Remove(*vrb.FoundNode, vrb.Vnode) 127 | case 53: 128 | //vgate.VGate.AddAuth(vrb.Vnode, *vrb.FoundNode, *vrb.Rnode) 129 | case 54: 130 | //vgate.VGate.DelAuth(vrb.Vnode, *vrb.FoundNode, *vrb.Rnode) 131 | case 57: 132 | //problem->send repeatedly 133 | if !reStream.Contains(*vrb.StreamId) { 134 | reStream.Put(*vrb.StreamId, 0) 135 | sys.TimSteamProcessor(vrb, sys.TRANS_GOAL) 136 | } else { 137 | buf := NewBufferByPool() 138 | defer buf.Free() 139 | buf.WriteString(vrb.Vnode) 140 | buf.WriteString(sys.Conf.Salt) 141 | buf.Write(Int64ToBytes(srcuuid)) 142 | f := CRC64(buf.Bytes()) 143 | if i, ok := reStreamUUID.Get(f); ok { 144 | if i > 5 { 145 | vb := &VBean{Rtype: 6, Vnode: vrb.Vnode} 146 | nodeWare.csVrHandle(srcuuid, 0, vb) 147 | } else { 148 | reStreamUUID.Put(f, atomic.AddInt32(&i, 1)) 149 | } 150 | } else { 151 | reStreamUUID.Put(f, 1) 152 | } 153 | } 154 | default: 155 | } 156 | } 157 | 158 | func (nd *nodeware) wsstt() (_r int64) { 159 | tcc := nd.GetAllTlContext() 160 | for _, tc := range tcc { 161 | _r += tc.onNum 162 | } 163 | _r += sys.WssLen() 164 | return 165 | } 166 | 167 | var _unaccess = NewMap[int64, int8]() 168 | 169 | func (nd *nodeware) unaccess() (_r []int64) { 170 | _r = make([]int64, 0) 171 | _unaccess.Range(func(k int64, _ int8) bool { 172 | _r = append(_r, k) 173 | return true 174 | }) 175 | return 176 | } 177 | -------------------------------------------------------------------------------- /mq/mq.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package mq 9 | 10 | import ( 11 | "errors" 12 | "github.com/donnie4w/gofer/hashmap" 13 | goutil "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/stub" 15 | "github.com/donnie4w/tim/sys" 16 | "github.com/donnie4w/tim/util" 17 | "sync" 18 | ) 19 | 20 | var mq = newMqBean() 21 | 22 | func Sub(topicType TopicType, id int64, f func(any)) { 23 | mq.Sub(topicType, id, f) 24 | } 25 | 26 | func Unsub(topicType TopicType, id int64) { 27 | mq.UnSub(topicType, id) 28 | } 29 | 30 | func Push(topicType TopicType, msg any) { 31 | defer util.Recover() 32 | mq.Push(topicType, msg) 33 | } 34 | 35 | type mqBean struct { 36 | topicmap *hashmap.MapL[TopicType, *hashmap.Map[int64, func(any)]] 37 | mux *sync.RWMutex 38 | } 39 | 40 | func newMqBean() *mqBean { 41 | return &mqBean{topicmap: hashmap.NewMapL[TopicType, *hashmap.Map[int64, func(any)]](), mux: new(sync.RWMutex)} 42 | } 43 | 44 | func (m *mqBean) Sub(topicType TopicType, id int64, f func(any)) error { 45 | if !m.check(topicType) || id == 0 || f == nil { 46 | return errors.New("invalid param") 47 | } 48 | var cm *hashmap.Map[int64, func(any)] 49 | if hm, b := m.topicmap.Get(topicType); b { 50 | cm = hm 51 | } else { 52 | m.mux.Lock() 53 | defer m.mux.Unlock() 54 | if hm, b := m.topicmap.Get(topicType); b { 55 | cm = hm 56 | } else { 57 | cm = hashmap.NewMap[int64, func(any)]() 58 | m.topicmap.Put(topicType, cm) 59 | } 60 | } 61 | cm.Put(id, f) 62 | return nil 63 | } 64 | 65 | func (m *mqBean) check(topicType TopicType) bool { 66 | switch topicType { 67 | case ONLINESTATUS: 68 | return true 69 | } 70 | return false 71 | } 72 | 73 | func (m *mqBean) UnSub(topicType TopicType, id int64) { 74 | if hm, b := m.topicmap.Get(topicType); b { 75 | hm.Del(id) 76 | } 77 | } 78 | 79 | func (m *mqBean) Len() int64 { 80 | return m.topicmap.Len() 81 | } 82 | 83 | func (m *mqBean) Push(topicType TopicType, bean any) { 84 | if m.Len() > 0 { 85 | if hm, b := m.topicmap.Get(topicType); b { 86 | hm.Range(func(_ int64, v func(any)) bool { 87 | v(bean) 88 | return true 89 | }) 90 | } 91 | } 92 | } 93 | 94 | type TopicType int8 95 | 96 | var ONLINESTATUS TopicType = 1 97 | 98 | func PushOnline(node string, on bool) { 99 | ab := stub.NewAdmSubBean() 100 | st := int8(ONLINESTATUS) 101 | ab.SubType = &st 102 | asob := stub.NewAdmSubOnlineBean() 103 | asob.Node = &node 104 | if on { 105 | asob.Status = &sys.ONLINE 106 | } else { 107 | asob.Status = &sys.OFFLIINE 108 | } 109 | ab.Bs = goutil.TEncode(asob) 110 | Push(ONLINESTATUS, ab) 111 | } 112 | -------------------------------------------------------------------------------- /stub/stub_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | // 8 | 9 | package stub 10 | 11 | import ( 12 | "github.com/donnie4w/gofer/util" 13 | "testing" 14 | ) 15 | 16 | func Test_json(t *testing.T) { 17 | n, p := "helloworld", "123abc" 18 | ta := &TimAuth{Name: &n, Pwd: &p} 19 | bs := util.JsonEncode(ta) 20 | t.Log(len(bs), ">>", string(bs)) 21 | t.Log(util.JsonDecode[*TimAuth](bs)) 22 | } 23 | 24 | func Test_tcode(t *testing.T) { 25 | n, p := "helloworld", "123abc" 26 | ta := &TimAuth{Name: &n, Pwd: &p} 27 | bs := util.TEncode(ta) 28 | t.Log(len(bs), ">>", string(bs)) 29 | t.Log(util.TDecode(bs, &TimAuth{})) 30 | } 31 | 32 | func Test_tcode2(t *testing.T) { 33 | s := "123" 34 | ta := &TimMessage{DataString: &s} 35 | bs := util.TEncode(ta) 36 | t.Log(len(bs), ">>", string(bs)) 37 | t.Log(util.TDecode(bs, &TimMessage{})) 38 | } 39 | -------------------------------------------------------------------------------- /sys/const.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package sys 9 | 10 | type DBMOD byte 11 | 12 | const ( 13 | NODB DBMOD = 1 14 | TLDB DBMOD = 2 15 | INLINEDB DBMOD = 3 16 | EXTERNALDB DBMOD = 4 17 | MONGODB DBMOD = 5 18 | CASSANDRA DBMOD = 6 19 | ) 20 | 21 | const ( 22 | MB = 1 << 20 23 | GB = 1 << 30 24 | ) 25 | 26 | const ( 27 | TRANS_SOURCE int8 = 1 28 | TRANS_CONSISHASH int8 = 2 29 | TRANS_STAFF int8 = 3 30 | TRANS_GOAL int8 = 4 31 | ) 32 | 33 | const ( 34 | ORDER_INOF int8 = 1 35 | ORDER_REVOKE int8 = 2 36 | ORDER_BURN int8 = 3 37 | ORDER_BUSINESS int8 = 4 38 | ORDER_STREAM int8 = 5 39 | ORDER_BIGSTRING int8 = 6 40 | ORDER_BIGBINARY int8 = 7 41 | ORDER_RESERVED int8 = 30 42 | ) 43 | 44 | const ( 45 | CB_MESSAGE int8 = 1 46 | CB_PRESENCE int8 = 2 47 | ) 48 | 49 | type CSTYPE byte 50 | 51 | const ( 52 | CS_RAFTX CSTYPE = 1 53 | CS_REDIS CSTYPE = 2 54 | CS_ETCD CSTYPE = 3 55 | CS_ZOOKEEPER CSTYPE = 4 56 | CS_RAX CSTYPE = 5 57 | ) 58 | 59 | const ( 60 | SOURCE_OS int8 = 1 61 | SOURCE_USER int8 = 2 62 | SOURCE_ROOM int8 = 3 63 | ) 64 | 65 | var ( 66 | ONLINE int8 = 1 67 | OFFLIINE int8 = 2 68 | ) 69 | 70 | const ( 71 | _ = iota 72 | INIT_SYS 73 | INIT_AMR 74 | INIT_KEYSTORE 75 | INIT_DATA 76 | INIT_TC 77 | INIT_MESH 78 | INIT_ADM 79 | INIT_TRANS 80 | INIT_INET 81 | ) 82 | 83 | const ( 84 | timlogo = ` 85 | ████████████████╗ ████╗ ██████╗ ██████╗ 86 | ╚═════████╔═════╝ ████║ ████████╗ ████████║ 87 | ████║ ████║ ████╔████████╔████║ 88 | ████║ ████║ ████║ ╚████╔═╝████║ 89 | ████║ ████║ ████║ ╚═══╝ ████║ 90 | ╚═══╝ ╚═══╝ ╚═══╝ ╚═══╝ 91 | ` 92 | 93 | dfaultCfg = `{ 94 | "client_listen": ":20003", 95 | "webadmin_listen": ":20002", 96 | "server_api_listen": ":20001", 97 | "connect_limit": 1000000, 98 | "request_rate": 100, 99 | "memLimit": 512, 100 | "inlinedb": { 101 | "sqlite": {"dbname": "tim.db"} 102 | } 103 | }` 104 | ) 105 | -------------------------------------------------------------------------------- /sys/flag.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package sys 9 | 10 | import ( 11 | "flag" 12 | "fmt" 13 | "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/log" 15 | "github.com/donnie4w/tim/stub" 16 | "os" 17 | "runtime" 18 | "runtime/debug" 19 | "sync/atomic" 20 | "time" 21 | ) 22 | 23 | func praseflag() { 24 | flag.StringVar(&TIMJSON, "c", "tim.json", "configuration file of tim in json") 25 | flag.StringVar(&ORIGIN, "origin", "", "origin for websocket") 26 | flag.IntVar(&GOGC, "gc", -1, "a collection is triggered when the ratio of freshly allocated data") 27 | flag.Usage = usage 28 | flag.Parse() 29 | flag.Usage() 30 | parser() 31 | 32 | if Conf.Pwd == "" { 33 | Conf.Pwd = defaultPwd 34 | } 35 | if Conf.EncryptKey == "" { 36 | Conf.EncryptKey = defaultAesencryptkey 37 | } 38 | if Conf.MaskSeed != "" { 39 | MaskSeed = util.Int64ToBytes(int64(util.FNVHash64([]byte(Conf.MaskSeed)))) 40 | } 41 | if Conf.Salt == "" { 42 | Conf.Salt = defaultSalt 43 | } 44 | if Conf.PingTo <= 0 { 45 | Conf.PingTo = defaultPingTimeot 46 | } 47 | if Conf.MaxBackup != nil { 48 | MaxBackup = *Conf.MaxBackup 49 | } 50 | if Conf.NodeMaxlength != nil { 51 | NodeMaxSize = *Conf.NodeMaxlength 52 | } 53 | if Conf.RequestRate <= 0 { 54 | Conf.RequestRate = defaultLimitRate 55 | } 56 | 57 | if Conf.CacheAuthExpire == 0 { 58 | Conf.CacheAuthExpire = defaultCacheAuthExpire 59 | } 60 | 61 | if Conf.MaxMessageSize > 0 { 62 | MaxTransLength = Conf.MaxMessageSize * MB 63 | } 64 | 65 | if Conf.Memlimit <= 0 { 66 | Conf.Memlimit = defaultMemlimit 67 | } 68 | 69 | if Conf.DeviceLimit > 0 { 70 | DeviceLimit = Conf.DeviceLimit 71 | } 72 | 73 | if Conf.DevicetypeLimit > 0 { 74 | DeviceTypeLimit = Conf.DevicetypeLimit 75 | } 76 | 77 | if Conf.ConnectLimit <= 0 { 78 | Conf.ConnectLimit = defaultConnectLimit 79 | } 80 | 81 | if Conf.Bind != nil { 82 | Bind = *Conf.Bind 83 | } 84 | 85 | if Conf.TTL <= 0 { 86 | Conf.TTL = defaultTTL 87 | } 88 | 89 | if Conf.TokenTimeout <= 0 { 90 | Conf.TokenTimeout = defaultTokenTimeout 91 | } else { 92 | Conf.TokenTimeout = Conf.TokenTimeout * 1e9 93 | } 94 | 95 | if Conf.AdminAccount == nil { 96 | Conf.AdminAccount = defaultAdminAccount 97 | } 98 | 99 | //if Conf.Security != nil && Conf.BlockAPI != nil { 100 | // BlockApiMap = hashmap.NewMap[TIMTYPE, int8]() 101 | // for _, v := range Conf.BlockAPI { 102 | // BlockApiMap.Put(TIMTYPE(v), 0) 103 | // } 104 | //} 105 | 106 | debug.SetMemoryLimit(int64(Conf.Memlimit) * MB) 107 | debug.SetGCPercent(GOGC) 108 | Stat = &stat{} 109 | } 110 | 111 | func usage() { 112 | exename := "tim" 113 | if runtime.GOOS == "windows" { 114 | exename = "tim.exe" 115 | } 116 | fmt.Fprintln(os.Stderr, `tim version: tim/`+VERSION+` 117 | Usage: `+exename+` 118 | -c: configuration file e.g: -c tim.json 119 | `) 120 | } 121 | 122 | func Service(init int, se Server) { 123 | service.Put(init, se) 124 | } 125 | 126 | func parser() { 127 | if bs, err := util.ReadFile(TIMJSON); err == nil { 128 | if Conf, err = util.JsonDecode[*stub.ConfBean](bs); err != nil { 129 | log.FmtPrint("configuration file[", TIMJSON, "] parsing error:", err) 130 | os.Exit(1) 131 | } 132 | } else { 133 | os.WriteFile(TIMJSON, []byte(dfaultCfg), os.ModePerm) 134 | Conf, _ = util.JsonDecode[*stub.ConfBean]([]byte(dfaultCfg)) 135 | } 136 | } 137 | 138 | type stat struct { 139 | creq int64 140 | cpros int64 141 | tx int64 142 | ibs int64 143 | obs int64 144 | } 145 | 146 | func (this *stat) CReq() int64 { 147 | return this.creq 148 | } 149 | func (this *stat) CReqDo() { 150 | atomic.AddInt64(&this.creq, 1) 151 | } 152 | func (this *stat) CReqDone() { 153 | atomic.AddInt64(&this.creq, -1) 154 | } 155 | 156 | func (this *stat) CPros() int64 { 157 | return this.cpros 158 | } 159 | func (this *stat) CProsDo() { 160 | atomic.AddInt64(&this.cpros, 1) 161 | } 162 | func (this *stat) CProsDone() { 163 | atomic.AddInt64(&this.cpros, -1) 164 | } 165 | 166 | func (this *stat) Tx() int64 { 167 | return this.tx 168 | } 169 | func (this *stat) TxDo() { 170 | atomic.AddInt64(&this.tx, 1) 171 | } 172 | func (this *stat) TxDone() { 173 | atomic.AddInt64(&this.tx, -1) 174 | } 175 | 176 | func (this *stat) Ibs() int64 { 177 | return this.ibs 178 | } 179 | func (this *stat) Ib(i int64) { 180 | atomic.AddInt64(&this.ibs, i) 181 | } 182 | func (this *stat) Obs() int64 { 183 | return this.obs 184 | } 185 | func (this *stat) Ob(i int64) { 186 | atomic.AddInt64(&this.obs, i) 187 | } 188 | 189 | func tkSqlProperty() { 190 | tk := time.NewTicker(time.Minute) 191 | for { 192 | select { 193 | case <-tk.C: 194 | func() { 195 | defer func() { recover() }() 196 | now := time.Now() 197 | t0 := now.Unix() 198 | t1 := time.Date(now.Year(), now.Month(), now.Day(), now.Hour()+1, 0, 0, 0, now.Location()).Unix() 199 | <-time.After(time.Duration(t1-t0) * (time.Second)) 200 | if bs, err := util.ReadFile(TIMJSON); err == nil { 201 | Conf, _ = util.JsonDecode[*stub.ConfBean](bs) 202 | } 203 | }() 204 | } 205 | } 206 | } 207 | 208 | func Start() { 209 | service.Ascend(func(_ int, s Server) bool { 210 | time.Sleep(10 * time.Millisecond) 211 | return s.Serve() == nil 212 | }) 213 | select {} 214 | } 215 | -------------------------------------------------------------------------------- /sys/sys.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package sys 9 | 10 | import ( 11 | "github.com/donnie4w/tim/log" 12 | "os" 13 | ) 14 | 15 | func init() { 16 | Service(INIT_SYS, server(0)) 17 | } 18 | 19 | type server byte 20 | 21 | func (s server) Serve() error { 22 | praseflag() 23 | log.Warn(timlogo) 24 | return nil 25 | } 26 | 27 | func (s server) Close() (err error) { 28 | service.Descend(func(_ int, s Server) bool { 29 | s.Close() 30 | return true 31 | }) 32 | os.Exit(0) 33 | return 34 | } 35 | 36 | func UseBuiltInData() bool { 37 | return Conf.InlineDB != nil || len(Conf.InlineExtent) > 0 || Conf.Tldb != nil || len(Conf.TldbExtent) > 0 || Conf.Mongodb != nil || len(Conf.MongodbExtent) > 0 38 | } 39 | 40 | type Server interface { 41 | Serve() (err error) 42 | Close() (err error) 43 | } 44 | 45 | type istat interface { 46 | CReq() int64 47 | CReqDo() 48 | CReqDone() 49 | 50 | CPros() int64 51 | CProsDo() 52 | CProsDone() 53 | 54 | Tx() int64 55 | TxDo() 56 | TxDone() 57 | 58 | Ibs() int64 59 | Ib(int64) 60 | 61 | Obs() int64 62 | Ob(int64) 63 | } 64 | 65 | func GetDBMOD() DBMOD { 66 | if Conf.InlineDB != nil || len(Conf.InlineExtent) > 0 { 67 | return INLINEDB 68 | } 69 | if Conf.Tldb != nil || len(Conf.TldbExtent) > 0 { 70 | return TLDB 71 | } 72 | if Conf.Mongodb != nil || len(Conf.MongodbExtent) > 0 { 73 | return MONGODB 74 | } 75 | if Conf.ExternalDB != nil { 76 | return EXTERNALDB 77 | } 78 | if Conf.NoDB != nil && *Conf.NoDB { 79 | return NODB 80 | } 81 | return INLINEDB 82 | } 83 | 84 | func GetCstype() CSTYPE { 85 | if Conf.Raftx != nil { 86 | return CS_RAFTX 87 | } 88 | if Conf.Rax != nil { 89 | return CS_RAX 90 | } 91 | if Conf.Redis != nil { 92 | return CS_REDIS 93 | } 94 | if Conf.Etcd != nil { 95 | return CS_ETCD 96 | } 97 | if Conf.ZooKeeper != nil { 98 | return CS_ZOOKEEPER 99 | } 100 | return 0 101 | } 102 | -------------------------------------------------------------------------------- /sys/var.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package sys 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/hashmap" 12 | "github.com/donnie4w/gofer/util" 13 | "github.com/donnie4w/tim/stub" 14 | "time" 15 | ) 16 | 17 | const VERSION = "2.1.0" 18 | 19 | var ( 20 | STARTTIME = time.Now() 21 | MaskSeed = util.Int64ToBytes(int64(1 << 60)) 22 | UUIDCSTIME = 180 //180 second 23 | ConnectTimeout = 10 * time.Second 24 | WaitTimeout = 10 * time.Second 25 | MaxTransLength = 10 * MB 26 | DeviceLimit = 1 27 | DeviceTypeLimit = 1 28 | MaxBackup = 3 29 | NodeMaxSize = 64 30 | OpenSSL = &stub.Openssl{} 31 | UUID int64 32 | GOGC int 33 | ORIGIN string 34 | TIMJSON string 35 | SEP_BIN = byte(131) 36 | SEP_STR = "|" 37 | Stat istat 38 | Conf *stub.ConfBean 39 | service = hashmap.NewTreeMap[int, Server](5) 40 | defaultAdminAccount = &stub.AdminAccount{Username: "admin", Password: "123"} 41 | defaultPingTimeot = int64(600) // 600 second 42 | defaultPwd = "tim20171212" 43 | defaultAesencryptkey = "ie8*&(I984){bW{@a@#¥%H'" 44 | defaultConnectLimit = int64(1 << 24) 45 | defaultMemlimit = 1 << 10 46 | defaultSalt = "#@*=+-<>?:|$&()%$#{]aQkLIPM79643028U'TRKF_}" 47 | defaultLimitRate = int64(1 << 8) 48 | defaultTTL = uint64(24 * 60 * 60) // 1 day 49 | defaultTokenTimeout = 10 * time.Second.Nanoseconds() 50 | defaultCacheAuthExpire = int64(300) //300 Second 51 | ) 52 | 53 | var ( 54 | LA bool 55 | Bind string 56 | ) 57 | -------------------------------------------------------------------------------- /tc/adm.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "bytes" 12 | "github.com/donnie4w/gofer/hashmap" 13 | goutil "github.com/donnie4w/gofer/util" 14 | "github.com/donnie4w/tim/adm" 15 | "github.com/donnie4w/tim/mq" 16 | "github.com/donnie4w/tim/stub" 17 | "github.com/donnie4w/tim/sys" 18 | "github.com/donnie4w/tim/util" 19 | "github.com/donnie4w/tlnet" 20 | "time" 21 | ) 22 | 23 | func init() { 24 | go expiredTimer() 25 | } 26 | 27 | func wsAdmConfig() *tlnet.WebsocketConfig { 28 | wc := &tlnet.WebsocketConfig{} 29 | wc.Origin = sys.ORIGIN 30 | wc.OnError = func(self *tlnet.Websocket) { 31 | mq.Unsub(mq.ONLINESTATUS, self.Id) 32 | admwsware.delws(self) 33 | } 34 | wc.OnOpen = func(hc *tlnet.HttpContext) { 35 | expiredMap.Put(hc.WS, time.Now().Unix()) 36 | } 37 | return wc 38 | } 39 | 40 | func wsAdmHandler(hc *tlnet.HttpContext) { 41 | defer util.Recover() 42 | bs := make([]byte, len(hc.WS.Read())) 43 | sys.Stat.Ib(int64(len(bs))) 44 | copy(bs, hc.WS.Read()) 45 | if t := sys.TIMTYPE(bs[0] & 0x7f); t != sys.ADMAUTH && t != sys.ADMPING && !isAuth(hc.WS) { 46 | hc.WS.Close() 47 | return 48 | } 49 | go processor(hc.WS, bs) 50 | } 51 | 52 | func processor(ws *tlnet.Websocket, bs []byte) { 53 | defer util.Recover() 54 | switch sys.TIMTYPE(bs[0] & 0x7f) { 55 | case sys.ADMPING: 56 | admwsware.Ping(ws.Id) 57 | case sys.ADMAUTH: 58 | if ab, err := goutil.TDecode(bs[1:], stub.NewAuthBean()); err == nil { 59 | ack := adm.Auth(ab) 60 | if ack != nil && ack.GetOk() { 61 | expiredMap.Delete(ws) 62 | admwsware.Addws(ws) 63 | } 64 | admwsware.SendWs(ws, ack, sys.ADMAUTH) 65 | } 66 | case sys.ADMSUB: 67 | if adb, err := goutil.TDecode(bs[1:], stub.NewAdmSubBean()); err == nil { 68 | switch mq.TopicType(adb.GetSubType()) { 69 | case mq.ONLINESTATUS: 70 | mq.Sub(mq.ONLINESTATUS, ws.Id, func(a any) { 71 | adb.Bs = a.(*stub.AdmSubBean).GetBs() 72 | admwsware.Send(ws.Id, adb, sys.ADMSUB) 73 | }) 74 | } 75 | } 76 | case sys.ADMSTREAM: 77 | case sys.ADMBIGSTRING: 78 | case sys.ADMBIGBINARY: 79 | case sys.ADMBIGBINARYSTREAM: 80 | bs = bs[1:] 81 | vnodeIdx := bytes.IndexByte(bs, sys.SEP_BIN) 82 | vnode := string(bs[:vnodeIdx]) 83 | bs = bs[vnodeIdx+1:] 84 | fnodeIdx := bytes.IndexByte(bs, sys.SEP_BIN) 85 | fnode := string(bs[:fnodeIdx]) 86 | bs = bs[fnodeIdx+1:] 87 | sid := goutil.UUID64() 88 | vb := &stub.VBean{StreamId: &sid, Vnode: vnode, Rnode: &fnode, Body: bs, Rtype: int8(sys.VROOM_MESSAGE)} 89 | if b, _ := sys.TimSteamProcessor(vb, sys.TRANS_GOAL); !b { 90 | ok, n, t := false, vnode, int64(int32(goutil.FNVHash32(goutil.Int64ToBytes(sys.UUID)))) 91 | ack := stub.NewAdmAck() 92 | ack.Ok = &ok 93 | ack.N = &n 94 | ack.T = &t 95 | admwsware.Send(ws.Id, ack, sys.ADMBIGBINARYSTREAM) 96 | } 97 | } 98 | } 99 | 100 | func isAuth(ws *tlnet.Websocket) (_b bool) { 101 | return admwsware.hasws(ws) 102 | } 103 | 104 | var expiredMap = hashmap.NewLinkedHashMap[*tlnet.Websocket, int64](1<<63 - 1) 105 | 106 | func expiredTimer() { 107 | t := time.NewTicker(5 * time.Second) 108 | for { 109 | select { 110 | case <-t.C: 111 | func() { 112 | defer util.Recover() 113 | iter := expiredMap.Iterator(false) 114 | for { 115 | if k, v, ok := iter.Next(); ok { 116 | if v+5 < time.Now().Unix() { 117 | k.Close() 118 | admwsware.delws(k) 119 | expiredMap.Delete(k) 120 | continue 121 | } 122 | } 123 | break 124 | } 125 | }() 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /tc/admsock.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/buffer" 12 | "github.com/donnie4w/gofer/hashmap" 13 | "github.com/donnie4w/gofer/lock" 14 | goutil "github.com/donnie4w/gofer/util" 15 | "github.com/donnie4w/gothrift/thrift" 16 | "github.com/donnie4w/tim/errs" 17 | "github.com/donnie4w/tim/sys" 18 | "github.com/donnie4w/tim/util" 19 | "github.com/donnie4w/tlnet" 20 | "sync/atomic" 21 | ) 22 | 23 | var numLock = lock.NewNumLock(64) 24 | var await = lock.NewFastAwait[int8]() 25 | 26 | var admwsware = &wsware{wsmap: hashmap.NewMapL[int64, *WsSock]()} 27 | 28 | type wsware struct { 29 | wsmap *hashmap.MapL[int64, *WsSock] 30 | } 31 | 32 | func (t *wsware) Addws(ws *tlnet.Websocket) { 33 | numLock.Lock(ws.Id) 34 | defer numLock.Unlock(ws.Id) 35 | if t.wsmap.Has(ws.Id) { 36 | return 37 | } 38 | wss := NewWsSock(ws) 39 | t.wsmap.Put(ws.Id, wss) 40 | } 41 | 42 | func (t *wsware) Send(id int64, ts thrift.TStruct, tt sys.TIMTYPE) (_r bool) { 43 | if wss, ok := t.wsmap.Get(id); ok { 44 | if err := wss.send(ts, tt, false); err == nil { 45 | _r = ok 46 | } 47 | } 48 | return 49 | } 50 | 51 | func (t *wsware) SendWs(sock *tlnet.Websocket, ts thrift.TStruct, tt sys.TIMTYPE) (_r bool) { 52 | if wss, ok := t.wsmap.Get(sock.Id); ok { 53 | if err := wss.send(ts, tt, false); err == nil { 54 | _r = ok 55 | } 56 | } else { 57 | NewWsSock(sock).send(ts, tt, false) 58 | } 59 | return 60 | } 61 | 62 | func (t *wsware) SendWsWithAck(id int64, ts thrift.TStruct, tt sys.TIMTYPE) (_r bool) { 63 | if wss, ok := t.wsmap.Get(id); ok { 64 | if err := wss.send(ts, tt, true); err == nil { 65 | _r = ok 66 | } 67 | } 68 | return 69 | } 70 | 71 | func (t *wsware) Ping(id int64) { 72 | if wss, ok := t.wsmap.Get(id); ok { 73 | wss.send(nil, sys.ADMPING, false) 74 | } 75 | } 76 | 77 | func (t *wsware) Get(ws *tlnet.Websocket) (*WsSock, bool) { 78 | return t.wsmap.Get(ws.Id) 79 | } 80 | 81 | func (t *wsware) hasws(ws *tlnet.Websocket) bool { 82 | return t.wsmap.Has(ws.Id) 83 | } 84 | 85 | func (t *wsware) wsById(id int64) (*tlnet.Websocket, bool) { 86 | if ws, b := t.wsmap.Get(id); b { 87 | return ws.ws, b 88 | } 89 | return nil, false 90 | } 91 | 92 | func (t *wsware) wsLen() int64 { 93 | return t.wsmap.Len() 94 | } 95 | 96 | func (t *wsware) delws(ws *tlnet.Websocket) { 97 | defer util.Recover() 98 | t.delId(ws.Id) 99 | } 100 | 101 | func (t *wsware) delId(id int64) { 102 | if sk, ok := t.wsmap.Get(id); ok { 103 | sk.ws.Close() 104 | t.wsmap.Del(id) 105 | } 106 | } 107 | 108 | type WsSock struct { 109 | ws *tlnet.Websocket 110 | } 111 | 112 | func NewWsSock(ws *tlnet.Websocket) (_r *WsSock) { 113 | _r = &WsSock{ws: ws} 114 | return 115 | } 116 | 117 | func (t *WsSock) _send(buf *buffer.Buffer) (err error) { 118 | sys.Stat.Ob(int64(buf.Len())) 119 | return t.ws.Send(buf.Bytes()) 120 | } 121 | 122 | var syncIndex atomic.Int32 123 | 124 | func (t *WsSock) send(ts thrift.TStruct, tt sys.TIMTYPE, sync bool) (err error) { 125 | length := 1 126 | if sync { 127 | length = 5 128 | } 129 | var bs []byte 130 | if ts != nil { 131 | bs = goutil.TEncode(ts) 132 | length += len(bs) 133 | } 134 | resendNum := byte(2) 135 | START: 136 | buf := buffer.NewBufferWithCapacity(length) 137 | var sendId int32 138 | if sync { 139 | sendId = syncIndex.Add(1) 140 | buf.WriteByte(byte(tt) | 0x80) 141 | buf.Write(goutil.Int32ToBytes(sendId)) 142 | } else { 143 | buf.WriteByte(byte(tt)) 144 | } 145 | if len(bs) > 0 { 146 | buf.Write(bs) 147 | } 148 | if err = t._send(buf); err == nil && sync { 149 | if _, err = await.Wait(int64(sendId), sys.WaitTimeout); err == nil { 150 | return 151 | } else if t.ws.Error == nil && resendNum > 0 { 152 | resendNum-- 153 | goto START 154 | } 155 | } 156 | if t.ws.Error != nil || err != nil { 157 | err = errs.ERR_OVERTIME.Error() 158 | } 159 | return 160 | } 161 | 162 | func (t *WsSock) close() { 163 | admwsware.delws(t.ws) 164 | } 165 | 166 | func awaitEnd(bs []byte) { 167 | await.Close(int64(goutil.BytesToInt32(bs))) 168 | } 169 | -------------------------------------------------------------------------------- /tc/bean.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "github.com/donnie4w/tim/stub" 12 | ) 13 | 14 | type SysVar struct { 15 | StartTime string 16 | Time string 17 | UUID int64 18 | CSNUM int32 19 | ALLUUIDS string 20 | ADDR string 21 | ADMINADDR string 22 | } 23 | 24 | type SysVarView struct { 25 | Show string 26 | SYS *SysVar 27 | RN []*stub.RemoteNode 28 | } 29 | 30 | type AdminView struct { 31 | Show string 32 | AdminUser map[string]string 33 | Init bool 34 | ShowCreate bool 35 | } 36 | 37 | type Tables struct { 38 | Name string 39 | Columns []string 40 | Idxs []string 41 | Seq int64 42 | Sub int64 43 | } 44 | 45 | type TData struct { 46 | Name string 47 | Id int64 48 | Columns map[string]string 49 | } 50 | 51 | type SelectBean struct { 52 | Name string 53 | Id string 54 | ColumnName string 55 | ColumnValue string 56 | StartId string 57 | Limit string 58 | } 59 | 60 | type DataView struct { 61 | Tb []*Tables 62 | Tds []*TData 63 | ColName map[string][]byte 64 | Sb *SelectBean 65 | Stat bool 66 | } 67 | 68 | /**********************************************************************************/ 69 | type SysParam struct { 70 | DBFILEDIR string 71 | MQTLS bool 72 | ADMINTLS bool 73 | CLITLS bool 74 | CLICRT string 75 | CLIKEY string 76 | MQCRT string 77 | MQKEY string 78 | ADMINCRT string 79 | ADMINKEY string 80 | COCURRENT_PUT int64 81 | COCURRENT_GET int64 82 | DBMode int 83 | NAMESPACE string 84 | VERSION string 85 | BINLOGSIZE int64 86 | ADDR string 87 | CLIADDR string 88 | MQADDR string 89 | WEBADMINADDR string 90 | CLUSTER_NUM int 91 | PWD string 92 | PUBLICKEY string 93 | PRIVATEKEY string 94 | CLUSTER_NUM_FINAL bool 95 | } 96 | 97 | type SysParamView struct { 98 | SYS *SysParam 99 | Stat bool 100 | } 101 | 102 | /**********************************************************************************/ 103 | type AlterTable struct { 104 | TableName string 105 | ID int64 106 | Columns map[string]*FieldInfo 107 | ColumnValue map[string]string 108 | } 109 | 110 | type FieldInfo struct { 111 | Idx bool 112 | Type string 113 | Tname string 114 | } 115 | -------------------------------------------------------------------------------- /tc/debug.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "github.com/donnie4w/tim/log" 12 | "github.com/donnie4w/tim/sys" 13 | "github.com/donnie4w/tim/util" 14 | "net/http" 15 | _ "net/http/pprof" 16 | "runtime" 17 | ) 18 | 19 | func tlDebug() { 20 | defer util.Recover() 21 | if sys.Conf.PprofAddr != "" { 22 | runtime.SetMutexProfileFraction(1) 23 | runtime.SetBlockProfileRate(1) 24 | var err error 25 | if sys.Conf.PprofAddr, err = util.ParseAddr(sys.Conf.PprofAddr); err == nil { 26 | log.FmtPrint("Http pprof Service start[", sys.Conf.PprofAddr, "]") 27 | if err := http.ListenAndServe(sys.Conf.PprofAddr, nil); err != nil { 28 | log.FmtPrint("Http pprof Service start failed:" + err.Error()) 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tc/monitor.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "encoding/json" 12 | "github.com/donnie4w/tim/sys" 13 | "github.com/shirou/gopsutil/v3/cpu" 14 | "github.com/shirou/gopsutil/v3/disk" 15 | "github.com/shirou/gopsutil/v3/mem" 16 | "runtime" 17 | "time" 18 | ) 19 | 20 | type dataMonitor struct { 21 | OnlineTotal int64 22 | Online int64 23 | Input int64 24 | Output int64 25 | Unaccess []int64 26 | } 27 | 28 | func getDataMonitor() (dm *dataMonitor) { 29 | dm = &dataMonitor{} 30 | dm.Input = sys.Stat.Ibs() 31 | dm.Output = sys.Stat.Obs() 32 | dm.Online = sys.WssLen() 33 | dm.OnlineTotal = 0 34 | dm.Unaccess = sys.Unaccess() 35 | return 36 | } 37 | 38 | func ddmonitorToJson() (_r string, err error) { 39 | var bs []byte 40 | if bs, err = json.Marshal(getDataMonitor()); err == nil { 41 | _r = string(bs) 42 | } 43 | return 44 | } 45 | 46 | type sysmonitor struct { 47 | Alloc uint64 48 | TotalAlloc uint64 49 | NumGC uint32 50 | NumTx int64 51 | CluserLoad int64 52 | NumGoroutine int 53 | NumCPU int 54 | RamUsage float64 55 | DiskFree uint64 56 | CpuUsage float64 57 | } 58 | 59 | func monitorToJson() (_r string, err error) { 60 | var bs []byte 61 | if bs, err = json.Marshal(getSysMonitor()); err == nil { 62 | _r = string(bs) 63 | } 64 | return 65 | } 66 | 67 | func getSysMonitor() (_r *sysmonitor) { 68 | _r = &sysmonitor{} 69 | var rtm runtime.MemStats 70 | runtime.ReadMemStats(&rtm) 71 | _r.NumGoroutine = runtime.NumGoroutine() 72 | _r.NumCPU = runtime.NumCPU() 73 | _r.NumTx = sys.Stat.Tx() 74 | _r.CluserLoad = sys.Stat.CReq() + sys.Stat.CPros() 75 | _r.Alloc = rtm.Alloc 76 | _r.TotalAlloc = rtm.TotalAlloc 77 | _r.NumGC = rtm.NumGC 78 | 79 | if ram, err := getRAM(); err == nil { 80 | _r.RamUsage = float64(ram.UsedMB) / float64(ram.TotalMB) 81 | } 82 | 83 | if d, err := getDisk(); err == nil { 84 | _r.DiskFree = d.TotalGB - d.UsedGB 85 | } 86 | 87 | if c, err := getCPU(); err == nil { 88 | s := float64(0) 89 | for _, v := range c.Cpus { 90 | s += v 91 | } 92 | _r.CpuUsage = s 93 | } 94 | 95 | return 96 | } 97 | 98 | type Cpu struct { 99 | Cpus []float64 100 | Cores int 101 | } 102 | 103 | type Ram struct { 104 | UsedMB uint64 105 | TotalMB uint64 106 | } 107 | 108 | type Disk struct { 109 | UsedGB uint64 110 | TotalGB uint64 111 | } 112 | 113 | func getRAM() (r Ram, err error) { 114 | if u, err := mem.VirtualMemory(); err == nil { 115 | r.UsedMB = u.Used / sys.MB 116 | r.TotalMB = u.Total / sys.MB 117 | } 118 | return r, nil 119 | } 120 | 121 | func getDisk() (d Disk, err error) { 122 | if u, err := disk.Usage("/"); err == nil { 123 | d.UsedGB = u.Used / uint64(sys.GB) 124 | d.TotalGB = u.Total / uint64(sys.GB) 125 | } 126 | return d, nil 127 | } 128 | 129 | func getCPU() (_r Cpu, err error) { 130 | _r.Cores, err = cpu.Counts(false) 131 | _r.Cpus, err = cpu.Percent(100*time.Millisecond, true) 132 | return 133 | } 134 | -------------------------------------------------------------------------------- /tc/processor.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "github.com/donnie4w/tim/log" 12 | "github.com/donnie4w/tlnet" 13 | htmlTpl "html/template" 14 | "os" 15 | textTpl "text/template" 16 | ) 17 | 18 | type TXTYPE int 19 | type LANG int 20 | 21 | const ( 22 | ZH LANG = 0 23 | EN LANG = 1 24 | ) 25 | 26 | const ( 27 | _ TXTYPE = iota 28 | LOGIN 29 | INIT 30 | SYSVAR 31 | DATA 32 | MONITOR 33 | ) 34 | 35 | var mod = 1 //0debug,1release 36 | 37 | func tplToHtml(lang LANG, flag TXTYPE, v any, hc *tlnet.HttpContext) { 38 | dir, _ := os.Getwd() 39 | switch flag { 40 | case LOGIN: 41 | tpl(lang, dir+"/tc/html/login.html", loginText, dir+"/tc/html/loginEn.html", loginEnText, v, hc) 42 | case INIT: 43 | tpl(lang, dir+"/tc/html/init.html", initText, dir+"/tc/html/initEn.html", initEnText, v, hc) 44 | case SYSVAR: 45 | tpl(lang, dir+"/tc/html/sysvar.html", sysvarText, dir+"/tc/html/sysvarEn.html", sysvarEnText, v, hc) 46 | case DATA: 47 | tpl(lang, dir+"/tc/html/data.html", dataText, dir+"/tc/html/dataEn.html", dataEnText, v, hc) 48 | case MONITOR: 49 | tpl(lang, dir+"/tc/html/monitor.html", monitorText, dir+"/tc/html/monitorEn.html", monitorEnText, v, hc) 50 | } 51 | } 52 | 53 | func tpl(lang LANG, tplZHPath, tplZHText, tplENPath, tplENText string, v any, hc *tlnet.HttpContext) { 54 | if lang == ZH { 55 | if mod == 0 { 56 | textTplByPath(tplZHPath, v, hc) 57 | } else if mod == 1 { 58 | textTplByText(tplZHText, v, hc) 59 | } 60 | } else if lang == EN { 61 | if mod == 0 { 62 | textTplByPath(tplENPath, v, hc) 63 | } else if mod == 1 { 64 | textTplByText(tplENText, v, hc) 65 | } 66 | } 67 | } 68 | 69 | func textTplByPath(path string, data any, hc *tlnet.HttpContext) { 70 | if tp, err := textTpl.ParseFiles(path); err == nil { 71 | tp.Execute(hc.Writer(), data) 72 | } else { 73 | log.Error(err) 74 | } 75 | } 76 | 77 | func textTplByText(text string, data any, hc *tlnet.HttpContext) { 78 | tl := textTpl.New("tldb") 79 | if _, err := tl.Parse(text); err == nil { 80 | tl.Execute(hc.Writer(), data) 81 | } else { 82 | log.Error(err) 83 | } 84 | } 85 | 86 | func htmlTplByPath(path string, data any, hc *tlnet.HttpContext) { 87 | if tp, err := htmlTpl.ParseFiles(path); err == nil { 88 | tp.Execute(hc.Writer(), data) 89 | } else { 90 | log.Error(err) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tc/templ.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "fmt" 12 | ) 13 | 14 | /***********************************************************************************/ 15 | func resultHtml(s ...any) (_r string) { 16 | _r = ` 17 | 18 |

` + fmt.Sprint(s...) + `

19 |

20 |

click here go back。

21 | 22 | 31 | ` 32 | return 33 | } 34 | 35 | /***********************************************************************************/ 36 | func resultHtmlAndClose(s ...any) (_r string) { 37 | _r = ` 38 | 39 |

` + fmt.Sprint(s...) + `

40 |

41 |

click here close page。

42 | 43 | 52 | ` 53 | return 54 | } 55 | -------------------------------------------------------------------------------- /tc/util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package tc 9 | 10 | import ( 11 | "github.com/donnie4w/tlnet" 12 | ) 13 | 14 | func reqjson(hc *tlnet.HttpContext) bool { 15 | return hc.Request().Header.Get("content-type") == "application/json" 16 | } 17 | 18 | func reqform(hc *tlnet.HttpContext) bool { 19 | return hc.Request().Header.Get("content-type") == "application/x-www-form-urlencoded" 20 | } 21 | -------------------------------------------------------------------------------- /tim.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package main 9 | 10 | import ( 11 | _ "github.com/donnie4w/tim/data" 12 | _ "github.com/donnie4w/tim/inet" 13 | _ "github.com/donnie4w/tim/keystore" 14 | _ "github.com/donnie4w/tim/service" 15 | . "github.com/donnie4w/tim/sys" 16 | _ "github.com/donnie4w/tim/tc" 17 | _ "github.com/donnie4w/tim/trans" 18 | ) 19 | 20 | func main() { 21 | Start() 22 | } 23 | -------------------------------------------------------------------------------- /tim_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | package main 8 | 9 | import ( 10 | "github.com/donnie4w/simplelog/logging" 11 | _ "github.com/donnie4w/tim/data" 12 | _ "github.com/donnie4w/tim/keystore" 13 | _ "github.com/donnie4w/tim/level1" 14 | _ "github.com/donnie4w/tim/service" 15 | _ "github.com/donnie4w/tim/tc" 16 | _ "github.com/donnie4w/tim/timnet" 17 | ) 18 | 19 | func Test_main() { 20 | logging.Debug("tim start") 21 | } 22 | -------------------------------------------------------------------------------- /trans/itnet.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package trans 9 | 10 | import ( 11 | "github.com/donnie4w/tim/stub" 12 | ) 13 | 14 | type csNet interface { 15 | addNoAck() int32 16 | Id() int64 17 | IsValid() bool 18 | Close() (err error) 19 | TimMessage(syncId int64, tm *stub.TimMessage) (err error) 20 | TimPresence(syncId int64, tp *stub.TimPresence) (err error) 21 | TimStream(syncId int64, vb *stub.VBean) (err error) 22 | TimCsVBean(syncId int64, vb *stub.CsVrBean) (err error) 23 | TimAck(syncId int64) (err error) 24 | TimCsDevice(syncId int64, vb *stub.CsDevice) (err error) 25 | TimCsDeviceAck(syncId int64, vb *stub.CsDevice) (err error) 26 | } 27 | 28 | const ( 29 | TIMMESSAGE byte = 1 30 | TIMPRESENCE byte = 2 31 | TIMSTREAM byte = 3 32 | TIMCSVBEAN byte = 4 33 | TIMACK byte = 5 34 | TIMCSDEVICE byte = 6 35 | TIMCSDEVICEACK byte = 7 36 | ) 37 | -------------------------------------------------------------------------------- /trans/processor.go: -------------------------------------------------------------------------------- 1 | package trans 2 | 3 | import ( 4 | "github.com/donnie4w/tim/cache" 5 | "github.com/donnie4w/tim/stub" 6 | "github.com/donnie4w/tim/sys" 7 | "github.com/donnie4w/tim/vgate" 8 | ) 9 | 10 | type processor struct { 11 | tran csNet 12 | isServ bool 13 | tw *TransWare 14 | } 15 | 16 | func (p *processor) Close() (err error) { 17 | return nil 18 | } 19 | 20 | func (p *processor) addNoAck() int32 { 21 | return 0 22 | } 23 | 24 | func (p *processor) TimMessage(syncId int64, tm *stub.TimMessage) (err error) { 25 | if len(tm.GetToList()) > 0 || tm.GetToTid() != nil { 26 | go sys.TimMessageProcessor(tm, sys.TRANS_GOAL) 27 | } 28 | if syncId != 0 { 29 | p.tran.TimAck(syncId) 30 | } 31 | return nil 32 | } 33 | 34 | func (p *processor) TimPresence(syncId int64, tp *stub.TimPresence) (err error) { 35 | if len(tp.GetToList()) > 0 || tp.GetToTid() != nil { 36 | if tp.GetOffline() && tp.FromTid != nil { 37 | cache.AccountCache.Del(tp.FromTid.GetNode()) 38 | } 39 | go sys.TimPresenceProcessor(tp, sys.TRANS_GOAL) 40 | } 41 | if syncId != 0 { 42 | p.tran.TimAck(syncId) 43 | } 44 | return nil 45 | } 46 | 47 | func (p *processor) TimStream(syncId int64, vb *stub.VBean) (err error) { 48 | go sys.TimSteamProcessor(vb, sys.TRANS_GOAL) 49 | if syncId != 0 { 50 | p.tran.TimAck(syncId) 51 | } 52 | return nil 53 | } 54 | 55 | func (p *processor) TimCsVBean(syncId int64, vb *stub.CsVrBean) (err error) { 56 | go func() { 57 | switch sys.TIMTYPE(vb.GetVbean().GetRtype()) { 58 | case sys.VROOM_SUB: 59 | if vb.GetVbean().GetRnode() != "" && vb.GetSrcuuid() != 0 && vb.GetSrcuuid() != sys.UUID { 60 | vgate.VGate.Sub(vb.GetVbean().GetVnode(), vb.GetSrcuuid(), 0) 61 | } 62 | case sys.VROOM_UNSUB: 63 | if vb.GetSrcuuid() != 0 && vb.GetSrcuuid() != sys.UUID { 64 | vgate.VGate.UnSubWithUUID(vb.GetVbean().GetVnode(), vb.GetSrcuuid()) 65 | } 66 | case sys.VROOM_MESSAGE: 67 | sys.TimSteamProcessor(vb.GetVbean(), sys.TRANS_GOAL) 68 | } 69 | }() 70 | if syncId != 0 { 71 | p.tran.TimAck(syncId) 72 | } 73 | return nil 74 | } 75 | 76 | func (p *processor) TimAck(syncId int64) (err error) { 77 | p.tw.dataWait.Close(syncId) 78 | return nil 79 | } 80 | 81 | func (p *processor) TimCsDevice(syncId int64, cd *stub.CsDevice) (err error) { 82 | bs := sys.DeviceTypeList(cd.GetNode()) 83 | cd.TypeList = bs 84 | p.tran.TimCsDeviceAck(syncId, cd) 85 | return 86 | } 87 | 88 | func (p *processor) TimCsDeviceAck(syncId int64, cd *stub.CsDevice) (err error) { 89 | p.tw.dataWait.CloseAndPut(syncId, cd) 90 | return 91 | } 92 | 93 | func (p *processor) Id() int64 { 94 | return p.tran.Id() 95 | } 96 | 97 | func (p *processor) IsValid() bool { 98 | return p.tran.IsValid() 99 | } 100 | 101 | func newProcessor(tw *TransWare, c csNet, serv bool) csNet { 102 | return &processor{tw: tw, tran: c, isServ: serv} 103 | } 104 | -------------------------------------------------------------------------------- /trans/route.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 donnie4w . All rights reserved. 3 | * Original source: https://github.com/donnie4w/raftx 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package trans 19 | 20 | import ( 21 | "fmt" 22 | "github.com/donnie4w/gofer/util" 23 | "github.com/donnie4w/tim/stub" 24 | ) 25 | 26 | func router(bs []byte, cn csNet) (err error) { 27 | defer util.Recover(&err) 28 | switch bs[0] { 29 | case TIMMESSAGE: 30 | if len(bs) <= 9 { 31 | return cn.TimMessage(util.BytesToInt64(bs[1:9]), nil) 32 | } 33 | if p, err := util.TDecode[*stub.TimMessage](bs[9:], stub.NewTimMessage()); err == nil { 34 | return cn.TimMessage(util.BytesToInt64(bs[1:9]), p) 35 | } 36 | case TIMPRESENCE: 37 | if len(bs) <= 9 { 38 | return cn.TimPresence(util.BytesToInt64(bs[1:9]), nil) 39 | } 40 | if p, err := util.TDecode[*stub.TimPresence](bs[9:], stub.NewTimPresence()); err == nil { 41 | return cn.TimPresence(util.BytesToInt64(bs[1:9]), p) 42 | } 43 | case TIMSTREAM: 44 | if len(bs) <= 9 { 45 | return cn.TimStream(util.BytesToInt64(bs[1:9]), nil) 46 | } 47 | if p, err := util.TDecode[*stub.VBean](bs[9:], stub.NewVBean()); err == nil { 48 | return cn.TimStream(util.BytesToInt64(bs[1:9]), p) 49 | } 50 | case TIMCSVBEAN: 51 | if len(bs) <= 9 { 52 | return cn.TimCsVBean(util.BytesToInt64(bs[1:9]), nil) 53 | } 54 | if p, err := util.TDecode[*stub.CsVrBean](bs[9:], stub.NewCsVrBean()); err == nil { 55 | return cn.TimCsVBean(util.BytesToInt64(bs[1:9]), p) 56 | } 57 | case TIMACK: 58 | if len(bs) <= 9 { 59 | return cn.TimAck(util.BytesToInt64(bs[1:9])) 60 | } 61 | case TIMCSDEVICE: 62 | if len(bs) <= 9 { 63 | return cn.TimCsDevice(util.BytesToInt64(bs[1:9]), nil) 64 | } 65 | if p, err := util.TDecode[*stub.CsDevice](bs[9:], stub.NewCsDevice()); err == nil { 66 | return cn.TimCsDevice(util.BytesToInt64(bs[1:9]), p) 67 | } 68 | case TIMCSDEVICEACK: 69 | if len(bs) <= 9 { 70 | return cn.TimCsDeviceAck(util.BytesToInt64(bs[1:9]), nil) 71 | } 72 | if p, err := util.TDecode[*stub.CsDevice](bs[9:], stub.NewCsDevice()); err == nil { 73 | return cn.TimCsDeviceAck(util.BytesToInt64(bs[1:9]), p) 74 | } 75 | default: 76 | err = fmt.Errorf("unknow command") 77 | } 78 | return 79 | } 80 | -------------------------------------------------------------------------------- /trans/trans.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package trans 9 | 10 | import ( 11 | "github.com/donnie4w/gofer/buffer" 12 | "github.com/donnie4w/gofer/util" 13 | "github.com/donnie4w/gothrift/thrift" 14 | "github.com/donnie4w/tim/errs" 15 | "github.com/donnie4w/tim/stub" 16 | "github.com/donnie4w/tsf" 17 | "sync" 18 | "sync/atomic" 19 | ) 20 | 21 | type trans struct { 22 | ts tsf.TsfSocket 23 | mux sync.RWMutex 24 | noAck atomic.Int32 25 | isValid bool 26 | } 27 | 28 | func newTrans(ts tsf.TsfSocket) csNet { 29 | return &trans{ts: ts, isValid: true} 30 | } 31 | 32 | func (t *trans) Id() int64 { 33 | return t.ts.ID() 34 | } 35 | 36 | func (t *trans) addNoAck() (r int32) { 37 | if r = t.noAck.Add(1); r > 3 { 38 | t.Close() 39 | } 40 | return 41 | } 42 | 43 | func (t *trans) IsValid() bool { return t.isValid } 44 | 45 | func (t *trans) Close() (err error) { 46 | defer util.Recover(&err) 47 | if t != nil { 48 | t.mux.Lock() 49 | defer t.mux.Unlock() 50 | if t.isValid { 51 | t.isValid = false 52 | return t.ts.Close() 53 | } 54 | } 55 | return nil 56 | } 57 | 58 | func (t *trans) write(bs []byte) (err error) { 59 | if !t.isValid { 60 | return errs.ERR_CONNECT.Error() 61 | } 62 | t.mux.RLock() 63 | defer t.mux.RUnlock() 64 | if _, err = t.ts.WriteWithMerge(bs); err != nil { 65 | t.Close() 66 | } 67 | return 68 | } 69 | 70 | func (t *trans) writeMessage(tp byte, syncId int64, ts thrift.TStruct) (err error) { 71 | var bs []byte 72 | if ts != nil { 73 | bs = util.TEncode(ts) 74 | } 75 | buf := buffer.NewBufferWithCapacity(9 + len(bs)) 76 | buf.WriteByte(tp) 77 | buf.Write(util.Int64ToBytes(syncId)) 78 | if len(bs) > 0 { 79 | buf.Write(bs) 80 | } 81 | return t.write(buf.Bytes()) 82 | } 83 | 84 | func (t *trans) writeBytes(tp byte, syncId int64, body []byte) (err error) { 85 | if syncId != 0 { 86 | buf := buffer.NewBufferWithCapacity(9 + len(body)) 87 | buf.WriteByte(tp) 88 | buf.Write(util.Int64ToBytes(syncId)) 89 | buf.Write(body) 90 | return t.write(buf.Bytes()) 91 | } else { 92 | buf := buffer.NewBufferWithCapacity(1 + len(body)) 93 | buf.WriteByte(tp) 94 | buf.Write(body) 95 | return t.write(buf.Bytes()) 96 | } 97 | } 98 | 99 | func (t *trans) TimMessage(syncId int64, tm *stub.TimMessage) (err error) { 100 | return t.writeMessage(TIMMESSAGE, syncId, tm) 101 | } 102 | 103 | func (t *trans) TimPresence(syncId int64, tp *stub.TimPresence) (err error) { 104 | return t.writeMessage(TIMPRESENCE, syncId, tp) 105 | } 106 | 107 | func (t *trans) TimStream(syncId int64, vb *stub.VBean) (err error) { 108 | return t.writeMessage(TIMSTREAM, syncId, vb) 109 | } 110 | 111 | func (t *trans) TimCsVBean(syncId int64, vb *stub.CsVrBean) (err error) { 112 | return t.writeMessage(TIMCSVBEAN, syncId, vb) 113 | } 114 | 115 | func (t *trans) TimAck(syncId int64) (err error) { 116 | if syncId != 0 { 117 | t.writeMessage(TIMACK, syncId, nil) 118 | } 119 | return nil 120 | } 121 | 122 | func (t *trans) TimCsDevice(syncId int64, cd *stub.CsDevice) (err error) { 123 | return t.writeMessage(TIMCSDEVICE, syncId, cd) 124 | } 125 | 126 | func (t *trans) TimCsDeviceAck(syncId int64, cd *stub.CsDevice) (err error) { 127 | return t.writeMessage(TIMCSDEVICEACK, syncId, cd) 128 | } 129 | -------------------------------------------------------------------------------- /trans/tservice.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package trans 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/donnie4w/tim/log" 14 | "github.com/donnie4w/tim/sys" 15 | "github.com/donnie4w/tim/util" 16 | "github.com/donnie4w/tsf" 17 | "os" 18 | "time" 19 | ) 20 | 21 | type tServer struct { 22 | isClose bool 23 | server *tsf.Tsf 24 | tw *TransWare 25 | } 26 | 27 | func newTServer(transWare *TransWare) *tServer { 28 | return &tServer{tw: transWare} 29 | } 30 | 31 | func (t *tServer) serve(listenAddr string) (err error) { 32 | if listenAddr, err = util.ParseAddr(listenAddr); err != nil { 33 | log.FmtPrint("Cluster tim Service ParseAddr error:", err.Error()) 34 | os.Exit(1) 35 | } 36 | defer util.Recover2(&err) 37 | cfg := &tsf.TsfConfig{ListenAddr: listenAddr, TConfiguration: &tsf.TConfiguration{ProcessMerge: true}} 38 | tc := &tsf.TContext{} 39 | tc.OnClose = func(ts tsf.TsfSocket) error { 40 | t.tw.romove(ts.ID()) 41 | return nil 42 | } 43 | tc.OnOpenSync = func(socket tsf.TsfSocket) error { 44 | cn := newTrans(socket) 45 | socket.SetContext(context.WithValue(context.Background(), true, newProcessor(t.tw, cn, true))) 46 | t.tw.Add(socket.ID(), cn) 47 | return nil 48 | } 49 | tc.Handler = func(socket tsf.TsfSocket, packet *tsf.Packet) error { 50 | return router(packet.ToBytes(), socket.GetContext().Value(true).(csNet)) 51 | } 52 | if t.server, err = tsf.NewTsf(cfg, tc); err == nil { 53 | if err = t.server.Listen(); err == nil { 54 | log.FmtPrint("Cluster tim service start [", listenAddr, "] ") 55 | err = t.server.AcceptLoop() 56 | } 57 | } 58 | if !t.isClose && err != nil { 59 | log.Error("Cluster tim service failed:", err) 60 | os.Exit(0) 61 | } 62 | return 63 | } 64 | 65 | func (t *tServer) close() error { 66 | t.isClose = true 67 | return t.server.Close() 68 | } 69 | 70 | type connect struct { 71 | csNet 72 | tw *TransWare 73 | } 74 | 75 | func newConnect(tw *TransWare) *connect { 76 | return &connect{tw: tw} 77 | } 78 | 79 | func (c *connect) open(addr string) (err error) { 80 | defer util.Recover2(&err) 81 | tx := &tsf.TContext{} 82 | wait := make(chan struct{}) 83 | tx.OnOpenSync = func(socket tsf.TsfSocket) error { 84 | log.Debug("connect open:", sys.Conf.CsListen, "->", addr) 85 | defer close(wait) 86 | c.csNet = newTrans(socket) 87 | socket.SetContext(context.WithValue(context.Background(), true, newProcessor(c.tw, c.csNet, false))) 88 | c.tw.Add(socket.ID(), c.csNet) 89 | return nil 90 | } 91 | tx.OnClose = func(ts tsf.TsfSocket) error { 92 | log.Info("OnClose:", ts.ID()) 93 | defer util.Recover() 94 | defer c.Close() 95 | c.tw.romove(ts.ID()) 96 | return nil 97 | } 98 | tx.Handler = func(socket tsf.TsfSocket, packet *tsf.Packet) error { 99 | return router(packet.ToBytes(), socket.GetContext().Value(true).(csNet)) 100 | } 101 | conn := tsf.NewTsfSocketConf(addr, &tsf.TConfiguration{ProcessMerge: true, ConnectTimeout: sys.ConnectTimeout}) 102 | if err = conn.Open(); err == nil { 103 | go conn.On(tx) 104 | } else { 105 | return 106 | } 107 | to := time.After(time.Second) 108 | select { 109 | case <-wait: 110 | case <-to: 111 | conn.Close() 112 | log.Errorf("connect timeout: %s -> %s ", sys.Conf.CsListen, addr) 113 | err = fmt.Errorf(fmt.Sprint("connect timeout: %s -> %s ", sys.Conf.CsListen, addr)) 114 | } 115 | return 116 | } 117 | -------------------------------------------------------------------------------- /util/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, donnie 2 | // All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | // 6 | // github.com/donnie4w/tim 7 | 8 | package util 9 | 10 | import ( 11 | "testing" 12 | ) 13 | 14 | func TestMarkId(t *testing.T) { 15 | var i int64 = 1 << 50 16 | id := MaskId(i) 17 | id2 := MaskId(id) 18 | t.Log(i) 19 | t.Log(id) 20 | t.Log(id2) 21 | } 22 | 23 | func TestMark(t *testing.T) { 24 | bs := []byte("hello world") 25 | bs1 := Mask(bs) 26 | bs2 := Mask(bs1) 27 | t.Log(string(bs1)) 28 | t.Log(string(bs2)) 29 | } 30 | 31 | func BenchmarkNodeName(b *testing.B) { 32 | domain := "tt" 33 | u := CreateUUID("aiaeinf22ienfefne1f", &domain) 34 | b.Log(u) 35 | b.Log(CheckUUID(2790553438565061983)) 36 | } 37 | 38 | func BenchmarkUUIDByNode(b *testing.B) { 39 | for i := 0; i < b.N; i++ { 40 | domain := "tt" 41 | CreateUUID("aiaeinfienfefne1f", &domain) 42 | } 43 | } 44 | 45 | func BenchmarkSearchString(b *testing.B) { 46 | b.Log(ContainStrings([]string{"ab", "b", "c"}, "ab")) 47 | } 48 | 49 | func BenchmarkSearchInt(b *testing.B) { 50 | b.Log(ContainInt([]int{11, 22, 33, 44}, 33)) 51 | } 52 | --------------------------------------------------------------------------------