github.com/gogf/gf/v2@v2.7.4/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/gogf/gf.
     6  
     7  package gproc
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"sync"
    13  
    14  	"github.com/gogf/gf/v2/container/gmap"
    15  	"github.com/gogf/gf/v2/errors/gerror"
    16  	"github.com/gogf/gf/v2/internal/intlog"
    17  	"github.com/gogf/gf/v2/net/gtcp"
    18  	"github.com/gogf/gf/v2/os/gfile"
    19  	"github.com/gogf/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  }