// 一个发起Post请求的按钮 // url: 将把url转化为表单并使用Post方法提交 // title: 按钮上面的字 // 在当前页面打开连接 //不支持一个 key 里塞多个 value 的 url func NewPostButton(urlStr string, title string) kmgView.HtmlRenderer { formAction, err := url.Parse(urlStr) kmgErr.PanicIfError(err) query, err := url.ParseQuery(formAction.RawQuery) kmgErr.PanicIfError(err) formAction.RawQuery = "" id := kmgRand.MustCryptoRandToReadableAlphaNum(10) form := Form{ Id: id, NoSubmit: true, Url: formAction.String(), InputList: []kmgView.HtmlRenderer{}, IsHidden: true, } for k, v := range query { form.InputList = append(form.InputList, InputHidden{ Name: k, Value: v[0], }) } button := Button{ FormId: id, Type: ButtonTypeButton, Content: kmgView.String(title), Size: ButtonSizeExtraSmall, Color: ButtonColorInfo, } return kmgView.Html(form.HtmlRender() + button.HtmlRender()) }
//Client Side func GetIPFromRemote(remoteServerUrl string) (ip string) { resp, err := http.Get(remoteServerUrl) kmgErr.PanicIfError(err) body, err := ioutil.ReadAll(resp.Body) kmgErr.PanicIfError(err) ip = string(body) if !strings.HasPrefix(ip, "OK") { panic("WhoAmI Error: can not get a Ipv4 address " + ip) } return strings.TrimPrefix(ip, "OK") }
//TODO 对于不会发 RPC 的进程,应该可以用一个 flag 来表明不需要等待 RPC 响应 func waitRpcRespond() chan error { returnChan := make(chan error) lock := &kmgProcessMutex.FileMutex{Name: "kmg_service_lock"} lock.Lock() rpcCloser := ListenAndServe_ServiceRpc(rpcAddress, &ServiceRpc{}, rpcPsk) __closer := func() { err := rpcCloser() time.Sleep(time.Second) lock.UnLock() kmgErr.PanicIfError(err) } go func() { select { case startStatus := <-statusChannel: __closer() if startStatus == StartStatusSuccess { returnChan <- nil } else { returnChan <- errors.New("StartFail") } case <-time.After(time.Minute * 2): __closer() returnChan <- errors.New("Rpc timeout") } }() return returnChan }
// flock 加的锁,有两种方式解除锁: // 1.加锁的进程退出了,锁自动释放 // 2.在进程内,使用 fd0 挂上的锁,显式的使用 fd0 解锁; // 注意:同一个进程内,fd0 和 fd1 指向同一个文件(fd1 不是 fd0 的副本),若是 fd0 挂上的锁,必须用 fd0 来解锁,fd1 无法解锁 func (fm *FileMutex) UnLock() { kmgErr.PanicIfError(syscall.Flock(fm.getFd(), int(syscall.LOCK_UN))) }
// flock 加锁,会将锁(系统级别)挂在某个文件上,只要有进程给某个文件挂上了锁,则其他进程(包括本进程)就必须解锁 func (fm *FileMutex) Lock() { kmgErr.PanicIfError(syscall.Flock(int(fm.getFd()), int(syscall.LOCK_EX))) }
func runFileHttpServer() { listenAddr := "" path := "" key := "" flag.StringVar(&listenAddr, "l", ":80", "listen address") flag.StringVar(&path, "path", "", "root path of the file server") flag.StringVar(&key, "key", "", "crypto key use to encrypt all request of this server") flag.Parse() var err error if path == "" { path, err = os.Getwd() if err != nil { fmt.Printf("os.Getwd() fail %s", err) return } } else { kmgErr.PanicIfError(os.Chdir(path)) } if key == "" { http.Handle("/", http.FileServer(http.Dir(path))) } if key != "" { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { realPath := filepath.Join(path, r.URL.Path) if !kmgFile.MustFileExist(realPath) { w.Write([]byte("File Not Exist")) return } if !kmgStrings.IsInSlice(cacheFilePathSlice, realPath) { cacheFilePathSlice = append(cacheFilePathSlice, realPath) } updateCache := func() { cacheFilePathEncryptMap[realPath] = kmgCrypto.CompressAndEncryptBytesEncodeV2( kmgCrypto.Get32PskFromString(key), kmgFile.MustReadFile(realPath), ) } checkCache := func() { lock.Lock() defer lock.Unlock() kmgCache.MustMd5FileChangeCache(realPath, []string{realPath}, func() { updateCache() }) } checkCache() //进程重启后,内存中的缓存掉了,但是文件系统的缓存还在 _, exist := cacheFilePathEncryptMap[realPath] if !exist { updateCache() } w.Write(cacheFilePathEncryptMap[realPath]) }) } fmt.Println("start server at", listenAddr) err = http.ListenAndServe(listenAddr, nil) if err != nil { fmt.Printf("http.ListenAndServe() fail %s", err) return } return }
func GetCurrentUserHomeDir() string { u, err := user.Current() kmgErr.PanicIfError(err) return u.HomeDir }