mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 01:12:24 -06:00 
			
		
		
		
	
		
			
	
	
		
			170 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			170 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2015 Google Inc. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by the Apache 2.0
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// +build appengine
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package internal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"net/http"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"appengine"
							 | 
						||
| 
								 | 
							
									"appengine_internal"
							 | 
						||
| 
								 | 
							
									basepb "appengine_internal/base"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"github.com/golang/protobuf/proto"
							 | 
						||
| 
								 | 
							
									netcontext "golang.org/x/net/context"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var contextKey = "holds an appengine.Context"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// fromContext returns the App Engine context or nil if ctx is not
							 | 
						||
| 
								 | 
							
								// derived from an App Engine context.
							 | 
						||
| 
								 | 
							
								func fromContext(ctx netcontext.Context) appengine.Context {
							 | 
						||
| 
								 | 
							
									c, _ := ctx.Value(&contextKey).(appengine.Context)
							 | 
						||
| 
								 | 
							
									return c
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// This is only for classic App Engine adapters.
							 | 
						||
| 
								 | 
							
								func ClassicContextFromContext(ctx netcontext.Context) (appengine.Context, error) {
							 | 
						||
| 
								 | 
							
									c := fromContext(ctx)
							 | 
						||
| 
								 | 
							
									if c == nil {
							 | 
						||
| 
								 | 
							
										return nil, errNotAppEngineContext
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return c, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func withContext(parent netcontext.Context, c appengine.Context) netcontext.Context {
							 | 
						||
| 
								 | 
							
									ctx := netcontext.WithValue(parent, &contextKey, c)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									s := &basepb.StringProto{}
							 | 
						||
| 
								 | 
							
									c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil)
							 | 
						||
| 
								 | 
							
									if ns := s.GetValue(); ns != "" {
							 | 
						||
| 
								 | 
							
										ctx = NamespacedContext(ctx, ns)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ctx
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func IncomingHeaders(ctx netcontext.Context) http.Header {
							 | 
						||
| 
								 | 
							
									if c := fromContext(ctx); c != nil {
							 | 
						||
| 
								 | 
							
										if req, ok := c.Request().(*http.Request); ok {
							 | 
						||
| 
								 | 
							
											return req.Header
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func ReqContext(req *http.Request) netcontext.Context {
							 | 
						||
| 
								 | 
							
									return WithContext(netcontext.Background(), req)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
							 | 
						||
| 
								 | 
							
									c := appengine.NewContext(req)
							 | 
						||
| 
								 | 
							
									return withContext(parent, c)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type testingContext struct {
							 | 
						||
| 
								 | 
							
									appengine.Context
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									req *http.Request
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (t *testingContext) FullyQualifiedAppID() string { return "dev~testcontext" }
							 | 
						||
| 
								 | 
							
								func (t *testingContext) Call(service, method string, _, _ appengine_internal.ProtoMessage, _ *appengine_internal.CallOptions) error {
							 | 
						||
| 
								 | 
							
									if service == "__go__" && method == "GetNamespace" {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return fmt.Errorf("testingContext: unsupported Call")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								func (t *testingContext) Request() interface{} { return t.req }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func ContextForTesting(req *http.Request) netcontext.Context {
							 | 
						||
| 
								 | 
							
									return withContext(netcontext.Background(), &testingContext{req: req})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
							 | 
						||
| 
								 | 
							
									if ns := NamespaceFromContext(ctx); ns != "" {
							 | 
						||
| 
								 | 
							
										if fn, ok := NamespaceMods[service]; ok {
							 | 
						||
| 
								 | 
							
											fn(in, ns)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if f, ctx, ok := callOverrideFromContext(ctx); ok {
							 | 
						||
| 
								 | 
							
										return f(ctx, service, method, in, out)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Handle already-done contexts quickly.
							 | 
						||
| 
								 | 
							
									select {
							 | 
						||
| 
								 | 
							
									case <-ctx.Done():
							 | 
						||
| 
								 | 
							
										return ctx.Err()
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									c := fromContext(ctx)
							 | 
						||
| 
								 | 
							
									if c == nil {
							 | 
						||
| 
								 | 
							
										// Give a good error message rather than a panic lower down.
							 | 
						||
| 
								 | 
							
										return errNotAppEngineContext
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Apply transaction modifications if we're in a transaction.
							 | 
						||
| 
								 | 
							
									if t := transactionFromContext(ctx); t != nil {
							 | 
						||
| 
								 | 
							
										if t.finished {
							 | 
						||
| 
								 | 
							
											return errors.New("transaction context has expired")
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										applyTransaction(in, &t.transaction)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var opts *appengine_internal.CallOptions
							 | 
						||
| 
								 | 
							
									if d, ok := ctx.Deadline(); ok {
							 | 
						||
| 
								 | 
							
										opts = &appengine_internal.CallOptions{
							 | 
						||
| 
								 | 
							
											Timeout: d.Sub(time.Now()),
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err := c.Call(service, method, in, out, opts)
							 | 
						||
| 
								 | 
							
									switch v := err.(type) {
							 | 
						||
| 
								 | 
							
									case *appengine_internal.APIError:
							 | 
						||
| 
								 | 
							
										return &APIError{
							 | 
						||
| 
								 | 
							
											Service: v.Service,
							 | 
						||
| 
								 | 
							
											Detail:  v.Detail,
							 | 
						||
| 
								 | 
							
											Code:    v.Code,
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case *appengine_internal.CallError:
							 | 
						||
| 
								 | 
							
										return &CallError{
							 | 
						||
| 
								 | 
							
											Detail:  v.Detail,
							 | 
						||
| 
								 | 
							
											Code:    v.Code,
							 | 
						||
| 
								 | 
							
											Timeout: v.Timeout,
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return err
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func handleHTTP(w http.ResponseWriter, r *http.Request) {
							 | 
						||
| 
								 | 
							
									panic("handleHTTP called; this should be impossible")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func logf(c appengine.Context, level int64, format string, args ...interface{}) {
							 | 
						||
| 
								 | 
							
									var fn func(format string, args ...interface{})
							 | 
						||
| 
								 | 
							
									switch level {
							 | 
						||
| 
								 | 
							
									case 0:
							 | 
						||
| 
								 | 
							
										fn = c.Debugf
							 | 
						||
| 
								 | 
							
									case 1:
							 | 
						||
| 
								 | 
							
										fn = c.Infof
							 | 
						||
| 
								 | 
							
									case 2:
							 | 
						||
| 
								 | 
							
										fn = c.Warningf
							 | 
						||
| 
								 | 
							
									case 3:
							 | 
						||
| 
								 | 
							
										fn = c.Errorf
							 | 
						||
| 
								 | 
							
									case 4:
							 | 
						||
| 
								 | 
							
										fn = c.Criticalf
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										// This shouldn't happen.
							 | 
						||
| 
								 | 
							
										fn = c.Criticalf
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									fn(format, args...)
							 | 
						||
| 
								 | 
							
								}
							 |