@@ -16,183 +16,188 @@ 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- targetDir := home .GetUserBinDir ()
98- targetBinaryFile := filepath .Join (targetDir , name )
99-
100- var binaryPath string
101- if _ , err = os .Stat (targetBinaryFile ); err == nil {
102- binaryPath = targetBinaryFile
103- } else {
104- binaryPath , err = s .execer .LookPath (name )
105- if err != nil {
106- err = fmt .Errorf ("not found extension, try to download it, error: %v" , err )
107- go func () {
108- reader , dErr := s .ociDownloader .Download (name , "" , "" )
109- if dErr != nil {
110- serverLogger .Error (dErr , "failed to download extension" , "name" , name )
111- } else {
112- extFile := s .ociDownloader .GetTargetFile ()
113-
114- targetFile := filepath .Base (extFile )
115- if dErr = downloader .WriteTo (reader , targetDir , targetFile ); dErr == nil {
116- binaryPath = filepath .Join (targetDir , targetFile )
117- s .startPlugin (socket , binaryPath , name )
118- } else {
119- serverLogger .Error (dErr , "failed to save extension" , "targetFile" , targetFile )
120- }
121- }
122- }()
123- }
124- }
125-
126- if err == nil {
127- go s .startPlugin (socket , binaryPath , name )
128- }
129- return
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
130135}
131136
132137func (s * storeExtManager ) startPlugin (socketURL , plugin , pluginName string ) (err error ) {
133- if strings .Contains (socketURL , ":" ) && ! strings .HasPrefix (socketURL , s .socketPrefix ) {
134- err = s .startPluginViaHTTP (socketURL , plugin , pluginName )
135- return
136- }
137- socketFile := strings .TrimPrefix (socketURL , s .socketPrefix )
138- _ = os .RemoveAll (socketFile ) // always deleting the socket file to avoid start failing
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
139144
140- s .lock .Lock ()
141- s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
142- s .extStatusMap [pluginName ] = true
143- s .lock .Unlock ()
145+ s .lock .Lock ()
146+ s .filesNeedToBeRemoved = append (s .filesNeedToBeRemoved , socketFile )
147+ s .extStatusMap [pluginName ] = true
148+ s .lock .Unlock ()
144149
145- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--socket" , socketFile ); err != nil {
146- serverLogger .Info ("failed to start ext manager" , "socket" , socketURL , "error: " , err .Error ())
147- }
148- return
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
149154}
150155
151156func (s * storeExtManager ) startPluginViaHTTP (httpURL , plugin , pluginName string ) (err error ) {
152- port := strings .Split (httpURL , ":" )[1 ]
153- if err = s .execer .RunCommandWithIO (plugin , "" , os .Stdout , os .Stderr , s .processChan , "--port" , port ); err != nil {
154- serverLogger .Info ("failed to start ext manager" , "port" , port , "error: " , err .Error ())
155- }
156- return
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
157162}
158163
159164func (s * storeExtManager ) StopAll () error {
160- serverLogger .Info ("stop" , "extensions" , len (s .processs ))
161- for _ , p := range s .processs {
162- if p != nil {
163- // Use Kill on Windows, Signal on other platforms
164- if isWindows () {
165- p .Kill ()
166- } else {
167- p .Signal (syscall .SIGTERM )
168- }
169- }
170- }
171- s .stopSingal <- struct {}{}
172- return nil
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
173178}
174179
175180// isWindows returns true if the program is running on Windows OS.
176181func isWindows () bool {
177- return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
178- (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
182+ return strings .Contains (strings .ToLower (os .Getenv ("OS" )), "windows" ) ||
183+ (strings .Contains (strings .ToLower (os .Getenv ("GOOS" )), "windows" ))
179184}
180185
181186func (s * storeExtManager ) WithDownloader (ociDownloader downloader.PlatformAwareOCIDownloader ) {
182- s .ociDownloader = ociDownloader
187+ s .ociDownloader = ociDownloader
183188}
184189
185190func (s * storeExtManager ) processCollect () {
186- go func () {
187- for {
188- select {
189- case p := <- s .processChan :
190- s .processs = append (s .processs , p )
191- case <- s .stopSingal :
192- return
193- }
194- }
195- }()
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+ }()
196201}
197202
198203var ErrDownloadNotSupport = errors .New ("no support" )
@@ -202,44 +207,44 @@ type nonDownloader struct{}
202207var _ downloader.PlatformAwareOCIDownloader = & nonDownloader {}
203208
204209func (n * nonDownloader ) WithBasicAuth (username string , password string ) {
205- // Do nothing because this is an empty implementation
210+ // Do nothing because this is an empty implementation
206211}
207212
208213func (n * nonDownloader ) Download (image , tag , file string ) (reader io.Reader , err error ) {
209- err = ErrDownloadNotSupport
210- return
214+ err = ErrDownloadNotSupport
215+ return
211216}
212217
213218func (n * nonDownloader ) WithOS (string ) {
214- // Do nothing because this is an empty implementation
219+ // Do nothing because this is an empty implementation
215220}
216221
217222func (n * nonDownloader ) WithArch (string ) {
218- // Do nothing because this is an empty implementation
223+ // Do nothing because this is an empty implementation
219224}
220225
221226func (n * nonDownloader ) WithRegistry (string ) {
222- // Do nothing because this is an empty implementation
227+ // Do nothing because this is an empty implementation
223228}
224229
225230func (n * nonDownloader ) WithKind (string ) {
226- // Do nothing because this is an empty implementation
231+ // Do nothing because this is an empty implementation
227232}
228233
229234func (n * nonDownloader ) WithImagePrefix (imagePrefix string ) {
230- // Do nothing because this is an empty implementation
235+ // Do nothing because this is an empty implementation
231236}
232237func (d * nonDownloader ) WithRoundTripper (rt http.RoundTripper ) {
233- // Do nothing because this is an empty implementation
238+ // Do nothing because this is an empty implementation
234239}
235240
236241func (d * nonDownloader ) WithInsecure (bool ) {
237- // Do nothing because this is an empty implementation
242+ // Do nothing because this is an empty implementation
238243}
239244
240245func (d * nonDownloader ) WithTimeout (time.Duration ) {}
241246func (d * nonDownloader ) WithContext (context.Context ) {}
242247
243248func (n * nonDownloader ) GetTargetFile () string {
244- return ""
249+ return ""
245250}
0 commit comments