feat: initial daemon implementation
This commit is contained in:
		
							
								
								
									
										202
									
								
								api/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								api/api.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"code.dumpstack.io/tools/out-of-tree/artifact" | ||||
| 	"code.dumpstack.io/tools/out-of-tree/distro" | ||||
|  | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| ) | ||||
|  | ||||
| var ErrInvalid = errors.New("") | ||||
|  | ||||
| type Status string | ||||
|  | ||||
| const ( | ||||
| 	StatusNew     Status = "new" | ||||
| 	StatusWaiting Status = "waiting" | ||||
| 	StatusRunning Status = "running" | ||||
| 	StatusSuccess Status = "success" | ||||
| 	StatusFailure Status = "failure" | ||||
| ) | ||||
|  | ||||
| type Command string | ||||
|  | ||||
| const ( | ||||
| 	RawMode Command = "rawmode" | ||||
|  | ||||
| 	AddJob    Command = "add_job" | ||||
| 	ListJobs  Command = "list_jobs" | ||||
| 	JobLogs   Command = "job_logs" | ||||
| 	JobStatus Command = "job_status" | ||||
|  | ||||
| 	AddRepo   Command = "add_repo" | ||||
| 	ListRepos Command = "list_repos" | ||||
|  | ||||
| 	Kernels Command = "kernels" | ||||
| ) | ||||
|  | ||||
| type Job struct { | ||||
| 	ID   int64 | ||||
| 	UUID string | ||||
|  | ||||
| 	RepoName string | ||||
| 	Commit   string | ||||
|  | ||||
| 	Params   string | ||||
| 	Artifact artifact.Artifact | ||||
| 	Target   distro.KernelInfo | ||||
|  | ||||
| 	Status Status | ||||
| } | ||||
|  | ||||
| func (job *Job) GenUUID() { | ||||
| 	job.UUID = uuid.New().String() | ||||
| } | ||||
|  | ||||
| type Repo struct { | ||||
| 	ID   int64 | ||||
| 	Name string | ||||
| 	Path string | ||||
| } | ||||
|  | ||||
| type JobLog struct { | ||||
| 	Name string | ||||
| 	Text string | ||||
| } | ||||
|  | ||||
| type Req struct { | ||||
| 	Command Command | ||||
|  | ||||
| 	Type string | ||||
| 	Data []byte | ||||
| } | ||||
|  | ||||
| func (r *Req) SetData(data any) { | ||||
| 	r.Type = fmt.Sprintf("%v", reflect.TypeOf(data)) | ||||
| 	r.Data = Marshal(data) | ||||
| } | ||||
|  | ||||
| func (r *Req) GetData(data any) (err error) { | ||||
| 	if len(r.Data) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t := fmt.Sprintf("%v", reflect.TypeOf(data)) | ||||
| 	if r.Type != t { | ||||
| 		err = fmt.Errorf("type mismatch (%v != %v)", r.Type, t) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Trace().Msgf("unmarshal %v", string(r.Data)) | ||||
| 	err = json.Unmarshal(r.Data, &data) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r Req) Encode(conn net.Conn) { | ||||
| 	log.Trace().Msgf("encode %v", spew.Sdump(r)) | ||||
| 	err := json.NewEncoder(conn).Encode(&r) | ||||
| 	if err != nil { | ||||
| 		log.Fatal().Err(err).Msgf("encode %v", r) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *Req) Decode(conn net.Conn) (err error) { | ||||
| 	err = json.NewDecoder(conn).Decode(r) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r Req) Marshal() (bytes []byte) { | ||||
| 	return Marshal(r) | ||||
| } | ||||
|  | ||||
| func (Req) Unmarshal(data []byte) (r Req, err error) { | ||||
| 	err = json.Unmarshal(data, &r) | ||||
| 	log.Trace().Msgf("unmarshal %v", spew.Sdump(r)) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| type Resp struct { | ||||
| 	UUID string | ||||
|  | ||||
| 	Error string | ||||
|  | ||||
| 	Err error `json:"-"` | ||||
|  | ||||
| 	Type string | ||||
| 	Data []byte | ||||
| } | ||||
|  | ||||
| func NewResp() (resp Resp) { | ||||
| 	resp.UUID = uuid.New().String() | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *Resp) SetData(data any) { | ||||
| 	r.Type = fmt.Sprintf("%v", reflect.TypeOf(data)) | ||||
| 	r.Data = Marshal(data) | ||||
| } | ||||
|  | ||||
| func (r *Resp) GetData(data any) (err error) { | ||||
| 	if len(r.Data) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t := fmt.Sprintf("%v", reflect.TypeOf(data)) | ||||
| 	if r.Type != t { | ||||
| 		err = fmt.Errorf("type mismatch (%v != %v)", r.Type, t) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Trace().Msgf("unmarshal %v", string(r.Data)) | ||||
| 	err = json.Unmarshal(r.Data, &data) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *Resp) Encode(conn net.Conn) { | ||||
| 	if r.Err != nil && r.Err != ErrInvalid && r.Error == "" { | ||||
| 		r.Error = fmt.Sprintf("%v", r.Err) | ||||
| 	} | ||||
| 	log.Trace().Msgf("encode %v", spew.Sdump(r)) | ||||
| 	err := json.NewEncoder(conn).Encode(r) | ||||
| 	if err != nil { | ||||
| 		log.Fatal().Err(err).Msgf("encode %v", r) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *Resp) Decode(conn net.Conn) (err error) { | ||||
| 	err = json.NewDecoder(conn).Decode(r) | ||||
| 	r.Err = ErrInvalid | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (r *Resp) Marshal() (bytes []byte) { | ||||
| 	if r.Err != nil && r.Err != ErrInvalid && r.Error == "" { | ||||
| 		r.Error = fmt.Sprintf("%v", r.Err) | ||||
| 	} | ||||
|  | ||||
| 	return Marshal(r) | ||||
| } | ||||
|  | ||||
| func (Resp) Unmarshal(data []byte) (r Resp, err error) { | ||||
| 	err = json.Unmarshal(data, &r) | ||||
| 	log.Trace().Msgf("unmarshal %v", spew.Sdump(r)) | ||||
| 	r.Err = ErrInvalid | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Marshal(data any) (bytes []byte) { | ||||
| 	bytes, err := json.Marshal(data) | ||||
| 	if err != nil { | ||||
| 		log.Fatal().Err(err).Msgf("marshal %v", data) | ||||
| 	} | ||||
| 	log.Trace().Msgf("marshal %v", string(bytes)) | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										47
									
								
								api/api_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								api/api_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestReq(t *testing.T) { | ||||
| 	req := Req{} | ||||
|  | ||||
| 	req.Command = ListRepos | ||||
| 	req.SetData(Job{ID: 999, RepoName: "test"}) | ||||
|  | ||||
| 	bytes := req.Marshal() | ||||
|  | ||||
| 	req2, err := Req{}.Unmarshal(bytes) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assert.Equal(t, req, req2) | ||||
|  | ||||
| 	job := Job{} | ||||
| 	err = req2.GetData(&job) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assert.Equal(t, req2.Type, "api.Job") | ||||
| } | ||||
|  | ||||
| func TestResp(t *testing.T) { | ||||
| 	resp := Resp{} | ||||
|  | ||||
| 	resp.Error = "abracadabra" | ||||
| 	resp.SetData([]Repo{Repo{}, Repo{}}) | ||||
|  | ||||
| 	bytes := resp.Marshal() | ||||
|  | ||||
| 	resp2, err := Resp{}.Unmarshal(bytes) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assert.Equal(t, resp, resp2) | ||||
|  | ||||
| 	var repos []Repo | ||||
| 	err = resp2.GetData(&repos) | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| 	assert.Equal(t, resp2.Type, "[]api.Repo") | ||||
| } | ||||
		Reference in New Issue
	
	Block a user