fork
Configure Feed
Select the types of activity you want to include in your feed.
Live video on the AT Protocol
fork
Configure Feed
Select the types of activity you want to include in your feed.
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}