Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v0.8.2 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}