Instead of writing every route under main(), like
func main() {
e := echo.New()
e.GET("/api", sayHello)
e.GET("/api/music", getMusic)
e.GET("/api/user/:id", getDetail)
e.POST("/api/user", addUser)
// ...
}
How can I import these all sub-routes from a file called api.go, and use those in the main function? Similar to
import "./API"
func main() {
e := echo.New()
e.UseSubroute(API.Routes) // <-- similar to this
// ...
}
What you can do is use the echo.Group and pass it to the api package, and initialize the routes handler there.
package api
import (
"github.com/labstack/echo"
)
func UseSubroute(group *echo.Group) {
group.GET("/", sayHello)
group.GET("/music", getMusic)
group.GET("/user/:id", getDetail)
group.POST("/user", addUser)
}
and in the main you can just import your api package.
package main
import (
"github.com/labstack/echo"
"your-repo/path-to/api" // your api package
)
func main() {
e := echo.New()
apiGroup := e.Group("/api")
api.UseSubroute(apiGroup)
// ...
}
The Echo object does not have this method. I think you need the code?
API.go:
package main
import "github.com/labstack/echo"
func UseSubroute(echo *echo.Echo) {
echo.GET("/api", sayHello)
echo.GET("/api/music", getMusic)
echo.GET("/api/user/:id", getDetail)
echo.POST("/api/user", addUser)
}
main.go:
package main
import "github.com/labstack/echo"
func main() {
e := echo.New()
UseSubroute(e)
}
These two files need to be placed in the same directory.
Do you need it?
Based on #Andy 's idea, I come up with a solution, that supports detachable nested routes.
The current folder structure is as follows:
.
├── routes
│ ├── index.go
│ └── music.go
└── server.go
...where server.go is the project main entry, belongs to the main package, while index.go and music.go belong to routes package.
The endpoints are
"/api" -> index.go
"/api/music" -> music.go
First in index.go we define a function for using routes at this level.
func UseRoute(group *echo.Group, routes func(group *echo.Group)) {
routes(group)
}
Then,
in server.go
func main() {
e := echo.New()
apiGroup := e.Group("/api")
routes.ActivateIndex(mainGroup)
}
in index.go
var mainGroup *echo.Group
func ActivateIndex(g *echo.Group) {
mainGroup = g
UseRoute(mainGroup, IndexRoutes)
// sub routes
musicGroup := mainGroup.Group("/music")
ActivateMusic(musicGroup)
}
and in music.go
var musicGroup *echo.Group
func ActivateMusic(g *echo.Group) {
musicGroup = g
UseRoute(musicGroup, MusicRoutes)
}
Note: IndexRoutes, MusicRoutes etc. are functions that specify endpoints at this level.
e.g.
func IndexRoutes(group *echo.Group) {
group.GET("/", sayHello)
group.GET("/user/:id", getDetail)
group.POST("/user", addUser)
}
In this way, the routes can be defined in different .go files, making the business logic clearer.
For example, to extend the nested level, we can create another ActivateHiphop function in hiphop.go, also import the new sub-routes at ActivateMusic function from music.go, so that "/api/music/hiphop" can be pointed to hiphop.go.
p.s. To add more routes in /api level, just create more endpoints in IndexRoutes function.
Related
I'm using VS Code API's ExtensionContext.globalState() to count the number of the times the sidebar of our extension has been opened. This is inside a command a handler in extension.ts and it counts the number of opens on local storage as expected.
I want to retrieve that count on a .js file where we are using JQuery to append components to the UI of the sidebar. However, I don't know how to retrieve ExtensionContext.globalState outisde of extension.ts
This is how I'm getting and updating the value of the count on extension.ts
const retrievedOpeningCountValue = context.globalState.get<Number>("sidebarOpeningCount");
// If show hasn't been called yet, retrieve 0, then increase it to 1 to store such value
let retrievedValue = retrievedOpeningCountValue?.valueOf() || 0;
let increasedValue = retrievedValue + 1;
context.globalState.update("sidebarOpeningCount", increasedValue);
And then I need to retrieve that number on my JQuery file. I can't do import * as vscode from "vscode"; because it't not a TS file. Even if it was, context: vscode.ExtensionContext can only be passed as a parameter to the activate function on extension.ts.
But basically I wanna do something like const retrievedOpeningCountValue = context.globalState.get<Number>("sidebarOpeningCount");on a js file. How do I do that?
You could simply assign context to some global / shared resource, and import it on any other .js/.ts file.
Something like:
extension.ts
export async function activate(context: vscode.ExtensionContext) {
Container.context = context;
container.ts
import { ExtensionContext } from "vscode";
export class Container {
private static _extContext: ExtensionContext;
public static get context(): ExtensionContext {
return this._extContext;
}
public static set context(ec: ExtensionContext) {
this._extContext = ec;
}
}
yourotherfile.ts
import { Container } from "../container";
...
const retrievedOpeningCountValue = Container.context.globalState.get<Number>("sidebarOpeningCount");
I have 3 different language files.
import { french } from '../fr/data.js';
import { englishUS } from '../US/data.js';
import { englishUK } from '../US/data.js';
I load them all in and then just switch in the data I need based on a global language variable. ($root.language)
mounted() {
//switch statement based on $root.language
}
Is there a better way to make this more dynamic and only import the file I need?
I am really stuck in here, i need to know how to gives routes for static file. I have static file in the root folder of project not in public
I tried this
GET /dump.txt controllers.Assets.at(path=".", "dump.txt")
gives me: Compilation error, Identifier expected
code that generates file:
val pw = new PrintWriter(new File("dump.txt"))
val result = Json.parse(qdb.sourceSystem(request.session("role")))
val source_system = (result \ "source_system").get.as[List[String]]
for (x ← source_system) {
try {
// val flagedJsonData = Json.parse(qdb.getSourceLineagesFromDBFlag(x, request.session("role")))
// val flagData = (flagedJsonData \ "flaglist").get.as[String]
val flagData = qdb.getSourceLineagesFromDBFlag(x, request.session("role"))
if (flagData.isEmpty == false) {
val myarray = flagData.split(",")
for (variable ← myarray) {
var dump = variable.split("::") map { y ⇒ "\"%s\"".format(y) } mkString ","
dump = "\"%s\",".format(x) + dump
pw.write(dump + "\n")
}
}
} catch {
case _: Throwable ⇒ println("Data Not Found for " + x)
}
}
pw.close
The Play docs address this well. I am assuming that you are using Play 2.x.x
You will need to add an extra route in your routes.conf file that maps to the special Assets controller. The at method will let you specify which physical file you want it to route to. If it's in your root folder, you shouldn't need to use any path spec.
Assets controller is for the serving "Assets" i.e. public static files.
You are trying to serve not public file that looks like dynamic file (name "dump" looks like you plan to do dumps time to time, so it's not seems to be static).
So, if you sure that your file is "asset" i.e. public and static then you need to put it in to the project "public" folder or subfolder and use controllers.Assets as you describe or as it is documented
In the case if you want to serve not public file that is dynamic, you need to create your own controller. I will show you a little example - you can take it and go:
app/controllers/Static.scala
package controllers
import play.api._
import play.api.mvc._
import scala.io.Source
import play.api.Play.current
class Static extends Controller {
def file(path: String) = Action {
var file = Play.application.getFile(path);
if (file.exists())
Ok(Source.fromFile(file.getCanonicalPath()).mkString);
else
NotFound
}
}
in the routs
GET /build.sbt controllers.Static.file(path="build.sbt")
result in the browser http://localhost:9000/build.sbt
name := """scala-assests-multy"""
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.11.6"
libraryDependencies ++= Seq(
jdbc,
cache,
ws,
specs2 % Test
)
resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases"
// Play provides two styles of routers, one expects its actions to be injected, the
// other, legacy style, accesses its actions statically.
routesGenerator := InjectedRoutesGenerator
You can take this controller and use it for the serving your dump file with the
GET /dump.txt controllers.Static.file(path="dump.txt")
This is how I bootstrap my SPA.
class Bootstrap extends Controller {
def index = Assets.at("/public", "app/index.html")
}
For SPA static assets, I just make sure they're visible from my routes.
GET / controllers.Bootstrap.index
GET /views/*file controllers.Assets.versioned(path="/public/app/js/views", file: Asset)
GET /*file controllers.Assets.versioned(path="/public/app", file: Asset)
What I wish is to catch the keypress using JScript .NET, and compile the code using that jsc.exe.
So, is there any equivalent of "addEventListener("keyDown", keyCheck)" from FLASH actionscript. Or GetAsyncKeyState() from C++.
And what library do I have to use?
Please be kind enough to share a small, simple example.
Here's a simple solution if you're writing a console app.
import System;
Console.Write("Press the M key... ");
var key:ConsoleKeyInfo;
while (1) {
while (!Console.KeyAvailable) {
System.Threading.Thread.Sleep(1);
}
key = Console.ReadKey(1);
if (key.Key == ConsoleKey.M) break;
}
Console.Write("Accepted.");
Read more about ConsoleKeyInfo.
If you need GetAsyncKeyState(), it is possible to access the method in JScript.NET. A couple days ago I came across a JScript.NET function that exposes Win32 API methods via P/Invoke. Here it is, slightly modified for simpler syntax (allowing pass-through of arguments from API function definitions).
import System;
import System.Reflection;
import System.Reflection.Emit;
// Invoke a Win32 P/Invoke call.
// credit: http://cx20.main.jp/blog/hello/2013/03/07/hello-win32-api-jscript-net-world/
function InvokeWin32(dllName:String, returnType:Type, methodName:String, params:Object[]) {
var paramTypes:Type[] = new Type[params.length];
for (var i:int in params) {
paramTypes[i] = params[i].GetType();
}
// Begin to build the dynamic assembly
var domain = AppDomain.CurrentDomain;
var name = new System.Reflection.AssemblyName('PInvokeAssembly');
var assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule('PInvokeModule');
var type = module.DefineType('PInvokeType',TypeAttributes.Public
+ TypeAttributes.BeforeFieldInit);
// Define the actual P/Invoke method
var method = type.DefineMethod(methodName, MethodAttributes.Public
+ MethodAttributes.HideBySig + MethodAttributes.Static +
MethodAttributes.PinvokeImpl, returnType, paramTypes);
// Apply the P/Invoke constructor
var ctor = System.Runtime.InteropServices.DllImportAttribute.GetConstructor(
[System.String]
);
var attr = new System.Reflection.Emit.CustomAttributeBuilder(ctor, [dllName]);
method.SetCustomAttribute(attr);
// Create the temporary type, and invoke the method.
var realType = type.CreateType();
return realType.InvokeMember(methodName, BindingFlags.Public + BindingFlags.Static
+ BindingFlags.InvokeMethod, null, null, params);
}
With this function, you can expose Win32 DLL methods with the following syntax. (See? Told you it was simpler.)
// ShowWindowAsync(hWnd:IntPtr, nCmdShow:int);
function ShowWindowAsync(... args:Object[]):boolean {
return InvokeWin32("user32.dll", System.Boolean, "ShowWindowAsync", args);
}
// GetWindowLong(hWnd:IntPtr, nIndex:int);
function GetWindowLong(... args:Object[]):int {
return InvokeWin32("user32.dll", System.Int32, "GetWindowLong", args);
}
// FindWindowEx(parentHandle:IntPtr, childAfter:IntPtr,
// lclassName:IntPtr, windowTitle:String);
function FindWindowEx(... args:Object[]):IntPtr {
return InvokeWin32("user32.dll", System.IntPtr, "FindWindowEx", args);
}
And I've never used GetAsyncKeyState(); but since it's a user32.dll method, I'm guessing it'll work the same way. (Edit: It does.)
// GetAsyncKeyState(vKey:int);
function GetAsyncKeyState(... args:Object[]):short {
return InvokeWin32("user32.dll", System.Int16, "GetAsyncKeyState", args);
}
Then for a trivial example:
import System; // for Console methods
import System.Windows.Forms; // for Keys object constants
Console.Write("Press the M key... ");
// while the M key is not being pressed, sleep
while (!GetAsyncKeyState(Keys.M)) {
System.Threading.Thread.Sleep(1);
}
// flush input buffer
while (Console.KeyAvailable) Console.ReadKey(1);
Console.WriteLine("Accepted.");
I am trying to call one of 2 snippet methods with the same name and same class, but these snippets are located in different packages. Here's the example code:
Snippet 1:
package v1.site.snippet
class TestSnippet {
def test = { println("printed from v1") }
}
Snippet 2:
package v2.site.snippet
class TestSnippet {
def test = { println("printed from v2") }
}
index.html:
<div class="lift:TestSnippet.test"></div>
So how do I tell index.html which TestSnippet.test to call? Both packages have been added in my Boot.scala.
One option:
LiftRules.snippetDispatch.append {
case "V1TestSnippet" => new v1.site.snippet.TestSnippet
case "V2TestSnippet" => new v2.site.snippet.TestSnippet
}
Your snippets must then inherit DispatchSnippet and define def dispatch = { case "test" => test _ } etc. You then invoke the snippets from the template as V1TestSnippet or V2TestSnippet.
Alternatively, something like
LiftRules.snippets.append {
case "V1TestSnippet"::"test"::Nil => (new v1.site.snippet.TestSnippet).test _
case "V2TestSnippet"::"test"::Nil => (new v2.site.snippet.TestSnippet).test _
}
I believe the List is the snippet name in the template split on dots.