Browse Source

add search guests/modify auto start

dev
bokuore 7 months ago
parent
commit
2509fd73c3
  1. 7
      CHANGELOG.md
  2. 16
      core_transaction_manager.go
  3. 5
      src/modules/api_module.go
  4. 9
      src/modules/instance.go
  5. 15
      src/modules/module_interface.go
  6. 204
      src/modules/resource_manager.go
  7. 99
      src/task/modify_guest_auto_start.go
  8. 2
      src/task/query_guest.go
  9. 61
      src/task/search_guests.go

7
CHANGELOG.md

@ -1,5 +1,12 @@
# Change Log
## [1.3.1] - 2021-02-19
### Added
- Search guests by keyword
- Modify auto start option of guest
## [1.3.0] - 2020-11-08
### Added

16
core_transaction_manager.go

@ -615,5 +615,21 @@ func CreateTransactionManager(sender framework.MessageSender, resourceModule mod
err = fmt.Errorf("register sync disk images fail: %s", err.Error())
return
}
if err = manager.RegisterExecutor(framework.SearchGuestRequest,
&task.SearchGuestsExecutor{
Sender: sender,
ResourceModule: resourceModule,
}); err != nil{
err = fmt.Errorf("register search guests fail: %s", err.Error())
return
}
if err = manager.RegisterExecutor(framework.ModifyAutoStartRequest,
&task.ModifyGuestAutoStartExecutor{
Sender: sender,
ResourceModule: resourceModule,
}); err != nil{
err = fmt.Errorf("register modify auto start fail: %s", err.Error())
return
}
return manager, nil
}

5
src/modules/api_module.go

@ -5803,6 +5803,11 @@ func (module *APIModule) searchGuests(w http.ResponseWriter, r *http.Request, pa
request.Limit = DefaultLimit
}
if "" != request.Keyword && strings.Contains(request.Keyword, " "){
ResponseFail(ResponseDefaultError, "only allow one keyword", w)
return
}
msg, _ := framework.CreateJsonMessage(framework.SearchGuestRequest)
msg.SetInt(framework.ParamKeyLimit, request.Limit)
msg.SetInt(framework.ParamKeyStart, request.Offset)

9
src/modules/instance.go

@ -1,8 +1,8 @@
package modules
import (
"github.com/project-nano/framework"
"fmt"
"github.com/project-nano/framework"
)
type InstanceResource struct {
@ -33,6 +33,7 @@ type InstanceStatus struct {
ID string
Pool string
Cell string
Host string //hosting cell ip
User string
Group string
AutoStart bool
@ -92,13 +93,15 @@ const (
func MarshalInstanceStatusListToMessage(list []InstanceStatus, msg framework.Message) error {
var count = uint(len(list))
msg.SetUInt(framework.ParamKeyCount, count)
var names, ids, pools, cells, users, monitors, addresses, groups, secrets, systems, createTime, internal, external, hardware []string
var names, ids, pools, cells, hosts, users, monitors, addresses, groups, secrets, systems,
createTime, internal, external, hardware []string
var cores, options, enables, progress, status, memories, disks, diskCounts, mediaAttached, cpuPriorities, ioLimits []uint64
for _, ins := range list {
names = append(names, ins.Name)
ids = append(ids, ins.ID)
pools = append(pools, ins.Pool)
cells = append(cells, ins.Cell)
hosts = append(hosts, ins.Host)
users = append(users, ins.User)
groups = append(groups, ins.Group)
cores = append(cores, uint64(ins.Cores))
@ -160,6 +163,7 @@ func MarshalInstanceStatusListToMessage(list []InstanceStatus, msg framework.Mes
msg.SetStringArray(framework.ParamKeyInstance, ids)
msg.SetStringArray(framework.ParamKeyPool, pools)
msg.SetStringArray(framework.ParamKeyCell, cells)
msg.SetStringArray(framework.ParamKeyHost, hosts)
msg.SetStringArray(framework.ParamKeyUser, users)
msg.SetStringArray(framework.ParamKeyMonitor, monitors)
@ -196,6 +200,7 @@ func (config *InstanceStatus) Marshal(msg framework.Message) error {
msg.SetString(framework.ParamKeyGroup, config.Group)
msg.SetString(framework.ParamKeyPool, config.Pool)
msg.SetString(framework.ParamKeyCell, config.Cell)
msg.SetString(framework.ParamKeyHost, config.Host)
if config.ID != "" {
msg.SetString(framework.ParamKeyInstance, config.ID)
}

15
src/modules/module_interface.go

@ -144,6 +144,17 @@ type ResourceResult struct {
PolicyGroup SecurityPolicyGroupStatus
PolicyGroupList []SecurityPolicyGroupStatus
PolicyRuleList []SecurityPolicyRule
Total int
Offset int
Limit int
}
type SearchGuestsCondition struct {
Limit int
Offset int
Pool string
Cell string
Keyword string
}
type DiskImageConfig struct {
@ -373,8 +384,9 @@ type ResourceModule interface {
FinishPurgeCell(cellName string, respChan chan error)
//instances
SearchGuestConfig(condition GuestQueryCondition, respChan chan ResourceResult)
QueryGuestsByCondition(condition GuestQueryCondition, respChan chan ResourceResult)
BatchUpdateInstanceStatus(pool, cell string, instances []InstanceStatus, respChan chan error)
SearchGuests(condition SearchGuestsCondition, respChan chan ResourceResult)
AllocateInstance(pool string, status InstanceStatus, respChan chan ResourceResult)
//running/create/progress/media only
@ -392,6 +404,7 @@ type ResourceModule interface {
UpdateInstanceDiskThreshold(id string, readSpeed, readIOPS, writeSpeed, writeIOPS uint64, respChan chan error)
UpdateInstanceNetworkThreshold(id string, receive, send uint64, respChan chan error)
UpdateInstanceMonitorSecret(id, secret string, respChan chan error)
UpdateGuestAutoStart(guestID string, enabled bool, respChan chan error)
//image server
AddImageServer(name, host string, port int)

204
src/modules/resource_manager.go

@ -17,6 +17,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strings"
"time"
)
@ -216,6 +217,7 @@ type resourceCommand struct {
PolicyRule SecurityPolicyRule
Index int
Flag bool
SearchCondition SearchGuestsCondition
ErrorChan chan error
ResultChan chan ResourceResult
}
@ -275,7 +277,7 @@ const (
cmdUpdateInstanceMonitorSecret
cmdRenameInstance
cmdGetInstanceByName
cmdSearchGuests
cmdQueryGuestsByCondition
cmdAddImageServer
cmdRemoveImageServer
cmdGetImageServer
@ -331,6 +333,8 @@ const (
cmdModifySecurityPolicyRule
cmdRemoveSecurityPolicyRule
cmdMoveSecurityPolicyRule
cmdSearchGuests
cmdUpdateAutoStart
cmdInvalid
)
@ -370,7 +374,7 @@ var commandNames = []string{
"UpdateInstanceMonitorSecret",
"RenameInstance",
"GetInstanceByName",
"SearchGuests",
"QueryGuestsByCondition",
"AddImageServer",
"RemoveImageServer",
"GetImageServer",
@ -426,6 +430,8 @@ var commandNames = []string{
"ModifySecurityPolicyRule",
"RemoveSecurityPolicyRule",
"MoveSecurityPolicyRule",
"SearchGuests",
"UpdateAutoStart",
}
func (c commandType) toString() string {
@ -604,11 +610,15 @@ func (manager *ResourceManager) SetCellDead(cellName string, respChan chan error
manager.commands <- resourceCommand{Type: cmdSetCellDead, Cell:cellName, ErrorChan:respChan}
}
func (manager *ResourceManager) SearchGuestConfig(condition GuestQueryCondition, respChan chan ResourceResult) {
cmd := resourceCommand{Type: cmdSearchGuests, InstanceQuery: condition, ResultChan: respChan}
func (manager *ResourceManager) QueryGuestsByCondition(condition GuestQueryCondition, respChan chan ResourceResult) {
cmd := resourceCommand{Type: cmdQueryGuestsByCondition, InstanceQuery: condition, ResultChan: respChan}
manager.commands <- cmd
}
func (manager *ResourceManager) SearchGuests(condition SearchGuestsCondition, respChan chan ResourceResult){
manager.commands <- resourceCommand{Type: cmdSearchGuests, SearchCondition: condition, ResultChan: respChan}
}
func (manager *ResourceManager) BatchUpdateInstanceStatus(pool, cell string, instances []InstanceStatus, respChan chan error) {
cmd := resourceCommand{Type: cmdBatchUpdateInstanceStatus, Pool: pool, Cell: cell, InstanceList: instances, ErrorChan: respChan}
manager.commands <- cmd
@ -666,6 +676,10 @@ func (manager *ResourceManager) UpdateInstanceNetworkThreshold(id string, receiv
manager.commands <- resourceCommand{Type: cmdUpdateInstanceNetworkThreshold, InstanceID: id, ReceiveSpeed:receive, SendSpeed: send, ErrorChan: respChan}
}
func (manager *ResourceManager) UpdateGuestAutoStart(guestID string, enabled bool, respChan chan error){
manager.commands <- resourceCommand{Type: cmdUpdateAutoStart, InstanceID: guestID, Flag: enabled, ErrorChan: respChan}
}
func (manager *ResourceManager) RenameInstance(id, name string, respChan chan error){
manager.commands <- resourceCommand{Type:cmdRenameInstance, InstanceID:id, Name:name, ErrorChan:respChan}
}
@ -1114,6 +1128,10 @@ func (manager *ResourceManager) handleCommand(cmd resourceCommand) {
err = manager.handleUpdateCellInfo(cmd.Cell, cmd.Address, cmd.ErrorChan)
case cmdGetCellStatus:
err = manager.handleGetCellStatus(cmd.Cell, cmd.ResultChan)
case cmdSearchGuests:
err = manager.handleSearchGuests(cmd.SearchCondition, cmd.ResultChan)
case cmdUpdateAutoStart:
err = manager.handleUpdateGuestAutoStart(cmd.InstanceID, cmd.Flag, cmd.ErrorChan)
case cmdBatchUpdateInstanceStatus:
err = manager.handleBatchUpdateInstanceStatus(cmd.Pool, cmd.Cell, cmd.InstanceList, cmd.ErrorChan)
case cmdAllocateInstance:
@ -1144,8 +1162,8 @@ func (manager *ResourceManager) handleCommand(cmd resourceCommand) {
err = manager.handleUpdateInstanceDiskThreshold(cmd.InstanceID, cmd.ReadSpeed, cmd.ReadIOPS, cmd.WriteSpeed, cmd.WriteIOPS, cmd.ErrorChan)
case cmdGetInstanceByName:
err = manager.handleGetInstanceByName(cmd.Pool, cmd.Name, cmd.ResultChan)
case cmdSearchGuests:
err = manager.handleSearchGuestConfig(cmd.InstanceQuery, cmd.ResultChan)
case cmdQueryGuestsByCondition:
err = manager.handleQueryGuestsByCondition(cmd.InstanceQuery, cmd.ResultChan)
case cmdAddImageServer:
err = manager.handleAddImageServer(cmd.Name, cmd.Host, cmd.Port)
case cmdGetImageServer:
@ -2019,7 +2037,7 @@ func (manager *ResourceManager) handleSetCellStopped(cellName string, respChan c
respChan <- nil
return nil
}
func (manager *ResourceManager) handleSearchGuestConfig(condition GuestQueryCondition, respChan chan ResourceResult) (err error) {
func (manager *ResourceManager) handleQueryGuestsByCondition(condition GuestQueryCondition, respChan chan ResourceResult) (err error) {
var idList []string
{
@ -2137,6 +2155,7 @@ func (manager *ResourceManager) handleBatchUpdateInstanceStatus(poolName, cellNa
cell.InstanceStatistic.Reset()
for _, config := range instances {
config.InternalNetwork.MonitorAddress = cell.Address
config.Host = cell.Address
manager.instances[config.ID] = config
cell.Instances[config.ID] = true
//todo: migrating
@ -2199,6 +2218,7 @@ func (manager *ResourceManager) handleAllocateInstance(poolName string, config I
config.InternalNetwork.AssignedAddress = internal
}
config.InternalNetwork.MonitorAddress = cell.Address
config.Host = cell.Address
cell.Pending[config.ID] = true
pool.InstanceNames[config.Name] = config.ID
@ -2300,6 +2320,7 @@ func (manager *ResourceManager) handleConfirmInstance(id string, monitorPort uin
respChan <- nil
return nil
}
func (manager *ResourceManager) handleDeallocateInstance(id string, err error, respChan chan error) error {
ins, exists := manager.instances[id]
if !exists {
@ -2438,6 +2459,169 @@ func (manager *ResourceManager) handleQueryInstanceStatusInCell(poolName, cellNa
return nil
}
func (manager *ResourceManager) handleSearchGuests(condition SearchGuestsCondition, respChan chan ResourceResult) (err error){
var poolSpecified = "" == condition.Pool
var cellSpecifed = "" == condition.Cell
var keywordSpecified = "" == condition.Keyword
var targets []string
if cellSpecifed{
cell, exists := manager.cells[condition.Cell]
if !exists{
err = fmt.Errorf("invalid cell '%s'", condition.Cell)
respChan <- ResourceResult{Error: err}
return
}
for instanceID, _ := range cell.Instances{
targets = append(targets, instanceID)
}
} else if poolSpecified{
pool, exists := manager.pools[condition.Pool]
if !exists{
err = fmt.Errorf("invalid pool '%s'", condition.Pool)
respChan <- ResourceResult{Error: err}
return
}
for _, intancesID := range pool.InstanceNames{
targets = append(targets, intancesID)
}
}
var idMap = map[string]string{}//name to id
if keywordSpecified{
//filter
var filtered []string
var matched bool
var guestName string
if 0 != len(targets){
for _, instanceID := range targets{
if matched, guestName, err = manager.matchKeyword(instanceID, condition.Keyword); err != nil{
respChan <- ResourceResult{Error: err}
return
}else if matched{
idMap[guestName] = instanceID
filtered = append(filtered, instanceID)
}
}
}else{
for instanceID, _ := range manager.instances{
if matched, guestName, err = manager.matchKeyword(instanceID, condition.Keyword); err != nil{
respChan <- ResourceResult{Error: err}
return
}else if matched{
idMap[guestName] = instanceID
filtered = append(filtered, instanceID)
}
}
}
targets = filtered
}else if 0 == len(targets){
//fill all instances
for instanceID, instance := range manager.instances{
targets = append(targets, instanceID)
idMap[instance.Name] = instanceID
}
}else {
//collect name
for _, instanceID := range targets{
if instance, exists := manager.instances[instanceID]; !exists{
err = fmt.Errorf("invalid instance '%s'", instanceID)
respChan <- ResourceResult{Error: err}
return
}else{
idMap[instance.Name] = instanceID
}
}
}
var result ResourceResult
result.Total = len(targets)
if condition.Offset >= result.Total{
err = fmt.Errorf("unexpected offset %d / %d", condition.Offset, result.Total)
respChan <- ResourceResult{Error: err}
return
}
//sort
var names []string
for name, _ := range idMap{
names = append(names, name)
}
sort.Stable(sort.StringSlice(names))
//fetch
var offset = 0
var count = 0
var instance InstanceStatus
var instanceID string
var exists bool
for _, name := range names{
if offset < condition.Offset{
offset++
continue
}
if instanceID, exists = idMap[name]; !exists{
err = fmt.Errorf("can not find id for guest '%s'", name)
respChan <- ResourceResult{Error: err}
return
}else if instance, exists = manager.instances[instanceID]; !exists{
err = fmt.Errorf("find invalid id '%s' for guest '%s'", instanceID, name)
respChan <- ResourceResult{Error: err}
return
}else{
result.InstanceList = append(result.InstanceList, instance)
count++
offset++
if count >= condition.Limit{
break
}
}
}
result.Limit = condition.Limit
result.Offset = condition.Offset
respChan <- result
return
}
func (manager *ResourceManager) matchKeyword(instanceID, keyword string) (matched bool, name string, err error){
instance, exists := manager.instances[instanceID]
if !exists{
err = fmt.Errorf("invalid instance %s", instanceID)
return
}
if -1 != strings.Index(instance.Name, keyword) || -1 != strings.Index(instance.InternalNetwork.InstanceAddress, keyword) ||
-1 != strings.Index(instance.Cell, keyword) || -1 != strings.Index(instance.Host, keyword){
//matched
matched = true
name = instance.Name
return
}
matched = false
return
}
func (manager *ResourceManager) handleUpdateGuestAutoStart(guestID string, enabled bool, respChan chan error) (err error){
instance, exists := manager.instances[guestID]
if !exists{
err = fmt.Errorf("invaliad guest '%s'", guestID)
respChan <- err
return
}
if enabled == instance.AutoStart{
if enabled{
err = fmt.Errorf("auto start of guest '%s' already enabled", instance.Name)
}else{
err = fmt.Errorf("auto start of guest '%s' already disabled", instance.Name)
}
respChan <- err
return
}
instance.AutoStart = enabled
manager.instances[guestID] = instance
respChan <- nil
if enabled{
log.Printf("<resource_manager> guest '%s' enabled auto start", instance.Name)
}else{
log.Printf("<resource_manager> guest '%s' disabled auto start", instance.Name)
}
return
}
func (manager *ResourceManager) getSortedInstances(idList []string) (result []InstanceStatus, err error){
var names []string
var nameToID = map[string]string{}
@ -2472,7 +2656,7 @@ func (manager *ResourceManager) getSortedInstances(idList []string) (result []In
return
}
func (manager *ResourceManager) handleUpdateInstanceAddress(id, ip string, respChan chan error) error{
func (manager *ResourceManager) handleUpdateInstanceAddress(id, ip string, respChan chan error) error{
instance, exists := manager.instances[id]
if !exists{
err := fmt.Errorf("invalid instance %s", id)
@ -3683,6 +3867,7 @@ func (manager *ResourceManager) handleUpdateInstanceMonitorSecret(instanceID, se
log.Printf("<resource_manager> monitor secret of instance '%s' updated", instance.Name)
return
}
func (manager *ResourceManager) handleQuerySystemTemplates(respChan chan ResourceResult) (err error){
defer func() {
if err != nil{
@ -3787,7 +3972,6 @@ func (manager *ResourceManager) handleDeleteSystemTemplate(id string, respChan c
err = manager.saveConfig()
return
}
//Security Policy Group
func (manager *ResourceManager) handleQuerySecurityPolicyGroups(condition SecurityPolicyGroupQueryCondition, respChan chan ResourceResult) (err error){
var group managedSecurityPolicyGroup
@ -4085,6 +4269,7 @@ func (manager *ResourceManager) transferInstances(sourceName, targetName string,
}
instance.Migrating = false
instance.Cell = targetName
instance.Host = targetCell.Address
instance.InternalNetwork.MonitorPort = uint(monitor)
instance.InternalNetwork.MonitorAddress = targetCell.Address
manager.instances[instanceID] = instance
@ -4188,7 +4373,6 @@ func (manager *ResourceManager) deallocateNetworkAddress(pool ManagedComputePool
return err
}
func (manager *ResourceManager) selectCell(poolName string, required InstanceResource, mustFulfill bool) (selected string, err error) {
const (
HealthCpuUsage float64 = 80

99
src/task/modify_guest_auto_start.go

@ -0,0 +1,99 @@
package task
import (
"fmt"
"github.com/project-nano/core/modules"
"github.com/project-nano/framework"
"log"
"time"
)
type ModifyGuestAutoStartExecutor struct {
Sender framework.MessageSender
ResourceModule modules.ResourceModule
}
func (executor *ModifyGuestAutoStartExecutor)Execute(id framework.SessionID, request framework.Message,
incoming chan framework.Message, terminate chan bool) (err error) {
var guestID string
var enable bool
if guestID, err = request.GetString(framework.ParamKeyGuest); err != nil{
err = fmt.Errorf("get guest ID fail: %s", err.Error())
return
}
if enable, err = request.GetBoolean(framework.ParamKeyEnable); err != nil{
err = fmt.Errorf("get enable option fail: %s", err.Error())
return
}
resp, _ := framework.CreateJsonMessage(framework.ModifyAutoStartResponse)
resp.SetToSession(request.GetFromSession())
resp.SetFromSession(id)
resp.SetSuccess(false)
var ins modules.InstanceStatus
{
var respChan = make(chan modules.ResourceResult, 1)
executor.ResourceModule.GetInstanceStatus(guestID, respChan)
result := <- respChan
if result.Error != nil{
log.Printf("[%08X] fetch instance fail: %s", id, result.Error.Error())
resp.SetError(result.Error.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
ins = result.Instance
if ins.AutoStart == enable{
if enable{
err = fmt.Errorf("auto start of guest '%s' already enabled", ins.Name)
}else{
err = fmt.Errorf("auto start of guest '%s' already disabled", ins.Name)
}
resp.SetError(err.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
}
{
//forward request
forward, _ := framework.CreateJsonMessage(framework.ModifyAutoStartRequest)
forward.SetFromSession(id)
forward.SetString(framework.ParamKeyGuest, guestID)
forward.SetBoolean(framework.ParamKeyEnable, enable)
if err = executor.Sender.SendMessage(forward, ins.Cell); err != nil{
log.Printf("[%08X] forward modify auto start to cell '%s' fail: %s", id, ins.Cell, err.Error())
resp.SetError(err.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
timer := time.NewTimer(modules.DefaultOperateTimeout)
select{
case cellResp := <- incoming:
if cellResp.IsSuccess(){
//update
var respChan = make(chan error, 1)
executor.ResourceModule.UpdateGuestAutoStart(guestID, enable, respChan)
err = <- respChan
if err != nil{
log.Printf("[%08X] update auto start status of guest '%s' fail: %s", id, ins.Name, err.Error())
resp.SetError(err.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
if enable{
log.Printf("[%08X] guest '%s' enable auto start", id, guestID)
}else{
log.Printf("[%08X] guest '%s' disable auto start", id, guestID)
}
}else{
log.Printf("[%08X] modify auto start fail: %s", id, cellResp.GetError())
}
cellResp.SetFromSession(id)
cellResp.SetToSession(request.GetFromSession())
//forward
return executor.Sender.SendMessage(cellResp, request.GetSender())
case <- timer.C:
//timeout
log.Printf("[%08X] wait modify auto start response timeout", id)
resp.SetError("request timeout")
return executor.Sender.SendMessage(resp, request.GetSender())
}
}
}

2
src/task/query_guest.go

@ -75,7 +75,7 @@ func (executor *QueryGuestConfigExecutor)Execute(id framework.SessionID, request
{
var respChan = make(chan modules.ResourceResult)
executor.ResourceModule.SearchGuestConfig(condition, respChan)
executor.ResourceModule.QueryGuestsByCondition(condition, respChan)
result := <- respChan
if result.Error != nil{
err = result.Error

61
src/task/search_guests.go

@ -0,0 +1,61 @@
package task
import (
"github.com/project-nano/core/modules"
"github.com/project-nano/framework"
"log"
)
type SearchGuestsExecutor struct {
Sender framework.MessageSender
ResourceModule modules.ResourceModule
}
func (executor *SearchGuestsExecutor)Execute(id framework.SessionID, request framework.Message,
incoming chan framework.Message, terminate chan bool) error {
var err error
var condition modules.SearchGuestsCondition
if condition.Pool, err = request.GetString(framework.ParamKeyPool); err != nil{
return err
}
if condition.Cell, err = request.GetString(framework.ParamKeyCell); err != nil{
return err
}
if condition.Keyword, err = request.GetString(framework.ParamKeyData); err != nil{
return err
}
if condition.Limit, err = request.GetInt(framework.ParamKeyLimit); err != nil{
return err
}
if condition.Offset, err = request.GetInt(framework.ParamKeyStart); err != nil{
return err
}
resp, _ := framework.CreateJsonMessage(framework.SearchGuestResponse)
resp.SetSuccess(false)
resp.SetFromSession(id)
resp.SetToSession(request.GetFromSession())
{
var respChan = make(chan modules.ResourceResult, 1)
executor.ResourceModule.SearchGuests(condition, respChan)
result := <- respChan
if result.Error != nil{
err = result.Error
log.Printf("[%08X] search guests fail: %s", id, err.Error())
resp.SetError(err.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
var guests = result.InstanceList
if err = modules.MarshalInstanceStatusListToMessage(guests, resp); err != nil{
log.Printf("[%08X] build response message for search guests result fail: %s", id, err.Error())
resp.SetError(err.Error())
return executor.Sender.SendMessage(resp, request.GetSender())
}
var flags = []uint64{uint64(result.Total), uint64(result.Limit), uint64(result.Offset)}
resp.SetUIntArray(framework.ParamKeyFlag, flags)
//log.Printf("[%08X] %d guest(s) available", id, len(guests))
resp.SetSuccess(true)
return executor.Sender.SendMessage(resp, request.GetSender())
}
}
Loading…
Cancel
Save