github.com/wangyougui/gf/v2@v2.6.5/os/gproc/gproc_comm.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gproc 8 9 import ( 10 "context" 11 "fmt" 12 "sync" 13 14 "github.com/wangyougui/gf/v2/container/gmap" 15 "github.com/wangyougui/gf/v2/errors/gerror" 16 "github.com/wangyougui/gf/v2/internal/intlog" 17 "github.com/wangyougui/gf/v2/net/gtcp" 18 "github.com/wangyougui/gf/v2/os/gfile" 19 "github.com/wangyougui/gf/v2/util/gconv" 20 ) 21 22 // MsgRequest is the request structure for process communication. 23 type MsgRequest struct { 24 SenderPid int // Sender PID. 25 ReceiverPid int // Receiver PID. 26 Group string // Message group name. 27 Data []byte // Request data. 28 } 29 30 // MsgResponse is the response structure for process communication. 31 type MsgResponse struct { 32 Code int // 1: OK; Other: Error. 33 Message string // Response message. 34 Data []byte // Response data. 35 } 36 37 const ( 38 defaultFolderNameForProcComm = "gf_pid_port_mapping" // Default folder name for storing pid to port mapping files. 39 defaultGroupNameForProcComm = "" // Default group name. 40 defaultTcpPortForProcComm = 10000 // Starting port number for receiver listening. 41 maxLengthForProcMsgQueue = 10000 // Max size for each message queue of the group. 42 ) 43 44 var ( 45 // commReceiveQueues is the group name to queue map for storing received data. 46 // The value of the map is type of *gqueue.Queue. 47 commReceiveQueues = gmap.NewStrAnyMap(true) 48 49 // commPidFolderPath specifies the folder path storing pid to port mapping files. 50 commPidFolderPath string 51 52 // commPidFolderPathOnce is used for lazy calculation for `commPidFolderPath` is necessary. 53 commPidFolderPathOnce sync.Once 54 ) 55 56 // getConnByPid creates and returns a TCP connection for specified pid. 57 func getConnByPid(pid int) (*gtcp.PoolConn, error) { 58 port := getPortByPid(pid) 59 if port > 0 { 60 if conn, err := gtcp.NewPoolConn(fmt.Sprintf("127.0.0.1:%d", port)); err == nil { 61 return conn, nil 62 } else { 63 return nil, err 64 } 65 } 66 return nil, gerror.Newf(`could not find port for pid "%d"`, pid) 67 } 68 69 // getPortByPid returns the listening port for specified pid. 70 // It returns 0 if no port found for the specified pid. 71 func getPortByPid(pid int) int { 72 path := getCommFilePath(pid) 73 if path == "" { 74 return 0 75 } 76 return gconv.Int(gfile.GetContentsWithCache(path)) 77 } 78 79 // getCommFilePath returns the pid to port mapping file path for given pid. 80 func getCommFilePath(pid int) string { 81 path, err := getCommPidFolderPath() 82 if err != nil { 83 intlog.Errorf(context.TODO(), `%+v`, err) 84 return "" 85 } 86 return gfile.Join(path, gconv.String(pid)) 87 } 88 89 // getCommPidFolderPath retrieves and returns the available directory for storing pid mapping files. 90 func getCommPidFolderPath() (folderPath string, err error) { 91 commPidFolderPathOnce.Do(func() { 92 availablePaths := []string{ 93 "/var/tmp", 94 "/var/run", 95 } 96 if path, _ := gfile.Home(".config"); path != "" { 97 availablePaths = append(availablePaths, path) 98 } 99 availablePaths = append(availablePaths, gfile.Temp()) 100 for _, availablePath := range availablePaths { 101 checkPath := gfile.Join(availablePath, defaultFolderNameForProcComm) 102 if !gfile.Exists(checkPath) && gfile.Mkdir(checkPath) != nil { 103 continue 104 } 105 if gfile.IsWritable(checkPath) { 106 commPidFolderPath = checkPath 107 break 108 } 109 } 110 if commPidFolderPath == "" { 111 err = gerror.Newf( 112 `cannot find available folder for storing pid to port mapping files in paths: %+v`, 113 availablePaths, 114 ) 115 } 116 }) 117 folderPath = commPidFolderPath 118 return 119 }