Live video on the AT Protocol
at eli/oatproxy-http-client 197 lines 5.9 kB view raw
1package api 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "strconv" 9 "strings" 10 11 "github.com/julienschmidt/httprouter" 12 "stream.place/streamplace/pkg/aqtime" 13 apierrors "stream.place/streamplace/pkg/errors" 14 "stream.place/streamplace/pkg/log" 15) 16 17const BRANCH = "latest" 18 19func formatRequest(r *http.Request) string { 20 // Create return string 21 var request []string 22 // Add the request string 23 url := fmt.Sprintf("%v %v %v", r.Method, r.URL, r.Proto) 24 request = append(request, url) 25 // Add the host 26 request = append(request, fmt.Sprintf("Host: %v", r.Host)) 27 // Loop through headers 28 for name, headers := range r.Header { 29 name = strings.ToLower(name) 30 for _, h := range headers { 31 request = append(request, fmt.Sprintf("%v: %v", name, h)) 32 } 33 } 34 35 // If this is a POST, add post data 36 if r.Method == "POST" { 37 _ = r.ParseForm() 38 request = append(request, "\n") 39 request = append(request, r.Form.Encode()) 40 } 41 // Return the request as a string 42 return strings.Join(request, "\n") 43} 44 45type MacManifestUpdateTo struct { 46 Version string `json:"version"` 47 PubDate string `json:"pub_date"` 48 Notes string `json:"notes"` 49 Name string `json:"name"` 50 URL string `json:"url"` 51} 52 53type MacManifestRelease struct { 54 Version string `json:"version"` 55 UpdateTo MacManifestUpdateTo `json:"updateTo"` 56} 57 58type MacManifest struct { 59 CurrentRelease string `json:"currentRelease"` 60 Releases []MacManifestRelease `json:"releases"` 61} 62 63func (a *StreamplaceAPI) HandleDesktopUpdates(ctx context.Context) httprouter.Handle { 64 mac := a.HandleMacDesktopUpdates(ctx) 65 win := a.HandleWindowsDesktopUpdates(ctx) 66 return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { 67 platform := params.ByName("platform") 68 if platform == "darwin" { 69 mac(w, req, params) 70 } else if platform == "windows" { 71 win(w, req, params) 72 } else { 73 apierrors.WriteHTTPBadRequest(w, fmt.Sprintf("unsupported platform: %s", platform), nil) 74 } 75 } 76} 77 78func (a *StreamplaceAPI) HandleMacDesktopUpdates(ctx context.Context) httprouter.Handle { 79 return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { 80 platform := params.ByName("platform") 81 architecture := params.ByName("architecture") 82 clientVersion := params.ByName("version") 83 clientBuildTime := params.ByName("buildTime") 84 file := params.ByName("file") 85 if file != "RELEASES.json" { 86 apierrors.WriteHTTPNotFound(w, fmt.Sprintf("unknown file: %s", file), nil) 87 return 88 } 89 log.Log(ctx, formatRequest(req), 90 "platform", platform, 91 "architecture", architecture, 92 "clientVersion", clientVersion, 93 "clientBuildTime", clientBuildTime, 94 ) 95 clientBuildSec, err := strconv.ParseInt(clientBuildTime, 10, 64) 96 if err != nil { 97 apierrors.WriteHTTPBadRequest(w, "build time must be a number", err) 98 return 99 } 100 var mani MacManifest 101 if clientBuildSec >= a.CLI.Build.BuildTime { 102 // client is newer or the same as server 103 mani = MacManifest{ 104 CurrentRelease: clientVersion, 105 Releases: []MacManifestRelease{}, 106 } 107 } else { 108 // we're newer than the client, tell it to update 109 aqt := aqtime.FromSec(a.CLI.Build.BuildTime) 110 // sigh. but at least it's only for dev versions. 111 serverVersionZ := strings.ReplaceAll(a.CLI.Build.Version, "-", "-z") 112 updateTo := MacManifestUpdateTo{ 113 Version: serverVersionZ, 114 PubDate: aqt.String(), 115 Notes: fmt.Sprintf("Streamplace %s", clientVersion), 116 Name: fmt.Sprintf("Streamplace %s", clientVersion), 117 URL: fmt.Sprintf("https://%s/dl/%s/streamplace-desktop-%s-%s.zip", req.Host, BRANCH, platform, architecture), 118 } 119 120 mani = MacManifest{ 121 CurrentRelease: serverVersionZ, 122 Releases: []MacManifestRelease{ 123 { 124 Version: clientVersion, 125 UpdateTo: updateTo, 126 }, 127 // todo: this is straight from their example, but why does this version upgrade to itself...? 128 { 129 Version: serverVersionZ, 130 UpdateTo: updateTo, 131 }, 132 }, 133 } 134 } 135 136 w.Header().Set("content-type", "application/json") 137 w.WriteHeader(200) 138 bs, err := json.Marshal(mani) 139 if err != nil { 140 log.Log(ctx, "error marshaling mac update manifest", "error", err) 141 } 142 if _, err := w.Write(bs); err != nil { 143 log.Error(ctx, "error writing response", "error", err) 144 } 145 } 146} 147 148func (a *StreamplaceAPI) HandleWindowsDesktopUpdates(ctx context.Context) httprouter.Handle { 149 return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { 150 platform := params.ByName("platform") 151 architecture := params.ByName("architecture") 152 clientVersion := params.ByName("version") 153 clientBuildTime := params.ByName("buildTime") 154 file := params.ByName("file") 155 log.Log(ctx, formatRequest(req), 156 "platform", platform, 157 "architecture", architecture, 158 "clientVersion", clientVersion, 159 "clientBuildTime", clientBuildTime, 160 ) 161 162 clientBuildSec, err := strconv.ParseInt(clientBuildTime, 10, 64) 163 if err != nil { 164 apierrors.WriteHTTPBadRequest(w, "build time must be a number", err) 165 return 166 } 167 168 files, err := a.getGitlabPackage(BRANCH) 169 if err != nil { 170 apierrors.WriteHTTPInternalServerError(w, "could not find gitlab package", err) 171 return 172 } 173 174 var gitlabFile *GitlabFile 175 for _, f := range files { 176 if f.Extension == "nupkg" { 177 gitlabFile = &f 178 break 179 } 180 } 181 if gitlabFile == nil { 182 apierrors.WriteHTTPInternalServerError(w, "could not find gitlab package", err) 183 return 184 } 185 186 if file == "RELEASES" { 187 if clientBuildSec >= a.CLI.Build.BuildTime { 188 // client is newer or the same as server 189 fmt.Fprintf(w, "0000000000000000000000000000000000000000 streamplace_desktop-%s-full.nupkg 1", clientVersion) 190 return 191 } 192 fmt.Fprintf(w, "%s streamplace_desktop-%s-full.nupkg %d", gitlabFile.SHA1, gitlabFile.Version, gitlabFile.Size) 193 return 194 } 195 http.Redirect(w, req, gitlabFile.URL(), http.StatusTemporaryRedirect) 196 } 197}