package host import ( "errors" "strings" log "git.staur.ca/stobbsm/simplelog" ) // URI is a string type, accessed via the pre-defined variables, and represent // the URI pattern used to connect to a host. // Example: // Driver[+Transport]://[:PORT]/[?Options&in=uri&format] type URI struct { Driver string Transport string Path string Host string Options []string } // Define create and return a custom URI method, following RFC2396, // keeping in mind that the hostname will be inserted between the transport and path func Define(driver, transport, path string, options ...string) *URI { return &URI{ Driver: driver, Transport: transport, Path: path, Options: options, } } var ( URI_QEMU_LOCAL = Define("qemu", "local", "system") URI_QEMU_SSH = Define("qemu", "ssh", "system") ) // WithHost sets the hostname as part of a URI. It copies the original URI and returns a new one func (u *URI) WithHost(host string) *URI { return &URI{ Driver: u.Driver, Transport: u.Transport, Path: u.Path, Host: host, Options: u.Options, } } // IsRemote returns true if the URI references a remote trasnport (ssh, tcp or tls) func (u *URI) IsRemote() bool { switch u.Transport { case "ssh": fallthrough case "tls": fallthrough case "tcp": return true default: return false } } // validTransport makes sure the value of transport if valid or empty. If the transport // isn't remote, it returns an empty string func (u *URI) validTransport() bool { if u.IsRemote() { return true } switch u.Transport { case "unix": fallthrough case "local": return true default: return false } } func (u *URI) validDriver() bool { switch u.Driver { case "qemu": fallthrough case "xen": fallthrough case "lxc": return true default: return false } } // ConnectionString takes a host name to interpolate into a URI and returns the string func (u *URI) ConnectionString() string { // Normalize the variables var driver, transport, path, host string if !u.validTransport() { log.Panic("host.URI.ConnectionString"). Err(errors.New("invalid transport")). Str("transport", u.Transport). Send() } transport = u.Transport if (u.Host == "localhost" && u.IsRemote()) || u.Host != "localhost" { host = u.Host } // TODO: validate driver, path if !u.validDriver() { log.Panic("host.URI.ConnectionString"). Err(errors.New("invalid driver")). Str("driver", u.Driver). Send() } driver = u.Driver path = u.Path var sb strings.Builder optlen := len(u.Options) sb.WriteString(driver) if transport != "" { sb.WriteRune('+') sb.WriteString(u.Transport) } sb.WriteString("://") if host != "" { sb.WriteString(host) } sb.WriteRune('/') sb.WriteString(path) if optlen > 0 { sb.WriteRune('?') for i, o := range u.Options { sb.WriteString(o) if optlen != i+1 { sb.WriteRune('&') } } } log.Info("Host.ConnectionString"). Str("uri.Driver", u.Driver). Str("uri.Transport", u.Transport). Str("uri.Path", u.Path). Strs("uri.Options", u.Options). Str("builtUri", sb.String()).Send() return sb.String() } // AddOpt adds more options to the option list func (u *URI) AddOpt(opt string) { u.Options = append(u.Options, opt) }