@@ -16,188 +16,191 @@ limitations under the License.
1616package server
1717
1818import (
19- "context"
20- "errors"
21- "fmt"
22- "io"
23- "net/http"
24- "os"
25- "path/filepath"
26- "strings"
27- sync "sync"
28- "syscall"
29- "time"
30-
31- "github.com/linuxsuren/api-testing/pkg/util/home"
32-
33- "github.com/linuxsuren/api-testing/pkg/downloader"
34- "github.com/linuxsuren/api-testing/pkg/logging"
35-
36- fakeruntime "github.com/linuxsuren/go-fake-runtime"
19+ "context"
20+ "errors"
21+ "fmt"
22+ "io"
23+ "net/http"
24+ "os"
25+ "path/filepath"
26+ "strings"
27+ sync "sync"
28+ "syscall"
29+ "time"
30+
31+ "github.com/linuxsuren/api-testing/pkg/util/home"
32+
33+ "github.com/linuxsuren/api-testing/pkg/downloader"
34+ "github.com/linuxsuren/api-testing/pkg/logging"
35+
36+ fakeruntime "github.com/linuxsuren/go-fake-runtime"
3737)
3838
3939var (
40- serverLogger = logging .DefaultLogger (logging .LogLevelInfo ).WithName ("server" )
40+ serverLogger = logging .DefaultLogger (logging .LogLevelInfo ).WithName ("server" )
4141)
4242
4343type ExtManager interface {
44- Start (name , socket string ) (err error )
45- StopAll () (err error )
46- WithDownloader (downloader.PlatformAwareOCIDownloader )
44+ Start (name , socket string ) (err error )
45+ StopAll () (err error )
46+ WithDownloader (downloader.PlatformAwareOCIDownloader )
4747}
4848
4949type storeExtManager struct {
50- execer fakeruntime.Execer
51- ociDownloader downloader.PlatformAwareOCIDownloader
52- socketPrefix string
53- filesNeedToBeRemoved []string
54- extStatusMap map [string ]bool
55- processs []fakeruntime.Process
56- processChan chan fakeruntime.Process
57- stopSingal chan struct {}
58- lock * sync.RWMutex
50+ execer fakeruntime.Execer
51+ ociDownloader downloader.PlatformAwareOCIDownloader
52+ socketPrefix string
53+ filesNeedToBeRemoved []string
54+ extStatusMap map [string ]bool
55+ processs []fakeruntime.Process
56+ processChan chan fakeruntime.Process
57+ stopSingal chan struct {}
58+ lock * sync.RWMutex
5959}
6060
6161var ss * storeExtManager
6262
6363func NewStoreExtManager (execer fakeruntime.Execer ) ExtManager {
64- if ss == nil {
65- ss = & storeExtManager {
66- processChan : make (chan fakeruntime.Process ),
67- stopSingal : make (chan struct {}, 1 ),
68- lock : & sync.RWMutex {},
69- }
70- ss .execer = execer
71- ss .socketPrefix = "unix://"
72- ss .extStatusMap = map [string ]bool {}
73- ss .processCollect ()
74- ss .WithDownloader (& nonDownloader {})
75- }
76- return ss
64+ if ss == nil {
65+ ss = & storeExtManager {
66+ processChan : make (chan fakeruntime.Process ),
67+ stopSingal : make (chan struct {}, 1 ),
68+ lock : & sync.RWMutex {},
69+ }
70+ ss .execer = execer
71+ ss .socketPrefix = "unix://"
72+ ss .extStatusMap = map [string ]bool {}
73+ ss .processCollect ()
74+ ss .WithDownloader (& nonDownloader {})
75+ }
76+ return ss
7777}
7878
7979func NewStoreExtManagerInstance (execer fakeruntime.Execer ) ExtManager {
80- ss = & storeExtManager {
81- processChan : make (chan fakeruntime.Process ),
82- stopSingal : make (chan struct {}, 1 ),
83- lock : & sync.RWMutex {},
84- }
85- ss .execer = execer
86- ss .socketPrefix = "unix://"
87- ss .extStatusMap = map [string ]bool {}
88- ss .processCollect ()
89- ss .WithDownloader (& nonDownloader {})
90- return ss
80+ ss = & storeExtManager {
81+ processChan : make (chan fakeruntime.Process ),
82+ stopSingal : make (chan struct {}, 1 ),
83+ lock : & sync.RWMutex {},
84+ }
85+ ss .execer = execer
86+ ss .socketPrefix = "unix://"
87+ ss .extStatusMap = map [string ]bool {}
88+ ss .processCollect ()
89+ ss .WithDownloader (& nonDownloader {})
90+ return ss
9191}
9292
9393func (s * storeExtManager ) Start (name , socket string ) (err error ) {
94- if v , ok := s .extStatusMap [name ]; ok && v {
95- return
96- }
97- if s .execer .OS () == "windows" {
98- name = name + ".exe"
99- }
100- targetDir := home .GetUserBinDir ()
101- targetBinaryFile := filepath .Join (targetDir , name )
102-
103- var binaryPath string
104- if _ , err = os .Stat (targetBinaryFile ); err == nil {
105- binaryPath = targetBinaryFile
106- } else {
107- serverLogger .Info ("failed to find extension" , "error" , err .Error ())
108-
109- binaryPath , err = s .execer .LookPath (name )
110- if err != nil {
111- err = fmt .Errorf ("not found extension, try to download it, error: %v" , err )
112- go func () {
113- reader , dErr := s .ociDownloader .Download (name , "" , "" )
114- if dErr != nil {
115- serverLogger .Error (dErr , "failed to download extension" , "name" , name )
116- } else {
117- extFile := s .ociDownloader .GetTargetFile ()
118-
119- targetFile := filepath .Base (extFile )
120- if dErr = downloader .WriteTo (reader , targetDir , targetFile ); dErr == nil {
121- binaryPath = filepath .Join (targetDir , targetFile )
122- s .startPlugin (socket , binaryPath , name )
123- } else {
124- serverLogger .Error (dErr , "failed to save extension" , "targetFile" , targetFile )
125- }
126- }
127- }()
128- }
129- }
130-
131- if err == nil {
132- go s .startPlugin (socket , binaryPath , name )
133- }
134- return
94+ if v , ok := s .extStatusMap [name ]; ok && v {
95+ return
96+ }
97+ platformBasedName := name
98+ if s .execer .OS () == "windows" {
99+ platformBasedName += ".exe"
100+ }
101+ targetDir := home .GetUserBinDir ()
102+ targetBinaryFile := filepath .Join (targetDir , platformBasedName )
103+
104+ var binaryPath string
105+ if _ , err = os .Stat (targetBinaryFile ); err == nil {
106+ binaryPath = targetBinaryFile
107+ } else {
108+ serverLogger .Info ("failed to find extension" , "error" , err .Error ())
109+
110+ binaryPath , err = s .execer .LookPath (platformBasedName )
111+ if err != nil {
112+ err = fmt .Errorf ("not found extension, try to download it, error: %v" , err )
113+ go func () {
114+ s .ociDownloader .WithKind ("store" )
115+ s .ociDownloader .WithOS (s .execer .OS ())
116+ reader , dErr := s .ociDownloader .Download (name , "" , "" )
117+ if dErr != nil {
118+ serverLogger .Error (dErr , "failed to download extension" , "name" , name )
119+ } else {
120+ extFile := s .ociDownloader .GetTargetFile ()
121+
122+ targetFile := filepath .Base (extFile )
123+ if dErr = downloader .WriteTo (reader , targetDir , targetFile ); dErr == nil {
124+ binaryPath = filepath .Join (targetDir , targetFile )
125+ s .startPlugin (socket , binaryPath , name )
126+ } else {
127+ serverLogger .Error (dErr , "failed to save extension" , "targetFile" , targetFile )
128+ }
129+ }
130+ }()
131+ }
132+ }
133+
134+ if err == nil {
135+ go s .startPlugin (socket , binaryPath , name )
136+ }
137+ return
135138}
136139
137140func (s * storeExtManager ) startPlugin (socketURL , plugin , pluginName string ) (err error ) {
138- if strings .Contains (socketURL , ":" ) && ! strings .HasPrefix (socketURL , s .socketPrefix ) {
139- err = s .startPluginViaHTTP (socketURL , plugin , pluginName )
140- return
141- }
142- socketFile := strings .TrimPrefix (socketURL , s .socketPrefix )
143- _ = os .RemoveAll (socketFile ) // always deleting the socket file to avoid start failing
141+ if strings .Contains (socketURL , ":" ) && ! strings .HasPrefix (socketURL , s .socketPrefix ) {
142+ err = s .startPluginViaHTTP (socketURL , plugin , pluginName )
143+ return
144+ }
145+ socketFile := strings .TrimPrefix (socketURL , s .socketPrefix )
146+ _ = os .RemoveAll (socketFile ) // always deleting the socket file to avoid start failing
144147
145- s .lock .Lock ()
146- s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
147- s .extStatusMap [pluginName ] = true
148- s .lock .Unlock ()
148+ s .lock .Lock ()
149+ s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
150+ s .extStatusMap [pluginName ] = true
151+ s .lock .Unlock ()
149152
150- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--socket" , socketFile ); err != nil {
151- serverLogger .Info ("failed to start ext manager" , "socket" , socketURL , "error: " , err .Error ())
152- }
153- return
153+ if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--socket" , socketFile ); err != nil {
154+ serverLogger .Info ("failed to start ext manager" , "socket" , socketURL , "error: " , err .Error ())
155+ }
156+ return
154157}
155158
156159func (s * storeExtManager ) startPluginViaHTTP (httpURL , plugin , pluginName string ) (err error ) {
157- port := strings .Split (httpURL , ":" )[1 ]
158- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--port" , port ); err != nil {
159- serverLogger .Info ("failed to start ext manager" , "port" , port , "error: " , err .Error ())
160- }
161- return
160+ port := strings .Split (httpURL , ":" )[1 ]
161+ if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--port" , port ); err != nil {
162+ serverLogger .Info ("failed to start ext manager" , "port" , port , "error: " , err .Error ())
163+ }
164+ return
162165}
163166
164167func (s * storeExtManager ) StopAll () error {
165- serverLogger .Info ("stop" , "extensions" , len (s .processs ))
166- for _ , p := range s .processs {
167- if p != nil {
168- // Use Kill on Windows, Signal on other platforms
169- if isWindows () {
170- p .Kill ()
171- } else {
172- p .Signal (syscall .SIGTERM )
173- }
174- }
175- }
176- s .stopSingal <- struct {}{}
177- return nil
168+ serverLogger .Info ("stop" , "extensions" , len (s .processs ))
169+ for _ , p := range s .processs {
170+ if p != nil {
171+ // Use Kill on Windows, Signal on other platforms
172+ if isWindows () {
173+ p .Kill ()
174+ } else {
175+ p .Signal (syscall .SIGTERM )
176+ }
177+ }
178+ }
179+ s .stopSingal <- struct {}{}
180+ return nil
178181}
179182
180183// isWindows returns true if the program is running on Windows OS.
181184func isWindows () bool {
182- return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
183- (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
185+ return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
186+ (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
184187}
185188
186189func (s * storeExtManager ) WithDownloader (ociDownloader downloader.PlatformAwareOCIDownloader ) {
187- s .ociDownloader = ociDownloader
190+ s .ociDownloader = ociDownloader
188191}
189192
190193func (s * storeExtManager ) processCollect () {
191- go func () {
192- for {
193- select {
194- case p := <- s .processChan :
195- s .processs = append (s .processs , p )
196- case <- s .stopSingal :
197- return
198- }
199- }
200- }()
194+ go func () {
195+ for {
196+ select {
197+ case p := <- s .processChan :
198+ s .processs = append (s .processs , p )
199+ case <- s .stopSingal :
200+ return
201+ }
202+ }
203+ }()
201204}
202205
203206var ErrDownloadNotSupport = errors .New ("no support" )
@@ -207,44 +210,44 @@ type nonDownloader struct{}
207210var _ downloader.PlatformAwareOCIDownloader = & nonDownloader {}
208211
209212func (n * nonDownloader ) WithBasicAuth (username string , password string ) {
210- // Do nothing because this is an empty implementation
213+ // Do nothing because this is an empty implementation
211214}
212215
213216func (n * nonDownloader ) Download (image , tag , file string ) (reader io.Reader , err error ) {
214- err = ErrDownloadNotSupport
215- return
217+ err = ErrDownloadNotSupport
218+ return
216219}
217220
218221func (n * nonDownloader ) WithOS (string ) {
219- // Do nothing because this is an empty implementation
222+ // Do nothing because this is an empty implementation
220223}
221224
222225func (n * nonDownloader ) WithArch (string ) {
223- // Do nothing because this is an empty implementation
226+ // Do nothing because this is an empty implementation
224227}
225228
226229func (n * nonDownloader ) WithRegistry (string ) {
227- // Do nothing because this is an empty implementation
230+ // Do nothing because this is an empty implementation
228231}
229232
230233func (n * nonDownloader ) WithKind (string ) {
231- // Do nothing because this is an empty implementation
234+ // Do nothing because this is an empty implementation
232235}
233236
234237func (n * nonDownloader ) WithImagePrefix (imagePrefix string ) {
235- // Do nothing because this is an empty implementation
238+ // Do nothing because this is an empty implementation
236239}
237240func (d * nonDownloader ) WithRoundTripper (rt http.RoundTripper ) {
238- // Do nothing because this is an empty implementation
241+ // Do nothing because this is an empty implementation
239242}
240243
241244func (d * nonDownloader ) WithInsecure (bool ) {
242- // Do nothing because this is an empty implementation
245+ // Do nothing because this is an empty implementation
243246}
244247
245248func (d * nonDownloader ) WithTimeout (time.Duration ) {}
246249func (d * nonDownloader ) WithContext (context.Context ) {}
247250
248251func (n * nonDownloader ) GetTargetFile () string {
249- return ""
252+ return ""
250253}
0 commit comments